usb_hub.c (259218) | usb_hub.c (260589) |
---|---|
1/* $FreeBSD: head/sys/dev/usb/usb_hub.c 259218 2013-12-11 13:20:32Z hselasky $ */ | 1/* $FreeBSD: head/sys/dev/usb/usb_hub.c 260589 2014-01-13 15:21:11Z hselasky $ */ |
2/*- 3 * Copyright (c) 1998 The NetBSD Foundation, Inc. All rights reserved. 4 * Copyright (c) 1998 Lennart Augustsson. All rights reserved. 5 * Copyright (c) 2008-2010 Hans Petter Selasky. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: --- 59 unchanged lines hidden (view full) --- 69#include <dev/usb/usb_transfer.h> 70#include <dev/usb/usb_dynamic.h> 71 72#include <dev/usb/usb_controller.h> 73#include <dev/usb/usb_bus.h> 74#endif /* USB_GLOBAL_INCLUDE_FILE */ 75 76#define UHUB_INTR_INTERVAL 250 /* ms */ | 2/*- 3 * Copyright (c) 1998 The NetBSD Foundation, Inc. All rights reserved. 4 * Copyright (c) 1998 Lennart Augustsson. All rights reserved. 5 * Copyright (c) 2008-2010 Hans Petter Selasky. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: --- 59 unchanged lines hidden (view full) --- 69#include <dev/usb/usb_transfer.h> 70#include <dev/usb/usb_dynamic.h> 71 72#include <dev/usb/usb_controller.h> 73#include <dev/usb/usb_bus.h> 74#endif /* USB_GLOBAL_INCLUDE_FILE */ 75 76#define UHUB_INTR_INTERVAL 250 /* ms */ |
77#define UHUB_N_TRANSFER 1 | 77enum { 78 UHUB_INTR_TRANSFER, 79#if USB_HAVE_TT_SUPPORT 80 UHUB_RESET_TT_TRANSFER, 81#endif 82 UHUB_N_TRANSFER, 83}; |
78 79#ifdef USB_DEBUG 80static int uhub_debug = 0; 81 82static SYSCTL_NODE(_hw_usb, OID_AUTO, uhub, CTLFLAG_RW, 0, "USB HUB"); 83SYSCTL_INT(_hw_usb_uhub, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_TUN, &uhub_debug, 0, 84 "Debug level"); 85TUNABLE_INT("hw.usb.uhub.debug", &uhub_debug); --- 38 unchanged lines hidden (view full) --- 124static device_suspend_t uhub_suspend; 125static device_resume_t uhub_resume; 126 127static bus_driver_added_t uhub_driver_added; 128static bus_child_location_str_t uhub_child_location_string; 129static bus_child_pnpinfo_str_t uhub_child_pnpinfo_string; 130 131static usb_callback_t uhub_intr_callback; | 84 85#ifdef USB_DEBUG 86static int uhub_debug = 0; 87 88static SYSCTL_NODE(_hw_usb, OID_AUTO, uhub, CTLFLAG_RW, 0, "USB HUB"); 89SYSCTL_INT(_hw_usb_uhub, OID_AUTO, debug, CTLFLAG_RW | CTLFLAG_TUN, &uhub_debug, 0, 90 "Debug level"); 91TUNABLE_INT("hw.usb.uhub.debug", &uhub_debug); --- 38 unchanged lines hidden (view full) --- 130static device_suspend_t uhub_suspend; 131static device_resume_t uhub_resume; 132 133static bus_driver_added_t uhub_driver_added; 134static bus_child_location_str_t uhub_child_location_string; 135static bus_child_pnpinfo_str_t uhub_child_pnpinfo_string; 136 137static usb_callback_t uhub_intr_callback; |
138#if USB_HAVE_TT_SUPPORT 139static usb_callback_t uhub_reset_tt_callback; 140#endif |
|
132 133static void usb_dev_resume_peer(struct usb_device *udev); 134static void usb_dev_suspend_peer(struct usb_device *udev); 135static uint8_t usb_peer_should_wakeup(struct usb_device *udev); 136 137static const struct usb_config uhub_config[UHUB_N_TRANSFER] = { 138 | 141 142static void usb_dev_resume_peer(struct usb_device *udev); 143static void usb_dev_suspend_peer(struct usb_device *udev); 144static uint8_t usb_peer_should_wakeup(struct usb_device *udev); 145 146static const struct usb_config uhub_config[UHUB_N_TRANSFER] = { 147 |
139 [0] = { | 148 [UHUB_INTR_TRANSFER] = { |
140 .type = UE_INTERRUPT, 141 .endpoint = UE_ADDR_ANY, 142 .direction = UE_DIR_ANY, 143 .timeout = 0, 144 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 145 .bufsize = 0, /* use wMaxPacketSize */ 146 .callback = &uhub_intr_callback, 147 .interval = UHUB_INTR_INTERVAL, 148 }, | 149 .type = UE_INTERRUPT, 150 .endpoint = UE_ADDR_ANY, 151 .direction = UE_DIR_ANY, 152 .timeout = 0, 153 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 154 .bufsize = 0, /* use wMaxPacketSize */ 155 .callback = &uhub_intr_callback, 156 .interval = UHUB_INTR_INTERVAL, 157 }, |
158#if USB_HAVE_TT_SUPPORT 159 [UHUB_RESET_TT_TRANSFER] = { 160 .type = UE_CONTROL, 161 .endpoint = 0x00, /* Control pipe */ 162 .direction = UE_DIR_ANY, 163 .bufsize = sizeof(struct usb_device_request), 164 .callback = &uhub_reset_tt_callback, 165 .timeout = 1000, /* 1 second */ 166 .usb_mode = USB_MODE_HOST, 167 }, 168#endif |
|
149}; 150 151/* 152 * driver instance for "hub" connected to "usb" 153 * and "hub" connected to "hub" 154 */ 155static devclass_t uhub_devclass; 156 --- 53 unchanged lines hidden (view full) --- 210 usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 211 usbd_transfer_submit(xfer); 212 } 213 break; 214 } 215} 216 217/*------------------------------------------------------------------------* | 169}; 170 171/* 172 * driver instance for "hub" connected to "usb" 173 * and "hub" connected to "hub" 174 */ 175static devclass_t uhub_devclass; 176 --- 53 unchanged lines hidden (view full) --- 230 usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 231 usbd_transfer_submit(xfer); 232 } 233 break; 234 } 235} 236 237/*------------------------------------------------------------------------* |
238 * uhub_reset_tt_proc 239 * 240 * This function starts the TT reset USB request 241 *------------------------------------------------------------------------*/ 242#if USB_HAVE_TT_SUPPORT 243static void 244uhub_reset_tt_proc(struct usb_proc_msg *_pm) 245{ 246 struct usb_udev_msg *pm = (void *)_pm; 247 struct usb_device *udev = pm->udev; 248 struct usb_hub *hub; 249 struct uhub_softc *sc; 250 251 hub = udev->hub; 252 if (hub == NULL) 253 return; 254 sc = hub->hubsoftc; 255 if (sc == NULL) 256 return; 257 258 /* Change lock */ 259 USB_BUS_UNLOCK(udev->bus); 260 mtx_lock(&sc->sc_mtx); 261 /* Start transfer */ 262 usbd_transfer_start(sc->sc_xfer[UHUB_RESET_TT_TRANSFER]); 263 /* Change lock */ 264 mtx_unlock(&sc->sc_mtx); 265 USB_BUS_LOCK(udev->bus); 266} 267#endif 268 269/*------------------------------------------------------------------------* 270 * uhub_tt_buffer_reset_async_locked 271 * 272 * This function queues a TT reset for the given USB device and endpoint. 273 *------------------------------------------------------------------------*/ 274#if USB_HAVE_TT_SUPPORT 275void 276uhub_tt_buffer_reset_async_locked(struct usb_device *child, struct usb_endpoint *ep) 277{ 278 struct usb_device_request req; 279 struct usb_device *udev; 280 struct usb_hub *hub; 281 struct usb_port *up; 282 uint16_t wValue; 283 uint8_t port; 284 285 if (child == NULL || ep == NULL) 286 return; 287 288 udev = child->parent_hs_hub; 289 port = child->hs_port_no; 290 291 if (udev == NULL) 292 return; 293 294 hub = udev->hub; 295 if ((hub == NULL) || 296 (udev->speed != USB_SPEED_HIGH) || 297 (child->speed != USB_SPEED_LOW && 298 child->speed != USB_SPEED_FULL) || 299 (child->flags.usb_mode != USB_MODE_HOST) || 300 (port == 0) || (ep->edesc == NULL)) { 301 /* not applicable */ 302 return; 303 } 304 305 USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED); 306 307 up = hub->ports + port - 1; 308 309 if (udev->ddesc.bDeviceClass == UDCLASS_HUB && 310 udev->ddesc.bDeviceProtocol == UDPROTO_HSHUBSTT) 311 port = 1; 312 313 /* if we already received a clear buffer request, reset the whole TT */ 314 if (up->req_reset_tt.bRequest != 0) { 315 req.bmRequestType = UT_WRITE_CLASS_OTHER; 316 req.bRequest = UR_RESET_TT; 317 USETW(req.wValue, 0); 318 req.wIndex[0] = port; 319 req.wIndex[1] = 0; 320 USETW(req.wLength, 0); 321 } else { 322 wValue = (ep->edesc->bEndpointAddress & 0xF) | 323 ((child->address & 0x7F) << 4) | 324 ((ep->edesc->bEndpointAddress & 0x80) << 8) | 325 ((ep->edesc->bmAttributes & 3) << 12); 326 327 req.bmRequestType = UT_WRITE_CLASS_OTHER; 328 req.bRequest = UR_CLEAR_TT_BUFFER; 329 USETW(req.wValue, wValue); 330 req.wIndex[0] = port; 331 req.wIndex[1] = 0; 332 USETW(req.wLength, 0); 333 } 334 up->req_reset_tt = req; 335 /* get reset transfer started */ 336 usb_proc_msignal(USB_BUS_NON_GIANT_PROC(udev->bus), 337 &hub->tt_msg[0], &hub->tt_msg[1]); 338} 339#endif 340 341#if USB_HAVE_TT_SUPPORT 342static void 343uhub_reset_tt_callback(struct usb_xfer *xfer, usb_error_t error) 344{ 345 struct uhub_softc *sc; 346 struct usb_device *udev; 347 struct usb_port *up; 348 uint8_t x; 349 350 DPRINTF("TT buffer reset\n"); 351 352 sc = usbd_xfer_softc(xfer); 353 udev = sc->sc_udev; 354 355 switch (USB_GET_STATE(xfer)) { 356 case USB_ST_TRANSFERRED: 357 case USB_ST_SETUP: 358tr_setup: 359 USB_BUS_LOCK(udev->bus); 360 /* find first port which needs a TT reset */ 361 for (x = 0; x != udev->hub->nports; x++) { 362 up = udev->hub->ports + x; 363 364 if (up->req_reset_tt.bRequest == 0) 365 continue; 366 367 /* copy in the transfer */ 368 usbd_copy_in(xfer->frbuffers, 0, &up->req_reset_tt, 369 sizeof(up->req_reset_tt)); 370 /* reset buffer */ 371 memset(&up->req_reset_tt, 0, sizeof(up->req_reset_tt)); 372 373 /* set length */ 374 usbd_xfer_set_frame_len(xfer, 0, sizeof(up->req_reset_tt)); 375 xfer->nframes = 1; 376 USB_BUS_UNLOCK(udev->bus); 377 378 usbd_transfer_submit(xfer); 379 return; 380 } 381 USB_BUS_UNLOCK(udev->bus); 382 break; 383 384 default: 385 if (error == USB_ERR_CANCELLED) 386 break; 387 388 DPRINTF("TT buffer reset failed (%s)\n", usbd_errstr(error)); 389 goto tr_setup; 390 } 391} 392#endif 393 394/*------------------------------------------------------------------------* 395 * uhub_count_active_host_ports 396 * 397 * This function counts the number of active ports at the given speed. 398 *------------------------------------------------------------------------*/ 399uint8_t 400uhub_count_active_host_ports(struct usb_device *udev, enum usb_dev_speed speed) 401{ 402 struct uhub_softc *sc; 403 struct usb_device *child; 404 struct usb_hub *hub; 405 struct usb_port *up; 406 uint8_t retval = 0; 407 uint8_t x; 408 409 if (udev == NULL) 410 goto done; 411 hub = udev->hub; 412 if (hub == NULL) 413 goto done; 414 sc = hub->hubsoftc; 415 if (sc == NULL) 416 goto done; 417 418 for (x = 0; x != hub->nports; x++) { 419 up = hub->ports + x; 420 child = usb_bus_port_get_device(udev->bus, up); 421 if (child != NULL && 422 child->flags.usb_mode == USB_MODE_HOST && 423 child->speed == speed) 424 retval++; 425 } 426done: 427 return (retval); 428} 429 430/*------------------------------------------------------------------------* |
|
218 * uhub_explore_sub - subroutine 219 * 220 * Return values: 221 * 0: Success 222 * Else: A control transaction failed 223 *------------------------------------------------------------------------*/ 224static usb_error_t 225uhub_explore_sub(struct uhub_softc *sc, struct usb_port *up) --- 883 unchanged lines hidden (view full) --- 1109#endif 1110 udev->hub = hub; 1111 1112 /* initialize HUB structure */ 1113 hub->hubsoftc = sc; 1114 hub->explore = &uhub_explore; 1115 hub->nports = nports; 1116 hub->hubudev = udev; | 431 * uhub_explore_sub - subroutine 432 * 433 * Return values: 434 * 0: Success 435 * Else: A control transaction failed 436 *------------------------------------------------------------------------*/ 437static usb_error_t 438uhub_explore_sub(struct uhub_softc *sc, struct usb_port *up) --- 883 unchanged lines hidden (view full) --- 1322#endif 1323 udev->hub = hub; 1324 1325 /* initialize HUB structure */ 1326 hub->hubsoftc = sc; 1327 hub->explore = &uhub_explore; 1328 hub->nports = nports; 1329 hub->hubudev = udev; |
1117 | 1330#if USB_HAVE_TT_SUPPORT 1331 hub->tt_msg[0].hdr.pm_callback = &uhub_reset_tt_proc; 1332 hub->tt_msg[0].udev = udev; 1333 hub->tt_msg[1].hdr.pm_callback = &uhub_reset_tt_proc; 1334 hub->tt_msg[1].udev = udev; 1335#endif |
1118 /* if self powered hub, give ports maximum current */ 1119 if (udev->flags.self_powered) { 1120 hub->portpower = USB_MAX_POWER; 1121 } else { 1122 hub->portpower = USB_MIN_POWER; 1123 } 1124 1125 /* set up interrupt pipe */ --- 85 unchanged lines hidden (view full) --- 1211 } 1212 1213 device_printf(dev, "%d port%s with %d " 1214 "removable, %s powered\n", nports, (nports != 1) ? "s" : "", 1215 removable, udev->flags.self_powered ? "self" : "bus"); 1216 1217 /* Start the interrupt endpoint, if any */ 1218 | 1336 /* if self powered hub, give ports maximum current */ 1337 if (udev->flags.self_powered) { 1338 hub->portpower = USB_MAX_POWER; 1339 } else { 1340 hub->portpower = USB_MIN_POWER; 1341 } 1342 1343 /* set up interrupt pipe */ --- 85 unchanged lines hidden (view full) --- 1429 } 1430 1431 device_printf(dev, "%d port%s with %d " 1432 "removable, %s powered\n", nports, (nports != 1) ? "s" : "", 1433 removable, udev->flags.self_powered ? "self" : "bus"); 1434 1435 /* Start the interrupt endpoint, if any */ 1436 |
1219 if (sc->sc_xfer[0] != NULL) { 1220 mtx_lock(&sc->sc_mtx); 1221 usbd_transfer_start(sc->sc_xfer[0]); 1222 mtx_unlock(&sc->sc_mtx); 1223 } | 1437 mtx_lock(&sc->sc_mtx); 1438 usbd_transfer_start(sc->sc_xfer[UHUB_INTR_TRANSFER]); 1439 mtx_unlock(&sc->sc_mtx); |
1224 1225 /* Enable automatic power save on all USB HUBs */ 1226 1227 usbd_set_power_mode(udev, USB_POWER_MODE_SAVE); 1228 1229 return (0); 1230 1231error: --- 13 unchanged lines hidden (view full) --- 1245 * Called from process context when the hub is gone. 1246 * Detach all devices on active ports. 1247 */ 1248static int 1249uhub_detach(device_t dev) 1250{ 1251 struct uhub_softc *sc = device_get_softc(dev); 1252 struct usb_hub *hub = sc->sc_udev->hub; | 1440 1441 /* Enable automatic power save on all USB HUBs */ 1442 1443 usbd_set_power_mode(udev, USB_POWER_MODE_SAVE); 1444 1445 return (0); 1446 1447error: --- 13 unchanged lines hidden (view full) --- 1461 * Called from process context when the hub is gone. 1462 * Detach all devices on active ports. 1463 */ 1464static int 1465uhub_detach(device_t dev) 1466{ 1467 struct uhub_softc *sc = device_get_softc(dev); 1468 struct usb_hub *hub = sc->sc_udev->hub; |
1469 struct usb_bus *bus = sc->sc_udev->bus; |
|
1253 struct usb_device *child; 1254 uint8_t x; 1255 1256 if (hub == NULL) /* must be partially working */ 1257 return (0); 1258 1259 /* Make sure interrupt transfer is gone. */ 1260 usbd_transfer_unsetup(sc->sc_xfer, UHUB_N_TRANSFER); 1261 1262 /* Detach all ports */ 1263 for (x = 0; x != hub->nports; x++) { 1264 | 1470 struct usb_device *child; 1471 uint8_t x; 1472 1473 if (hub == NULL) /* must be partially working */ 1474 return (0); 1475 1476 /* Make sure interrupt transfer is gone. */ 1477 usbd_transfer_unsetup(sc->sc_xfer, UHUB_N_TRANSFER); 1478 1479 /* Detach all ports */ 1480 for (x = 0; x != hub->nports; x++) { 1481 |
1265 child = usb_bus_port_get_device(sc->sc_udev->bus, hub->ports + x); | 1482 child = usb_bus_port_get_device(bus, hub->ports + x); |
1266 1267 if (child == NULL) { 1268 continue; 1269 } 1270 1271 /* 1272 * Free USB device and all subdevices, if any. 1273 */ 1274 usb_free_device(child, 0); 1275 } 1276 | 1483 1484 if (child == NULL) { 1485 continue; 1486 } 1487 1488 /* 1489 * Free USB device and all subdevices, if any. 1490 */ 1491 usb_free_device(child, 0); 1492 } 1493 |
1494#if USB_HAVE_TT_SUPPORT 1495 /* Make sure our TT messages are not queued anywhere */ 1496 USB_BUS_LOCK(bus); 1497 usb_proc_mwait(USB_BUS_NON_GIANT_PROC(bus), 1498 &hub->tt_msg[0], &hub->tt_msg[1]); 1499 USB_BUS_UNLOCK(bus); 1500#endif 1501 |
|
1277#if (USB_HAVE_FIXED_PORT == 0) 1278 free(hub, M_USBDEV); 1279#endif 1280 sc->sc_udev->hub = NULL; 1281 1282 mtx_destroy(&sc->sc_mtx); 1283 1284 return (0); --- 1291 unchanged lines hidden --- | 1502#if (USB_HAVE_FIXED_PORT == 0) 1503 free(hub, M_USBDEV); 1504#endif 1505 sc->sc_udev->hub = NULL; 1506 1507 mtx_destroy(&sc->sc_mtx); 1508 1509 return (0); --- 1291 unchanged lines hidden --- |