| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: usbroothub.c,v 1.3 2017/10/28 00:37:13 pgoyette Exp $ */ | | 1 | /* $NetBSD: usbroothub.c,v 1.4 2017/11/28 07:36:08 skrll Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 1998, 2004, 2011, 2012 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 1998, 2004, 2011, 2012 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Lennart Augustsson (lennart@augustsson.net) at | | 8 | * by Lennart Augustsson (lennart@augustsson.net) at |
9 | * Carlstedt Research & Technology, Jared D. McNeill (jmcneill@invisible.ca), | | 9 | * Carlstedt Research & Technology, Jared D. McNeill (jmcneill@invisible.ca), |
10 | * Matthew R. Green (mrg@eterna.com.au) and Nick Hudson. | | 10 | * Matthew R. Green (mrg@eterna.com.au) and Nick Hudson. |
11 | * | | 11 | * |
12 | * Redistribution and use in source and binary forms, with or without | | 12 | * Redistribution and use in source and binary forms, with or without |
13 | * modification, are permitted provided that the following conditions | | 13 | * modification, are permitted provided that the following conditions |
14 | * are met: | | 14 | * are met: |
| @@ -159,26 +159,44 @@ static const struct usb_roothub_descript | | | @@ -159,26 +159,44 @@ static const struct usb_roothub_descript |
159 | .bInterfaceProtocol = UIPROTO_FSHUB, | | 159 | .bInterfaceProtocol = UIPROTO_FSHUB, |
160 | .iInterface = 0 | | 160 | .iInterface = 0 |
161 | }, | | 161 | }, |
162 | .urh_endpd = { | | 162 | .urh_endpd = { |
163 | .bLength = USB_ENDPOINT_DESCRIPTOR_SIZE, | | 163 | .bLength = USB_ENDPOINT_DESCRIPTOR_SIZE, |
164 | .bDescriptorType = UDESC_ENDPOINT, | | 164 | .bDescriptorType = UDESC_ENDPOINT, |
165 | .bEndpointAddress = UE_DIR_IN | USBROOTHUB_INTR_ENDPT, | | 165 | .bEndpointAddress = UE_DIR_IN | USBROOTHUB_INTR_ENDPT, |
166 | .bmAttributes = UE_INTERRUPT, | | 166 | .bmAttributes = UE_INTERRUPT, |
167 | .wMaxPacketSize = USETWD(8), /* max packet */ | | 167 | .wMaxPacketSize = USETWD(8), /* max packet */ |
168 | .bInterval = 255, | | 168 | .bInterval = 255, |
169 | }, | | 169 | }, |
170 | }; | | 170 | }; |
171 | | | 171 | |
| | | 172 | /* USB 3.0 10.15.1 */ |
| | | 173 | static const usb_device_descriptor_t usbroothub_devd3 = { |
| | | 174 | .bLength = sizeof(usb_device_descriptor_t), |
| | | 175 | .bDescriptorType = UDESC_DEVICE, |
| | | 176 | .bcdUSB = {0x00, 0x03}, |
| | | 177 | .bDeviceClass = UDCLASS_HUB, |
| | | 178 | .bDeviceSubClass = UDSUBCLASS_HUB, |
| | | 179 | .bDeviceProtocol = UDPROTO_SSHUB, |
| | | 180 | .bMaxPacketSize = 9, |
| | | 181 | .idVendor = {0}, |
| | | 182 | .idProduct = {0}, |
| | | 183 | .bcdDevice = {0x00, 0x01}, |
| | | 184 | .iManufacturer = 1, |
| | | 185 | .iProduct = 2, |
| | | 186 | .iSerialNumber = 0, |
| | | 187 | .bNumConfigurations = 1 |
| | | 188 | }; |
| | | 189 | |
172 | static const usb_device_descriptor_t usbroothub_devd2 = { | | 190 | static const usb_device_descriptor_t usbroothub_devd2 = { |
173 | .bLength = sizeof(usb_device_descriptor_t), | | 191 | .bLength = sizeof(usb_device_descriptor_t), |
174 | .bDescriptorType = UDESC_DEVICE, | | 192 | .bDescriptorType = UDESC_DEVICE, |
175 | .bcdUSB = {0x00, 0x02}, | | 193 | .bcdUSB = {0x00, 0x02}, |
176 | .bDeviceClass = UDCLASS_HUB, | | 194 | .bDeviceClass = UDCLASS_HUB, |
177 | .bDeviceSubClass = UDSUBCLASS_HUB, | | 195 | .bDeviceSubClass = UDSUBCLASS_HUB, |
178 | .bDeviceProtocol = UDPROTO_HSHUBSTT, | | 196 | .bDeviceProtocol = UDPROTO_HSHUBSTT, |
179 | .bMaxPacketSize = 64, | | 197 | .bMaxPacketSize = 64, |
180 | .idVendor = {0}, | | 198 | .idVendor = {0}, |
181 | .idProduct = {0}, | | 199 | .idProduct = {0}, |
182 | .bcdDevice = {0x00, 0x01}, | | 200 | .bcdDevice = {0x00, 0x01}, |
183 | .iManufacturer = 1, | | 201 | .iManufacturer = 1, |
184 | .iProduct = 2, | | 202 | .iProduct = 2, |
| @@ -219,26 +237,102 @@ static const struct usb_roothub_descript | | | @@ -219,26 +237,102 @@ static const struct usb_roothub_descript |
219 | .bInterfaceProtocol = UIPROTO_HSHUBSTT, | | 237 | .bInterfaceProtocol = UIPROTO_HSHUBSTT, |
220 | .iInterface = 0 | | 238 | .iInterface = 0 |
221 | }, | | 239 | }, |
222 | .urh_endpd = { | | 240 | .urh_endpd = { |
223 | .bLength = USB_ENDPOINT_DESCRIPTOR_SIZE, | | 241 | .bLength = USB_ENDPOINT_DESCRIPTOR_SIZE, |
224 | .bDescriptorType = UDESC_ENDPOINT, | | 242 | .bDescriptorType = UDESC_ENDPOINT, |
225 | .bEndpointAddress = UE_DIR_IN | USBROOTHUB_INTR_ENDPT, | | 243 | .bEndpointAddress = UE_DIR_IN | USBROOTHUB_INTR_ENDPT, |
226 | .bmAttributes = UE_INTERRUPT, | | 244 | .bmAttributes = UE_INTERRUPT, |
227 | .wMaxPacketSize = USETWD(8), /* max packet */ | | 245 | .wMaxPacketSize = USETWD(8), /* max packet */ |
228 | .bInterval = 12, | | 246 | .bInterval = 12, |
229 | }, | | 247 | }, |
230 | }; | | 248 | }; |
231 | | | 249 | |
| | | 250 | static const struct usb3_roothub_descriptors usbroothub_confd3 = { |
| | | 251 | .urh_confd = { |
| | | 252 | .bLength = USB_CONFIG_DESCRIPTOR_SIZE, |
| | | 253 | .bDescriptorType = UDESC_CONFIG, |
| | | 254 | .wTotalLength = USETWD(sizeof(usbroothub_confd3)), |
| | | 255 | .bNumInterface = 1, |
| | | 256 | .bConfigurationValue = 1, |
| | | 257 | .iConfiguration = 0, |
| | | 258 | .bmAttributes = UC_SELF_POWERED, /* 10.13.1 */ |
| | | 259 | .bMaxPower = 0, |
| | | 260 | }, |
| | | 261 | .urh_ifcd = { |
| | | 262 | .bLength = USB_INTERFACE_DESCRIPTOR_SIZE, |
| | | 263 | .bDescriptorType = UDESC_INTERFACE, |
| | | 264 | .bInterfaceNumber = 0, |
| | | 265 | .bAlternateSetting = 0, |
| | | 266 | .bNumEndpoints = 1, |
| | | 267 | .bInterfaceClass = UICLASS_HUB, |
| | | 268 | .bInterfaceSubClass = UISUBCLASS_HUB, |
| | | 269 | .bInterfaceProtocol = 0, /* UIPROTO_SSHUB ??? */ |
| | | 270 | .iInterface = 0 |
| | | 271 | }, |
| | | 272 | .urh_endpd = { |
| | | 273 | .bLength = USB_ENDPOINT_DESCRIPTOR_SIZE, |
| | | 274 | .bDescriptorType = UDESC_ENDPOINT, |
| | | 275 | .bEndpointAddress = UE_DIR_IN | USBROOTHUB_INTR_ENDPT, |
| | | 276 | .bmAttributes = UE_INTERRUPT, |
| | | 277 | .wMaxPacketSize = USETWD(2), /* max packet */ |
| | | 278 | .bInterval = 8, |
| | | 279 | }, |
| | | 280 | .urh_endpssd = { |
| | | 281 | .bLength = USB_ENDPOINT_SS_COMP_DESCRIPTOR_SIZE, |
| | | 282 | .bDescriptorType = UDESC_ENDPOINT_SS_COMP, |
| | | 283 | .bMaxBurst = 0, |
| | | 284 | .bmAttributes = 0, |
| | | 285 | .wBytesPerInterval = USETWD(2) |
| | | 286 | }, |
| | | 287 | }; |
| | | 288 | |
| | | 289 | static const struct usb3_roothub_bos_descriptors usbroothub_bosd3 = { |
| | | 290 | .urh_bosd = { |
| | | 291 | .bLength = USB_BOS_DESCRIPTOR_SIZE, |
| | | 292 | .bDescriptorType = UDESC_BOS, |
| | | 293 | .wTotalLength = USETWD(sizeof(usbroothub_bosd3)), |
| | | 294 | .bNumDeviceCaps = 3, |
| | | 295 | }, |
| | | 296 | /* 9.6.2.1 USB 2.0 Extension */ |
| | | 297 | .urh_usb2extd = { |
| | | 298 | .bLength = USB_DEVCAP_USB2EXT_DESCRIPTOR_SIZE, |
| | | 299 | .bDescriptorType = 1, |
| | | 300 | .bDevCapabilityType = 2, |
| | | 301 | .bmAttributes[0] = 2, |
| | | 302 | }, |
| | | 303 | /* 9.6.2.2 Superspeed device capability */ |
| | | 304 | .urh_ssd = { |
| | | 305 | .bLength = USB_DEVCAP_SS_DESCRIPTOR_SIZE, |
| | | 306 | .bDescriptorType = UDESC_DEVICE_CAPABILITY, |
| | | 307 | .bDevCapabilityType = USB_DEVCAP_SUPER_SPEED, |
| | | 308 | .bmAttributes = 0, /* USB_DEVCAP_SS_LTM */ |
| | | 309 | .wSpeedsSupported = USETWD( |
| | | 310 | USB_DEVCAP_SS_SPEED_LS | USB_DEVCAP_SS_SPEED_FS | |
| | | 311 | USB_DEVCAP_SS_SPEED_HS | USB_DEVCAP_SS_SPEED_SS), |
| | | 312 | .bFunctionalitySupport = 8, /* SS is 3, i.e. 1 << 3? */ |
| | | 313 | .bU1DevExitLat = 255, /* Dummy... 0? */ |
| | | 314 | .wU2DevExitLat = USETWD(8), /* Also dummy... 0? */ |
| | | 315 | }, |
| | | 316 | /* 9.6.2.3 Container ID - see RFC 4122 */ |
| | | 317 | .urh_containerd = { |
| | | 318 | .bLength = USB_DEVCAP_CONTAINER_ID_DESCRIPTOR_SIZE, |
| | | 319 | .bDescriptorType = 1, |
| | | 320 | .bDevCapabilityType = 4, |
| | | 321 | .bReserved = 0, |
| | | 322 | // ContainerID will be zero |
| | | 323 | }, |
| | | 324 | }; |
| | | 325 | |
232 | static const usb_hub_descriptor_t usbroothub_hubd = { | | 326 | static const usb_hub_descriptor_t usbroothub_hubd = { |
233 | .bDescLength = USB_HUB_DESCRIPTOR_SIZE, | | 327 | .bDescLength = USB_HUB_DESCRIPTOR_SIZE, |
234 | .bDescriptorType = UDESC_HUB, | | 328 | .bDescriptorType = UDESC_HUB, |
235 | .bNbrPorts = 1, | | 329 | .bNbrPorts = 1, |
236 | .wHubCharacteristics = USETWD(UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL), | | 330 | .wHubCharacteristics = USETWD(UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL), |
237 | .bPwrOn2PwrGood = 50, | | 331 | .bPwrOn2PwrGood = 50, |
238 | .bHubContrCurrent = 0, | | 332 | .bHubContrCurrent = 0, |
239 | .DeviceRemovable = {0}, /* port is removable */ | | 333 | .DeviceRemovable = {0}, /* port is removable */ |
240 | }; | | 334 | }; |
241 | | | 335 | |
242 | /* | | 336 | /* |
243 | * Simulate a hardware hub by handling all the necessary requests. | | 337 | * Simulate a hardware hub by handling all the necessary requests. |
244 | */ | | 338 | */ |
| @@ -300,36 +394,42 @@ roothub_ctrl_start(struct usbd_xfer *xfe | | | @@ -300,36 +394,42 @@ roothub_ctrl_start(struct usbd_xfer *xfe |
300 | uint8_t *out = buf; | | 394 | uint8_t *out = buf; |
301 | | | 395 | |
302 | *out = bus->ub_rhconf; | | 396 | *out = bus->ub_rhconf; |
303 | buflen = sizeof(*out); | | 397 | buflen = sizeof(*out); |
304 | } | | 398 | } |
305 | break; | | 399 | break; |
306 | case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE): | | 400 | case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE): |
307 | USBHIST_LOG(usbdebug, "wValue=%#4jx", value, 0, 0, 0); | | 401 | USBHIST_LOG(usbdebug, "wValue=%#4jx", value, 0, 0, 0); |
308 | | | 402 | |
309 | if (len == 0) | | 403 | if (len == 0) |
310 | break; | | 404 | break; |
311 | switch (value) { | | 405 | switch (value) { |
312 | case C(0, UDESC_DEVICE): | | 406 | case C(0, UDESC_DEVICE): |
313 | if (bus->ub_revision == USBREV_2_0) { | | 407 | if (bus->ub_revision >= USBREV_3_0) { |
| | | 408 | buflen = min(len, sizeof(usbroothub_devd3)); |
| | | 409 | memcpy(buf, &usbroothub_devd3, buflen); |
| | | 410 | } else if (bus->ub_revision == USBREV_2_0) { |
314 | buflen = min(len, sizeof(usbroothub_devd2)); | | 411 | buflen = min(len, sizeof(usbroothub_devd2)); |
315 | memcpy(buf, &usbroothub_devd2, buflen); | | 412 | memcpy(buf, &usbroothub_devd2, buflen); |
316 | } else { | | 413 | } else { |
317 | buflen = min(len, sizeof(usbroothub_devd1)); | | 414 | buflen = min(len, sizeof(usbroothub_devd1)); |
318 | memcpy(buf, &usbroothub_devd1, buflen); | | 415 | memcpy(buf, &usbroothub_devd1, buflen); |
319 | } | | 416 | } |
320 | break; | | 417 | break; |
321 | case C(0, UDESC_CONFIG): | | 418 | case C(0, UDESC_CONFIG): |
322 | if (bus->ub_revision == USBREV_2_0) { | | 419 | if (bus->ub_revision >= USBREV_3_0) { |
| | | 420 | buflen = min(len, sizeof(usbroothub_confd3)); |
| | | 421 | memcpy(buf, &usbroothub_confd3, buflen); |
| | | 422 | } else if (bus->ub_revision == USBREV_2_0) { |
323 | buflen = min(len, sizeof(usbroothub_confd2)); | | 423 | buflen = min(len, sizeof(usbroothub_confd2)); |
324 | memcpy(buf, &usbroothub_confd2, buflen); | | 424 | memcpy(buf, &usbroothub_confd2, buflen); |
325 | } else { | | 425 | } else { |
326 | buflen = min(len, sizeof(usbroothub_confd1)); | | 426 | buflen = min(len, sizeof(usbroothub_confd1)); |
327 | memcpy(buf, &usbroothub_confd1, buflen); | | 427 | memcpy(buf, &usbroothub_confd1, buflen); |
328 | } | | 428 | } |
329 | break; | | 429 | break; |
330 | case C(0, UDESC_DEVICE_QUALIFIER): | | 430 | case C(0, UDESC_DEVICE_QUALIFIER): |
331 | if (bus->ub_revision == USBREV_2_0) { | | 431 | if (bus->ub_revision == USBREV_2_0) { |
332 | /* | | 432 | /* |
333 | * We can't really operate at another speed, | | 433 | * We can't really operate at another speed, |
334 | * but the spec says we need this descriptor. | | 434 | * but the spec says we need this descriptor. |
335 | */ | | 435 | */ |
| @@ -344,26 +444,33 @@ roothub_ctrl_start(struct usbd_xfer *xfe | | | @@ -344,26 +444,33 @@ roothub_ctrl_start(struct usbd_xfer *xfe |
344 | | | 444 | |
345 | /* | | 445 | /* |
346 | * We can't really operate at another speed, | | 446 | * We can't really operate at another speed, |
347 | * but the spec says we need this descriptor. | | 447 | * but the spec says we need this descriptor. |
348 | */ | | 448 | */ |
349 | buflen = min(len, sizeof(usbroothub_confd2)); | | 449 | buflen = min(len, sizeof(usbroothub_confd2)); |
350 | memcpy(&confd, &usbroothub_confd2, buflen); | | 450 | memcpy(&confd, &usbroothub_confd2, buflen); |
351 | confd.urh_confd.bDescriptorType = | | 451 | confd.urh_confd.bDescriptorType = |
352 | UDESC_OTHER_SPEED_CONFIGURATION; | | 452 | UDESC_OTHER_SPEED_CONFIGURATION; |
353 | memcpy(buf, &confd, buflen); | | 453 | memcpy(buf, &confd, buflen); |
354 | } else | | 454 | } else |
355 | goto fail; | | 455 | goto fail; |
356 | break; | | 456 | break; |
| | | 457 | case C(0, UDESC_BOS): |
| | | 458 | if (bus->ub_revision >= USBREV_3_0) { |
| | | 459 | buflen = min(len, sizeof(usbroothub_bosd3)); |
| | | 460 | memcpy(buf, &usbroothub_bosd3, buflen); |
| | | 461 | } else |
| | | 462 | goto fail; |
| | | 463 | break; |
357 | #define sd ((usb_string_descriptor_t *)buf) | | 464 | #define sd ((usb_string_descriptor_t *)buf) |
358 | case C(0, UDESC_STRING): | | 465 | case C(0, UDESC_STRING): |
359 | /* Language table */ | | 466 | /* Language table */ |
360 | buflen = usb_makelangtbl(sd, len); | | 467 | buflen = usb_makelangtbl(sd, len); |
361 | break; | | 468 | break; |
362 | case C(1, UDESC_STRING): | | 469 | case C(1, UDESC_STRING): |
363 | /* Vendor */ | | 470 | /* Vendor */ |
364 | buflen = usb_makestrdesc(sd, len, "NetBSD"); | | 471 | buflen = usb_makestrdesc(sd, len, "NetBSD"); |
365 | break; | | 472 | break; |
366 | case C(2, UDESC_STRING): | | 473 | case C(2, UDESC_STRING): |
367 | /* Product */ | | 474 | /* Product */ |
368 | buflen = usb_makestrdesc(sd, len, "Root hub"); | | 475 | buflen = usb_makestrdesc(sd, len, "Root hub"); |
369 | break; | | 476 | break; |