Home | History | Annotate | Line # | Download | only in usb
      1  1.16       mrg /* $NetBSD: usbroothub.c,v 1.16 2024/02/04 05:43:06 mrg Exp $ */
      2   1.2     skrll 
      3   1.2     skrll /*-
      4   1.2     skrll  * Copyright (c) 1998, 2004, 2011, 2012 The NetBSD Foundation, Inc.
      5   1.2     skrll  * All rights reserved.
      6   1.2     skrll  *
      7   1.2     skrll  * This code is derived from software contributed to The NetBSD Foundation
      8   1.2     skrll  * by Lennart Augustsson (lennart (at) augustsson.net) at
      9   1.2     skrll  * Carlstedt Research & Technology, Jared D. McNeill (jmcneill (at) invisible.ca),
     10  1.16       mrg  * Matthew R. Green (mrg (at) eterna23.net) and Nick Hudson.
     11   1.2     skrll  *
     12   1.2     skrll  * Redistribution and use in source and binary forms, with or without
     13   1.2     skrll  * modification, are permitted provided that the following conditions
     14   1.2     skrll  * are met:
     15   1.2     skrll  * 1. Redistributions of source code must retain the above copyright
     16   1.2     skrll  *    notice, this list of conditions and the following disclaimer.
     17   1.2     skrll  * 2. Redistributions in binary form must reproduce the above copyright
     18   1.2     skrll  *    notice, this list of conditions and the following disclaimer in the
     19   1.2     skrll  *    documentation and/or other materials provided with the distribution.
     20   1.2     skrll  *
     21   1.2     skrll  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     22   1.2     skrll  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     23   1.2     skrll  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     24   1.2     skrll  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     25   1.2     skrll  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     26   1.2     skrll  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     27   1.2     skrll  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     28   1.2     skrll  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     29   1.2     skrll  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     30   1.2     skrll  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     31   1.2     skrll  * POSSIBILITY OF SUCH DAMAGE.
     32   1.2     skrll  */
     33   1.2     skrll 
     34   1.2     skrll /*
     35   1.2     skrll  * Copyright (c) 2008
     36   1.2     skrll  *	Matthias Drochner.  All rights reserved.
     37   1.2     skrll  *
     38   1.2     skrll  * Redistribution and use in source and binary forms, with or without
     39   1.2     skrll  * modification, are permitted provided that the following conditions
     40   1.2     skrll  * are met:
     41   1.2     skrll  * 1. Redistributions of source code must retain the above copyright
     42   1.2     skrll  *    notice, this list of conditions and the following disclaimer.
     43   1.2     skrll  * 2. Redistributions in binary form must reproduce the above copyright
     44   1.2     skrll  *    notice, this list of conditions and the following disclaimer in the
     45   1.2     skrll  *    documentation and/or other materials provided with the distribution.
     46   1.2     skrll  *
     47   1.2     skrll  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     48   1.2     skrll  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     49   1.2     skrll  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     50   1.2     skrll  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     51   1.2     skrll  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     52   1.2     skrll  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     53   1.2     skrll  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     54   1.2     skrll  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     55   1.2     skrll  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     56   1.2     skrll  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     57   1.2     skrll  *
     58   1.2     skrll  */
     59   1.2     skrll 
     60   1.6       rin #include <sys/cdefs.h>
     61  1.16       mrg __KERNEL_RCSID(0, "$NetBSD: usbroothub.c,v 1.16 2024/02/04 05:43:06 mrg Exp $");
     62  1.10     skrll 
     63  1.10     skrll #include <sys/param.h>
     64  1.10     skrll #include <sys/systm.h>		/* for ostype */
     65   1.6       rin 
     66   1.2     skrll #include <dev/usb/usb.h>
     67   1.2     skrll #include <dev/usb/usbdi.h>
     68   1.2     skrll #include <dev/usb/usbdivar.h>
     69   1.2     skrll #include <dev/usb/usbroothub.h>
     70   1.2     skrll #include <dev/usb/usbhist.h>
     71   1.2     skrll 
     72   1.2     skrll /* helper functions for USB root hub emulation */
     73   1.2     skrll 
     74   1.2     skrll static usbd_status	roothub_ctrl_transfer(struct usbd_xfer *);
     75   1.2     skrll static usbd_status	roothub_ctrl_start(struct usbd_xfer *);
     76   1.2     skrll static void		roothub_ctrl_abort(struct usbd_xfer *);
     77   1.2     skrll static void		roothub_ctrl_close(struct usbd_pipe *);
     78   1.2     skrll static void		roothub_ctrl_done(struct usbd_xfer *);
     79   1.2     skrll static void		roothub_noop(struct usbd_pipe *pipe);
     80   1.2     skrll 
     81   1.2     skrll const struct usbd_pipe_methods roothub_ctrl_methods = {
     82   1.2     skrll 	.upm_transfer =	roothub_ctrl_transfer,
     83   1.2     skrll 	.upm_start =	roothub_ctrl_start,
     84   1.2     skrll 	.upm_abort =	roothub_ctrl_abort,
     85   1.2     skrll 	.upm_close =	roothub_ctrl_close,
     86   1.2     skrll 	.upm_cleartoggle =	roothub_noop,
     87   1.2     skrll 	.upm_done =	roothub_ctrl_done,
     88   1.2     skrll };
     89   1.2     skrll 
     90   1.2     skrll int
     91   1.2     skrll usb_makestrdesc(usb_string_descriptor_t *p, int l, const char *s)
     92   1.2     skrll {
     93   1.2     skrll 	int i;
     94   1.2     skrll 
     95   1.2     skrll 	if (l == 0)
     96   1.2     skrll 		return 0;
     97   1.2     skrll 	p->bLength = 2 * strlen(s) + 2;
     98   1.2     skrll 	if (l == 1)
     99   1.2     skrll 		return 1;
    100   1.2     skrll 	p->bDescriptorType = UDESC_STRING;
    101   1.2     skrll 	l -= 2;
    102   1.2     skrll 	/* poor man's utf-16le conversion */
    103   1.2     skrll 	for (i = 0; s[i] && l > 1; i++, l -= 2)
    104   1.2     skrll 		USETW2(p->bString[i], 0, s[i]);
    105   1.2     skrll 	return 2 * i + 2;
    106   1.2     skrll }
    107   1.2     skrll 
    108   1.2     skrll int
    109   1.2     skrll usb_makelangtbl(usb_string_descriptor_t *p, int l)
    110   1.2     skrll {
    111   1.2     skrll 
    112   1.2     skrll 	if (l == 0)
    113   1.2     skrll 		return 0;
    114   1.2     skrll 	p->bLength = 4;
    115   1.2     skrll 	if (l == 1)
    116   1.2     skrll 		return 1;
    117   1.2     skrll 	p->bDescriptorType = UDESC_STRING;
    118   1.2     skrll 	if (l < 4)
    119   1.2     skrll 		return 2;
    120   1.2     skrll 	USETW(p->bString[0], 0x0409); /* english/US */
    121   1.2     skrll 	return 4;
    122   1.2     skrll }
    123   1.2     skrll 
    124   1.2     skrll /*
    125   1.2     skrll  * Data structures and routines to emulate the root hub.
    126   1.2     skrll  */
    127   1.2     skrll static const usb_device_descriptor_t usbroothub_devd1 = {
    128   1.2     skrll 	.bLength = sizeof(usb_device_descriptor_t),
    129   1.2     skrll 	.bDescriptorType = UDESC_DEVICE,
    130   1.2     skrll 	.bcdUSB = {0x00, 0x01},
    131   1.2     skrll 	.bDeviceClass = UDCLASS_HUB,
    132   1.2     skrll 	.bDeviceSubClass = UDSUBCLASS_HUB,
    133   1.2     skrll 	.bDeviceProtocol = UDPROTO_FSHUB,
    134   1.2     skrll 	.bMaxPacketSize = 64,
    135   1.2     skrll 	.idVendor = {0},
    136   1.2     skrll 	.idProduct = {0},
    137   1.2     skrll 	.bcdDevice = {0x00, 0x01},
    138   1.2     skrll 	.iManufacturer = 1,
    139   1.2     skrll 	.iProduct = 2,
    140   1.2     skrll 	.iSerialNumber = 0,
    141   1.2     skrll 	.bNumConfigurations = 1
    142   1.2     skrll };
    143   1.2     skrll 
    144   1.2     skrll static const struct usb_roothub_descriptors usbroothub_confd1 = {
    145   1.2     skrll 	.urh_confd = {
    146   1.2     skrll 		.bLength = USB_CONFIG_DESCRIPTOR_SIZE,
    147   1.2     skrll 		.bDescriptorType = UDESC_CONFIG,
    148   1.2     skrll 		.wTotalLength = USETWD(sizeof(usbroothub_confd1)),
    149   1.2     skrll 		.bNumInterface = 1,
    150   1.2     skrll 		.bConfigurationValue = 1,
    151   1.2     skrll 		.iConfiguration = 0,
    152   1.2     skrll 		.bmAttributes = UC_ATTR_MBO | UC_SELF_POWERED,
    153   1.2     skrll 		.bMaxPower = 0,
    154   1.2     skrll 	},
    155   1.2     skrll 	.urh_ifcd = {
    156   1.2     skrll 		.bLength = USB_INTERFACE_DESCRIPTOR_SIZE,
    157   1.2     skrll 		.bDescriptorType = UDESC_INTERFACE,
    158   1.2     skrll 		.bInterfaceNumber = 0,
    159   1.2     skrll 		.bAlternateSetting = 0,
    160   1.2     skrll 		.bNumEndpoints = 1,
    161   1.2     skrll 		.bInterfaceClass = UICLASS_HUB,
    162   1.2     skrll 		.bInterfaceSubClass = UISUBCLASS_HUB,
    163   1.2     skrll 		.bInterfaceProtocol = UIPROTO_FSHUB,
    164   1.2     skrll 		.iInterface = 0
    165   1.2     skrll 	},
    166   1.2     skrll 	.urh_endpd = {
    167   1.2     skrll 		.bLength = USB_ENDPOINT_DESCRIPTOR_SIZE,
    168   1.2     skrll 		.bDescriptorType = UDESC_ENDPOINT,
    169   1.2     skrll 		.bEndpointAddress = UE_DIR_IN | USBROOTHUB_INTR_ENDPT,
    170   1.2     skrll 		.bmAttributes = UE_INTERRUPT,
    171   1.2     skrll 		.wMaxPacketSize = USETWD(8),			/* max packet */
    172   1.2     skrll 		.bInterval = 255,
    173   1.2     skrll 	},
    174   1.2     skrll };
    175   1.2     skrll 
    176   1.4     skrll /* USB 3.0 10.15.1 */
    177   1.4     skrll static const usb_device_descriptor_t usbroothub_devd3 = {
    178   1.4     skrll 	.bLength = sizeof(usb_device_descriptor_t),
    179   1.4     skrll 	.bDescriptorType = UDESC_DEVICE,
    180   1.4     skrll 	.bcdUSB = {0x00, 0x03},
    181   1.4     skrll 	.bDeviceClass = UDCLASS_HUB,
    182   1.4     skrll 	.bDeviceSubClass = UDSUBCLASS_HUB,
    183   1.4     skrll 	.bDeviceProtocol = UDPROTO_SSHUB,
    184   1.4     skrll 	.bMaxPacketSize = 9,
    185   1.4     skrll 	.idVendor = {0},
    186   1.4     skrll 	.idProduct = {0},
    187   1.4     skrll 	.bcdDevice = {0x00, 0x01},
    188   1.4     skrll 	.iManufacturer = 1,
    189   1.4     skrll 	.iProduct = 2,
    190   1.4     skrll 	.iSerialNumber = 0,
    191   1.4     skrll 	.bNumConfigurations = 1
    192   1.4     skrll };
    193   1.4     skrll 
    194   1.2     skrll static const usb_device_descriptor_t usbroothub_devd2 = {
    195   1.2     skrll 	.bLength = sizeof(usb_device_descriptor_t),
    196   1.2     skrll 	.bDescriptorType = UDESC_DEVICE,
    197   1.2     skrll 	.bcdUSB = {0x00, 0x02},
    198   1.2     skrll 	.bDeviceClass = UDCLASS_HUB,
    199   1.2     skrll 	.bDeviceSubClass = UDSUBCLASS_HUB,
    200   1.2     skrll 	.bDeviceProtocol = UDPROTO_HSHUBSTT,
    201   1.2     skrll 	.bMaxPacketSize = 64,
    202   1.2     skrll 	.idVendor = {0},
    203   1.2     skrll 	.idProduct = {0},
    204   1.2     skrll 	.bcdDevice = {0x00, 0x01},
    205   1.2     skrll 	.iManufacturer = 1,
    206   1.2     skrll 	.iProduct = 2,
    207   1.2     skrll 	.iSerialNumber = 0,
    208   1.2     skrll 	.bNumConfigurations = 1
    209   1.2     skrll };
    210   1.2     skrll 
    211   1.2     skrll static const usb_device_qualifier_t usbroothub_odevd2 = {
    212   1.2     skrll 	.bLength = USB_DEVICE_QUALIFIER_SIZE,
    213   1.2     skrll 	.bDescriptorType = UDESC_DEVICE_QUALIFIER,
    214   1.2     skrll 	.bcdUSB = {0x00, 0x02},
    215   1.2     skrll 	.bDeviceClass = UDCLASS_HUB,
    216   1.2     skrll 	.bDeviceSubClass = UDSUBCLASS_HUB,
    217   1.2     skrll 	.bDeviceProtocol = UDPROTO_FSHUB,
    218   1.2     skrll 	.bMaxPacketSize0 = 64,
    219   1.2     skrll 	.bNumConfigurations = 1,
    220   1.2     skrll };
    221   1.2     skrll 
    222   1.2     skrll static const struct usb_roothub_descriptors usbroothub_confd2 = {
    223   1.2     skrll 	.urh_confd = {
    224   1.2     skrll 		.bLength = USB_CONFIG_DESCRIPTOR_SIZE,
    225   1.2     skrll 		.bDescriptorType = UDESC_CONFIG,
    226   1.2     skrll 		.wTotalLength = USETWD(sizeof(usbroothub_confd2)),
    227   1.2     skrll 		.bNumInterface = 1,
    228   1.2     skrll 		.bConfigurationValue = 1,
    229   1.2     skrll 		.iConfiguration = 0,
    230   1.2     skrll 		.bmAttributes = UC_ATTR_MBO | UC_SELF_POWERED,
    231   1.2     skrll 		.bMaxPower = 0,
    232   1.2     skrll 	},
    233   1.2     skrll 	.urh_ifcd = {
    234   1.2     skrll 		.bLength = USB_INTERFACE_DESCRIPTOR_SIZE,
    235   1.2     skrll 		.bDescriptorType = UDESC_INTERFACE,
    236   1.2     skrll 		.bInterfaceNumber = 0,
    237   1.2     skrll 		.bAlternateSetting = 0,
    238   1.2     skrll 		.bNumEndpoints = 1,
    239   1.2     skrll 		.bInterfaceClass = UICLASS_HUB,
    240   1.2     skrll 		.bInterfaceSubClass = UISUBCLASS_HUB,
    241   1.2     skrll 		.bInterfaceProtocol = UIPROTO_HSHUBSTT,
    242   1.2     skrll 		.iInterface = 0
    243   1.2     skrll 	},
    244   1.2     skrll 	.urh_endpd = {
    245   1.2     skrll 		.bLength = USB_ENDPOINT_DESCRIPTOR_SIZE,
    246   1.2     skrll 		.bDescriptorType = UDESC_ENDPOINT,
    247   1.2     skrll 		.bEndpointAddress = UE_DIR_IN | USBROOTHUB_INTR_ENDPT,
    248   1.2     skrll 		.bmAttributes = UE_INTERRUPT,
    249   1.2     skrll 		.wMaxPacketSize = USETWD(8),			/* max packet */
    250   1.2     skrll 		.bInterval = 12,
    251   1.2     skrll 	},
    252   1.2     skrll };
    253   1.2     skrll 
    254   1.4     skrll static const struct usb3_roothub_descriptors usbroothub_confd3 = {
    255   1.4     skrll 	.urh_confd = {
    256   1.4     skrll 		.bLength = USB_CONFIG_DESCRIPTOR_SIZE,
    257   1.4     skrll 		.bDescriptorType = UDESC_CONFIG,
    258   1.4     skrll 		.wTotalLength = USETWD(sizeof(usbroothub_confd3)),
    259   1.4     skrll 		.bNumInterface = 1,
    260   1.4     skrll 		.bConfigurationValue = 1,
    261   1.4     skrll 		.iConfiguration = 0,
    262   1.4     skrll 		.bmAttributes = UC_SELF_POWERED,		/* 10.13.1 */
    263   1.4     skrll 		.bMaxPower = 0,
    264   1.4     skrll 	},
    265   1.4     skrll 	.urh_ifcd = {
    266   1.4     skrll 		.bLength = USB_INTERFACE_DESCRIPTOR_SIZE,
    267   1.4     skrll 		.bDescriptorType = UDESC_INTERFACE,
    268   1.4     skrll 		.bInterfaceNumber = 0,
    269   1.4     skrll 		.bAlternateSetting = 0,
    270   1.4     skrll 		.bNumEndpoints = 1,
    271   1.4     skrll 		.bInterfaceClass = UICLASS_HUB,
    272   1.4     skrll 		.bInterfaceSubClass = UISUBCLASS_HUB,
    273   1.4     skrll 		.bInterfaceProtocol = 0,			/* UIPROTO_SSHUB ??? */
    274   1.4     skrll 		.iInterface = 0
    275   1.4     skrll 	},
    276   1.4     skrll 	.urh_endpd = {
    277   1.4     skrll 		.bLength = USB_ENDPOINT_DESCRIPTOR_SIZE,
    278   1.4     skrll 		.bDescriptorType = UDESC_ENDPOINT,
    279   1.4     skrll 		.bEndpointAddress = UE_DIR_IN | USBROOTHUB_INTR_ENDPT,
    280   1.4     skrll 		.bmAttributes = UE_INTERRUPT,
    281   1.4     skrll 		.wMaxPacketSize = USETWD(2),			/* max packet */
    282   1.4     skrll 		.bInterval = 8,
    283   1.4     skrll 	},
    284   1.4     skrll 	.urh_endpssd = {
    285   1.4     skrll 		.bLength = USB_ENDPOINT_SS_COMP_DESCRIPTOR_SIZE,
    286   1.4     skrll 		.bDescriptorType = UDESC_ENDPOINT_SS_COMP,
    287   1.4     skrll 		.bMaxBurst = 0,
    288   1.4     skrll 		.bmAttributes = 0,
    289   1.4     skrll 		.wBytesPerInterval = USETWD(2)
    290   1.4     skrll 	},
    291   1.4     skrll };
    292   1.4     skrll 
    293   1.4     skrll static const struct usb3_roothub_bos_descriptors usbroothub_bosd3 = {
    294   1.4     skrll 	.urh_bosd = {
    295   1.4     skrll 		.bLength = USB_BOS_DESCRIPTOR_SIZE,
    296   1.4     skrll 		.bDescriptorType = UDESC_BOS,
    297   1.4     skrll 		.wTotalLength = USETWD(sizeof(usbroothub_bosd3)),
    298   1.4     skrll 		.bNumDeviceCaps = 3,
    299   1.4     skrll 	},
    300   1.4     skrll 	/* 9.6.2.1 USB 2.0 Extension */
    301   1.4     skrll 	.urh_usb2extd = {
    302   1.4     skrll 		.bLength = USB_DEVCAP_USB2EXT_DESCRIPTOR_SIZE,
    303   1.4     skrll 		.bDescriptorType = 1,
    304   1.4     skrll 		.bDevCapabilityType = 2,
    305   1.4     skrll 		.bmAttributes[0] = 2,
    306   1.4     skrll 	},
    307   1.4     skrll 	/* 9.6.2.2 Superspeed device capability */
    308   1.4     skrll 	.urh_ssd = {
    309   1.4     skrll 		.bLength = USB_DEVCAP_SS_DESCRIPTOR_SIZE,
    310   1.4     skrll 		.bDescriptorType = UDESC_DEVICE_CAPABILITY,
    311   1.4     skrll 		.bDevCapabilityType = USB_DEVCAP_SUPER_SPEED,
    312   1.4     skrll 		.bmAttributes = 0,	/* USB_DEVCAP_SS_LTM */
    313   1.4     skrll 		.wSpeedsSupported = USETWD(
    314   1.4     skrll 		    USB_DEVCAP_SS_SPEED_LS | USB_DEVCAP_SS_SPEED_FS |
    315   1.4     skrll 		    USB_DEVCAP_SS_SPEED_HS | USB_DEVCAP_SS_SPEED_SS),
    316   1.4     skrll 		.bFunctionalitySupport = 8,		/* SS is 3, i.e. 1 << 3? */
    317   1.4     skrll 		.bU1DevExitLat = 255,		/* Dummy... 0? */
    318   1.4     skrll 		.wU2DevExitLat = USETWD(8),	/* Also dummy... 0? */
    319   1.4     skrll 	},
    320   1.4     skrll 	/* 9.6.2.3 Container ID  - see RFC 4122 */
    321   1.4     skrll 	.urh_containerd = {
    322   1.4     skrll 		.bLength = USB_DEVCAP_CONTAINER_ID_DESCRIPTOR_SIZE,
    323   1.4     skrll 		.bDescriptorType = 1,
    324   1.4     skrll 		.bDevCapabilityType = 4,
    325   1.4     skrll 		.bReserved = 0,
    326   1.4     skrll 		// ContainerID will be zero
    327   1.4     skrll 	},
    328   1.4     skrll };
    329   1.4     skrll 
    330   1.2     skrll static const usb_hub_descriptor_t usbroothub_hubd = {
    331   1.2     skrll 	.bDescLength = USB_HUB_DESCRIPTOR_SIZE,
    332   1.2     skrll 	.bDescriptorType = UDESC_HUB,
    333   1.2     skrll 	.bNbrPorts = 1,
    334   1.2     skrll 	.wHubCharacteristics = USETWD(UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL),
    335   1.2     skrll 	.bPwrOn2PwrGood = 50,
    336   1.2     skrll 	.bHubContrCurrent = 0,
    337   1.2     skrll 	.DeviceRemovable = {0},		/* port is removable */
    338   1.2     skrll };
    339   1.2     skrll 
    340   1.2     skrll /*
    341   1.2     skrll  * Simulate a hardware hub by handling all the necessary requests.
    342   1.2     skrll  */
    343   1.2     skrll usbd_status
    344   1.2     skrll roothub_ctrl_transfer(struct usbd_xfer *xfer)
    345   1.2     skrll {
    346   1.2     skrll 
    347   1.2     skrll 	/* Pipe isn't running, start first */
    348   1.2     skrll 	return roothub_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
    349   1.2     skrll }
    350   1.2     skrll 
    351   1.2     skrll static usbd_status
    352   1.2     skrll roothub_ctrl_start(struct usbd_xfer *xfer)
    353   1.2     skrll {
    354   1.2     skrll 	struct usbd_pipe *pipe = xfer->ux_pipe;
    355   1.2     skrll 	struct usbd_bus *bus = pipe->up_dev->ud_bus;
    356   1.2     skrll 	usb_device_request_t *req;
    357   1.2     skrll 	usbd_status err = USBD_IOERROR;		/* XXX STALL? */
    358   1.2     skrll 	uint16_t len, value;
    359   1.9       mrg 	int buflen, actlen = -1;
    360   1.2     skrll 	void *buf;
    361   1.2     skrll 
    362   1.9       mrg 	USBHIST_FUNC();
    363   1.2     skrll 
    364  1.13  riastrad 	/*
    365  1.13  riastrad 	 * XXX Should really assert pipe lock, in case ever have
    366  1.13  riastrad 	 * per-pipe locking instead of using the bus lock for all
    367  1.13  riastrad 	 * pipes.
    368  1.13  riastrad 	 */
    369  1.13  riastrad 	KASSERT(bus->ub_usepolling || mutex_owned(bus->ub_lock));
    370  1.13  riastrad 
    371  1.15  riastrad 	/* Roothub xfers are serialized through the pipe.  */
    372  1.15  riastrad 	KASSERTMSG(bus->ub_rhxfer == NULL, "rhxfer=%p", bus->ub_rhxfer);
    373  1.15  riastrad 
    374   1.2     skrll 	KASSERT(xfer->ux_rqflags & URQ_REQUEST);
    375   1.2     skrll 	req = &xfer->ux_request;
    376   1.2     skrll 
    377   1.2     skrll 	len = UGETW(req->wLength);
    378   1.2     skrll 	value = UGETW(req->wValue);
    379   1.2     skrll 
    380   1.9       mrg 	USBHIST_CALLARGS(usbdebug, "type=%#jx request=%#jx len=%#jx value=%#jx",
    381   1.9       mrg 	    req->bmRequestType, req->bRequest, len, value);
    382   1.9       mrg 
    383   1.2     skrll 	buf = len ? usbd_get_buffer(xfer) : NULL;
    384   1.2     skrll 	buflen = 0;
    385   1.2     skrll 
    386   1.2     skrll #define C(x,y) ((x) | ((y) << 8))
    387   1.2     skrll 	switch (C(req->bRequest, req->bmRequestType)) {
    388   1.2     skrll 	case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE):
    389   1.2     skrll 	case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE):
    390   1.2     skrll 	case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT):
    391   1.2     skrll 		/*
    392   1.2     skrll 		 * DEVICE_REMOTE_WAKEUP and ENDPOINT_HALT are no-ops
    393   1.2     skrll 		 * for the integrated root hub.
    394   1.2     skrll 		 */
    395   1.2     skrll 		break;
    396   1.2     skrll 	case C(UR_GET_CONFIG, UT_READ_DEVICE):
    397   1.2     skrll 		if (len > 0) {
    398   1.2     skrll 			uint8_t *out = buf;
    399   1.2     skrll 
    400   1.2     skrll 			*out = bus->ub_rhconf;
    401   1.2     skrll 			buflen = sizeof(*out);
    402   1.2     skrll 		}
    403   1.2     skrll 		break;
    404   1.2     skrll 	case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE):
    405   1.3  pgoyette 		USBHIST_LOG(usbdebug, "wValue=%#4jx", value, 0, 0, 0);
    406   1.2     skrll 
    407   1.2     skrll 		if (len == 0)
    408   1.2     skrll 			break;
    409   1.2     skrll 		switch (value) {
    410   1.2     skrll 		case C(0, UDESC_DEVICE):
    411   1.4     skrll 			if (bus->ub_revision >= USBREV_3_0) {
    412   1.7  riastrad 				buflen = uimin(len, sizeof(usbroothub_devd3));
    413   1.4     skrll 				memcpy(buf, &usbroothub_devd3, buflen);
    414   1.4     skrll 			} else if (bus->ub_revision == USBREV_2_0) {
    415   1.7  riastrad 				buflen = uimin(len, sizeof(usbroothub_devd2));
    416   1.2     skrll 				memcpy(buf, &usbroothub_devd2, buflen);
    417   1.2     skrll 			} else {
    418   1.7  riastrad 				buflen = uimin(len, sizeof(usbroothub_devd1));
    419   1.2     skrll 				memcpy(buf, &usbroothub_devd1, buflen);
    420   1.2     skrll 			}
    421   1.2     skrll 			break;
    422   1.2     skrll 		case C(0, UDESC_CONFIG):
    423   1.4     skrll 			if (bus->ub_revision >= USBREV_3_0) {
    424   1.7  riastrad 				buflen = uimin(len, sizeof(usbroothub_confd3));
    425   1.4     skrll 				memcpy(buf, &usbroothub_confd3, buflen);
    426   1.4     skrll 			} else if (bus->ub_revision == USBREV_2_0) {
    427   1.7  riastrad 				buflen = uimin(len, sizeof(usbroothub_confd2));
    428   1.2     skrll 				memcpy(buf, &usbroothub_confd2, buflen);
    429   1.2     skrll 			} else {
    430   1.7  riastrad 				buflen = uimin(len, sizeof(usbroothub_confd1));
    431   1.2     skrll 				memcpy(buf, &usbroothub_confd1, buflen);
    432   1.2     skrll 			}
    433   1.2     skrll 			break;
    434   1.2     skrll 		case C(0, UDESC_DEVICE_QUALIFIER):
    435   1.2     skrll 			if (bus->ub_revision == USBREV_2_0) {
    436   1.2     skrll 				/*
    437   1.2     skrll 				 * We can't really operate at another speed,
    438   1.2     skrll 				 * but the spec says we need this descriptor.
    439   1.2     skrll 				 */
    440   1.7  riastrad 				buflen = uimin(len, sizeof(usbroothub_odevd2));
    441   1.2     skrll 				memcpy(buf, &usbroothub_odevd2, buflen);
    442   1.2     skrll 			} else
    443   1.2     skrll 				goto fail;
    444   1.2     skrll 			break;
    445   1.2     skrll 		case C(0, UDESC_OTHER_SPEED_CONFIGURATION):
    446   1.2     skrll 			if (bus->ub_revision == USBREV_2_0) {
    447   1.2     skrll 				struct usb_roothub_descriptors confd;
    448   1.2     skrll 
    449   1.2     skrll 				/*
    450   1.2     skrll 				 * We can't really operate at another speed,
    451   1.2     skrll 				 * but the spec says we need this descriptor.
    452   1.2     skrll 				 */
    453   1.7  riastrad 				buflen = uimin(len, sizeof(usbroothub_confd2));
    454   1.2     skrll 				memcpy(&confd, &usbroothub_confd2, buflen);
    455   1.2     skrll 				confd.urh_confd.bDescriptorType =
    456   1.2     skrll 				    UDESC_OTHER_SPEED_CONFIGURATION;
    457   1.2     skrll 				memcpy(buf, &confd, buflen);
    458   1.2     skrll 			} else
    459   1.2     skrll 				goto fail;
    460   1.2     skrll 			break;
    461   1.4     skrll 		case C(0, UDESC_BOS):
    462   1.4     skrll 			if (bus->ub_revision >= USBREV_3_0) {
    463   1.7  riastrad 				buflen = uimin(len, sizeof(usbroothub_bosd3));
    464   1.4     skrll 				memcpy(buf, &usbroothub_bosd3, buflen);
    465   1.4     skrll 			} else
    466   1.4     skrll 				goto fail;
    467   1.4     skrll 			break;
    468   1.2     skrll #define sd ((usb_string_descriptor_t *)buf)
    469   1.2     skrll 		case C(0, UDESC_STRING):
    470   1.2     skrll 			/* Language table */
    471   1.2     skrll 			buflen = usb_makelangtbl(sd, len);
    472   1.2     skrll 			break;
    473   1.2     skrll 		case C(1, UDESC_STRING):
    474   1.2     skrll 			/* Vendor */
    475   1.5  jakllsch 			buflen = usb_makestrdesc(sd, len, ostype);
    476   1.2     skrll 			break;
    477   1.2     skrll 		case C(2, UDESC_STRING):
    478   1.2     skrll 			/* Product */
    479   1.2     skrll 			buflen = usb_makestrdesc(sd, len, "Root hub");
    480   1.2     skrll 			break;
    481   1.2     skrll #undef sd
    482   1.2     skrll 		default:
    483   1.2     skrll 			/* Default to error */
    484   1.2     skrll 			buflen = -1;
    485   1.2     skrll 		}
    486   1.2     skrll 		break;
    487   1.2     skrll 	case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE):
    488   1.7  riastrad 		buflen = uimin(len, sizeof(usbroothub_hubd));
    489   1.2     skrll 		memcpy(buf, &usbroothub_hubd, buflen);
    490   1.2     skrll 		break;
    491   1.2     skrll 	case C(UR_GET_INTERFACE, UT_READ_INTERFACE):
    492   1.2     skrll 		/* Get Interface, 9.4.4 */
    493   1.2     skrll 		if (len > 0) {
    494   1.2     skrll 			uint8_t *out = buf;
    495   1.2     skrll 
    496   1.2     skrll 			*out = 0;
    497   1.2     skrll 			buflen = sizeof(*out);
    498   1.2     skrll 		}
    499   1.2     skrll 		break;
    500   1.2     skrll 	case C(UR_GET_STATUS, UT_READ_DEVICE):
    501   1.2     skrll 		/* Get Status from device, 9.4.5 */
    502   1.2     skrll 		if (len > 1) {
    503   1.2     skrll 			usb_status_t *out = buf;
    504   1.2     skrll 
    505   1.2     skrll 			USETW(out->wStatus, UDS_SELF_POWERED);
    506   1.2     skrll 			buflen = sizeof(*out);
    507   1.2     skrll 		}
    508   1.2     skrll 		break;
    509   1.2     skrll 	case C(UR_GET_STATUS, UT_READ_INTERFACE):
    510   1.2     skrll 	case C(UR_GET_STATUS, UT_READ_ENDPOINT):
    511   1.2     skrll 		/* Get Status from interface, endpoint, 9.4.5 */
    512   1.2     skrll 		if (len > 1) {
    513   1.2     skrll 			usb_status_t *out = buf;
    514   1.2     skrll 
    515   1.2     skrll 			USETW(out->wStatus, 0);
    516   1.2     skrll 			buflen = sizeof(*out);
    517   1.2     skrll 		}
    518   1.2     skrll 		break;
    519   1.2     skrll 	case C(UR_SET_ADDRESS, UT_WRITE_DEVICE):
    520   1.2     skrll 		/* Set Address, 9.4.6 */
    521   1.3  pgoyette 		USBHIST_LOG(usbdebug, "UR_SET_ADDRESS, UT_WRITE_DEVICE: "
    522   1.3  pgoyette 		    "addr %jd", value, 0, 0, 0);
    523   1.2     skrll 		if (value >= USB_MAX_DEVICES) {
    524   1.2     skrll 			goto fail;
    525   1.2     skrll 		}
    526   1.2     skrll 		bus->ub_rhaddr = value;
    527   1.2     skrll 		break;
    528   1.2     skrll 	case C(UR_SET_CONFIG, UT_WRITE_DEVICE):
    529   1.2     skrll 		/* Set Configuration, 9.4.7 */
    530   1.2     skrll 		if (value != 0 && value != 1) {
    531   1.2     skrll 			goto fail;
    532   1.2     skrll 		}
    533   1.2     skrll 		bus->ub_rhconf = value;
    534   1.2     skrll 		break;
    535   1.2     skrll 	case C(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE):
    536   1.2     skrll 		/* Set Descriptor, 9.4.8, not supported */
    537   1.2     skrll 		break;
    538   1.2     skrll 	case C(UR_SET_FEATURE, UT_WRITE_DEVICE):
    539   1.2     skrll 	case C(UR_SET_FEATURE, UT_WRITE_INTERFACE):
    540   1.2     skrll 	case C(UR_SET_FEATURE, UT_WRITE_ENDPOINT):
    541   1.2     skrll 		/* Set Feature, 9.4.9, not supported */
    542   1.2     skrll 		goto fail;
    543   1.2     skrll 	case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE):
    544   1.2     skrll 		/* Set Interface, 9.4.10, not supported */
    545   1.2     skrll 		break;
    546   1.2     skrll 	case C(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT):
    547   1.2     skrll 		/* Synch Frame, 9.4.11, not supported */
    548   1.2     skrll 		break;
    549   1.2     skrll 	default:
    550   1.2     skrll 		/* Default to error */
    551   1.2     skrll 		buflen = -1;
    552   1.2     skrll 		break;
    553   1.2     skrll 	}
    554   1.2     skrll 
    555  1.15  riastrad 	KASSERTMSG(bus->ub_rhxfer == NULL, "rhxfer=%p", bus->ub_rhxfer);
    556  1.15  riastrad 	bus->ub_rhxfer = xfer;
    557  1.14  riastrad 	if (!bus->ub_usepolling)
    558  1.14  riastrad 		mutex_exit(bus->ub_lock);
    559  1.15  riastrad 
    560   1.2     skrll 	actlen = bus->ub_methods->ubm_rhctrl(bus, req, buf, buflen);
    561  1.15  riastrad 
    562  1.14  riastrad 	if (!bus->ub_usepolling)
    563  1.14  riastrad 		mutex_enter(bus->ub_lock);
    564  1.15  riastrad 	KASSERTMSG(bus->ub_rhxfer == xfer, "rhxfer=%p", bus->ub_rhxfer);
    565  1.15  riastrad 	bus->ub_rhxfer = NULL;
    566  1.15  riastrad 	cv_signal(&bus->ub_rhxfercv);
    567  1.15  riastrad 
    568   1.2     skrll 	if (actlen < 0)
    569   1.2     skrll 		goto fail;
    570   1.2     skrll 
    571   1.2     skrll 	xfer->ux_actlen = actlen;
    572   1.2     skrll 	err = USBD_NORMAL_COMPLETION;
    573   1.2     skrll 
    574   1.2     skrll  fail:
    575   1.9       mrg 	USBHIST_LOG(usbdebug, "xfer %#jx buflen %jd actlen %jd err %jd",
    576   1.9       mrg 	    (uintptr_t)xfer, buflen, actlen, err);
    577   1.2     skrll 
    578   1.2     skrll 	xfer->ux_status = err;
    579   1.2     skrll 	usb_transfer_complete(xfer);
    580   1.2     skrll 
    581   1.2     skrll 	return USBD_NORMAL_COMPLETION;
    582   1.2     skrll }
    583   1.2     skrll 
    584   1.2     skrll /* Abort a root control request. */
    585   1.2     skrll Static void
    586   1.2     skrll roothub_ctrl_abort(struct usbd_xfer *xfer)
    587   1.2     skrll {
    588  1.15  riastrad 	struct usbd_bus *bus = xfer->ux_bus;
    589  1.15  riastrad 
    590  1.15  riastrad 	KASSERT(mutex_owned(bus->ub_lock));
    591  1.15  riastrad 	KASSERTMSG(bus->ub_rhxfer == xfer, "rhxfer=%p", bus->ub_rhxfer);
    592   1.2     skrll 
    593  1.15  riastrad 	/*
    594  1.15  riastrad 	 * No mechanism to abort the xfer (would have to coordinate
    595  1.15  riastrad 	 * with the bus's ubm_rhctrl to be useful, and usually at most
    596  1.15  riastrad 	 * there's some short bounded delays of a few tens of
    597  1.15  riastrad 	 * milliseconds), so just wait for it to complete.
    598  1.15  riastrad 	 */
    599  1.15  riastrad 	while (bus->ub_rhxfer == xfer)
    600  1.15  riastrad 		cv_wait(&bus->ub_rhxfercv, bus->ub_lock);
    601   1.2     skrll }
    602   1.2     skrll 
    603   1.2     skrll /* Close the root pipe. */
    604   1.2     skrll Static void
    605   1.2     skrll roothub_ctrl_close(struct usbd_pipe *pipe)
    606   1.2     skrll {
    607   1.2     skrll 
    608   1.2     skrll 	/* Nothing to do. */
    609   1.2     skrll }
    610   1.2     skrll 
    611   1.2     skrll Static void
    612   1.2     skrll roothub_ctrl_done(struct usbd_xfer *xfer)
    613   1.2     skrll {
    614   1.2     skrll 
    615   1.2     skrll 	/* Nothing to do. */
    616   1.2     skrll }
    617   1.2     skrll 
    618   1.2     skrll static void
    619   1.2     skrll roothub_noop(struct usbd_pipe *pipe)
    620   1.2     skrll {
    621   1.2     skrll 
    622   1.2     skrll }
    623