Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F166675930
D56891.id177469.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
9 KB
Referenced Files
None
Subscribers
None
D56891.id177469.diff
View Options
diff --git a/sys/dev/usb/controller/usb_controller.c b/sys/dev/usb/controller/usb_controller.c
--- a/sys/dev/usb/controller/usb_controller.c
+++ b/sys/dev/usb/controller/usb_controller.c
@@ -885,9 +885,8 @@
usb_proc_msignal(USB_BUS_EXPLORE_PROC(bus),
&bus->attach_msg[0], &bus->attach_msg[1]);
USB_BUS_UNLOCK(bus);
-
/* Do initial explore */
- usb_needs_explore(bus, 1);
+ usb_needs_explore(bus, 1, 1);
}
}
SYSUNINIT(usb_bus_unload, SI_SUB_KLD, SI_ORDER_ANY, usb_bus_unload, NULL);
diff --git a/sys/dev/usb/usb_handle_request.c b/sys/dev/usb/usb_handle_request.c
--- a/sys/dev/usb/usb_handle_request.c
+++ b/sys/dev/usb/usb_handle_request.c
@@ -102,7 +102,7 @@
if (err) {
if (err == USB_ERR_BAD_CONTEXT) {
/* we need to re-setup the control transfer */
- usb_needs_explore(xfer->xroot->bus, 0);
+ usb_needs_explore(xfer->xroot->bus, 0, 1);
break;
}
goto tr_restart;
diff --git a/sys/dev/usb/usb_hub.h b/sys/dev/usb/usb_hub.h
--- a/sys/dev/usb/usb_hub.h
+++ b/sys/dev/usb/usb_hub.h
@@ -70,7 +70,8 @@
struct usb_device *udev, uint8_t device_index);
struct usb_device *usb_bus_port_get_device(struct usb_bus *bus,
struct usb_port *up);
-void usb_needs_explore(struct usb_bus *bus, uint8_t do_probe);
+void usb_needs_explore(struct usb_bus *bus, uint8_t do_probe,
+ uint8_t all_ports);
void usb_needs_explore_all(void);
void usb_bus_power_update(struct usb_bus *bus);
void usb_bus_powerd(struct usb_bus *bus);
diff --git a/sys/dev/usb/usb_hub.c b/sys/dev/usb/usb_hub.c
--- a/sys/dev/usb/usb_hub.c
+++ b/sys/dev/usb/usb_hub.c
@@ -42,6 +42,7 @@
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/bus.h>
+#include <sys/bitset.h>
#include <sys/module.h>
#include <sys/lock.h>
#include <sys/mutex.h>
@@ -185,17 +186,31 @@
uhub_intr_callback(struct usb_xfer *xfer, usb_error_t error)
{
struct uhub_softc *sc = usbd_xfer_softc(xfer);
+ struct usb_page_cache *pc;
+ int len;
switch (USB_GET_STATE(xfer)) {
case USB_ST_TRANSFERRED:
DPRINTFN(2, "\n");
+
+ pc = usbd_xfer_get_frame(xfer, 0);
+ usbd_xfer_status(xfer, &len, NULL, NULL, NULL);
+ if (len > USB_HUB_MAX_DEVS_NUMS / 8) {
+ len = USB_HUB_MAX_DEVS_NUMS / 8;
+ DPRINTF("Hub has more than %d devices",
+ USB_HUB_MAX_DEVS_NUMS);
+ }
+
+ USB_MTX_LOCK(&sc->sc_mtx);
+ usbd_copy_out(pc, 0, &sc->sc_port_changed, len);
+ USB_MTX_UNLOCK(&sc->sc_mtx);
/*
* This is an indication that some port
* has changed status. Notify the bus
* event handler thread that we need
* to be explored again:
*/
- usb_needs_explore(sc->sc_udev->bus, 0);
+ usb_needs_explore(sc->sc_udev->bus, 0, 0);
case USB_ST_SETUP:
usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
@@ -240,11 +255,11 @@
/* Change lock */
USB_BUS_UNLOCK(udev->bus);
- USB_MTX_LOCK(&sc->sc_mtx);
+ USB_MTX_LOCK(&sc->sc_xfer_mtx);
/* Start transfer */
usbd_transfer_start(sc->sc_xfer[UHUB_RESET_TT_TRANSFER]);
/* Change lock */
- USB_MTX_UNLOCK(&sc->sc_mtx);
+ USB_MTX_UNLOCK(&sc->sc_xfer_mtx);
USB_BUS_LOCK(udev->bus);
}
#endif
@@ -508,6 +523,7 @@
{
struct usb_bus *bus;
struct usb_device *child;
+ struct uhub_softc *child_sc;
uint8_t refcount;
usb_error_t err;
@@ -543,8 +559,13 @@
/* if a HUB becomes present, do a recursive HUB explore */
- if (child->hub)
+ if (child->hub) {
+ child_sc = (child->hub->hubsoftc);
+ USB_MTX_LOCK(&child_sc->sc_mtx);
+ UHUB_FILL_USB_PORT_CHANGED(&child_sc->sc_port_changed);
+ USB_MTX_UNLOCK(&child_sc->sc_mtx);
err = (child->hub->explore) (child);
+ }
done:
return (err);
@@ -957,9 +978,15 @@
uhub_root_intr(struct usb_bus *bus,
const uint8_t *ptr __unused, uint8_t len __unused)
{
- USB_BUS_LOCK_ASSERT(bus, MA_OWNED);
+ struct uhub_softc *sc = bus->devices[USB_ROOT_HUB_ADDR]->hub->hubsoftc;
- usb_needs_explore(bus, 0);
+ USB_BUS_LOCK_ASSERT(bus, MA_OWNED);
+ if (len > USB_HUB_MAX_DEVS_NUMS / 8)
+ len = USB_HUB_MAX_DEVS_NUMS / 8;
+ USB_MTX_LOCK(&sc->sc_mtx);
+ memcpy(&sc->sc_port_changed, ptr, len);
+ USB_MTX_UNLOCK(&sc->sc_mtx);
+ usb_needs_explore(bus, 0, 0);
}
static uint8_t
@@ -1000,9 +1027,13 @@
uint8_t portno;
uint8_t x;
uint8_t do_unlock;
+ uhub_port_changed_status changed_status;
hub = udev->hub;
sc = hub->hubsoftc;
+ USB_MTX_LOCK(&sc->sc_mtx);
+ UHUB_COPY_USB_PORT_CHANGED(&sc->sc_port_changed, &changed_status);
+ USB_MTX_UNLOCK(&sc->sc_mtx);
DPRINTFN(11, "udev=%p addr=%d\n", udev, udev->address);
@@ -1033,6 +1064,9 @@
up = hub->ports + x;
portno = x + 1;
+ if (!UHUB_GET_USB_PORT_CHANGED(&changed_status, x))
+ continue;
+
err = uhub_read_port_status(sc, portno);
if (err != USB_ERR_NORMAL_COMPLETION)
retval = err;
@@ -1225,6 +1259,7 @@
sc->sc_dev = dev;
mtx_init(&sc->sc_mtx, "USB HUB mutex", NULL, MTX_DEF);
+ mtx_init(&sc->sc_xfer_mtx, "USB HUB xfer mutex", NULL, MTX_DEF);
device_set_usb_desc(dev);
@@ -1400,7 +1435,7 @@
} else {
/* normal HUB */
err = usbd_transfer_setup(udev, &iface_index, sc->sc_xfer,
- uhub_config, UHUB_N_TRANSFER, sc, &sc->sc_mtx);
+ uhub_config, UHUB_N_TRANSFER, sc, &sc->sc_xfer_mtx);
}
if (err) {
DPRINTFN(0, "cannot setup interrupt transfer, "
@@ -1460,7 +1495,6 @@
for (x = 0; x != nports; x++) {
/* set up data structures */
struct usb_port *up = hub->ports + x;
-
up->device_index = 0;
up->restartcnt = 0;
portno = x + 1;
@@ -1518,9 +1552,9 @@
/* Start the interrupt endpoint, if any */
- USB_MTX_LOCK(&sc->sc_mtx);
+ USB_MTX_LOCK(&sc->sc_xfer_mtx);
usbd_transfer_start(sc->sc_xfer[UHUB_INTR_TRANSFER]);
- USB_MTX_UNLOCK(&sc->sc_mtx);
+ USB_MTX_UNLOCK(&sc->sc_xfer_mtx);
/* Enable automatic power save on all USB HUBs */
@@ -1537,6 +1571,7 @@
udev->hub = NULL;
mtx_destroy(&sc->sc_mtx);
+ mtx_destroy(&sc->sc_xfer_mtx);
return (ENXIO);
}
@@ -1588,6 +1623,7 @@
sc->sc_udev->hub = NULL;
mtx_destroy(&sc->sc_mtx);
+ mtx_destroy(&sc->sc_xfer_mtx);
return (0);
}
@@ -2265,9 +2301,10 @@
* This functions is called when the USB event thread needs to run.
*------------------------------------------------------------------------*/
void
-usb_needs_explore(struct usb_bus *bus, uint8_t do_probe)
+usb_needs_explore(struct usb_bus *bus, uint8_t do_probe, uint8_t all_ports)
{
uint8_t do_unlock;
+ struct uhub_softc *sc;
DPRINTF("\n");
@@ -2294,6 +2331,12 @@
if (do_probe) {
bus->do_probe = 1;
}
+ if (all_ports) {
+ sc = bus->devices[USB_ROOT_HUB_ADDR]->hub->hubsoftc;
+ USB_MTX_LOCK(&sc->sc_mtx);
+ UHUB_FILL_USB_PORT_CHANGED(&sc->sc_port_changed);
+ USB_MTX_UNLOCK(&sc->sc_mtx);
+ }
if (usb_proc_msignal(USB_BUS_EXPLORE_PROC(bus),
&bus->explore_msg[0], &bus->explore_msg[1])) {
/* ignore */
@@ -2333,7 +2376,7 @@
if (dev) {
bus = device_get_softc(dev);
if (bus) {
- usb_needs_explore(bus, 1);
+ usb_needs_explore(bus, 1, 1);
}
}
max--;
@@ -2371,7 +2414,7 @@
void
usb_bus_power_update(struct usb_bus *bus)
{
- usb_needs_explore(bus, 0 /* no probe */ );
+ usb_needs_explore(bus, 0 /* no probe */, 1);
}
#endif
@@ -2920,7 +2963,7 @@
#if USB_HAVE_POWERD
usb_bus_power_update(udev->bus);
#else
- usb_needs_explore(udev->bus, 0 /* no probe */ );
+ usb_needs_explore(udev->bus, 0 /* no probe */, 1);
#endif
}
@@ -2959,9 +3002,14 @@
void
usbd_start_re_enumerate(struct usb_device *udev)
{
+ struct uhub_softc *sc = udev->parent_hub->hub->hubsoftc;
+
if (udev->re_enumerate_wait == USB_RE_ENUM_DONE) {
udev->re_enumerate_wait = USB_RE_ENUM_START;
- usb_needs_explore(udev->bus, 0);
+ USB_MTX_LOCK(&sc->sc_mtx);
+ UHUB_SET_USB_PORT_CHANGED(&sc->sc_port_changed, udev->port_no);
+ USB_MTX_UNLOCK(&sc->sc_mtx);
+ usb_needs_explore(udev->bus, 0, 1);
}
}
@@ -2975,6 +3023,8 @@
usb_error_t
usbd_start_set_config(struct usb_device *udev, uint8_t index)
{
+ struct uhub_softc *sc = udev->parent_hub->hub->hubsoftc;
+
if (udev->re_enumerate_wait == USB_RE_ENUM_DONE) {
if (udev->curr_config_index == index) {
/* no change needed */
@@ -2982,7 +3032,10 @@
}
udev->next_config_index = index;
udev->re_enumerate_wait = USB_RE_ENUM_SET_CONFIG;
- usb_needs_explore(udev->bus, 0);
+ USB_MTX_LOCK(&sc->sc_mtx);
+ UHUB_SET_USB_PORT_CHANGED(&sc->sc_port_changed, udev->port_no);
+ USB_MTX_UNLOCK(&sc->sc_mtx);
+ usb_needs_explore(udev->bus, 0, 1);
return (0);
} else if (udev->re_enumerate_wait == USB_RE_ENUM_SET_CONFIG) {
if (udev->next_config_index == index) {
diff --git a/sys/dev/usb/usb_hub_private.h b/sys/dev/usb/usb_hub_private.h
--- a/sys/dev/usb/usb_hub_private.h
+++ b/sys/dev/usb/usb_hub_private.h
@@ -48,6 +48,10 @@
uint16_t port_status;
};
+#define USB_HUB_MAX_DEVS_NUMS 256 /* A hub can have max 16 * 8 = 256 devices */
+__BITSET_DEFINE(_uhub_port_changed_status, USB_HUB_MAX_DEVS_NUMS);
+typedef struct _uhub_port_changed_status uhub_port_changed_status;
+
struct uhub_softc {
struct uhub_current_state sc_st; /* current state */
#if (USB_HAVE_FIXED_PORT != 0)
@@ -55,6 +59,7 @@
#endif
device_t sc_dev; /* base device */
struct mtx sc_mtx; /* our mutex */
+ struct mtx sc_xfer_mtx; /* our xfer mutex */
struct usb_device *sc_udev; /* USB device */
struct usb_xfer *sc_xfer[UHUB_N_TRANSFER]; /* interrupt xfer */
#if USB_HAVE_DISABLE_ENUM
@@ -65,6 +70,17 @@
#define UHUB_USB_PORT_ERRORS_MAX 4
uint8_t sc_flags;
#define UHUB_FLAG_DID_EXPLORE 0x01
+#define UHUB_SET_USB_PORT_CHANGED(ports, portno) \
+ __BIT_SET(USB_HUB_MAX_DEVS_NUMS, portno, ports)
+#define UHUB_CLR_USB_PORT_CHANGED(ports, portno) \
+ __BIT_CLR(USB_HUB_MAX_DEVS_NUMS, portno, ports)
+#define UHUB_GET_USB_PORT_CHANGED(ports, portno) \
+ __BIT_ISSET(USB_HUB_MAX_DEVS_NUMS, portno, ports)
+#define UHUB_FILL_USB_PORT_CHANGED(ports) \
+ __BIT_FILL(USB_HUB_MAX_DEVS_NUMS, ports)
+#define UHUB_COPY_USB_PORT_CHANGED(from, to) \
+ __BIT_COPY(USB_HUB_MAX_DEVS_NUMS, from, to)
+ uhub_port_changed_status sc_port_changed;
};
struct hub_result {
struct usb_device *udev;
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Aug 16, 11:24 AM (4 h, 41 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
36822119
Default Alt Text
D56891.id177469.diff (9 KB)
Attached To
Mode
D56891: usb_hub: Trigger only chaged port on enumeration
Attached
Detach File
Event Timeline
Log In to Comment