summaryrefslogtreecommitdiff
path: root/sys/dev/usb
diff options
context:
space:
mode:
authorMarcus Glocker <mglocker@cvs.openbsd.org>2013-04-08 10:34:21 +0000
committerMarcus Glocker <mglocker@cvs.openbsd.org>2013-04-08 10:34:21 +0000
commitddec2027d9edb59dff664ea02c5ecabd791c2981 (patch)
tree84034339ca710df9359bf58209f3dd920f811e73 /sys/dev/usb
parent5285fafd3b88f9e11cb286d9449e37ec35fee719 (diff)
Add new ioctl's USB_DEVICE_GET_CDESC and USB_DEVICE_GET_FDESC to usb(4).
Those are the equivalents for ugen(4)'s USB_GET_CONFIG_DESC and USB_GET_FULL_DESC. Help and OK mpi@, jmc@
Diffstat (limited to 'sys/dev/usb')
-rw-r--r--sys/dev/usb/usb.c120
-rw-r--r--sys/dev/usb/usb.h19
-rw-r--r--sys/dev/usb/usbdi.h4
3 files changed, 140 insertions, 3 deletions
diff --git a/sys/dev/usb/usb.c b/sys/dev/usb/usb.c
index 2a5e45c41d6..07566b0c598 100644
--- a/sys/dev/usb/usb.c
+++ b/sys/dev/usb/usb.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: usb.c,v 1.84 2013/03/28 03:58:03 tedu Exp $ */
+/* $OpenBSD: usb.c,v 1.85 2013/04/08 10:34:20 mglocker Exp $ */
/* $NetBSD: usb.c,v 1.77 2003/01/01 00:10:26 thorpej Exp $ */
/*
@@ -499,6 +499,57 @@ usbd_fill_di_task(void *arg)
usbd_fill_deviceinfo(dev, di, 1);
}
+void
+usbd_fill_udc_task(void *arg)
+{
+ struct usb_device_cdesc *udc = (struct usb_device_cdesc *)arg;
+ struct usb_softc *sc;
+ usbd_device_handle dev;
+ int addr = udc->udc_addr;
+ usb_config_descriptor_t *cdesc;
+
+ /* check that the bus and device are still present */
+ if (udc->udc_bus >= usb_cd.cd_ndevs)
+ return;
+ sc = usb_cd.cd_devs[udc->udc_bus];
+ if (sc == NULL)
+ return;
+ dev = sc->sc_bus->devices[udc->udc_addr];
+ if (dev == NULL)
+ return;
+
+ cdesc = usbd_get_cdesc(sc->sc_bus->devices[addr],
+ udc->udc_config_index, 0);
+ if (cdesc == NULL)
+ return;
+ udc->udc_desc = *cdesc;
+ free(cdesc, M_TEMP);
+}
+
+void
+usbd_fill_udf_task(void *arg)
+{
+ struct usb_device_fdesc *udf = (struct usb_device_fdesc *)arg;
+ struct usb_softc *sc;
+ usbd_device_handle dev;
+ int addr = udf->udf_addr;
+ usb_config_descriptor_t *cdesc;
+
+ /* check that the bus and device are still present */
+ if (udf->udf_bus >= usb_cd.cd_ndevs)
+ return;
+ sc = usb_cd.cd_devs[udf->udf_bus];
+ if (sc == NULL)
+ return;
+ dev = sc->sc_bus->devices[udf->udf_addr];
+ if (dev == NULL)
+ return;
+
+ cdesc = usbd_get_cdesc(sc->sc_bus->devices[addr],
+ udf->udf_config_index, &udf->udf_size);
+ udf->udf_data = (char *)cdesc;
+}
+
int
usbioctl(dev_t devt, u_long cmd, caddr_t data, int flag, struct proc *p)
{
@@ -628,6 +679,73 @@ usbioctl(dev_t devt, u_long cmd, caddr_t data, int flag, struct proc *p)
*(struct usb_device_stats *)data = sc->sc_bus->stats;
break;
+ case USB_DEVICE_GET_CDESC:
+ {
+ struct usb_device_cdesc *udc = (struct usb_device_cdesc *)data;
+ int addr = udc->udc_addr;
+ struct usb_task udc_task;
+
+ if (addr < 1 || addr >= USB_MAX_DEVICES)
+ return (EINVAL);
+ if (sc->sc_bus->devices[addr] == NULL)
+ return (ENXIO);
+
+ udc->udc_bus = unit;
+
+ udc->udc_desc.bLength = 0;
+ usb_init_task(&udc_task, usbd_fill_udc_task, udc,
+ USB_TASK_TYPE_GENERIC);
+ usb_add_task(sc->sc_bus->root_hub, &udc_task);
+ usb_wait_task(sc->sc_bus->root_hub, &udc_task);
+ if (udc->udc_desc.bLength == 0)
+ return (EINVAL);
+ break;
+ }
+
+ case USB_DEVICE_GET_FDESC:
+ {
+ struct usb_device_fdesc *udf = (struct usb_device_fdesc *)data;
+ int addr = udf->udf_addr;
+ struct usb_task udf_task;
+ struct usb_device_fdesc save_udf;
+ usb_config_descriptor_t *cdesc;
+ struct iovec iov;
+ struct uio uio;
+ int len, error;
+
+ if (addr < 1 || addr >= USB_MAX_DEVICES)
+ return (EINVAL);
+ if (sc->sc_bus->devices[addr] == NULL)
+ return (ENXIO);
+
+ udf->udf_bus = unit;
+
+ save_udf = *udf;
+ usb_init_task(&udf_task, usbd_fill_udf_task, udf,
+ USB_TASK_TYPE_GENERIC);
+ usb_add_task(sc->sc_bus->root_hub, &udf_task);
+ usb_wait_task(sc->sc_bus->root_hub, &udf_task);
+ len = udf->udf_size;
+ cdesc = (usb_config_descriptor_t *)udf->udf_data;
+ *udf = save_udf;
+ if (cdesc == NULL)
+ return (EINVAL);
+ if (len > udf->udf_size)
+ len = udf->udf_size;
+ iov.iov_base = (caddr_t)udf->udf_data;
+ iov.iov_len = len;
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+ uio.uio_resid = len;
+ uio.uio_offset = 0;
+ uio.uio_segflg = UIO_USERSPACE;
+ uio.uio_rw = UIO_READ;
+ uio.uio_procp = p;
+ error = uiomove((void *)cdesc, len, &uio);
+ free(cdesc, M_TEMP);
+ return (error);
+ }
+
default:
return (EINVAL);
}
diff --git a/sys/dev/usb/usb.h b/sys/dev/usb/usb.h
index bf71960edf7..a889553c302 100644
--- a/sys/dev/usb/usb.h
+++ b/sys/dev/usb/usb.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: usb.h,v 1.42 2013/03/16 09:58:40 mpi Exp $ */
+/* $OpenBSD: usb.h,v 1.43 2013/04/08 10:34:20 mglocker Exp $ */
/* $NetBSD: usb.h,v 1.69 2002/09/22 23:20:50 augustss Exp $ */
/* $FreeBSD: src/sys/dev/usb/usb.h,v 1.14 1999/11/17 22:33:46 n_hibma Exp $ */
@@ -560,6 +560,13 @@ struct usb_config_desc {
usb_config_descriptor_t ucd_desc;
};
+struct usb_device_cdesc {
+ u_int8_t udc_bus;
+ u_int8_t udc_addr; /* device address */
+ int udc_config_index;
+ usb_config_descriptor_t udc_desc;
+};
+
struct usb_interface_desc {
int uid_config_index;
int uid_interface_index;
@@ -581,6 +588,14 @@ struct usb_full_desc {
u_char *ufd_data;
};
+struct usb_device_fdesc {
+ u_int8_t udf_bus;
+ u_int8_t udf_addr; /* device address */
+ int udf_config_index;
+ u_int udf_size;
+ u_char *udf_data;
+};
+
struct usb_string_desc {
int usd_string_index;
int usd_language_id;
@@ -637,6 +652,8 @@ struct usb_device_stats {
#define USB_DISCOVER _IO ('U', 3)
#define USB_DEVICEINFO _IOWR('U', 4, struct usb_device_info)
#define USB_DEVICESTATS _IOR ('U', 5, struct usb_device_stats)
+#define USB_DEVICE_GET_CDESC _IOWR('U', 6, struct usb_device_cdesc)
+#define USB_DEVICE_GET_FDESC _IOWR('U', 7, struct usb_device_fdesc)
/* Generic HID device */
#define USB_GET_REPORT_DESC _IOR ('U', 21, struct usb_ctl_report_desc)
diff --git a/sys/dev/usb/usbdi.h b/sys/dev/usb/usbdi.h
index 0440d55370d..913ec2868be 100644
--- a/sys/dev/usb/usbdi.h
+++ b/sys/dev/usb/usbdi.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: usbdi.h,v 1.43 2013/04/01 19:49:53 mglocker Exp $ */
+/* $OpenBSD: usbdi.h,v 1.44 2013/04/08 10:34:20 mglocker Exp $ */
/* $NetBSD: usbdi.h,v 1.62 2002/07/11 21:14:35 augustss Exp $ */
/* $FreeBSD: src/sys/dev/usb/usbdi.h,v 1.18 1999/11/17 22:33:49 n_hibma Exp $ */
@@ -140,6 +140,8 @@ int usbd_get_no_alts(usb_config_descriptor_t *, int);
usbd_status usbd_get_interface(usbd_interface_handle iface, u_int8_t *aiface);
void usbd_fill_deviceinfo(usbd_device_handle, struct usb_device_info *, int);
void usbd_fill_di_task(void *);
+void usbd_fill_udc_task(void *);
+void usbd_fill_udf_task(void *);
usb_config_descriptor_t *usbd_get_cdesc(usbd_device_handle, int, int *);
int usbd_get_interface_altindex(usbd_interface_handle iface);