version 1.14.2.7, 2005/12/11 10:29:06 |
version 1.15, 2003/07/14 15:47:29 |
Line 67 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 67 __KERNEL_RCSID(0, "$NetBSD$"); |
|
/* Report descriptor for broken Wacom Graphire */ |
/* Report descriptor for broken Wacom Graphire */ |
#include <dev/usb/ugraphire_rdesc.h> |
#include <dev/usb/ugraphire_rdesc.h> |
|
|
#include "locators.h" |
|
|
|
#ifdef UHIDEV_DEBUG |
#ifdef UHIDEV_DEBUG |
#define DPRINTF(x) if (uhidevdebug) logprintf x |
#define DPRINTF(x) if (uhidevdebug) logprintf x |
#define DPRINTFN(n,x) if (uhidevdebug>(n)) logprintf x |
#define DPRINTFN(n,x) if (uhidevdebug>(n)) logprintf x |
Line 80 int uhidevdebug = 0; |
|
Line 78 int uhidevdebug = 0; |
|
|
|
Static void uhidev_intr(usbd_xfer_handle, usbd_private_handle, usbd_status); |
Static void uhidev_intr(usbd_xfer_handle, usbd_private_handle, usbd_status); |
|
|
Static int uhidev_maxrepid(void *, int); |
Static int uhidev_maxrepid(void *buf, int len); |
Static int uhidevprint(void *, const char *); |
Static int uhidevprint(void *aux, const char *pnp); |
Static int uhidevsubmatch(struct device *, struct cfdata *, |
Static int uhidevsubmatch(struct device *parent, struct cfdata *cf, void *aux); |
const int *, void *); |
|
|
|
USB_DECLARE_DRIVER(uhidev); |
USB_DECLARE_DRIVER(uhidev); |
|
|
Line 97 USB_MATCH(uhidev) |
|
Line 94 USB_MATCH(uhidev) |
|
id = usbd_get_interface_descriptor(uaa->iface); |
id = usbd_get_interface_descriptor(uaa->iface); |
if (id == NULL || id->bInterfaceClass != UICLASS_HID) |
if (id == NULL || id->bInterfaceClass != UICLASS_HID) |
return (UMATCH_NONE); |
return (UMATCH_NONE); |
|
if (uaa->matchlvl) |
|
return (uaa->matchlvl); |
return (UMATCH_IFACECLASS_GENERIC); |
return (UMATCH_IFACECLASS_GENERIC); |
} |
} |
|
|
Line 110 USB_ATTACH(uhidev) |
|
Line 109 USB_ATTACH(uhidev) |
|
struct uhidev *dev; |
struct uhidev *dev; |
int size, nrepid, repid, repsz; |
int size, nrepid, repid, repsz; |
int repsizes[256]; |
int repsizes[256]; |
int i; |
|
void *desc; |
void *desc; |
const void *descptr; |
|
usbd_status err; |
usbd_status err; |
char *devinfop; |
char devinfo[1024]; |
int locs[UHIDBUSCF_NLOCS]; |
|
|
|
sc->sc_udev = uaa->device; |
sc->sc_udev = uaa->device; |
sc->sc_iface = iface; |
sc->sc_iface = iface; |
id = usbd_get_interface_descriptor(iface); |
id = usbd_get_interface_descriptor(iface); |
|
usbd_devinfo(uaa->device, 0, devinfo); |
devinfop = usbd_devinfo_alloc(uaa->device, 0); |
|
USB_ATTACH_SETUP; |
USB_ATTACH_SETUP; |
printf("%s: %s, iclass %d/%d\n", USBDEVNAME(sc->sc_dev), |
printf("%s: %s, iclass %d/%d\n", USBDEVNAME(sc->sc_dev), |
devinfop, id->bInterfaceClass, id->bInterfaceSubClass); |
devinfo, id->bInterfaceClass, id->bInterfaceSubClass); |
usbd_devinfo_free(devinfop); |
|
|
|
(void)usbd_set_idle(iface, 0, 0); |
(void)usbd_set_idle(iface, 0, 0); |
#if 0 |
#if 0 |
Line 136 USB_ATTACH(uhidev) |
|
Line 130 USB_ATTACH(uhidev) |
|
(void)usbd_set_protocol(iface, 1); |
(void)usbd_set_protocol(iface, 1); |
#endif |
#endif |
|
|
sc->sc_iep_addr = sc->sc_oep_addr = -1; |
ed = usbd_interface2endpoint_descriptor(iface, 0); |
for (i = 0; i < id->bNumEndpoints; i++) { |
if (ed == NULL) { |
ed = usbd_interface2endpoint_descriptor(iface, i); |
printf("%s: could not read endpoint descriptor\n", |
if (ed == NULL) { |
USBDEVNAME(sc->sc_dev)); |
printf("%s: could not read endpoint descriptor\n", |
sc->sc_dying = 1; |
USBDEVNAME(sc->sc_dev)); |
USB_ATTACH_ERROR_RETURN; |
sc->sc_dying = 1; |
|
USB_ATTACH_ERROR_RETURN; |
|
} |
|
|
|
DPRINTFN(10,("uhidev_attach: bLength=%d bDescriptorType=%d " |
|
"bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d" |
|
" bInterval=%d\n", |
|
ed->bLength, ed->bDescriptorType, |
|
ed->bEndpointAddress & UE_ADDR, |
|
UE_GET_DIR(ed->bEndpointAddress)==UE_DIR_IN? "in" : "out", |
|
ed->bmAttributes & UE_XFERTYPE, |
|
UGETW(ed->wMaxPacketSize), ed->bInterval)); |
|
|
|
if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && |
|
(ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT) { |
|
sc->sc_iep_addr = ed->bEndpointAddress; |
|
} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && |
|
(ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT) { |
|
sc->sc_oep_addr = ed->bEndpointAddress; |
|
} else { |
|
printf("%s: endpoint %d: ignored\n", USBDEVNAME(sc->sc_dev), i); |
|
} |
|
} |
} |
|
|
/* |
DPRINTFN(10,("uhidev_attach: bLength=%d bDescriptorType=%d " |
* Check that we found an input interrupt endpoint. The output interrupt |
"bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d" |
* endpoint is optional |
" bInterval=%d\n", |
*/ |
ed->bLength, ed->bDescriptorType, |
if (sc->sc_iep_addr == -1) { |
ed->bEndpointAddress & UE_ADDR, |
printf("%s: no input interrupt endpoint\n", USBDEVNAME(sc->sc_dev)); |
UE_GET_DIR(ed->bEndpointAddress)==UE_DIR_IN? "in" : "out", |
|
ed->bmAttributes & UE_XFERTYPE, |
|
UGETW(ed->wMaxPacketSize), ed->bInterval)); |
|
|
|
if (UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_IN || |
|
(ed->bmAttributes & UE_XFERTYPE) != UE_INTERRUPT) { |
|
printf("%s: unexpected endpoint\n", USBDEVNAME(sc->sc_dev)); |
sc->sc_dying = 1; |
sc->sc_dying = 1; |
USB_ATTACH_ERROR_RETURN; |
USB_ATTACH_ERROR_RETURN; |
} |
} |
|
|
/* XXX need to extend this */ |
sc->sc_ep_addr = ed->bEndpointAddress; |
descptr = NULL; |
|
if (uaa->vendor == USB_VENDOR_WACOM) { |
|
static uByte reportbuf[] = {2, 2, 2}; |
|
|
|
|
/* XXX need to extend this */ |
|
if (uaa->vendor == USB_VENDOR_WACOM && |
|
uaa->product == USB_PRODUCT_WACOM_GRAPHIRE /* && |
|
uaa->revision == 0x???? */) { /* XXX should use revision */ |
/* The report descriptor for the Wacom Graphire is broken. */ |
/* The report descriptor for the Wacom Graphire is broken. */ |
switch (uaa->product) { |
size = sizeof uhid_graphire_report_descr; |
case USB_PRODUCT_WACOM_GRAPHIRE: |
|
size = sizeof uhid_graphire_report_descr; |
|
descptr = uhid_graphire_report_descr; |
|
break; |
|
|
|
case USB_PRODUCT_WACOM_GRAPHIRE3_4X5: /* The 6x8 too? */ |
|
/* |
|
* The Graphire3 needs 0x0202 to be written to |
|
* feature report ID 2 before it'll start |
|
* returning digitizer data. |
|
*/ |
|
usbd_set_report(uaa->iface, UHID_FEATURE_REPORT, 2, |
|
&reportbuf, sizeof reportbuf); |
|
|
|
size = sizeof uhid_graphire3_4x5_report_descr; |
|
descptr = uhid_graphire3_4x5_report_descr; |
|
break; |
|
default: |
|
/* Keep descriptor */ |
|
break; |
|
} |
|
} |
|
|
|
if (descptr) { |
|
desc = malloc(size, M_USBDEV, M_NOWAIT); |
desc = malloc(size, M_USBDEV, M_NOWAIT); |
if (desc == NULL) |
if (desc == NULL) |
err = USBD_NOMEM; |
err = USBD_NOMEM; |
else { |
else { |
err = USBD_NORMAL_COMPLETION; |
err = USBD_NORMAL_COMPLETION; |
memcpy(desc, descptr, size); |
memcpy(desc, uhid_graphire_report_descr, size); |
} |
} |
} else { |
} else { |
desc = NULL; |
desc = NULL; |
err = usbd_read_report_desc(uaa->iface, &desc, &size, |
err = usbd_read_report_desc(uaa->iface, &desc, &size, M_USBDEV); |
M_USBDEV); |
|
} |
} |
if (err) { |
if (err) { |
printf("%s: no report descriptor\n", USBDEVNAME(sc->sc_dev)); |
printf("%s: no report descriptor\n", USBDEVNAME(sc->sc_dev)); |
Line 225 USB_ATTACH(uhidev) |
|
Line 179 USB_ATTACH(uhidev) |
|
USB_ATTACH_ERROR_RETURN; |
USB_ATTACH_ERROR_RETURN; |
} |
} |
|
|
if (uaa->vendor == USB_VENDOR_HOSIDEN && |
|
uaa->product == USB_PRODUCT_HOSIDEN_PPP) { |
|
static uByte reportbuf[] = { 1 }; |
|
/* |
|
* This device was sold by Konami with its ParaParaParadise |
|
* game for PlayStation2. It needs to be "turned on" |
|
* before it will send any reports. |
|
*/ |
|
|
|
usbd_set_report(uaa->iface, UHID_FEATURE_REPORT, 0, |
|
&reportbuf, sizeof reportbuf); |
|
} |
|
|
|
sc->sc_repdesc = desc; |
sc->sc_repdesc = desc; |
sc->sc_repdesc_size = size; |
sc->sc_repdesc_size = size; |
|
|
Line 281 USB_ATTACH(uhidev) |
|
Line 222 USB_ATTACH(uhidev) |
|
; /* already NULL in sc->sc_subdevs[repid] */ |
; /* already NULL in sc->sc_subdevs[repid] */ |
} else { |
} else { |
uha.reportid = repid; |
uha.reportid = repid; |
locs[UHIDBUSCF_REPORTID] = repid; |
dev = (struct uhidev *)config_found_sm(self, &uha, |
|
uhidevprint, uhidevsubmatch); |
dev = (struct uhidev *)config_found_sm_loc(self, |
|
"uhidbus", locs, &uha, |
|
uhidevprint, uhidevsubmatch); |
|
sc->sc_subdevs[repid] = dev; |
sc->sc_subdevs[repid] = dev; |
if (dev != NULL) { |
if (dev != NULL) { |
dev->sc_in_rep_size = repsizes[repid]; |
dev->sc_in_rep_size = repsizes[repid]; |
Line 299 USB_ATTACH(uhidev) |
|
Line 237 USB_ATTACH(uhidev) |
|
} |
} |
#endif |
#endif |
#if NRND > 0 |
#if NRND > 0 |
rnd_attach_source(&dev->rnd_source, |
rnd_attach_source(&dev->rnd_source, |
USBDEVNAME(dev->sc_dev), |
USBDEVNAME(dev->sc_dev), |
RND_TYPE_TTY, 0); |
RND_TYPE_TTY, 0); |
#endif |
#endif |
} |
} |
Line 339 uhidevprint(void *aux, const char *pnp) |
|
Line 277 uhidevprint(void *aux, const char *pnp) |
|
} |
} |
|
|
int |
int |
uhidevsubmatch(struct device *parent, struct cfdata *cf, |
uhidevsubmatch(struct device *parent, struct cfdata *cf, void *aux) |
const int *locs, void *aux) |
|
{ |
{ |
if (cf->cf_loc[UHIDBUSCF_REPORTID] != UHIDBUSCF_REPORTID_DEFAULT && |
struct uhidev_attach_arg *uha = aux; |
cf->cf_loc[UHIDBUSCF_REPORTID] != locs[UHIDBUSCF_REPORTID]) |
|
return (0); |
|
|
|
|
if (cf->uhidevcf_reportid != UHIDEV_UNK_REPORTID && |
|
cf->uhidevcf_reportid != uha->reportid) |
|
return (0); |
|
if (cf->uhidevcf_reportid == uha->reportid) |
|
uha->matchlvl = UMATCH_VENDOR_PRODUCT; |
|
else |
|
uha->matchlvl = 0; |
return (config_match(parent, cf, aux)); |
return (config_match(parent, cf, aux)); |
} |
} |
|
|
Line 367 uhidev_activate(device_ptr_t self, enum |
|
Line 309 uhidev_activate(device_ptr_t self, enum |
|
&sc->sc_subdevs[i]->sc_dev); |
&sc->sc_subdevs[i]->sc_dev); |
sc->sc_dying = 1; |
sc->sc_dying = 1; |
break; |
break; |
default: |
|
rv = 0; |
|
break; |
|
} |
} |
return (rv); |
return (rv); |
} |
} |
Line 382 USB_DETACH(uhidev) |
|
Line 321 USB_DETACH(uhidev) |
|
DPRINTF(("uhidev_detach: sc=%p flags=%d\n", sc, flags)); |
DPRINTF(("uhidev_detach: sc=%p flags=%d\n", sc, flags)); |
|
|
sc->sc_dying = 1; |
sc->sc_dying = 1; |
if (sc->sc_ipipe != NULL) |
if (sc->sc_intrpipe != NULL) |
usbd_abort_pipe(sc->sc_ipipe); |
usbd_abort_pipe(sc->sc_intrpipe); |
|
|
if (sc->sc_repdesc != NULL) |
if (sc->sc_repdesc != NULL) |
free(sc->sc_repdesc, M_USBDEV); |
free(sc->sc_repdesc, M_USBDEV); |
Line 434 uhidev_intr(usbd_xfer_handle xfer, usbd_ |
|
Line 373 uhidev_intr(usbd_xfer_handle xfer, usbd_ |
|
if (status != USBD_NORMAL_COMPLETION) { |
if (status != USBD_NORMAL_COMPLETION) { |
DPRINTF(("%s: interrupt status=%d\n", USBDEVNAME(sc->sc_dev), |
DPRINTF(("%s: interrupt status=%d\n", USBDEVNAME(sc->sc_dev), |
status)); |
status)); |
usbd_clear_endpoint_stall_async(sc->sc_ipipe); |
usbd_clear_endpoint_stall_async(sc->sc_intrpipe); |
return; |
return; |
} |
} |
|
|
Line 452 uhidev_intr(usbd_xfer_handle xfer, usbd_ |
|
Line 391 uhidev_intr(usbd_xfer_handle xfer, usbd_ |
|
rep, scd, scd ? scd->sc_state : 0)); |
rep, scd, scd ? scd->sc_state : 0)); |
if (scd == NULL || !(scd->sc_state & UHIDEV_OPEN)) |
if (scd == NULL || !(scd->sc_state & UHIDEV_OPEN)) |
return; |
return; |
if (scd->sc_in_rep_size != cc) { |
#ifdef DIAGNOSTIC |
printf("%s: bad input length %d != %d\n", |
if (scd->sc_in_rep_size != cc) |
USBDEVNAME(sc->sc_dev), scd->sc_in_rep_size, cc); |
printf("%s: bad input length %d != %d\n",USBDEVNAME(sc->sc_dev), |
return; |
scd->sc_in_rep_size, cc); |
} |
#endif |
#if NRND > 0 |
#if NRND > 0 |
rnd_add_uint32(&scd->rnd_source, (uintptr_t)(sc->sc_ibuf)); |
rnd_add_uint32(&scd->rnd_source, (uintptr_t)(sc->sc_ibuf)); |
#endif |
#endif |
Line 475 uhidev_open(struct uhidev *scd) |
|
Line 414 uhidev_open(struct uhidev *scd) |
|
{ |
{ |
struct uhidev_softc *sc = scd->sc_parent; |
struct uhidev_softc *sc = scd->sc_parent; |
usbd_status err; |
usbd_status err; |
int error; |
|
|
|
DPRINTF(("uhidev_open: open pipe, state=%d refcnt=%d\n", |
DPRINTF(("uhidev_open: open pipe, state=%d refcnt=%d\n", |
scd->sc_state, sc->sc_refcnt)); |
scd->sc_state, sc->sc_refcnt)); |
Line 491 uhidev_open(struct uhidev *scd) |
|
Line 429 uhidev_open(struct uhidev *scd) |
|
|
|
sc->sc_ibuf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK); |
sc->sc_ibuf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK); |
|
|
/* Set up input interrupt pipe. */ |
/* Set up interrupt pipe. */ |
DPRINTF(("uhidev_open: isize=%d, ep=0x%02x\n", sc->sc_isize, |
DPRINTF(("uhidev_open: isize=%d, ep=0x%02x\n", sc->sc_isize, |
sc->sc_iep_addr)); |
sc->sc_ep_addr)); |
|
err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_ep_addr, |
err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_iep_addr, |
USBD_SHORT_XFER_OK, &sc->sc_intrpipe, sc, sc->sc_ibuf, |
USBD_SHORT_XFER_OK, &sc->sc_ipipe, sc, sc->sc_ibuf, |
|
sc->sc_isize, uhidev_intr, USBD_DEFAULT_INTERVAL); |
sc->sc_isize, uhidev_intr, USBD_DEFAULT_INTERVAL); |
if (err != USBD_NORMAL_COMPLETION) { |
if (err) { |
DPRINTF(("uhidopen: usbd_open_pipe_intr failed, " |
DPRINTF(("uhidopen: usbd_open_pipe_intr failed, " |
"error=%d\n", err)); |
"error=%d\n",err)); |
error = EIO; |
free(sc->sc_ibuf, M_USBDEV); |
goto out1; |
scd->sc_state &= ~UHIDEV_OPEN; |
} |
sc->sc_refcnt = 0; |
|
sc->sc_intrpipe = NULL; |
/* |
return (EIO); |
* Set up output interrupt pipe if an output interrupt endpoint |
|
* exists. |
|
*/ |
|
if (sc->sc_oep_addr != -1) { |
|
DPRINTF(("uhidev_open: oep=0x%02x\n", sc->sc_oep_addr)); |
|
|
|
err = usbd_open_pipe(sc->sc_iface, sc->sc_oep_addr, |
|
0, &sc->sc_opipe); |
|
|
|
if (err != USBD_NORMAL_COMPLETION) { |
|
DPRINTF(("uhidev_open: usbd_open_pipe failed, " |
|
"error=%d\n", err)); |
|
error = EIO; |
|
goto out2; |
|
} |
|
DPRINTF(("uhidev_open: sc->sc_opipe=%p\n", sc->sc_opipe)); |
|
|
|
sc->sc_oxfer = usbd_alloc_xfer(sc->sc_udev); |
|
if (sc->sc_oxfer == NULL) { |
|
DPRINTF(("uhidev_open: couldn't allocate an xfer\n")); |
|
error = ENOMEM; |
|
goto out3; |
|
} |
|
} |
} |
|
|
return (0); |
return (0); |
out3: |
|
/* Abort output pipe */ |
|
usbd_close_pipe(sc->sc_opipe); |
|
out2: |
|
/* Abort input pipe */ |
|
usbd_close_pipe(sc->sc_ipipe); |
|
out1: |
|
DPRINTF(("uhidev_open: failed in someway")); |
|
free(sc->sc_ibuf, M_USBDEV); |
|
scd->sc_state &= ~UHIDEV_OPEN; |
|
sc->sc_refcnt = 0; |
|
sc->sc_ipipe = NULL; |
|
sc->sc_opipe = NULL; |
|
sc->sc_oxfer = NULL; |
|
return error; |
|
} |
} |
|
|
void |
void |
Line 561 uhidev_close(struct uhidev *scd) |
|
Line 459 uhidev_close(struct uhidev *scd) |
|
return; |
return; |
DPRINTF(("uhidev_close: close pipe\n")); |
DPRINTF(("uhidev_close: close pipe\n")); |
|
|
if (sc->sc_oxfer != NULL) |
|
usbd_free_xfer(sc->sc_oxfer); |
|
|
|
/* Disable interrupts. */ |
/* Disable interrupts. */ |
if (sc->sc_opipe != NULL) { |
if (sc->sc_intrpipe != NULL) { |
usbd_abort_pipe(sc->sc_opipe); |
usbd_abort_pipe(sc->sc_intrpipe); |
usbd_close_pipe(sc->sc_opipe); |
usbd_close_pipe(sc->sc_intrpipe); |
sc->sc_opipe = NULL; |
sc->sc_intrpipe = NULL; |
} |
|
|
|
if (sc->sc_ipipe != NULL) { |
|
usbd_abort_pipe(sc->sc_ipipe); |
|
usbd_close_pipe(sc->sc_ipipe); |
|
sc->sc_ipipe = NULL; |
|
} |
} |
|
|
if (sc->sc_ibuf != NULL) { |
if (sc->sc_ibuf != NULL) { |
Line 598 uhidev_set_report(struct uhidev *scd, in |
|
Line 487 uhidev_set_report(struct uhidev *scd, in |
|
memcpy(buf+1, data, len); |
memcpy(buf+1, data, len); |
|
|
retstat = usbd_set_report(scd->sc_parent->sc_iface, type, |
retstat = usbd_set_report(scd->sc_parent->sc_iface, type, |
scd->sc_report_id, buf, len + 1); |
scd->sc_report_id, data, len + 1); |
|
|
free(buf, M_TEMP); |
free(buf, M_TEMP); |
|
|
Line 627 uhidev_get_report(struct uhidev *scd, in |
|
Line 516 uhidev_get_report(struct uhidev *scd, in |
|
return usbd_get_report(scd->sc_parent->sc_iface, type, |
return usbd_get_report(scd->sc_parent->sc_iface, type, |
scd->sc_report_id, data, len); |
scd->sc_report_id, data, len); |
} |
} |
|
|
usbd_status |
|
uhidev_write(struct uhidev_softc *sc, void *data, int len) |
|
{ |
|
|
|
DPRINTF(("uhidev_write: data=%p, len=%d\n", data, len)); |
|
|
|
if (sc->sc_opipe == NULL) |
|
return USBD_INVAL; |
|
|
|
#ifdef UHIDEV_DEBUG |
|
if (uhidevdebug > 50) { |
|
|
|
u_int32_t i; |
|
u_int8_t *d = data; |
|
|
|
DPRINTF(("uhidev_write: data =")); |
|
for (i = 0; i < len; i++) |
|
DPRINTF((" %02x", d[i])); |
|
DPRINTF(("\n")); |
|
} |
|
#endif |
|
return usbd_intr_transfer(sc->sc_oxfer, sc->sc_opipe, 0, |
|
USBD_NO_TIMEOUT, data, &len, "uhidevwi"); |
|
} |
|