2007-05-11 17:12:14 +04:00
|
|
|
/* $NetBSD: uirda.c,v 1.25 2007/05/11 13:12:14 is Exp $ */
|
2001-12-12 18:27:24 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (c) 2001 The NetBSD Foundation, Inc.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This code is derived from software contributed to The NetBSD Foundation
|
2001-12-14 16:07:33 +03:00
|
|
|
* by Lennart Augustsson (lennart@augustsson.net).
|
2001-12-12 18:27:24 +03:00
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
|
|
* must display the following acknowledgement:
|
|
|
|
* This product includes software developed by the NetBSD
|
|
|
|
* Foundation, Inc. and its contributors.
|
|
|
|
* 4. Neither the name of The NetBSD Foundation nor the names of its
|
|
|
|
* contributors may be used to endorse or promote products derived
|
|
|
|
* from this software without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
|
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
|
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/cdefs.h>
|
2007-05-11 17:12:14 +04:00
|
|
|
__KERNEL_RCSID(0, "$NetBSD: uirda.c,v 1.25 2007/05/11 13:12:14 is Exp $");
|
2001-12-12 18:27:24 +03:00
|
|
|
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/kernel.h>
|
|
|
|
#include <sys/device.h>
|
|
|
|
#include <sys/lock.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <sys/conf.h>
|
|
|
|
#include <sys/file.h>
|
|
|
|
#include <sys/poll.h>
|
|
|
|
#include <sys/select.h>
|
|
|
|
#include <sys/proc.h>
|
|
|
|
|
|
|
|
#include <dev/usb/usb.h>
|
|
|
|
#include <dev/usb/usbdi.h>
|
|
|
|
#include <dev/usb/usbdi_util.h>
|
|
|
|
#include <dev/usb/usbdevs.h>
|
|
|
|
|
|
|
|
#include <dev/ir/ir.h>
|
|
|
|
#include <dev/ir/irdaio.h>
|
|
|
|
#include <dev/ir/irframevar.h>
|
|
|
|
|
2007-05-11 17:12:14 +04:00
|
|
|
#include <dev/usb/uirdavar.h>
|
|
|
|
|
2002-08-22 13:57:13 +04:00
|
|
|
#ifdef UIRDA_DEBUG
|
2001-12-12 18:27:24 +03:00
|
|
|
#define DPRINTF(x) if (uirdadebug) logprintf x
|
|
|
|
#define DPRINTFN(n,x) if (uirdadebug>(n)) logprintf x
|
2001-12-14 18:44:04 +03:00
|
|
|
int uirdadebug = 0;
|
2001-12-12 18:27:24 +03:00
|
|
|
#else
|
|
|
|
#define DPRINTF(x)
|
|
|
|
#define DPRINTFN(n,x)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
/* Class specific requests */
|
|
|
|
#define UR_IRDA_RECEIVING 0x01 /* Receive in progress? */
|
|
|
|
#define UR_IRDA_CHECK_MEDIA_BUSY 0x03
|
|
|
|
#define UR_IRDA_SET_RATE_SNIFF 0x04 /* opt */
|
|
|
|
#define UR_IRDA_SET_UNICAST_LIST 0x05 /* opt */
|
|
|
|
#define UR_IRDA_GET_DESC 0x06
|
|
|
|
|
|
|
|
#define UIRDA_NEBOFS 8
|
|
|
|
static struct {
|
|
|
|
int count;
|
|
|
|
int mask;
|
|
|
|
int header;
|
|
|
|
} uirda_ebofs[UIRDA_NEBOFS] = {
|
|
|
|
{ 0, UI_EB_0, UIRDA_EB_0 },
|
|
|
|
{ 1, UI_EB_1, UIRDA_EB_1 },
|
|
|
|
{ 2, UI_EB_2, UIRDA_EB_2 },
|
|
|
|
{ 3, UI_EB_3, UIRDA_EB_3 },
|
|
|
|
{ 6, UI_EB_6, UIRDA_EB_6 },
|
|
|
|
{ 12, UI_EB_12, UIRDA_EB_12 },
|
|
|
|
{ 24, UI_EB_24, UIRDA_EB_24 },
|
|
|
|
{ 48, UI_EB_48, UIRDA_EB_48 }
|
|
|
|
};
|
|
|
|
|
|
|
|
#define UIRDA_NSPEEDS 9
|
|
|
|
static struct {
|
|
|
|
int speed;
|
|
|
|
int mask;
|
|
|
|
int header;
|
|
|
|
} uirda_speeds[UIRDA_NSPEEDS] = {
|
|
|
|
{ 4000000, UI_BR_4000000, UIRDA_4000000 },
|
|
|
|
{ 1152000, UI_BR_1152000, UIRDA_1152000 },
|
|
|
|
{ 576000, UI_BR_576000, UIRDA_576000 },
|
|
|
|
{ 115200, UI_BR_115200, UIRDA_115200 },
|
|
|
|
{ 57600, UI_BR_57600, UIRDA_57600 },
|
|
|
|
{ 38400, UI_BR_38400, UIRDA_38400 },
|
|
|
|
{ 19200, UI_BR_19200, UIRDA_19200 },
|
|
|
|
{ 9600, UI_BR_9600, UIRDA_9600 },
|
|
|
|
{ 2400, UI_BR_2400, UIRDA_2400 },
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
2005-12-11 15:16:03 +03:00
|
|
|
int uirda_open(void *h, int flag, int mode, struct lwp *l);
|
|
|
|
int uirda_close(void *h, int flag, int mode, struct lwp *l);
|
2001-12-12 18:27:24 +03:00
|
|
|
int uirda_read(void *h, struct uio *uio, int flag);
|
|
|
|
int uirda_write(void *h, struct uio *uio, int flag);
|
|
|
|
int uirda_set_params(void *h, struct irda_params *params);
|
|
|
|
int uirda_get_speeds(void *h, int *speeds);
|
|
|
|
int uirda_get_turnarounds(void *h, int *times);
|
2005-12-11 15:16:03 +03:00
|
|
|
int uirda_poll(void *h, int events, struct lwp *l);
|
2002-10-23 13:10:23 +04:00
|
|
|
int uirda_kqfilter(void *h, struct knote *kn);
|
2001-12-12 18:27:24 +03:00
|
|
|
|
|
|
|
struct irframe_methods uirda_methods = {
|
2002-07-12 01:14:24 +04:00
|
|
|
uirda_open, uirda_close, uirda_read, uirda_write, uirda_poll,
|
2002-10-23 13:10:23 +04:00
|
|
|
uirda_kqfilter, uirda_set_params, uirda_get_speeds,
|
|
|
|
uirda_get_turnarounds
|
2001-12-12 18:27:24 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
void uirda_rd_cb(usbd_xfer_handle xfer, usbd_private_handle priv,
|
|
|
|
usbd_status status);
|
|
|
|
usbd_status uirda_start_read(struct uirda_softc *sc);
|
|
|
|
|
2002-07-12 01:14:24 +04:00
|
|
|
/*
|
2001-12-12 18:27:24 +03:00
|
|
|
* These devices don't quite follow the spec. Speed changing is broken
|
|
|
|
* and they don't handle windows.
|
|
|
|
* But we change speed in a safe way, and don't use windows now.
|
|
|
|
* Some devices also seem to have an interrupt pipe that can be ignored.
|
|
|
|
*
|
|
|
|
* Table information taken from Linux driver.
|
|
|
|
*/
|
|
|
|
Static const struct usb_devno uirda_devs[] = {
|
|
|
|
{ USB_VENDOR_ACTISYS, USB_PRODUCT_ACTISYS_IR2000U },
|
|
|
|
{ USB_VENDOR_EXTENDED, USB_PRODUCT_EXTENDED_XTNDACCESS },
|
|
|
|
{ USB_VENDOR_KAWATSU, USB_PRODUCT_KAWATSU_KC180 },
|
|
|
|
};
|
|
|
|
#define uirda_lookup(v, p) (usb_lookup(uirda_devs, v, p))
|
|
|
|
|
|
|
|
USB_DECLARE_DRIVER(uirda);
|
|
|
|
|
|
|
|
USB_MATCH(uirda)
|
|
|
|
{
|
Introduce different autoconf interface attributes for USB drivers
matching (and handling) a whole device and those which match an
interface only. This will allow to enforce some rules, eg that
the former don't use interface information for matching or that the
latter don't modify global device state.
The previous way left too much freedom do the drivers which led to
inconsistencies and abuse.
For now, I've not changed locators and submatch rules, this will
happen later.
There should not be any change in behaviour, except in the case of
some drivers which did behave inconsistently:
if_atu, if_axe, uep: matched the configured device in the interface
stage, but did configuration again. I've converted them to match
in the device stage.
ustir, utoppy: matched in the interface stage, but only against
vendor/device information, and used any configuration/interface
without checking. Changed to match in device stage, and added
some simple code to configure and use the first interface.
If you have one of those devices, please test!
2007-03-13 16:51:53 +03:00
|
|
|
USB_IFMATCH_START(uirda, uaa);
|
2001-12-12 18:27:24 +03:00
|
|
|
|
|
|
|
DPRINTFN(50,("uirda_match\n"));
|
|
|
|
|
|
|
|
if (uirda_lookup(uaa->vendor, uaa->product) != NULL)
|
|
|
|
return (UMATCH_VENDOR_PRODUCT);
|
|
|
|
|
Introduce different autoconf interface attributes for USB drivers
matching (and handling) a whole device and those which match an
interface only. This will allow to enforce some rules, eg that
the former don't use interface information for matching or that the
latter don't modify global device state.
The previous way left too much freedom do the drivers which led to
inconsistencies and abuse.
For now, I've not changed locators and submatch rules, this will
happen later.
There should not be any change in behaviour, except in the case of
some drivers which did behave inconsistently:
if_atu, if_axe, uep: matched the configured device in the interface
stage, but did configuration again. I've converted them to match
in the device stage.
ustir, utoppy: matched in the interface stage, but only against
vendor/device information, and used any configuration/interface
without checking. Changed to match in device stage, and added
some simple code to configure and use the first interface.
If you have one of those devices, please test!
2007-03-13 16:51:53 +03:00
|
|
|
if (uaa->class == UICLASS_APPL_SPEC &&
|
|
|
|
uaa->subclass == UISUBCLASS_IRDA &&
|
|
|
|
uaa->proto == UIPROTO_IRDA)
|
2001-12-12 18:27:24 +03:00
|
|
|
return (UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO);
|
|
|
|
return (UMATCH_NONE);
|
|
|
|
}
|
|
|
|
|
|
|
|
USB_ATTACH(uirda)
|
|
|
|
{
|
Introduce different autoconf interface attributes for USB drivers
matching (and handling) a whole device and those which match an
interface only. This will allow to enforce some rules, eg that
the former don't use interface information for matching or that the
latter don't modify global device state.
The previous way left too much freedom do the drivers which led to
inconsistencies and abuse.
For now, I've not changed locators and submatch rules, this will
happen later.
There should not be any change in behaviour, except in the case of
some drivers which did behave inconsistently:
if_atu, if_axe, uep: matched the configured device in the interface
stage, but did configuration again. I've converted them to match
in the device stage.
ustir, utoppy: matched in the interface stage, but only against
vendor/device information, and used any configuration/interface
without checking. Changed to match in device stage, and added
some simple code to configure and use the first interface.
If you have one of those devices, please test!
2007-03-13 16:51:53 +03:00
|
|
|
USB_IFATTACH_START(uirda, sc, uaa);
|
2001-12-12 18:27:24 +03:00
|
|
|
usbd_device_handle dev = uaa->device;
|
|
|
|
usbd_interface_handle iface = uaa->iface;
|
2005-05-11 14:02:28 +04:00
|
|
|
char *devinfop;
|
2001-12-12 18:27:24 +03:00
|
|
|
usb_endpoint_descriptor_t *ed;
|
|
|
|
usbd_status err;
|
|
|
|
u_int8_t epcount;
|
2001-12-14 15:02:53 +03:00
|
|
|
u_int specrev;
|
2001-12-12 18:27:24 +03:00
|
|
|
int i;
|
|
|
|
struct ir_attach_args ia;
|
|
|
|
|
|
|
|
DPRINTFN(10,("uirda_attach: sc=%p\n", sc));
|
|
|
|
|
2005-05-11 14:02:28 +04:00
|
|
|
devinfop = usbd_devinfo_alloc(dev, 0);
|
2001-12-12 18:27:24 +03:00
|
|
|
USB_ATTACH_SETUP;
|
2005-05-11 14:02:28 +04:00
|
|
|
printf("%s: %s\n", USBDEVNAME(sc->sc_dev), devinfop);
|
|
|
|
usbd_devinfo_free(devinfop);
|
2001-12-12 18:27:24 +03:00
|
|
|
|
|
|
|
sc->sc_udev = dev;
|
|
|
|
sc->sc_iface = iface;
|
|
|
|
|
2007-05-11 17:12:14 +04:00
|
|
|
if (sc->sc_hdszi == 0)
|
|
|
|
sc->sc_hdszi = UIRDA_INPUT_HEADER_SIZE;
|
|
|
|
|
2001-12-12 18:27:24 +03:00
|
|
|
epcount = 0;
|
|
|
|
(void)usbd_endpoint_count(iface, &epcount);
|
|
|
|
|
|
|
|
sc->sc_rd_addr = -1;
|
|
|
|
sc->sc_wr_addr = -1;
|
|
|
|
for (i = 0; i < epcount; i++) {
|
|
|
|
ed = usbd_interface2endpoint_descriptor(iface, i);
|
|
|
|
if (ed == NULL) {
|
|
|
|
printf("%s: couldn't get ep %d\n",
|
|
|
|
USBDEVNAME(sc->sc_dev), i);
|
|
|
|
USB_ATTACH_ERROR_RETURN;
|
|
|
|
}
|
|
|
|
if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
|
|
|
|
UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
|
|
|
|
sc->sc_rd_addr = ed->bEndpointAddress;
|
|
|
|
} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
|
|
|
|
UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
|
|
|
|
sc->sc_wr_addr = ed->bEndpointAddress;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (sc->sc_rd_addr == -1 || sc->sc_wr_addr == -1) {
|
|
|
|
printf("%s: missing endpoint\n", USBDEVNAME(sc->sc_dev));
|
|
|
|
USB_ATTACH_ERROR_RETURN;
|
|
|
|
}
|
|
|
|
|
2007-05-11 17:12:14 +04:00
|
|
|
if (sc->sc_loadfw(sc) != 0) {
|
|
|
|
USB_ATTACH_ERROR_RETURN;
|
|
|
|
}
|
|
|
|
|
2001-12-12 18:27:24 +03:00
|
|
|
/* Get the IrDA descriptor */
|
2007-05-11 17:12:14 +04:00
|
|
|
err = usbd_get_class_desc(sc->sc_udev, UDESC_IRDA, 0,
|
|
|
|
USB_IRDA_DESCRIPTOR_SIZE, &sc->sc_irdadesc);
|
|
|
|
printf("error %d reading class desc\n", err);
|
|
|
|
if (err) {
|
|
|
|
err = usbd_get_desc(sc->sc_udev, UDESC_IRDA, 0,
|
2001-12-12 18:27:24 +03:00
|
|
|
USB_IRDA_DESCRIPTOR_SIZE, &sc->sc_irdadesc);
|
2007-05-11 17:12:14 +04:00
|
|
|
}
|
|
|
|
printf("error %d reading desc\n", err);
|
2001-12-12 18:27:24 +03:00
|
|
|
if (err) {
|
2001-12-18 17:50:01 +03:00
|
|
|
/* maybe it's embedded in the config desc? */
|
2007-02-26 16:36:01 +03:00
|
|
|
usbd_desc_iter_t iter;
|
|
|
|
const usb_descriptor_t *d;
|
|
|
|
usb_desc_iter_init(sc->sc_udev, &iter);
|
|
|
|
for (;;) {
|
|
|
|
d = usb_desc_iter_next(&iter);
|
|
|
|
if (!d || d->bDescriptorType == UDESC_IRDA)
|
|
|
|
break;
|
|
|
|
}
|
2001-12-12 18:27:24 +03:00
|
|
|
if (d == NULL) {
|
|
|
|
printf("%s: Cannot get IrDA descriptor\n",
|
|
|
|
USBDEVNAME(sc->sc_dev));
|
|
|
|
USB_ATTACH_ERROR_RETURN;
|
|
|
|
}
|
|
|
|
memcpy(&sc->sc_irdadesc, d, USB_IRDA_DESCRIPTOR_SIZE);
|
|
|
|
}
|
2007-05-11 17:12:14 +04:00
|
|
|
DPRINTF(("uirda_attach: bDescriptorSize %d bDescriptorType 0x%x "
|
|
|
|
"bmDataSize=0x%02x bmWindowSize=0x%02x "
|
2001-12-18 17:50:01 +03:00
|
|
|
"bmMinTurnaroundTime=0x%02x wBaudRate=0x%04x "
|
|
|
|
"bmAdditionalBOFs=0x%02x bIrdaSniff=%d bMaxUnicastList=%d\n",
|
2007-05-11 17:12:14 +04:00
|
|
|
sc->sc_irdadesc.bLength,
|
|
|
|
sc->sc_irdadesc.bDescriptorType,
|
2001-12-14 15:02:53 +03:00
|
|
|
sc->sc_irdadesc.bmDataSize,
|
|
|
|
sc->sc_irdadesc.bmWindowSize,
|
|
|
|
sc->sc_irdadesc.bmMinTurnaroundTime,
|
|
|
|
UGETW(sc->sc_irdadesc.wBaudRate),
|
|
|
|
sc->sc_irdadesc.bmAdditionalBOFs,
|
|
|
|
sc->sc_irdadesc.bIrdaSniff,
|
|
|
|
sc->sc_irdadesc.bMaxUnicastList));
|
|
|
|
|
|
|
|
specrev = UGETW(sc->sc_irdadesc.bcdSpecRevision);
|
2001-12-18 17:50:01 +03:00
|
|
|
printf("%s: USB-IrDA protocol version %x.%02x\n",
|
|
|
|
USBDEVNAME(sc->sc_dev), specrev >> 8, specrev & 0xff);
|
2001-12-12 18:27:24 +03:00
|
|
|
|
|
|
|
DPRINTFN(10, ("uirda_attach: %p\n", sc->sc_udev));
|
|
|
|
|
|
|
|
usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
|
|
|
|
USBDEV(sc->sc_dev));
|
|
|
|
|
2001-12-13 20:25:37 +03:00
|
|
|
lockinit(&sc->sc_wr_buf_lk, PZERO, "iirwrl", 0, 0);
|
|
|
|
lockinit(&sc->sc_rd_buf_lk, PZERO, "uirrdl", 0, 0);
|
|
|
|
|
2001-12-12 18:27:24 +03:00
|
|
|
ia.ia_type = IR_TYPE_IRFRAME;
|
2007-05-11 17:12:14 +04:00
|
|
|
ia.ia_methods = sc->sc_irm ? sc->sc_irm : &uirda_methods;
|
2001-12-12 18:27:24 +03:00
|
|
|
ia.ia_handle = sc;
|
|
|
|
|
|
|
|
sc->sc_child = config_found(self, &ia, ir_print);
|
|
|
|
|
|
|
|
USB_ATTACH_SUCCESS_RETURN;
|
|
|
|
}
|
|
|
|
|
|
|
|
USB_DETACH(uirda)
|
|
|
|
{
|
|
|
|
USB_DETACH_START(uirda, sc);
|
|
|
|
int s;
|
|
|
|
int rv = 0;
|
|
|
|
|
|
|
|
DPRINTF(("uirda_detach: sc=%p flags=%d\n", sc, flags));
|
|
|
|
|
|
|
|
sc->sc_dying = 1;
|
|
|
|
/* Abort all pipes. Causes processes waiting for transfer to wake. */
|
|
|
|
if (sc->sc_rd_pipe != NULL) {
|
|
|
|
usbd_abort_pipe(sc->sc_rd_pipe);
|
|
|
|
usbd_close_pipe(sc->sc_rd_pipe);
|
|
|
|
sc->sc_rd_pipe = NULL;
|
|
|
|
}
|
|
|
|
if (sc->sc_wr_pipe != NULL) {
|
|
|
|
usbd_abort_pipe(sc->sc_wr_pipe);
|
|
|
|
usbd_close_pipe(sc->sc_wr_pipe);
|
|
|
|
sc->sc_wr_pipe = NULL;
|
|
|
|
}
|
|
|
|
wakeup(&sc->sc_rd_count);
|
|
|
|
|
|
|
|
s = splusb();
|
|
|
|
if (--sc->sc_refcnt >= 0) {
|
|
|
|
/* Wait for processes to go away. */
|
|
|
|
usb_detach_wait(USBDEV(sc->sc_dev));
|
|
|
|
}
|
|
|
|
splx(s);
|
|
|
|
|
|
|
|
if (sc->sc_child != NULL) {
|
|
|
|
rv = config_detach(sc->sc_child, flags);
|
|
|
|
sc->sc_child = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
|
|
|
|
USBDEV(sc->sc_dev));
|
|
|
|
|
|
|
|
return (rv);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
uirda_activate(device_ptr_t self, enum devact act)
|
|
|
|
{
|
|
|
|
struct uirda_softc *sc = (struct uirda_softc *)self;
|
|
|
|
int error = 0;
|
|
|
|
|
|
|
|
switch (act) {
|
|
|
|
case DVACT_ACTIVATE:
|
|
|
|
return (EOPNOTSUPP);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DVACT_DEACTIVATE:
|
|
|
|
sc->sc_dying = 1;
|
|
|
|
if (sc->sc_child != NULL)
|
|
|
|
error = config_deactivate(sc->sc_child);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2006-11-16 04:32:37 +03:00
|
|
|
uirda_open(void *h, int flag, int mode,
|
|
|
|
struct lwp *l)
|
2001-12-12 18:27:24 +03:00
|
|
|
{
|
|
|
|
struct uirda_softc *sc = h;
|
|
|
|
int error;
|
|
|
|
usbd_status err;
|
|
|
|
|
2002-07-08 21:46:23 +04:00
|
|
|
DPRINTF(("%s: sc=%p\n", __func__, sc));
|
2001-12-12 18:27:24 +03:00
|
|
|
|
|
|
|
err = usbd_open_pipe(sc->sc_iface, sc->sc_rd_addr, 0, &sc->sc_rd_pipe);
|
|
|
|
if (err) {
|
|
|
|
error = EIO;
|
|
|
|
goto bad1;
|
|
|
|
}
|
|
|
|
err = usbd_open_pipe(sc->sc_iface, sc->sc_wr_addr, 0, &sc->sc_wr_pipe);
|
|
|
|
if (err) {
|
|
|
|
error = EIO;
|
|
|
|
goto bad2;
|
|
|
|
}
|
|
|
|
sc->sc_rd_xfer = usbd_alloc_xfer(sc->sc_udev);
|
|
|
|
if (sc->sc_rd_xfer == NULL) {
|
|
|
|
error = ENOMEM;
|
|
|
|
goto bad3;
|
|
|
|
}
|
|
|
|
sc->sc_wr_xfer = usbd_alloc_xfer(sc->sc_udev);
|
|
|
|
if (sc->sc_wr_xfer == NULL) {
|
|
|
|
error = ENOMEM;
|
|
|
|
goto bad4;
|
|
|
|
}
|
2001-12-14 15:08:14 +03:00
|
|
|
sc->sc_rd_buf = usbd_alloc_buffer(sc->sc_rd_xfer,
|
2007-05-11 17:12:14 +04:00
|
|
|
IRDA_MAX_FRAME_SIZE + sc->sc_hdszi);
|
2001-12-14 15:08:14 +03:00
|
|
|
if (sc->sc_rd_buf == NULL) {
|
|
|
|
error = ENOMEM;
|
|
|
|
goto bad5;
|
|
|
|
}
|
|
|
|
sc->sc_wr_buf = usbd_alloc_buffer(sc->sc_wr_xfer,
|
2007-05-11 17:12:14 +04:00
|
|
|
IRDA_MAX_FRAME_SIZE + UIRDA_OUTPUT_HEADER_SIZE +
|
|
|
|
2 + 1 /* worst case ST-UIRDA */);
|
2001-12-14 15:08:14 +03:00
|
|
|
if (sc->sc_wr_buf == NULL) {
|
|
|
|
error = ENOMEM;
|
|
|
|
goto bad5;
|
|
|
|
}
|
2001-12-13 05:16:21 +03:00
|
|
|
sc->sc_rd_count = 0;
|
2001-12-14 15:02:53 +03:00
|
|
|
sc->sc_rd_err = 0;
|
2001-12-13 05:16:21 +03:00
|
|
|
sc->sc_params.speed = 0;
|
|
|
|
sc->sc_params.ebofs = 0;
|
2001-12-14 16:07:33 +03:00
|
|
|
sc->sc_params.maxsize = IRDA_MAX_FRAME_SIZE;
|
|
|
|
sc->sc_wr_hdr = -1;
|
|
|
|
|
|
|
|
err = uirda_start_read(sc);
|
|
|
|
/* XXX check err */
|
2001-12-13 05:16:21 +03:00
|
|
|
|
2001-12-12 18:27:24 +03:00
|
|
|
return (0);
|
|
|
|
|
2001-12-14 15:08:14 +03:00
|
|
|
bad5:
|
|
|
|
usbd_free_xfer(sc->sc_wr_xfer);
|
|
|
|
sc->sc_wr_xfer = NULL;
|
2001-12-12 18:27:24 +03:00
|
|
|
bad4:
|
|
|
|
usbd_free_xfer(sc->sc_rd_xfer);
|
|
|
|
sc->sc_rd_xfer = NULL;
|
|
|
|
bad3:
|
|
|
|
usbd_close_pipe(sc->sc_wr_pipe);
|
|
|
|
sc->sc_wr_pipe = NULL;
|
|
|
|
bad2:
|
|
|
|
usbd_close_pipe(sc->sc_rd_pipe);
|
|
|
|
sc->sc_rd_pipe = NULL;
|
|
|
|
bad1:
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2006-11-16 04:32:37 +03:00
|
|
|
uirda_close(void *h, int flag, int mode,
|
|
|
|
struct lwp *l)
|
2001-12-12 18:27:24 +03:00
|
|
|
{
|
|
|
|
struct uirda_softc *sc = h;
|
|
|
|
|
2002-07-08 21:46:23 +04:00
|
|
|
DPRINTF(("%s: sc=%p\n", __func__, sc));
|
2001-12-12 18:27:24 +03:00
|
|
|
|
|
|
|
if (sc->sc_rd_pipe != NULL) {
|
|
|
|
usbd_abort_pipe(sc->sc_rd_pipe);
|
|
|
|
usbd_close_pipe(sc->sc_rd_pipe);
|
|
|
|
sc->sc_rd_pipe = NULL;
|
|
|
|
}
|
2001-12-13 05:16:21 +03:00
|
|
|
if (sc->sc_wr_pipe != NULL) {
|
|
|
|
usbd_abort_pipe(sc->sc_wr_pipe);
|
|
|
|
usbd_close_pipe(sc->sc_wr_pipe);
|
|
|
|
sc->sc_wr_pipe = NULL;
|
|
|
|
}
|
2001-12-12 18:27:24 +03:00
|
|
|
if (sc->sc_rd_xfer != NULL) {
|
|
|
|
usbd_free_xfer(sc->sc_rd_xfer);
|
|
|
|
sc->sc_rd_xfer = NULL;
|
2001-12-13 05:16:21 +03:00
|
|
|
sc->sc_rd_buf = NULL;
|
2001-12-12 18:27:24 +03:00
|
|
|
}
|
|
|
|
if (sc->sc_wr_xfer != NULL) {
|
|
|
|
usbd_free_xfer(sc->sc_wr_xfer);
|
|
|
|
sc->sc_wr_xfer = NULL;
|
2001-12-13 05:16:21 +03:00
|
|
|
sc->sc_wr_buf = NULL;
|
2001-12-12 18:27:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2006-11-16 04:32:37 +03:00
|
|
|
uirda_read(void *h, struct uio *uio, int flag)
|
2001-12-12 18:27:24 +03:00
|
|
|
{
|
|
|
|
struct uirda_softc *sc = h;
|
|
|
|
usbd_status err;
|
|
|
|
int s;
|
|
|
|
int error;
|
2001-12-13 05:16:21 +03:00
|
|
|
u_int n;
|
2001-12-12 18:27:24 +03:00
|
|
|
|
2002-07-08 21:46:23 +04:00
|
|
|
DPRINTFN(1,("%s: sc=%p\n", __func__, sc));
|
2001-12-12 18:27:24 +03:00
|
|
|
|
|
|
|
if (sc->sc_dying)
|
|
|
|
return (EIO);
|
|
|
|
|
2001-12-14 15:08:14 +03:00
|
|
|
#ifdef DIAGNOSTIC
|
2001-12-12 18:27:24 +03:00
|
|
|
if (sc->sc_rd_buf == NULL)
|
|
|
|
return (EINVAL);
|
2001-12-14 15:08:14 +03:00
|
|
|
#endif
|
2001-12-12 18:27:24 +03:00
|
|
|
|
2001-12-13 05:16:21 +03:00
|
|
|
sc->sc_refcnt++;
|
|
|
|
|
|
|
|
do {
|
|
|
|
s = splusb();
|
|
|
|
while (sc->sc_rd_count == 0) {
|
2001-12-14 15:02:53 +03:00
|
|
|
DPRINTFN(5,("uirda_read: calling tsleep()\n"));
|
2001-12-13 05:16:21 +03:00
|
|
|
error = tsleep(&sc->sc_rd_count, PZERO | PCATCH,
|
|
|
|
"uirdrd", 0);
|
|
|
|
if (sc->sc_dying)
|
|
|
|
error = EIO;
|
|
|
|
if (error) {
|
|
|
|
splx(s);
|
|
|
|
DPRINTF(("uirda_read: tsleep() = %d\n", error));
|
|
|
|
goto ret;
|
|
|
|
}
|
2001-12-12 18:27:24 +03:00
|
|
|
}
|
2001-12-13 05:16:21 +03:00
|
|
|
splx(s);
|
2002-07-12 01:14:24 +04:00
|
|
|
|
2001-12-13 05:16:21 +03:00
|
|
|
lockmgr(&sc->sc_rd_buf_lk, LK_EXCLUSIVE, NULL);
|
2007-05-11 17:12:14 +04:00
|
|
|
n = sc->sc_rd_count - sc->sc_hdszi;
|
2002-07-08 21:46:23 +04:00
|
|
|
DPRINTFN(1,("%s: sc=%p n=%u, hdr=0x%02x\n", __func__,
|
2001-12-14 18:44:04 +03:00
|
|
|
sc, n, sc->sc_rd_buf[0]));
|
2001-12-13 05:16:21 +03:00
|
|
|
if (n > uio->uio_resid)
|
|
|
|
error = EINVAL;
|
|
|
|
else
|
2007-05-11 17:12:14 +04:00
|
|
|
error = uiomove(sc->sc_rd_buf + sc->sc_hdszi, n, uio);
|
2001-12-13 05:16:21 +03:00
|
|
|
sc->sc_rd_count = 0;
|
|
|
|
lockmgr(&sc->sc_rd_buf_lk, LK_RELEASE, NULL);
|
2002-07-12 01:14:24 +04:00
|
|
|
|
2001-12-13 05:16:21 +03:00
|
|
|
err = uirda_start_read(sc);
|
|
|
|
/* XXX check err */
|
2001-12-12 18:27:24 +03:00
|
|
|
|
2001-12-13 05:16:21 +03:00
|
|
|
} while (n == 0);
|
2001-12-12 18:27:24 +03:00
|
|
|
|
2001-12-13 05:16:21 +03:00
|
|
|
DPRINTFN(1,("uirda_read: return %d\n", error));
|
2001-12-12 18:27:24 +03:00
|
|
|
|
2001-12-13 05:16:21 +03:00
|
|
|
ret:
|
|
|
|
if (--sc->sc_refcnt < 0)
|
|
|
|
usb_detach_wakeup(USBDEV(sc->sc_dev));
|
|
|
|
return (error);
|
2001-12-12 18:27:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2006-11-16 04:32:37 +03:00
|
|
|
uirda_write(void *h, struct uio *uio, int flag)
|
2001-12-12 18:27:24 +03:00
|
|
|
{
|
|
|
|
struct uirda_softc *sc = h;
|
|
|
|
usbd_status err;
|
|
|
|
u_int32_t n;
|
|
|
|
int error = 0;
|
|
|
|
|
2002-07-08 21:46:23 +04:00
|
|
|
DPRINTFN(1,("%s: sc=%p\n", __func__, sc));
|
2001-12-12 18:27:24 +03:00
|
|
|
|
|
|
|
if (sc->sc_dying)
|
|
|
|
return (EIO);
|
|
|
|
|
2001-12-14 15:08:14 +03:00
|
|
|
#ifdef DIAGNOSTIC
|
|
|
|
if (sc->sc_wr_buf == NULL)
|
|
|
|
return (EINVAL);
|
|
|
|
#endif
|
|
|
|
|
2001-12-12 18:27:24 +03:00
|
|
|
n = uio->uio_resid;
|
2001-12-14 15:08:14 +03:00
|
|
|
if (n > sc->sc_params.maxsize)
|
2001-12-12 18:27:24 +03:00
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
sc->sc_refcnt++;
|
|
|
|
lockmgr(&sc->sc_wr_buf_lk, LK_EXCLUSIVE, NULL);
|
|
|
|
|
|
|
|
sc->sc_wr_buf[0] = UIRDA_EB_NO_CHANGE | UIRDA_NO_SPEED;
|
2001-12-14 18:44:04 +03:00
|
|
|
error = uiomove(sc->sc_wr_buf + UIRDA_OUTPUT_HEADER_SIZE, n, uio);
|
2001-12-12 18:27:24 +03:00
|
|
|
if (!error) {
|
|
|
|
DPRINTFN(1, ("uirdawrite: transfer %d bytes\n", n));
|
|
|
|
|
2007-05-11 17:12:14 +04:00
|
|
|
n += UIRDA_OUTPUT_HEADER_SIZE;
|
2001-12-12 18:27:24 +03:00
|
|
|
err = usbd_bulk_transfer(sc->sc_wr_xfer, sc->sc_wr_pipe,
|
|
|
|
USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
|
|
|
|
UIRDA_WR_TIMEOUT,
|
|
|
|
sc->sc_wr_buf, &n, "uirdawr");
|
|
|
|
DPRINTFN(2, ("uirdawrite: err=%d\n", err));
|
|
|
|
if (err) {
|
|
|
|
if (err == USBD_INTERRUPTED)
|
|
|
|
error = EINTR;
|
|
|
|
else if (err == USBD_TIMEOUT)
|
|
|
|
error = ETIMEDOUT;
|
|
|
|
else
|
|
|
|
error = EIO;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
lockmgr(&sc->sc_wr_buf_lk, LK_RELEASE, NULL);
|
|
|
|
if (--sc->sc_refcnt < 0)
|
|
|
|
usb_detach_wakeup(USBDEV(sc->sc_dev));
|
|
|
|
|
2002-07-08 21:46:23 +04:00
|
|
|
DPRINTFN(1,("%s: sc=%p done\n", __func__, sc));
|
2001-12-12 18:27:24 +03:00
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2005-12-11 15:16:03 +03:00
|
|
|
uirda_poll(void *h, int events, struct lwp *l)
|
2001-12-12 18:27:24 +03:00
|
|
|
{
|
|
|
|
struct uirda_softc *sc = h;
|
|
|
|
int revents = 0;
|
|
|
|
int s;
|
|
|
|
|
2002-07-08 21:46:23 +04:00
|
|
|
DPRINTFN(1,("%s: sc=%p\n", __func__, sc));
|
2001-12-12 18:27:24 +03:00
|
|
|
|
|
|
|
s = splusb();
|
|
|
|
if (events & (POLLOUT | POLLWRNORM))
|
|
|
|
revents |= events & (POLLOUT | POLLWRNORM);
|
|
|
|
if (events & (POLLIN | POLLRDNORM)) {
|
|
|
|
if (sc->sc_rd_count != 0) {
|
2002-07-08 21:46:23 +04:00
|
|
|
DPRINTFN(2,("%s: have data\n", __func__));
|
2001-12-12 18:27:24 +03:00
|
|
|
revents |= events & (POLLIN | POLLRDNORM);
|
|
|
|
} else {
|
2002-07-08 21:46:23 +04:00
|
|
|
DPRINTFN(2,("%s: recording select\n", __func__));
|
2005-12-11 15:16:03 +03:00
|
|
|
selrecord(l, &sc->sc_rd_sel);
|
2001-12-12 18:27:24 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
splx(s);
|
|
|
|
|
|
|
|
return (revents);
|
|
|
|
}
|
|
|
|
|
2002-10-23 13:10:23 +04:00
|
|
|
static void
|
|
|
|
filt_uirdardetach(struct knote *kn)
|
|
|
|
{
|
|
|
|
struct uirda_softc *sc = kn->kn_hook;
|
|
|
|
int s;
|
|
|
|
|
|
|
|
s = splusb();
|
2002-11-26 21:49:40 +03:00
|
|
|
SLIST_REMOVE(&sc->sc_rd_sel.sel_klist, kn, knote, kn_selnext);
|
2002-10-23 13:10:23 +04:00
|
|
|
splx(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2006-11-16 04:32:37 +03:00
|
|
|
filt_uirdaread(struct knote *kn, long hint)
|
2002-10-23 13:10:23 +04:00
|
|
|
{
|
|
|
|
struct uirda_softc *sc = kn->kn_hook;
|
|
|
|
|
|
|
|
kn->kn_data = sc->sc_rd_count;
|
|
|
|
return (kn->kn_data > 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
filt_uirdawdetach(struct knote *kn)
|
|
|
|
{
|
|
|
|
struct uirda_softc *sc = kn->kn_hook;
|
|
|
|
int s;
|
|
|
|
|
|
|
|
s = splusb();
|
2002-11-26 21:49:40 +03:00
|
|
|
SLIST_REMOVE(&sc->sc_wr_sel.sel_klist, kn, knote, kn_selnext);
|
2002-10-23 13:10:23 +04:00
|
|
|
splx(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct filterops uirdaread_filtops =
|
|
|
|
{ 1, NULL, filt_uirdardetach, filt_uirdaread };
|
|
|
|
static const struct filterops uirdawrite_filtops =
|
|
|
|
{ 1, NULL, filt_uirdawdetach, filt_seltrue };
|
|
|
|
|
|
|
|
int
|
2006-11-16 04:32:37 +03:00
|
|
|
uirda_kqfilter(void *h, struct knote *kn)
|
2002-10-23 13:10:23 +04:00
|
|
|
{
|
|
|
|
struct uirda_softc *sc = kn->kn_hook;
|
|
|
|
struct klist *klist;
|
|
|
|
int s;
|
|
|
|
|
|
|
|
switch (kn->kn_filter) {
|
|
|
|
case EVFILT_READ:
|
2002-11-26 21:49:40 +03:00
|
|
|
klist = &sc->sc_rd_sel.sel_klist;
|
2002-10-23 13:10:23 +04:00
|
|
|
kn->kn_fop = &uirdaread_filtops;
|
|
|
|
break;
|
|
|
|
case EVFILT_WRITE:
|
2002-11-26 21:49:40 +03:00
|
|
|
klist = &sc->sc_wr_sel.sel_klist;
|
2002-10-23 13:10:23 +04:00
|
|
|
kn->kn_fop = &uirdawrite_filtops;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
|
|
|
|
kn->kn_hook = sc;
|
|
|
|
|
|
|
|
s = splusb();
|
|
|
|
SLIST_INSERT_HEAD(klist, kn, kn_selnext);
|
|
|
|
splx(s);
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2001-12-12 18:27:24 +03:00
|
|
|
int
|
|
|
|
uirda_set_params(void *h, struct irda_params *p)
|
|
|
|
{
|
|
|
|
struct uirda_softc *sc = h;
|
|
|
|
usbd_status err;
|
|
|
|
int i;
|
|
|
|
u_int8_t hdr;
|
|
|
|
u_int32_t n;
|
|
|
|
u_int mask;
|
|
|
|
|
2002-07-08 21:46:23 +04:00
|
|
|
DPRINTF(("%s: sc=%p, speed=%d ebofs=%d maxsize=%d\n", __func__,
|
2001-12-12 18:27:24 +03:00
|
|
|
sc, p->speed, p->ebofs, p->maxsize));
|
|
|
|
|
|
|
|
if (sc->sc_dying)
|
|
|
|
return (EIO);
|
|
|
|
|
|
|
|
hdr = 0;
|
|
|
|
if (p->ebofs != sc->sc_params.ebofs) {
|
|
|
|
/* round up ebofs */
|
2007-05-11 17:12:14 +04:00
|
|
|
mask = 1 /* sc->sc_irdadesc.bmAdditionalBOFs*/;
|
|
|
|
DPRINTF(("u.s.p.: mask=0x%x, sc->ebofs=%d, p->ebofs=%d\n",
|
|
|
|
mask, sc->sc_params.ebofs, p->ebofs));
|
2001-12-12 18:27:24 +03:00
|
|
|
for (i = 0; i < UIRDA_NEBOFS; i++) {
|
2007-05-11 17:12:14 +04:00
|
|
|
DPRINTF(("u.s.p.: u_e[%d].mask=0x%x, count=%d\n",
|
|
|
|
i, uirda_ebofs[i].mask, uirda_ebofs[i].count));
|
2001-12-12 18:27:24 +03:00
|
|
|
if ((mask & uirda_ebofs[i].mask) &&
|
|
|
|
uirda_ebofs[i].count >= p->ebofs) {
|
|
|
|
hdr = uirda_ebofs[i].header;
|
|
|
|
goto found1;
|
|
|
|
}
|
|
|
|
}
|
2007-05-11 17:12:14 +04:00
|
|
|
for (i = 0; i < UIRDA_NEBOFS; i++) {
|
|
|
|
DPRINTF(("u.s.p.: u_e[%d].mask=0x%x, count=%d\n",
|
|
|
|
i, uirda_ebofs[i].mask, uirda_ebofs[i].count));
|
|
|
|
if ((mask & uirda_ebofs[i].mask)) {
|
|
|
|
hdr = uirda_ebofs[i].header;
|
|
|
|
goto found1;
|
|
|
|
}
|
|
|
|
}
|
2001-12-12 18:27:24 +03:00
|
|
|
/* no good value found */
|
|
|
|
return (EINVAL);
|
|
|
|
found1:
|
2001-12-14 16:07:33 +03:00
|
|
|
DPRINTF(("uirda_set_params: ebofs hdr=0x%02x\n", hdr));
|
2001-12-12 18:27:24 +03:00
|
|
|
;
|
2002-07-12 01:14:24 +04:00
|
|
|
|
2001-12-12 18:27:24 +03:00
|
|
|
}
|
2001-12-14 16:07:33 +03:00
|
|
|
if (hdr != 0 || p->speed != sc->sc_params.speed) {
|
2001-12-12 18:27:24 +03:00
|
|
|
/* find speed */
|
|
|
|
mask = UGETW(sc->sc_irdadesc.wBaudRate);
|
|
|
|
for (i = 0; i < UIRDA_NSPEEDS; i++) {
|
|
|
|
if ((mask & uirda_speeds[i].mask) &&
|
|
|
|
uirda_speeds[i].speed == p->speed) {
|
|
|
|
hdr |= uirda_speeds[i].header;
|
|
|
|
goto found2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* no good value found */
|
|
|
|
return (EINVAL);
|
|
|
|
found2:
|
2001-12-14 16:07:33 +03:00
|
|
|
DPRINTF(("uirda_set_params: speed hdr=0x%02x\n", hdr));
|
2001-12-12 18:27:24 +03:00
|
|
|
;
|
|
|
|
}
|
|
|
|
if (p->maxsize != sc->sc_params.maxsize) {
|
2001-12-14 15:08:14 +03:00
|
|
|
if (p->maxsize > IRDA_MAX_FRAME_SIZE)
|
|
|
|
return (EINVAL);
|
|
|
|
sc->sc_params.maxsize = p->maxsize;
|
|
|
|
#if 0
|
2002-07-08 21:46:23 +04:00
|
|
|
DPRINTF(("%s: new buffers, old size=%d\n", __func__,
|
2001-12-13 05:16:21 +03:00
|
|
|
sc->sc_params.maxsize));
|
2001-12-12 18:27:24 +03:00
|
|
|
if (p->maxsize > 10000 || p < 0) /* XXX */
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
/* Change the write buffer */
|
|
|
|
lockmgr(&sc->sc_wr_buf_lk, LK_EXCLUSIVE, NULL);
|
|
|
|
if (sc->sc_wr_buf != NULL)
|
|
|
|
usbd_free_buffer(sc->sc_wr_xfer);
|
|
|
|
sc->sc_wr_buf = usbd_alloc_buffer(sc->sc_wr_xfer, p->maxsize+1);
|
|
|
|
lockmgr(&sc->sc_wr_buf_lk, LK_RELEASE, NULL);
|
|
|
|
if (sc->sc_wr_buf == NULL)
|
|
|
|
return (ENOMEM);
|
|
|
|
|
|
|
|
/* Change the read buffer */
|
|
|
|
lockmgr(&sc->sc_rd_buf_lk, LK_EXCLUSIVE, NULL);
|
|
|
|
usbd_abort_pipe(sc->sc_rd_pipe);
|
|
|
|
if (sc->sc_rd_buf != NULL)
|
|
|
|
usbd_free_buffer(sc->sc_rd_xfer);
|
|
|
|
sc->sc_rd_buf = usbd_alloc_buffer(sc->sc_rd_xfer, p->maxsize+1);
|
|
|
|
sc->sc_rd_count = 0;
|
2001-12-13 05:16:21 +03:00
|
|
|
if (sc->sc_rd_buf == NULL) {
|
|
|
|
lockmgr(&sc->sc_rd_buf_lk, LK_RELEASE, NULL);
|
|
|
|
return (ENOMEM);
|
|
|
|
}
|
2001-12-14 15:02:53 +03:00
|
|
|
sc->sc_params.maxsize = p->maxsize;
|
2001-12-12 18:27:24 +03:00
|
|
|
err = uirda_start_read(sc); /* XXX check */
|
|
|
|
lockmgr(&sc->sc_rd_buf_lk, LK_RELEASE, NULL);
|
2001-12-14 15:08:14 +03:00
|
|
|
#endif
|
2001-12-12 18:27:24 +03:00
|
|
|
}
|
2001-12-14 16:07:33 +03:00
|
|
|
if (hdr != 0 && hdr != sc->sc_wr_hdr) {
|
2002-07-12 01:14:24 +04:00
|
|
|
/*
|
2001-12-12 18:27:24 +03:00
|
|
|
* A change has occurred, transmit a 0 length frame with
|
|
|
|
* the new settings. The 0 length frame is not sent to the
|
|
|
|
* device.
|
|
|
|
*/
|
2001-12-14 16:07:33 +03:00
|
|
|
DPRINTF(("%s: sc=%p setting header 0x%02x\n",
|
2002-07-08 21:46:23 +04:00
|
|
|
__func__, sc, hdr));
|
2001-12-14 16:07:33 +03:00
|
|
|
sc->sc_wr_hdr = hdr;
|
2001-12-13 05:16:21 +03:00
|
|
|
lockmgr(&sc->sc_wr_buf_lk, LK_EXCLUSIVE, NULL);
|
|
|
|
sc->sc_wr_buf[0] = hdr;
|
2001-12-14 18:44:04 +03:00
|
|
|
n = UIRDA_OUTPUT_HEADER_SIZE;
|
2001-12-12 18:27:24 +03:00
|
|
|
err = usbd_bulk_transfer(sc->sc_wr_xfer, sc->sc_wr_pipe,
|
|
|
|
USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
|
2001-12-13 05:16:21 +03:00
|
|
|
UIRDA_WR_TIMEOUT, sc->sc_wr_buf, &n, "uirdast");
|
|
|
|
if (err) {
|
2001-12-12 18:27:24 +03:00
|
|
|
printf("%s: set failed, err=%d\n",
|
|
|
|
USBDEVNAME(sc->sc_dev), err);
|
|
|
|
usbd_clear_endpoint_stall(sc->sc_wr_pipe);
|
|
|
|
}
|
2001-12-14 16:07:33 +03:00
|
|
|
lockmgr(&sc->sc_wr_buf_lk, LK_RELEASE, NULL);
|
2001-12-12 18:27:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
sc->sc_params = *p;
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
uirda_get_speeds(void *h, int *speeds)
|
|
|
|
{
|
|
|
|
struct uirda_softc *sc = h;
|
|
|
|
u_int isp;
|
|
|
|
u_int usp;
|
|
|
|
|
2002-07-08 21:46:23 +04:00
|
|
|
DPRINTF(("%s: sc=%p\n", __func__, sc));
|
2001-12-12 18:27:24 +03:00
|
|
|
|
|
|
|
if (sc->sc_dying)
|
|
|
|
return (EIO);
|
|
|
|
|
|
|
|
usp = UGETW(sc->sc_irdadesc.wBaudRate);
|
|
|
|
isp = 0;
|
|
|
|
if (usp & UI_BR_4000000) isp |= IRDA_SPEED_4000000;
|
|
|
|
if (usp & UI_BR_1152000) isp |= IRDA_SPEED_1152000;
|
|
|
|
if (usp & UI_BR_576000) isp |= IRDA_SPEED_576000;
|
|
|
|
if (usp & UI_BR_115200) isp |= IRDA_SPEED_115200;
|
|
|
|
if (usp & UI_BR_57600) isp |= IRDA_SPEED_57600;
|
|
|
|
if (usp & UI_BR_38400) isp |= IRDA_SPEED_38400;
|
|
|
|
if (usp & UI_BR_19200) isp |= IRDA_SPEED_19200;
|
|
|
|
if (usp & UI_BR_9600) isp |= IRDA_SPEED_9600;
|
|
|
|
if (usp & UI_BR_2400) isp |= IRDA_SPEED_2400;
|
|
|
|
*speeds = isp;
|
2007-05-11 17:12:14 +04:00
|
|
|
DPRINTF(("%s: speeds = 0x%x\n", __func__, isp));
|
2001-12-12 18:27:24 +03:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
uirda_get_turnarounds(void *h, int *turnarounds)
|
|
|
|
{
|
|
|
|
struct uirda_softc *sc = h;
|
|
|
|
u_int ita;
|
|
|
|
u_int uta;
|
|
|
|
|
2002-07-08 21:46:23 +04:00
|
|
|
DPRINTF(("%s: sc=%p\n", __func__, sc));
|
2001-12-12 18:27:24 +03:00
|
|
|
|
|
|
|
if (sc->sc_dying)
|
|
|
|
return (EIO);
|
|
|
|
|
|
|
|
uta = sc->sc_irdadesc.bmMinTurnaroundTime;
|
|
|
|
ita = 0;
|
|
|
|
if (uta & UI_TA_0) ita |= IRDA_TURNT_0;
|
|
|
|
if (uta & UI_TA_10) ita |= IRDA_TURNT_10;
|
|
|
|
if (uta & UI_TA_50) ita |= IRDA_TURNT_50;
|
|
|
|
if (uta & UI_TA_100) ita |= IRDA_TURNT_100;
|
|
|
|
if (uta & UI_TA_500) ita |= IRDA_TURNT_500;
|
|
|
|
if (uta & UI_TA_1000) ita |= IRDA_TURNT_1000;
|
|
|
|
if (uta & UI_TA_5000) ita |= IRDA_TURNT_5000;
|
|
|
|
if (uta & UI_TA_10000) ita |= IRDA_TURNT_10000;
|
|
|
|
*turnarounds = ita;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
uirda_rd_cb(usbd_xfer_handle xfer, usbd_private_handle priv,
|
|
|
|
usbd_status status)
|
|
|
|
{
|
|
|
|
struct uirda_softc *sc = priv;
|
|
|
|
u_int32_t size;
|
|
|
|
|
2002-07-08 21:46:23 +04:00
|
|
|
DPRINTFN(1,("%s: sc=%p\n", __func__, sc));
|
2001-12-13 05:16:21 +03:00
|
|
|
|
2001-12-12 18:27:24 +03:00
|
|
|
if (status == USBD_CANCELLED) /* this is normal */
|
|
|
|
return;
|
|
|
|
if (status) {
|
2007-05-11 17:12:14 +04:00
|
|
|
size = sc->sc_hdszi;
|
2001-12-14 15:02:53 +03:00
|
|
|
sc->sc_rd_err = 1;
|
|
|
|
} else {
|
|
|
|
usbd_get_xfer_status(xfer, NULL, NULL, &size, NULL);
|
2001-12-12 18:27:24 +03:00
|
|
|
}
|
2002-07-08 21:46:23 +04:00
|
|
|
DPRINTFN(1,("%s: sc=%p size=%u, err=%d\n", __func__, sc, size,
|
2001-12-14 15:02:53 +03:00
|
|
|
sc->sc_rd_err));
|
2001-12-12 18:27:24 +03:00
|
|
|
sc->sc_rd_count = size;
|
2001-12-13 05:16:21 +03:00
|
|
|
wakeup(&sc->sc_rd_count); /* XXX should use flag */
|
2002-10-23 13:10:23 +04:00
|
|
|
selnotify(&sc->sc_rd_sel, 0);
|
2001-12-12 18:27:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
usbd_status
|
|
|
|
uirda_start_read(struct uirda_softc *sc)
|
|
|
|
{
|
|
|
|
usbd_status err;
|
|
|
|
|
2002-07-08 21:46:23 +04:00
|
|
|
DPRINTFN(1,("%s: sc=%p, size=%d\n", __func__, sc,
|
2001-12-14 18:44:04 +03:00
|
|
|
sc->sc_params.maxsize + UIRDA_INPUT_HEADER_SIZE));
|
2001-12-13 05:16:21 +03:00
|
|
|
|
2001-12-12 18:27:24 +03:00
|
|
|
if (sc->sc_dying)
|
|
|
|
return (USBD_IOERROR);
|
|
|
|
|
2001-12-14 15:02:53 +03:00
|
|
|
if (sc->sc_rd_err) {
|
|
|
|
sc->sc_rd_err = 0;
|
|
|
|
DPRINTF(("uirda_start_read: clear stall\n"));
|
|
|
|
usbd_clear_endpoint_stall(sc->sc_rd_pipe);
|
|
|
|
}
|
|
|
|
|
2001-12-12 18:27:24 +03:00
|
|
|
usbd_setup_xfer(sc->sc_rd_xfer, sc->sc_rd_pipe, sc, sc->sc_rd_buf,
|
2007-05-11 17:12:14 +04:00
|
|
|
sc->sc_params.maxsize + sc->sc_hdszi,
|
2001-12-13 05:16:21 +03:00
|
|
|
USBD_SHORT_XFER_OK | USBD_NO_COPY,
|
|
|
|
USBD_NO_TIMEOUT, uirda_rd_cb);
|
2001-12-12 18:27:24 +03:00
|
|
|
err = usbd_transfer(sc->sc_rd_xfer);
|
2001-12-14 15:02:53 +03:00
|
|
|
if (err != USBD_IN_PROGRESS) {
|
|
|
|
DPRINTF(("uirda_start_read: err=%d\n", err));
|
2001-12-12 18:27:24 +03:00
|
|
|
return (err);
|
2001-12-14 15:02:53 +03:00
|
|
|
}
|
2001-12-12 18:27:24 +03:00
|
|
|
return (USBD_NORMAL_COMPLETION);
|
|
|
|
}
|
2007-05-11 17:12:14 +04:00
|
|
|
|
|
|
|
usbd_status
|
|
|
|
usbd_get_class_desc(usbd_device_handle dev, int type, int index, int len, void *desc)
|
|
|
|
{
|
|
|
|
usb_device_request_t req;
|
|
|
|
|
|
|
|
DPRINTFN(3,("usbd_get_desc: type=%d, index=%d, len=%d\n",
|
|
|
|
type, index, len));
|
|
|
|
|
|
|
|
req.bmRequestType = 0xa1; /* XXX ? */
|
|
|
|
req.bRequest = UR_GET_DESCRIPTOR;
|
|
|
|
USETW2(req.wValue, type, index);
|
|
|
|
USETW(req.wIndex, 0);
|
|
|
|
USETW(req.wLength, len);
|
|
|
|
return (usbd_do_request(dev, &req, desc));
|
|
|
|
}
|