/*------------------------------------------------------------------------* * usb_detach *------------------------------------------------------------------------*/ static int usb_detach(device_t dev) { struct usb_bus *bus = device_get_softc(dev); DPRINTF("\n"); if (bus == NULL) { /* was never setup properly */ return (0); } /* Stop power watchdog */ usb_callout_drain(&bus->power_wdog); #if USB_HAVE_ROOT_MOUNT_HOLD /* Let the USB explore process detach all devices. */ usb_root_mount_rel(bus); #endif USB_BUS_LOCK(bus); /* Queue detach job */ usb_proc_msignal(USB_BUS_EXPLORE_PROC(bus), &bus->detach_msg[0], &bus->detach_msg[1]); /* Wait for detach to complete */ usb_proc_mwait(USB_BUS_EXPLORE_PROC(bus), &bus->detach_msg[0], &bus->detach_msg[1]); #if USB_HAVE_UGEN /* Wait for cleanup to complete */ usb_proc_mwait(USB_BUS_EXPLORE_PROC(bus), &bus->cleanup_msg[0], &bus->cleanup_msg[1]); #endif USB_BUS_UNLOCK(bus); #if USB_HAVE_PER_BUS_PROCESS /* Get rid of USB callback processes */ usb_proc_free(USB_BUS_GIANT_PROC(bus)); usb_proc_free(USB_BUS_NON_GIANT_ISOC_PROC(bus)); usb_proc_free(USB_BUS_NON_GIANT_BULK_PROC(bus)); /* Get rid of USB explore process */ usb_proc_free(USB_BUS_EXPLORE_PROC(bus)); /* Get rid of control transfer process */ usb_proc_free(USB_BUS_CONTROL_XFER_PROC(bus)); #endif #if USB_HAVE_PF usbpf_detach(bus); #endif return (0); }
/*------------------------------------------------------------------------* * usb_bus_explore * * This function is used to explore the device tree from the root. *------------------------------------------------------------------------*/ static void usb_bus_explore(struct usb_proc_msg *pm) { struct usb_bus *bus; struct usb_device *udev; bus = ((struct usb_bus_msg *)pm)->bus; udev = bus->devices[USB_ROOT_HUB_ADDR]; if (bus->no_explore != 0) return; if (udev != NULL) { USB_BUS_UNLOCK(bus); uhub_explore_handle_re_enumerate(udev); USB_BUS_LOCK(bus); } if (udev != NULL && udev->hub != NULL) { if (bus->do_probe) { bus->do_probe = 0; bus->driver_added_refcount++; } if (bus->driver_added_refcount == 0) { /* avoid zero, hence that is memory default */ bus->driver_added_refcount = 1; } #ifdef DDB /* * The following three lines of code are only here to * recover from DDB: */ usb_proc_rewakeup(USB_BUS_CONTROL_XFER_PROC(bus)); usb_proc_rewakeup(USB_BUS_GIANT_PROC(bus)); usb_proc_rewakeup(USB_BUS_NON_GIANT_ISOC_PROC(bus)); usb_proc_rewakeup(USB_BUS_NON_GIANT_BULK_PROC(bus)); #endif USB_BUS_UNLOCK(bus); #if USB_HAVE_POWERD /* * First update the USB power state! */ usb_bus_powerd(bus); #endif /* Explore the Root USB HUB. */ (udev->hub->explore) (udev); USB_BUS_LOCK(bus); } #if USB_HAVE_ROOT_MOUNT_HOLD usb_root_mount_rel(bus); #endif }
/*------------------------------------------------------------------------* * usb_detach *------------------------------------------------------------------------*/ static int usb_detach(device_t dev) { struct usb_bus *bus = device_get_softc(dev); DPRINTF("\n"); if (bus == NULL) { /* was never setup properly */ return (0); } /* Stop power watchdog */ usb_callout_drain(&bus->power_wdog); /* Let the USB explore process detach all devices. */ usb_root_mount_rel(bus); USB_BUS_LOCK(bus); /* Queue detach job */ usb_proc_msignal(&bus->explore_proc, &bus->detach_msg[0], &bus->detach_msg[1]); /* Wait for detach to complete */ usb_proc_mwait(&bus->explore_proc, &bus->detach_msg[0], &bus->detach_msg[1]); #if USB_HAVE_UGEN /* Wait for cleanup to complete */ usb_proc_mwait(&bus->explore_proc, &bus->cleanup_msg[0], &bus->cleanup_msg[1]); #endif USB_BUS_UNLOCK(bus); /* Get rid of USB callback processes */ usb_proc_free(&bus->giant_callback_proc); usb_proc_free(&bus->non_giant_callback_proc); /* Get rid of USB explore process */ usb_proc_free(&bus->explore_proc); /* Get rid of control transfer process */ usb_proc_free(&bus->control_xfer_proc); #if USB_HAVE_PF usbpf_detach(bus); #endif return (0); }
/*------------------------------------------------------------------------* * usb_bus_explore * * This function is used to explore the device tree from the root. *------------------------------------------------------------------------*/ static void usb_bus_explore(struct usb_proc_msg *pm) { struct usb_bus *bus; struct usb_device *udev; bus = ((struct usb_bus_msg *)pm)->bus; udev = bus->devices[USB_ROOT_HUB_ADDR]; if (bus->no_explore != 0) return; if (udev && udev->hub) { if (bus->do_probe) { bus->do_probe = 0; bus->driver_added_refcount++; } if (bus->driver_added_refcount == 0) { /* avoid zero, hence that is memory default */ bus->driver_added_refcount = 1; } #ifdef DDB /* * The following three lines of code are only here to * recover from DDB: */ usb_proc_rewakeup(&bus->control_xfer_proc); usb_proc_rewakeup(&bus->giant_callback_proc); usb_proc_rewakeup(&bus->non_giant_callback_proc); #endif USB_BUS_UNLOCK(bus); #if USB_HAVE_POWERD /* * First update the USB power state! */ usb_bus_powerd(bus); #endif /* Explore the Root USB HUB. */ (udev->hub->explore) (udev); USB_BUS_LOCK(bus); } usb_root_mount_rel(bus); }
/*------------------------------------------------------------------------* * usb_bus_attach * * This function attaches USB in context of the explore thread. *------------------------------------------------------------------------*/ static void usb_bus_attach(struct usb_proc_msg *pm) { struct usb_bus *bus; struct usb_device *child; device_t dev; usb_error_t err; enum usb_dev_speed speed; bus = ((struct usb_bus_msg *)pm)->bus; dev = bus->bdev; DPRINTF("\n"); switch (bus->usbrev) { case USB_REV_1_0: speed = USB_SPEED_FULL; device_printf(bus->bdev, "12Mbps Full Speed USB v1.0\n"); break; case USB_REV_1_1: speed = USB_SPEED_FULL; device_printf(bus->bdev, "12Mbps Full Speed USB v1.1\n"); break; case USB_REV_2_0: speed = USB_SPEED_HIGH; device_printf(bus->bdev, "480Mbps High Speed USB v2.0\n"); break; case USB_REV_2_5: speed = USB_SPEED_VARIABLE; device_printf(bus->bdev, "480Mbps Wireless USB v2.5\n"); break; case USB_REV_3_0: speed = USB_SPEED_SUPER; device_printf(bus->bdev, "4.8Gbps Super Speed USB v3.0\n"); break; default: device_printf(bus->bdev, "Unsupported USB revision\n"); usb_root_mount_rel(bus); return; } USB_BUS_UNLOCK(bus); /* default power_mask value */ bus->hw_power_state = USB_HW_POWER_CONTROL | USB_HW_POWER_BULK | USB_HW_POWER_INTERRUPT | USB_HW_POWER_ISOC | USB_HW_POWER_NON_ROOT_HUB; /* make sure power is set at least once */ if (bus->methods->set_hw_power != NULL) { (bus->methods->set_hw_power) (bus); } /* Allocate the Root USB device */ child = usb_alloc_device(bus->bdev, bus, NULL, 0, 0, 1, speed, USB_MODE_HOST); if (child) { err = usb_probe_and_attach(child, USB_IFACE_INDEX_ANY); if (!err) { if ((bus->devices[USB_ROOT_HUB_ADDR] == NULL) || (bus->devices[USB_ROOT_HUB_ADDR]->hub == NULL)) { err = USB_ERR_NO_ROOT_HUB; } } } else { err = USB_ERR_NOMEM; } USB_BUS_LOCK(bus); if (err) { device_printf(bus->bdev, "Root HUB problem, error=%s\n", usbd_errstr(err)); usb_root_mount_rel(bus); } /* set softc - we are ready */ device_set_softc(dev, bus); /* start watchdog */ usb_power_wdog(bus); }