diff options
author | Marcus Glocker <mglocker@cvs.openbsd.org> | 2013-04-08 10:34:21 +0000 |
---|---|---|
committer | Marcus Glocker <mglocker@cvs.openbsd.org> | 2013-04-08 10:34:21 +0000 |
commit | ddec2027d9edb59dff664ea02c5ecabd791c2981 (patch) | |
tree | 84034339ca710df9359bf58209f3dd920f811e73 | |
parent | 5285fafd3b88f9e11cb286d9449e37ec35fee719 (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@
-rw-r--r-- | share/man/man4/usb.4 | 71 | ||||
-rw-r--r-- | sys/dev/usb/usb.c | 120 | ||||
-rw-r--r-- | sys/dev/usb/usb.h | 19 | ||||
-rw-r--r-- | sys/dev/usb/usbdi.h | 4 |
4 files changed, 209 insertions, 5 deletions
diff --git a/share/man/man4/usb.4 b/share/man/man4/usb.4 index c1c26f475c7..19c0e24517f 100644 --- a/share/man/man4/usb.4 +++ b/share/man/man4/usb.4 @@ -1,4 +1,4 @@ -.\" $OpenBSD: usb.4,v 1.136 2012/12/31 04:24:34 miod Exp $ +.\" $OpenBSD: usb.4,v 1.137 2013/04/08 10:34:20 mglocker Exp $ .\" $NetBSD: usb.4,v 1.15 1999/07/29 14:20:32 augustss Exp $ .\" .\" Copyright (c) 1999 The NetBSD Foundation, Inc. @@ -28,7 +28,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd $Mdocdate: December 31 2012 $ +.Dd $Mdocdate: April 8 2013 $ .Dt USB 4 .Os .Sh NAME @@ -508,6 +508,73 @@ field is indexed by the transfer kind, i.e.\& .Dv UE_* , and indicates how many transfers of each kind have been completed by the controller. +.It Dv USB_DEVICE_GET_CDESC (struct usb_device_cdesc) +This command can be used to retrieve the configuration descriptor for the +given configuration of a device on the bus. +The +.Va udi_addr +field needs to be filled with the bus device address. +The +.Va udc_config_index +field needs to be filled with the configuration index for the +relevant configuration descriptor. +For convenience the current configuration can be specified by +.Dv USB_CURRENT_CONFIG_INDEX : +.Bd -literal +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; +}; +.Ed +.Pp +The +.Va udc_bus +field contains the device unit number. +.Pp +The +.Va udc_desc +field contains the configuration descriptor structure. +.It Dv USB_DEVICE_GET_FDESC (struct usb_device_fdesc) +This command can be used to retrieve all descriptors for the +given configuration of a device on the bus. +The +.Va udf_addr +field needs to be filled with the bus device address. +The +.Va udf_config_index +field needs to be filled with the configuration index for the +relevant configuration descriptor. +For convenience the current configuration can be specified by +.Dv USB_CURRENT_CONFIG_INDEX . +The +.Va udf_data +field needs to point to a memory area of the size given in the +.Va udf_size +field. +The proper size can be determined by first issuing a +.Dv USB_DEVICE_GET_CDESC +command and inspecting the +.Va wTotalLength +field: +.Bd -literal +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; +}; +.Ed +.Pp +The +.Va udf_bus +field contains the device unit number. +.Pp +The +.Va udf_data +field contains all descriptors. .It Dv USB_REQUEST Fa "struct usb_ctl_request *" This command can be used to execute arbitrary requests on the control pipe. This is 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); |