Deleted Added
full compact
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 ---