Page MenuHomeFreeBSD

D56891.id.diff
No OneTemporary

D56891.id.diff

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

Mime Type
text/plain
Expires
Mon, Aug 17, 2:54 AM (20 h, 11 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
36822119
Default Alt Text
D56891.id.diff (9 KB)

Event Timeline