diff --git a/sys/dev/usb2/core/usb2_compat_linux.c b/sys/dev/usb2/core/usb2_compat_linux.c index b094a429062..b632cf0cdce 100644 --- a/sys/dev/usb2/core/usb2_compat_linux.c +++ b/sys/dev/usb2/core/usb2_compat_linux.c @@ -393,8 +393,14 @@ usb_linux_shutdown(device_t dev) static uint16_t usb_max_isoc_frames(struct usb_device *dev) { - return ((usb2_get_speed(dev->bsd_udev) == USB_SPEED_HIGH) ? - USB_MAX_HIGH_SPEED_ISOC_FRAMES : USB_MAX_FULL_SPEED_ISOC_FRAMES); + ; /* indent fix */ + switch (usb2_get_speed(dev->bsd_udev)) { + case USB_SPEED_LOW: + case USB_SPEED_FULL: + return (USB_MAX_FULL_SPEED_ISOC_FRAMES); + default: + return (USB_MAX_HIGH_SPEED_ISOC_FRAMES); + } } /*------------------------------------------------------------------------* diff --git a/sys/dev/usb2/core/usb2_device.c b/sys/dev/usb2/core/usb2_device.c index dfe5e8abf65..6f398bc13f1 100644 --- a/sys/dev/usb2/core/usb2_device.c +++ b/sys/dev/usb2/core/usb2_device.c @@ -75,18 +75,6 @@ static usb2_error_t usb2_fill_iface_data(struct usb2_device *, uint8_t, static void usb2_notify_addq(const char *type, struct usb2_device *); static void usb2_fifo_free_wrap(struct usb2_device *, uint8_t, uint8_t); -/* static structures */ - -static const uint8_t usb2_hub_speed_combs[USB_SPEED_MAX][USB_SPEED_MAX] = { - /* HUB *//* subdevice */ - [USB_SPEED_HIGH][USB_SPEED_HIGH] = 1, - [USB_SPEED_HIGH][USB_SPEED_FULL] = 1, - [USB_SPEED_HIGH][USB_SPEED_LOW] = 1, - [USB_SPEED_FULL][USB_SPEED_FULL] = 1, - [USB_SPEED_FULL][USB_SPEED_LOW] = 1, - [USB_SPEED_LOW][USB_SPEED_LOW] = 1, -}; - /* This variable is global to allow easy access to it: */ int usb2_template = 0; @@ -1364,21 +1352,10 @@ usb2_alloc_device(device_t parent_dev, struct usb2_bus *bus, udev->speed = speed; udev->flags.usb2_mode = usb2_mode; - /* check speed combination */ + /* speed combination should be checked by the parent HUB */ hub = udev->parent_hub; - if (hub) { - if (usb2_hub_speed_combs[hub->speed][speed] == 0) { -#if USB_DEBUG - printf("%s: the selected subdevice and HUB speed " - "combination is not supported %d/%d.\n", - __FUNCTION__, speed, hub->speed); -#endif - /* reject this combination */ - err = USB_ERR_INVAL; - goto done; - } - } + /* search for our High Speed USB HUB, if any */ adev = udev; diff --git a/sys/dev/usb2/core/usb2_generic.c b/sys/dev/usb2/core/usb2_generic.c index c486be0231d..79bfc2ffbb5 100644 --- a/sys/dev/usb2/core/usb2_generic.c +++ b/sys/dev/usb2/core/usb2_generic.c @@ -157,12 +157,16 @@ ugen_open(struct usb2_fifo *f, int fflags, struct thread *td) DPRINTFN(6, "flag=0x%x\n", fflags); mtx_lock(f->priv_mtx); - if (usb2_get_speed(f->udev) == USB_SPEED_HIGH) { - f->nframes = UGEN_HW_FRAMES * 8; - f->bufsize = UGEN_BULK_HS_BUFFER_SIZE; - } else { + switch (usb2_get_speed(f->udev)) { + case USB_SPEED_LOW: + case USB_SPEED_FULL: f->nframes = UGEN_HW_FRAMES; f->bufsize = UGEN_BULK_FS_BUFFER_SIZE; + break; + default: + f->nframes = UGEN_HW_FRAMES * 8; + f->bufsize = UGEN_BULK_HS_BUFFER_SIZE; + break; } type = ed->bmAttributes & UE_XFERTYPE; diff --git a/sys/dev/usb2/core/usb2_hub.c b/sys/dev/usb2/core/usb2_hub.c index 6dd6d10ecf8..2c528d4d435 100644 --- a/sys/dev/usb2/core/usb2_hub.c +++ b/sys/dev/usb2/core/usb2_hub.c @@ -372,18 +372,38 @@ repeat: /* * Figure out the device speed */ - speed = - (sc->sc_st.port_status & UPS_HIGH_SPEED) ? USB_SPEED_HIGH : - (sc->sc_st.port_status & UPS_LOW_SPEED) ? USB_SPEED_LOW : USB_SPEED_FULL; - + switch (udev->speed) { + case USB_SPEED_HIGH: + if (sc->sc_st.port_status & UPS_HIGH_SPEED) + speed = USB_SPEED_HIGH; + else if (sc->sc_st.port_status & UPS_LOW_SPEED) + speed = USB_SPEED_LOW; + else + speed = USB_SPEED_FULL; + break; + case USB_SPEED_FULL: + if (sc->sc_st.port_status & UPS_LOW_SPEED) + speed = USB_SPEED_LOW; + else + speed = USB_SPEED_FULL; + break; + case USB_SPEED_LOW: + speed = USB_SPEED_LOW; + break; + default: + /* same speed like parent */ + speed = udev->speed; + break; + } /* * Figure out the device mode * * NOTE: This part is currently FreeBSD specific. */ - usb2_mode = - (sc->sc_st.port_status & UPS_PORT_MODE_DEVICE) ? - USB_MODE_DEVICE : USB_MODE_HOST; + if (sc->sc_st.port_status & UPS_PORT_MODE_DEVICE) + usb2_mode = USB_MODE_DEVICE; + else + usb2_mode = USB_MODE_HOST; /* need to create a new child */ @@ -1049,17 +1069,16 @@ usb2_intr_schedule_adjust(struct usb2_device *udev, int16_t len, uint8_t slot) { struct usb2_bus *bus = udev->bus; struct usb2_hub *hub; + uint8_t speed; USB_BUS_LOCK_ASSERT(bus, MA_OWNED); - if (usb2_get_speed(udev) == USB_SPEED_HIGH) { - if (slot >= USB_HS_MICRO_FRAMES_MAX) { - slot = usb2_intr_find_best_slot(bus->uframe_usage, 0, - USB_HS_MICRO_FRAMES_MAX); - } - bus->uframe_usage[slot] += len; - } else { - if (usb2_get_speed(udev) == USB_SPEED_LOW) { + speed = usb2_get_speed(udev); + + switch (speed) { + case USB_SPEED_LOW: + case USB_SPEED_FULL: + if (speed == USB_SPEED_LOW) { len *= 8; } /* @@ -1076,6 +1095,14 @@ usb2_intr_schedule_adjust(struct usb2_device *udev, int16_t len, uint8_t slot) } hub->uframe_usage[slot] += len; bus->uframe_usage[slot] += len; + break; + default: + if (slot >= USB_HS_MICRO_FRAMES_MAX) { + slot = usb2_intr_find_best_slot(bus->uframe_usage, 0, + USB_HS_MICRO_FRAMES_MAX); + } + bus->uframe_usage[slot] += len; + break; } return (slot); } diff --git a/sys/dev/usb2/core/usb2_transfer.c b/sys/dev/usb2/core/usb2_transfer.c index a5a3e8b0ec8..d47845e4d75 100644 --- a/sys/dev/usb2/core/usb2_transfer.c +++ b/sys/dev/usb2/core/usb2_transfer.c @@ -63,6 +63,7 @@ static const struct usb2_std_packet_size [USB_SPEED_FULL] = {.range = {0, 64}}, [USB_SPEED_HIGH] = {.range = {0, 1024}}, [USB_SPEED_VARIABLE] = {.range = {0, 1024}}, + [USB_SPEED_SUPER] = {.range = {0, 1024}}, }, [UE_CONTROL] = { @@ -70,6 +71,7 @@ static const struct usb2_std_packet_size [USB_SPEED_FULL] = {.fixed = {8, 16, 32, 64}}, [USB_SPEED_HIGH] = {.fixed = {64, 64, 64, 64}}, [USB_SPEED_VARIABLE] = {.fixed = {512, 512, 512, 512}}, + [USB_SPEED_SUPER] = {.fixed = {512, 512, 512, 512}}, }, [UE_BULK] = { @@ -77,6 +79,7 @@ static const struct usb2_std_packet_size [USB_SPEED_FULL] = {.fixed = {8, 16, 32, 64}}, [USB_SPEED_HIGH] = {.fixed = {512, 512, 512, 512}}, [USB_SPEED_VARIABLE] = {.fixed = {512, 512, 1024, 1536}}, + [USB_SPEED_SUPER] = {.fixed = {1024, 1024, 1024, 1024}}, }, [UE_ISOCHRONOUS] = { @@ -84,6 +87,7 @@ static const struct usb2_std_packet_size [USB_SPEED_FULL] = {.range = {0, 1023}}, [USB_SPEED_HIGH] = {.range = {0, 1024}}, [USB_SPEED_VARIABLE] = {.range = {0, 3584}}, + [USB_SPEED_SUPER] = {.range = {0, 1024}}, }, }; @@ -413,10 +417,14 @@ usb2_transfer_setup_sub(struct usb2_setup_params *parm) */ xfer->timeout = 1000 / 4; } - if (parm->speed == USB_SPEED_HIGH) { - frame_limit = USB_MAX_HS_ISOC_FRAMES_PER_XFER; - } else { + switch (parm->speed) { + case USB_SPEED_LOW: + case USB_SPEED_FULL: frame_limit = USB_MAX_FS_ISOC_FRAMES_PER_XFER; + break; + default: + frame_limit = USB_MAX_HS_ISOC_FRAMES_PER_XFER; + break; } if (xfer->nframes > frame_limit) { @@ -446,13 +454,29 @@ usb2_transfer_setup_sub(struct usb2_setup_params *parm) xfer->interval = edesc->bInterval; - if (parm->speed == USB_SPEED_HIGH) { - xfer->interval /= 8; /* 125us -> 1ms */ + switch (parm->speed) { + case USB_SPEED_SUPER: + case USB_SPEED_VARIABLE: + /* 125us -> 1ms */ + if (xfer->interval < 4) + xfer->interval = 1; + else if (xfer->interval > 16) + xfer->interval = (1<<(16-4)); + else + xfer->interval = + (1 << (xfer->interval-4)); + break; + case USB_SPEED_HIGH: + /* 125us -> 1ms */ + xfer->interval /= 8; + break; + default: + break; } if (xfer->interval == 0) { /* - * one millisecond is the smallest - * interval + * One millisecond is the smallest + * interval we support: */ xfer->interval = 1; } diff --git a/sys/dev/usb2/include/usb2_standard.h b/sys/dev/usb2/include/usb2_standard.h index fbe6f366a42..f81f3469a96 100644 --- a/sys/dev/usb2/include/usb2_standard.h +++ b/sys/dev/usb2/include/usb2_standard.h @@ -602,12 +602,12 @@ struct usb2_port_status { #define UPS_SUSPEND 0x0004 #define UPS_OVERCURRENT_INDICATOR 0x0008 #define UPS_RESET 0x0010 -#define UPS_PORT_MODE_DEVICE 0x0020 /* currently FreeBSD specific */ #define UPS_PORT_POWER 0x0100 #define UPS_LOW_SPEED 0x0200 #define UPS_HIGH_SPEED 0x0400 #define UPS_PORT_TEST 0x0800 #define UPS_PORT_INDICATOR 0x1000 +#define UPS_PORT_MODE_DEVICE 0x8000 /* currently FreeBSD specific */ uWord wPortChange; #define UPS_C_CONNECT_STATUS 0x0001 #define UPS_C_PORT_ENABLED 0x0002