diff options
Diffstat (limited to 'sys/dev/usb')
83 files changed, 5939 insertions, 1096 deletions
diff --git a/sys/dev/usb/README.TXT b/sys/dev/usb/README.TXT deleted file mode 100644 index d24770c24068..000000000000 --- a/sys/dev/usb/README.TXT +++ /dev/null @@ -1,411 +0,0 @@ - -$FreeBSD$ - -DESCRIPTION OF THE NEW USB API - -The new USB 2.0 API consists of 5 functions. All transfer types are -managed using these functions. There is no longer need for separate -functions to setup INTERRUPT- and ISOCHRONOUS- transfers. - -+--------------------------------------------------------------+ -| | -| "usb2_transfer_setup" - This function will allocate all | -| necessary DMA memory and might | -| sleep! | -| | -| "usb2_transfer_unsetup" - This function will stop the USB | -| transfer, if it is currently | -| active, release all DMA | -| memory and might sleep! | -| | -| "usb2_transfer_start" - This function will start an USB | -| transfer, if not already started.| -| This function is always | -| non-blocking. ** | -| | -| "usb2_transfer_stop" - This function will stop an USB | -| transfer, if not already stopped.| -| The callback function will be | -| called before this function | -| returns. This function is always | -| non-blocking. ** | -| | -| "usb2_transfer_drain" - This function will stop an USB | -| transfer, if not already stopped | -| and wait for any additional | -| DMA load operations to complete. | -| Buffers that are loaded into DMA | -| using "usb2_set_frame_data" can | -| safely be freed after that | -| this function has returned. This | -| function can block the caller. | -| | -| ** These functions must be called with the private driver's | -| lock locked. | -| | -| NOTE: These USB API functions are NULL safe, with regard | -| to the USB transfer structure pointer. | -+--------------------------------------------------------------+ - -Reference: /sys/dev/usb/usb_transfer.c - -/* - * A simple USB callback state-machine: - * - * +->-----------------------+ - * | | - * +-<-+-------[tr_setup]--------+-<-+-<-[start/restart] - * | | - * | | - * | | - * +------>-[tr_transferred]---------+ - * | | - * +--------->-[tr_error]------------+ - */ - -void -usb2_default_callback(struct usb2_xfer *xfer) -{ - /* - * NOTE: it is not allowed to return - * before "USB_CHECK_STATUS()", - * even if the system is tearing down! - */ - switch (USB_GET_STATE(xfer)) { - case USB_ST_SETUP: - /* - * Setup xfer->frlengths[], xfer->nframes - * and write data to xfer->frbuffers[], if any - */ - - /**/ - usb2_start_hardware(xfer); - return; - - case USB_ST_TRANSFERRED: - /* - * Read data from xfer->frbuffers[], if any. - * "xfer->frlengths[]" should now have been - * updated to the actual length. - */ - return; - - default: /* Error */ - /* print error message and clear stall for example */ - return; - } -} - -=== Notes for USB control transfers === - -An USB control transfer has three parts. First the SETUP packet, then -DATA packet(s) and then a STATUS packet. The SETUP packet is always -pointed to by "xfer->frbuffers[0]" and the length is stored in -"xfer->frlengths[0]" also if there should not be sent any SETUP -packet! If an USB control transfer has no DATA stage, then -"xfer->nframes" should be set to 1. Else the default value is -"xfer->nframes" equal to 2. - -Example1: SETUP + STATUS - xfer->nframes = 1; - xfer->frlenghts[0] = 8; - usb2_start_hardware(xfer); - -Example2: SETUP + DATA + STATUS - xfer->nframes = 2; - xfer->frlenghts[0] = 8; - xfer->frlenghts[1] = 1; - usb2_start_hardware(xfer); - -Example3: SETUP + DATA + STATUS - split -1st callback: - xfer->nframes = 1; - xfer->frlenghts[0] = 8; - usb2_start_hardware(xfer); - -2nd callback: - /* IMPORTANT: frbuffer[0] must still point at the setup packet! */ - xfer->nframes = 2; - xfer->frlenghts[0] = 0; - xfer->frlenghts[1] = 1; - usb2_start_hardware(xfer); - -Example4: SETUP + STATUS - split -1st callback: - xfer->nframes = 1; - xfer->frlenghts[0] = 8; - xfer->flags.manual_status = 1; - usb2_start_hardware(xfer); - -2nd callback: - xfer->nframes = 1; - xfer->frlenghts[0] = 0; - xfer->flags.manual_status = 0; - usb2_start_hardware(xfer); - - -=== General USB transfer notes === - - 1) Something that one should be aware of is that all USB callbacks support -recursation. That means one can start/stop whatever transfer from the callback -of another transfer one desires. Also the transfer that is currently called -back. Recursion is handled like this that when the callback that wants to -recurse returns it is called one more time. - - 2) After that the "usb2_start_hardware()" function has been called in -the callback one can always depend on that "tr_error" or "tr_transferred" -will get jumped afterwards. Always! - - 3) Sleeping functions can only be called from the attach routine of the -driver. Else one should not use sleeping functions unless one has to. It is -very difficult with sleep, because one has to think that the device might have -detached when the thread returns from sleep. - - 4) Polling. - - use_polling - This flag can be used with any callback and will cause the - "usb2_transfer_start()" function to wait using "DELAY()", - without exiting any mutexes, until the transfer is finished or - has timed out. This flag can be changed during operation. - - NOTE: If polling is used the "timeout" field should be non-zero! - NOTE: USB_ERR_CANCELLED is returned in case of timeout - instead of USB_ERR_TIMEOUT! - - - -USB device driver examples: - -/sys/dev/usb/net/if_axe.c -/sys/dev/usb/net/if_aue.c - -QUICK REFERENCE -=============== - - -/*------------------------------------------------------------------------* - * usb2_error_t - * usb2_transfer_setup(udev, ifaces, pxfer, setup_start, - * n_setup, priv_sc, priv_mtx) - *------------------------------------------------------------------------*/ - -- "udev" is a pointer to "struct usb2_device". - -- "ifaces" array of interface index numbers to use. See "if_index". - -- "pxfer" is a pointer to an array of USB transfer pointers that are - initialized to NULL, and then pointed to allocated USB transfers. - -- "setup_start" is a pointer to an array of USB config structures. - -- "n_setup" is a number telling the USB system how many USB transfers - should be setup. - -- "priv_sc" is the private softc pointer, which will be used to - initialize "xfer->priv_sc". - -- "priv_mtx" is the private mutex protecting the transfer structure and - the softc. This pointer is used to initialize "xfer->priv_mtx". - -/*------------------------------------------------------------------------* - * void - * usb2_transfer_unsetup(pxfer, n_setup) - *------------------------------------------------------------------------*/ - -- "pxfer" is a pointer to an array of USB transfer pointers, that may - be NULL, that should be freed by the USB system. - -- "n_setup" is a number telling the USB system how many USB transfers - should be unsetup - -NOTE: This function can sleep, waiting for active mutexes to become unlocked! -NOTE: It is not allowed to call "usb2_transfer_unsetup" from the callback - of a USB transfer. - -/*------------------------------------------------------------------------* - * void - * usb2_transfer_start(xfer) - *------------------------------------------------------------------------*/ - -- "xfer" is pointer to a USB transfer that should be started - -NOTE: this function must be called with "priv_mtx" locked - -/*------------------------------------------------------------------------* - * void - * usb2_transfer_stop(xfer) - *------------------------------------------------------------------------*/ - -- "xfer" is a pointer to a USB transfer that should be stopped - -NOTE: this function must be called with "priv_mtx" locked - -NOTE: if the transfer was in progress, the callback will called with - "xfer->error=USB_ERR_CANCELLED", before this function returns - -/*------------------------------------------------------------------------* - * struct usb2_config { - * type, endpoint, direction, interval, timeout, frames, index - * flags, bufsize, callback - * }; - *------------------------------------------------------------------------*/ - -- The "type" field selects the USB pipe type. Valid values are: - UE_INTERRUPT, UE_CONTROL, UE_BULK, UE_ISOCHRONOUS. The special - value UE_BULK_INTR will select BULK and INTERRUPT pipes. - This field is mandatory. - -- The "endpoint" field selects the USB endpoint number. A value of - 0xFF, "-1" or "UE_ADDR_ANY" will select the first matching endpoint. - This field is mandatory. - -- The "direction" field selects the USB endpoint direction. A value of - "UE_DIR_ANY" will select the first matching endpoint. Else valid - values are: "UE_DIR_IN" and "UE_DIR_OUT". "UE_DIR_IN" and - "UE_DIR_OUT" can be binary ORed by "UE_DIR_SID" which means that the - direction will be swapped in case of USB_MODE_DEVICE. Note that - "UE_DIR_IN" refers to the data transfer direction of the "IN" tokens - and "UE_DIR_OUT" refers to the data transfer direction of the "OUT" - tokens. This field is mandatory. - -- The "interval" field selects the interrupt interval. The value of this - field is given in milliseconds and is independent of device speed. Depending - on the endpoint type, this field has different meaning: - - UE_INTERRUPT) - "0" use the default interrupt interval based on endpoint descriptor. - "Else" use the given value for polling rate. - - UE_ISOCHRONOUS) - "0" use default. - "Else" the value is ignored. - - UE_BULK) - UE_CONTROL) - "0" no transfer pre-delay. - "Else" a delay as given by this field in milliseconds is - inserted before the hardware is started when - "usb2_start_hardware()" is called. - NOTE: The transfer timeout, if any, is started after that - the pre-delay has elapsed! - -- The "timeout" field, if non-zero, will set the transfer timeout in - milliseconds. If the "timeout" field is zero and the transfer type - is ISOCHRONOUS a timeout of 250ms will be used. - -- The "frames" field sets the maximum number of frames. If zero is - specified it will yield the following results: - - UE_BULK) - UE_INTERRUPT) - xfer->nframes = 1; - - UE_CONTROL) - xfer->nframes = 2; - - UE_ISOCHRONOUS) - Not allowed. Will cause an error. - -- The "ep_index" field allows you to give a number, in case more - endpoints match the description, that selects which matching - "ep_index" should be used. - -- The "if_index" field allows you to select which of the interface - numbers in the "ifaces" array parameter passed to "usb2_transfer_setup" - that should be used when setting up the given USB transfer. - -- The "flags" field has type "struct usb2_xfer_flags" and allows one - to set initial flags an USB transfer. Valid flags are: - - force_short_xfer - This flag forces the last transmitted USB packet to be short. - A short packet has a length of less than "xfer->max_packet_size", - which derives from "wMaxPacketSize". This flag can be changed - during operation. - - short_xfer_ok - This flag allows the received transfer length, "xfer->actlen" - to be less than "xfer->sumlen" upon completion of a transfer. - This flag can be changed during operation. - - pipe_bof - This flag causes a failing USB transfer to remain first - in the PIPE queue except in the case of "xfer->error" equal - to "USB_ERR_CANCELLED". No other USB transfers in the affected - PIPE queue will be started until either: - - 1) The failing USB transfer is stopped using "usb2_transfer_stop()". - 2) The failing USB transfer performs a successful transfer. - - The purpose of this flag is to avoid races when multiple - transfers are queued for execution on an USB endpoint, and the - first executing transfer fails leading to the need for - clearing of stall for example. In this case this flag is used - to prevent the following USB transfers from being executed at - the same time the clear-stall command is executed on the USB - control endpoint. This flag can be changed during operation. - - "BOF" is short for "Block On Failure" - - NOTE: This flag should be set on all BULK and INTERRUPT - USB transfers which use an endpoint that can be shared - between userland and kernel. - - proxy_buffer - Setting this flag will cause that the total buffer size will - be rounded up to the nearest atomic hardware transfer - size. The maximum data length of any USB transfer is always - stored in the "xfer->max_data_length". For control transfers - the USB kernel will allocate additional space for the 8-bytes - of SETUP header. These 8-bytes are not counted by the - "xfer->max_data_length" variable. This flag can not be changed - during operation. - - ext_buffer - Setting this flag will cause that no data buffer will be - allocated. Instead the USB client must supply a data buffer. - This flag can not be changed during operation. - - manual_status - Setting this flag prevents an USB STATUS stage to be appended - to the end of the USB control transfer. If no control data is - transferred this flag must be cleared. Else an error will be - returned to the USB callback. This flag is mostly useful for - the USB device side. This flag can be changed during - operation. - - no_pipe_ok - Setting this flag causes the USB_ERR_NO_PIPE error to be - ignored. This flag can not be changed during operation. - - stall_pipe - Setting this flag will cause STALL pids to be sent to the - endpoint belonging to this transfer before the transfer is - started. The transfer is started at the moment the host issues - a clear-stall command on the STALL'ed endpoint. This flag can - be changed during operation. This flag does only have effect - in USB device side mode except for control endpoints. This - flag is cleared when the stall command has been executed. This - flag can only be changed outside the callback function by - using the functions "usb2_transfer_set_stall()" and - "usb2_transfer_clear_stall()" ! - -- The "bufsize" field sets the total buffer size in bytes. If - this field is zero, "wMaxPacketSize" will be used, multiplied by the - "frames" field if the transfer type is ISOCHRONOUS. This is useful for - setting up interrupt pipes. This field is mandatory. - - NOTE: For control transfers "bufsize" includes - the length of the request structure. - -- The "callback" pointer sets the USB callback. This field is mandatory. - -MUTEX NOTE: -=========== - -When you create a mutex using "mtx_init()", don't forget to call -"mtx_destroy()" at detach, else you can get "freed memory accessed" -panics. - ---HPS diff --git a/sys/dev/usb/bluetooth/ng_ubt.c b/sys/dev/usb/bluetooth/ng_ubt.c index a5a19ded53dd..4d97791f9c8c 100644 --- a/sys/dev/usb/bluetooth/ng_ubt.c +++ b/sys/dev/usb/bluetooth/ng_ubt.c @@ -399,7 +399,7 @@ ubt_probe(device_t dev) { struct usb2_attach_arg *uaa = device_get_ivars(dev); - if (uaa->usb2_mode != USB_MODE_HOST) + if (uaa->usb_mode != USB_MODE_HOST) return (ENXIO); if (uaa->info.bIfaceIndex != 0) diff --git a/sys/dev/usb/bluetooth/ubtbcmfw.c b/sys/dev/usb/bluetooth/ubtbcmfw.c index 1932a3971a95..2c53e8259b79 100644 --- a/sys/dev/usb/bluetooth/ubtbcmfw.c +++ b/sys/dev/usb/bluetooth/ubtbcmfw.c @@ -174,7 +174,7 @@ ubtbcmfw_probe(device_t dev) struct usb2_attach_arg *uaa = device_get_ivars(dev); - if (uaa->usb2_mode != USB_MODE_HOST) + if (uaa->usb_mode != USB_MODE_HOST) return (ENXIO); if (uaa->info.bIfaceIndex != 0) diff --git a/sys/dev/usb/controller/at91dci.c b/sys/dev/usb/controller/at91dci.c index 0dfb4fefd253..63a589af0e54 100644 --- a/sys/dev/usb/controller/at91dci.c +++ b/sys/dev/usb/controller/at91dci.c @@ -73,8 +73,8 @@ __FBSDID("$FreeBSD$"); #if USB_DEBUG static int at91dcidebug = 0; -SYSCTL_NODE(_hw_usb2, OID_AUTO, at91dci, CTLFLAG_RW, 0, "USB at91dci"); -SYSCTL_INT(_hw_usb2_at91dci, OID_AUTO, debug, CTLFLAG_RW, +SYSCTL_NODE(_hw_usb, OID_AUTO, at91dci, CTLFLAG_RW, 0, "USB at91dci"); +SYSCTL_INT(_hw_usb_at91dci, OID_AUTO, debug, CTLFLAG_RW, &at91dcidebug, 0, "at91dci debug level"); #endif @@ -848,7 +848,7 @@ at91dci_setup_standard_chain_sub(struct at91dci_std_temp *temp) td->remainder = temp->len; td->fifo_bank = 0; td->error = 0; - td->did_stall = 0; + td->did_stall = temp->did_stall; td->short_pkt = temp->short_pkt; td->alt_next = temp->setup_alt_next; } @@ -879,6 +879,7 @@ at91dci_setup_standard_chain(struct usb2_xfer *xfer) temp.td_next = xfer->td_start[0]; temp.offset = 0; temp.setup_alt_next = xfer->flags_int.short_frames_ok; + temp.did_stall = !xfer->flags_int.control_stall; sc = AT9100_DCI_BUS2SC(xfer->xroot->bus); ep_no = (xfer->endpoint & UE_ADDR); @@ -1193,7 +1194,7 @@ at91dci_device_done(struct usb2_xfer *xfer, usb2_error_t error) DPRINTFN(2, "xfer=%p, pipe=%p, error=%d\n", xfer, xfer->pipe, error); - if (xfer->flags_int.usb2_mode == USB_MODE_DEVICE) { + if (xfer->flags_int.usb_mode == USB_MODE_DEVICE) { ep_no = (xfer->endpoint & UE_ADDR); /* disable endpoint interrupt */ @@ -1337,7 +1338,7 @@ at91dci_clear_stall(struct usb2_device *udev, struct usb2_pipe *pipe) USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED); /* check mode */ - if (udev->flags.usb2_mode != USB_MODE_DEVICE) { + if (udev->flags.usb_mode != USB_MODE_DEVICE) { /* not supported */ return; } @@ -2264,12 +2265,12 @@ at91dci_pipe_init(struct usb2_device *udev, struct usb2_endpoint_descriptor *ede DPRINTFN(2, "pipe=%p, addr=%d, endpt=%d, mode=%d (%d)\n", pipe, udev->address, - edesc->bEndpointAddress, udev->flags.usb2_mode, + edesc->bEndpointAddress, udev->flags.usb_mode, sc->sc_rt_addr); if (udev->device_index != sc->sc_rt_addr) { - if (udev->flags.usb2_mode != USB_MODE_DEVICE) { + if (udev->flags.usb_mode != USB_MODE_DEVICE) { /* not supported */ return; } diff --git a/sys/dev/usb/controller/at91dci.h b/sys/dev/usb/controller/at91dci.h index 0271fb9b8c8e..87cbc87e2408 100644 --- a/sys/dev/usb/controller/at91dci.h +++ b/sys/dev/usb/controller/at91dci.h @@ -169,6 +169,7 @@ struct at91dci_std_temp { * short_pkt = 1: transfer should not be short terminated */ uint8_t setup_alt_next; + uint8_t did_stall; }; struct at91dci_config_desc { diff --git a/sys/dev/usb/controller/atmegadci.c b/sys/dev/usb/controller/atmegadci.c index dc9372a69109..df1fe781672f 100644 --- a/sys/dev/usb/controller/atmegadci.c +++ b/sys/dev/usb/controller/atmegadci.c @@ -65,8 +65,8 @@ __FBSDID("$FreeBSD$"); #if USB_DEBUG static int atmegadci_debug = 0; -SYSCTL_NODE(_hw_usb2, OID_AUTO, atmegadci, CTLFLAG_RW, 0, "USB ATMEGA DCI"); -SYSCTL_INT(_hw_usb2_atmegadci, OID_AUTO, debug, CTLFLAG_RW, +SYSCTL_NODE(_hw_usb, OID_AUTO, atmegadci, CTLFLAG_RW, 0, "USB ATMEGA DCI"); +SYSCTL_INT(_hw_usb_atmegadci, OID_AUTO, debug, CTLFLAG_RW, &atmegadci_debug, 0, "ATMEGA DCI debug level"); #endif @@ -672,7 +672,7 @@ atmegadci_interrupt(struct atmegadci_softc *sc) * that like RESUME. Resume is set when there is at least 3 * milliseconds of inactivity on the USB BUS. */ - if (status & ATMEGA_UDINT_EORSMI) { + if (status & ATMEGA_UDINT_WAKEUPI) { DPRINTFN(5, "resume interrupt\n"); @@ -700,7 +700,7 @@ atmegadci_interrupt(struct atmegadci_softc *sc) /* disable suspend interrupt */ ATMEGA_WRITE_1(sc, ATMEGA_UDIEN, - ATMEGA_UDINT_EORSMI | + ATMEGA_UDINT_WAKEUPE | ATMEGA_UDINT_EORSTE); /* complete root HUB interrupt endpoint */ @@ -751,7 +751,7 @@ atmegadci_setup_standard_chain_sub(struct atmegadci_std_temp *temp) td->offset = temp->offset; td->remainder = temp->len; td->error = 0; - td->did_stall = 0; + td->did_stall = temp->did_stall; td->short_pkt = temp->short_pkt; td->alt_next = temp->setup_alt_next; } @@ -782,6 +782,7 @@ atmegadci_setup_standard_chain(struct usb2_xfer *xfer) temp.td_next = xfer->td_start[0]; temp.offset = 0; temp.setup_alt_next = xfer->flags_int.short_frames_ok; + temp.did_stall = !xfer->flags_int.control_stall; sc = ATMEGA_BUS2SC(xfer->xroot->bus); ep_no = (xfer->endpoint & UE_ADDR); @@ -1076,7 +1077,7 @@ atmegadci_device_done(struct usb2_xfer *xfer, usb2_error_t error) DPRINTFN(9, "xfer=%p, pipe=%p, error=%d\n", xfer, xfer->pipe, error); - if (xfer->flags_int.usb2_mode == USB_MODE_DEVICE) { + if (xfer->flags_int.usb_mode == USB_MODE_DEVICE) { ep_no = (xfer->endpoint & UE_ADDR); /* select endpoint number */ @@ -1152,13 +1153,12 @@ atmegadci_clear_stall_sub(struct atmegadci_softc *sc, uint8_t ep_no, ATMEGA_UECONX_STALLRQC); do { - temp = 0; if (ep_type == UE_BULK) { - temp |= ATMEGA_UECFG0X_EPTYPE2; + temp = ATMEGA_UECFG0X_EPTYPE2; } else if (ep_type == UE_INTERRUPT) { - temp |= ATMEGA_UECFG0X_EPTYPE3; + temp = ATMEGA_UECFG0X_EPTYPE3; } else { - temp |= ATMEGA_UECFG0X_EPTYPE1; + temp = ATMEGA_UECFG0X_EPTYPE1; } if (ep_dir & UE_DIR_IN) { temp |= ATMEGA_UECFG0X_EPDIR; @@ -1188,7 +1188,7 @@ atmegadci_clear_stall(struct usb2_device *udev, struct usb2_pipe *pipe) USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED); /* check mode */ - if (udev->flags.usb2_mode != USB_MODE_DEVICE) { + if (udev->flags.usb_mode != USB_MODE_DEVICE) { /* not supported */ return; } @@ -1217,13 +1217,28 @@ atmegadci_init(struct atmegadci_softc *sc) sc->sc_bus.methods = &atmegadci_bus_methods; USB_BUS_LOCK(&sc->sc_bus); -#if 0 - /* XXX TODO - currently done by boot strap */ + + /* make sure USB is enabled */ + ATMEGA_WRITE_1(sc, ATMEGA_USBCON, + ATMEGA_USBCON_USBE | + ATMEGA_USBCON_FRZCLK); /* enable USB PAD regulator */ ATMEGA_WRITE_1(sc, ATMEGA_UHWCON, - ATMEGA_UHWCON_UVREGE | ATMEGA_UHWCON_UIMOD); -#endif + ATMEGA_UHWCON_UVREGE | + ATMEGA_UHWCON_UIMOD); + + /* the following register sets up the USB PLL, assuming 16MHz X-tal */ + ATMEGA_WRITE_1(sc, 0x49 /* PLLCSR */, 0x14 | 0x02); + + /* wait for PLL to lock */ + for (n = 0; n != 20; n++) { + if (ATMEGA_READ_1(sc, 0x49) & 0x01) + break; + /* wait a little bit for PLL to start */ + usb2_pause_mtx(&sc->sc_bus.bus_mtx, hz / 100); + } + /* make sure USB is enabled */ ATMEGA_WRITE_1(sc, ATMEGA_USBCON, ATMEGA_USBCON_USBE | @@ -1847,6 +1862,11 @@ tr_handle_clear_port_feature: /* clear connect change flag */ sc->sc_flags.change_connect = 0; + if (!sc->sc_flags.status_bus_reset) { + /* we are not connected */ + break; + } + /* configure the control endpoint */ /* select endpoint number */ @@ -2075,12 +2095,12 @@ atmegadci_pipe_init(struct usb2_device *udev, struct usb2_endpoint_descriptor *e DPRINTFN(2, "pipe=%p, addr=%d, endpt=%d, mode=%d (%d,%d)\n", pipe, udev->address, - edesc->bEndpointAddress, udev->flags.usb2_mode, + edesc->bEndpointAddress, udev->flags.usb_mode, sc->sc_rt_addr, udev->device_index); if (udev->device_index != sc->sc_rt_addr) { - if (udev->flags.usb2_mode != USB_MODE_DEVICE) { + if (udev->flags.usb_mode != USB_MODE_DEVICE) { /* not supported */ return; } diff --git a/sys/dev/usb/controller/atmegadci.h b/sys/dev/usb/controller/atmegadci.h index 69939544a781..8f5a538d5678 100644 --- a/sys/dev/usb/controller/atmegadci.h +++ b/sys/dev/usb/controller/atmegadci.h @@ -34,6 +34,10 @@ #define ATMEGA_MAX_DEVICES (USB_MIN_DEVICES + 1) +#define ATMEGA_OTGTCON 0xF9 +#define ATMEGA_OTGTCON_VALUE(x) ((x) << 0) +#define ATMEGA_OTGTCON_PAGE(x) ((x) << 5) + #define ATMEGA_UEINT 0xF4 #define ATMEGA_UEINT_MASK(n) (1 << (n)) /* endpoint interrupt mask */ @@ -136,8 +140,19 @@ #define ATMEGA_UDCON_LSM (1 << 2) #define ATMEGA_UDCON_RSTCPU (1 << 3) +#define ATMEGA_OTGINT 0xDF + +#define ATMEGA_OTGCON 0xDD +#define ATMEGA_OTGCON_VBUSRQC (1 << 0) +#define ATMEGA_OTGCON_VBUSREQ (1 << 1) +#define ATMEGA_OTGCON_VBUSHWC (1 << 2) +#define ATMEGA_OTGCON_SRPSEL (1 << 3) +#define ATMEGA_OTGCON_SRPREQ (1 << 4) +#define ATMEGA_OTGCON_HNPREQ (1 << 5) + #define ATMEGA_USBINT 0xDA #define ATMEGA_USBINT_VBUSTI (1 << 0) /* USB VBUS interrupt */ +#define ATMEGA_USBINT_IDI (1 << 1) /* USB ID interrupt */ #define ATMEGA_USBSTA 0xD9 #define ATMEGA_USBSTA_VBUS (1 << 0) @@ -145,6 +160,7 @@ #define ATMEGA_USBCON 0xD8 #define ATMEGA_USBCON_VBUSTE (1 << 0) +#define ATMEGA_USBCON_IDE (1 << 1) #define ATMEGA_USBCON_OTGPADE (1 << 4) #define ATMEGA_USBCON_FRZCLK (1 << 5) #define ATMEGA_USBCON_USBE (1 << 7) @@ -206,6 +222,7 @@ struct atmegadci_std_temp { * short_pkt = 1: transfer should not be short terminated */ uint8_t setup_alt_next; + uint8_t did_stall; }; struct atmegadci_config_desc { diff --git a/sys/dev/usb/controller/avr32dci.c b/sys/dev/usb/controller/avr32dci.c new file mode 100644 index 000000000000..1836589aa906 --- /dev/null +++ b/sys/dev/usb/controller/avr32dci.c @@ -0,0 +1,2065 @@ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/*- + * Copyright (c) 2009 Hans Petter Selasky. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This file contains the driver for the AVR32 series USB Device + * Controller + */ + +/* + * NOTE: When the chip detects BUS-reset it will also reset the + * endpoints, Function-address and more. + */ + +#include <dev/usb/usb.h> +#include <dev/usb/usb_mfunc.h> +#include <dev/usb/usb_error.h> + +#define USB_DEBUG_VAR avr32dci_debug + +#include <dev/usb/usb_core.h> +#include <dev/usb/usb_debug.h> +#include <dev/usb/usb_busdma.h> +#include <dev/usb/usb_process.h> +#include <dev/usb/usb_transfer.h> +#include <dev/usb/usb_device.h> +#include <dev/usb/usb_hub.h> +#include <dev/usb/usb_util.h> + +#include <dev/usb/usb_controller.h> +#include <dev/usb/usb_bus.h> +#include <dev/usb/controller/avr32dci.h> + +#define AVR32_BUS2SC(bus) \ + ((struct avr32dci_softc *)(((uint8_t *)(bus)) - \ + ((uint8_t *)&(((struct avr32dci_softc *)0)->sc_bus)))) + +#define AVR32_PC2SC(pc) \ + AVR32_BUS2SC(USB_DMATAG_TO_XROOT((pc)->tag_parent)->bus) + +#if USB_DEBUG +static int avr32dci_debug = 0; + +SYSCTL_NODE(_hw_usb, OID_AUTO, avr32dci, CTLFLAG_RW, 0, "USB AVR32 DCI"); +SYSCTL_INT(_hw_usb_avr32dci, OID_AUTO, debug, CTLFLAG_RW, + &avr32dci_debug, 0, "AVR32 DCI debug level"); +#endif + +#define AVR32_INTR_ENDPT 1 + +/* prototypes */ + +struct usb2_bus_methods avr32dci_bus_methods; +struct usb2_pipe_methods avr32dci_device_non_isoc_methods; +struct usb2_pipe_methods avr32dci_device_isoc_fs_methods; + +static avr32dci_cmd_t avr32dci_setup_rx; +static avr32dci_cmd_t avr32dci_data_rx; +static avr32dci_cmd_t avr32dci_data_tx; +static avr32dci_cmd_t avr32dci_data_tx_sync; +static void avr32dci_device_done(struct usb2_xfer *, usb2_error_t); +static void avr32dci_do_poll(struct usb2_bus *); +static void avr32dci_standard_done(struct usb2_xfer *); +static void avr32dci_root_intr(struct avr32dci_softc *sc); + +/* + * Here is a list of what the chip supports: + */ +static const struct usb2_hw_ep_profile + avr32dci_ep_profile[4] = { + + [0] = { + .max_in_frame_size = 64, + .max_out_frame_size = 64, + .is_simplex = 1, + .support_control = 1, + }, + + [1] = { + .max_in_frame_size = 512, + .max_out_frame_size = 512, + .is_simplex = 1, + .support_bulk = 1, + .support_interrupt = 1, + .support_isochronous = 1, + .support_in = 1, + .support_out = 1, + }, + + [2] = { + .max_in_frame_size = 64, + .max_out_frame_size = 64, + .is_simplex = 1, + .support_bulk = 1, + .support_interrupt = 1, + .support_in = 1, + .support_out = 1, + }, + + [3] = { + .max_in_frame_size = 1024, + .max_out_frame_size = 1024, + .is_simplex = 1, + .support_bulk = 1, + .support_interrupt = 1, + .support_isochronous = 1, + .support_in = 1, + .support_out = 1, + }, +}; + +static void +avr32dci_get_hw_ep_profile(struct usb2_device *udev, + const struct usb2_hw_ep_profile **ppf, uint8_t ep_addr) +{ + if (ep_addr == 0) + *ppf = avr32dci_ep_profile; + else if (ep_addr < 3) + *ppf = avr32dci_ep_profile + 1; + else if (ep_addr < 5) + *ppf = avr32dci_ep_profile + 2; + else if (ep_addr < 7) + *ppf = avr32dci_ep_profile + 3; + else + *ppf = NULL; +} + +static void +avr32dci_mod_ctrl(struct avr32dci_softc *sc, uint32_t set, uint32_t clear) +{ + uint32_t temp; + + temp = AVR32_READ_4(sc, AVR32_CTRL); + temp |= set; + temp &= ~clear; + AVR32_WRITE_4(sc, AVR32_CTRL, temp); +} + +static void +avr32dci_mod_ien(struct avr32dci_softc *sc, uint32_t set, uint32_t clear) +{ + uint32_t temp; + + temp = AVR32_READ_4(sc, AVR32_IEN); + temp |= set; + temp &= ~clear; + AVR32_WRITE_4(sc, AVR32_IEN, temp); +} + +static void +avr32dci_clocks_on(struct avr32dci_softc *sc) +{ + if (sc->sc_flags.clocks_off && + sc->sc_flags.port_powered) { + + DPRINTFN(5, "\n"); + + /* turn on clocks */ + (sc->sc_clocks_on) (&sc->sc_bus); + + avr32dci_mod_ctrl(sc, AVR32_CTRL_DEV_EN_USBA, 0); + + sc->sc_flags.clocks_off = 0; + } +} + +static void +avr32dci_clocks_off(struct avr32dci_softc *sc) +{ + if (!sc->sc_flags.clocks_off) { + + DPRINTFN(5, "\n"); + + avr32dci_mod_ctrl(sc, 0, AVR32_CTRL_DEV_EN_USBA); + + /* turn clocks off */ + (sc->sc_clocks_off) (&sc->sc_bus); + + sc->sc_flags.clocks_off = 1; + } +} + +static void +avr32dci_pull_up(struct avr32dci_softc *sc) +{ + /* pullup D+, if possible */ + + if (!sc->sc_flags.d_pulled_up && + sc->sc_flags.port_powered) { + sc->sc_flags.d_pulled_up = 1; + avr32dci_mod_ctrl(sc, 0, AVR32_CTRL_DEV_DETACH); + } +} + +static void +avr32dci_pull_down(struct avr32dci_softc *sc) +{ + /* pulldown D+, if possible */ + + if (sc->sc_flags.d_pulled_up) { + sc->sc_flags.d_pulled_up = 0; + avr32dci_mod_ctrl(sc, AVR32_CTRL_DEV_DETACH, 0); + } +} + +static void +avr32dci_wakeup_peer(struct avr32dci_softc *sc) +{ + if (!sc->sc_flags.status_suspend) { + return; + } + avr32dci_mod_ctrl(sc, AVR32_CTRL_DEV_REWAKEUP, 0); + + /* wait 8 milliseconds */ + /* Wait for reset to complete. */ + usb2_pause_mtx(&sc->sc_bus.bus_mtx, hz / 125); + + /* hardware should have cleared RMWKUP bit */ +} + +static void +avr32dci_set_address(struct avr32dci_softc *sc, uint8_t addr) +{ + DPRINTFN(5, "addr=%d\n", addr); + + avr32dci_mod_ctrl(sc, AVR32_UDADDR_ADDEN | addr, 0); +} + +static uint8_t +avr32dci_setup_rx(struct avr32dci_td *td) +{ + struct avr32dci_softc *sc; + struct usb2_device_request req; + uint16_t count; + uint32_t temp; + + /* get pointer to softc */ + sc = AVR32_PC2SC(td->pc); + + /* check endpoint status */ + temp = AVR32_READ_4(sc, AVR32_EPTSTA(td->ep_no)); + + DPRINTFN(5, "EPTSTA(%u)=0x%08x\n", td->ep_no, temp); + + if (!(temp & AVR32_EPTSTA_RX_SETUP)) { + goto not_complete; + } + /* clear did stall */ + td->did_stall = 0; + /* get the packet byte count */ + count = AVR32_EPTSTA_BYTE_COUNT(temp); + + /* verify data length */ + if (count != td->remainder) { + DPRINTFN(0, "Invalid SETUP packet " + "length, %d bytes\n", count); + goto not_complete; + } + if (count != sizeof(req)) { + DPRINTFN(0, "Unsupported SETUP packet " + "length, %d bytes\n", count); + goto not_complete; + } + /* receive data */ + memcpy(&req, sc->physdata, sizeof(req)); + + /* copy data into real buffer */ + usb2_copy_in(td->pc, 0, &req, sizeof(req)); + + td->offset = sizeof(req); + td->remainder = 0; + + /* sneak peek the set address */ + if ((req.bmRequestType == UT_WRITE_DEVICE) && + (req.bRequest == UR_SET_ADDRESS)) { + sc->sc_dv_addr = req.wValue[0] & 0x7F; + /* must write address before ZLP */ + avr32dci_mod_ctrl(sc, 0, AVR32_CTRL_DEV_FADDR_EN | + AVR32_CTRL_DEV_ADDR); + avr32dci_mod_ctrl(sc, sc->sc_dv_addr, 0); + } else { + sc->sc_dv_addr = 0xFF; + } + + /* clear SETUP packet interrupt */ + AVR32_WRITE_4(sc, AVR32_EPTCLRSTA(td->ep_no), AVR32_EPTSTA_RX_SETUP); + return (0); /* complete */ + +not_complete: + if (temp & AVR32_EPTSTA_RX_SETUP) { + /* clear SETUP packet interrupt */ + AVR32_WRITE_4(sc, AVR32_EPTCLRSTA(td->ep_no), AVR32_EPTSTA_RX_SETUP); + } + /* abort any ongoing transfer */ + if (!td->did_stall) { + DPRINTFN(5, "stalling\n"); + AVR32_WRITE_4(sc, AVR32_EPTSETSTA(td->ep_no), + AVR32_EPTSTA_FRCESTALL); + td->did_stall = 1; + } + return (1); /* not complete */ +} + +static uint8_t +avr32dci_data_rx(struct avr32dci_td *td) +{ + struct avr32dci_softc *sc; + struct usb2_page_search buf_res; + uint16_t count; + uint32_t temp; + uint8_t to; + uint8_t got_short; + + to = 4; /* don't loop forever! */ + got_short = 0; + + /* get pointer to softc */ + sc = AVR32_PC2SC(td->pc); + +repeat: + /* check if any of the FIFO banks have data */ + /* check endpoint status */ + temp = AVR32_READ_4(sc, AVR32_EPTSTA(td->ep_no)); + + DPRINTFN(5, "EPTSTA(%u)=0x%08x\n", td->ep_no, temp); + + if (temp & AVR32_EPTSTA_RX_SETUP) { + if (td->remainder == 0) { + /* + * We are actually complete and have + * received the next SETUP + */ + DPRINTFN(5, "faking complete\n"); + return (0); /* complete */ + } + /* + * USB Host Aborted the transfer. + */ + td->error = 1; + return (0); /* complete */ + } + /* check status */ + if (!(temp & AVR32_EPTSTA_RX_BK_RDY)) { + /* no data */ + goto not_complete; + } + /* get the packet byte count */ + count = AVR32_EPTSTA_BYTE_COUNT(temp); + + /* verify the packet byte count */ + if (count != td->max_packet_size) { + if (count < td->max_packet_size) { + /* we have a short packet */ + td->short_pkt = 1; + got_short = 1; + } else { + /* invalid USB packet */ + td->error = 1; + return (0); /* we are complete */ + } + } + /* verify the packet byte count */ + if (count > td->remainder) { + /* invalid USB packet */ + td->error = 1; + return (0); /* we are complete */ + } + while (count > 0) { + usb2_get_page(td->pc, td->offset, &buf_res); + + /* get correct length */ + if (buf_res.length > count) { + buf_res.length = count; + } + /* receive data */ + bcopy(sc->physdata + + (AVR32_EPTSTA_CURRENT_BANK(temp) << td->bank_shift) + + (td->ep_no << 16) + (td->offset % td->max_packet_size), + buf_res.buffer, buf_res.length) + /* update counters */ + count -= buf_res.length; + td->offset += buf_res.length; + td->remainder -= buf_res.length; + } + + /* clear OUT packet interrupt */ + AVR32_WRITE_4(sc, AVR32_EPTCLRSTA(td->ep_no), AVR32_EPTSTA_RX_BK_RDY); + + /* check if we are complete */ + if ((td->remainder == 0) || got_short) { + if (td->short_pkt) { + /* we are complete */ + return (0); + } + /* else need to receive a zero length packet */ + } + if (--to) { + goto repeat; + } +not_complete: + return (1); /* not complete */ +} + +static uint8_t +avr32dci_data_tx(struct avr32dci_td *td) +{ + struct avr32dci_softc *sc; + struct usb2_page_search buf_res; + uint16_t count; + uint8_t to; + uint32_t temp; + + to = 4; /* don't loop forever! */ + + /* get pointer to softc */ + sc = AVR32_PC2SC(td->pc); + +repeat: + + /* check endpoint status */ + temp = AVR32_READ_4(sc, AVR32_EPTSTA(td->ep_no)); + + DPRINTFN(5, "EPTSTA(%u)=0x%08x\n", td->ep_no, temp); + + if (temp & AVR32_EPTSTA_RX_SETUP) { + /* + * The current transfer was aborted + * by the USB Host + */ + td->error = 1; + return (0); /* complete */ + } + if (temp & AVR32_EPTSTA_TX_PK_RDY) { + /* cannot write any data - all banks are busy */ + goto not_complete; + } + count = td->max_packet_size; + if (td->remainder < count) { + /* we have a short packet */ + td->short_pkt = 1; + count = td->remainder; + } + while (count > 0) { + + usb2_get_page(td->pc, td->offset, &buf_res); + + /* get correct length */ + if (buf_res.length > count) { + buf_res.length = count; + } + /* transmit data */ + bcopy(buf_res.buffer, sc->physdata + + (AVR32_EPTSTA_CURRENT_BANK(temp) << td->bank_shift) + + (td->ep_no << 16) + (td->offset % td->max_packet_size), + buf_res.length) + /* update counters */ + count -= buf_res.length; + td->offset += buf_res.length; + td->remainder -= buf_res.length; + } + + /* allocate FIFO bank */ + AVR32_WRITE_4(sc, AVR32_EPTCLRSTA(td->ep_no), AVR32_EPTSTA_TX_BK_RDY); + + /* check remainder */ + if (td->remainder == 0) { + if (td->short_pkt) { + return (0); /* complete */ + } + /* else we need to transmit a short packet */ + } + if (--to) { + goto repeat; + } +not_complete: + return (1); /* not complete */ +} + +static uint8_t +avr32dci_data_tx_sync(struct avr32dci_td *td) +{ + struct avr32dci_softc *sc; + uint32_t temp; + + /* get pointer to softc */ + sc = AVR32_PC2SC(td->pc); + + /* check endpoint status */ + temp = AVR32_READ_4(sc, AVR32_EPTSTA(td->ep_no)); + + DPRINTFN(5, "EPTSTA(%u)=0x%08x\n", td->ep_no, temp); + + if (temp & AVR32_EPTSTA_RX_SETUP) { + DPRINTFN(5, "faking complete\n"); + /* Race condition */ + return (0); /* complete */ + } + /* + * The control endpoint has only got one bank, so if that bank + * is free the packet has been transferred! + */ + if (AVR32_EPTSTA_BUSY_BANK_STA(temp) != 0) { + /* cannot write any data - a bank is busy */ + goto not_complete; + } + if (sc->sc_dv_addr != 0xFF) { + /* set new address */ + avr32dci_set_address(sc, sc->sc_dv_addr); + } + return (0); /* complete */ + +not_complete: + return (1); /* not complete */ +} + +static uint8_t +avr32dci_xfer_do_fifo(struct usb2_xfer *xfer) +{ + struct avr32dci_td *td; + + DPRINTFN(9, "\n"); + + td = xfer->td_transfer_cache; + while (1) { + if ((td->func) (td)) { + /* operation in progress */ + break; + } + if (((void *)td) == xfer->td_transfer_last) { + goto done; + } + if (td->error) { + goto done; + } else if (td->remainder > 0) { + /* + * We had a short transfer. If there is no alternate + * next, stop processing ! + */ + if (!td->alt_next) { + goto done; + } + } + /* + * Fetch the next transfer descriptor and transfer + * some flags to the next transfer descriptor + */ + td = td->obj_next; + xfer->td_transfer_cache = td; + } + return (1); /* not complete */ + +done: + /* compute all actual lengths */ + + avr32dci_standard_done(xfer); + return (0); /* complete */ +} + +static void +avr32dci_interrupt_poll(struct avr32dci_softc *sc) +{ + struct usb2_xfer *xfer; + +repeat: + TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { + if (!avr32dci_xfer_do_fifo(xfer)) { + /* queue has been modified */ + goto repeat; + } + } +} + +void +avr32dci_vbus_interrupt(struct avr32dci_softc *sc, uint8_t is_on) +{ + DPRINTFN(5, "vbus = %u\n", is_on); + + if (is_on) { + if (!sc->sc_flags.status_vbus) { + sc->sc_flags.status_vbus = 1; + + /* complete root HUB interrupt endpoint */ + + avr32dci_root_intr(sc); + } + } else { + if (sc->sc_flags.status_vbus) { + sc->sc_flags.status_vbus = 0; + sc->sc_flags.status_bus_reset = 0; + sc->sc_flags.status_suspend = 0; + sc->sc_flags.change_suspend = 0; + sc->sc_flags.change_connect = 1; + + /* complete root HUB interrupt endpoint */ + + avr32dci_root_intr(sc); + } + } +} + +void +avr32dci_interrupt(struct avr32dci_softc *sc) +{ + uint32_t status; + + USB_BUS_LOCK(&sc->sc_bus); + + /* read interrupt status */ + status = AVR32_READ_4(sc, AVR32_INTSTA); + + /* clear all set interrupts */ + AVR32_WRITE_4(sc, AVR32_CLRINT, status); + + DPRINTFN(14, "INTSTA=0x%08x\n", status); + + /* check for any bus state change interrupts */ + if (status & AVR32_INT_ENDRESET) { + + DPRINTFN(5, "end of reset\n"); + + /* set correct state */ + sc->sc_flags.status_bus_reset = 1; + sc->sc_flags.status_suspend = 0; + sc->sc_flags.change_suspend = 0; + sc->sc_flags.change_connect = 1; + + /* disable resume interrupt */ + avr32dci_mod_ien(sc, AVR32_INT_DET_SUSPD | + AVR32_INT_ENDRESET, AVR32_INT_WAKE_UP); + + /* complete root HUB interrupt endpoint */ + avr32dci_root_intr(sc); + } + /* + * If resume and suspend is set at the same time we interpret + * that like RESUME. Resume is set when there is at least 3 + * milliseconds of inactivity on the USB BUS. + */ + if (status & AVR32_INT_WAKE_UP) { + + DPRINTFN(5, "resume interrupt\n"); + + if (sc->sc_flags.status_suspend) { + /* update status bits */ + sc->sc_flags.status_suspend = 0; + sc->sc_flags.change_suspend = 1; + + /* disable resume interrupt */ + avr32dci_mod_ien(sc, AVR32_INT_DET_SUSPD | + AVR32_INT_ENDRESET, AVR32_INT_WAKE_UP); + + /* complete root HUB interrupt endpoint */ + avr32dci_root_intr(sc); + } + } else if (status & AVR32_INT_DET_SUSPD) { + + DPRINTFN(5, "suspend interrupt\n"); + + if (!sc->sc_flags.status_suspend) { + /* update status bits */ + sc->sc_flags.status_suspend = 1; + sc->sc_flags.change_suspend = 1; + + /* disable suspend interrupt */ + avr32dci_mod_ien(sc, AVR32_INT_WAKE_UP | + AVR32_INT_ENDRESET, AVR32_INT_DET_SUSPD); + + /* complete root HUB interrupt endpoint */ + avr32dci_root_intr(sc); + } + } + /* check for any endpoint interrupts */ + if (status & -AVR32_INT_EPT_INT(0)) { + + DPRINTFN(5, "real endpoint interrupt\n"); + + avr32dci_interrupt_poll(sc); + } + USB_BUS_UNLOCK(&sc->sc_bus); +} + +static void +avr32dci_setup_standard_chain_sub(struct avr32dci_std_temp *temp) +{ + struct avr32dci_td *td; + + /* get current Transfer Descriptor */ + td = temp->td_next; + temp->td = td; + + /* prepare for next TD */ + temp->td_next = td->obj_next; + + /* fill out the Transfer Descriptor */ + td->func = temp->func; + td->pc = temp->pc; + td->offset = temp->offset; + td->remainder = temp->len; + td->error = 0; + td->did_stall = temp->did_stall; + td->short_pkt = temp->short_pkt; + td->alt_next = temp->setup_alt_next; +} + +static void +avr32dci_setup_standard_chain(struct usb2_xfer *xfer) +{ + struct avr32dci_std_temp temp; + struct avr32dci_softc *sc; + struct avr32dci_td *td; + uint32_t x; + uint8_t ep_no; + uint8_t need_sync; + + DPRINTFN(9, "addr=%d endpt=%d sumlen=%d speed=%d\n", + xfer->address, UE_GET_ADDR(xfer->endpoint), + xfer->sumlen, usb2_get_speed(xfer->xroot->udev)); + + temp.max_frame_size = xfer->max_frame_size; + + td = xfer->td_start[0]; + xfer->td_transfer_first = td; + xfer->td_transfer_cache = td; + + /* setup temp */ + + temp.td = NULL; + temp.td_next = xfer->td_start[0]; + temp.offset = 0; + temp.setup_alt_next = xfer->flags_int.short_frames_ok; + temp.did_stall = !xfer->flags_int.control_stall; + + sc = AVR32_BUS2SC(xfer->xroot->bus); + ep_no = (xfer->endpoint & UE_ADDR); + + /* check if we should prepend a setup message */ + + if (xfer->flags_int.control_xfr) { + if (xfer->flags_int.control_hdr) { + + temp.func = &avr32dci_setup_rx; + temp.len = xfer->frlengths[0]; + temp.pc = xfer->frbuffers + 0; + temp.short_pkt = temp.len ? 1 : 0; + /* check for last frame */ + if (xfer->nframes == 1) { + /* no STATUS stage yet, SETUP is last */ + if (xfer->flags_int.control_act) + temp.setup_alt_next = 0; + } + avr32dci_setup_standard_chain_sub(&temp); + } + x = 1; + } else { + x = 0; + } + + if (x != xfer->nframes) { + if (xfer->endpoint & UE_DIR_IN) { + temp.func = &avr32dci_data_tx; + need_sync = 1; + } else { + temp.func = &avr32dci_data_rx; + need_sync = 0; + } + + /* setup "pc" pointer */ + temp.pc = xfer->frbuffers + x; + } else { + need_sync = 0; + } + while (x != xfer->nframes) { + + /* DATA0 / DATA1 message */ + + temp.len = xfer->frlengths[x]; + + x++; + + if (x == xfer->nframes) { + if (xfer->flags_int.control_xfr) { + if (xfer->flags_int.control_act) { + temp.setup_alt_next = 0; + } + } else { + temp.setup_alt_next = 0; + } + } + if (temp.len == 0) { + + /* make sure that we send an USB packet */ + + temp.short_pkt = 0; + + } else { + + /* regular data transfer */ + + temp.short_pkt = (xfer->flags.force_short_xfer) ? 0 : 1; + } + + avr32dci_setup_standard_chain_sub(&temp); + + if (xfer->flags_int.isochronous_xfr) { + temp.offset += temp.len; + } else { + /* get next Page Cache pointer */ + temp.pc = xfer->frbuffers + x; + } + } + + if (xfer->flags_int.control_xfr) { + + /* always setup a valid "pc" pointer for status and sync */ + temp.pc = xfer->frbuffers + 0; + temp.len = 0; + temp.short_pkt = 0; + temp.setup_alt_next = 0; + + /* check if we need to sync */ + if (need_sync) { + /* we need a SYNC point after TX */ + temp.func = &avr32dci_data_tx_sync; + avr32dci_setup_standard_chain_sub(&temp); + } + /* check if we should append a status stage */ + if (!xfer->flags_int.control_act) { + + /* + * Send a DATA1 message and invert the current + * endpoint direction. + */ + if (xfer->endpoint & UE_DIR_IN) { + temp.func = &avr32dci_data_rx; + need_sync = 0; + } else { + temp.func = &avr32dci_data_tx; + need_sync = 1; + } + + avr32dci_setup_standard_chain_sub(&temp); + if (need_sync) { + /* we need a SYNC point after TX */ + temp.func = &avr32dci_data_tx_sync; + avr32dci_setup_standard_chain_sub(&temp); + } + } + } + /* must have at least one frame! */ + td = temp.td; + xfer->td_transfer_last = td; +} + +static void +avr32dci_timeout(void *arg) +{ + struct usb2_xfer *xfer = arg; + + DPRINTF("xfer=%p\n", xfer); + + USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED); + + /* transfer is transferred */ + avr32dci_device_done(xfer, USB_ERR_TIMEOUT); +} + +static void +avr32dci_start_standard_chain(struct usb2_xfer *xfer) +{ + DPRINTFN(9, "\n"); + + /* poll one time - will turn on interrupts */ + if (avr32dci_xfer_do_fifo(xfer)) { + uint8_t ep_no = xfer->endpoint & UE_ADDR_MASK; + + avr32dci_mod_ien(sc, AVR32_INT_EPT_INT(ep_no), 0); + + /* put transfer on interrupt queue */ + usb2_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer); + + /* start timeout, if any */ + if (xfer->timeout != 0) { + usb2_transfer_timeout_ms(xfer, + &avr32dci_timeout, xfer->timeout); + } + } +} + +static void +avr32dci_root_intr(struct avr32dci_softc *sc) +{ + DPRINTFN(9, "\n"); + + USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); + + /* set port bit */ + sc->sc_hub_idata[0] = 0x02; /* we only have one port */ + + uhub_root_intr(&sc->sc_bus, sc->sc_hub_idata, + sizeof(sc->sc_hub_idata)); +} + +static usb2_error_t +avr32dci_standard_done_sub(struct usb2_xfer *xfer) +{ + struct avr32dci_td *td; + uint32_t len; + uint8_t error; + + DPRINTFN(9, "\n"); + + td = xfer->td_transfer_cache; + + do { + len = td->remainder; + + if (xfer->aframes != xfer->nframes) { + /* + * Verify the length and subtract + * the remainder from "frlengths[]": + */ + if (len > xfer->frlengths[xfer->aframes]) { + td->error = 1; + } else { + xfer->frlengths[xfer->aframes] -= len; + } + } + /* Check for transfer error */ + if (td->error) { + /* the transfer is finished */ + error = 1; + td = NULL; + break; + } + /* Check for short transfer */ + if (len > 0) { + if (xfer->flags_int.short_frames_ok) { + /* follow alt next */ + if (td->alt_next) { + td = td->obj_next; + } else { + td = NULL; + } + } else { + /* the transfer is finished */ + td = NULL; + } + error = 0; + break; + } + td = td->obj_next; + + /* this USB frame is complete */ + error = 0; + break; + + } while (0); + + /* update transfer cache */ + + xfer->td_transfer_cache = td; + + return (error ? + USB_ERR_STALLED : USB_ERR_NORMAL_COMPLETION); +} + +static void +avr32dci_standard_done(struct usb2_xfer *xfer) +{ + usb2_error_t err = 0; + + DPRINTFN(13, "xfer=%p pipe=%p transfer done\n", + xfer, xfer->pipe); + + /* reset scanner */ + + xfer->td_transfer_cache = xfer->td_transfer_first; + + if (xfer->flags_int.control_xfr) { + + if (xfer->flags_int.control_hdr) { + + err = avr32dci_standard_done_sub(xfer); + } + xfer->aframes = 1; + + if (xfer->td_transfer_cache == NULL) { + goto done; + } + } + while (xfer->aframes != xfer->nframes) { + + err = avr32dci_standard_done_sub(xfer); + xfer->aframes++; + + if (xfer->td_transfer_cache == NULL) { + goto done; + } + } + + if (xfer->flags_int.control_xfr && + !xfer->flags_int.control_act) { + + err = avr32dci_standard_done_sub(xfer); + } +done: + avr32dci_device_done(xfer, err); +} + +/*------------------------------------------------------------------------* + * avr32dci_device_done + * + * NOTE: this function can be called more than one time on the + * same USB transfer! + *------------------------------------------------------------------------*/ +static void +avr32dci_device_done(struct usb2_xfer *xfer, usb2_error_t error) +{ + struct avr32dci_softc *sc = AVR32_BUS2SC(xfer->xroot->bus); + uint8_t ep_no; + + USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); + + DPRINTFN(9, "xfer=%p, pipe=%p, error=%d\n", + xfer, xfer->pipe, error); + + if (xfer->flags_int.usb_mode == USB_MODE_DEVICE) { + ep_no = (xfer->endpoint & UE_ADDR); + + /* disable endpoint interrupt */ + avr32dci_mod_ien(sc, 0, AVR32_INT_EPT_INT(ep_no)); + + DPRINTFN(15, "disabled interrupts!\n"); + } + /* dequeue transfer and start next transfer */ + usb2_transfer_done(xfer, error); +} + +static void +avr32dci_set_stall(struct usb2_device *udev, struct usb2_xfer *xfer, + struct usb2_pipe *pipe) +{ + struct avr32dci_softc *sc; + uint8_t ep_no; + + USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED); + + DPRINTFN(5, "pipe=%p\n", pipe); + + if (xfer) { + /* cancel any ongoing transfers */ + avr32dci_device_done(xfer, USB_ERR_STALLED); + } + sc = AVR32_BUS2SC(udev->bus); + /* get endpoint number */ + ep_no = (pipe->edesc->bEndpointAddress & UE_ADDR); + /* set stall */ + AVR32_WRITE_4(sc, AVR32_EPTSETSTA(ep_no), AVR32_EPTSTA_FRCESTALL); +} + +static void +avr32dci_clear_stall_sub(struct avr32dci_softc *sc, uint8_t ep_no, + uint8_t ep_type, uint8_t ep_dir) +{ + const struct usb2_hw_ep_profile *pf; + uint32_t temp; + uint32_t epsize; + uint8_t n; + + if (ep_type == UE_CONTROL) { + /* clearing stall is not needed */ + return; + } + /* set endpoint reset */ + AVR32_WRITE_4(sc, AVR32_EPTRST, AVR32_EPTRST_MASK(ep_no)); + + /* set stall */ + AVR32_WRITE_4(sc, AVR32_EPTSETSTA(ep_no), AVR32_EPTSTA_FRCESTALL); + + /* reset data toggle */ + AVR32_WRITE_4(sc, AVR32_EPTCLRSTA(ep_no), AVR32_EPTSTA_TOGGLESQ); + + /* clear stall */ + AVR32_WRITE_4(sc, AVR32_EPTCLRSTA(ep_no), AVR32_EPTSTA_FRCESTALL); + + if (ep_type == UE_BULK) { + temp = AVR32_EPTCFG_TYPE_BULK; + } else if (ep_type == UE_INTERRUPT) { + temp = AVR32_EPTCFG_TYPE_INTR; + } else { + temp = AVR32_EPTCFG_TYPE_ISOC | + AVR32_EPTCFG_NB_TRANS(1); + } + if (ep_dir & UE_DIR_IN) { + temp |= AVR32_EPTCFG_EPDIR_IN; + } + avr32dci_get_hw_ep_profile(NULL, &pf, ep_no); + + /* compute endpoint size (use maximum) */ + epsize = pf->max_in_frame_size | pf->max_out_frame_size; + n = 0; + while ((epsize /= 2)) + n++; + temp |= AVR32_EPTCFG_EPSIZE(n); + + /* use the maximum number of banks supported */ + if (ep_no < 1) + temp |= AVR32_EPTCFG_NBANK(1); + else if (ep_no < 3) + temp |= AVR32_EPTCFG_NBANK(2); + else + temp |= AVR32_EPTCFG_NBANK(3); + + AVR32_WRITE_4(sc, AVR32_EPTCFG(ep_no), temp); + + temp = AVR32_READ_4(sc, AVR32_EPTCFG(ep_no)); + + if (!(temp & AVR32_EPTCFG_EPT_MAPD)) { + DPRINTFN(0, "Chip rejected configuration\n"); + } else { + AVR32_WRITE_4(sc, AVR32_EPTCTLENB(ep_no), + AVR32_EPTCTL_EPT_ENABL); + } +} + +static void +avr32dci_clear_stall(struct usb2_device *udev, struct usb2_pipe *pipe) +{ + struct avr32dci_softc *sc; + struct usb2_endpoint_descriptor *ed; + + DPRINTFN(5, "pipe=%p\n", pipe); + + USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED); + + /* check mode */ + if (udev->flags.usb_mode != USB_MODE_DEVICE) { + /* not supported */ + return; + } + /* get softc */ + sc = AVR32_BUS2SC(udev->bus); + + /* get endpoint descriptor */ + ed = pipe->edesc; + + /* reset endpoint */ + avr32dci_clear_stall_sub(sc, + (ed->bEndpointAddress & UE_ADDR), + (ed->bmAttributes & UE_XFERTYPE), + (ed->bEndpointAddress & (UE_DIR_IN | UE_DIR_OUT))); +} + +usb2_error_t +avr32dci_init(struct avr32dci_softc *sc) +{ + uint8_t n; + + DPRINTF("start\n"); + + /* set up the bus structure */ + sc->sc_bus.usbrev = USB_REV_1_1; + sc->sc_bus.methods = &avr32dci_bus_methods; + + USB_BUS_LOCK(&sc->sc_bus); + + /* make sure USB is enabled */ + avr32dci_mod_ctrl(sc, AVR32_CTRL_DEV_EN_USBA, 0); + + /* turn on clocks */ + (sc->sc_clocks_on) (&sc->sc_bus); + + /* make sure device is re-enumerated */ + avr32dci_mod_ctrl(sc, AVR32_CTRL_DEV_DETACH, 0); + + /* wait a little for things to stabilise */ + usb2_pause_mtx(&sc->sc_bus.bus_mtx, hz / 20); + + /* disable interrupts */ + avr32dci_mod_ien(sc, 0, 0xFFFFFFFF); + + /* enable interrupts */ + avr32dci_mod_ien(sc, AVR32_INT_DET_SUSPD | + AVR32_INT_ENDRESET, 0); + + /* reset all endpoints */ +/**INDENT** Warning@1207: Extra ) */ + AVR32_WRITE_4(sc, AVR32_EPTRST, (1 << AVR32_EP_MAX) - 1)); + + /* disable all endpoints */ + for (n = 0; n != AVR32_EP_MAX; n++) { + /* disable endpoint */ + AVR32_WRITE_4(sc, AVR32_EPTCTLDIS(n), AVR32_EPTCTL_EPT_ENABL); + } + + /* turn off clocks */ + + avr32dci_clocks_off(sc); + + USB_BUS_UNLOCK(&sc->sc_bus); + + /* catch any lost interrupts */ + + avr32dci_do_poll(&sc->sc_bus); + + return (0); /* success */ +} + +void +avr32dci_uninit(struct avr32dci_softc *sc) +{ + uint8_t n; + + USB_BUS_LOCK(&sc->sc_bus); + + /* turn on clocks */ + (sc->sc_clocks_on) (&sc->sc_bus); + + /* disable interrupts */ + avr32dci_mod_ien(sc, 0, 0xFFFFFFFF); + + /* reset all endpoints */ +/**INDENT** Warning@1242: Extra ) */ + AVR32_WRITE_4(sc, AVR32_EPTRST, (1 << AVR32_EP_MAX) - 1)); + + /* disable all endpoints */ + for (n = 0; n != AVR32_EP_MAX; n++) { + /* disable endpoint */ + AVR32_WRITE_4(sc, AVR32_EPTCTLDIS(n), AVR32_EPTCTL_EPT_ENABL); + } + + sc->sc_flags.port_powered = 0; + sc->sc_flags.status_vbus = 0; + sc->sc_flags.status_bus_reset = 0; + sc->sc_flags.status_suspend = 0; + sc->sc_flags.change_suspend = 0; + sc->sc_flags.change_connect = 1; + + avr32dci_pull_down(sc); + avr32dci_clocks_off(sc); + + USB_BUS_UNLOCK(&sc->sc_bus); +} + +void +avr32dci_suspend(struct avr32dci_softc *sc) +{ + return; +} + +void +avr32dci_resume(struct avr32dci_softc *sc) +{ + return; +} + +static void +avr32dci_do_poll(struct usb2_bus *bus) +{ + struct avr32dci_softc *sc = AVR32_BUS2SC(bus); + + USB_BUS_LOCK(&sc->sc_bus); + avr32dci_interrupt_poll(sc); + USB_BUS_UNLOCK(&sc->sc_bus); +} + +/*------------------------------------------------------------------------* + * at91dci bulk support + * at91dci control support + * at91dci interrupt support + *------------------------------------------------------------------------*/ +static void +avr32dci_device_non_isoc_open(struct usb2_xfer *xfer) +{ + return; +} + +static void +avr32dci_device_non_isoc_close(struct usb2_xfer *xfer) +{ + avr32dci_device_done(xfer, USB_ERR_CANCELLED); +} + +static void +avr32dci_device_non_isoc_enter(struct usb2_xfer *xfer) +{ + return; +} + +static void +avr32dci_device_non_isoc_start(struct usb2_xfer *xfer) +{ + /* setup TDs */ + avr32dci_setup_standard_chain(xfer); + avr32dci_start_standard_chain(xfer); +} + +struct usb2_pipe_methods avr32dci_device_non_isoc_methods = +{ + .open = avr32dci_device_non_isoc_open, + .close = avr32dci_device_non_isoc_close, + .enter = avr32dci_device_non_isoc_enter, + .start = avr32dci_device_non_isoc_start, +}; + +/*------------------------------------------------------------------------* + * at91dci full speed isochronous support + *------------------------------------------------------------------------*/ +static void +avr32dci_device_isoc_fs_open(struct usb2_xfer *xfer) +{ + return; +} + +static void +avr32dci_device_isoc_fs_close(struct usb2_xfer *xfer) +{ + avr32dci_device_done(xfer, USB_ERR_CANCELLED); +} + +static void +avr32dci_device_isoc_fs_enter(struct usb2_xfer *xfer) +{ + struct avr32dci_softc *sc = AVR32_BUS2SC(xfer->xroot->bus); + uint32_t temp; + uint32_t nframes; + uint8_t ep_no; + + DPRINTFN(6, "xfer=%p next=%d nframes=%d\n", + xfer, xfer->pipe->isoc_next, xfer->nframes); + + /* get the current frame index */ + ep_no = xfer->endpoint & UE_ADDR_MASK; + nframes = (AVR32_READ_4(sc, AVR32_FNUM) / 8); + + nframes &= AVR32_FRAME_MASK; + + /* + * check if the frame index is within the window where the frames + * will be inserted + */ + temp = (nframes - xfer->pipe->isoc_next) & AVR32_FRAME_MASK; + + if ((xfer->pipe->is_synced == 0) || + (temp < xfer->nframes)) { + /* + * If there is data underflow or the pipe queue is + * empty we schedule the transfer a few frames ahead + * of the current frame position. Else two isochronous + * transfers might overlap. + */ + xfer->pipe->isoc_next = (nframes + 3) & AVR32_FRAME_MASK; + xfer->pipe->is_synced = 1; + DPRINTFN(3, "start next=%d\n", xfer->pipe->isoc_next); + } + /* + * compute how many milliseconds the insertion is ahead of the + * current frame position: + */ + temp = (xfer->pipe->isoc_next - nframes) & AVR32_FRAME_MASK; + + /* + * pre-compute when the isochronous transfer will be finished: + */ + xfer->isoc_time_complete = + usb2_isoc_time_expand(&sc->sc_bus, nframes) + temp + + xfer->nframes; + + /* compute frame number for next insertion */ + xfer->pipe->isoc_next += xfer->nframes; + + /* setup TDs */ + avr32dci_setup_standard_chain(xfer); +} + +static void +avr32dci_device_isoc_fs_start(struct usb2_xfer *xfer) +{ + /* start TD chain */ + avr32dci_start_standard_chain(xfer); +} + +struct usb2_pipe_methods avr32dci_device_isoc_fs_methods = +{ + .open = avr32dci_device_isoc_fs_open, + .close = avr32dci_device_isoc_fs_close, + .enter = avr32dci_device_isoc_fs_enter, + .start = avr32dci_device_isoc_fs_start, +}; + +/*------------------------------------------------------------------------* + * at91dci root control support + *------------------------------------------------------------------------* + * Simulate a hardware HUB by handling all the necessary requests. + *------------------------------------------------------------------------*/ + +static const struct usb2_device_descriptor avr32dci_devd = { + .bLength = sizeof(struct usb2_device_descriptor), + .bDescriptorType = UDESC_DEVICE, + .bcdUSB = {0x00, 0x02}, + .bDeviceClass = UDCLASS_HUB, + .bDeviceSubClass = UDSUBCLASS_HUB, + .bDeviceProtocol = UDPROTO_HSHUBSTT, + .bMaxPacketSize = 64, + .bcdDevice = {0x00, 0x01}, + .iManufacturer = 1, + .iProduct = 2, + .bNumConfigurations = 1, +}; + +static const struct usb2_device_qualifier avr32dci_odevd = { + .bLength = sizeof(struct usb2_device_qualifier), + .bDescriptorType = UDESC_DEVICE_QUALIFIER, + .bcdUSB = {0x00, 0x02}, + .bDeviceClass = UDCLASS_HUB, + .bDeviceSubClass = UDSUBCLASS_HUB, + .bDeviceProtocol = UDPROTO_FSHUB, + .bMaxPacketSize0 = 0, + .bNumConfigurations = 0, +}; + +static const struct avr32dci_config_desc avr32dci_confd = { + .confd = { + .bLength = sizeof(struct usb2_config_descriptor), + .bDescriptorType = UDESC_CONFIG, + .wTotalLength[0] = sizeof(avr32dci_confd), + .bNumInterface = 1, + .bConfigurationValue = 1, + .iConfiguration = 0, + .bmAttributes = UC_SELF_POWERED, + .bMaxPower = 0, + }, + .ifcd = { + .bLength = sizeof(struct usb2_interface_descriptor), + .bDescriptorType = UDESC_INTERFACE, + .bNumEndpoints = 1, + .bInterfaceClass = UICLASS_HUB, + .bInterfaceSubClass = UISUBCLASS_HUB, + .bInterfaceProtocol = UIPROTO_HSHUBSTT, + }, + .endpd = { + .bLength = sizeof(struct usb2_endpoint_descriptor), + .bDescriptorType = UDESC_ENDPOINT, + .bEndpointAddress = (UE_DIR_IN | AVR32_INTR_ENDPT), + .bmAttributes = UE_INTERRUPT, + .wMaxPacketSize[0] = 8, + .bInterval = 255, + }, +}; + +static const struct usb2_hub_descriptor_min avr32dci_hubd = { + .bDescLength = sizeof(avr32dci_hubd), + .bDescriptorType = UDESC_HUB, + .bNbrPorts = 1, + .wHubCharacteristics[0] = + (UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL) & 0xFF, + .wHubCharacteristics[1] = + (UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL) >> 8, + .bPwrOn2PwrGood = 50, + .bHubContrCurrent = 0, + .DeviceRemovable = {0}, /* port is removable */ +}; + +#define STRING_LANG \ + 0x09, 0x04, /* American English */ + +#define STRING_VENDOR \ + 'A', 0, 'V', 0, 'R', 0, '3', 0, '2', 0 + +#define STRING_PRODUCT \ + 'D', 0, 'C', 0, 'I', 0, ' ', 0, 'R', 0, \ + 'o', 0, 'o', 0, 't', 0, ' ', 0, 'H', 0, \ + 'U', 0, 'B', 0, + +USB_MAKE_STRING_DESC(STRING_LANG, avr32dci_langtab); +USB_MAKE_STRING_DESC(STRING_VENDOR, avr32dci_vendor); +USB_MAKE_STRING_DESC(STRING_PRODUCT, avr32dci_product); + +static usb2_error_t +avr32dci_roothub_exec(struct usb2_device *udev, + struct usb2_device_request *req, const void **pptr, uint16_t *plength) +{ + struct avr32dci_softc *sc = AVR32_BUS2SC(udev->bus); + const void *ptr; + uint16_t len; + uint16_t value; + uint16_t index; + uint32_t temp; + usb2_error_t err; + + USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); + + /* buffer reset */ + ptr = (const void *)&sc->sc_hub_temp; + len = 0; + err = 0; + + value = UGETW(req->wValue); + index = UGETW(req->wIndex); + + /* demultiplex the control request */ + + switch (req->bmRequestType) { + case UT_READ_DEVICE: + switch (req->bRequest) { + case UR_GET_DESCRIPTOR: + goto tr_handle_get_descriptor; + case UR_GET_CONFIG: + goto tr_handle_get_config; + case UR_GET_STATUS: + goto tr_handle_get_status; + default: + goto tr_stalled; + } + break; + + case UT_WRITE_DEVICE: + switch (req->bRequest) { + case UR_SET_ADDRESS: + goto tr_handle_set_address; + case UR_SET_CONFIG: + goto tr_handle_set_config; + case UR_CLEAR_FEATURE: + goto tr_valid; /* nop */ + case UR_SET_DESCRIPTOR: + goto tr_valid; /* nop */ + case UR_SET_FEATURE: + default: + goto tr_stalled; + } + break; + + case UT_WRITE_ENDPOINT: + switch (req->bRequest) { + case UR_CLEAR_FEATURE: + switch (UGETW(req->wValue)) { + case UF_ENDPOINT_HALT: + goto tr_handle_clear_halt; + case UF_DEVICE_REMOTE_WAKEUP: + goto tr_handle_clear_wakeup; + default: + goto tr_stalled; + } + break; + case UR_SET_FEATURE: + switch (UGETW(req->wValue)) { + case UF_ENDPOINT_HALT: + goto tr_handle_set_halt; + case UF_DEVICE_REMOTE_WAKEUP: + goto tr_handle_set_wakeup; + default: + goto tr_stalled; + } + break; + case UR_SYNCH_FRAME: + goto tr_valid; /* nop */ + default: + goto tr_stalled; + } + break; + + case UT_READ_ENDPOINT: + switch (req->bRequest) { + case UR_GET_STATUS: + goto tr_handle_get_ep_status; + default: + goto tr_stalled; + } + break; + + case UT_WRITE_INTERFACE: + switch (req->bRequest) { + case UR_SET_INTERFACE: + goto tr_handle_set_interface; + case UR_CLEAR_FEATURE: + goto tr_valid; /* nop */ + case UR_SET_FEATURE: + default: + goto tr_stalled; + } + break; + + case UT_READ_INTERFACE: + switch (req->bRequest) { + case UR_GET_INTERFACE: + goto tr_handle_get_interface; + case UR_GET_STATUS: + goto tr_handle_get_iface_status; + default: + goto tr_stalled; + } + break; + + case UT_WRITE_CLASS_INTERFACE: + case UT_WRITE_VENDOR_INTERFACE: + /* XXX forward */ + break; + + case UT_READ_CLASS_INTERFACE: + case UT_READ_VENDOR_INTERFACE: + /* XXX forward */ + break; + + case UT_WRITE_CLASS_DEVICE: + switch (req->bRequest) { + case UR_CLEAR_FEATURE: + goto tr_valid; + case UR_SET_DESCRIPTOR: + case UR_SET_FEATURE: + break; + default: + goto tr_stalled; + } + break; + + case UT_WRITE_CLASS_OTHER: + switch (req->bRequest) { + case UR_CLEAR_FEATURE: + goto tr_handle_clear_port_feature; + case UR_SET_FEATURE: + goto tr_handle_set_port_feature; + case UR_CLEAR_TT_BUFFER: + case UR_RESET_TT: + case UR_STOP_TT: + goto tr_valid; + + default: + goto tr_stalled; + } + break; + + case UT_READ_CLASS_OTHER: + switch (req->bRequest) { + case UR_GET_TT_STATE: + goto tr_handle_get_tt_state; + case UR_GET_STATUS: + goto tr_handle_get_port_status; + default: + goto tr_stalled; + } + break; + + case UT_READ_CLASS_DEVICE: + switch (req->bRequest) { + case UR_GET_DESCRIPTOR: + goto tr_handle_get_class_descriptor; + case UR_GET_STATUS: + goto tr_handle_get_class_status; + + default: + goto tr_stalled; + } + break; + default: + goto tr_stalled; + } + goto tr_valid; + +tr_handle_get_descriptor: + switch (value >> 8) { + case UDESC_DEVICE: + if (value & 0xff) { + goto tr_stalled; + } + len = sizeof(avr32dci_devd); + ptr = (const void *)&avr32dci_devd; + goto tr_valid; + case UDESC_CONFIG: + if (value & 0xff) { + goto tr_stalled; + } + len = sizeof(avr32dci_confd); + ptr = (const void *)&avr32dci_confd; + goto tr_valid; + case UDESC_STRING: + switch (value & 0xff) { + case 0: /* Language table */ + len = sizeof(avr32dci_langtab); + ptr = (const void *)&avr32dci_langtab; + goto tr_valid; + + case 1: /* Vendor */ + len = sizeof(avr32dci_vendor); + ptr = (const void *)&avr32dci_vendor; + goto tr_valid; + + case 2: /* Product */ + len = sizeof(avr32dci_product); + ptr = (const void *)&avr32dci_product; + goto tr_valid; + default: + break; + } + break; + default: + goto tr_stalled; + } + goto tr_stalled; + +tr_handle_get_config: + len = 1; + sc->sc_hub_temp.wValue[0] = sc->sc_conf; + goto tr_valid; + +tr_handle_get_status: + len = 2; + USETW(sc->sc_hub_temp.wValue, UDS_SELF_POWERED); + goto tr_valid; + +tr_handle_set_address: + if (value & 0xFF00) { + goto tr_stalled; + } + sc->sc_rt_addr = value; + goto tr_valid; + +tr_handle_set_config: + if (value >= 2) { + goto tr_stalled; + } + sc->sc_conf = value; + goto tr_valid; + +tr_handle_get_interface: + len = 1; + sc->sc_hub_temp.wValue[0] = 0; + goto tr_valid; + +tr_handle_get_tt_state: +tr_handle_get_class_status: +tr_handle_get_iface_status: +tr_handle_get_ep_status: + len = 2; + USETW(sc->sc_hub_temp.wValue, 0); + goto tr_valid; + +tr_handle_set_halt: +tr_handle_set_interface: +tr_handle_set_wakeup: +tr_handle_clear_wakeup: +tr_handle_clear_halt: + goto tr_valid; + +tr_handle_clear_port_feature: + if (index != 1) { + goto tr_stalled; + } + DPRINTFN(9, "UR_CLEAR_PORT_FEATURE on port %d\n", index); + + switch (value) { + case UHF_PORT_SUSPEND: + avr32dci_wakeup_peer(sc); + break; + + case UHF_PORT_ENABLE: + sc->sc_flags.port_enabled = 0; + break; + + case UHF_PORT_TEST: + case UHF_PORT_INDICATOR: + case UHF_C_PORT_ENABLE: + case UHF_C_PORT_OVER_CURRENT: + case UHF_C_PORT_RESET: + /* nops */ + break; + case UHF_PORT_POWER: + sc->sc_flags.port_powered = 0; + avr32dci_pull_down(sc); + avr32dci_clocks_off(sc); + break; + case UHF_C_PORT_CONNECTION: + /* clear connect change flag */ + sc->sc_flags.change_connect = 0; + + if (!sc->sc_flags.status_bus_reset) { + /* we are not connected */ + break; + } + /* configure the control endpoint */ + /* set endpoint reset */ + AVR32_WRITE_4(sc, AVR32_EPTRST, AVR32_EPTRST_MASK(0)); + + /* set stall */ + AVR32_WRITE_4(sc, AVR32_EPTSETSTA(0), AVR32_EPTSTA_FRCESTALL); + + /* reset data toggle */ + AVR32_WRITE_4(sc, AVR32_EPTCLRSTA(0), AVR32_EPTSTA_TOGGLESQ); + + /* clear stall */ + AVR32_WRITE_4(sc, AVR32_EPTCLRSTA(0), AVR32_EPTSTA_FRCESTALL); + + /* configure */ + AVR32_WRITE_4(sc, AVR32_EPTCFG(0), AVR32_EPTCFG_TYPE_CONTROL | + AVR32_EPTCFG_NBANK(1) | AVR32_EPTCFG_EPSIZE(6)); + + temp = AVR32_READ_4(sc, AVR32_EPTCFG(0)); + + if (!(temp & AVR32_EPTCFG_EPT_MAPD)) { + DPRINTFN(0, "Chip rejected configuration\n"); + } else { + AVR32_WRITE_4(sc, AVR32_EPTCTLENB(0), + AVR32_EPTCTL_EPT_ENABL); + } + break; + case UHF_C_PORT_SUSPEND: + sc->sc_flags.change_suspend = 0; + break; + default: + err = USB_ERR_IOERROR; + goto done; + } + goto tr_valid; + +tr_handle_set_port_feature: + if (index != 1) { + goto tr_stalled; + } + DPRINTFN(9, "UR_SET_PORT_FEATURE\n"); + + switch (value) { + case UHF_PORT_ENABLE: + sc->sc_flags.port_enabled = 1; + break; + case UHF_PORT_SUSPEND: + case UHF_PORT_RESET: + case UHF_PORT_TEST: + case UHF_PORT_INDICATOR: + /* nops */ + break; + case UHF_PORT_POWER: + sc->sc_flags.port_powered = 1; + break; + default: + err = USB_ERR_IOERROR; + goto done; + } + goto tr_valid; + +tr_handle_get_port_status: + + DPRINTFN(9, "UR_GET_PORT_STATUS\n"); + + if (index != 1) { + goto tr_stalled; + } + if (sc->sc_flags.status_vbus) { + avr32dci_clocks_on(sc); + avr32dci_pull_up(sc); + } else { + avr32dci_pull_down(sc); + avr32dci_clocks_off(sc); + } + + /* Select Device Side Mode */ + + value = UPS_PORT_MODE_DEVICE; + + /* Check for High Speed */ + if (AVR32_READ_4(sc, AVR32_INTSTA) & AVR32_INT_SPEED) + value |= UPS_HIGH_SPEED; + + if (sc->sc_flags.port_powered) { + value |= UPS_PORT_POWER; + } + if (sc->sc_flags.port_enabled) { + value |= UPS_PORT_ENABLED; + } + if (sc->sc_flags.status_vbus && + sc->sc_flags.status_bus_reset) { + value |= UPS_CURRENT_CONNECT_STATUS; + } + if (sc->sc_flags.status_suspend) { + value |= UPS_SUSPEND; + } + USETW(sc->sc_hub_temp.ps.wPortStatus, value); + + value = 0; + + if (sc->sc_flags.change_connect) { + value |= UPS_C_CONNECT_STATUS; + } + if (sc->sc_flags.change_suspend) { + value |= UPS_C_SUSPEND; + } + USETW(sc->sc_hub_temp.ps.wPortChange, value); + len = sizeof(sc->sc_hub_temp.ps); + goto tr_valid; + +tr_handle_get_class_descriptor: + if (value & 0xFF) { + goto tr_stalled; + } + ptr = (const void *)&avr32dci_hubd; + len = sizeof(avr32dci_hubd); + goto tr_valid; + +tr_stalled: + err = USB_ERR_STALLED; +tr_valid: +done: + *plength = len; + *pptr = ptr; + return (err); +} + +static void +avr32dci_xfer_setup(struct usb2_setup_params *parm) +{ + const struct usb2_hw_ep_profile *pf; + struct avr32dci_softc *sc; + struct usb2_xfer *xfer; + void *last_obj; + uint32_t ntd; + uint32_t n; + uint8_t ep_no; + + sc = AVR32_BUS2SC(parm->udev->bus); + xfer = parm->curr_xfer; + + /* + * NOTE: This driver does not use any of the parameters that + * are computed from the following values. Just set some + * reasonable dummies: + */ + parm->hc_max_packet_size = 0x400; + parm->hc_max_packet_count = 1; + parm->hc_max_frame_size = 0x400; + + usb2_transfer_setup_sub(parm); + + /* + * compute maximum number of TDs + */ + if ((xfer->pipe->edesc->bmAttributes & UE_XFERTYPE) == UE_CONTROL) { + + ntd = xfer->nframes + 1 /* STATUS */ + 1 /* SYNC 1 */ + + 1 /* SYNC 2 */ ; + } else { + + ntd = xfer->nframes + 1 /* SYNC */ ; + } + + /* + * check if "usb2_transfer_setup_sub" set an error + */ + if (parm->err) + return; + + /* + * allocate transfer descriptors + */ + last_obj = NULL; + + /* + * get profile stuff + */ + ep_no = xfer->endpoint & UE_ADDR; + avr32dci_get_hw_ep_profile(parm->udev, &pf, ep_no); + + if (pf == NULL) { + /* should not happen */ + parm->err = USB_ERR_INVAL; + return; + } + /* align data */ + parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1)); + + for (n = 0; n != ntd; n++) { + + struct avr32dci_td *td; + + if (parm->buf) { + uint32_t temp; + + td = USB_ADD_BYTES(parm->buf, parm->size[0]); + + /* init TD */ + td->max_packet_size = xfer->max_packet_size; + td->ep_no = ep_no; + temp = pf->max_in_frame_size | pf->max_out_frame_size; + td->bank_shift = 0; + while ((temp /= 2)) + td->bank_shift++; + if (pf->support_multi_buffer) { + td->support_multi_buffer = 1; + } + td->obj_next = last_obj; + + last_obj = td; + } + parm->size[0] += sizeof(*td); + } + + xfer->td_start[0] = last_obj; +} + +static void +avr32dci_xfer_unsetup(struct usb2_xfer *xfer) +{ + return; +} + +static void +avr32dci_pipe_init(struct usb2_device *udev, struct usb2_endpoint_descriptor *edesc, + struct usb2_pipe *pipe) +{ + struct avr32dci_softc *sc = AVR32_BUS2SC(udev->bus); + + DPRINTFN(2, "pipe=%p, addr=%d, endpt=%d, mode=%d (%d,%d)\n", + pipe, udev->address, + edesc->bEndpointAddress, udev->flags.usb_mode, + sc->sc_rt_addr, udev->device_index); + + if (udev->device_index != sc->sc_rt_addr) { + + if (udev->flags.usb_mode != USB_MODE_DEVICE) { + /* not supported */ + return; + } + if ((udev->speed != USB_SPEED_FULL) && + (udev->speed != USB_SPEED_HIGH)) { + /* not supported */ + return; + } + if ((edesc->bmAttributes & UE_XFERTYPE) == UE_ISOCHRONOUS) + pipe->methods = &avr32dci_device_isoc_fs_methods; + else + pipe->methods = &avr32dci_device_non_isoc_methods; + } +} + +struct usb2_bus_methods avr32dci_bus_methods = +{ + .pipe_init = &avr32dci_pipe_init, + .xfer_setup = &avr32dci_xfer_setup, + .xfer_unsetup = &avr32dci_xfer_unsetup, + .get_hw_ep_profile = &avr32dci_get_hw_ep_profile, + .set_stall = &avr32dci_set_stall, + .clear_stall = &avr32dci_clear_stall, + .roothub_exec = &avr32dci_roothub_exec, +}; diff --git a/sys/dev/usb/controller/avr32dci.h b/sys/dev/usb/controller/avr32dci.h new file mode 100644 index 000000000000..6a9895f2fff5 --- /dev/null +++ b/sys/dev/usb/controller/avr32dci.h @@ -0,0 +1,254 @@ +/* $FreeBSD$ */ +/*- + * Copyright (c) 2009 Hans Petter Selasky. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _AVR32DCI_H_ +#define _AVR32DCI_H_ + +#define AVR32_MAX_DEVICES (USB_MIN_DEVICES + 1) + +/* Register definitions */ + +#define AVR32_CTRL 0x00 /* Control */ +#define AVR32_CTRL_DEV_ADDR 0x7F +#define AVR32_CTRL_DEV_FADDR_EN 0x80 +#define AVR32_CTRL_DEV_EN_USBA 0x100 +#define AVR32_CTRL_DEV_DETACH 0x200 +#define AVR32_CTRL_DEV_REWAKEUP 0x400 + +#define AVR32_FNUM 0x04 /* Frame Number */ +#define AVR32_FNUM_MASK 0x3FFF +#define AVR32_FRAME_MASK 0x7FF + +/* 0x08 - 0x0C Reserved */ +#define AVR32_IEN 0x10 /* Interrupt Enable */ +#define AVR32_INTSTA 0x14 /* Interrupt Status */ +#define AVR32_CLRINT 0x18 /* Clear Interrupt */ + +#define AVR32_INT_SPEED 0x00000001 /* set if High Speed else Full Speed */ +#define AVR32_INT_DET_SUSPD 0x00000002 +#define AVR32_INT_MICRO_SOF 0x00000004 +#define AVR32_INT_INT_SOF 0x00000008 +#define AVR32_INT_ENDRESET 0x00000010 +#define AVR32_INT_WAKE_UP 0x00000020 +#define AVR32_INT_ENDOFRSM 0x00000040 +#define AVR32_INT_UPSTR_RES 0x00000080 +#define AVR32_INT_EPT_INT(n) (0x00000100 << (n)) +#define AVR32_INT_DMA_INT(n) (0x01000000 << (n)) + +#define AVR32_EPTRST 0x1C /* Endpoints Reset */ +#define AVR32_EPTRST_MASK(n) (0x00000001 << (n)) + +/* 0x20 - 0xCC Reserved */ +#define AVR32_TSTSOFCNT 0xD0 /* Test SOF Counter */ +#define AVR32_TSTCNTA 0xD4 /* Test A Counter */ +#define AVR32_TSTCNTB 0xD8 /* Test B Counter */ +#define AVR32_TSTMODEREG 0xDC /* Test Mode */ +#define AVR32_TST 0xE0 /* Test */ +#define AVR32_TST_NORMAL 0x00000000 +#define AVR32_TST_HS_ONLY 0x00000002 +#define AVR32_TST_FS_ONLY 0x00000003 + +/* 0xE4 - 0xE8 Reserved */ +#define AVR32_IPPADDRSIZE 0xEC /* PADDRSIZE */ +#define AVR32_IPNAME1 0xF0 /* Name1 */ +#define AVR32_IPNAME2 0xF4 /* Name2 */ +#define AVR32_IPFEATURES 0xF8 /* Features */ +#define AVR32_IPFEATURES_NEP(x) (((x) & 0xF) ? ((x) & 0xF) : 0x10) + +#define AVR32_IPVERSION 0xFC /* IP Version */ + +#define _A(base,n) ((base) + (0x20*(n))) +#define AVR32_EPTCFG(n) _A(0x100, n) /* Endpoint Configuration */ +#define AVR32_EPTCFG_EPSIZE(n) ((n)-3) /* power of two */ +#define AVR32_EPTCFG_EPDIR_OUT 0x00000000 +#define AVR32_EPTCFG_EPDIR_IN 0x00000008 +#define AVR32_EPTCFG_TYPE_CTRL 0x00000000 +#define AVR32_EPTCFG_TYPE_ISOC 0x00000100 +#define AVR32_EPTCFG_TYPE_BULK 0x00000200 +#define AVR32_EPTCFG_TYPE_INTR 0x00000300 +#define AVR32_EPTCFG_NBANK(n) (0x00000400*(n)) +#define AVR32_EPTCFG_NB_TRANS(n) (0x00001000*(n)) +#define AVR32_EPTCFG_EPT_MAPD 0x80000000 + +#define AVR32_EPTCTLENB(n) _A(0x104, n) /* Endpoint Control Enable */ +#define AVR32_EPTCTLDIS(n) _A(0x108, n) /* Endpoint Control Disable */ +#define AVR32_EPTCTL(n) _A(0x10C, n) /* Endpoint Control */ +#define AVR32_EPTCTL_EPT_ENABL 0x00000001 +#define AVR32_EPTCTL_AUTO_VALID 0x00000002 +#define AVR32_EPTCTL_INTDIS_DMA 0x00000008 +#define AVR32_EPTCTL_NYET_DIS 0x00000010 +#define AVR32_EPTCTL_DATAX_RX 0x00000040 +#define AVR32_EPTCTL_MDATA_RX 0x00000080 +#define AVR32_EPTCTL_ERR_OVFLW 0x00000100 +#define AVR32_EPTCTL_RX_BK_RDY 0x00000200 +#define AVR32_EPTCTL_TX_COMPLT 0x00000400 +#define AVR32_EPTCTL_TX_PK_RDY 0x00000800 +#define AVR32_EPTCTL_RX_SETUP 0x00001000 +#define AVR32_EPTCTL_STALL_SNT 0x00002000 +#define AVR32_EPTCTL_NAK_IN 0x00004000 +#define AVR32_EPTCTL_NAK_OUT 0x00008000 +#define AVR32_EPTCTL_BUSY_BANK 0x00040000 +#define AVR32_EPTCTL_SHORT_PCKT 0x80000000 + +/* 0x110 Reserved */ +#define AVR32_EPTSETSTA(n) _A(0x114, n) /* Endpoint Set Status */ +#define AVR32_EPTCLRSTA(n) _A(0x118, n) /* Endpoint Clear Status */ +#define AVR32_EPTSTA(n) _A(0x11C, n) /* Endpoint Status */ +#define AVR32_EPTSTA_FRCESTALL 0x00000020 +#define AVR32_EPTSTA_TOGGLESQ_STA(x) (((x) & 0xC0) >> 6) +#define AVR32_EPTSTA_TOGGLESQ 0x00000040 +#define AVR32_EPTSTA_ERR_OVFLW 0x00000100 +#define AVR32_EPTSTA_RX_BK_RDY 0x00000200 +#define AVR32_EPTSTA_TX_COMPLT 0x00000400 +#define AVR32_EPTSTA_TX_PK_RDY 0x00000800 +#define AVR32_EPTSTA_RX_SETUP 0x00001000 +#define AVR32_EPTSTA_STALL_SNT 0x00002000 +#define AVR32_EPTSTA_NAK_IN 0x00004000 +#define AVR32_EPTSTA_NAK_OUT 0x00008000 +#define AVR32_EPTSTA_CURRENT_BANK(x) (((x) & 0x00030000) >> 16) +#define AVR32_EPTSTA_BUSY_BANK_STA(x) (((x) & 0x000C0000) >> 18) +#define AVR32_EPTSTA_BYTE_COUNT(x) (((x) & 0x7FF00000) >> 20) +#define AVR32_EPTSTA_SHRT_PCKT 0x80000000 + +/* 0x300 - 0x30C Reserved */ +#define AVR32_DMANXTDSC 0x310 /* DMA Next Descriptor Address */ +#define AVR32_DMAADDRESS 0x314 /* DMA Channel Address */ + +#define AVR32_READ_4(sc, reg) \ + bus_space_read_4((sc)->sc_io_tag, (sc)->sc_io_hdl, reg) + +#define AVR32_WRITE_4(sc, reg, data) \ + bus_space_write_4((sc)->sc_io_tag, (sc)->sc_io_hdl, reg, data) + +#define AVR32_WRITE_MULTI_4(sc, reg, ptr, len) \ + bus_space_write_multi_4((sc)->sc_io_tag, (sc)->sc_io_hdl, reg, ptr, len) + +#define AVR32_READ_MULTI_4(sc, reg, ptr, len) \ + bus_space_read_multi_4((sc)->sc_io_tag, (sc)->sc_io_hdl, reg, ptr, len) + +/* + * Maximum number of endpoints supported: + */ +#define AVR32_EP_MAX 7 + +struct avr32dci_td; + +typedef uint8_t (avr32dci_cmd_t)(struct avr32dci_td *td); +typedef void (avr32dci_clocks_t)(struct usb2_bus *); + +struct avr32dci_td { + struct avr32dci_td *obj_next; + avr32dci_cmd_t *func; + struct usb2_page_cache *pc; + uint32_t offset; + uint32_t remainder; + uint16_t max_packet_size; + uint8_t error:1; + uint8_t alt_next:1; + uint8_t short_pkt:1; + uint8_t support_multi_buffer:1; + uint8_t did_stall:1; + uint8_t ep_no:3; +}; + +struct avr32dci_std_temp { + avr32dci_cmd_t *func; + struct usb2_page_cache *pc; + struct avr32dci_td *td; + struct avr32dci_td *td_next; + uint32_t len; + uint32_t offset; + uint16_t max_frame_size; + uint8_t bank_shift; + uint8_t short_pkt; + /* + * short_pkt = 0: transfer should be short terminated + * short_pkt = 1: transfer should not be short terminated + */ + uint8_t setup_alt_next; + uint8_t did_stall; +}; + +struct avr32dci_config_desc { + struct usb2_config_descriptor confd; + struct usb2_interface_descriptor ifcd; + struct usb2_endpoint_descriptor endpd; +} __packed; + +union avr32dci_hub_temp { + uWord wValue; + struct usb2_port_status ps; +}; + +struct avr32dci_flags { + uint8_t change_connect:1; + uint8_t change_suspend:1; + uint8_t status_suspend:1; /* set if suspended */ + uint8_t status_vbus:1; /* set if present */ + uint8_t status_bus_reset:1; /* set if reset complete */ + uint8_t remote_wakeup:1; + uint8_t self_powered:1; + uint8_t clocks_off:1; + uint8_t port_powered:1; + uint8_t port_enabled:1; + uint8_t d_pulled_up:1; +}; + +struct avr32dci_softc { + struct usb2_bus sc_bus; + union avr32dci_hub_temp sc_hub_temp; + + /* must be set by by the bus interface layer */ + avr32dci_clocks_t *sc_clocks_on; + avr32dci_clocks_t *sc_clocks_off; + + struct usb2_device *sc_devices[AVR32_MAX_DEVICES]; + struct resource *sc_irq_res; + void *sc_intr_hdl; + struct resource *sc_io_res; + bus_space_tag_t sc_io_tag; + bus_space_handle_t sc_io_hdl; + uint8_t *physdata; + + uint8_t sc_rt_addr; /* root hub address */ + uint8_t sc_dv_addr; /* device address */ + uint8_t sc_conf; /* root hub config */ + + uint8_t sc_hub_idata[1]; + + struct avr32dci_flags sc_flags; +}; + +/* prototypes */ + +usb2_error_t avr32dci_init(struct avr32dci_softc *sc); +void avr32dci_uninit(struct avr32dci_softc *sc); +void avr32dci_suspend(struct avr32dci_softc *sc); +void avr32dci_resume(struct avr32dci_softc *sc); +void avr32dci_interrupt(struct avr32dci_softc *sc); +void avr32dci_vbus_interrupt(struct avr32dci_softc *sc, uint8_t is_on); + +#endif /* _AVR32DCI_H_ */ diff --git a/sys/dev/usb/controller/ehci.c b/sys/dev/usb/controller/ehci.c index 74539f575043..c3b7ba4ca5bc 100644 --- a/sys/dev/usb/controller/ehci.c +++ b/sys/dev/usb/controller/ehci.c @@ -73,10 +73,10 @@ __FBSDID("$FreeBSD$"); static int ehcidebug = 0; static int ehcinohighspeed = 0; -SYSCTL_NODE(_hw_usb2, OID_AUTO, ehci, CTLFLAG_RW, 0, "USB ehci"); -SYSCTL_INT(_hw_usb2_ehci, OID_AUTO, debug, CTLFLAG_RW, +SYSCTL_NODE(_hw_usb, OID_AUTO, ehci, CTLFLAG_RW, 0, "USB ehci"); +SYSCTL_INT(_hw_usb_ehci, OID_AUTO, debug, CTLFLAG_RW, &ehcidebug, 0, "Debug level"); -SYSCTL_INT(_hw_usb2_ehci, OID_AUTO, no_hs, CTLFLAG_RW, +SYSCTL_INT(_hw_usb_ehci, OID_AUTO, no_hs, CTLFLAG_RW, &ehcinohighspeed, 0, "Disable High Speed USB"); static void ehci_dump_regs(ehci_softc_t *sc); @@ -1156,13 +1156,6 @@ ehci_non_isoc_done_sub(struct usb2_xfer *xfer) } /* Check for last transfer */ if (((void *)td) == xfer->td_transfer_last) { - if (len == 0) { - /* - * Halt is ok if descriptor is last, - * and complete: - */ - status &= ~EHCI_QTD_HALTED; - } td = NULL; break; } @@ -2028,6 +2021,8 @@ ehci_isoc_fs_done(ehci_softc_t *sc, struct usb2_xfer *xfer) len = EHCI_SITD_GET_LEN(status); + DPRINTFN(2, "status=0x%08x, rem=%u\n", status, len); + if (*plen >= len) { len = *plen - len; } else { @@ -2081,6 +2076,8 @@ ehci_isoc_hs_done(ehci_softc_t *sc, struct usb2_xfer *xfer) len = EHCI_ITD_GET_LEN(status); + DPRINTFN(2, "status=0x%08x, len=%u\n", status, len); + if (*plen >= len) { /* * The length is valid. NOTE: The complete @@ -3645,10 +3642,10 @@ ehci_pipe_init(struct usb2_device *udev, struct usb2_endpoint_descriptor *edesc, DPRINTFN(2, "pipe=%p, addr=%d, endpt=%d, mode=%d (%d)\n", pipe, udev->address, - edesc->bEndpointAddress, udev->flags.usb2_mode, + edesc->bEndpointAddress, udev->flags.usb_mode, sc->sc_addr); - if (udev->flags.usb2_mode != USB_MODE_HOST) { + if (udev->flags.usb_mode != USB_MODE_HOST) { /* not supported */ return; } diff --git a/sys/dev/usb/controller/musb_otg.c b/sys/dev/usb/controller/musb_otg.c index 1feb8a4a6fae..6b867d5750c8 100644 --- a/sys/dev/usb/controller/musb_otg.c +++ b/sys/dev/usb/controller/musb_otg.c @@ -67,8 +67,8 @@ #if USB_DEBUG static int musbotgdebug = 0; -SYSCTL_NODE(_hw_usb2, OID_AUTO, musbotg, CTLFLAG_RW, 0, "USB musbotg"); -SYSCTL_INT(_hw_usb2_musbotg, OID_AUTO, debug, CTLFLAG_RW, +SYSCTL_NODE(_hw_usb, OID_AUTO, musbotg, CTLFLAG_RW, 0, "USB musbotg"); +SYSCTL_INT(_hw_usb_musbotg, OID_AUTO, debug, CTLFLAG_RW, &musbotgdebug, 0, "Debug level"); #endif @@ -1099,7 +1099,7 @@ musbotg_setup_standard_chain_sub(struct musbotg_std_temp *temp) td->offset = temp->offset; td->remainder = temp->len; td->error = 0; - td->did_stall = 0; + td->did_stall = temp->did_stall; td->short_pkt = temp->short_pkt; td->alt_next = temp->setup_alt_next; } @@ -1129,6 +1129,7 @@ musbotg_setup_standard_chain(struct usb2_xfer *xfer) temp.td_next = xfer->td_start[0]; temp.offset = 0; temp.setup_alt_next = xfer->flags_int.short_frames_ok; + temp.did_stall = !xfer->flags_int.control_stall; sc = MUSBOTG_BUS2SC(xfer->xroot->bus); ep_no = (xfer->endpoint & UE_ADDR); @@ -1441,7 +1442,7 @@ musbotg_device_done(struct usb2_xfer *xfer, usb2_error_t error) DPRINTFN(2, "xfer=%p, pipe=%p, error=%d\n", xfer, xfer->pipe, error); - if (xfer->flags_int.usb2_mode == USB_MODE_DEVICE) { + if (xfer->flags_int.usb_mode == USB_MODE_DEVICE) { musbotg_ep_int_set(xfer, 0); @@ -1645,7 +1646,7 @@ musbotg_clear_stall(struct usb2_device *udev, struct usb2_pipe *pipe) USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED); /* check mode */ - if (udev->flags.usb2_mode != USB_MODE_DEVICE) { + if (udev->flags.usb_mode != USB_MODE_DEVICE) { /* not supported */ return; } @@ -2673,12 +2674,12 @@ musbotg_pipe_init(struct usb2_device *udev, struct usb2_endpoint_descriptor *ede DPRINTFN(2, "pipe=%p, addr=%d, endpt=%d, mode=%d (%d)\n", pipe, udev->address, - edesc->bEndpointAddress, udev->flags.usb2_mode, + edesc->bEndpointAddress, udev->flags.usb_mode, sc->sc_rt_addr); if (udev->device_index != sc->sc_rt_addr) { - if (udev->flags.usb2_mode != USB_MODE_DEVICE) { + if (udev->flags.usb_mode != USB_MODE_DEVICE) { /* not supported */ return; } diff --git a/sys/dev/usb/controller/musb_otg.h b/sys/dev/usb/controller/musb_otg.h index 2dd2ce317be2..f68792198d94 100644 --- a/sys/dev/usb/controller/musb_otg.h +++ b/sys/dev/usb/controller/musb_otg.h @@ -332,6 +332,7 @@ struct musbotg_std_temp { * short_pkt = 1: transfer should not be short terminated */ uint8_t setup_alt_next; + uint8_t did_stall; }; struct musbotg_config_desc { diff --git a/sys/dev/usb/controller/ohci.c b/sys/dev/usb/controller/ohci.c index 6cff48ae3145..4b407ab368f8 100644 --- a/sys/dev/usb/controller/ohci.c +++ b/sys/dev/usb/controller/ohci.c @@ -61,8 +61,8 @@ __FBSDID("$FreeBSD$"); #if USB_DEBUG static int ohcidebug = 0; -SYSCTL_NODE(_hw_usb2, OID_AUTO, ohci, CTLFLAG_RW, 0, "USB ohci"); -SYSCTL_INT(_hw_usb2_ohci, OID_AUTO, debug, CTLFLAG_RW, +SYSCTL_NODE(_hw_usb, OID_AUTO, ohci, CTLFLAG_RW, 0, "USB ohci"); +SYSCTL_INT(_hw_usb_ohci, OID_AUTO, debug, CTLFLAG_RW, &ohcidebug, 0, "ohci debug level"); static void ohci_dumpregs(ohci_softc_t *); static void ohci_dump_tds(ohci_td_t *); @@ -2570,10 +2570,10 @@ ohci_pipe_init(struct usb2_device *udev, struct usb2_endpoint_descriptor *edesc, DPRINTFN(2, "pipe=%p, addr=%d, endpt=%d, mode=%d (%d)\n", pipe, udev->address, - edesc->bEndpointAddress, udev->flags.usb2_mode, + edesc->bEndpointAddress, udev->flags.usb_mode, sc->sc_addr); - if (udev->flags.usb2_mode != USB_MODE_HOST) { + if (udev->flags.usb_mode != USB_MODE_HOST) { /* not supported */ return; } diff --git a/sys/dev/usb/controller/uhci.c b/sys/dev/usb/controller/uhci.c index 29235b368dd0..7a6ba1628b91 100644 --- a/sys/dev/usb/controller/uhci.c +++ b/sys/dev/usb/controller/uhci.c @@ -66,10 +66,10 @@ __FBSDID("$FreeBSD$"); static int uhcidebug = 0; static int uhcinoloop = 0; -SYSCTL_NODE(_hw_usb2, OID_AUTO, uhci, CTLFLAG_RW, 0, "USB uhci"); -SYSCTL_INT(_hw_usb2_uhci, OID_AUTO, debug, CTLFLAG_RW, +SYSCTL_NODE(_hw_usb, OID_AUTO, uhci, CTLFLAG_RW, 0, "USB uhci"); +SYSCTL_INT(_hw_usb_uhci, OID_AUTO, debug, CTLFLAG_RW, &uhcidebug, 0, "uhci debug level"); -SYSCTL_INT(_hw_usb2_uhci, OID_AUTO, loop, CTLFLAG_RW, +SYSCTL_INT(_hw_usb_uhci, OID_AUTO, loop, CTLFLAG_RW, &uhcinoloop, 0, "uhci noloop"); static void uhci_dumpregs(uhci_softc_t *sc); static void uhci_dump_tds(uhci_td_t *td); @@ -3050,10 +3050,10 @@ uhci_pipe_init(struct usb2_device *udev, struct usb2_endpoint_descriptor *edesc, DPRINTFN(2, "pipe=%p, addr=%d, endpt=%d, mode=%d (%d)\n", pipe, udev->address, - edesc->bEndpointAddress, udev->flags.usb2_mode, + edesc->bEndpointAddress, udev->flags.usb_mode, sc->sc_addr); - if (udev->flags.usb2_mode != USB_MODE_HOST) { + if (udev->flags.usb_mode != USB_MODE_HOST) { /* not supported */ return; } diff --git a/sys/dev/usb/controller/usb_controller.c b/sys/dev/usb/controller/usb_controller.c index cf30051a5c2b..93e9c32e9db4 100644 --- a/sys/dev/usb/controller/usb_controller.c +++ b/sys/dev/usb/controller/usb_controller.c @@ -55,8 +55,8 @@ static void usb2_post_init(void *); #if USB_DEBUG static int usb2_ctrl_debug = 0; -SYSCTL_NODE(_hw_usb2, OID_AUTO, ctrl, CTLFLAG_RW, 0, "USB controller"); -SYSCTL_INT(_hw_usb2_ctrl, OID_AUTO, debug, CTLFLAG_RW, &usb2_ctrl_debug, 0, +SYSCTL_NODE(_hw_usb, OID_AUTO, ctrl, CTLFLAG_RW, 0, "USB controller"); +SYSCTL_INT(_hw_usb_ctrl, OID_AUTO, debug, CTLFLAG_RW, &usb2_ctrl_debug, 0, "Debug level"); #endif @@ -290,7 +290,7 @@ usb2_bus_attach(struct usb2_proc_msg *pm) struct usb2_device *child; device_t dev; usb2_error_t err; - uint8_t speed; + enum usb_dev_speed speed; bus = ((struct usb2_bus_msg *)pm)->bus; dev = bus->bdev; diff --git a/sys/dev/usb/controller/uss820dci.c b/sys/dev/usb/controller/uss820dci.c index e31942545ade..05389c4f91f6 100644 --- a/sys/dev/usb/controller/uss820dci.c +++ b/sys/dev/usb/controller/uss820dci.c @@ -62,8 +62,8 @@ #if USB_DEBUG static int uss820dcidebug = 0; -SYSCTL_NODE(_hw_usb2, OID_AUTO, uss820dci, CTLFLAG_RW, 0, "USB uss820dci"); -SYSCTL_INT(_hw_usb2_uss820dci, OID_AUTO, debug, CTLFLAG_RW, +SYSCTL_NODE(_hw_usb, OID_AUTO, uss820dci, CTLFLAG_RW, 0, "USB uss820dci"); +SYSCTL_INT(_hw_usb_uss820dci, OID_AUTO, debug, CTLFLAG_RW, &uss820dcidebug, 0, "uss820dci debug level"); #endif @@ -230,11 +230,11 @@ uss820dci_setup_rx(struct uss820dci_td *td) /* select the correct endpoint */ bus_space_write_1(td->io_tag, td->io_hdl, - td->ep_reg, td->ep_index); + USS820_EPINDEX, td->ep_index); /* read out FIFO status */ rx_stat = bus_space_read_1(td->io_tag, td->io_hdl, - td->rx_stat_reg); + USS820_RXSTAT); /* get pointer to softc */ sc = USS820_DCI_PC2SC(td->pc); @@ -260,9 +260,9 @@ uss820dci_setup_rx(struct uss820dci_td *td) /* get the packet byte count */ count = bus_space_read_1(td->io_tag, td->io_hdl, - td->rx_count_low_reg); + USS820_RXCNTL); count |= (bus_space_read_1(td->io_tag, td->io_hdl, - td->rx_count_high_reg) << 8); + USS820_RXCNTH) << 8); count &= 0x3FF; /* verify data length */ @@ -278,11 +278,11 @@ uss820dci_setup_rx(struct uss820dci_td *td) } /* receive data */ bus_space_read_multi_1(td->io_tag, td->io_hdl, - td->rx_fifo_reg, (void *)&req, sizeof(req)); + USS820_RXDAT, (void *)&req, sizeof(req)); /* read out FIFO status */ rx_stat = bus_space_read_1(td->io_tag, td->io_hdl, - td->rx_stat_reg); + USS820_RXSTAT); if (rx_stat & (USS820_RXSTAT_EDOVW | USS820_RXSTAT_STOVW)) { @@ -297,10 +297,10 @@ uss820dci_setup_rx(struct uss820dci_td *td) /* set RXFFRC bit */ temp = bus_space_read_1(td->io_tag, td->io_hdl, - td->rx_cntl_reg); + USS820_RXCON); temp |= USS820_RXCON_RXFFRC; bus_space_write_1(td->io_tag, td->io_hdl, - td->rx_cntl_reg, temp); + USS820_RXCON, temp); /* copy data into real buffer */ usb2_copy_in(td->pc, 0, &req, sizeof(req)); @@ -321,10 +321,10 @@ setup_not_complete: /* set RXFFRC bit */ temp = bus_space_read_1(td->io_tag, td->io_hdl, - td->rx_cntl_reg); + USS820_RXCON); temp |= USS820_RXCON_RXFFRC; bus_space_write_1(td->io_tag, td->io_hdl, - td->rx_cntl_reg, temp); + USS820_RXCON, temp); /* FALLTHROUGH */ @@ -365,16 +365,16 @@ uss820dci_data_rx(struct uss820dci_td *td) got_short = 0; /* select the correct endpoint */ - bus_space_write_1(td->io_tag, td->io_hdl, td->ep_reg, td->ep_index); + bus_space_write_1(td->io_tag, td->io_hdl, USS820_EPINDEX, td->ep_index); /* check if any of the FIFO banks have data */ repeat: /* read out FIFO flag */ rx_flag = bus_space_read_1(td->io_tag, td->io_hdl, - td->rx_flag_reg); + USS820_RXFLG); /* read out FIFO status */ rx_stat = bus_space_read_1(td->io_tag, td->io_hdl, - td->rx_stat_reg); + USS820_RXSTAT); DPRINTFN(5, "rx_stat=0x%02x rx_flag=0x%02x rem=%u\n", rx_stat, rx_flag, td->remainder); @@ -410,19 +410,19 @@ repeat: /* read out EPCON register */ /* enable RX input */ - if (!td->did_stall) { + if (!td->did_enable) { uss820dci_update_shared_1(USS820_DCI_PC2SC(td->pc), USS820_EPCON, 0xFF, USS820_EPCON_RXIE); - td->did_stall = 1; + td->did_enable = 1; } return (1); /* not complete */ } /* get the packet byte count */ count = bus_space_read_1(td->io_tag, td->io_hdl, - td->rx_count_low_reg); + USS820_RXCNTL); count |= (bus_space_read_1(td->io_tag, td->io_hdl, - td->rx_count_high_reg) << 8); + USS820_RXCNTH) << 8); count &= 0x3FF; DPRINTFN(5, "count=0x%04x\n", count); @@ -454,7 +454,7 @@ repeat: } /* receive data */ bus_space_read_multi_1(td->io_tag, td->io_hdl, - td->rx_fifo_reg, buf_res.buffer, buf_res.length); + USS820_RXDAT, buf_res.buffer, buf_res.length); /* update counters */ count -= buf_res.length; @@ -464,10 +464,10 @@ repeat: /* set RXFFRC bit */ rx_cntl = bus_space_read_1(td->io_tag, td->io_hdl, - td->rx_cntl_reg); + USS820_RXCON); rx_cntl |= USS820_RXCON_RXFFRC; bus_space_write_1(td->io_tag, td->io_hdl, - td->rx_cntl_reg, rx_cntl); + USS820_RXCON, rx_cntl); /* check if we are complete */ if ((td->remainder == 0) || got_short) { @@ -495,18 +495,18 @@ uss820dci_data_tx(struct uss820dci_td *td) /* select the correct endpoint */ bus_space_write_1(td->io_tag, td->io_hdl, - td->ep_reg, td->ep_index); + USS820_EPINDEX, td->ep_index); to = 2; /* don't loop forever! */ repeat: /* read out TX FIFO flags */ tx_flag = bus_space_read_1(td->io_tag, td->io_hdl, - td->tx_flag_reg); + USS820_TXFLG); /* read out RX FIFO status last */ rx_stat = bus_space_read_1(td->io_tag, td->io_hdl, - td->rx_stat_reg); + USS820_RXSTAT); DPRINTFN(5, "rx_stat=0x%02x tx_flag=0x%02x rem=%u\n", rx_stat, tx_flag, td->remainder); @@ -553,7 +553,7 @@ repeat: } /* transmit data */ bus_space_write_multi_1(td->io_tag, td->io_hdl, - td->tx_fifo_reg, buf_res.buffer, buf_res.length); + USS820_TXDAT, buf_res.buffer, buf_res.length); /* update counters */ count -= buf_res.length; @@ -563,20 +563,20 @@ repeat: /* post-write high packet byte count first */ bus_space_write_1(td->io_tag, td->io_hdl, - td->tx_count_high_reg, count_copy >> 8); + USS820_TXCNTH, count_copy >> 8); /* post-write low packet byte count last */ bus_space_write_1(td->io_tag, td->io_hdl, - td->tx_count_low_reg, count_copy); + USS820_TXCNTL, count_copy); /* * Enable TX output, which must happen after that we have written * data into the FIFO. This is undocumented. */ - if (!td->did_stall) { + if (!td->did_enable) { uss820dci_update_shared_1(USS820_DCI_PC2SC(td->pc), USS820_EPCON, 0xFF, USS820_EPCON_TXOE); - td->did_stall = 1; + td->did_enable = 1; } /* check remainder */ if (td->remainder == 0) { @@ -600,15 +600,15 @@ uss820dci_data_tx_sync(struct uss820dci_td *td) /* select the correct endpoint */ bus_space_write_1(td->io_tag, td->io_hdl, - td->ep_reg, td->ep_index); + USS820_EPINDEX, td->ep_index); /* read out TX FIFO flag */ tx_flag = bus_space_read_1(td->io_tag, td->io_hdl, - td->tx_flag_reg); + USS820_TXFLG); /* read out RX FIFO status last */ rx_stat = bus_space_read_1(td->io_tag, td->io_hdl, - td->rx_stat_reg); + USS820_RXSTAT); DPRINTFN(5, "rx_stat=0x%02x rem=%u\n", rx_stat, td->remainder); @@ -813,7 +813,8 @@ uss820dci_setup_standard_chain_sub(struct uss820_std_temp *temp) td->offset = temp->offset; td->remainder = temp->len; td->error = 0; - td->did_stall = 0; + td->did_enable = 0; + td->did_stall = temp->did_stall; td->short_pkt = temp->short_pkt; td->alt_next = temp->setup_alt_next; } @@ -843,6 +844,7 @@ uss820dci_setup_standard_chain(struct usb2_xfer *xfer) temp.td_next = xfer->td_start[0]; temp.offset = 0; temp.setup_alt_next = xfer->flags_int.short_frames_ok; + temp.did_stall = !xfer->flags_int.control_stall; sc = USS820_DCI_BUS2SC(xfer->xroot->bus); ep_no = (xfer->endpoint & UE_ADDR); @@ -1173,7 +1175,7 @@ uss820dci_device_done(struct usb2_xfer *xfer, usb2_error_t error) DPRINTFN(2, "xfer=%p, pipe=%p, error=%d\n", xfer, xfer->pipe, error); - if (xfer->flags_int.usb2_mode == USB_MODE_DEVICE) { + if (xfer->flags_int.usb_mode == USB_MODE_DEVICE) { uss820dci_intr_set(xfer, 0); } /* dequeue transfer and start next transfer */ @@ -1279,7 +1281,7 @@ uss820dci_clear_stall(struct usb2_device *udev, struct usb2_pipe *pipe) DPRINTFN(5, "pipe=%p\n", pipe); /* check mode */ - if (udev->flags.usb2_mode != USB_MODE_DEVICE) { + if (udev->flags.usb_mode != USB_MODE_DEVICE) { /* not supported */ return; } @@ -2269,20 +2271,6 @@ uss820dci_xfer_setup(struct usb2_setup_params *parm) td->io_tag = sc->sc_io_tag; td->io_hdl = sc->sc_io_hdl; td->max_packet_size = xfer->max_packet_size; - td->rx_stat_reg = USS820_GET_REG(sc, USS820_RXSTAT); - td->tx_stat_reg = USS820_GET_REG(sc, USS820_TXSTAT); - td->rx_flag_reg = USS820_GET_REG(sc, USS820_RXFLG); - td->tx_flag_reg = USS820_GET_REG(sc, USS820_TXFLG); - td->rx_fifo_reg = USS820_GET_REG(sc, USS820_RXDAT); - td->tx_fifo_reg = USS820_GET_REG(sc, USS820_TXDAT); - td->rx_count_low_reg = USS820_GET_REG(sc, USS820_RXCNTL); - td->rx_count_high_reg = USS820_GET_REG(sc, USS820_RXCNTH); - td->tx_count_low_reg = USS820_GET_REG(sc, USS820_TXCNTL); - td->tx_count_high_reg = USS820_GET_REG(sc, USS820_TXCNTH); - td->rx_cntl_reg = USS820_GET_REG(sc, USS820_RXCON); - td->tx_cntl_reg = USS820_GET_REG(sc, USS820_TXCON); - td->pend_reg = USS820_GET_REG(sc, USS820_PEND); - td->ep_reg = USS820_GET_REG(sc, USS820_EPINDEX); td->ep_index = ep_no; if (pf->support_multi_buffer && (parm->methods != &uss820dci_device_ctrl_methods)) { @@ -2312,12 +2300,12 @@ uss820dci_pipe_init(struct usb2_device *udev, struct usb2_endpoint_descriptor *e DPRINTFN(2, "pipe=%p, addr=%d, endpt=%d, mode=%d (%d)\n", pipe, udev->address, - edesc->bEndpointAddress, udev->flags.usb2_mode, + edesc->bEndpointAddress, udev->flags.usb_mode, sc->sc_rt_addr); if (udev->device_index != sc->sc_rt_addr) { - if (udev->flags.usb2_mode != USB_MODE_DEVICE) { + if (udev->flags.usb_mode != USB_MODE_DEVICE) { /* not supported */ return; } diff --git a/sys/dev/usb/controller/uss820dci.h b/sys/dev/usb/controller/uss820dci.h index deba99002004..08bbb6a463d4 100644 --- a/sys/dev/usb/controller/uss820dci.h +++ b/sys/dev/usb/controller/uss820dci.h @@ -255,16 +255,11 @@ #define USS820_UNK1 0x1f /* Unknown */ #define USS820_UNK1_UNKNOWN 0xFF -#define USS820_GET_REG(sc,reg) \ - ((reg) << (sc)->sc_reg_shift) - #define USS820_READ_1(sc, reg) \ - bus_space_read_1((sc)->sc_io_tag, (sc)->sc_io_hdl, \ - USS820_GET_REG(sc,reg)) + bus_space_read_1((sc)->sc_io_tag, (sc)->sc_io_hdl, reg) #define USS820_WRITE_1(sc, reg, data) \ - bus_space_write_1((sc)->sc_io_tag, (sc)->sc_io_hdl, \ - USS820_GET_REG(sc,reg), data) + bus_space_write_1((sc)->sc_io_tag, (sc)->sc_io_hdl, reg, data) struct uss820dci_td; @@ -279,26 +274,13 @@ struct uss820dci_td { uint32_t offset; uint32_t remainder; uint16_t max_packet_size; - uint8_t rx_stat_reg; - uint8_t tx_stat_reg; - uint8_t rx_flag_reg; - uint8_t tx_flag_reg; - uint8_t rx_fifo_reg; - uint8_t tx_fifo_reg; - uint8_t rx_count_low_reg; - uint8_t rx_count_high_reg; - uint8_t tx_count_low_reg; - uint8_t tx_count_high_reg; - uint8_t rx_cntl_reg; - uint8_t tx_cntl_reg; - uint8_t ep_reg; - uint8_t pend_reg; uint8_t ep_index; uint8_t error:1; uint8_t alt_next:1; uint8_t short_pkt:1; uint8_t support_multi_buffer:1; uint8_t did_stall:1; + uint8_t did_enable:1; }; struct uss820_std_temp { @@ -315,6 +297,7 @@ struct uss820_std_temp { * short_pkt = 1: transfer should not be short terminated */ uint8_t setup_alt_next; + uint8_t did_stall; }; struct uss820dci_config_desc { @@ -356,7 +339,6 @@ struct uss820dci_softc { uint8_t sc_rt_addr; /* root HUB address */ uint8_t sc_dv_addr; /* device address */ uint8_t sc_conf; /* root HUB config */ - uint8_t sc_reg_shift; uint8_t sc_hub_idata[1]; diff --git a/sys/dev/usb/controller/uss820dci_atmelarm.c b/sys/dev/usb/controller/uss820dci_atmelarm.c index c01c2c57628a..18b0eb380da8 100644 --- a/sys/dev/usb/controller/uss820dci_atmelarm.c +++ b/sys/dev/usb/controller/uss820dci_atmelarm.c @@ -152,9 +152,6 @@ uss820_atmelarm_attach(device_t dev) sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res); sc->sc_io_size = rman_get_size(sc->sc_io_res); - /* multiply all addresses by 4 */ - sc->sc_reg_shift = 2; - rid = 0; sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); diff --git a/sys/dev/usb/input/uhid.c b/sys/dev/usb/input/uhid.c index 78931bdb7c48..da3b5a3473e5 100644 --- a/sys/dev/usb/input/uhid.c +++ b/sys/dev/usb/input/uhid.c @@ -76,8 +76,8 @@ __FBSDID("$FreeBSD$"); #if USB_DEBUG static int uhid_debug = 0; -SYSCTL_NODE(_hw_usb2, OID_AUTO, uhid, CTLFLAG_RW, 0, "USB uhid"); -SYSCTL_INT(_hw_usb2_uhid, OID_AUTO, debug, CTLFLAG_RW, +SYSCTL_NODE(_hw_usb, OID_AUTO, uhid, CTLFLAG_RW, 0, "USB uhid"); +SYSCTL_INT(_hw_usb_uhid, OID_AUTO, debug, CTLFLAG_RW, &uhid_debug, 0, "Debug level"); #endif @@ -599,7 +599,7 @@ uhid_probe(device_t dev) DPRINTFN(11, "\n"); - if (uaa->usb2_mode != USB_MODE_HOST) { + if (uaa->usb_mode != USB_MODE_HOST) { return (ENXIO); } if (uaa->use_generic == 0) { diff --git a/sys/dev/usb/input/ukbd.c b/sys/dev/usb/input/ukbd.c index 58e815169a73..d8d76c7fd144 100644 --- a/sys/dev/usb/input/ukbd.c +++ b/sys/dev/usb/input/ukbd.c @@ -86,8 +86,8 @@ __FBSDID("$FreeBSD$"); #if USB_DEBUG static int ukbd_debug = 0; -SYSCTL_NODE(_hw_usb2, OID_AUTO, ukbd, CTLFLAG_RW, 0, "USB ukbd"); -SYSCTL_INT(_hw_usb2_ukbd, OID_AUTO, debug, CTLFLAG_RW, +SYSCTL_NODE(_hw_usb, OID_AUTO, ukbd, CTLFLAG_RW, 0, "USB ukbd"); +SYSCTL_INT(_hw_usb_ukbd, OID_AUTO, debug, CTLFLAG_RW, &ukbd_debug, 0, "Debug level"); #endif @@ -598,7 +598,7 @@ ukbd_probe(device_t dev) if (sw == NULL) { return (ENXIO); } - if (uaa->usb2_mode != USB_MODE_HOST) { + if (uaa->usb_mode != USB_MODE_HOST) { return (ENXIO); } /* check that the keyboard speaks the boot protocol: */ diff --git a/sys/dev/usb/input/ums.c b/sys/dev/usb/input/ums.c index 6ed030de3d67..9b7d1fd8699c 100644 --- a/sys/dev/usb/input/ums.c +++ b/sys/dev/usb/input/ums.c @@ -72,8 +72,8 @@ __FBSDID("$FreeBSD$"); #if USB_DEBUG static int ums_debug = 0; -SYSCTL_NODE(_hw_usb2, OID_AUTO, ums, CTLFLAG_RW, 0, "USB ums"); -SYSCTL_INT(_hw_usb2_ums, OID_AUTO, debug, CTLFLAG_RW, +SYSCTL_NODE(_hw_usb, OID_AUTO, ums, CTLFLAG_RW, 0, "USB ums"); +SYSCTL_INT(_hw_usb_ums, OID_AUTO, debug, CTLFLAG_RW, &ums_debug, 0, "Debug level"); #endif @@ -339,7 +339,7 @@ ums_probe(device_t dev) DPRINTFN(11, "\n"); - if (uaa->usb2_mode != USB_MODE_HOST) + if (uaa->usb_mode != USB_MODE_HOST) return (ENXIO); id = usb2_get_interface_descriptor(uaa->iface); diff --git a/sys/dev/usb/misc/udbp.c b/sys/dev/usb/misc/udbp.c index e8acba81cfe8..1a7f8af5b024 100644 --- a/sys/dev/usb/misc/udbp.c +++ b/sys/dev/usb/misc/udbp.c @@ -83,8 +83,8 @@ __FBSDID("$FreeBSD$"); #if USB_DEBUG static int udbp_debug = 0; -SYSCTL_NODE(_hw_usb2, OID_AUTO, udbp, CTLFLAG_RW, 0, "USB udbp"); -SYSCTL_INT(_hw_usb2_udbp, OID_AUTO, debug, CTLFLAG_RW, +SYSCTL_NODE(_hw_usb, OID_AUTO, udbp, CTLFLAG_RW, 0, "USB udbp"); +SYSCTL_INT(_hw_usb_udbp, OID_AUTO, debug, CTLFLAG_RW, &udbp_debug, 0, "udbp debug level"); #endif @@ -279,7 +279,7 @@ udbp_probe(device_t dev) { struct usb2_attach_arg *uaa = device_get_ivars(dev); - if (uaa->usb2_mode != USB_MODE_HOST) { + if (uaa->usb_mode != USB_MODE_HOST) { return (ENXIO); } /* diff --git a/sys/dev/usb/misc/ufm.c b/sys/dev/usb/misc/ufm.c index f33065fa0eee..08808bbb5824 100644 --- a/sys/dev/usb/misc/ufm.c +++ b/sys/dev/usb/misc/ufm.c @@ -112,7 +112,7 @@ ufm_probe(device_t dev) { struct usb2_attach_arg *uaa = device_get_ivars(dev); - if (uaa->usb2_mode != USB_MODE_HOST) { + if (uaa->usb_mode != USB_MODE_HOST) { return (ENXIO); } if ((uaa->info.idVendor == USB_VENDOR_CYPRESS) && diff --git a/sys/dev/usb/net/if_aue.c b/sys/dev/usb/net/if_aue.c index e1cd066b4edd..4902c1cd5d54 100644 --- a/sys/dev/usb/net/if_aue.c +++ b/sys/dev/usb/net/if_aue.c @@ -89,8 +89,8 @@ __FBSDID("$FreeBSD$"); #if USB_DEBUG static int aue_debug = 0; -SYSCTL_NODE(_hw_usb2, OID_AUTO, aue, CTLFLAG_RW, 0, "USB aue"); -SYSCTL_INT(_hw_usb2_aue, OID_AUTO, debug, CTLFLAG_RW, &aue_debug, 0, +SYSCTL_NODE(_hw_usb, OID_AUTO, aue, CTLFLAG_RW, 0, "USB aue"); +SYSCTL_INT(_hw_usb_aue, OID_AUTO, debug, CTLFLAG_RW, &aue_debug, 0, "Debug level"); #endif @@ -628,7 +628,7 @@ aue_probe(device_t dev) { struct usb2_attach_arg *uaa = device_get_ivars(dev); - if (uaa->usb2_mode != USB_MODE_HOST) + if (uaa->usb_mode != USB_MODE_HOST) return (ENXIO); if (uaa->info.bConfigIndex != AUE_CONFIG_INDEX) return (ENXIO); diff --git a/sys/dev/usb/net/if_axe.c b/sys/dev/usb/net/if_axe.c index 6240e77d7ad6..f720c4ec3ca0 100644 --- a/sys/dev/usb/net/if_axe.c +++ b/sys/dev/usb/net/if_axe.c @@ -112,8 +112,8 @@ __FBSDID("$FreeBSD$"); #if USB_DEBUG static int axe_debug = 0; -SYSCTL_NODE(_hw_usb2, OID_AUTO, axe, CTLFLAG_RW, 0, "USB axe"); -SYSCTL_INT(_hw_usb2_axe, OID_AUTO, debug, CTLFLAG_RW, &axe_debug, 0, +SYSCTL_NODE(_hw_usb, OID_AUTO, axe, CTLFLAG_RW, 0, "USB axe"); +SYSCTL_INT(_hw_usb_axe, OID_AUTO, debug, CTLFLAG_RW, &axe_debug, 0, "Debug level"); #endif @@ -662,7 +662,7 @@ axe_probe(device_t dev) { struct usb2_attach_arg *uaa = device_get_ivars(dev); - if (uaa->usb2_mode != USB_MODE_HOST) + if (uaa->usb_mode != USB_MODE_HOST) return (ENXIO); if (uaa->info.bConfigIndex != AXE_CONFIG_IDX) return (ENXIO); diff --git a/sys/dev/usb/net/if_cdce.c b/sys/dev/usb/net/if_cdce.c index eec58fc114e1..0c1e4c1dc35a 100644 --- a/sys/dev/usb/net/if_cdce.c +++ b/sys/dev/usb/net/if_cdce.c @@ -88,8 +88,8 @@ static uint32_t cdce_m_crc32(struct mbuf *, uint32_t, uint32_t); #if USB_DEBUG static int cdce_debug = 0; -SYSCTL_NODE(_hw_usb2, OID_AUTO, cdce, CTLFLAG_RW, 0, "USB CDC-Ethernet"); -SYSCTL_INT(_hw_usb2_cdce, OID_AUTO, debug, CTLFLAG_RW, &cdce_debug, 0, +SYSCTL_NODE(_hw_usb, OID_AUTO, cdce, CTLFLAG_RW, 0, "USB CDC-Ethernet"); +SYSCTL_INT(_hw_usb_cdce, OID_AUTO, debug, CTLFLAG_RW, &cdce_debug, 0, "Debug level"); #endif @@ -105,7 +105,7 @@ static const struct usb2_config cdce_config[CDCE_N_TRANSFER] = { .flags = {.pipe_bof = 1,.short_frames_ok = 1,.short_xfer_ok = 1,.ext_buffer = 1,}, .callback = cdce_bulk_read_callback, .timeout = 0, /* no timeout */ - .usb_mode = USB_MODE_MAX, /* both modes */ + .usb_mode = USB_MODE_DUAL, /* both modes */ }, [CDCE_BULK_TX] = { @@ -118,7 +118,7 @@ static const struct usb2_config cdce_config[CDCE_N_TRANSFER] = { .flags = {.pipe_bof = 1,.force_short_xfer = 1,.ext_buffer = 1,}, .callback = cdce_bulk_write_callback, .timeout = 10000, /* 10 seconds */ - .usb_mode = USB_MODE_MAX, /* both modes */ + .usb_mode = USB_MODE_DUAL, /* both modes */ }, [CDCE_INTR_RX] = { @@ -361,7 +361,7 @@ alloc_transfers: sc->sc_ue.ue_eaddr[i / 2] |= c; } - if (uaa->usb2_mode == USB_MODE_DEVICE) { + if (uaa->usb_mode == USB_MODE_DEVICE) { /* * Do not use the same MAC address like the peer ! */ diff --git a/sys/dev/usb/net/if_cue.c b/sys/dev/usb/net/if_cue.c index e487280cda38..f5bb9aca20d9 100644 --- a/sys/dev/usb/net/if_cue.c +++ b/sys/dev/usb/net/if_cue.c @@ -109,8 +109,8 @@ static void cue_reset(struct cue_softc *); #if USB_DEBUG static int cue_debug = 0; -SYSCTL_NODE(_hw_usb2, OID_AUTO, cue, CTLFLAG_RW, 0, "USB cue"); -SYSCTL_INT(_hw_usb2_cue, OID_AUTO, debug, CTLFLAG_RW, &cue_debug, 0, +SYSCTL_NODE(_hw_usb, OID_AUTO, cue, CTLFLAG_RW, 0, "USB cue"); +SYSCTL_INT(_hw_usb_cue, OID_AUTO, debug, CTLFLAG_RW, &cue_debug, 0, "Debug level"); #endif @@ -360,7 +360,7 @@ cue_probe(device_t dev) { struct usb2_attach_arg *uaa = device_get_ivars(dev); - if (uaa->usb2_mode != USB_MODE_HOST) + if (uaa->usb_mode != USB_MODE_HOST) return (ENXIO); if (uaa->info.bConfigIndex != CUE_CONFIG_IDX) return (ENXIO); diff --git a/sys/dev/usb/net/if_kue.c b/sys/dev/usb/net/if_kue.c index c72210cc8269..91b25b3ca27a 100644 --- a/sys/dev/usb/net/if_kue.c +++ b/sys/dev/usb/net/if_kue.c @@ -151,8 +151,8 @@ static void kue_reset(struct kue_softc *); #if USB_DEBUG static int kue_debug = 0; -SYSCTL_NODE(_hw_usb2, OID_AUTO, kue, CTLFLAG_RW, 0, "USB kue"); -SYSCTL_INT(_hw_usb2_kue, OID_AUTO, debug, CTLFLAG_RW, &kue_debug, 0, +SYSCTL_NODE(_hw_usb, OID_AUTO, kue, CTLFLAG_RW, 0, "USB kue"); +SYSCTL_INT(_hw_usb_kue, OID_AUTO, debug, CTLFLAG_RW, &kue_debug, 0, "Debug level"); #endif @@ -436,7 +436,7 @@ kue_probe(device_t dev) { struct usb2_attach_arg *uaa = device_get_ivars(dev); - if (uaa->usb2_mode != USB_MODE_HOST) + if (uaa->usb_mode != USB_MODE_HOST) return (ENXIO); if (uaa->info.bConfigIndex != KUE_CONFIG_IDX) return (ENXIO); diff --git a/sys/dev/usb/net/if_rue.c b/sys/dev/usb/net/if_rue.c index 578394397234..645177934ae1 100644 --- a/sys/dev/usb/net/if_rue.c +++ b/sys/dev/usb/net/if_rue.c @@ -86,8 +86,8 @@ __FBSDID("$FreeBSD$"); #if USB_DEBUG static int rue_debug = 0; -SYSCTL_NODE(_hw_usb2, OID_AUTO, rue, CTLFLAG_RW, 0, "USB rue"); -SYSCTL_INT(_hw_usb2_rue, OID_AUTO, debug, CTLFLAG_RW, +SYSCTL_NODE(_hw_usb, OID_AUTO, rue, CTLFLAG_RW, 0, "USB rue"); +SYSCTL_INT(_hw_usb_rue, OID_AUTO, debug, CTLFLAG_RW, &rue_debug, 0, "Debug level"); #endif @@ -546,7 +546,7 @@ rue_probe(device_t dev) { struct usb2_attach_arg *uaa = device_get_ivars(dev); - if (uaa->usb2_mode != USB_MODE_HOST) + if (uaa->usb_mode != USB_MODE_HOST) return (ENXIO); if (uaa->info.bConfigIndex != RUE_CONFIG_IDX) return (ENXIO); diff --git a/sys/dev/usb/net/if_udav.c b/sys/dev/usb/net/if_udav.c index 85155162c519..3d3a05802fec 100644 --- a/sys/dev/usb/net/if_udav.c +++ b/sys/dev/usb/net/if_udav.c @@ -174,8 +174,8 @@ static const struct usb2_ether_methods udav_ue_methods = { #if USB_DEBUG static int udav_debug = 0; -SYSCTL_NODE(_hw_usb2, OID_AUTO, udav, CTLFLAG_RW, 0, "USB udav"); -SYSCTL_INT(_hw_usb2_udav, OID_AUTO, debug, CTLFLAG_RW, &udav_debug, 0, +SYSCTL_NODE(_hw_usb, OID_AUTO, udav, CTLFLAG_RW, 0, "USB udav"); +SYSCTL_INT(_hw_usb_udav, OID_AUTO, debug, CTLFLAG_RW, &udav_debug, 0, "Debug level"); #endif @@ -211,7 +211,7 @@ udav_probe(device_t dev) { struct usb2_attach_arg *uaa = device_get_ivars(dev); - if (uaa->usb2_mode != USB_MODE_HOST) + if (uaa->usb_mode != USB_MODE_HOST) return (ENXIO); if (uaa->info.bConfigIndex != UDAV_CONFIG_INDEX) return (ENXIO); diff --git a/sys/dev/usb/serial/u3g.c b/sys/dev/usb/serial/u3g.c index 19009c6eea9b..72a406a8e333 100644 --- a/sys/dev/usb/serial/u3g.c +++ b/sys/dev/usb/serial/u3g.c @@ -53,12 +53,12 @@ #if USB_DEBUG static int u3g_debug = 0; -SYSCTL_NODE(_hw_usb2, OID_AUTO, u3g, CTLFLAG_RW, 0, "USB 3g"); -SYSCTL_INT(_hw_usb2_u3g, OID_AUTO, debug, CTLFLAG_RW, +SYSCTL_NODE(_hw_usb, OID_AUTO, u3g, CTLFLAG_RW, 0, "USB 3g"); +SYSCTL_INT(_hw_usb_u3g, OID_AUTO, debug, CTLFLAG_RW, &u3g_debug, 0, "Debug level"); #endif -#define U3G_MAXPORTS 4 +#define U3G_MAXPORTS 8 #define U3G_CONFIG_INDEX 0 #define U3G_BSIZE 2048 @@ -71,7 +71,6 @@ SYSCTL_INT(_hw_usb2_u3g, OID_AUTO, debug, CTLFLAG_RW, #define U3GSP_HSPA 6 #define U3GSP_MAX 7 -#define U3GFL_NONE 0x0000 /* No flags */ #define U3GFL_HUAWEI_INIT 0x0001 /* Init command required */ #define U3GFL_SCSI_EJECT 0x0002 /* SCSI eject command required */ #define U3GFL_SIERRA_INIT 0x0004 /* Init command required */ @@ -158,70 +157,72 @@ MODULE_DEPEND(u3g, ucom, 1, 1, 1); MODULE_DEPEND(u3g, usb, 1, 1, 1); static const struct usb2_device_id u3g_devs[] = { +#define U3G_DEV(v,p,i) { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, i) } /* OEM: Option */ - {USB_VPI(USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GT3G, U3GFL_NONE)}, - {USB_VPI(USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GT3GQUAD, U3GFL_NONE)}, - {USB_VPI(USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GT3GPLUS, U3GFL_NONE)}, - {USB_VPI(USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GTMAX36, U3GFL_NONE)}, - {USB_VPI(USB_VENDOR_OPTION, USB_PRODUCT_OPTION_GTMAXHSUPA, U3GFL_NONE)}, - {USB_VPI(USB_VENDOR_OPTION, USB_PRODUCT_OPTION_VODAFONEMC3G, U3GFL_NONE)}, + U3G_DEV(OPTION, GT3G, 0), + U3G_DEV(OPTION, GT3GQUAD, 0), + U3G_DEV(OPTION, GT3GPLUS, 0), + U3G_DEV(OPTION, GTMAX36, 0), + U3G_DEV(OPTION, GTHSDPA, 0), + U3G_DEV(OPTION, GTMAXHSUPA, 0), + U3G_DEV(OPTION, VODAFONEMC3G, 0), /* OEM: Qualcomm, Inc. */ - {USB_VPI(USB_VENDOR_QUALCOMMINC, USB_PRODUCT_QUALCOMMINC_ZTE_STOR, U3GFL_SCSI_EJECT)}, - {USB_VPI(USB_VENDOR_QUALCOMMINC, USB_PRODUCT_QUALCOMMINC_CDMA_MSM, U3GFL_SCSI_EJECT)}, + U3G_DEV(QUALCOMMINC, ZTE_STOR, U3GFL_SCSI_EJECT), + U3G_DEV(QUALCOMMINC, CDMA_MSM, U3GFL_SCSI_EJECT), /* OEM: Huawei */ - {USB_VPI(USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_MOBILE, U3GFL_HUAWEI_INIT)}, - {USB_VPI(USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E220, U3GFL_HUAWEI_INIT)}, + U3G_DEV(HUAWEI, MOBILE, U3GFL_HUAWEI_INIT), + U3G_DEV(HUAWEI, E220, U3GFL_HUAWEI_INIT), /* OEM: Novatel */ - {USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_CDMA_MODEM, U3GFL_SCSI_EJECT)}, - {USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_ES620, U3GFL_SCSI_EJECT)}, - {USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_MC950D, U3GFL_SCSI_EJECT)}, - {USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U720, U3GFL_SCSI_EJECT)}, - {USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U727, U3GFL_SCSI_EJECT)}, - {USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U740, U3GFL_SCSI_EJECT)}, - {USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U740_2, U3GFL_SCSI_EJECT)}, - {USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_U870, U3GFL_SCSI_EJECT)}, - {USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_V620, U3GFL_SCSI_EJECT)}, - {USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_V640, U3GFL_SCSI_EJECT)}, - {USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_V720, U3GFL_SCSI_EJECT)}, - {USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_V740, U3GFL_SCSI_EJECT)}, - {USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_X950D, U3GFL_SCSI_EJECT)}, - {USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_XU870, U3GFL_SCSI_EJECT)}, - {USB_VPI(USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_ZEROCD, U3GFL_SCSI_EJECT)}, - {USB_VPI(USB_VENDOR_DELL, USB_PRODUCT_DELL_U740, U3GFL_SCSI_EJECT)}, + U3G_DEV(NOVATEL, CDMA_MODEM, 0), + U3G_DEV(NOVATEL, ES620, 0), + U3G_DEV(NOVATEL, MC950D, 0), + U3G_DEV(NOVATEL, U720, 0), + U3G_DEV(NOVATEL, U727, 0), + U3G_DEV(NOVATEL, U740, 0), + U3G_DEV(NOVATEL, U740_2, 0), + U3G_DEV(NOVATEL, U870, 0), + U3G_DEV(NOVATEL, V620, 0), + U3G_DEV(NOVATEL, V640, 0), + U3G_DEV(NOVATEL, V720, 0), + U3G_DEV(NOVATEL, V740, 0), + U3G_DEV(NOVATEL, X950D, 0), + U3G_DEV(NOVATEL, XU870, 0), + U3G_DEV(NOVATEL, ZEROCD, U3GFL_SCSI_EJECT), + U3G_DEV(DELL, U740, 0), /* OEM: Merlin */ - {USB_VPI(USB_VENDOR_MERLIN, USB_PRODUCT_MERLIN_V620, U3GFL_NONE)}, + U3G_DEV(MERLIN, V620, 0), /* OEM: Sierra Wireless: */ - {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD580, U3GFL_NONE)}, - {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD595, U3GFL_NONE)}, - {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC595U, U3GFL_NONE)}, - {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC597E, U3GFL_NONE)}, - {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_C597, U3GFL_NONE)}, - {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880, U3GFL_NONE)}, - {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880E, U3GFL_NONE)}, - {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC880U, U3GFL_NONE)}, - {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881, U3GFL_NONE)}, - {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881E, U3GFL_NONE)}, - {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC881U, U3GFL_NONE)}, - {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_EM5625, U3GFL_NONE)}, - {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5720, U3GFL_NONE)}, - {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5720_2, U3GFL_NONE)}, - {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5725, U3GFL_NONE)}, - {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MINI5725, U3GFL_NONE)}, - {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD875, U3GFL_NONE)}, - {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755, U3GFL_NONE)}, - {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755_2, U3GFL_NONE)}, - {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755_3, U3GFL_NONE)}, - {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8765, U3GFL_NONE)}, - {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AC875U, U3GFL_NONE)}, - {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8775_2, U3GFL_NONE)}, - {USB_VPI(USB_VENDOR_HP, USB_PRODUCT_HP_HS2300, U3GFL_NONE)}, - {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8780, U3GFL_NONE)}, - {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8781, U3GFL_NONE)}, - {USB_VPI(USB_VENDOR_HP, USB_PRODUCT_HP_HS2300, U3GFL_NONE)}, + U3G_DEV(SIERRA, AIRCARD580, 0), + U3G_DEV(SIERRA, AIRCARD595, 0), + U3G_DEV(SIERRA, AC595U, 0), + U3G_DEV(SIERRA, AC597E, 0), + U3G_DEV(SIERRA, C597, 0), + U3G_DEV(SIERRA, AC880, 0), + U3G_DEV(SIERRA, AC880E, 0), + U3G_DEV(SIERRA, AC880U, 0), + U3G_DEV(SIERRA, AC881, 0), + U3G_DEV(SIERRA, AC881E, 0), + U3G_DEV(SIERRA, AC881U, 0), + U3G_DEV(SIERRA, AC885U, 0), + U3G_DEV(SIERRA, EM5625, 0), + U3G_DEV(SIERRA, MC5720, 0), + U3G_DEV(SIERRA, MC5720_2, 0), + U3G_DEV(SIERRA, MC5725, 0), + U3G_DEV(SIERRA, MINI5725, 0), + U3G_DEV(SIERRA, AIRCARD875, 0), + U3G_DEV(SIERRA, MC8755, 0), + U3G_DEV(SIERRA, MC8755_2, 0), + U3G_DEV(SIERRA, MC8755_3, 0), + U3G_DEV(SIERRA, MC8765, 0), + U3G_DEV(SIERRA, AC875U, 0), + U3G_DEV(SIERRA, MC8775_2, 0), + U3G_DEV(SIERRA, MC8780, 0), + U3G_DEV(SIERRA, MC8781, 0), + U3G_DEV(HP, HS2300, 0), /* Sierra TruInstaller device ID */ - {USB_VPI(USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_TRUINSTALL, U3GFL_SIERRA_INIT)}, + U3G_DEV(SIERRA, TRUINSTALL, U3GFL_SIERRA_INIT), /* PRUEBA SILABS */ - {USB_VPI(USB_VENDOR_SILABS, USB_PRODUCT_SILABS_SAEL, U3GFL_SAEL_M460_INIT)}, + U3G_DEV(SILABS, SAEL, U3GFL_SAEL_M460_INIT), }; static void @@ -420,7 +421,7 @@ u3g_probe(device_t self) { struct usb2_attach_arg *uaa = device_get_ivars(self); - if (uaa->usb2_mode != USB_MODE_HOST) { + if (uaa->usb_mode != USB_MODE_HOST) { return (ENXIO); } if (uaa->info.bConfigIndex != U3G_CONFIG_INDEX) { @@ -440,12 +441,10 @@ u3g_attach(device_t dev) struct u3g_softc *sc = device_get_softc(dev); struct usb2_interface *iface; struct usb2_interface_descriptor *id; - uint32_t flags; - uint8_t m; - uint8_t n; + uint32_t iface_valid; + int error, flags, nports; + int ep, n; uint8_t i; - uint8_t x; - int error; DPRINTF("sc=%p\n", sc); @@ -463,72 +462,68 @@ u3g_attach(device_t dev) sc->sc_udev = uaa->device; - x = 0; /* interface index */ - i = 0; /* endpoint index */ - m = 0; /* number of ports */ - - while (m != U3G_MAXPORTS) { - - /* update BULK endpoint index */ - for (n = 0; n != U3G_N_TRANSFER; n++) - u3g_config_tmp[n].ep_index = i; - - iface = usb2_get_iface(uaa->device, x); - if (iface == NULL) { - if (m != 0) - break; /* end of interfaces */ - DPRINTF("did not find any modem endpoints\n"); - goto detach; - } - + /* Claim all interfaces on the device */ + iface_valid = 0; + for (i = uaa->info.bIfaceIndex; i < USB_IFACE_MAX; i++) { + iface = usb2_get_iface(uaa->device, i); + if (iface == NULL) + break; id = usb2_get_interface_descriptor(iface); - if ((id == NULL) || - (id->bInterfaceClass != UICLASS_VENDOR)) { - /* next interface */ - x++; - i = 0; + if (id == NULL || id->bInterfaceClass != UICLASS_VENDOR) + continue; + usb2_set_parent_iface(uaa->device, i, uaa->info.bIfaceIndex); + iface_valid |= (1<<i); + } + + i = 0; /* interface index */ + ep = 0; /* endpoint index */ + nports = 0; /* number of ports */ + while (i < USB_IFACE_MAX) { + if ((iface_valid & (1<<i)) == 0) { + i++; continue; } + /* update BULK endpoint index */ + for (n = 0; n < U3G_N_TRANSFER; n++) + u3g_config_tmp[n].ep_index = ep; + /* try to allocate a set of BULK endpoints */ - error = usb2_transfer_setup(uaa->device, &x, - sc->sc_xfer[m], u3g_config_tmp, U3G_N_TRANSFER, - &sc->sc_ucom[m], &sc->sc_mtx); + error = usb2_transfer_setup(uaa->device, &i, + sc->sc_xfer[nports], u3g_config_tmp, U3G_N_TRANSFER, + &sc->sc_ucom[nports], &sc->sc_mtx); if (error) { /* next interface */ - x++; - i = 0; + i++; + ep = 0; continue; } - /* grab other interface, if any */ - if (x != uaa->info.bIfaceIndex) - usb2_set_parent_iface(uaa->device, x, - uaa->info.bIfaceIndex); - /* set stall by default */ mtx_lock(&sc->sc_mtx); - usb2_transfer_set_stall(sc->sc_xfer[m][U3G_BULK_WR]); - usb2_transfer_set_stall(sc->sc_xfer[m][U3G_BULK_RD]); + usb2_transfer_set_stall(sc->sc_xfer[nports][U3G_BULK_WR]); + usb2_transfer_set_stall(sc->sc_xfer[nports][U3G_BULK_RD]); mtx_unlock(&sc->sc_mtx); - m++; /* found one port */ - i++; /* next endpoint index */ + nports++; /* found one port */ + ep++; + if (nports == U3G_MAXPORTS) + break; } + if (nports == 0) { + device_printf(dev, "no ports found\n"); + goto detach; + } + sc->sc_numports = nports; - sc->sc_numports = m; - - error = usb2_com_attach(&sc->sc_super_ucom, sc->sc_ucom, + error = usb2_com_attach(&sc->sc_super_ucom, sc->sc_ucom, sc->sc_numports, sc, &u3g_callback, &sc->sc_mtx); if (error) { DPRINTF("usb2_com_attach failed\n"); goto detach; } - if (sc->sc_numports != 1) { - /* be verbose */ - device_printf(dev, "Found %u ports.\n", - (unsigned int)sc->sc_numports); - } + if (sc->sc_numports > 1) + device_printf(dev, "Found %u ports.\n", sc->sc_numports); return (0); detach: diff --git a/sys/dev/usb/serial/uark.c b/sys/dev/usb/serial/uark.c index bc0bace12188..4ea6dbdfe903 100644 --- a/sys/dev/usb/serial/uark.c +++ b/sys/dev/usb/serial/uark.c @@ -161,7 +161,7 @@ uark_probe(device_t dev) { struct usb2_attach_arg *uaa = device_get_ivars(dev); - if (uaa->usb2_mode != USB_MODE_HOST) { + if (uaa->usb_mode != USB_MODE_HOST) { return (ENXIO); } if (uaa->info.bConfigIndex != 0) { diff --git a/sys/dev/usb/serial/ubsa.c b/sys/dev/usb/serial/ubsa.c index a52c828b5152..78b0fd5822e9 100644 --- a/sys/dev/usb/serial/ubsa.c +++ b/sys/dev/usb/serial/ubsa.c @@ -83,8 +83,8 @@ __FBSDID("$FreeBSD$"); #if USB_DEBUG static int ubsa_debug = 0; -SYSCTL_NODE(_hw_usb2, OID_AUTO, ubsa, CTLFLAG_RW, 0, "USB ubsa"); -SYSCTL_INT(_hw_usb2_ubsa, OID_AUTO, debug, CTLFLAG_RW, +SYSCTL_NODE(_hw_usb, OID_AUTO, ubsa, CTLFLAG_RW, 0, "USB ubsa"); +SYSCTL_INT(_hw_usb_ubsa, OID_AUTO, debug, CTLFLAG_RW, &ubsa_debug, 0, "ubsa debug level"); #endif @@ -268,7 +268,7 @@ ubsa_probe(device_t dev) { struct usb2_attach_arg *uaa = device_get_ivars(dev); - if (uaa->usb2_mode != USB_MODE_HOST) { + if (uaa->usb_mode != USB_MODE_HOST) { return (ENXIO); } if (uaa->info.bConfigIndex != UBSA_CONFIG_INDEX) { diff --git a/sys/dev/usb/serial/ubser.c b/sys/dev/usb/serial/ubser.c index 6ec67ae1e9f1..74100b481eff 100644 --- a/sys/dev/usb/serial/ubser.c +++ b/sys/dev/usb/serial/ubser.c @@ -104,8 +104,8 @@ __FBSDID("$FreeBSD$"); #if USB_DEBUG static int ubser_debug = 0; -SYSCTL_NODE(_hw_usb2, OID_AUTO, ubser, CTLFLAG_RW, 0, "USB ubser"); -SYSCTL_INT(_hw_usb2_ubser, OID_AUTO, debug, CTLFLAG_RW, +SYSCTL_NODE(_hw_usb, OID_AUTO, ubser, CTLFLAG_RW, 0, "USB ubser"); +SYSCTL_INT(_hw_usb_ubser, OID_AUTO, debug, CTLFLAG_RW, &ubser_debug, 0, "ubser debug level"); #endif @@ -205,7 +205,7 @@ ubser_probe(device_t dev) { struct usb2_attach_arg *uaa = device_get_ivars(dev); - if (uaa->usb2_mode != USB_MODE_HOST) { + if (uaa->usb_mode != USB_MODE_HOST) { return (ENXIO); } /* check if this is a BWCT vendor specific ubser interface */ diff --git a/sys/dev/usb/serial/uchcom.c b/sys/dev/usb/serial/uchcom.c index 413fb125cd4a..58cf12554826 100644 --- a/sys/dev/usb/serial/uchcom.c +++ b/sys/dev/usb/serial/uchcom.c @@ -91,8 +91,8 @@ __FBSDID("$FreeBSD$"); #if USB_DEBUG static int uchcom_debug = 0; -SYSCTL_NODE(_hw_usb2, OID_AUTO, uchcom, CTLFLAG_RW, 0, "USB uchcom"); -SYSCTL_INT(_hw_usb2_uchcom, OID_AUTO, debug, CTLFLAG_RW, +SYSCTL_NODE(_hw_usb, OID_AUTO, uchcom, CTLFLAG_RW, 0, "USB uchcom"); +SYSCTL_INT(_hw_usb_uchcom, OID_AUTO, debug, CTLFLAG_RW, &uchcom_debug, 0, "uchcom debug level"); #endif @@ -281,7 +281,7 @@ uchcom_probe(device_t dev) DPRINTFN(11, "\n"); - if (uaa->usb2_mode != USB_MODE_HOST) { + if (uaa->usb_mode != USB_MODE_HOST) { return (ENXIO); } if (uaa->info.bConfigIndex != UCHCOM_CONFIG_INDEX) { diff --git a/sys/dev/usb/serial/ucycom.c b/sys/dev/usb/serial/ucycom.c index a044c007286b..28ebbb8cfc9f 100644 --- a/sys/dev/usb/serial/ucycom.c +++ b/sys/dev/usb/serial/ucycom.c @@ -179,7 +179,7 @@ ucycom_probe(device_t dev) { struct usb2_attach_arg *uaa = device_get_ivars(dev); - if (uaa->usb2_mode != USB_MODE_HOST) { + if (uaa->usb_mode != USB_MODE_HOST) { return (ENXIO); } if (uaa->info.bConfigIndex != 0) { diff --git a/sys/dev/usb/serial/ufoma.c b/sys/dev/usb/serial/ufoma.c index 62471e724ef8..fb27061b554e 100644 --- a/sys/dev/usb/serial/ufoma.c +++ b/sys/dev/usb/serial/ufoma.c @@ -322,7 +322,7 @@ ufoma_probe(device_t dev) struct usb2_config_descriptor *cd; usb2_mcpc_acm_descriptor *mad; - if (uaa->usb2_mode != USB_MODE_HOST) { + if (uaa->usb_mode != USB_MODE_HOST) { return (ENXIO); } id = usb2_get_interface_descriptor(uaa->iface); diff --git a/sys/dev/usb/serial/uftdi.c b/sys/dev/usb/serial/uftdi.c index 8a6e7e11ac12..f79922fc075a 100644 --- a/sys/dev/usb/serial/uftdi.c +++ b/sys/dev/usb/serial/uftdi.c @@ -70,8 +70,8 @@ __FBSDID("$FreeBSD$"); #if USB_DEBUG static int uftdi_debug = 0; -SYSCTL_NODE(_hw_usb2, OID_AUTO, uftdi, CTLFLAG_RW, 0, "USB uftdi"); -SYSCTL_INT(_hw_usb2_uftdi, OID_AUTO, debug, CTLFLAG_RW, +SYSCTL_NODE(_hw_usb, OID_AUTO, uftdi, CTLFLAG_RW, 0, "USB uftdi"); +SYSCTL_INT(_hw_usb_uftdi, OID_AUTO, debug, CTLFLAG_RW, &uftdi_debug, 0, "Debug level"); #endif @@ -240,7 +240,7 @@ uftdi_probe(device_t dev) { struct usb2_attach_arg *uaa = device_get_ivars(dev); - if (uaa->usb2_mode != USB_MODE_HOST) { + if (uaa->usb_mode != USB_MODE_HOST) { return (ENXIO); } if (uaa->info.bConfigIndex != UFTDI_CONFIG_INDEX) { diff --git a/sys/dev/usb/serial/ugensa.c b/sys/dev/usb/serial/ugensa.c index f370e1b310fd..483a2dc2ac43 100644 --- a/sys/dev/usb/serial/ugensa.c +++ b/sys/dev/usb/serial/ugensa.c @@ -161,7 +161,7 @@ ugensa_probe(device_t dev) { struct usb2_attach_arg *uaa = device_get_ivars(dev); - if (uaa->usb2_mode != USB_MODE_HOST) { + if (uaa->usb_mode != USB_MODE_HOST) { return (ENXIO); } if (uaa->info.bConfigIndex != UGENSA_CONFIG_INDEX) { diff --git a/sys/dev/usb/serial/uipaq.c b/sys/dev/usb/serial/uipaq.c index 24dbd25618bf..97480475a5b6 100644 --- a/sys/dev/usb/serial/uipaq.c +++ b/sys/dev/usb/serial/uipaq.c @@ -996,8 +996,10 @@ static const struct usb2_device_id uipaq_devs[] = { {USB_VPI(USB_VENDOR_SHARP, 0x9121, 0)}, /* SHARP S01SH USB Modem */ {USB_VPI(USB_VENDOR_SHARP, 0x9151, 0)}, -/**/ + /**/ {USB_VPI(USB_VENDOR_SHARP, USB_PRODUCT_SHARP_WZERO3ES, 0)}, + /**/ + {USB_VPI(USB_VENDOR_SHARP, USB_PRODUCT_SHARP_WILLCOM03, 0)}, /* Symbol USB Sync */ {USB_VPI(USB_VENDOR_SYMBOL, 0x2000, 0)}, /* Symbol USB Sync 0x2001 */ @@ -1078,7 +1080,7 @@ uipaq_probe(device_t dev) { struct usb2_attach_arg *uaa = device_get_ivars(dev); - if (uaa->usb2_mode != USB_MODE_HOST) { + if (uaa->usb_mode != USB_MODE_HOST) { return (ENXIO); } if (uaa->info.bConfigIndex != UIPAQ_CONFIG_INDEX) { diff --git a/sys/dev/usb/serial/ulpt.c b/sys/dev/usb/serial/ulpt.c index 024325ee7433..80df2ce57a0e 100644 --- a/sys/dev/usb/serial/ulpt.c +++ b/sys/dev/usb/serial/ulpt.c @@ -68,8 +68,8 @@ __FBSDID("$FreeBSD$"); #if USB_DEBUG static int ulpt_debug = 0; -SYSCTL_NODE(_hw_usb2, OID_AUTO, ulpt, CTLFLAG_RW, 0, "USB ulpt"); -SYSCTL_INT(_hw_usb2_ulpt, OID_AUTO, debug, CTLFLAG_RW, +SYSCTL_NODE(_hw_usb, OID_AUTO, ulpt, CTLFLAG_RW, 0, "USB ulpt"); +SYSCTL_INT(_hw_usb_ulpt, OID_AUTO, debug, CTLFLAG_RW, &ulpt_debug, 0, "Debug level"); #endif @@ -471,7 +471,7 @@ ulpt_probe(device_t dev) DPRINTFN(11, "\n"); - if (uaa->usb2_mode != USB_MODE_HOST) { + if (uaa->usb_mode != USB_MODE_HOST) { return (ENXIO); } if ((uaa->info.bInterfaceClass == UICLASS_PRINTER) && diff --git a/sys/dev/usb/serial/umct.c b/sys/dev/usb/serial/umct.c index db3ddb46ce59..b72943b92638 100644 --- a/sys/dev/usb/serial/umct.c +++ b/sys/dev/usb/serial/umct.c @@ -77,7 +77,7 @@ __FBSDID("$FreeBSD$"); #define UMCT_INTR_INTERVAL 100 #define UMCT_IFACE_INDEX 0 -#define UMCT_CONFIG_INDEX 1 +#define UMCT_CONFIG_INDEX 0 enum { UMCT_BULK_DT_WR, @@ -208,7 +208,7 @@ umct_probe(device_t dev) { struct usb2_attach_arg *uaa = device_get_ivars(dev); - if (uaa->usb2_mode != USB_MODE_HOST) { + if (uaa->usb_mode != USB_MODE_HOST) { return (ENXIO); } if (uaa->info.bConfigIndex != UMCT_CONFIG_INDEX) { diff --git a/sys/dev/usb/serial/umodem.c b/sys/dev/usb/serial/umodem.c index 35186fd93a10..785ac9b3e25f 100644 --- a/sys/dev/usb/serial/umodem.c +++ b/sys/dev/usb/serial/umodem.c @@ -103,8 +103,8 @@ __FBSDID("$FreeBSD$"); #if USB_DEBUG static int umodem_debug = 0; -SYSCTL_NODE(_hw_usb2, OID_AUTO, umodem, CTLFLAG_RW, 0, "USB umodem"); -SYSCTL_INT(_hw_usb2_umodem, OID_AUTO, debug, CTLFLAG_RW, +SYSCTL_NODE(_hw_usb, OID_AUTO, umodem, CTLFLAG_RW, 0, "USB umodem"); +SYSCTL_INT(_hw_usb_umodem, OID_AUTO, debug, CTLFLAG_RW, &umodem_debug, 0, "Debug level"); #endif @@ -257,7 +257,7 @@ umodem_probe(device_t dev) DPRINTFN(11, "\n"); - if (uaa->usb2_mode != USB_MODE_HOST) { + if (uaa->usb_mode != USB_MODE_HOST) { return (ENXIO); } error = usb2_lookup_id_by_uaa(umodem_devs, sizeof(umodem_devs), uaa); diff --git a/sys/dev/usb/serial/umoscom.c b/sys/dev/usb/serial/umoscom.c index f2820aec0d4c..a6549e553d0a 100644 --- a/sys/dev/usb/serial/umoscom.c +++ b/sys/dev/usb/serial/umoscom.c @@ -38,8 +38,8 @@ #if USB_DEBUG static int umoscom_debug = 0; -SYSCTL_NODE(_hw_usb2, OID_AUTO, umoscom, CTLFLAG_RW, 0, "USB umoscom"); -SYSCTL_INT(_hw_usb2_umoscom, OID_AUTO, debug, CTLFLAG_RW, +SYSCTL_NODE(_hw_usb, OID_AUTO, umoscom, CTLFLAG_RW, 0, "USB umoscom"); +SYSCTL_INT(_hw_usb_umoscom, OID_AUTO, debug, CTLFLAG_RW, &umoscom_debug, 0, "Debug level"); #endif @@ -274,7 +274,7 @@ umoscom_probe(device_t dev) { struct usb2_attach_arg *uaa = device_get_ivars(dev); - if (uaa->usb2_mode != USB_MODE_HOST) { + if (uaa->usb_mode != USB_MODE_HOST) { return (ENXIO); } if (uaa->info.bConfigIndex != UMOSCOM_CONFIG_INDEX) { diff --git a/sys/dev/usb/serial/uplcom.c b/sys/dev/usb/serial/uplcom.c index 24a4b36eb049..f01f7448ac0e 100644 --- a/sys/dev/usb/serial/uplcom.c +++ b/sys/dev/usb/serial/uplcom.c @@ -105,8 +105,8 @@ __FBSDID("$FreeBSD$"); #if USB_DEBUG static int uplcom_debug = 0; -SYSCTL_NODE(_hw_usb2, OID_AUTO, uplcom, CTLFLAG_RW, 0, "USB uplcom"); -SYSCTL_INT(_hw_usb2_uplcom, OID_AUTO, debug, CTLFLAG_RW, +SYSCTL_NODE(_hw_usb, OID_AUTO, uplcom, CTLFLAG_RW, 0, "USB uplcom"); +SYSCTL_INT(_hw_usb_uplcom, OID_AUTO, debug, CTLFLAG_RW, &uplcom_debug, 0, "Debug level"); #endif @@ -306,7 +306,7 @@ uplcom_probe(device_t dev) DPRINTFN(11, "\n"); - if (uaa->usb2_mode != USB_MODE_HOST) { + if (uaa->usb_mode != USB_MODE_HOST) { return (ENXIO); } if (uaa->info.bConfigIndex != UPLCOM_CONFIG_INDEX) { diff --git a/sys/dev/usb/serial/usb_serial.c b/sys/dev/usb/serial/usb_serial.c index 6f5558acdfb5..23d61f240540 100644 --- a/sys/dev/usb/serial/usb_serial.c +++ b/sys/dev/usb/serial/usb_serial.c @@ -87,8 +87,8 @@ __FBSDID("$FreeBSD$"); #if USB_DEBUG static int usb2_com_debug = 0; -SYSCTL_NODE(_hw_usb2, OID_AUTO, ucom, CTLFLAG_RW, 0, "USB ucom"); -SYSCTL_INT(_hw_usb2_ucom, OID_AUTO, debug, CTLFLAG_RW, +SYSCTL_NODE(_hw_usb, OID_AUTO, ucom, CTLFLAG_RW, 0, "USB ucom"); +SYSCTL_INT(_hw_usb_ucom, OID_AUTO, debug, CTLFLAG_RW, &usb2_com_debug, 0, "ucom debug level"); #endif diff --git a/sys/dev/usb/serial/uslcom.c b/sys/dev/usb/serial/uslcom.c index 5df0abb0867c..f09a4706fa38 100644 --- a/sys/dev/usb/serial/uslcom.c +++ b/sys/dev/usb/serial/uslcom.c @@ -39,8 +39,8 @@ __FBSDID("$FreeBSD$"); #if USB_DEBUG static int uslcom_debug = 0; -SYSCTL_NODE(_hw_usb2, OID_AUTO, uslcom, CTLFLAG_RW, 0, "USB uslcom"); -SYSCTL_INT(_hw_usb2_uslcom, OID_AUTO, debug, CTLFLAG_RW, +SYSCTL_NODE(_hw_usb, OID_AUTO, uslcom, CTLFLAG_RW, 0, "USB uslcom"); +SYSCTL_INT(_hw_usb_uslcom, OID_AUTO, debug, CTLFLAG_RW, &uslcom_debug, 0, "Debug level"); #endif @@ -206,7 +206,7 @@ uslcom_probe(device_t dev) DPRINTFN(11, "\n"); - if (uaa->usb2_mode != USB_MODE_HOST) { + if (uaa->usb_mode != USB_MODE_HOST) { return (ENXIO); } if (uaa->info.bConfigIndex != USLCOM_CONFIG_INDEX) { diff --git a/sys/dev/usb/serial/uvisor.c b/sys/dev/usb/serial/uvisor.c index 54de2e29b8ee..efab25f23d7d 100644 --- a/sys/dev/usb/serial/uvisor.c +++ b/sys/dev/usb/serial/uvisor.c @@ -76,8 +76,8 @@ #if USB_DEBUG static int uvisor_debug = 0; -SYSCTL_NODE(_hw_usb2, OID_AUTO, uvisor, CTLFLAG_RW, 0, "USB uvisor"); -SYSCTL_INT(_hw_usb2_uvisor, OID_AUTO, debug, CTLFLAG_RW, +SYSCTL_NODE(_hw_usb, OID_AUTO, uvisor, CTLFLAG_RW, 0, "USB uvisor"); +SYSCTL_INT(_hw_usb_uvisor, OID_AUTO, debug, CTLFLAG_RW, &uvisor_debug, 0, "Debug level"); #endif @@ -273,7 +273,7 @@ uvisor_probe(device_t dev) { struct usb2_attach_arg *uaa = device_get_ivars(dev); - if (uaa->usb2_mode != USB_MODE_HOST) { + if (uaa->usb_mode != USB_MODE_HOST) { return (ENXIO); } if (uaa->info.bConfigIndex != UVISOR_CONFIG_INDEX) { diff --git a/sys/dev/usb/serial/uvscom.c b/sys/dev/usb/serial/uvscom.c index cfda9f8cca0a..a784ec47aabb 100644 --- a/sys/dev/usb/serial/uvscom.c +++ b/sys/dev/usb/serial/uvscom.c @@ -58,8 +58,8 @@ __FBSDID("$FreeBSD$"); #if USB_DEBUG static int uvscom_debug = 0; -SYSCTL_NODE(_hw_usb2, OID_AUTO, uvscom, CTLFLAG_RW, 0, "USB uvscom"); -SYSCTL_INT(_hw_usb2_uvscom, OID_AUTO, debug, CTLFLAG_RW, +SYSCTL_NODE(_hw_usb, OID_AUTO, uvscom, CTLFLAG_RW, 0, "USB uvscom"); +SYSCTL_INT(_hw_usb_uvscom, OID_AUTO, debug, CTLFLAG_RW, &uvscom_debug, 0, "Debug level"); #endif @@ -257,7 +257,7 @@ uvscom_probe(device_t dev) { struct usb2_attach_arg *uaa = device_get_ivars(dev); - if (uaa->usb2_mode != USB_MODE_HOST) { + if (uaa->usb_mode != USB_MODE_HOST) { return (ENXIO); } if (uaa->info.bConfigIndex != UVSCOM_CONFIG_INDEX) { diff --git a/sys/dev/usb/storage/umass.c b/sys/dev/usb/storage/umass.c index 2f2a163523fc..f66573b62a81 100644 --- a/sys/dev/usb/storage/umass.c +++ b/sys/dev/usb/storage/umass.c @@ -159,8 +159,8 @@ __FBSDID("$FreeBSD$"); #define UDMASS_ALL 0xffff0000 /* all of the above */ static int umass_debug = 0; -SYSCTL_NODE(_hw_usb2, OID_AUTO, umass, CTLFLAG_RW, 0, "USB umass"); -SYSCTL_INT(_hw_usb2_umass, OID_AUTO, debug, CTLFLAG_RW, +SYSCTL_NODE(_hw_usb, OID_AUTO, umass, CTLFLAG_RW, 0, "USB umass"); +SYSCTL_INT(_hw_usb_umass, OID_AUTO, debug, CTLFLAG_RW, &umass_debug, 0, "umass debug level"); #else #define DIF(...) do { } while (0) @@ -309,6 +309,7 @@ struct umass_devdescr { /* wire and command protocol */ uint16_t proto; +#define UMASS_PROTO_DEFAULT 0x0000 /* use protocol indicated by USB descriptors */ #define UMASS_PROTO_BBB 0x0001 /* USB wire protocol */ #define UMASS_PROTO_CBI 0x0002 #define UMASS_PROTO_CBI_I 0x0004 @@ -372,7 +373,7 @@ struct umass_devdescr { static const struct umass_devdescr umass_devdescr[] = { {USB_VENDOR_ASAHIOPTICAL, PID_WILDCARD, RID_WILDCARD, - UMASS_PROTO_ATAPI | UMASS_PROTO_CBI_I, + UMASS_PROTO_DEFAULT, RS_NO_CLEAR_UA }, {USB_VENDOR_ADDON, USB_PRODUCT_ADDON_ATTACHE, RID_WILDCARD, @@ -395,6 +396,10 @@ static const struct umass_devdescr umass_devdescr[] = { UMASS_PROTO_SCSI | UMASS_PROTO_BBB, NO_QUIRKS }, + {USB_VENDOR_ALCOR, USB_PRODUCT_ALCOR_AU6390, RID_WILDCARD, + UMASS_PROTO_DEFAULT, + NO_SYNCHRONIZE_CACHE + }, {USB_VENDOR_ALCOR, USB_PRODUCT_ALCOR_UMCR_9361, RID_WILDCARD, UMASS_PROTO_SCSI | UMASS_PROTO_BBB, NO_GETMAXLUN @@ -427,6 +432,10 @@ static const struct umass_devdescr umass_devdescr[] = { UMASS_PROTO_SCSI | UMASS_PROTO_BBB, FORCE_SHORT_INQUIRY | NO_START_STOP | IGNORE_RESIDUE }, + {USB_VENDOR_CYPRESS, USB_PRODUCT_CYPRESS_XX6830XX, RID_WILDCARD, + UMASS_PROTO_DEFAULT, + NO_GETMAXLUN | NO_SYNCHRONIZE_CACHE + }, {USB_VENDOR_DESKNOTE, USB_PRODUCT_DESKNOTE_UCR_61S2B, RID_WILDCARD, UMASS_PROTO_SCSI | UMASS_PROTO_BBB, NO_QUIRKS @@ -600,6 +609,10 @@ static const struct umass_devdescr umass_devdescr[] = { UMASS_PROTO_SCSI | UMASS_PROTO_BBB, FORCE_SHORT_INQUIRY | NO_INQUIRY_EVPD | NO_GETMAXLUN }, + {USB_VENDOR_MPMAN, PID_WILDCARD, RID_WILDCARD, + UMASS_PROTO_DEFAULT, + NO_SYNCHRONIZE_CACHE + }, {USB_VENDOR_MSYSTEMS, USB_PRODUCT_MSYSTEMS_DISKONKEY, RID_WILDCARD, UMASS_PROTO_SCSI | UMASS_PROTO_BBB, IGNORE_RESIDUE | NO_GETMAXLUN | RS_NO_CLEAR_UA @@ -609,11 +622,11 @@ static const struct umass_devdescr umass_devdescr[] = { NO_QUIRKS }, {USB_VENDOR_MYSON, USB_PRODUCT_MYSON_HEDEN, RID_WILDCARD, - UMASS_PROTO_SCSI | UMASS_PROTO_BBB, + UMASS_PROTO_DEFAULT, IGNORE_RESIDUE | NO_SYNCHRONIZE_CACHE }, {USB_VENDOR_MYSON, USB_PRODUCT_MYSON_STARREADER, RID_WILDCARD, - UMASS_PROTO_SCSI | UMASS_PROTO_BBB, + UMASS_PROTO_DEFAULT, NO_SYNCHRONIZE_CACHE }, {USB_VENDOR_NEODIO, USB_PRODUCT_NEODIO_ND3260, RID_WILDCARD, @@ -849,7 +862,7 @@ static const struct umass_devdescr umass_devdescr[] = { NO_QUIRKS }, {USB_VENDOR_SUPERTOP, USB_PRODUCT_SUPERTOP_IDE, RID_WILDCARD, - UMASS_PROTO_SCSI | UMASS_PROTO_BBB, + UMASS_PROTO_DEFAULT, IGNORE_RESIDUE | NO_SYNCHRONIZE_CACHE }, {USB_VENDOR_TAUGA, USB_PRODUCT_TAUGA_CAMERAMATE, RID_WILDCARD, @@ -1281,6 +1294,58 @@ MODULE_DEPEND(umass, cam, 1, 1, 1); * USB device probe/attach/detach */ +static uint16_t +umass_get_proto(struct usb2_interface *iface) +{ + struct usb2_interface_descriptor *id; + uint16_t retval; + + retval = 0; + + /* Check for a standards compliant device */ + id = usb2_get_interface_descriptor(iface); + if ((id == NULL) || + (id->bInterfaceClass != UICLASS_MASS)) { + goto done; + } + switch (id->bInterfaceSubClass) { + case UISUBCLASS_SCSI: + retval |= UMASS_PROTO_SCSI; + break; + case UISUBCLASS_UFI: + retval |= UMASS_PROTO_UFI; + break; + case UISUBCLASS_RBC: + retval |= UMASS_PROTO_RBC; + break; + case UISUBCLASS_SFF8020I: + case UISUBCLASS_SFF8070I: + retval |= UMASS_PROTO_ATAPI; + break; + default: + retval = 0; + goto done; + } + + switch (id->bInterfaceProtocol) { + case UIPROTO_MASS_CBI: + retval |= UMASS_PROTO_CBI; + break; + case UIPROTO_MASS_CBI_I: + retval |= UMASS_PROTO_CBI_I; + break; + case UIPROTO_MASS_BBB_OLD: + case UIPROTO_MASS_BBB: + retval |= UMASS_PROTO_BBB; + break; + default: + retval = 0; + goto done; + } +done: + return (retval); +} + /* * Match the device we are seeing with the * devices supported. @@ -1289,10 +1354,9 @@ static struct umass_probe_proto umass_probe_proto(device_t dev, struct usb2_attach_arg *uaa) { const struct umass_devdescr *udd = umass_devdescr; - struct usb2_interface_descriptor *id; struct umass_probe_proto ret; - bzero(&ret, sizeof(ret)); + memset(&ret, 0, sizeof(ret)); /* * An entry specifically for Y-E Data devices as they don't fit in @@ -1319,7 +1383,6 @@ umass_probe_proto(device_t dev, struct usb2_attach_arg *uaa) ret.quirks |= NO_TEST_UNIT_READY; } ret.quirks |= RS_NO_CLEAR_UA | FLOPPY_SPEED; - ret.error = 0; goto done; } /* @@ -1327,13 +1390,6 @@ umass_probe_proto(device_t dev, struct usb2_attach_arg *uaa) * check for wildcarded and fully matched. First match wins. */ for (; udd->vid != VID_EOT; udd++) { - if ((udd->vid == VID_WILDCARD) && - (udd->pid == PID_WILDCARD) && - (udd->rid == RID_WILDCARD)) { - device_printf(dev, "ignoring invalid " - "wildcard quirk\n"); - continue; - } if (((udd->vid == uaa->info.idVendor) || (udd->vid == VID_WILDCARD)) && ((udd->pid == uaa->info.idProduct) || @@ -1341,64 +1397,27 @@ umass_probe_proto(device_t dev, struct usb2_attach_arg *uaa) if (udd->rid == RID_WILDCARD) { ret.proto = udd->proto; ret.quirks = udd->quirks; - ret.error = 0; - goto done; + if (ret.proto == UMASS_PROTO_DEFAULT) + goto default_proto; + else + goto done; } else if (udd->rid == uaa->info.bcdDevice) { ret.proto = udd->proto; ret.quirks = udd->quirks; - ret.error = 0; - goto done; + if (ret.proto == UMASS_PROTO_DEFAULT) + goto default_proto; + else + goto done; } /* else RID does not match */ } } - /* Check for a standards compliant device */ - id = usb2_get_interface_descriptor(uaa->iface); - if ((id == NULL) || - (id->bInterfaceClass != UICLASS_MASS)) { - ret.error = ENXIO; - goto done; - } - switch (id->bInterfaceSubClass) { - case UISUBCLASS_SCSI: - ret.proto |= UMASS_PROTO_SCSI; - break; - case UISUBCLASS_UFI: - ret.proto |= UMASS_PROTO_UFI; - break; - case UISUBCLASS_RBC: - ret.proto |= UMASS_PROTO_RBC; - break; - case UISUBCLASS_SFF8020I: - case UISUBCLASS_SFF8070I: - ret.proto |= UMASS_PROTO_ATAPI; - break; - default: - device_printf(dev, "unsupported command " - "protocol %d\n", id->bInterfaceSubClass); - ret.error = ENXIO; - goto done; - } - - switch (id->bInterfaceProtocol) { - case UIPROTO_MASS_CBI: - ret.proto |= UMASS_PROTO_CBI; - break; - case UIPROTO_MASS_CBI_I: - ret.proto |= UMASS_PROTO_CBI_I; - break; - case UIPROTO_MASS_BBB_OLD: - case UIPROTO_MASS_BBB: - ret.proto |= UMASS_PROTO_BBB; - break; - default: - device_printf(dev, "unsupported wire " - "protocol %d\n", id->bInterfaceProtocol); +default_proto: + ret.proto = umass_get_proto(uaa->iface); + if (ret.proto == 0) ret.error = ENXIO; - goto done; - } - - ret.error = 0; + else + ret.error = 0; done: return (ret); } @@ -1409,7 +1428,7 @@ umass_probe(device_t dev) struct usb2_attach_arg *uaa = device_get_ivars(dev); struct umass_probe_proto temp; - if (uaa->usb2_mode != USB_MODE_HOST) { + if (uaa->usb_mode != USB_MODE_HOST) { return (ENXIO); } if (uaa->use_generic == 0) { diff --git a/sys/dev/usb/storage/urio.c b/sys/dev/usb/storage/urio.c index 0c27aa04d6cc..3064d223d906 100644 --- a/sys/dev/usb/storage/urio.c +++ b/sys/dev/usb/storage/urio.c @@ -67,8 +67,8 @@ __FBSDID("$FreeBSD$"); #if USB_DEBUG static int urio_debug = 0; -SYSCTL_NODE(_hw_usb2, OID_AUTO, urio, CTLFLAG_RW, 0, "USB urio"); -SYSCTL_INT(_hw_usb2_urio, OID_AUTO, debug, CTLFLAG_RW, +SYSCTL_NODE(_hw_usb, OID_AUTO, urio, CTLFLAG_RW, 0, "USB urio"); +SYSCTL_INT(_hw_usb_urio, OID_AUTO, debug, CTLFLAG_RW, &urio_debug, 0, "urio debug level"); #endif @@ -189,7 +189,7 @@ urio_probe(device_t dev) { struct usb2_attach_arg *uaa = device_get_ivars(dev); - if (uaa->usb2_mode != USB_MODE_HOST) { + if (uaa->usb_mode != USB_MODE_HOST) { return (ENXIO); } if ((((uaa->info.idVendor == USB_VENDOR_DIAMOND) && diff --git a/sys/dev/usb/storage/ustorage_fs.c b/sys/dev/usb/storage/ustorage_fs.c index c810c2e0f190..02a21aeda1df 100644 --- a/sys/dev/usb/storage/ustorage_fs.c +++ b/sys/dev/usb/storage/ustorage_fs.c @@ -52,8 +52,8 @@ #if USB_DEBUG static int ustorage_fs_debug = 0; -SYSCTL_NODE(_hw_usb2, OID_AUTO, ustorage_fs, CTLFLAG_RW, 0, "USB ustorage_fs"); -SYSCTL_INT(_hw_usb2_ustorage_fs, OID_AUTO, debug, CTLFLAG_RW, +SYSCTL_NODE(_hw_usb, OID_AUTO, ustorage_fs, CTLFLAG_RW, 0, "USB ustorage_fs"); +SYSCTL_INT(_hw_usb_ustorage_fs, OID_AUTO, debug, CTLFLAG_RW, &ustorage_fs_debug, 0, "ustorage_fs debug level"); #endif @@ -317,7 +317,7 @@ ustorage_fs_probe(device_t dev) struct usb2_attach_arg *uaa = device_get_ivars(dev); struct usb2_interface_descriptor *id; - if (uaa->usb2_mode != USB_MODE_DEVICE) { + if (uaa->usb_mode != USB_MODE_DEVICE) { return (ENXIO); } if (uaa->use_generic == 0) { @@ -466,7 +466,8 @@ ustorage_fs_handle_request(device_t dev, const struct usb2_device_request *req = preq; if (!is_complete) { - if (req->bRequest == UR_BBB_RESET) { + if ((req->bmRequestType == UT_WRITE_CLASS_INTERFACE) && + (req->bRequest == UR_BBB_RESET)) { *plen = 0; mtx_lock(&sc->sc_mtx); ustorage_fs_transfer_stop(sc); @@ -475,7 +476,8 @@ ustorage_fs_handle_request(device_t dev, USTORAGE_FS_T_BBB_COMMAND); mtx_unlock(&sc->sc_mtx); return (0); - } else if (req->bRequest == UR_BBB_GET_MAX_LUN) { + } else if ((req->bmRequestType == UT_READ_CLASS_INTERFACE) && + (req->bRequest == UR_BBB_GET_MAX_LUN)) { if (offset == 0) { *plen = 1; *pptr = &sc->sc_last_lun; diff --git a/sys/dev/usb/template/usb_template.c b/sys/dev/usb/template/usb_template.c index cc407965df2c..de704ffa1b36 100644 --- a/sys/dev/usb/template/usb_template.c +++ b/sys/dev/usb/template/usb_template.c @@ -167,7 +167,7 @@ usb2_make_endpoint_desc(struct usb2_temp_setup *temp, temp->err = USB_ERR_INVAL; return; } - mps = ted->pPacketSize->mps[temp->usb2_speed]; + mps = ted->pPacketSize->mps[temp->usb_speed]; if (mps == 0) { /* not initialized */ temp->err = USB_ERR_INVAL; @@ -194,9 +194,9 @@ usb2_make_endpoint_desc(struct usb2_temp_setup *temp, /* setup bInterval parameter */ if (ted->pIntervals && - ted->pIntervals->bInterval[temp->usb2_speed]) { + ted->pIntervals->bInterval[temp->usb_speed]) { ed->bInterval = - ted->pIntervals->bInterval[temp->usb2_speed]; + ted->pIntervals->bInterval[temp->usb_speed]; } else { switch (et) { case UE_BULK: @@ -204,7 +204,7 @@ usb2_make_endpoint_desc(struct usb2_temp_setup *temp, ed->bInterval = 0; /* not used */ break; case UE_INTERRUPT: - switch (temp->usb2_speed) { + switch (temp->usb_speed) { case USB_SPEED_LOW: case USB_SPEED_FULL: ed->bInterval = 1; /* 1 ms */ @@ -215,7 +215,7 @@ usb2_make_endpoint_desc(struct usb2_temp_setup *temp, } break; default: /* UE_ISOCHRONOUS */ - switch (temp->usb2_speed) { + switch (temp->usb_speed) { case USB_SPEED_LOW: case USB_SPEED_FULL: ed->bInterval = 1; /* 1 ms */ @@ -435,7 +435,7 @@ usb2_make_device_desc(struct usb2_temp_setup *temp, USETW(utd->udq.bcdUSB, 0x0200); utd->udq.bMaxPacketSize0 = 0; - switch (temp->usb2_speed) { + switch (temp->usb_speed) { case USB_SPEED_LOW: USETW(utd->udd.bcdUSB, 0x0110); utd->udd.bMaxPacketSize = 8; @@ -622,9 +622,9 @@ usb2_hw_ep_get_needs(struct usb2_hw_ep_scratch *ues, struct usb2_descriptor *desc; struct usb2_interface_descriptor *id; struct usb2_endpoint_descriptor *ed; + enum usb_dev_speed speed; uint16_t wMaxPacketSize; uint16_t temp; - uint8_t speed; uint8_t ep_no; ep_iface = ues->ep_max; @@ -1192,7 +1192,7 @@ usb2_temp_setup(struct usb2_device *udev, bzero(uts, sizeof(*uts)); - uts->usb2_speed = udev->speed; + uts->usb_speed = udev->speed; uts->self_powered = udev->flags.self_powered; /* first pass */ diff --git a/sys/dev/usb/usb_bus.h b/sys/dev/usb/usb_bus.h index e778c6c28ea9..66c2fac3934d 100644 --- a/sys/dev/usb/usb_bus.h +++ b/sys/dev/usb/usb_bus.h @@ -93,7 +93,7 @@ struct usb2_bus { uint8_t alloc_failed; /* Set if memory allocation failed. */ uint8_t driver_added_refcount; /* Current driver generation count */ - uint8_t usbrev; /* USB revision. See "USB_REV_XXX". */ + enum usb_revision usbrev; /* USB revision. See "USB_REV_XXX". */ uint8_t devices_max; /* maximum number of USB devices */ uint8_t do_probe; /* set if USB BUS should be re-probed */ diff --git a/sys/dev/usb/usb_busdma.c b/sys/dev/usb/usb_busdma.c index c8f30ed28b0b..5fb67c58b658 100644 --- a/sys/dev/usb/usb_busdma.c +++ b/sys/dev/usb/usb_busdma.c @@ -1279,7 +1279,7 @@ usb2_bdma_work_loop(struct usb2_xfer_queue *pq) if (xfer->flags_int.control_xfr && xfer->flags_int.control_hdr) { /* special case */ - if (xfer->flags_int.usb2_mode == USB_MODE_DEVICE) { + if (xfer->flags_int.usb_mode == USB_MODE_DEVICE) { /* The device controller writes to memory */ xfer->frbuffers[0].isread = 1; } else { diff --git a/sys/dev/usb/usb_compat_linux.c b/sys/dev/usb/usb_compat_linux.c index 85dba849659f..c7906c2be657 100644 --- a/sys/dev/usb/usb_compat_linux.c +++ b/sys/dev/usb/usb_compat_linux.c @@ -194,7 +194,7 @@ usb_linux_probe(device_t dev) struct usb_driver *udrv; int err = ENXIO; - if (uaa->usb2_mode != USB_MODE_HOST) { + if (uaa->usb_mode != USB_MODE_HOST) { return (ENXIO); } mtx_lock(&Giant); @@ -640,7 +640,7 @@ usb_control_msg(struct usb_device *dev, struct usb_host_endpoint *uhe, } return (err); } - if (dev->bsd_udev->flags.usb2_mode != USB_MODE_HOST) { + if (dev->bsd_udev->flags.usb_mode != USB_MODE_HOST) { /* not supported */ return (-EINVAL); } diff --git a/sys/dev/usb/usb_compat_linux.h b/sys/dev/usb/usb_compat_linux.h index c63d82e42daa..44db8e2b7c2b 100644 --- a/sys/dev/usb/usb_compat_linux.h +++ b/sys/dev/usb/usb_compat_linux.h @@ -370,7 +370,7 @@ struct usb_device { uint16_t devnum; - uint8_t speed; /* USB_SPEED_XXX */ + enum usb_dev_speed speed; /* USB_SPEED_XXX */ } __aligned(USB_HOST_ALIGN); /* diff --git a/sys/dev/usb/usb_controller.h b/sys/dev/usb/usb_controller.h index 70b65514b38a..48c20cbefce4 100644 --- a/sys/dev/usb/usb_controller.h +++ b/sys/dev/usb/usb_controller.h @@ -171,7 +171,7 @@ struct usb2_hw_ep_scratch { struct usb2_temp_setup { void *buf; usb2_size_t size; - uint8_t usb2_speed; + enum usb_dev_speed usb_speed; uint8_t self_powered; uint8_t bNumEndpoints; uint8_t bInterfaceNumber; diff --git a/sys/dev/usb/usb_core.h b/sys/dev/usb/usb_core.h index a9fc6bcf9a7c..5c4fde81d7c6 100644 --- a/sys/dev/usb/usb_core.h +++ b/sys/dev/usb/usb_core.h @@ -233,9 +233,9 @@ * The following macro will tell if an USB transfer is currently * receiving or transferring data. */ -#define USB_GET_DATA_ISREAD(xfer) (((xfer)->flags_int.usb2_mode == \ - USB_MODE_DEVICE) ? ((xfer->endpoint & UE_DIR_IN) ? 0 : 1) : \ - ((xfer->endpoint & UE_DIR_IN) ? 1 : 0)) +#define USB_GET_DATA_ISREAD(xfer) ((xfer)->flags_int.usb_mode == \ + USB_MODE_DEVICE ? (((xfer)->endpoint & UE_DIR_IN) ? 0 : 1) : \ + (((xfer)->endpoint & UE_DIR_IN) ? 1 : 0)) /* * The following macros are used used to convert milliseconds into @@ -354,6 +354,8 @@ struct usb2_xfer_flags { * flags. */ struct usb2_xfer_flags_int { + + enum usb_hc_mode usb_mode; /* shadow copy of "udev->usb_mode" */ uint16_t control_rem; /* remainder in bytes */ uint8_t open:1; /* set if USB pipe has been opened */ @@ -369,6 +371,7 @@ struct usb2_xfer_flags_int { uint8_t control_hdr:1; /* set if control header should be * sent */ uint8_t control_act:1; /* set if control transfer is active */ + uint8_t control_stall:1; /* set if control transfer should be stalled */ uint8_t short_frames_ok:1; /* filtered version */ uint8_t short_xfer_ok:1; /* filtered version */ @@ -381,7 +384,6 @@ struct usb2_xfer_flags_int { uint8_t bdma_setup:1; /* set if BUS-DMA has been setup */ #endif uint8_t isochronous_xfr:1; /* set if isochronous transfer */ - uint8_t usb2_mode:1; /* shadow copy of "udev->usb2_mode" */ uint8_t curr_dma_set:1; /* used by USB HC/DC driver */ uint8_t can_cancel_immed:1; /* set if USB transfer can be * cancelled immediately */ @@ -399,13 +401,12 @@ struct usb2_config { #define USB_DEFAULT_INTERVAL 0 usb2_timeout_t timeout; /* transfer timeout in milliseconds */ struct usb2_xfer_flags flags; /* transfer flags */ + enum usb_hc_mode usb_mode; /* host or device mode */ uint8_t type; /* pipe type */ uint8_t endpoint; /* pipe number */ uint8_t direction; /* pipe direction */ uint8_t ep_index; /* pipe index match to use */ uint8_t if_index; /* "ifaces" index to use */ - uint8_t usb_mode; /* see "USB_MODE_XXX", - * "USB_MODE_MAX" means any mode! */ }; /* @@ -495,7 +496,7 @@ struct usb2_attach_arg { const void *driver_info; /* for internal use */ struct usb2_device *device; /* current device */ struct usb2_interface *iface; /* current interface */ - uint8_t usb2_mode; /* see USB_MODE_XXX */ + enum usb_hc_mode usb_mode; /* host or device mode */ uint8_t port; uint8_t use_generic; /* hint for generic drivers */ }; @@ -515,7 +516,7 @@ typedef struct malloc_type *usb2_malloc_type; /* prototypes */ const char *usb2_errstr(usb2_error_t error); -const char *usb2_statestr(enum usb2_dev_state state); +const char *usb2_statestr(enum usb_dev_state state); struct usb2_config_descriptor *usb2_get_config_descriptor( struct usb2_device *udev); struct usb2_device_descriptor *usb2_get_device_descriptor( @@ -529,8 +530,8 @@ uint8_t usb2_clear_stall_callback(struct usb2_xfer *xfer1, uint8_t usb2_get_interface_altindex(struct usb2_interface *iface); usb2_error_t usb2_set_alt_interface_index(struct usb2_device *udev, uint8_t iface_index, uint8_t alt_index); -uint8_t usb2_get_mode(struct usb2_device *udev); -uint8_t usb2_get_speed(struct usb2_device *udev); +enum usb_hc_mode usb2_get_mode(struct usb2_device *udev); +enum usb_dev_speed usb2_get_speed(struct usb2_device *udev); uint32_t usb2_get_isoc_fps(struct usb2_device *udev); usb2_error_t usb2_transfer_setup(struct usb2_device *udev, const uint8_t *ifaces, struct usb2_xfer **pxfer, diff --git a/sys/dev/usb/usb_debug.c b/sys/dev/usb/usb_debug.c index da317fe4b791..de75f8933500 100644 --- a/sys/dev/usb/usb_debug.c +++ b/sys/dev/usb/usb_debug.c @@ -39,8 +39,8 @@ */ int usb2_debug = 0; -SYSCTL_NODE(_hw, OID_AUTO, usb2, CTLFLAG_RW, 0, "USB debugging"); -SYSCTL_INT(_hw_usb2, OID_AUTO, debug, CTLFLAG_RW, +SYSCTL_NODE(_hw, OID_AUTO, usb, CTLFLAG_RW, 0, "USB debugging"); +SYSCTL_INT(_hw_usb, OID_AUTO, debug, CTLFLAG_RW, &usb2_debug, 0, "Debug level"); /*------------------------------------------------------------------------* diff --git a/sys/dev/usb/usb_debug.h b/sys/dev/usb/usb_debug.h index 3d1f87220c0b..9ddd597ed2b0 100644 --- a/sys/dev/usb/usb_debug.h +++ b/sys/dev/usb/usb_debug.h @@ -30,7 +30,7 @@ #define _USB2_DEBUG_H_ /* Declare parent SYSCTL USB node. */ -SYSCTL_DECL(_hw_usb2); +SYSCTL_DECL(_hw_usb); /* Declare global USB debug variable. */ extern int usb2_debug; diff --git a/sys/dev/usb/usb_dev.c b/sys/dev/usb/usb_dev.c index d9d81e0800d0..e20c31e7064c 100644 --- a/sys/dev/usb/usb_dev.c +++ b/sys/dev/usb/usb_dev.c @@ -59,8 +59,8 @@ #if USB_DEBUG static int usb2_fifo_debug = 0; -SYSCTL_NODE(_hw_usb2, OID_AUTO, dev, CTLFLAG_RW, 0, "USB device"); -SYSCTL_INT(_hw_usb2_dev, OID_AUTO, debug, CTLFLAG_RW, +SYSCTL_NODE(_hw_usb, OID_AUTO, dev, CTLFLAG_RW, 0, "USB device"); +SYSCTL_INT(_hw_usb_dev, OID_AUTO, debug, CTLFLAG_RW, &usb2_fifo_debug, 0, "Debug Level"); #endif @@ -597,13 +597,13 @@ usb2_dev_get_pipe(struct usb2_device *udev, uint8_t ep_index, uint8_t dir) pipe = &udev->default_pipe; } else { if (dir == USB_FIFO_RX) { - if (udev->flags.usb2_mode == USB_MODE_HOST) { + if (udev->flags.usb_mode == USB_MODE_HOST) { ep_dir = UE_DIR_IN; } else { ep_dir = UE_DIR_OUT; } } else { - if (udev->flags.usb2_mode == USB_MODE_HOST) { + if (udev->flags.usb_mode == USB_MODE_HOST) { ep_dir = UE_DIR_OUT; } else { ep_dir = UE_DIR_IN; @@ -1203,7 +1203,7 @@ usb2_read(struct cdev *dev, struct uio *uio, int ioflag) (f->methods->f_start_read) (f); - if (fflags & IO_NDELAY) { + if (ioflag & IO_NDELAY) { if (tr_data) { /* return length before error */ break; @@ -1326,7 +1326,7 @@ usb2_write(struct cdev *dev, struct uio *uio, int ioflag) if (m == NULL) { - if (fflags & IO_NDELAY) { + if (ioflag & IO_NDELAY) { if (tr_data) { /* return length before error */ break; diff --git a/sys/dev/usb/usb_device.c b/sys/dev/usb/usb_device.c index 2463c1f2dba9..c1dde2334b25 100644 --- a/sys/dev/usb/usb_device.c +++ b/sys/dev/usb/usb_device.c @@ -87,7 +87,7 @@ static void usb2_cdev_cleanup(void *); int usb2_template = 0; -SYSCTL_INT(_hw_usb2, OID_AUTO, template, CTLFLAG_RW, +SYSCTL_INT(_hw_usb, OID_AUTO, template, CTLFLAG_RW, &usb2_template, 0, "Selected USB device side template"); static const char* statestr[USB_STATE_MAX] = { @@ -99,7 +99,7 @@ static const char* statestr[USB_STATE_MAX] = { }; const char * -usb2_statestr(enum usb2_dev_state state) +usb2_statestr(enum usb_dev_state state) { return ((state < USB_STATE_MAX) ? statestr[state] : "UNKNOWN"); } @@ -187,8 +187,8 @@ usb2_get_pipe(struct usb2_device *udev, uint8_t iface_index, /* check USB mode */ - if ((setup->usb_mode != USB_MODE_MAX) && - (udev->flags.usb2_mode != setup->usb_mode)) { + if (setup->usb_mode != USB_MODE_DUAL && + udev->flags.usb_mode != setup->usb_mode) { /* wrong mode - no pipe */ return (NULL); } @@ -197,11 +197,11 @@ usb2_get_pipe(struct usb2_device *udev, uint8_t iface_index, if (setup->direction == UE_DIR_RX) { ea_mask = (UE_DIR_IN | UE_DIR_OUT); - ea_val = (udev->flags.usb2_mode == USB_MODE_DEVICE) ? + ea_val = (udev->flags.usb_mode == USB_MODE_DEVICE) ? UE_DIR_OUT : UE_DIR_IN; } else if (setup->direction == UE_DIR_TX) { ea_mask = (UE_DIR_IN | UE_DIR_OUT); - ea_val = (udev->flags.usb2_mode == USB_MODE_DEVICE) ? + ea_val = (udev->flags.usb_mode == USB_MODE_DEVICE) ? UE_DIR_IN : UE_DIR_OUT; } else if (setup->direction == UE_DIR_ANY) { /* match any endpoint direction */ @@ -416,7 +416,7 @@ usb2_unconfigure(struct usb2_device *udev, uint8_t flag) /* free "cdesc" after "ifaces" and "pipes", if any */ if (udev->cdesc != NULL) { - if (udev->flags.usb2_mode != USB_MODE_DEVICE) + if (udev->flags.usb_mode != USB_MODE_DEVICE) free(udev->cdesc, M_USB); udev->cdesc = NULL; } @@ -475,7 +475,7 @@ usb2_set_config_index(struct usb2_device *udev, uint8_t index) goto done; } /* get the full config descriptor */ - if (udev->flags.usb2_mode == USB_MODE_DEVICE) { + if (udev->flags.usb_mode == USB_MODE_DEVICE) { /* save some memory */ err = usb2_req_get_descriptor_ptr(udev, &cdp, (UDESC_CONFIG << 8) | index); @@ -495,7 +495,7 @@ usb2_set_config_index(struct usb2_device *udev, uint8_t index) selfpowered = 0; if ((!udev->flags.uq_bus_powered) && (cdp->bmAttributes & UC_SELF_POWERED) && - (udev->flags.usb2_mode == USB_MODE_HOST)) { + (udev->flags.usb_mode == USB_MODE_HOST)) { /* May be self powered. */ if (cdp->bmAttributes & UC_BUS_POWERED) { /* Must ask device. */ @@ -533,7 +533,7 @@ usb2_set_config_index(struct usb2_device *udev, uint8_t index) goto done; } /* Only update "self_powered" in USB Host Mode */ - if (udev->flags.usb2_mode == USB_MODE_HOST) { + if (udev->flags.usb_mode == USB_MODE_HOST) { udev->flags.self_powered = selfpowered; } udev->power = power; @@ -815,7 +815,7 @@ usb2_set_alt_interface_index(struct usb2_device *udev, err = USB_ERR_INVAL; goto done; } - if (udev->flags.usb2_mode == USB_MODE_DEVICE) { + if (udev->flags.usb_mode == USB_MODE_DEVICE) { usb2_detach_device(udev, iface_index, USB_UNCFG_FLAG_FREE_SUBDEV); } else { @@ -1178,7 +1178,7 @@ usb2_init_attach_arg(struct usb2_device *udev, bzero(uaa, sizeof(*uaa)); uaa->device = udev; - uaa->usb2_mode = udev->flags.usb2_mode; + uaa->usb_mode = udev->flags.usb_mode; uaa->port = udev->port_no; uaa->info.idVendor = UGETW(udev->ddesc.idVendor); @@ -1416,8 +1416,8 @@ usb2_clear_stall_proc(struct usb2_proc_msg *_pm) *------------------------------------------------------------------------*/ struct usb2_device * usb2_alloc_device(device_t parent_dev, struct usb2_bus *bus, - struct usb2_device *parent_hub, uint8_t depth, - uint8_t port_index, uint8_t port_no, uint8_t speed, uint8_t usb2_mode) + struct usb2_device *parent_hub, uint8_t depth, uint8_t port_index, + uint8_t port_no, enum usb_dev_speed speed, enum usb_hc_mode mode) { struct usb2_attach_arg uaa; struct usb2_device *udev; @@ -1429,9 +1429,9 @@ usb2_alloc_device(device_t parent_dev, struct usb2_bus *bus, uint8_t device_index; DPRINTF("parent_dev=%p, bus=%p, parent_hub=%p, depth=%u, " - "port_index=%u, port_no=%u, speed=%u, usb2_mode=%u\n", + "port_index=%u, port_no=%u, speed=%u, usb_mode=%u\n", parent_dev, bus, parent_hub, depth, port_index, port_no, - speed, usb2_mode); + speed, mode); /* * Find an unused device index. In USB Host mode this is the @@ -1509,7 +1509,7 @@ usb2_alloc_device(device_t parent_dev, struct usb2_bus *bus, udev->ddesc.bMaxPacketSize = USB_MAX_IPACKET; udev->speed = speed; - udev->flags.usb2_mode = usb2_mode; + udev->flags.usb_mode = mode; /* search for our High Speed USB HUB, if any */ @@ -1548,7 +1548,7 @@ usb2_alloc_device(device_t parent_dev, struct usb2_bus *bus, /* Create a link from /dev/ugenX.X to the default endpoint */ make_dev_alias(udev->default_dev, udev->ugen_name); #endif - if (udev->flags.usb2_mode == USB_MODE_HOST) { + if (udev->flags.usb_mode == USB_MODE_HOST) { err = usb2_req_set_address(udev, NULL, device_index); @@ -1703,7 +1703,7 @@ usb2_alloc_device(device_t parent_dev, struct usb2_bus *bus, usb2_check_strings(udev); #endif - if (udev->flags.usb2_mode == USB_MODE_HOST) { + if (udev->flags.usb_mode == USB_MODE_HOST) { uint8_t config_index; uint8_t config_quirk; uint8_t set_config_failed = 0; @@ -1981,7 +1981,7 @@ usb2_free_device(struct usb2_device *udev, uint8_t flag) udev->default_dev->si_drv1); #endif - if (udev->flags.usb2_mode == USB_MODE_DEVICE) { + if (udev->flags.usb_mode == USB_MODE_DEVICE) { /* stop receiving any control transfers (Device Side Mode) */ usb2_transfer_unsetup(udev->default_xfer, USB_DEFAULT_XFER_MAX); } @@ -2239,17 +2239,17 @@ usb2_check_strings(struct usb2_device *udev) * Returns: * See: USB_MODE_XXX */ -uint8_t +enum usb_hc_mode usb2_get_mode(struct usb2_device *udev) { - return (udev->flags.usb2_mode); + return (udev->flags.usb_mode); } /* * Returns: * See: USB_SPEED_XXX */ -uint8_t +enum usb_dev_speed usb2_get_speed(struct usb2_device *udev) { return (udev->speed); @@ -2452,14 +2452,14 @@ usb2_peer_can_wakeup(struct usb2_device *udev) const struct usb2_config_descriptor *cdp; cdp = udev->cdesc; - if ((cdp != NULL) && (udev->flags.usb2_mode == USB_MODE_HOST)) { + if ((cdp != NULL) && (udev->flags.usb_mode == USB_MODE_HOST)) { return (cdp->bmAttributes & UC_REMOTE_WAKEUP); } return (0); /* not supported */ } void -usb2_set_device_state(struct usb2_device *udev, enum usb2_dev_state state) +usb2_set_device_state(struct usb2_device *udev, enum usb_dev_state state) { KASSERT(state < USB_STATE_MAX, ("invalid udev state")); diff --git a/sys/dev/usb/usb_device.h b/sys/dev/usb/usb_device.h index 4aa385f59eea..d262d3e51344 100644 --- a/sys/dev/usb/usb_device.h +++ b/sys/dev/usb/usb_device.h @@ -83,7 +83,7 @@ struct usb2_interface { * The following structure defines the USB device flags. */ struct usb2_device_flags { - uint8_t usb2_mode:1; /* USB mode (see USB_MODE_XXX) */ + enum usb_hc_mode usb_mode; /* host or device mode */ uint8_t self_powered:1; /* set if USB device is self powered */ uint8_t no_strings:1; /* set if USB device does not support * strings */ @@ -145,7 +145,8 @@ struct usb2_device { #endif usb2_ticks_t plugtime; /* copy of "ticks" */ - enum usb2_dev_state state; + enum usb_dev_state state; + enum usb_dev_speed speed; uint16_t refcount; #define USB_DEV_REF_MAX 0xffff @@ -157,7 +158,6 @@ struct usb2_device { uint8_t curr_config_index; /* current configuration index */ uint8_t curr_config_no; /* current configuration number */ uint8_t depth; /* distance from root HUB */ - uint8_t speed; /* low/full/high speed */ uint8_t port_index; /* parent HUB port index */ uint8_t port_no; /* parent HUB port number */ uint8_t hs_hub_addr; /* high-speed HUB address */ @@ -189,8 +189,8 @@ extern int usb2_template; struct usb2_device *usb2_alloc_device(device_t parent_dev, struct usb2_bus *bus, struct usb2_device *parent_hub, uint8_t depth, - uint8_t port_index, uint8_t port_no, uint8_t speed, - uint8_t usb2_mode); + uint8_t port_index, uint8_t port_no, + enum usb_dev_speed speed, enum usb_hc_mode mode); struct usb2_pipe *usb2_get_pipe(struct usb2_device *udev, uint8_t iface_index, const struct usb2_config *setup); struct usb2_pipe *usb2_get_pipe_by_addr(struct usb2_device *udev, uint8_t ea_val); @@ -213,6 +213,6 @@ void usb_linux_free_device(struct usb_device *dev); uint8_t usb2_peer_can_wakeup(struct usb2_device *udev); struct usb2_pipe *usb2_pipe_foreach(struct usb2_device *udev, struct usb2_pipe *pipe); void usb2_set_device_state(struct usb2_device *udev, - enum usb2_dev_state state); + enum usb_dev_state state); #endif /* _USB2_DEVICE_H_ */ diff --git a/sys/dev/usb/usb_generic.c b/sys/dev/usb/usb_generic.c index d7d73b88d693..02aba15b222c 100644 --- a/sys/dev/usb/usb_generic.c +++ b/sys/dev/usb/usb_generic.c @@ -105,8 +105,8 @@ struct usb2_fifo_methods usb2_ugen_methods = { #if USB_DEBUG static int ugen_debug = 0; -SYSCTL_NODE(_hw_usb2, OID_AUTO, ugen, CTLFLAG_RW, 0, "USB generic"); -SYSCTL_INT(_hw_usb2_ugen, OID_AUTO, debug, CTLFLAG_RW, &ugen_debug, +SYSCTL_NODE(_hw_usb, OID_AUTO, ugen, CTLFLAG_RW, 0, "USB generic"); +SYSCTL_INT(_hw_usb_ugen, OID_AUTO, debug, CTLFLAG_RW, &ugen_debug, 0, "Debug level"); #endif @@ -233,7 +233,7 @@ ugen_open_pipe_write(struct usb2_fifo *f) usb2_config[0].direction = UE_DIR_TX; usb2_config[0].interval = USB_DEFAULT_INTERVAL; usb2_config[0].flags.proxy_buffer = 1; - usb2_config[0].usb_mode = USB_MODE_MAX; /* both modes */ + usb2_config[0].usb_mode = USB_MODE_DUAL; /* both modes */ switch (ed->bmAttributes & UE_XFERTYPE) { case UE_INTERRUPT: @@ -301,7 +301,7 @@ ugen_open_pipe_read(struct usb2_fifo *f) usb2_config[0].direction = UE_DIR_RX; usb2_config[0].interval = USB_DEFAULT_INTERVAL; usb2_config[0].flags.proxy_buffer = 1; - usb2_config[0].usb_mode = USB_MODE_MAX; /* both modes */ + usb2_config[0].usb_mode = USB_MODE_DUAL; /* both modes */ switch (ed->bmAttributes & UE_XFERTYPE) { case UE_INTERRUPT: @@ -584,7 +584,7 @@ ugen_set_config(struct usb2_fifo *f, uint8_t index) { DPRINTFN(2, "index %u\n", index); - if (f->udev->flags.usb2_mode != USB_MODE_HOST) { + if (f->udev->flags.usb_mode != USB_MODE_HOST) { /* not possible in device side mode */ return (ENOTTY); } @@ -615,7 +615,7 @@ ugen_set_interface(struct usb2_fifo *f, { DPRINTFN(2, "%u, %u\n", iface_index, alt_index); - if (f->udev->flags.usb2_mode != USB_MODE_HOST) { + if (f->udev->flags.usb_mode != USB_MODE_HOST) { /* not possible in device side mode */ return (ENOTTY); } @@ -821,7 +821,7 @@ usb2_gen_fill_deviceinfo(struct usb2_fifo *f, struct usb2_device_info *di) di->udi_config_index = udev->curr_config_index; di->udi_power = udev->flags.self_powered ? 0 : udev->power; di->udi_speed = udev->speed; - di->udi_mode = udev->flags.usb2_mode; + di->udi_mode = udev->flags.usb_mode; di->udi_power_mode = udev->power_mode; di->udi_suspended = udev->flags.peer_suspended; @@ -1465,10 +1465,10 @@ ugen_ioctl(struct usb2_fifo *f, u_long cmd, void *addr, int fflags) usb2_config[0].timeout = 0; /* no timeout */ usb2_config[0].frames = u.popen->max_frames; usb2_config[0].bufsize = u.popen->max_bufsize; - usb2_config[0].usb_mode = USB_MODE_MAX; /* both modes */ + usb2_config[0].usb_mode = USB_MODE_DUAL; /* both modes */ if (usb2_config[0].type == UE_CONTROL) { - if (f->udev->flags.usb2_mode != USB_MODE_HOST) { + if (f->udev->flags.usb_mode != USB_MODE_HOST) { error = EINVAL; break; } @@ -1477,7 +1477,7 @@ ugen_ioctl(struct usb2_fifo *f, u_long cmd, void *addr, int fflags) isread = ((usb2_config[0].endpoint & (UE_DIR_IN | UE_DIR_OUT)) == UE_DIR_IN); - if (f->udev->flags.usb2_mode != USB_MODE_HOST) { + if (f->udev->flags.usb_mode != USB_MODE_HOST) { isread = !isread; } /* check permissions */ @@ -1530,7 +1530,7 @@ ugen_ioctl(struct usb2_fifo *f, u_long cmd, void *addr, int fflags) error = EINVAL; break; } - if (f->udev->flags.usb2_mode != USB_MODE_HOST) { + if (f->udev->flags.usb_mode != USB_MODE_HOST) { error = EINVAL; break; } diff --git a/sys/dev/usb/usb_hid.c b/sys/dev/usb/usb_hid.c index 555d324ded43..52efa6777908 100644 --- a/sys/dev/usb/usb_hid.c +++ b/sys/dev/usb/usb_hid.c @@ -296,9 +296,6 @@ hid_get_item(struct hid_data *s, struct hid_item *h) } else { s->ncount = 1; } - /* set default usage */ - /* use the undefined HID PAGE */ - s->usage_last = 0; goto top; case 9: /* Output */ @@ -309,6 +306,7 @@ hid_get_item(struct hid_data *s, struct hid_item *h) c->kind = hid_collection; c->collection = dval; c->collevel++; + c->usage = s->usage_last; *h = *c; return (1); case 11: /* Feature */ @@ -408,6 +406,9 @@ hid_get_item(struct hid_data *s, struct hid_item *h) if (bSize != 4) dval = (dval & mask) | c->_usage_page; + /* set last usage, in case of a collection */ + s->usage_last = dval; + if (s->nusage < MAXUSAGE) { s->usages_min[s->nusage] = dval; s->usages_max[s->nusage] = dval; @@ -630,9 +631,11 @@ hid_is_collection(const void *desc, usb2_size_t size, uint32_t usage) if (hd == NULL) return (0); - err = hid_get_item(hd, &hi) && - hi.kind == hid_collection && - hi.usage == usage; + while ((err = hid_get_item(hd, &hi))) { + if (hi.kind == hid_collection && + hi.usage == usage) + break; + } hid_end_parse(hd); return (err); } diff --git a/sys/dev/usb/usb_hub.c b/sys/dev/usb/usb_hub.c index f92072bacc8e..31d84a4be432 100644 --- a/sys/dev/usb/usb_hub.c +++ b/sys/dev/usb/usb_hub.c @@ -57,15 +57,15 @@ #if USB_DEBUG static int uhub_debug = 0; -SYSCTL_NODE(_hw_usb2, OID_AUTO, uhub, CTLFLAG_RW, 0, "USB HUB"); -SYSCTL_INT(_hw_usb2_uhub, OID_AUTO, debug, CTLFLAG_RW, &uhub_debug, 0, +SYSCTL_NODE(_hw_usb, OID_AUTO, uhub, CTLFLAG_RW, 0, "USB HUB"); +SYSCTL_INT(_hw_usb_uhub, OID_AUTO, debug, CTLFLAG_RW, &uhub_debug, 0, "Debug level"); #endif #if USB_HAVE_POWERD static int usb2_power_timeout = 30; /* seconds */ -SYSCTL_INT(_hw_usb2, OID_AUTO, power_timeout, CTLFLAG_RW, +SYSCTL_INT(_hw_usb, OID_AUTO, power_timeout, CTLFLAG_RW, &usb2_power_timeout, 0, "USB power timeout"); #endif @@ -223,7 +223,7 @@ uhub_explore_sub(struct uhub_softc *sc, struct usb2_port *up) } /* start control transfer, if device mode */ - if (child->flags.usb2_mode == USB_MODE_DEVICE) { + if (child->flags.usb_mode == USB_MODE_DEVICE) { usb2_default_transfer_setup(child); } /* if a HUB becomes present, do a recursive HUB explore */ @@ -273,10 +273,10 @@ uhub_reattach_port(struct uhub_softc *sc, uint8_t portno) { struct usb2_device *child; struct usb2_device *udev; + enum usb_dev_speed speed; + enum usb_hc_mode mode; usb2_error_t err; uint8_t timeout; - uint8_t speed; - uint8_t usb2_mode; DPRINTF("reattaching port %d\n", portno); @@ -404,14 +404,14 @@ repeat: * NOTE: This part is currently FreeBSD specific. */ if (sc->sc_st.port_status & UPS_PORT_MODE_DEVICE) - usb2_mode = USB_MODE_DEVICE; + mode = USB_MODE_DEVICE; else - usb2_mode = USB_MODE_HOST; + mode = USB_MODE_HOST; /* need to create a new child */ child = usb2_alloc_device(sc->sc_dev, udev->bus, udev, - udev->depth + 1, portno - 1, portno, speed, usb2_mode); + udev->depth + 1, portno - 1, portno, speed, mode); if (child == NULL) { DPRINTFN(0, "could not allocate new device!\n"); goto error; @@ -495,7 +495,7 @@ uhub_suspend_resume_port(struct uhub_softc *sc, uint8_t portno) */ if (is_suspend == 0) usb2_dev_resume_peer(child); - else if (child->flags.usb2_mode == USB_MODE_DEVICE) + else if (child->flags.usb_mode == USB_MODE_DEVICE) usb2_dev_suspend_peer(child); } done: @@ -638,7 +638,7 @@ uhub_probe(device_t dev) { struct usb2_attach_arg *uaa = device_get_ivars(dev); - if (uaa->usb2_mode != USB_MODE_HOST) { + if (uaa->usb_mode != USB_MODE_HOST) { return (ENXIO); } /* @@ -1098,7 +1098,7 @@ 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; + enum usb_dev_speed speed; USB_BUS_LOCK_ASSERT(bus, MA_OWNED); @@ -1505,7 +1505,7 @@ usb2_transfer_power_ref(struct usb2_xfer *xfer, int val) if (xfer->flags_int.control_xfr) { udev->pwr_save.read_refs += val; - if (xfer->flags_int.usb2_mode == USB_MODE_HOST) { + if (xfer->flags_int.usb_mode == USB_MODE_HOST) { /* * it is not allowed to suspend during a control * transfer @@ -1706,7 +1706,7 @@ usb2_dev_resume_peer(struct usb2_device *udev) DPRINTF("udev=%p\n", udev); - if ((udev->flags.usb2_mode == USB_MODE_DEVICE) && + if ((udev->flags.usb_mode == USB_MODE_DEVICE) && (udev->flags.remote_wakeup == 0)) { /* * If the host did not set the remote wakeup feature, we can diff --git a/sys/dev/usb/usb_hub.h b/sys/dev/usb/usb_hub.h index 0c8905d6de97..74df2b959202 100644 --- a/sys/dev/usb/usb_hub.h +++ b/sys/dev/usb/usb_hub.h @@ -34,8 +34,7 @@ struct usb2_port { uint8_t restartcnt; #define USB_RESTART_MAX 5 uint8_t device_index; /* zero means not valid */ - uint8_t usb2_mode:1; /* current USB mode */ - uint8_t unused:7; + enum usb_hc_mode usb_mode; /* host or device mode */ }; /* diff --git a/sys/dev/usb/usb_process.c b/sys/dev/usb/usb_process.c index 5ec46d1328a1..86882d2d0125 100644 --- a/sys/dev/usb/usb_process.c +++ b/sys/dev/usb/usb_process.c @@ -55,8 +55,8 @@ #if USB_DEBUG static int usb2_proc_debug; -SYSCTL_NODE(_hw_usb2, OID_AUTO, proc, CTLFLAG_RW, 0, "USB process"); -SYSCTL_INT(_hw_usb2_proc, OID_AUTO, debug, CTLFLAG_RW, &usb2_proc_debug, 0, +SYSCTL_NODE(_hw_usb, OID_AUTO, proc, CTLFLAG_RW, 0, "USB process"); +SYSCTL_INT(_hw_usb_proc, OID_AUTO, debug, CTLFLAG_RW, &usb2_proc_debug, 0, "Debug level"); #endif diff --git a/sys/dev/usb/usb_request.c b/sys/dev/usb/usb_request.c index 8b18bbc5cb5c..6eeb59dd3349 100644 --- a/sys/dev/usb/usb_request.c +++ b/sys/dev/usb/usb_request.c @@ -53,11 +53,11 @@ static int usb2_pr_poll_delay = USB_PORT_RESET_DELAY; static int usb2_pr_recovery_delay = USB_PORT_RESET_RECOVERY; static int usb2_ss_delay = 0; -SYSCTL_INT(_hw_usb2, OID_AUTO, pr_poll_delay, CTLFLAG_RW, +SYSCTL_INT(_hw_usb, OID_AUTO, pr_poll_delay, CTLFLAG_RW, &usb2_pr_poll_delay, 0, "USB port reset poll delay in ms"); -SYSCTL_INT(_hw_usb2, OID_AUTO, pr_recovery_delay, CTLFLAG_RW, +SYSCTL_INT(_hw_usb, OID_AUTO, pr_recovery_delay, CTLFLAG_RW, &usb2_pr_recovery_delay, 0, "USB port reset recovery delay in ms"); -SYSCTL_INT(_hw_usb2, OID_AUTO, ss_delay, CTLFLAG_RW, +SYSCTL_INT(_hw_usb, OID_AUTO, ss_delay, CTLFLAG_RW, &usb2_ss_delay, 0, "USB status stage delay in ms"); #endif @@ -176,7 +176,7 @@ static usb2_handle_request_t * usb2_get_hr_func(struct usb2_device *udev) { /* figure out if there is a Handle Request function */ - if (udev->flags.usb2_mode == USB_MODE_DEVICE) + if (udev->flags.usb_mode == USB_MODE_DEVICE) return (usb2_temp_get_desc_p); else if (udev->parent_hub == NULL) return (udev->bus->methods->roothub_exec); @@ -1485,7 +1485,7 @@ usb2_req_re_enumerate(struct usb2_device *udev, struct mtx *mtx) uint8_t old_addr; uint8_t do_retry = 1; - if (udev->flags.usb2_mode != USB_MODE_HOST) { + if (udev->flags.usb_mode != USB_MODE_HOST) { return (USB_ERR_INVAL); } old_addr = udev->address; diff --git a/sys/dev/usb/usb_revision.h b/sys/dev/usb/usb_revision.h index 18b2d67020f6..d367e6c4f42e 100644 --- a/sys/dev/usb/usb_revision.h +++ b/sys/dev/usb/usb_revision.h @@ -30,47 +30,48 @@ /* * The "USB_SPEED" macros defines all the supported USB speeds. */ -enum usb2_speed { +enum usb_dev_speed { USB_SPEED_VARIABLE, USB_SPEED_LOW, USB_SPEED_FULL, USB_SPEED_HIGH, USB_SPEED_SUPER, - USB_SPEED_MAX }; +#define USB_SPEED_MAX (USB_SPEED_SUPER+1) /* * The "USB_REV" macros defines all the supported USB revisions. */ -enum usb2_revision { +enum usb_revision { USB_REV_UNKNOWN, USB_REV_PRE_1_0, USB_REV_1_0, USB_REV_1_1, USB_REV_2_0, USB_REV_2_5, - USB_REV_3_0, - USB_REV_MAX + USB_REV_3_0 }; +#define USB_REV_MAX (USB_REV_3_0+1) /* - * The "USB_MODE" macros defines all the supported USB modes. + * Supported host contoller modes. */ -enum usb2_mode { - USB_MODE_HOST, - USB_MODE_DEVICE, - USB_MODE_MAX +enum usb_hc_mode { + USB_MODE_HOST, /* initiates transfers */ + USB_MODE_DEVICE, /* bus transfer target */ + USB_MODE_DUAL /* can be host or device */ }; +#define USB_MODE_MAX (USB_MODE_DUAL+1) /* * The "USB_MODE" macros defines all the supported device states. */ -enum usb2_dev_state { +enum usb_dev_state { USB_STATE_DETACHED, USB_STATE_ATTACHED, USB_STATE_POWERED, USB_STATE_ADDRESSED, USB_STATE_CONFIGURED, - USB_STATE_MAX, }; +#define USB_STATE_MAX (USB_STATE_CONFIGURED+1) #endif /* _USB2_REVISION_H_ */ diff --git a/sys/dev/usb/usb_transfer.c b/sys/dev/usb/usb_transfer.c index b0aba0f6c2f8..304edd5d28bf 100644 --- a/sys/dev/usb/usb_transfer.c +++ b/sys/dev/usb/usb_transfer.c @@ -63,7 +63,7 @@ static const struct usb2_config usb2_control_ep_cfg[USB_DEFAULT_XFER_MAX] = { .bufsize = USB_EP0_BUFSIZE, /* bytes */ .flags = {.proxy_buffer = 1,}, .callback = &usb2_request_callback, - .usb_mode = USB_MODE_MAX, /* both modes */ + .usb_mode = USB_MODE_DUAL, /* both modes */ }, /* This transfer is used for generic clear stall only */ @@ -93,7 +93,7 @@ static void usb2_dma_delay_done_cb(void *); static void usb2_transfer_start_cb(void *); static uint8_t usb2_callback_wrapper_sub(struct usb2_xfer *); static void usb2_get_std_packet_size(struct usb2_std_packet_size *ptr, - uint8_t type, uint8_t usb_speed); + uint8_t type, enum usb_dev_speed speed); /*------------------------------------------------------------------------* * usb2_request_callback @@ -101,7 +101,7 @@ static void usb2_get_std_packet_size(struct usb2_std_packet_size *ptr, static void usb2_request_callback(struct usb2_xfer *xfer) { - if (xfer->flags_int.usb2_mode == USB_MODE_DEVICE) + if (xfer->flags_int.usb_mode == USB_MODE_DEVICE) usb2_handle_request_callback(xfer); else usb2_do_request_callback(xfer); @@ -327,7 +327,7 @@ usb2_transfer_setup_sub(struct usb2_setup_params *parm) xfer->max_packet_size = UGETW(edesc->wMaxPacketSize); xfer->max_packet_count = 1; /* make a shadow copy: */ - xfer->flags_int.usb2_mode = parm->udev->flags.usb2_mode; + xfer->flags_int.usb_mode = parm->udev->flags.usb_mode; parm->bufsize = setup->bufsize; @@ -858,8 +858,8 @@ usb2_transfer_setup(struct usb2_device *udev, if ((pipe == NULL) || (pipe->methods == NULL)) { if (setup->flags.no_pipe_ok) continue; - if ((setup->usb_mode != USB_MODE_MAX) && - (setup->usb_mode != udev->flags.usb2_mode)) + if ((setup->usb_mode != USB_MODE_DUAL) && + (setup->usb_mode != udev->flags.usb_mode)) continue; parm.err = USB_ERR_NO_PIPE; goto done; @@ -1225,9 +1225,13 @@ usb2_start_hardware_sub(struct usb2_xfer *xfer) usb2_frlength_t len; /* Check for control endpoint stall */ - if (xfer->flags.stall_pipe) { - /* no longer active */ + if (xfer->flags.stall_pipe && xfer->flags_int.control_act) { + /* the control transfer is no longer active */ + xfer->flags_int.control_stall = 1; xfer->flags_int.control_act = 0; + } else { + /* don't stall control transfer by default */ + xfer->flags_int.control_stall = 0; } /* Check for invalid number of frames */ @@ -1256,7 +1260,7 @@ usb2_start_hardware_sub(struct usb2_xfer *xfer) xfer->flags_int.control_hdr = 0; /* setup control transfer */ - if (xfer->flags_int.usb2_mode == USB_MODE_DEVICE) { + if (xfer->flags_int.usb_mode == USB_MODE_DEVICE) { usb2_control_transfer_init(xfer); } } @@ -1275,7 +1279,7 @@ usb2_start_hardware_sub(struct usb2_xfer *xfer) goto error; } /* check USB mode */ - if (xfer->flags_int.usb2_mode == USB_MODE_DEVICE) { + if (xfer->flags_int.usb_mode == USB_MODE_DEVICE) { /* check number of frames */ if (xfer->nframes != 1) { @@ -1439,7 +1443,11 @@ usb2_start_hardware(struct usb2_xfer *xfer) /* Check if the device is still alive */ if (info->udev->state < USB_STATE_POWERED) { USB_BUS_LOCK(bus); - usb2_transfer_done(xfer, USB_ERR_NOT_CONFIGURED); + /* + * Must return cancelled error code else + * device drivers can hang. + */ + usb2_transfer_done(xfer, USB_ERR_CANCELLED); USB_BUS_UNLOCK(bus); return; } @@ -2237,7 +2245,7 @@ usb2_pipe_start(struct usb2_xfer_queue *pq) udev = info->udev; pipe->is_stalled = 1; - if (udev->flags.usb2_mode == USB_MODE_DEVICE) { + if (udev->flags.usb_mode == USB_MODE_DEVICE) { (udev->bus->methods->set_stall) ( udev, NULL, pipe); } else if (udev->default_xfer[1]) { @@ -2570,7 +2578,7 @@ repeat: ((xfer->address == udev->address) && (udev->default_ep_desc.wMaxPacketSize[0] == udev->ddesc.bMaxPacketSize)); - if (udev->flags.usb2_mode == USB_MODE_DEVICE) { + if (udev->flags.usb_mode == USB_MODE_DEVICE) { if (no_resetup) { /* * NOTE: checking "xfer->address" and @@ -2738,8 +2746,8 @@ usb2_do_poll(struct usb2_xfer **ppxfer, uint16_t max) } static void -usb2_get_std_packet_size(struct usb2_std_packet_size *ptr, - uint8_t type, uint8_t usb_speed) +usb2_get_std_packet_size(struct usb2_std_packet_size *ptr, + uint8_t type, enum usb_dev_speed speed) { static const uint16_t intr_range_max[USB_SPEED_MAX] = { [USB_SPEED_LOW] = 8, @@ -2779,16 +2787,16 @@ usb2_get_std_packet_size(struct usb2_std_packet_size *ptr, switch (type) { case UE_INTERRUPT: - ptr->range.max = intr_range_max[usb_speed]; + ptr->range.max = intr_range_max[speed]; break; case UE_ISOCHRONOUS: - ptr->range.max = isoc_range_max[usb_speed]; + ptr->range.max = isoc_range_max[speed]; break; default: if (type == UE_BULK) - temp = bulk_min[usb_speed]; + temp = bulk_min[speed]; else /* UE_CONTROL */ - temp = control_min[usb_speed]; + temp = control_min[speed]; /* default is fixed */ ptr->fixed[0] = temp; @@ -2796,13 +2804,13 @@ usb2_get_std_packet_size(struct usb2_std_packet_size *ptr, ptr->fixed[2] = temp; ptr->fixed[3] = temp; - if (usb_speed == USB_SPEED_FULL) { + if (speed == USB_SPEED_FULL) { /* multiple sizes */ ptr->fixed[1] = 16; ptr->fixed[2] = 32; ptr->fixed[3] = 64; } - if ((usb_speed == USB_SPEED_VARIABLE) && + if ((speed == USB_SPEED_VARIABLE) && (type == UE_BULK)) { /* multiple sizes */ ptr->fixed[2] = 1024; diff --git a/sys/dev/usb/usb_transfer.h b/sys/dev/usb/usb_transfer.h index a15e8a3c0c96..c385dd822d1f 100644 --- a/sys/dev/usb/usb_transfer.h +++ b/sys/dev/usb/usb_transfer.h @@ -104,7 +104,7 @@ struct usb2_setup_params { uint16_t hc_max_frame_size; uint16_t hc_max_packet_size; uint8_t hc_max_packet_count; - uint8_t speed; + enum usb_dev_speed speed; uint8_t dma_tag_max; usb2_error_t err; }; diff --git a/sys/dev/usb/usbdevs b/sys/dev/usb/usbdevs index 73def19d63e5..183a77d4b555 100644 --- a/sys/dev/usb/usbdevs +++ b/sys/dev/usb/usbdevs @@ -624,6 +624,7 @@ vendor QCOM 0x18e8 Qcom vendor LINKSYS3 0x1915 Linksys vendor QUALCOMMINC 0x19d2 Qualcomm, Incorporated vendor STELERA 0x1a8d Stelera Wireless +vendor MPMAN 0x1cae MpMan vendor DRESDENELEKTRONIK 0x1cf1 dresden elektronik vendor DLINK 0x2001 D-Link vendor PLANEX2 0x2019 Planex Communications @@ -817,6 +818,7 @@ product ALCOR AU9814 0x9215 AU9814 Hub product ALCOR UMCR_9361 0x9361 USB Multimedia Card Reader product ALCOR SM_KBD 0x9410 MicroConnectors/StrongMan Keyboard product ALCOR NEC_KBD_HUB 0x9472 NEC Kbd Hub +product ALCOR AU6390 0x6390 AU6390 USB-IDE converter /* Altec Lansing products */ product ALTEC ADA70 0x0070 ADA70 Speakers @@ -1023,6 +1025,7 @@ product CHPRODUCTS FIGHTERSTICK 0x00f3 Fighterstick product CHPRODUCTS FLIGHTYOKE 0x00ff Flight Sim Yoke /* Cisco-Linksys products */ +product CISCOLINKSYS WUSB54AG 0x000c WUSB54AG Wireless Adapter product CISCOLINKSYS WUSB54G 0x000d WUSB54G Wireless Adapter product CISCOLINKSYS WUSB54GP 0x0011 WUSB54GP Wireless Adapter product CISCOLINKSYS USB200MV2 0x0018 USB200M v2 @@ -1106,6 +1109,7 @@ product CYPRESS KBDHUB 0x0101 Keyboard/Hub product CYPRESS FMRADIO 0x1002 FM Radio product CYPRESS USBRS232 0x5500 USB-RS232 Interface product CYPRESS SLIM_HUB 0x6560 Slim Hub +product CYPRESS XX6830XX 0x6830 PATA Storage Device /* Daisy Technology products */ product DAISY DMC 0x6901 USB MultiMedia Reader @@ -1910,6 +1914,7 @@ product OPTION GT3GQUAD 0x6300 GlobeTrotter 3G QUAD datacard product OPTION GT3GPLUS 0x6600 GlobeTrotter 3G+ datacard product OPTION GTICON322 0xd033 GlobeTrotter Icon322 storage product OPTION GTMAX36 0x6701 GlobeTrotter Max 3.6 Modem +product OPTION GTHSDPA 0x6971 GlobeTrotter HSDPA product OPTION GTMAXHSUPA 0x7001 GlobeTrotter HSUPA /* OQO */ @@ -2130,6 +2135,7 @@ product SHARP SL5600 0x8006 Zaurus SL-5600 PDA product SHARP SLC700 0x8007 Zaurus SL-C700 PDA product SHARP SLC750 0x9031 Zaurus SL-C750 PDA product SHARP WZERO3ES 0x9123 W-ZERO3 ES Smartphone +product SHARP WILLCOM03 0x9242 WILLCOM03 /* Shuttle Technology products */ product SHUTTLE EUSB 0x0001 E-USB Bridge @@ -2296,6 +2302,10 @@ product SPHAIRON UB801R 0x0110 UB801R product STELERA ZEROCD 0x1000 Zerocd Installer product STELERA C105 0x1002 Stelera/Bandrish C105 USB +/* MpMan products */ +product MPMAN MPF400_1 0x36d0 MPF400 Music Player 1Go +product MPMAN MPF400_2 0x25a8 MPF400 Music Player 2Go + /* STMicroelectronics products */ product STMICRO BIOCPU 0x2016 Biometric Coprocessor product STMICRO COMMUNICATOR 0x7554 USB Communicator @@ -2417,6 +2427,7 @@ product UMEDIA TEW429UBC1 0x300d TEW-429UB C1 product UMEDIA ALL0298V2 0x3204 ALL0298 v2 product UMEDIA AR5523_2 0x3205 AR5523 product UMEDIA AR5523_2_NF 0x3206 AR5523 (no firmware) +product UMEDIA AR5523_3 0x3207 AR5523 /* Universal Access products */ product UNIACCESS PANACHE 0x0101 Panache Surf USB ISDN Adapter @@ -2516,6 +2527,7 @@ product ZCOM XG703A 0x0008 PrismGT USB 2.0 WLAN product ZCOM ZD1211 0x0011 ZD1211 product ZCOM AR5523 0x0012 AR5523 product ZCOM AR5523_NF 0x0013 AR5523 driver (no firmware) +product ZCOM XM142 0x0015 XM-142 product ZCOM ZD1211B 0x001a ZD1211B /* Zinwell products */ diff --git a/sys/dev/usb/wlan/if_rum.c b/sys/dev/usb/wlan/if_rum.c index 0c3012e89d45..5fa08992bbb5 100644 --- a/sys/dev/usb/wlan/if_rum.c +++ b/sys/dev/usb/wlan/if_rum.c @@ -85,8 +85,8 @@ __FBSDID("$FreeBSD$"); #if USB_DEBUG static int rum_debug = 0; -SYSCTL_NODE(_hw_usb2, OID_AUTO, rum, CTLFLAG_RW, 0, "USB rum"); -SYSCTL_INT(_hw_usb2_rum, OID_AUTO, debug, CTLFLAG_RW, &rum_debug, 0, +SYSCTL_NODE(_hw_usb, OID_AUTO, rum, CTLFLAG_RW, 0, "USB rum"); +SYSCTL_INT(_hw_usb_rum, OID_AUTO, debug, CTLFLAG_RW, &rum_debug, 0, "Debug level"); #endif @@ -196,6 +196,7 @@ static void rum_select_band(struct rum_softc *, static void rum_set_chan(struct rum_softc *, struct ieee80211_channel *); static void rum_enable_tsf_sync(struct rum_softc *); +static void rum_enable_tsf(struct rum_softc *); static void rum_update_slot(struct ifnet *); static void rum_set_bssid(struct rum_softc *, const uint8_t *); static void rum_set_macaddr(struct rum_softc *, const uint8_t *); @@ -410,7 +411,7 @@ rum_match(device_t self) { struct usb2_attach_arg *uaa = device_get_ivars(self); - if (uaa->usb2_mode != USB_MODE_HOST) + if (uaa->usb_mode != USB_MODE_HOST) return (ENXIO); if (uaa->info.bConfigIndex != 0) return (ENXIO); @@ -522,16 +523,11 @@ rum_attach(device_t self) ic->ic_vap_create = rum_vap_create; ic->ic_vap_delete = rum_vap_delete; - bpfattach(ifp, DLT_IEEE802_11_RADIO, - sizeof (struct ieee80211_frame) + sizeof(sc->sc_txtap)); - - sc->sc_rxtap_len = sizeof sc->sc_rxtap; - sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len); - sc->sc_rxtap.wr_ihdr.it_present = htole32(RT2573_RX_RADIOTAP_PRESENT); - - sc->sc_txtap_len = sizeof sc->sc_txtap; - sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len); - sc->sc_txtap.wt_ihdr.it_present = htole32(RT2573_TX_RADIOTAP_PRESENT); + ieee80211_radiotap_attach(ic, + &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), + RT2573_TX_RADIOTAP_PRESENT, + &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), + RT2573_RX_RADIOTAP_PRESENT); if (bootverbose) ieee80211_announce(ic); @@ -560,7 +556,6 @@ rum_detach(device_t self) if (ifp) { ic = ifp->if_l2com; - bpfdetach(ifp); ieee80211_ifdetach(ic); if_free(ifp); } @@ -752,9 +747,11 @@ rum_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) if (vap->iv_opmode != IEEE80211_M_MONITOR) rum_enable_tsf_sync(sc); + else + rum_enable_tsf(sc); /* enable automatic rate adaptation */ - tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_bsschan)]; + tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) rum_amrr_start(sc, ni); break; @@ -771,8 +768,7 @@ rum_bulk_write_callback(struct usb2_xfer *xfer) { struct rum_softc *sc = xfer->priv_sc; struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; - struct ieee80211_channel *c = ic->ic_curchan; + struct ieee80211vap *vap; struct rum_tx_data *data; struct mbuf *m; unsigned int len; @@ -807,16 +803,15 @@ tr_setup: usb2_m_copy_in(xfer->frbuffers, RT2573_TX_DESC_SIZE, m, 0, m->m_pkthdr.len); - if (bpf_peers_present(ifp->if_bpf)) { + vap = data->ni->ni_vap; + if (ieee80211_radiotap_active_vap(vap)) { struct rum_tx_radiotap_header *tap = &sc->sc_txtap; tap->wt_flags = 0; tap->wt_rate = data->rate; - tap->wt_chan_freq = htole16(c->ic_freq); - tap->wt_chan_flags = htole16(c->ic_flags); tap->wt_antenna = sc->tx_ant; - bpf_mtap2(ifp->if_bpf, tap, sc->sc_txtap_len, m); + ieee80211_radiotap_tx(vap, m); } /* align end on a 4-bytes boundary */ @@ -911,19 +906,17 @@ rum_bulk_read_callback(struct usb2_xfer *xfer) m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = m->m_len = (flags >> 16) & 0xfff; - if (bpf_peers_present(ifp->if_bpf)) { + if (ieee80211_radiotap_active(ic)) { struct rum_rx_radiotap_header *tap = &sc->sc_rxtap; - tap->wr_flags = IEEE80211_RADIOTAP_F_FCS; + /* XXX read tsf */ + tap->wr_flags = 0; tap->wr_rate = ieee80211_plcp2rate(sc->sc_rx_desc.rate, (flags & RT2573_RX_OFDM) ? IEEE80211_T_OFDM : IEEE80211_T_CCK); - tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq); - tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags); + tap->wr_antsignal = RT2573_NOISE_FLOOR + rssi; + tap->wr_antnoise = RT2573_NOISE_FLOOR; tap->wr_antenna = sc->rx_ant; - tap->wr_antsignal = rssi; - - bpf_mtap2(ifp->if_bpf, tap, sc->sc_rxtap_len, m); } /* FALLTHROUGH */ case USB_ST_SETUP: @@ -942,11 +935,11 @@ tr_setup: mtod(m, struct ieee80211_frame_min *)); if (ni != NULL) { (void) ieee80211_input(ni, m, rssi, - RT2573_NOISE_FLOOR, 0); + RT2573_NOISE_FLOOR); ieee80211_free_node(ni); } else (void) ieee80211_input_all(ic, m, rssi, - RT2573_NOISE_FLOOR, 0); + RT2573_NOISE_FLOOR); RUM_LOCK(sc); } return; @@ -1737,6 +1730,14 @@ rum_enable_tsf_sync(struct rum_softc *sc) } static void +rum_enable_tsf(struct rum_softc *sc) +{ + rum_write(sc, RT2573_TXRX_CSR9, + (rum_read(sc, RT2573_TXRX_CSR9) & 0xff000000) | + RT2573_TSF_TICKING | RT2573_TSF_MODE(2)); +} + +static void rum_update_slot(struct ifnet *ifp) { struct rum_softc *sc = ifp->if_softc; diff --git a/sys/dev/usb/wlan/if_rumvar.h b/sys/dev/usb/wlan/if_rumvar.h index 2ba40075c24f..13b84f7ee1aa 100644 --- a/sys/dev/usb/wlan/if_rumvar.h +++ b/sys/dev/usb/wlan/if_rumvar.h @@ -26,16 +26,19 @@ struct rum_rx_radiotap_header { uint8_t wr_rate; uint16_t wr_chan_freq; uint16_t wr_chan_flags; + int8_t wr_antsignal; + int8_t wr_antnoise; uint8_t wr_antenna; - uint8_t wr_antsignal; }; #define RT2573_RX_RADIOTAP_PRESENT \ ((1 << IEEE80211_RADIOTAP_FLAGS) | \ (1 << IEEE80211_RADIOTAP_RATE) | \ (1 << IEEE80211_RADIOTAP_CHANNEL) | \ + (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | \ + (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | \ (1 << IEEE80211_RADIOTAP_ANTENNA) | \ - (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL)) + 0) struct rum_tx_radiotap_header { struct ieee80211_radiotap_header wt_ihdr; diff --git a/sys/dev/usb/wlan/if_uath.c b/sys/dev/usb/wlan/if_uath.c index 8e6577030f55..34acd52bc0c2 100644 --- a/sys/dev/usb/wlan/if_uath.c +++ b/sys/dev/usb/wlan/if_uath.c @@ -116,19 +116,19 @@ __FBSDID("$FreeBSD$"); #include <dev/usb/wlan/if_uathreg.h> #include <dev/usb/wlan/if_uathvar.h> -SYSCTL_NODE(_hw_usb2, OID_AUTO, uath, CTLFLAG_RW, 0, "USB Atheros"); +SYSCTL_NODE(_hw_usb, OID_AUTO, uath, CTLFLAG_RW, 0, "USB Atheros"); static int uath_countrycode = CTRY_DEFAULT; /* country code */ -SYSCTL_INT(_hw_usb2_uath, OID_AUTO, countrycode, CTLFLAG_RW, &uath_countrycode, +SYSCTL_INT(_hw_usb_uath, OID_AUTO, countrycode, CTLFLAG_RW, &uath_countrycode, 0, "country code"); -TUNABLE_INT("hw.usb2.uath.countrycode", &uath_countrycode); +TUNABLE_INT("hw.usb.uath.countrycode", &uath_countrycode); static int uath_regdomain = 0; /* regulatory domain */ -SYSCTL_INT(_hw_usb2_uath, OID_AUTO, regdomain, CTLFLAG_RD, &uath_regdomain, +SYSCTL_INT(_hw_usb_uath, OID_AUTO, regdomain, CTLFLAG_RD, &uath_regdomain, 0, "regulatory domain"); #ifdef UATH_DEBUG int uath_debug = 0; -SYSCTL_INT(_hw_usb2_uath, OID_AUTO, debug, CTLFLAG_RW, &uath_debug, 0, +SYSCTL_INT(_hw_usb_uath, OID_AUTO, debug, CTLFLAG_RW, &uath_debug, 0, "uath debug level"); TUNABLE_INT("hw.usb.uath.debug", &uath_debug); enum { @@ -192,6 +192,7 @@ static const struct usb2_device_id uath_devs[] = { UATH_DEV(NETGEAR3, WPN111), UATH_DEV(UMEDIA, TEW444UBEU), UATH_DEV(UMEDIA, AR5523_2), + UATH_DEV(UMEDIA, AR5523_3), UATH_DEV(WISTRONNEWEB, AR5523_1), UATH_DEV(WISTRONNEWEB, AR5523_2), UATH_DEV(ZCOM, AR5523) @@ -328,7 +329,7 @@ uath_match(device_t dev) { struct usb2_attach_arg *uaa = device_get_ivars(dev); - if (uaa->usb2_mode != USB_MODE_HOST) + if (uaa->usb_mode != USB_MODE_HOST) return (ENXIO); if (uaa->info.bConfigIndex != UATH_CONFIG_INDEX) return (ENXIO); @@ -354,6 +355,7 @@ uath_attach(device_t dev) #ifdef UATH_DEBUG sc->sc_debug = uath_debug; #endif + device_set_usb2_desc(dev); /* * Only post-firmware devices here. @@ -480,16 +482,11 @@ uath_attach(device_t dev) ic->ic_update_mcast = uath_update_mcast; ic->ic_update_promisc = uath_update_promisc; - bpfattach(ifp, DLT_IEEE802_11_RADIO, - sizeof (struct ieee80211_frame) + sizeof(sc->sc_txtap)); - - sc->sc_rxtap_len = sizeof sc->sc_rxtap; - sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len); - sc->sc_rxtap.wr_ihdr.it_present = htole32(UATH_RX_RADIOTAP_PRESENT); - - sc->sc_txtap_len = sizeof sc->sc_txtap; - sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len); - sc->sc_txtap.wt_ihdr.it_present = htole32(UATH_TX_RADIOTAP_PRESENT); + ieee80211_radiotap_attach(ic, + &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), + UATH_TX_RADIOTAP_PRESENT, + &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), + UATH_RX_RADIOTAP_PRESENT); if (bootverbose) ieee80211_announce(ic); @@ -516,12 +513,12 @@ uath_detach(device_t dev) sc->sc_flags |= UATH_FLAG_INVALID; uath_stop(ifp); - ieee80211_ifdetach(ic); callout_drain(&sc->stat_ch); callout_drain(&sc->watchdog_ch); usb2_transfer_unsetup(sc->sc_xfer, UATH_N_XFERS); + ieee80211_ifdetach(ic); /* free buffers */ UATH_LOCK(sc); @@ -530,7 +527,6 @@ uath_detach(device_t dev) uath_free_cmd_list(sc, sc->sc_cmd, UATH_CMD_LIST_COUNT); UATH_UNLOCK(sc); - bpfdetach(ifp); if_free(ifp); mtx_destroy(&sc->sc_mtx); return (0); @@ -1492,9 +1488,9 @@ uath_set_chan(struct uath_softc *sc, struct ieee80211_channel *c) if (IEEE80211_IS_CHAN_5GHZ(c)) reset.flags |= htobe32(UATH_CHAN_5GHZ); /* NB: 11g =>'s 11b so don't specify both OFDM and CCK */ - if (IEEE80211_IS_CHAN_G(c)) + if (IEEE80211_IS_CHAN_OFDM(c)) reset.flags |= htobe32(UATH_CHAN_OFDM); - else if (IEEE80211_IS_CHAN_B(c)) + else if (IEEE80211_IS_CHAN_CCK(c)) reset.flags |= htobe32(UATH_CHAN_CCK); /* turbo can be used in either 2GHz or 5GHz */ if (c->ic_flags & IEEE80211_CHAN_TURBO) @@ -1600,8 +1596,6 @@ static int uath_tx_start(struct uath_softc *sc, struct mbuf *m0, struct ieee80211_node *ni, struct uath_data *data) { - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; struct ieee80211vap *vap = ni->ni_vap; struct uath_chunk *chunk; struct uath_tx_desc *desc; @@ -1616,16 +1610,14 @@ uath_tx_start(struct uath_softc *sc, struct mbuf *m0, struct ieee80211_node *ni, chunk = (struct uath_chunk *)data->buf; desc = (struct uath_tx_desc *)(chunk + 1); - if (bpf_peers_present(ifp->if_bpf)) { + if (ieee80211_radiotap_active_vap(vap)) { struct uath_tx_radiotap_header *tap = &sc->sc_txtap; tap->wt_flags = 0; if (m0->m_flags & M_FRAG) tap->wt_flags |= IEEE80211_RADIOTAP_F_FRAG; - tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq); - tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags); - bpf_mtap2(ifp->if_bpf, tap, sc->sc_txtap_len, m0); + ieee80211_radiotap_tx(vap, m0); } wh = mtod(m0, struct ieee80211_frame *); @@ -1920,7 +1912,7 @@ uath_set_channel(struct ieee80211com *ic) static int uath_set_rxmulti_filter(struct uath_softc *sc) { - + /* XXX broken */ return (0); } static void @@ -1928,13 +1920,14 @@ uath_update_mcast(struct ifnet *ifp) { struct uath_softc *sc = ifp->if_softc; + UATH_LOCK(sc); /* * this is for avoiding the race condition when we're try to * connect to the AP with WPA. */ - if (!(sc->sc_flags & UATH_FLAG_INITDONE)) - return; - (void)uath_set_rxmulti_filter(sc); + if (sc->sc_flags & UATH_FLAG_INITDONE) + (void)uath_set_rxmulti_filter(sc); + UATH_UNLOCK(sc); } static void @@ -1942,12 +1935,14 @@ uath_update_promisc(struct ifnet *ifp) { struct uath_softc *sc = ifp->if_softc; - if (!(sc->sc_flags & UATH_FLAG_INITDONE)) - return; - uath_set_rxfilter(sc, - UATH_FILTER_RX_UCAST | UATH_FILTER_RX_MCAST | - UATH_FILTER_RX_BCAST | UATH_FILTER_RX_BEACON | - UATH_FILTER_RX_PROM, UATH_FILTER_OP_SET); + UATH_LOCK(sc); + if (sc->sc_flags & UATH_FLAG_INITDONE) { + uath_set_rxfilter(sc, + UATH_FILTER_RX_UCAST | UATH_FILTER_RX_MCAST | + UATH_FILTER_RX_BCAST | UATH_FILTER_RX_BEACON | + UATH_FILTER_RX_PROM, UATH_FILTER_OP_SET); + } + UATH_UNLOCK(sc); } static int @@ -2652,14 +2647,22 @@ uath_data_rxeof(struct usb2_xfer *xfer, struct uath_data *data, } /* there are a lot more fields in the RX descriptor */ - if (bpf_peers_present(ifp->if_bpf)) { + if (ieee80211_radiotap_active(ic)) { struct uath_rx_radiotap_header *tap = &sc->sc_rxtap; + uint32_t tsf_hi = be32toh(desc->tstamp_high); + uint32_t tsf_lo = be32toh(desc->tstamp_low); - tap->wr_chan_freq = htole16(be32toh(desc->channel)); - tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags); - tap->wr_dbm_antsignal = (int8_t)be32toh(desc->rssi); - - bpf_mtap2(ifp->if_bpf, tap, sc->sc_rxtap_len, m); + /* XXX only get low order 24bits of tsf from h/w */ + tap->wr_tsf = htole64(((uint64_t)tsf_hi << 32) | tsf_lo); + tap->wr_flags = 0; + if (be32toh(desc->status) == UATH_STATUS_CRC_ERR) + tap->wr_flags |= IEEE80211_RADIOTAP_F_BADFCS; + /* XXX map other status to BADFCS? */ + /* XXX ath h/w rate code, need to map */ + tap->wr_rate = be32toh(desc->rate); + tap->wr_antenna = be32toh(desc->antenna); + tap->wr_antsignal = -95 + be32toh(desc->rssi); + tap->wr_antnoise = -95; } ifp->if_ipackets++; @@ -2720,12 +2723,12 @@ setup: nf = -95; /* XXX */ if (ni != NULL) { (void) ieee80211_input(ni, m, - (int)be32toh(desc->rssi), nf, 0); + (int)be32toh(desc->rssi), nf); /* node is no longer needed */ ieee80211_free_node(ni); } else (void) ieee80211_input_all(ic, m, - (int)be32toh(desc->rssi), nf, 0); + (int)be32toh(desc->rssi), nf); m = NULL; desc = NULL; } diff --git a/sys/dev/usb/wlan/if_uathvar.h b/sys/dev/usb/wlan/if_uathvar.h index 2757ad459c94..9b0a12694e55 100644 --- a/sys/dev/usb/wlan/if_uathvar.h +++ b/sys/dev/usb/wlan/if_uathvar.h @@ -44,22 +44,31 @@ enum { struct uath_rx_radiotap_header { struct ieee80211_radiotap_header wr_ihdr; - uint8_t wr_flags; - uint16_t wr_chan_freq; - uint16_t wr_chan_flags; - int8_t wr_dbm_antsignal; + u_int64_t wr_tsf; + u_int8_t wr_flags; + u_int8_t wr_rate; + uint16_t wr_chan_freq; + uint16_t wr_chan_flags; + int8_t wr_antsignal; + int8_t wr_antnoise; + u_int8_t wr_antenna; } __packed; -#define UATH_RX_RADIOTAP_PRESENT \ - ((1 << IEEE80211_RADIOTAP_FLAGS) | \ - (1 << IEEE80211_RADIOTAP_CHANNEL) | \ - (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL)) +#define UATH_RX_RADIOTAP_PRESENT ( \ + (1 << IEEE80211_RADIOTAP_TSFT) | \ + (1 << IEEE80211_RADIOTAP_FLAGS) | \ + (1 << IEEE80211_RADIOTAP_RATE) | \ + (1 << IEEE80211_RADIOTAP_ANTENNA) | \ + (1 << IEEE80211_RADIOTAP_CHANNEL) | \ + (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | \ + (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | \ + 0) struct uath_tx_radiotap_header { struct ieee80211_radiotap_header wt_ihdr; - uint8_t wt_flags; - uint16_t wt_chan_freq; - uint16_t wt_chan_flags; + uint8_t wt_flags; + uint16_t wt_chan_freq; + uint16_t wt_chan_flags; } __packed; #define UATH_TX_RADIOTAP_PRESENT \ diff --git a/sys/dev/usb/wlan/if_upgt.c b/sys/dev/usb/wlan/if_upgt.c new file mode 100644 index 000000000000..0a7d0a48c0ab --- /dev/null +++ b/sys/dev/usb/wlan/if_upgt.c @@ -0,0 +1,2395 @@ +/* $OpenBSD: if_upgt.c,v 1.35 2008/04/16 18:32:15 damien Exp $ */ +/* $FreeBSD$ */ + +/* + * Copyright (c) 2007 Marcus Glocker <mglocker@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/endian.h> +#include <sys/firmware.h> +#include <sys/linker.h> +#include <sys/mbuf.h> +#include <sys/malloc.h> +#include <sys/module.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <sys/sysctl.h> + +#include <net/if.h> +#include <net/if_arp.h> +#include <net/ethernet.h> +#include <net/if_dl.h> +#include <net/if_media.h> +#include <net/if_types.h> + +#include <sys/bus.h> +#include <machine/bus.h> + +#include <net80211/ieee80211_var.h> +#include <net80211/ieee80211_phy.h> +#include <net80211/ieee80211_radiotap.h> +#include <net80211/ieee80211_regdomain.h> + +#include <net/bpf.h> + +#include <dev/usb/usb.h> +#include <dev/usb/usb_core.h> +#include <dev/usb/usb_busdma.h> +#include <dev/usb/usb_debug.h> +#include <dev/usb/usb_error.h> +#include <dev/usb/usb_lookup.h> +#include <dev/usb/usb_util.h> +#include "usbdevs.h" + +#include <dev/usb/wlan/if_upgtvar.h> + +/* + * Driver for the USB PrismGT devices. + * + * For now just USB 2.0 devices with the GW3887 chipset are supported. + * The driver has been written based on the firmware version 2.13.1.0_LM87. + * + * TODO's: + * - MONITOR mode test. + * - Add HOSTAP mode. + * - Add IBSS mode. + * - Support the USB 1.0 devices (NET2280, ISL3880, ISL3886 chipsets). + * + * Parts of this driver has been influenced by reading the p54u driver + * written by Jean-Baptiste Note <jean-baptiste.note@m4x.org> and + * Sebastien Bourdeauducq <lekernel@prism54.org>. + */ + +SYSCTL_NODE(_hw, OID_AUTO, upgt, CTLFLAG_RD, 0, + "USB PrismGT GW3887 driver parameters"); + +#ifdef UPGT_DEBUG +int upgt_debug = 0; +SYSCTL_INT(_hw_upgt, OID_AUTO, debug, CTLFLAG_RW, &upgt_debug, + 0, "control debugging printfs"); +TUNABLE_INT("hw.upgt.debug", &upgt_debug); +enum { + UPGT_DEBUG_XMIT = 0x00000001, /* basic xmit operation */ + UPGT_DEBUG_RECV = 0x00000002, /* basic recv operation */ + UPGT_DEBUG_RESET = 0x00000004, /* reset processing */ + UPGT_DEBUG_INTR = 0x00000008, /* INTR */ + UPGT_DEBUG_TX_PROC = 0x00000010, /* tx ISR proc */ + UPGT_DEBUG_RX_PROC = 0x00000020, /* rx ISR proc */ + UPGT_DEBUG_STATE = 0x00000040, /* 802.11 state transitions */ + UPGT_DEBUG_STAT = 0x00000080, /* statistic */ + UPGT_DEBUG_FW = 0x00000100, /* firmware */ + UPGT_DEBUG_ANY = 0xffffffff +}; +#define DPRINTF(sc, m, fmt, ...) do { \ + if (sc->sc_debug & (m)) \ + printf(fmt, __VA_ARGS__); \ +} while (0) +#else +#define DPRINTF(sc, m, fmt, ...) do { \ + (void) sc; \ +} while (0) +#endif + +/* + * Prototypes. + */ +static device_probe_t upgt_match; +static device_attach_t upgt_attach; +static device_detach_t upgt_detach; +static int upgt_alloc_tx(struct upgt_softc *); +static int upgt_alloc_rx(struct upgt_softc *); +static int upgt_device_reset(struct upgt_softc *); +static void upgt_bulk_tx(struct upgt_softc *, struct upgt_data *); +static int upgt_fw_verify(struct upgt_softc *); +static int upgt_mem_init(struct upgt_softc *); +static int upgt_fw_load(struct upgt_softc *); +static int upgt_fw_copy(const uint8_t *, char *, int); +static uint32_t upgt_crc32_le(const void *, size_t); +static struct mbuf * + upgt_rxeof(struct usb2_xfer *, struct upgt_data *, int *); +static struct mbuf * + upgt_rx(struct upgt_softc *, uint8_t *, int, int *); +static void upgt_txeof(struct usb2_xfer *, struct upgt_data *); +static int upgt_eeprom_read(struct upgt_softc *); +static int upgt_eeprom_parse(struct upgt_softc *); +static void upgt_eeprom_parse_hwrx(struct upgt_softc *, uint8_t *); +static void upgt_eeprom_parse_freq3(struct upgt_softc *, uint8_t *, int); +static void upgt_eeprom_parse_freq4(struct upgt_softc *, uint8_t *, int); +static void upgt_eeprom_parse_freq6(struct upgt_softc *, uint8_t *, int); +static uint32_t upgt_chksum_le(const uint32_t *, size_t); +static void upgt_tx_done(struct upgt_softc *, uint8_t *); +static void upgt_init(void *); +static void upgt_init_locked(struct upgt_softc *); +static int upgt_ioctl(struct ifnet *, u_long, caddr_t); +static void upgt_start(struct ifnet *); +static int upgt_raw_xmit(struct ieee80211_node *, struct mbuf *, + const struct ieee80211_bpf_params *); +static void upgt_scan_start(struct ieee80211com *); +static void upgt_scan_end(struct ieee80211com *); +static void upgt_set_channel(struct ieee80211com *); +static struct ieee80211vap *upgt_vap_create(struct ieee80211com *, + const char name[IFNAMSIZ], int unit, int opmode, + int flags, const uint8_t bssid[IEEE80211_ADDR_LEN], + const uint8_t mac[IEEE80211_ADDR_LEN]); +static void upgt_vap_delete(struct ieee80211vap *); +static void upgt_update_mcast(struct ifnet *); +static uint8_t upgt_rx_rate(struct upgt_softc *, const int); +static void upgt_set_multi(void *); +static void upgt_stop(struct upgt_softc *); +static void upgt_setup_rates(struct ieee80211vap *, struct ieee80211com *); +static int upgt_set_macfilter(struct upgt_softc *, uint8_t); +static int upgt_newstate(struct ieee80211vap *, enum ieee80211_state, int); +static void upgt_set_chan(struct upgt_softc *, struct ieee80211_channel *); +static void upgt_set_led(struct upgt_softc *, int); +static void upgt_set_led_blink(void *); +static void upgt_get_stats(struct upgt_softc *); +static void upgt_mem_free(struct upgt_softc *, uint32_t); +static uint32_t upgt_mem_alloc(struct upgt_softc *); +static void upgt_free_tx(struct upgt_softc *); +static void upgt_free_rx(struct upgt_softc *); +static void upgt_watchdog(void *); +static void upgt_abort_xfers(struct upgt_softc *); +static void upgt_abort_xfers_locked(struct upgt_softc *); +static void upgt_sysctl_node(struct upgt_softc *); +static struct upgt_data * + upgt_getbuf(struct upgt_softc *); +static struct upgt_data * + upgt_gettxbuf(struct upgt_softc *); +static int upgt_tx_start(struct upgt_softc *, struct mbuf *, + struct ieee80211_node *, struct upgt_data *); + +static const char *upgt_fwname = "upgt-gw3887"; + +static const struct usb2_device_id upgt_devs_2[] = { +#define UPGT_DEV(v,p) { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) } + /* version 2 devices */ + UPGT_DEV(ACCTON, PRISM_GT), + UPGT_DEV(BELKIN, F5D7050), + UPGT_DEV(CISCOLINKSYS, WUSB54AG), + UPGT_DEV(CONCEPTRONIC, PRISM_GT), + UPGT_DEV(DELL, PRISM_GT_1), + UPGT_DEV(DELL, PRISM_GT_2), + UPGT_DEV(FSC, E5400), + UPGT_DEV(GLOBESPAN, PRISM_GT_1), + UPGT_DEV(GLOBESPAN, PRISM_GT_2), + UPGT_DEV(INTERSIL, PRISM_GT), + UPGT_DEV(SMC, 2862WG), + UPGT_DEV(WISTRONNEWEB, UR045G), + UPGT_DEV(XYRATEX, PRISM_GT_1), + UPGT_DEV(XYRATEX, PRISM_GT_2), + UPGT_DEV(ZCOM, XG703A), + UPGT_DEV(ZCOM, XM142) +}; + +static usb2_callback_t upgt_bulk_rx_callback; +static usb2_callback_t upgt_bulk_tx_callback; + +static const struct usb2_config upgt_config[UPGT_N_XFERS] = { + [UPGT_BULK_TX] = { + .type = UE_BULK, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_OUT, + .bufsize = MCLBYTES, + .flags = { + .ext_buffer = 1, + .force_short_xfer = 1, + .pipe_bof = 1 + }, + .callback = upgt_bulk_tx_callback, + .timeout = UPGT_USB_TIMEOUT, /* ms */ + }, + [UPGT_BULK_RX] = { + .type = UE_BULK, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_IN, + .bufsize = MCLBYTES, + .flags = { + .ext_buffer = 1, + .pipe_bof = 1, + .short_xfer_ok = 1 + }, + .callback = upgt_bulk_rx_callback, + }, +}; + +static int +upgt_match(device_t dev) +{ + struct usb2_attach_arg *uaa = device_get_ivars(dev); + + if (uaa->usb_mode != USB_MODE_HOST) + return (ENXIO); + if (uaa->info.bConfigIndex != UPGT_CONFIG_INDEX) + return (ENXIO); + if (uaa->info.bIfaceIndex != UPGT_IFACE_INDEX) + return (ENXIO); + + return (usb2_lookup_id_by_uaa(upgt_devs_2, sizeof(upgt_devs_2), uaa)); +} + +static int +upgt_attach(device_t dev) +{ + int error; + struct ieee80211com *ic; + struct ifnet *ifp; + struct upgt_softc *sc = device_get_softc(dev); + struct usb2_attach_arg *uaa = device_get_ivars(dev); + uint8_t bands, iface_index = UPGT_IFACE_INDEX; + + sc->sc_dev = dev; + sc->sc_udev = uaa->device; +#ifdef UPGT_DEBUG + sc->sc_debug = upgt_debug; +#endif + device_set_usb2_desc(dev); + + mtx_init(&sc->sc_mtx, device_get_nameunit(sc->sc_dev), MTX_NETWORK_LOCK, + MTX_DEF); + callout_init(&sc->sc_led_ch, 0); + callout_init(&sc->sc_watchdog_ch, 0); + + /* Allocate TX and RX xfers. */ + error = upgt_alloc_tx(sc); + if (error) + goto fail1; + error = upgt_alloc_rx(sc); + if (error) + goto fail2; + + error = usb2_transfer_setup(uaa->device, &iface_index, sc->sc_xfer, + upgt_config, UPGT_N_XFERS, sc, &sc->sc_mtx); + if (error) { + device_printf(dev, "could not allocate USB transfers, " + "err=%s\n", usb2_errstr(error)); + goto fail3; + } + + ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211); + if (ifp == NULL) { + device_printf(dev, "can not if_alloc()\n"); + goto fail4; + } + + /* Initialize the device. */ + error = upgt_device_reset(sc); + if (error) + goto fail5; + /* Verify the firmware. */ + error = upgt_fw_verify(sc); + if (error) + goto fail5; + /* Calculate device memory space. */ + if (sc->sc_memaddr_frame_start == 0 || sc->sc_memaddr_frame_end == 0) { + device_printf(dev, + "could not find memory space addresses on FW!\n"); + error = EIO; + goto fail5; + } + sc->sc_memaddr_frame_end -= UPGT_MEMSIZE_RX + 1; + sc->sc_memaddr_rx_start = sc->sc_memaddr_frame_end + 1; + + DPRINTF(sc, UPGT_DEBUG_FW, "memory address frame start=0x%08x\n", + sc->sc_memaddr_frame_start); + DPRINTF(sc, UPGT_DEBUG_FW, "memory address frame end=0x%08x\n", + sc->sc_memaddr_frame_end); + DPRINTF(sc, UPGT_DEBUG_FW, "memory address rx start=0x%08x\n", + sc->sc_memaddr_rx_start); + + upgt_mem_init(sc); + + /* Load the firmware. */ + error = upgt_fw_load(sc); + if (error) + goto fail5; + + /* Read the whole EEPROM content and parse it. */ + error = upgt_eeprom_read(sc); + if (error) + goto fail5; + error = upgt_eeprom_parse(sc); + if (error) + goto fail5; + + /* all works related with the device have done here. */ + upgt_abort_xfers(sc); + + /* Setup the 802.11 device. */ + ifp->if_softc = sc; + if_initname(ifp, "upgt", device_get_unit(sc->sc_dev)); + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_init = upgt_init; + ifp->if_ioctl = upgt_ioctl; + ifp->if_start = upgt_start; + IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); + IFQ_SET_READY(&ifp->if_snd); + + ic = ifp->if_l2com; + ic->ic_ifp = ifp; + ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ + ic->ic_opmode = IEEE80211_M_STA; + /* set device capabilities */ + ic->ic_caps = + IEEE80211_C_STA /* station mode */ + | IEEE80211_C_MONITOR /* monitor mode */ + | IEEE80211_C_SHPREAMBLE /* short preamble supported */ + | IEEE80211_C_SHSLOT /* short slot time supported */ + | IEEE80211_C_BGSCAN /* capable of bg scanning */ + | IEEE80211_C_WPA /* 802.11i */ + ; + + bands = 0; + setbit(&bands, IEEE80211_MODE_11B); + setbit(&bands, IEEE80211_MODE_11G); + ieee80211_init_channels(ic, NULL, &bands); + + ieee80211_ifattach(ic, sc->sc_myaddr); + ic->ic_raw_xmit = upgt_raw_xmit; + ic->ic_scan_start = upgt_scan_start; + ic->ic_scan_end = upgt_scan_end; + ic->ic_set_channel = upgt_set_channel; + + ic->ic_vap_create = upgt_vap_create; + ic->ic_vap_delete = upgt_vap_delete; + ic->ic_update_mcast = upgt_update_mcast; + + ieee80211_radiotap_attach(ic, + &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), + UPGT_TX_RADIOTAP_PRESENT, + &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), + UPGT_RX_RADIOTAP_PRESENT); + + upgt_sysctl_node(sc); + + if (bootverbose) + ieee80211_announce(ic); + + return (0); + +fail5: if_free(ifp); +fail4: usb2_transfer_unsetup(sc->sc_xfer, UPGT_N_XFERS); +fail3: upgt_free_rx(sc); +fail2: upgt_free_tx(sc); +fail1: mtx_destroy(&sc->sc_mtx); + + return (error); +} + +static void +upgt_txeof(struct usb2_xfer *xfer, struct upgt_data *data) +{ + struct upgt_softc *sc = xfer->priv_sc; + struct ifnet *ifp = sc->sc_ifp; + struct mbuf *m; + + UPGT_ASSERT_LOCKED(sc); + + /* + * Do any tx complete callback. Note this must be done before releasing + * the node reference. + */ + if (data->m) { + m = data->m; + if (m->m_flags & M_TXCB) { + /* XXX status? */ + ieee80211_process_callback(data->ni, m, 0); + } + m_freem(m); + data->m = NULL; + } + if (data->ni) { + ieee80211_free_node(data->ni); + data->ni = NULL; + } + ifp->if_opackets++; +} + +static void +upgt_get_stats(struct upgt_softc *sc) +{ + struct upgt_data *data_cmd; + struct upgt_lmac_mem *mem; + struct upgt_lmac_stats *stats; + + data_cmd = upgt_getbuf(sc); + if (data_cmd == NULL) { + device_printf(sc->sc_dev, "%s: out of buffer.\n", __func__); + return; + } + + /* + * Transmit the URB containing the CMD data. + */ + bzero(data_cmd->buf, MCLBYTES); + + mem = (struct upgt_lmac_mem *)data_cmd->buf; + mem->addr = htole32(sc->sc_memaddr_frame_start + + UPGT_MEMSIZE_FRAME_HEAD); + + stats = (struct upgt_lmac_stats *)(mem + 1); + + stats->header1.flags = 0; + stats->header1.type = UPGT_H1_TYPE_CTRL; + stats->header1.len = htole16( + sizeof(struct upgt_lmac_stats) - sizeof(struct upgt_lmac_header)); + + stats->header2.reqid = htole32(sc->sc_memaddr_frame_start); + stats->header2.type = htole16(UPGT_H2_TYPE_STATS); + stats->header2.flags = 0; + + data_cmd->buflen = sizeof(*mem) + sizeof(*stats); + + mem->chksum = upgt_chksum_le((uint32_t *)stats, + data_cmd->buflen - sizeof(*mem)); + + upgt_bulk_tx(sc, data_cmd); +} + +static int +upgt_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) +{ + struct upgt_softc *sc = ifp->if_softc; + struct ieee80211com *ic = ifp->if_l2com; + struct ifreq *ifr = (struct ifreq *) data; + int error = 0, startall = 0; + + switch (cmd) { + case SIOCSIFFLAGS: + mtx_lock(&Giant); + if (ifp->if_flags & IFF_UP) { + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + if ((ifp->if_flags ^ sc->sc_if_flags) & + (IFF_ALLMULTI | IFF_PROMISC)) + upgt_set_multi(sc); + } else { + upgt_init(sc); + startall = 1; + } + } else { + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + upgt_stop(sc); + } + sc->sc_if_flags = ifp->if_flags; + if (startall) + ieee80211_start_all(ic); + mtx_unlock(&Giant); + break; + case SIOCGIFMEDIA: + error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); + break; + case SIOCGIFADDR: + error = ether_ioctl(ifp, cmd, data); + break; + default: + error = EINVAL; + break; + } + return error; +} + +static void +upgt_stop_locked(struct upgt_softc *sc) +{ + struct ifnet *ifp = sc->sc_ifp; + + UPGT_ASSERT_LOCKED(sc); + + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + upgt_set_macfilter(sc, IEEE80211_S_INIT); + upgt_abort_xfers_locked(sc); +} + +static void +upgt_stop(struct upgt_softc *sc) +{ + struct ifnet *ifp = sc->sc_ifp; + + UPGT_LOCK(sc); + upgt_stop_locked(sc); + UPGT_UNLOCK(sc); + + /* device down */ + sc->sc_tx_timer = 0; + ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); + sc->sc_flags &= ~UPGT_FLAG_INITDONE; +} + +static void +upgt_set_led(struct upgt_softc *sc, int action) +{ + struct upgt_data *data_cmd; + struct upgt_lmac_mem *mem; + struct upgt_lmac_led *led; + + data_cmd = upgt_getbuf(sc); + if (data_cmd == NULL) { + device_printf(sc->sc_dev, "%s: out of buffers.\n", __func__); + return; + } + + /* + * Transmit the URB containing the CMD data. + */ + bzero(data_cmd->buf, MCLBYTES); + + mem = (struct upgt_lmac_mem *)data_cmd->buf; + mem->addr = htole32(sc->sc_memaddr_frame_start + + UPGT_MEMSIZE_FRAME_HEAD); + + led = (struct upgt_lmac_led *)(mem + 1); + + led->header1.flags = UPGT_H1_FLAGS_TX_NO_CALLBACK; + led->header1.type = UPGT_H1_TYPE_CTRL; + led->header1.len = htole16( + sizeof(struct upgt_lmac_led) - + sizeof(struct upgt_lmac_header)); + + led->header2.reqid = htole32(sc->sc_memaddr_frame_start); + led->header2.type = htole16(UPGT_H2_TYPE_LED); + led->header2.flags = 0; + + switch (action) { + case UPGT_LED_OFF: + led->mode = htole16(UPGT_LED_MODE_SET); + led->action_fix = 0; + led->action_tmp = htole16(UPGT_LED_ACTION_OFF); + led->action_tmp_dur = 0; + break; + case UPGT_LED_ON: + led->mode = htole16(UPGT_LED_MODE_SET); + led->action_fix = 0; + led->action_tmp = htole16(UPGT_LED_ACTION_ON); + led->action_tmp_dur = 0; + break; + case UPGT_LED_BLINK: + if (sc->sc_state != IEEE80211_S_RUN) { + STAILQ_INSERT_TAIL(&sc->sc_tx_inactive, data_cmd, next); + return; + } + if (sc->sc_led_blink) { + /* previous blink was not finished */ + STAILQ_INSERT_TAIL(&sc->sc_tx_inactive, data_cmd, next); + return; + } + led->mode = htole16(UPGT_LED_MODE_SET); + led->action_fix = htole16(UPGT_LED_ACTION_OFF); + led->action_tmp = htole16(UPGT_LED_ACTION_ON); + led->action_tmp_dur = htole16(UPGT_LED_ACTION_TMP_DUR); + /* lock blink */ + sc->sc_led_blink = 1; + callout_reset(&sc->sc_led_ch, hz, upgt_set_led_blink, sc); + break; + default: + STAILQ_INSERT_TAIL(&sc->sc_tx_inactive, data_cmd, next); + return; + } + + data_cmd->buflen = sizeof(*mem) + sizeof(*led); + + mem->chksum = upgt_chksum_le((uint32_t *)led, + data_cmd->buflen - sizeof(*mem)); + + upgt_bulk_tx(sc, data_cmd); +} + +static void +upgt_set_led_blink(void *arg) +{ + struct upgt_softc *sc = arg; + + /* blink finished, we are ready for a next one */ + sc->sc_led_blink = 0; +} + +static void +upgt_init(void *priv) +{ + struct upgt_softc *sc = priv; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + + UPGT_LOCK(sc); + upgt_init_locked(sc); + UPGT_UNLOCK(sc); + + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + ieee80211_start_all(ic); /* start all vap's */ +} + +static void +upgt_init_locked(struct upgt_softc *sc) +{ + struct ifnet *ifp = sc->sc_ifp; + + UPGT_ASSERT_LOCKED(sc); + + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + upgt_stop_locked(sc); + + usb2_transfer_start(sc->sc_xfer[UPGT_BULK_RX]); + + (void)upgt_set_macfilter(sc, IEEE80211_S_SCAN); + + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + ifp->if_drv_flags |= IFF_DRV_RUNNING; + sc->sc_flags |= UPGT_FLAG_INITDONE; + + callout_reset(&sc->sc_watchdog_ch, hz, upgt_watchdog, sc); +} + +static int +upgt_set_macfilter(struct upgt_softc *sc, uint8_t state) +{ + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + struct ieee80211_node *ni = vap->iv_bss; + struct upgt_data *data_cmd; + struct upgt_lmac_mem *mem; + struct upgt_lmac_filter *filter; + uint8_t broadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + + UPGT_ASSERT_LOCKED(sc); + + data_cmd = upgt_getbuf(sc); + if (data_cmd == NULL) { + device_printf(sc->sc_dev, "out of TX buffers.\n"); + return (ENOBUFS); + } + + /* + * Transmit the URB containing the CMD data. + */ + bzero(data_cmd->buf, MCLBYTES); + + mem = (struct upgt_lmac_mem *)data_cmd->buf; + mem->addr = htole32(sc->sc_memaddr_frame_start + + UPGT_MEMSIZE_FRAME_HEAD); + + filter = (struct upgt_lmac_filter *)(mem + 1); + + filter->header1.flags = UPGT_H1_FLAGS_TX_NO_CALLBACK; + filter->header1.type = UPGT_H1_TYPE_CTRL; + filter->header1.len = htole16( + sizeof(struct upgt_lmac_filter) - + sizeof(struct upgt_lmac_header)); + + filter->header2.reqid = htole32(sc->sc_memaddr_frame_start); + filter->header2.type = htole16(UPGT_H2_TYPE_MACFILTER); + filter->header2.flags = 0; + + switch (state) { + case IEEE80211_S_INIT: + DPRINTF(sc, UPGT_DEBUG_STATE, "%s: set MAC filter to INIT\n", + __func__); + filter->type = htole16(UPGT_FILTER_TYPE_RESET); + break; + case IEEE80211_S_SCAN: + DPRINTF(sc, UPGT_DEBUG_STATE, + "set MAC filter to SCAN (bssid %s)\n", + ether_sprintf(broadcast)); + filter->type = htole16(UPGT_FILTER_TYPE_NONE); + IEEE80211_ADDR_COPY(filter->dst, sc->sc_myaddr); + IEEE80211_ADDR_COPY(filter->src, broadcast); + filter->unknown1 = htole16(UPGT_FILTER_UNKNOWN1); + filter->rxaddr = htole32(sc->sc_memaddr_rx_start); + filter->unknown2 = htole16(UPGT_FILTER_UNKNOWN2); + filter->rxhw = htole32(sc->sc_eeprom_hwrx); + filter->unknown3 = htole16(UPGT_FILTER_UNKNOWN3); + break; + case IEEE80211_S_RUN: + /* XXX monitor mode isn't tested yet. */ + if (vap->iv_opmode == IEEE80211_M_MONITOR) { + filter->type = htole16(UPGT_FILTER_TYPE_MONITOR); + IEEE80211_ADDR_COPY(filter->dst, sc->sc_myaddr); + IEEE80211_ADDR_COPY(filter->src, ni->ni_bssid); + filter->unknown1 = htole16(UPGT_FILTER_MONITOR_UNKNOWN1); + filter->rxaddr = htole32(sc->sc_memaddr_rx_start); + filter->unknown2 = htole16(UPGT_FILTER_MONITOR_UNKNOWN2); + filter->rxhw = htole32(sc->sc_eeprom_hwrx); + filter->unknown3 = htole16(UPGT_FILTER_MONITOR_UNKNOWN3); + } else { + DPRINTF(sc, UPGT_DEBUG_STATE, + "set MAC filter to RUN (bssid %s)\n", + ether_sprintf(ni->ni_bssid)); + filter->type = htole16(UPGT_FILTER_TYPE_STA); + IEEE80211_ADDR_COPY(filter->dst, sc->sc_myaddr); + IEEE80211_ADDR_COPY(filter->src, ni->ni_bssid); + filter->unknown1 = htole16(UPGT_FILTER_UNKNOWN1); + filter->rxaddr = htole32(sc->sc_memaddr_rx_start); + filter->unknown2 = htole16(UPGT_FILTER_UNKNOWN2); + filter->rxhw = htole32(sc->sc_eeprom_hwrx); + filter->unknown3 = htole16(UPGT_FILTER_UNKNOWN3); + } + break; + default: + device_printf(sc->sc_dev, + "MAC filter does not know that state!\n"); + break; + } + + data_cmd->buflen = sizeof(*mem) + sizeof(*filter); + + mem->chksum = upgt_chksum_le((uint32_t *)filter, + data_cmd->buflen - sizeof(*mem)); + + upgt_bulk_tx(sc, data_cmd); + + return (0); +} + +static void +upgt_setup_rates(struct ieee80211vap *vap, struct ieee80211com *ic) +{ + struct ifnet *ifp = ic->ic_ifp; + struct upgt_softc *sc = ifp->if_softc; + const struct ieee80211_txparam *tp; + + /* + * 0x01 = OFMD6 0x10 = DS1 + * 0x04 = OFDM9 0x11 = DS2 + * 0x06 = OFDM12 0x12 = DS5 + * 0x07 = OFDM18 0x13 = DS11 + * 0x08 = OFDM24 + * 0x09 = OFDM36 + * 0x0a = OFDM48 + * 0x0b = OFDM54 + */ + const uint8_t rateset_auto_11b[] = + { 0x13, 0x13, 0x12, 0x11, 0x11, 0x10, 0x10, 0x10 }; + const uint8_t rateset_auto_11g[] = + { 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x04, 0x01 }; + const uint8_t rateset_fix_11bg[] = + { 0x10, 0x11, 0x12, 0x13, 0x01, 0x04, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b }; + + tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; + + /* XXX */ + if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) { + /* + * Automatic rate control is done by the device. + * We just pass the rateset from which the device + * will pickup a rate. + */ + if (ic->ic_curmode == IEEE80211_MODE_11B) + bcopy(rateset_auto_11b, sc->sc_cur_rateset, + sizeof(sc->sc_cur_rateset)); + if (ic->ic_curmode == IEEE80211_MODE_11G || + ic->ic_curmode == IEEE80211_MODE_AUTO) + bcopy(rateset_auto_11g, sc->sc_cur_rateset, + sizeof(sc->sc_cur_rateset)); + } else { + /* set a fixed rate */ + memset(sc->sc_cur_rateset, rateset_fix_11bg[tp->ucastrate], + sizeof(sc->sc_cur_rateset)); + } +} + +static void +upgt_set_multi(void *arg) +{ + struct upgt_softc *sc = arg; + struct ifnet *ifp = sc->sc_ifp; + + if (!(ifp->if_flags & IFF_UP)) + return; + + /* + * XXX don't know how to set a device. Lack of docs. Just try to set + * IFF_ALLMULTI flag here. + */ + IF_ADDR_LOCK(ifp); + ifp->if_flags |= IFF_ALLMULTI; + IF_ADDR_UNLOCK(ifp); +} + +static void +upgt_start(struct ifnet *ifp) +{ + struct upgt_softc *sc = ifp->if_softc; + struct upgt_data *data_tx; + struct ieee80211_node *ni; + struct mbuf *m; + + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) + return; + + UPGT_LOCK(sc); + for (;;) { + IFQ_DRV_DEQUEUE(&ifp->if_snd, m); + if (m == NULL) + break; + + data_tx = upgt_gettxbuf(sc); + if (data_tx == NULL) { + IFQ_DRV_PREPEND(&ifp->if_snd, m); + break; + } + + ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; + m->m_pkthdr.rcvif = NULL; + + if (upgt_tx_start(sc, m, ni, data_tx) != 0) { + STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, data_tx, next); + UPGT_STAT_INC(sc, st_tx_inactive); + ieee80211_free_node(ni); + ifp->if_oerrors++; + continue; + } + sc->sc_tx_timer = 5; + } + UPGT_UNLOCK(sc); +} + +static int +upgt_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, + const struct ieee80211_bpf_params *params) +{ + struct ieee80211com *ic = ni->ni_ic; + struct ifnet *ifp = ic->ic_ifp; + struct upgt_softc *sc = ifp->if_softc; + struct upgt_data *data_tx = NULL; + + /* prevent management frames from being sent if we're not ready */ + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { + m_freem(m); + ieee80211_free_node(ni); + return ENETDOWN; + } + + UPGT_LOCK(sc); + data_tx = upgt_gettxbuf(sc); + if (data_tx == NULL) { + ieee80211_free_node(ni); + m_freem(m); + UPGT_UNLOCK(sc); + return (ENOBUFS); + } + + if (upgt_tx_start(sc, m, ni, data_tx) != 0) { + STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, data_tx, next); + UPGT_STAT_INC(sc, st_tx_inactive); + ieee80211_free_node(ni); + ifp->if_oerrors++; + UPGT_UNLOCK(sc); + return (EIO); + } + UPGT_UNLOCK(sc); + + sc->sc_tx_timer = 5; + return (0); +} + +static void +upgt_watchdog(void *arg) +{ + struct upgt_softc *sc = arg; + struct ifnet *ifp = sc->sc_ifp; + + if (sc->sc_tx_timer > 0) { + if (--sc->sc_tx_timer == 0) { + device_printf(sc->sc_dev, "watchdog timeout\n"); + /* upgt_init(ifp); XXX needs a process context ? */ + ifp->if_oerrors++; + return; + } + callout_reset(&sc->sc_watchdog_ch, hz, upgt_watchdog, sc); + } +} + +static uint32_t +upgt_mem_alloc(struct upgt_softc *sc) +{ + int i; + + for (i = 0; i < sc->sc_memory.pages; i++) { + if (sc->sc_memory.page[i].used == 0) { + sc->sc_memory.page[i].used = 1; + return (sc->sc_memory.page[i].addr); + } + } + + return (0); +} + +static void +upgt_scan_start(struct ieee80211com *ic) +{ + /* do nothing. */ +} + +static void +upgt_scan_end(struct ieee80211com *ic) +{ + /* do nothing. */ +} + +static void +upgt_set_channel(struct ieee80211com *ic) +{ + struct upgt_softc *sc = ic->ic_ifp->if_softc; + + UPGT_LOCK(sc); + upgt_set_chan(sc, ic->ic_curchan); + UPGT_UNLOCK(sc); +} + +static void +upgt_set_chan(struct upgt_softc *sc, struct ieee80211_channel *c) +{ + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + struct upgt_data *data_cmd; + struct upgt_lmac_mem *mem; + struct upgt_lmac_channel *chan; + int channel; + + UPGT_ASSERT_LOCKED(sc); + + channel = ieee80211_chan2ieee(ic, c); + if (channel == 0 || channel == IEEE80211_CHAN_ANY) { + /* XXX should NEVER happen */ + device_printf(sc->sc_dev, + "%s: invalid channel %x\n", __func__, channel); + return; + } + + DPRINTF(sc, UPGT_DEBUG_STATE, "%s: channel %d\n", __func__, channel); + + data_cmd = upgt_getbuf(sc); + if (data_cmd == NULL) { + device_printf(sc->sc_dev, "%s: out of buffers.\n", __func__); + return; + } + /* + * Transmit the URB containing the CMD data. + */ + bzero(data_cmd->buf, MCLBYTES); + + mem = (struct upgt_lmac_mem *)data_cmd->buf; + mem->addr = htole32(sc->sc_memaddr_frame_start + + UPGT_MEMSIZE_FRAME_HEAD); + + chan = (struct upgt_lmac_channel *)(mem + 1); + + chan->header1.flags = UPGT_H1_FLAGS_TX_NO_CALLBACK; + chan->header1.type = UPGT_H1_TYPE_CTRL; + chan->header1.len = htole16( + sizeof(struct upgt_lmac_channel) - sizeof(struct upgt_lmac_header)); + + chan->header2.reqid = htole32(sc->sc_memaddr_frame_start); + chan->header2.type = htole16(UPGT_H2_TYPE_CHANNEL); + chan->header2.flags = 0; + + chan->unknown1 = htole16(UPGT_CHANNEL_UNKNOWN1); + chan->unknown2 = htole16(UPGT_CHANNEL_UNKNOWN2); + chan->freq6 = sc->sc_eeprom_freq6[channel]; + chan->settings = sc->sc_eeprom_freq6_settings; + chan->unknown3 = UPGT_CHANNEL_UNKNOWN3; + + bcopy(&sc->sc_eeprom_freq3[channel].data, chan->freq3_1, + sizeof(chan->freq3_1)); + bcopy(&sc->sc_eeprom_freq4[channel], chan->freq4, + sizeof(sc->sc_eeprom_freq4[channel])); + bcopy(&sc->sc_eeprom_freq3[channel].data, chan->freq3_2, + sizeof(chan->freq3_2)); + + data_cmd->buflen = sizeof(*mem) + sizeof(*chan); + + mem->chksum = upgt_chksum_le((uint32_t *)chan, + data_cmd->buflen - sizeof(*mem)); + + upgt_bulk_tx(sc, data_cmd); +} + +static struct ieee80211vap * +upgt_vap_create(struct ieee80211com *ic, + const char name[IFNAMSIZ], int unit, int opmode, int flags, + const uint8_t bssid[IEEE80211_ADDR_LEN], + const uint8_t mac[IEEE80211_ADDR_LEN]) +{ + struct upgt_vap *uvp; + struct ieee80211vap *vap; + + if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ + return NULL; + uvp = (struct upgt_vap *) malloc(sizeof(struct upgt_vap), + M_80211_VAP, M_NOWAIT | M_ZERO); + if (uvp == NULL) + return NULL; + vap = &uvp->vap; + /* enable s/w bmiss handling for sta mode */ + ieee80211_vap_setup(ic, vap, name, unit, opmode, + flags | IEEE80211_CLONE_NOBEACONS, bssid, mac); + + /* override state transition machine */ + uvp->newstate = vap->iv_newstate; + vap->iv_newstate = upgt_newstate; + + /* setup device rates */ + upgt_setup_rates(vap, ic); + + /* complete setup */ + ieee80211_vap_attach(vap, ieee80211_media_change, + ieee80211_media_status); + ic->ic_opmode = opmode; + return vap; +} + +static int +upgt_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) +{ + struct upgt_vap *uvp = UPGT_VAP(vap); + struct ieee80211com *ic = vap->iv_ic; + struct upgt_softc *sc = ic->ic_ifp->if_softc; + + /* do it in a process context */ + sc->sc_state = nstate; + + IEEE80211_UNLOCK(ic); + UPGT_LOCK(sc); + callout_stop(&sc->sc_led_ch); + callout_stop(&sc->sc_watchdog_ch); + + switch (nstate) { + case IEEE80211_S_INIT: + /* do not accept any frames if the device is down */ + (void)upgt_set_macfilter(sc, sc->sc_state); + upgt_set_led(sc, UPGT_LED_OFF); + break; + case IEEE80211_S_SCAN: + upgt_set_chan(sc, ic->ic_curchan); + break; + case IEEE80211_S_AUTH: + upgt_set_chan(sc, ic->ic_curchan); + break; + case IEEE80211_S_ASSOC: + break; + case IEEE80211_S_RUN: + upgt_set_macfilter(sc, sc->sc_state); + upgt_set_led(sc, UPGT_LED_ON); + break; + default: + break; + } + UPGT_UNLOCK(sc); + IEEE80211_LOCK(ic); + return (uvp->newstate(vap, nstate, arg)); +} + +static void +upgt_vap_delete(struct ieee80211vap *vap) +{ + struct upgt_vap *uvp = UPGT_VAP(vap); + + ieee80211_vap_detach(vap); + free(uvp, M_80211_VAP); +} + +static void +upgt_update_mcast(struct ifnet *ifp) +{ + struct upgt_softc *sc = ifp->if_softc; + + upgt_set_multi(sc); +} + +static int +upgt_eeprom_parse(struct upgt_softc *sc) +{ + struct upgt_eeprom_header *eeprom_header; + struct upgt_eeprom_option *eeprom_option; + uint16_t option_len; + uint16_t option_type; + uint16_t preamble_len; + int option_end = 0; + + /* calculate eeprom options start offset */ + eeprom_header = (struct upgt_eeprom_header *)sc->sc_eeprom; + preamble_len = le16toh(eeprom_header->preamble_len); + eeprom_option = (struct upgt_eeprom_option *)(sc->sc_eeprom + + (sizeof(struct upgt_eeprom_header) + preamble_len)); + + while (!option_end) { + /* the eeprom option length is stored in words */ + option_len = + (le16toh(eeprom_option->len) - 1) * sizeof(uint16_t); + option_type = + le16toh(eeprom_option->type); + + switch (option_type) { + case UPGT_EEPROM_TYPE_NAME: + DPRINTF(sc, UPGT_DEBUG_FW, + "EEPROM name len=%d\n", option_len); + break; + case UPGT_EEPROM_TYPE_SERIAL: + DPRINTF(sc, UPGT_DEBUG_FW, + "EEPROM serial len=%d\n", option_len); + break; + case UPGT_EEPROM_TYPE_MAC: + DPRINTF(sc, UPGT_DEBUG_FW, + "EEPROM mac len=%d\n", option_len); + + IEEE80211_ADDR_COPY(sc->sc_myaddr, eeprom_option->data); + break; + case UPGT_EEPROM_TYPE_HWRX: + DPRINTF(sc, UPGT_DEBUG_FW, + "EEPROM hwrx len=%d\n", option_len); + + upgt_eeprom_parse_hwrx(sc, eeprom_option->data); + break; + case UPGT_EEPROM_TYPE_CHIP: + DPRINTF(sc, UPGT_DEBUG_FW, + "EEPROM chip len=%d\n", option_len); + break; + case UPGT_EEPROM_TYPE_FREQ3: + DPRINTF(sc, UPGT_DEBUG_FW, + "EEPROM freq3 len=%d\n", option_len); + + upgt_eeprom_parse_freq3(sc, eeprom_option->data, + option_len); + break; + case UPGT_EEPROM_TYPE_FREQ4: + DPRINTF(sc, UPGT_DEBUG_FW, + "EEPROM freq4 len=%d\n", option_len); + + upgt_eeprom_parse_freq4(sc, eeprom_option->data, + option_len); + break; + case UPGT_EEPROM_TYPE_FREQ5: + DPRINTF(sc, UPGT_DEBUG_FW, + "EEPROM freq5 len=%d\n", option_len); + break; + case UPGT_EEPROM_TYPE_FREQ6: + DPRINTF(sc, UPGT_DEBUG_FW, + "EEPROM freq6 len=%d\n", option_len); + + upgt_eeprom_parse_freq6(sc, eeprom_option->data, + option_len); + break; + case UPGT_EEPROM_TYPE_END: + DPRINTF(sc, UPGT_DEBUG_FW, + "EEPROM end len=%d\n", option_len); + option_end = 1; + break; + case UPGT_EEPROM_TYPE_OFF: + DPRINTF(sc, UPGT_DEBUG_FW, + "%s: EEPROM off without end option!\n", __func__); + return (EIO); + default: + DPRINTF(sc, UPGT_DEBUG_FW, + "EEPROM unknown type 0x%04x len=%d\n", + option_type, option_len); + break; + } + + /* jump to next EEPROM option */ + eeprom_option = (struct upgt_eeprom_option *) + (eeprom_option->data + option_len); + } + + return (0); +} + +static void +upgt_eeprom_parse_freq3(struct upgt_softc *sc, uint8_t *data, int len) +{ + struct upgt_eeprom_freq3_header *freq3_header; + struct upgt_lmac_freq3 *freq3; + int i, elements, flags; + unsigned channel; + + freq3_header = (struct upgt_eeprom_freq3_header *)data; + freq3 = (struct upgt_lmac_freq3 *)(freq3_header + 1); + + flags = freq3_header->flags; + elements = freq3_header->elements; + + DPRINTF(sc, UPGT_DEBUG_FW, "flags=0x%02x elements=%d\n", + flags, elements); + + for (i = 0; i < elements; i++) { + channel = ieee80211_mhz2ieee(le16toh(freq3[i].freq), 0); + if (!(channel >= 0 && channel < IEEE80211_CHAN_MAX)) + continue; + + sc->sc_eeprom_freq3[channel] = freq3[i]; + + DPRINTF(sc, UPGT_DEBUG_FW, "frequence=%d, channel=%d\n", + le16toh(sc->sc_eeprom_freq3[channel].freq), channel); + } +} + +void +upgt_eeprom_parse_freq4(struct upgt_softc *sc, uint8_t *data, int len) +{ + struct upgt_eeprom_freq4_header *freq4_header; + struct upgt_eeprom_freq4_1 *freq4_1; + struct upgt_eeprom_freq4_2 *freq4_2; + int i, j, elements, settings, flags; + unsigned channel; + + freq4_header = (struct upgt_eeprom_freq4_header *)data; + freq4_1 = (struct upgt_eeprom_freq4_1 *)(freq4_header + 1); + flags = freq4_header->flags; + elements = freq4_header->elements; + settings = freq4_header->settings; + + /* we need this value later */ + sc->sc_eeprom_freq6_settings = freq4_header->settings; + + DPRINTF(sc, UPGT_DEBUG_FW, "flags=0x%02x elements=%d settings=%d\n", + flags, elements, settings); + + for (i = 0; i < elements; i++) { + channel = ieee80211_mhz2ieee(le16toh(freq4_1[i].freq), 0); + if (!(channel >= 0 && channel < IEEE80211_CHAN_MAX)) + continue; + + freq4_2 = (struct upgt_eeprom_freq4_2 *)freq4_1[i].data; + for (j = 0; j < settings; j++) { + sc->sc_eeprom_freq4[channel][j].cmd = freq4_2[j]; + sc->sc_eeprom_freq4[channel][j].pad = 0; + } + + DPRINTF(sc, UPGT_DEBUG_FW, "frequence=%d, channel=%d\n", + le16toh(freq4_1[i].freq), channel); + } +} + +void +upgt_eeprom_parse_freq6(struct upgt_softc *sc, uint8_t *data, int len) +{ + struct upgt_lmac_freq6 *freq6; + int i, elements; + unsigned channel; + + freq6 = (struct upgt_lmac_freq6 *)data; + elements = len / sizeof(struct upgt_lmac_freq6); + + DPRINTF(sc, UPGT_DEBUG_FW, "elements=%d\n", elements); + + for (i = 0; i < elements; i++) { + channel = ieee80211_mhz2ieee(le16toh(freq6[i].freq), 0); + if (!(channel >= 0 && channel < IEEE80211_CHAN_MAX)) + continue; + + sc->sc_eeprom_freq6[channel] = freq6[i]; + + DPRINTF(sc, UPGT_DEBUG_FW, "frequence=%d, channel=%d\n", + le16toh(sc->sc_eeprom_freq6[channel].freq), channel); + } +} + +static void +upgt_eeprom_parse_hwrx(struct upgt_softc *sc, uint8_t *data) +{ + struct upgt_eeprom_option_hwrx *option_hwrx; + + option_hwrx = (struct upgt_eeprom_option_hwrx *)data; + + sc->sc_eeprom_hwrx = option_hwrx->rxfilter - UPGT_EEPROM_RX_CONST; + + DPRINTF(sc, UPGT_DEBUG_FW, "hwrx option value=0x%04x\n", + sc->sc_eeprom_hwrx); +} + +static int +upgt_eeprom_read(struct upgt_softc *sc) +{ + struct upgt_data *data_cmd; + struct upgt_lmac_mem *mem; + struct upgt_lmac_eeprom *eeprom; + int block, error, offset; + + UPGT_LOCK(sc); + usb2_pause_mtx(&sc->sc_mtx, 100); + + offset = 0; + block = UPGT_EEPROM_BLOCK_SIZE; + while (offset < UPGT_EEPROM_SIZE) { + DPRINTF(sc, UPGT_DEBUG_FW, + "request EEPROM block (offset=%d, len=%d)\n", offset, block); + + data_cmd = upgt_getbuf(sc); + if (data_cmd == NULL) { + UPGT_UNLOCK(sc); + return (ENOBUFS); + } + + /* + * Transmit the URB containing the CMD data. + */ + bzero(data_cmd->buf, MCLBYTES); + + mem = (struct upgt_lmac_mem *)data_cmd->buf; + mem->addr = htole32(sc->sc_memaddr_frame_start + + UPGT_MEMSIZE_FRAME_HEAD); + + eeprom = (struct upgt_lmac_eeprom *)(mem + 1); + eeprom->header1.flags = 0; + eeprom->header1.type = UPGT_H1_TYPE_CTRL; + eeprom->header1.len = htole16(( + sizeof(struct upgt_lmac_eeprom) - + sizeof(struct upgt_lmac_header)) + block); + + eeprom->header2.reqid = htole32(sc->sc_memaddr_frame_start); + eeprom->header2.type = htole16(UPGT_H2_TYPE_EEPROM); + eeprom->header2.flags = 0; + + eeprom->offset = htole16(offset); + eeprom->len = htole16(block); + + data_cmd->buflen = sizeof(*mem) + sizeof(*eeprom) + block; + + mem->chksum = upgt_chksum_le((uint32_t *)eeprom, + data_cmd->buflen - sizeof(*mem)); + upgt_bulk_tx(sc, data_cmd); + + error = mtx_sleep(sc, &sc->sc_mtx, 0, "eeprom_request", hz); + if (error != 0) { + device_printf(sc->sc_dev, + "timeout while waiting for EEPROM data!\n"); + UPGT_UNLOCK(sc); + return (EIO); + } + + offset += block; + if (UPGT_EEPROM_SIZE - offset < block) + block = UPGT_EEPROM_SIZE - offset; + } + + UPGT_UNLOCK(sc); + return (0); +} + +/* + * When a rx data came in the function returns a mbuf and a rssi values. + */ +static struct mbuf * +upgt_rxeof(struct usb2_xfer *xfer, struct upgt_data *data, int *rssi) +{ + struct mbuf *m = NULL; + struct upgt_softc *sc = xfer->priv_sc; + struct upgt_lmac_header *header; + struct upgt_lmac_eeprom *eeprom; + uint8_t h1_type; + uint16_t h2_type; + + UPGT_ASSERT_LOCKED(sc); + + if (xfer->actlen < 1) + return (NULL); + + /* Check only at the very beginning. */ + if (!(sc->sc_flags & UPGT_FLAG_FWLOADED) && + (memcmp(data->buf, "OK", 2) == 0)) { + sc->sc_flags |= UPGT_FLAG_FWLOADED; + wakeup_one(sc); + return (NULL); + } + + if (xfer->actlen < UPGT_RX_MINSZ) + return (NULL); + + /* + * Check what type of frame came in. + */ + header = (struct upgt_lmac_header *)(data->buf + 4); + + h1_type = header->header1.type; + h2_type = le16toh(header->header2.type); + + if (h1_type == UPGT_H1_TYPE_CTRL && h2_type == UPGT_H2_TYPE_EEPROM) { + eeprom = (struct upgt_lmac_eeprom *)(data->buf + 4); + uint16_t eeprom_offset = le16toh(eeprom->offset); + uint16_t eeprom_len = le16toh(eeprom->len); + + DPRINTF(sc, UPGT_DEBUG_FW, + "received EEPROM block (offset=%d, len=%d)\n", + eeprom_offset, eeprom_len); + + bcopy(data->buf + sizeof(struct upgt_lmac_eeprom) + 4, + sc->sc_eeprom + eeprom_offset, eeprom_len); + + /* EEPROM data has arrived in time, wakeup. */ + wakeup(sc); + } else if (h1_type == UPGT_H1_TYPE_CTRL && + h2_type == UPGT_H2_TYPE_TX_DONE) { + DPRINTF(sc, UPGT_DEBUG_XMIT, "%s: received 802.11 TX done\n", + __func__); + upgt_tx_done(sc, data->buf + 4); + } else if (h1_type == UPGT_H1_TYPE_RX_DATA || + h1_type == UPGT_H1_TYPE_RX_DATA_MGMT) { + DPRINTF(sc, UPGT_DEBUG_RECV, "%s: received 802.11 RX data\n", + __func__); + m = upgt_rx(sc, data->buf + 4, le16toh(header->header1.len), + rssi); + } else if (h1_type == UPGT_H1_TYPE_CTRL && + h2_type == UPGT_H2_TYPE_STATS) { + DPRINTF(sc, UPGT_DEBUG_STAT, "%s: received statistic data\n", + __func__); + /* TODO: what could we do with the statistic data? */ + } else { + /* ignore unknown frame types */ + DPRINTF(sc, UPGT_DEBUG_INTR, + "received unknown frame type 0x%02x\n", + header->header1.type); + } + return (m); +} + +/* + * The firmware awaits a checksum for each frame we send to it. + * The algorithm used therefor is uncommon but somehow similar to CRC32. + */ +static uint32_t +upgt_chksum_le(const uint32_t *buf, size_t size) +{ + int i; + uint32_t crc = 0; + + for (i = 0; i < size; i += sizeof(uint32_t)) { + crc = htole32(crc ^ *buf++); + crc = htole32((crc >> 5) ^ (crc << 3)); + } + + return (crc); +} + +static struct mbuf * +upgt_rx(struct upgt_softc *sc, uint8_t *data, int pkglen, int *rssi) +{ + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + struct upgt_lmac_rx_desc *rxdesc; + struct mbuf *m; + + /* + * don't pass packets to the ieee80211 framework if the driver isn't + * RUNNING. + */ + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) + return (NULL); + + /* access RX packet descriptor */ + rxdesc = (struct upgt_lmac_rx_desc *)data; + + /* create mbuf which is suitable for strict alignment archs */ + KASSERT((pkglen + ETHER_ALIGN) < MCLBYTES, + ("A current mbuf storage is small (%d)", pkglen + ETHER_ALIGN)); + m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); + if (m == NULL) { + device_printf(sc->sc_dev, "could not create RX mbuf!\n"); + return (NULL); + } + m_adj(m, ETHER_ALIGN); + bcopy(rxdesc->data, mtod(m, char *), pkglen); + /* trim FCS */ + m->m_len = m->m_pkthdr.len = pkglen - IEEE80211_CRC_LEN; + m->m_pkthdr.rcvif = ifp; + + if (ieee80211_radiotap_active(ic)) { + struct upgt_rx_radiotap_header *tap = &sc->sc_rxtap; + + tap->wr_flags = 0; + tap->wr_rate = upgt_rx_rate(sc, rxdesc->rate); + tap->wr_antsignal = rxdesc->rssi; + } + ifp->if_ipackets++; + + DPRINTF(sc, UPGT_DEBUG_RX_PROC, "%s: RX done\n", __func__); + *rssi = rxdesc->rssi; + return (m); +} + +static uint8_t +upgt_rx_rate(struct upgt_softc *sc, const int rate) +{ + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + static const uint8_t cck_upgt2rate[4] = { 2, 4, 11, 22 }; + static const uint8_t ofdm_upgt2rate[12] = + { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 }; + + if (ic->ic_curmode == IEEE80211_MODE_11B && + !(rate < 0 || rate > 3)) + return cck_upgt2rate[rate & 0xf]; + + if (ic->ic_curmode == IEEE80211_MODE_11G && + !(rate < 0 || rate > 11)) + return ofdm_upgt2rate[rate & 0xf]; + + return (0); +} + +static void +upgt_tx_done(struct upgt_softc *sc, uint8_t *data) +{ + struct ifnet *ifp = sc->sc_ifp; + struct upgt_lmac_tx_done_desc *desc; + int i, freed = 0; + + UPGT_ASSERT_LOCKED(sc); + + desc = (struct upgt_lmac_tx_done_desc *)data; + + for (i = 0; i < UPGT_TX_MAXCOUNT; i++) { + struct upgt_data *data_tx = &sc->sc_tx_data[i]; + + if (data_tx->addr == le32toh(desc->header2.reqid)) { + upgt_mem_free(sc, data_tx->addr); + data_tx->ni = NULL; + data_tx->addr = 0; + data_tx->m = NULL; + data_tx->use = 0; + + DPRINTF(sc, UPGT_DEBUG_TX_PROC, + "TX done: memaddr=0x%08x, status=0x%04x, rssi=%d, ", + le32toh(desc->header2.reqid), + le16toh(desc->status), le16toh(desc->rssi)); + DPRINTF(sc, UPGT_DEBUG_TX_PROC, "seq=%d\n", + le16toh(desc->seq)); + + freed++; + } + } + + if (freed != 0) { + sc->sc_tx_timer = 0; + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + UPGT_UNLOCK(sc); + upgt_start(ifp); + UPGT_LOCK(sc); + } +} + +static void +upgt_mem_free(struct upgt_softc *sc, uint32_t addr) +{ + int i; + + for (i = 0; i < sc->sc_memory.pages; i++) { + if (sc->sc_memory.page[i].addr == addr) { + sc->sc_memory.page[i].used = 0; + return; + } + } + + device_printf(sc->sc_dev, + "could not free memory address 0x%08x!\n", addr); +} + +static int +upgt_fw_load(struct upgt_softc *sc) +{ + const struct firmware *fw; + struct upgt_data *data_cmd; + struct upgt_fw_x2_header *x2; + char start_fwload_cmd[] = { 0x3c, 0x0d }; + int error = 0, offset, bsize, n; + uint32_t crc32; + + fw = firmware_get(upgt_fwname); + if (fw == NULL) { + device_printf(sc->sc_dev, "could not read microcode %s!\n", + upgt_fwname); + return (EIO); + } + + UPGT_LOCK(sc); + + /* send firmware start load command */ + data_cmd = upgt_getbuf(sc); + if (data_cmd == NULL) { + error = ENOBUFS; + goto fail; + } + data_cmd->buflen = sizeof(start_fwload_cmd); + bcopy(start_fwload_cmd, data_cmd->buf, data_cmd->buflen); + upgt_bulk_tx(sc, data_cmd); + + /* send X2 header */ + data_cmd = upgt_getbuf(sc); + if (data_cmd == NULL) { + error = ENOBUFS; + goto fail; + } + data_cmd->buflen = sizeof(struct upgt_fw_x2_header); + x2 = (struct upgt_fw_x2_header *)data_cmd->buf; + bcopy(UPGT_X2_SIGNATURE, x2->signature, UPGT_X2_SIGNATURE_SIZE); + x2->startaddr = htole32(UPGT_MEMADDR_FIRMWARE_START); + x2->len = htole32(fw->datasize); + x2->crc = upgt_crc32_le((uint8_t *)data_cmd->buf + + UPGT_X2_SIGNATURE_SIZE, + sizeof(struct upgt_fw_x2_header) - UPGT_X2_SIGNATURE_SIZE - + sizeof(uint32_t)); + upgt_bulk_tx(sc, data_cmd); + + /* download firmware */ + for (offset = 0; offset < fw->datasize; offset += bsize) { + if (fw->datasize - offset > UPGT_FW_BLOCK_SIZE) + bsize = UPGT_FW_BLOCK_SIZE; + else + bsize = fw->datasize - offset; + + data_cmd = upgt_getbuf(sc); + if (data_cmd == NULL) { + error = ENOBUFS; + goto fail; + } + n = upgt_fw_copy((const uint8_t *)fw->data + offset, + data_cmd->buf, bsize); + data_cmd->buflen = bsize; + upgt_bulk_tx(sc, data_cmd); + + DPRINTF(sc, UPGT_DEBUG_FW, "FW offset=%d, read=%d, sent=%d\n", + offset, n, bsize); + bsize = n; + } + DPRINTF(sc, UPGT_DEBUG_FW, "%s: firmware downloaded\n", __func__); + + /* load firmware */ + data_cmd = upgt_getbuf(sc); + if (data_cmd == NULL) { + error = ENOBUFS; + goto fail; + } + crc32 = upgt_crc32_le(fw->data, fw->datasize); + *((uint32_t *)(data_cmd->buf) ) = crc32; + *((uint8_t *)(data_cmd->buf) + 4) = 'g'; + *((uint8_t *)(data_cmd->buf) + 5) = '\r'; + data_cmd->buflen = 6; + upgt_bulk_tx(sc, data_cmd); + + /* waiting 'OK' response. */ + usb2_transfer_start(sc->sc_xfer[UPGT_BULK_RX]); + error = mtx_sleep(sc, &sc->sc_mtx, 0, "upgtfw", 2 * hz); + if (error != 0) { + device_printf(sc->sc_dev, "firmware load failed!\n"); + error = EIO; + } + + DPRINTF(sc, UPGT_DEBUG_FW, "%s: firmware loaded\n", __func__); +fail: + UPGT_UNLOCK(sc); + firmware_put(fw, FIRMWARE_UNLOAD); + return (error); +} + +static uint32_t +upgt_crc32_le(const void *buf, size_t size) +{ + uint32_t crc; + + crc = ether_crc32_le(buf, size); + + /* apply final XOR value as common for CRC-32 */ + crc = htole32(crc ^ 0xffffffffU); + + return (crc); +} + +/* + * While copying the version 2 firmware, we need to replace two characters: + * + * 0x7e -> 0x7d 0x5e + * 0x7d -> 0x7d 0x5d + */ +static int +upgt_fw_copy(const uint8_t *src, char *dst, int size) +{ + int i, j; + + for (i = 0, j = 0; i < size && j < size; i++) { + switch (src[i]) { + case 0x7e: + dst[j] = 0x7d; + j++; + dst[j] = 0x5e; + j++; + break; + case 0x7d: + dst[j] = 0x7d; + j++; + dst[j] = 0x5d; + j++; + break; + default: + dst[j] = src[i]; + j++; + break; + } + } + + return (i); +} + +static int +upgt_mem_init(struct upgt_softc *sc) +{ + int i; + + for (i = 0; i < UPGT_MEMORY_MAX_PAGES; i++) { + sc->sc_memory.page[i].used = 0; + + if (i == 0) { + /* + * The first memory page is always reserved for + * command data. + */ + sc->sc_memory.page[i].addr = + sc->sc_memaddr_frame_start + MCLBYTES; + } else { + sc->sc_memory.page[i].addr = + sc->sc_memory.page[i - 1].addr + MCLBYTES; + } + + if (sc->sc_memory.page[i].addr + MCLBYTES >= + sc->sc_memaddr_frame_end) + break; + + DPRINTF(sc, UPGT_DEBUG_FW, "memory address page %d=0x%08x\n", + i, sc->sc_memory.page[i].addr); + } + + sc->sc_memory.pages = i; + + DPRINTF(sc, UPGT_DEBUG_FW, "memory pages=%d\n", sc->sc_memory.pages); + return (0); +} + +static int +upgt_fw_verify(struct upgt_softc *sc) +{ + const struct firmware *fw; + const struct upgt_fw_bra_option *bra_opt; + const struct upgt_fw_bra_descr *descr; + const uint8_t *p; + const uint32_t *uc; + uint32_t bra_option_type, bra_option_len; + int offset, bra_end = 0, error = 0; + + fw = firmware_get(upgt_fwname); + if (fw == NULL) { + device_printf(sc->sc_dev, "could not read microcode %s!\n", + upgt_fwname); + return EIO; + } + + /* + * Seek to beginning of Boot Record Area (BRA). + */ + for (offset = 0; offset < fw->datasize; offset += sizeof(*uc)) { + uc = (const uint32_t *)((const uint8_t *)fw->data + offset); + if (*uc == 0) + break; + } + for (; offset < fw->datasize; offset += sizeof(*uc)) { + uc = (const uint32_t *)((const uint8_t *)fw->data + offset); + if (*uc != 0) + break; + } + if (offset == fw->datasize) { + device_printf(sc->sc_dev, + "firmware Boot Record Area not found!\n"); + error = EIO; + goto fail; + } + + DPRINTF(sc, UPGT_DEBUG_FW, + "firmware Boot Record Area found at offset %d\n", offset); + + /* + * Parse Boot Record Area (BRA) options. + */ + while (offset < fw->datasize && bra_end == 0) { + /* get current BRA option */ + p = (const uint8_t *)fw->data + offset; + bra_opt = (const struct upgt_fw_bra_option *)p; + bra_option_type = le32toh(bra_opt->type); + bra_option_len = le32toh(bra_opt->len) * sizeof(*uc); + + switch (bra_option_type) { + case UPGT_BRA_TYPE_FW: + DPRINTF(sc, UPGT_DEBUG_FW, "UPGT_BRA_TYPE_FW len=%d\n", + bra_option_len); + + if (bra_option_len != UPGT_BRA_FWTYPE_SIZE) { + device_printf(sc->sc_dev, + "wrong UPGT_BRA_TYPE_FW len!\n"); + error = EIO; + goto fail; + } + if (memcmp(UPGT_BRA_FWTYPE_LM86, bra_opt->data, + bra_option_len) == 0) { + sc->sc_fw_type = UPGT_FWTYPE_LM86; + break; + } + if (memcmp(UPGT_BRA_FWTYPE_LM87, bra_opt->data, + bra_option_len) == 0) { + sc->sc_fw_type = UPGT_FWTYPE_LM87; + break; + } + device_printf(sc->sc_dev, + "unsupported firmware type!\n"); + error = EIO; + goto fail; + case UPGT_BRA_TYPE_VERSION: + DPRINTF(sc, UPGT_DEBUG_FW, + "UPGT_BRA_TYPE_VERSION len=%d\n", bra_option_len); + break; + case UPGT_BRA_TYPE_DEPIF: + DPRINTF(sc, UPGT_DEBUG_FW, + "UPGT_BRA_TYPE_DEPIF len=%d\n", bra_option_len); + break; + case UPGT_BRA_TYPE_EXPIF: + DPRINTF(sc, UPGT_DEBUG_FW, + "UPGT_BRA_TYPE_EXPIF len=%d\n", bra_option_len); + break; + case UPGT_BRA_TYPE_DESCR: + DPRINTF(sc, UPGT_DEBUG_FW, + "UPGT_BRA_TYPE_DESCR len=%d\n", bra_option_len); + + descr = (const struct upgt_fw_bra_descr *)bra_opt->data; + + sc->sc_memaddr_frame_start = + le32toh(descr->memaddr_space_start); + sc->sc_memaddr_frame_end = + le32toh(descr->memaddr_space_end); + + DPRINTF(sc, UPGT_DEBUG_FW, + "memory address space start=0x%08x\n", + sc->sc_memaddr_frame_start); + DPRINTF(sc, UPGT_DEBUG_FW, + "memory address space end=0x%08x\n", + sc->sc_memaddr_frame_end); + break; + case UPGT_BRA_TYPE_END: + DPRINTF(sc, UPGT_DEBUG_FW, "UPGT_BRA_TYPE_END len=%d\n", + bra_option_len); + bra_end = 1; + break; + default: + DPRINTF(sc, UPGT_DEBUG_FW, "unknown BRA option len=%d\n", + bra_option_len); + error = EIO; + goto fail; + } + + /* jump to next BRA option */ + offset += sizeof(struct upgt_fw_bra_option) + bra_option_len; + } + + DPRINTF(sc, UPGT_DEBUG_FW, "%s: firmware verified", __func__); +fail: + firmware_put(fw, FIRMWARE_UNLOAD); + return (error); +} + +static void +upgt_bulk_tx(struct upgt_softc *sc, struct upgt_data *data) +{ + + UPGT_ASSERT_LOCKED(sc); + + STAILQ_INSERT_TAIL(&sc->sc_tx_pending, data, next); + UPGT_STAT_INC(sc, st_tx_pending); + usb2_transfer_start(sc->sc_xfer[UPGT_BULK_TX]); +} + +static int +upgt_device_reset(struct upgt_softc *sc) +{ + struct upgt_data *data; + char init_cmd[] = { 0x7e, 0x7e, 0x7e, 0x7e }; + + UPGT_LOCK(sc); + + data = upgt_getbuf(sc); + if (data == NULL) { + UPGT_UNLOCK(sc); + return (ENOBUFS); + } + bcopy(init_cmd, data->buf, sizeof(init_cmd)); + data->buflen = sizeof(init_cmd); + upgt_bulk_tx(sc, data); + usb2_pause_mtx(&sc->sc_mtx, 100); + + UPGT_UNLOCK(sc); + DPRINTF(sc, UPGT_DEBUG_FW, "%s: device initialized\n", __func__); + return (0); +} + +static int +upgt_alloc_tx(struct upgt_softc *sc) +{ + int i; + + STAILQ_INIT(&sc->sc_tx_active); + STAILQ_INIT(&sc->sc_tx_inactive); + STAILQ_INIT(&sc->sc_tx_pending); + + for (i = 0; i < UPGT_TX_MAXCOUNT; i++) { + struct upgt_data *data = &sc->sc_tx_data[i]; + + data->buf = malloc(MCLBYTES, M_USBDEV, M_NOWAIT | M_ZERO); + if (data->buf == NULL) { + device_printf(sc->sc_dev, + "could not allocate TX buffer!\n"); + return (ENOMEM); + } + STAILQ_INSERT_TAIL(&sc->sc_tx_inactive, data, next); + UPGT_STAT_INC(sc, st_tx_inactive); + } + + return (0); +} + +static int +upgt_alloc_rx(struct upgt_softc *sc) +{ + int i; + + STAILQ_INIT(&sc->sc_rx_active); + STAILQ_INIT(&sc->sc_rx_inactive); + + for (i = 0; i < UPGT_RX_MAXCOUNT; i++) { + struct upgt_data *data = &sc->sc_rx_data[i]; + + data->buf = malloc(MCLBYTES, M_USBDEV, M_NOWAIT | M_ZERO); + if (data->buf == NULL) { + device_printf(sc->sc_dev, + "could not allocate RX buffer!\n"); + return (ENOMEM); + } + STAILQ_INSERT_TAIL(&sc->sc_rx_inactive, data, next); + } + + return (0); +} + +static int +upgt_detach(device_t dev) +{ + struct upgt_softc *sc = device_get_softc(dev); + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + + if (!device_is_attached(dev)) + return 0; + + upgt_stop(sc); + + callout_drain(&sc->sc_led_ch); + callout_drain(&sc->sc_watchdog_ch); + + usb2_transfer_unsetup(sc->sc_xfer, UPGT_N_XFERS); + ieee80211_ifdetach(ic); + upgt_free_rx(sc); + upgt_free_tx(sc); + + if_free(ifp); + mtx_destroy(&sc->sc_mtx); + + return (0); +} + +static void +upgt_free_rx(struct upgt_softc *sc) +{ + int i; + + for (i = 0; i < UPGT_RX_MAXCOUNT; i++) { + struct upgt_data *data = &sc->sc_rx_data[i]; + + free(data->buf, M_USBDEV); + data->ni = NULL; + } +} + +static void +upgt_free_tx(struct upgt_softc *sc) +{ + int i; + + for (i = 0; i < UPGT_TX_MAXCOUNT; i++) { + struct upgt_data *data = &sc->sc_tx_data[i]; + + free(data->buf, M_USBDEV); + data->ni = NULL; + } +} + +static void +upgt_abort_xfers_locked(struct upgt_softc *sc) +{ + int i; + + UPGT_ASSERT_LOCKED(sc); + /* abort any pending transfers */ + for (i = 0; i < UPGT_N_XFERS; i++) + usb2_transfer_stop(sc->sc_xfer[i]); +} + +static void +upgt_abort_xfers(struct upgt_softc *sc) +{ + + UPGT_LOCK(sc); + upgt_abort_xfers_locked(sc); + UPGT_UNLOCK(sc); +} + +#define UPGT_SYSCTL_STAT_ADD32(c, h, n, p, d) \ + SYSCTL_ADD_UINT(c, h, OID_AUTO, n, CTLFLAG_RD, p, 0, d) + +static void +upgt_sysctl_node(struct upgt_softc *sc) +{ + struct sysctl_ctx_list *ctx; + struct sysctl_oid_list *child; + struct sysctl_oid *tree; + struct upgt_stat *stats; + + stats = &sc->sc_stat; + ctx = device_get_sysctl_ctx(sc->sc_dev); + child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->sc_dev)); + + tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "stats", CTLFLAG_RD, + NULL, "UPGT statistics"); + child = SYSCTL_CHILDREN(tree); + UPGT_SYSCTL_STAT_ADD32(ctx, child, "tx_active", + &stats->st_tx_active, "Active numbers in TX queue"); + UPGT_SYSCTL_STAT_ADD32(ctx, child, "tx_inactive", + &stats->st_tx_inactive, "Inactive numbers in TX queue"); + UPGT_SYSCTL_STAT_ADD32(ctx, child, "tx_pending", + &stats->st_tx_pending, "Pending numbers in TX queue"); +} + +#undef UPGT_SYSCTL_STAT_ADD32 + +static struct upgt_data * +_upgt_getbuf(struct upgt_softc *sc) +{ + struct upgt_data *bf; + + bf = STAILQ_FIRST(&sc->sc_tx_inactive); + if (bf != NULL) { + STAILQ_REMOVE_HEAD(&sc->sc_tx_inactive, next); + UPGT_STAT_DEC(sc, st_tx_inactive); + } else + bf = NULL; + if (bf == NULL) + DPRINTF(sc, UPGT_DEBUG_XMIT, "%s: %s\n", __func__, + "out of xmit buffers"); + return (bf); +} + +static struct upgt_data * +upgt_getbuf(struct upgt_softc *sc) +{ + struct upgt_data *bf; + + UPGT_ASSERT_LOCKED(sc); + + bf = _upgt_getbuf(sc); + if (bf == NULL) { + struct ifnet *ifp = sc->sc_ifp; + + DPRINTF(sc, UPGT_DEBUG_XMIT, "%s: stop queue\n", __func__); + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + } + + return (bf); +} + +static struct upgt_data * +upgt_gettxbuf(struct upgt_softc *sc) +{ + struct upgt_data *bf; + + UPGT_ASSERT_LOCKED(sc); + + bf = upgt_getbuf(sc); + if (bf == NULL) + return (NULL); + + bf->addr = upgt_mem_alloc(sc); + if (bf->addr == 0) { + struct ifnet *ifp = sc->sc_ifp; + + DPRINTF(sc, UPGT_DEBUG_XMIT, "%s: no free prism memory!\n", + __func__); + STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next); + UPGT_STAT_INC(sc, st_tx_inactive); + if (!(ifp->if_drv_flags & IFF_DRV_OACTIVE)) + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + return (NULL); + } + return (bf); +} + +static int +upgt_tx_start(struct upgt_softc *sc, struct mbuf *m, struct ieee80211_node *ni, + struct upgt_data *data) +{ + struct ieee80211vap *vap = ni->ni_vap; + int error = 0, len; + struct ieee80211_frame *wh; + struct ieee80211_key *k; + struct ifnet *ifp = sc->sc_ifp; + struct upgt_lmac_mem *mem; + struct upgt_lmac_tx_desc *txdesc; + + UPGT_ASSERT_LOCKED(sc); + + upgt_set_led(sc, UPGT_LED_BLINK); + + /* + * Software crypto. + */ + wh = mtod(m, struct ieee80211_frame *); + if (wh->i_fc[1] & IEEE80211_FC1_WEP) { + k = ieee80211_crypto_encap(ni, m); + if (k == NULL) { + device_printf(sc->sc_dev, + "ieee80211_crypto_encap returns NULL.\n"); + error = EIO; + goto done; + } + + /* in case packet header moved, reset pointer */ + wh = mtod(m, struct ieee80211_frame *); + } + + /* Transmit the URB containing the TX data. */ + bzero(data->buf, MCLBYTES); + mem = (struct upgt_lmac_mem *)data->buf; + mem->addr = htole32(data->addr); + txdesc = (struct upgt_lmac_tx_desc *)(mem + 1); + + if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == + IEEE80211_FC0_TYPE_MGT) { + /* mgmt frames */ + txdesc->header1.flags = UPGT_H1_FLAGS_TX_MGMT; + /* always send mgmt frames at lowest rate (DS1) */ + memset(txdesc->rates, 0x10, sizeof(txdesc->rates)); + } else { + /* data frames */ + txdesc->header1.flags = UPGT_H1_FLAGS_TX_DATA; + bcopy(sc->sc_cur_rateset, txdesc->rates, sizeof(txdesc->rates)); + } + txdesc->header1.type = UPGT_H1_TYPE_TX_DATA; + txdesc->header1.len = htole16(m->m_pkthdr.len); + txdesc->header2.reqid = htole32(data->addr); + txdesc->header2.type = htole16(UPGT_H2_TYPE_TX_ACK_YES); + txdesc->header2.flags = htole16(UPGT_H2_FLAGS_TX_ACK_YES); + txdesc->type = htole32(UPGT_TX_DESC_TYPE_DATA); + txdesc->pad3[0] = UPGT_TX_DESC_PAD3_SIZE; + + if (ieee80211_radiotap_active_vap(vap)) { + struct upgt_tx_radiotap_header *tap = &sc->sc_txtap; + + tap->wt_flags = 0; + tap->wt_rate = 0; /* XXX where to get from? */ + + ieee80211_radiotap_tx(vap, m); + } + + /* copy frame below our TX descriptor header */ + m_copydata(m, 0, m->m_pkthdr.len, + data->buf + (sizeof(*mem) + sizeof(*txdesc))); + /* calculate frame size */ + len = sizeof(*mem) + sizeof(*txdesc) + m->m_pkthdr.len; + /* we need to align the frame to a 4 byte boundary */ + len = (len + 3) & ~3; + /* calculate frame checksum */ + mem->chksum = upgt_chksum_le((uint32_t *)txdesc, len - sizeof(*mem)); + data->ni = ni; + data->m = m; + data->buflen = len; + + DPRINTF(sc, UPGT_DEBUG_XMIT, "%s: TX start data sending (%d bytes)\n", + __func__, len); + KASSERT(len <= MCLBYTES, ("mbuf is small for saving data")); + + upgt_bulk_tx(sc, data); +done: + /* + * If we don't regulary read the device statistics, the RX queue + * will stall. It's strange, but it works, so we keep reading + * the statistics here. *shrug* + */ + if (!(ifp->if_opackets % UPGT_TX_STAT_INTERVAL)) + upgt_get_stats(sc); + + return (error); +} + +static void +upgt_bulk_rx_callback(struct usb2_xfer *xfer) +{ + struct upgt_softc *sc = xfer->priv_sc; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; + struct ieee80211_frame *wh; + struct ieee80211_node *ni; + struct mbuf *m = NULL; + struct upgt_data *data; + int8_t nf; + int rssi = -1; + + UPGT_ASSERT_LOCKED(sc); + + switch (USB_GET_STATE(xfer)) { + case USB_ST_TRANSFERRED: + data = STAILQ_FIRST(&sc->sc_rx_active); + if (data == NULL) + goto setup; + STAILQ_REMOVE_HEAD(&sc->sc_rx_active, next); + m = upgt_rxeof(xfer, data, &rssi); + STAILQ_INSERT_TAIL(&sc->sc_rx_inactive, data, next); + /* FALLTHROUGH */ + case USB_ST_SETUP: +setup: + data = STAILQ_FIRST(&sc->sc_rx_inactive); + if (data == NULL) + return; + STAILQ_REMOVE_HEAD(&sc->sc_rx_inactive, next); + STAILQ_INSERT_TAIL(&sc->sc_rx_active, data, next); + usb2_set_frame_data(xfer, data->buf, 0); + xfer->frlengths[0] = xfer->max_data_length; + usb2_start_hardware(xfer); + + /* + * To avoid LOR we should unlock our private mutex here to call + * ieee80211_input() because here is at the end of a USB + * callback and safe to unlock. + */ + UPGT_UNLOCK(sc); + if (m != NULL) { + wh = mtod(m, struct ieee80211_frame *); + ni = ieee80211_find_rxnode(ic, + (struct ieee80211_frame_min *)wh); + nf = -95; /* XXX */ + if (ni != NULL) { + (void) ieee80211_input(ni, m, rssi, nf); + /* node is no longer needed */ + ieee80211_free_node(ni); + } else + (void) ieee80211_input_all(ic, m, rssi, nf); + m = NULL; + } + UPGT_LOCK(sc); + break; + default: + /* needs it to the inactive queue due to a error. */ + data = STAILQ_FIRST(&sc->sc_rx_active); + if (data != NULL) { + STAILQ_REMOVE_HEAD(&sc->sc_rx_active, next); + STAILQ_INSERT_TAIL(&sc->sc_rx_inactive, data, next); + } + if (xfer->error != USB_ERR_CANCELLED) { + xfer->flags.stall_pipe = 1; + ifp->if_ierrors++; + goto setup; + } + break; + } +} + +static void +upgt_bulk_tx_callback(struct usb2_xfer *xfer) +{ + struct upgt_softc *sc = xfer->priv_sc; + struct ifnet *ifp = sc->sc_ifp; + struct upgt_data *data; + + UPGT_ASSERT_LOCKED(sc); + switch (USB_GET_STATE(xfer)) { + case USB_ST_TRANSFERRED: + data = STAILQ_FIRST(&sc->sc_tx_active); + if (data == NULL) + goto setup; + STAILQ_REMOVE_HEAD(&sc->sc_tx_active, next); + UPGT_STAT_DEC(sc, st_tx_active); + upgt_txeof(xfer, data); + STAILQ_INSERT_TAIL(&sc->sc_tx_inactive, data, next); + UPGT_STAT_INC(sc, st_tx_inactive); + /* FALLTHROUGH */ + case USB_ST_SETUP: +setup: + data = STAILQ_FIRST(&sc->sc_tx_pending); + if (data == NULL) { + DPRINTF(sc, UPGT_DEBUG_XMIT, "%s: empty pending queue\n", + __func__); + return; + } + STAILQ_REMOVE_HEAD(&sc->sc_tx_pending, next); + UPGT_STAT_DEC(sc, st_tx_pending); + STAILQ_INSERT_TAIL(&sc->sc_tx_active, data, next); + UPGT_STAT_INC(sc, st_tx_active); + + usb2_set_frame_data(xfer, data->buf, 0); + xfer->frlengths[0] = data->buflen; + usb2_start_hardware(xfer); + UPGT_UNLOCK(sc); + upgt_start(ifp); + UPGT_LOCK(sc); + break; + default: + data = STAILQ_FIRST(&sc->sc_tx_active); + if (data == NULL) + goto setup; + if (data->ni != NULL) { + ieee80211_free_node(data->ni); + data->ni = NULL; + ifp->if_oerrors++; + } + if (xfer->error != USB_ERR_CANCELLED) { + xfer->flags.stall_pipe = 1; + goto setup; + } + break; + } +} + +static device_method_t upgt_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, upgt_match), + DEVMETHOD(device_attach, upgt_attach), + DEVMETHOD(device_detach, upgt_detach), + + { 0, 0 } +}; + +static driver_t upgt_driver = { + "upgt", + upgt_methods, + sizeof(struct upgt_softc) +}; + +static devclass_t upgt_devclass; + +DRIVER_MODULE(if_upgt, uhub, upgt_driver, upgt_devclass, NULL, 0); +MODULE_VERSION(if_upgt, 1); +MODULE_DEPEND(if_upgt, usb, 1, 1, 1); +MODULE_DEPEND(if_upgt, wlan, 1, 1, 1); +MODULE_DEPEND(if_upgt, upgtfw_fw, 1, 1, 1); diff --git a/sys/dev/usb/wlan/if_upgtvar.h b/sys/dev/usb/wlan/if_upgtvar.h new file mode 100644 index 000000000000..719d8c29186d --- /dev/null +++ b/sys/dev/usb/wlan/if_upgtvar.h @@ -0,0 +1,482 @@ +/* $OpenBSD: if_upgtvar.h,v 1.14 2008/02/02 13:48:44 mglocker Exp $ */ +/* $FreeBSD$ */ + +/* + * Copyright (c) 2007 Marcus Glocker <mglocker@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +struct upgt_softc; + +/* + * General values. + */ +enum { + UPGT_BULK_RX, + UPGT_BULK_TX, + UPGT_N_XFERS = 2, +}; + +#define UPGT_CONFIG_INDEX 0 +#define UPGT_IFACE_INDEX 0 +#define UPGT_USB_TIMEOUT 1000 +#define UPGT_FIRMWARE_TIMEOUT 10 + +#define UPGT_MEMADDR_FIRMWARE_START 0x00020000 /* 512 bytes large */ +#define UPGT_MEMSIZE_FRAME_HEAD 0x0070 +#define UPGT_MEMSIZE_RX 0x3500 + +#define UPGT_RX_MAXCOUNT 6 +#define UPGT_TX_MAXCOUNT 128 +#define UPGT_TX_STAT_INTERVAL 5 +#define UPGT_RX_MINSZ (sizeof(struct upgt_lmac_header) + 4) + +/* device flags */ +#define UPGT_DEVICE_ATTACHED (1 << 0) + +/* leds */ +#define UPGT_LED_OFF 0 +#define UPGT_LED_ON 1 +#define UPGT_LED_BLINK 2 + +/* + * Firmware. + */ +#define UPGT_FW_BLOCK_SIZE 256 + +#define UPGT_BRA_FWTYPE_SIZE 4 +#define UPGT_BRA_FWTYPE_LM86 "LM86" +#define UPGT_BRA_FWTYPE_LM87 "LM87" +enum upgt_fw_type { + UPGT_FWTYPE_LM86, + UPGT_FWTYPE_LM87 +}; + +#define UPGT_BRA_TYPE_FW 0x80000001 +#define UPGT_BRA_TYPE_VERSION 0x80000002 +#define UPGT_BRA_TYPE_DEPIF 0x80000003 +#define UPGT_BRA_TYPE_EXPIF 0x80000004 +#define UPGT_BRA_TYPE_DESCR 0x80000101 +#define UPGT_BRA_TYPE_END 0xff0000ff +struct upgt_fw_bra_option { + uint32_t type; + uint32_t len; + uint8_t data[]; +} __packed; + +struct upgt_fw_bra_descr { + uint32_t unknown1; + uint32_t memaddr_space_start; + uint32_t memaddr_space_end; + uint32_t unknown2; + uint32_t unknown3; + uint8_t rates[20]; +} __packed; + +#define UPGT_X2_SIGNATURE_SIZE 4 +#define UPGT_X2_SIGNATURE "x2 " +struct upgt_fw_x2_header { + uint8_t signature[4]; + uint32_t startaddr; + uint32_t len; + uint32_t crc; +} __packed; + +/* + * EEPROM. + */ +#define UPGT_EEPROM_SIZE 8192 +#define UPGT_EEPROM_BLOCK_SIZE 1020 + +struct upgt_eeprom_header { + /* 14 bytes */ + uint32_t magic; + uint16_t pad1; + uint16_t preamble_len; + uint32_t pad2; + /* data */ +} __packed; + +#define UPGT_EEPROM_TYPE_END 0x0000 +#define UPGT_EEPROM_TYPE_NAME 0x0001 +#define UPGT_EEPROM_TYPE_SERIAL 0x0003 +#define UPGT_EEPROM_TYPE_MAC 0x0101 +#define UPGT_EEPROM_TYPE_HWRX 0x1001 +#define UPGT_EEPROM_TYPE_CHIP 0x1002 +#define UPGT_EEPROM_TYPE_FREQ3 0x1903 +#define UPGT_EEPROM_TYPE_FREQ4 0x1904 +#define UPGT_EEPROM_TYPE_FREQ5 0x1905 +#define UPGT_EEPROM_TYPE_FREQ6 0x1906 +#define UPGT_EEPROM_TYPE_OFF 0xffff +struct upgt_eeprom_option { + uint16_t len; + uint16_t type; + uint8_t data[]; + /* data */ +} __packed; + +#define UPGT_EEPROM_RX_CONST 0x88 +struct upgt_eeprom_option_hwrx { + uint32_t pad1; + uint8_t rxfilter; + uint8_t pad2[15]; +} __packed; + +struct upgt_eeprom_freq3_header { + uint8_t flags; + uint8_t elements; +} __packed; + +struct upgt_eeprom_freq4_header { + uint8_t flags; + uint8_t elements; + uint8_t settings; + uint8_t type; +} __packed; + +struct upgt_eeprom_freq4_1 { + uint16_t freq; + uint8_t data[50]; +} __packed; + +struct upgt_eeprom_freq4_2 { + uint16_t head; + uint8_t subtails[4]; + uint8_t tail; +} __packed; + +/* + * LMAC protocol. + */ +struct upgt_lmac_mem { + uint32_t addr; + uint32_t chksum; +} __packed; + +#define UPGT_H1_FLAGS_TX_MGMT 0x00 /* for TX: mgmt frame */ +#define UPGT_H1_FLAGS_TX_NO_CALLBACK 0x01 /* for TX: no USB callback */ +#define UPGT_H1_FLAGS_TX_DATA 0x10 /* for TX: data frame */ +#define UPGT_H1_TYPE_RX_DATA 0x00 /* 802.11 RX data frame */ +#define UPGT_H1_TYPE_RX_DATA_MGMT 0x04 /* 802.11 RX mgmt frame */ +#define UPGT_H1_TYPE_TX_DATA 0x40 /* 802.11 TX data frame */ +#define UPGT_H1_TYPE_CTRL 0x80 /* control frame */ +struct upgt_lmac_h1 { + /* 4 bytes */ + uint8_t flags; + uint8_t type; + uint16_t len; +} __packed; + +#define UPGT_H2_TYPE_TX_ACK_NO 0x0000 +#define UPGT_H2_TYPE_TX_ACK_YES 0x0001 +#define UPGT_H2_TYPE_MACFILTER 0x0000 +#define UPGT_H2_TYPE_CHANNEL 0x0001 +#define UPGT_H2_TYPE_TX_DONE 0x0008 +#define UPGT_H2_TYPE_STATS 0x000a +#define UPGT_H2_TYPE_EEPROM 0x000c +#define UPGT_H2_TYPE_LED 0x000d +#define UPGT_H2_FLAGS_TX_ACK_NO 0x0101 +#define UPGT_H2_FLAGS_TX_ACK_YES 0x0707 +struct upgt_lmac_h2 { + /* 8 bytes */ + uint32_t reqid; + uint16_t type; + uint16_t flags; +} __packed; + +struct upgt_lmac_header { + /* 12 bytes */ + struct upgt_lmac_h1 header1; + struct upgt_lmac_h2 header2; +} __packed; + +struct upgt_lmac_eeprom { + /* 16 bytes */ + struct upgt_lmac_h1 header1; + struct upgt_lmac_h2 header2; + uint16_t offset; + uint16_t len; + /* data */ +} __packed; + +#define UPGT_FILTER_TYPE_NONE 0x0000 +#define UPGT_FILTER_TYPE_STA 0x0001 +#define UPGT_FILTER_TYPE_IBSS 0x0002 +#define UPGT_FILTER_TYPE_HOSTAP 0x0004 +#define UPGT_FILTER_TYPE_MONITOR 0x0010 +#define UPGT_FILTER_TYPE_RESET 0x0020 +#define UPGT_FILTER_UNKNOWN1 0x0002 +#define UPGT_FILTER_UNKNOWN2 0x0ca8 +#define UPGT_FILTER_UNKNOWN3 0xffff +#define UPGT_FILTER_MONITOR_UNKNOWN1 0x0000 +#define UPGT_FILTER_MONITOR_UNKNOWN2 0x0000 +#define UPGT_FILTER_MONITOR_UNKNOWN3 0x0000 +struct upgt_lmac_filter { + struct upgt_lmac_h1 header1; + struct upgt_lmac_h2 header2; + /* 32 bytes */ + uint16_t type; + uint8_t dst[IEEE80211_ADDR_LEN]; + uint8_t src[IEEE80211_ADDR_LEN]; + uint16_t unknown1; + uint32_t rxaddr; + uint16_t unknown2; + uint32_t rxhw; + uint16_t unknown3; + uint32_t unknown4; +} __packed; + +/* frequence 3 data */ +struct upgt_lmac_freq3 { + uint16_t freq; + uint8_t data[6]; +} __packed; + +/* frequence 4 data */ +struct upgt_lmac_freq4 { + struct upgt_eeprom_freq4_2 cmd; + uint8_t pad; +}; + +/* frequence 6 data */ +struct upgt_lmac_freq6 { + uint16_t freq; + uint8_t data[8]; +} __packed; + +#define UPGT_CHANNEL_UNKNOWN1 0x0001 +#define UPGT_CHANNEL_UNKNOWN2 0x0000 +#define UPGT_CHANNEL_UNKNOWN3 0x48 +struct upgt_lmac_channel { + struct upgt_lmac_h1 header1; + struct upgt_lmac_h2 header2; + /* 112 bytes */ + uint16_t unknown1; + uint16_t unknown2; + uint8_t pad1[20]; + struct upgt_lmac_freq6 freq6; + uint8_t settings; + uint8_t unknown3; + uint8_t freq3_1[4]; + struct upgt_lmac_freq4 freq4[8]; + uint8_t freq3_2[4]; + uint32_t pad2; +} __packed; + +#define UPGT_LED_MODE_SET 0x0003 +#define UPGT_LED_ACTION_OFF 0x0002 +#define UPGT_LED_ACTION_ON 0x0003 +#define UPGT_LED_ACTION_TMP_DUR 100 /* ms */ +struct upgt_lmac_led { + struct upgt_lmac_h1 header1; + struct upgt_lmac_h2 header2; + uint16_t mode; + uint16_t action_fix; + uint16_t action_tmp; + uint16_t action_tmp_dur; +} __packed; + +struct upgt_lmac_stats { + struct upgt_lmac_h1 header1; + struct upgt_lmac_h2 header2; + uint8_t data[76]; +} __packed; + +struct upgt_lmac_rx_desc { + struct upgt_lmac_h1 header1; + /* 16 bytes */ + uint16_t freq; + uint8_t unknown1; + uint8_t rate; + uint8_t rssi; + uint8_t pad; + uint16_t unknown2; + uint32_t timestamp; + uint32_t unknown3; + uint8_t data[]; +} __packed; + +#define UPGT_TX_DESC_KEY_EXISTS 0x01 +struct upgt_lmac_tx_desc_wep { + uint8_t key_exists; + uint8_t key_len; + uint8_t key_val[16]; +} __packed; + +#define UPGT_TX_DESC_TYPE_BEACON 0x00000000 +#define UPGT_TX_DESC_TYPE_PROBE 0x00000001 +#define UPGT_TX_DESC_TYPE_MGMT 0x00000002 +#define UPGT_TX_DESC_TYPE_DATA 0x00000004 +#define UPGT_TX_DESC_PAD3_SIZE 2 +struct upgt_lmac_tx_desc { + struct upgt_lmac_h1 header1; + struct upgt_lmac_h2 header2; + uint8_t rates[8]; + uint16_t pad1; + struct upgt_lmac_tx_desc_wep wep_key; + uint32_t type; + uint32_t pad2; + uint32_t unknown1; + uint32_t unknown2; + uint8_t pad3[2]; + /* 802.11 frame data */ +} __packed; + +#define UPGT_TX_DONE_DESC_STATUS_OK 0x0001 +struct upgt_lmac_tx_done_desc { + struct upgt_lmac_h1 header1; + struct upgt_lmac_h2 header2; + uint16_t status; + uint16_t rssi; + uint16_t seq; + uint16_t unknown; +} __packed; + +/* + * USB xfers. + */ +struct upgt_data { + uint8_t *buf; + uint32_t buflen; + struct ieee80211_node *ni; + struct mbuf *m; + uint32_t addr; + uint8_t use; + STAILQ_ENTRY(upgt_data) next; +}; +typedef STAILQ_HEAD(, upgt_data) upgt_datahead; + +/* + * Prism memory. + */ +struct upgt_memory_page { + uint8_t used; + uint32_t addr; +} __packed; + +#define UPGT_MEMORY_MAX_PAGES 8 +struct upgt_memory { + uint8_t pages; + struct upgt_memory_page page[UPGT_MEMORY_MAX_PAGES]; +} __packed; + +/* + * BPF + */ +struct upgt_rx_radiotap_header { + struct ieee80211_radiotap_header wr_ihdr; + uint8_t wr_flags; + uint8_t wr_rate; + uint16_t wr_chan_freq; + uint16_t wr_chan_flags; + int8_t wr_antsignal; +} __packed; + +#define UPGT_RX_RADIOTAP_PRESENT \ + ((1 << IEEE80211_RADIOTAP_FLAGS) | \ + (1 << IEEE80211_RADIOTAP_RATE) | \ + (1 << IEEE80211_RADIOTAP_CHANNEL) | \ + (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL)) + +struct upgt_tx_radiotap_header { + struct ieee80211_radiotap_header wt_ihdr; + uint8_t wt_flags; + uint8_t wt_rate; + uint16_t wt_chan_freq; + uint16_t wt_chan_flags; +} __packed; + +#define UPGT_TX_RADIOTAP_PRESENT \ + ((1 << IEEE80211_RADIOTAP_FLAGS) | \ + (1 << IEEE80211_RADIOTAP_RATE) | \ + (1 << IEEE80211_RADIOTAP_CHANNEL)) + +struct upgt_stat { + uint32_t st_tx_active; + uint32_t st_tx_inactive; + uint32_t st_tx_pending; +}; + +#define UPGT_STAT_INC(sc, var) (sc)->sc_stat.var++ +#define UPGT_STAT_DEC(sc, var) (sc)->sc_stat.var-- + +struct upgt_vap { + struct ieee80211vap vap; + int (*newstate)(struct ieee80211vap *, + enum ieee80211_state, int); +}; +#define UPGT_VAP(vap) ((struct upgt_vap *)(vap)) + +struct upgt_softc { + device_t sc_dev; + struct ifnet *sc_ifp; + struct usb2_device *sc_udev; + struct mtx sc_mtx; + struct upgt_stat sc_stat; + int sc_flags; +#define UPGT_FLAG_FWLOADED (1 << 0) +#define UPGT_FLAG_INITDONE (1 << 1) + int sc_if_flags; + int sc_debug; + + uint8_t sc_myaddr[IEEE80211_ADDR_LEN]; + + enum ieee80211_state sc_state; + int sc_arg; + int sc_led_blink; + struct callout sc_led_ch; + uint8_t sc_cur_rateset[8]; + + /* watchdog */ + int sc_tx_timer; + struct callout sc_watchdog_ch; + + /* Firmware. */ + int sc_fw_type; + /* memory addresses on device */ + uint32_t sc_memaddr_frame_start; + uint32_t sc_memaddr_frame_end; + uint32_t sc_memaddr_rx_start; + struct upgt_memory sc_memory; + + /* data which we found in the EEPROM */ + uint8_t sc_eeprom[UPGT_EEPROM_SIZE]; + uint16_t sc_eeprom_hwrx; + struct upgt_lmac_freq3 sc_eeprom_freq3[IEEE80211_CHAN_MAX]; + struct upgt_lmac_freq4 sc_eeprom_freq4[IEEE80211_CHAN_MAX][8]; + struct upgt_lmac_freq6 sc_eeprom_freq6[IEEE80211_CHAN_MAX]; + uint8_t sc_eeprom_freq6_settings; + + /* RX/TX */ + struct usb2_xfer *sc_xfer[UPGT_N_XFERS]; + int sc_rx_no; + int sc_tx_no; + struct upgt_data sc_rx_data[UPGT_RX_MAXCOUNT]; + upgt_datahead sc_rx_active; + upgt_datahead sc_rx_inactive; + struct upgt_data sc_tx_data[UPGT_TX_MAXCOUNT]; + upgt_datahead sc_tx_active; + upgt_datahead sc_tx_inactive; + upgt_datahead sc_tx_pending; + + /* BPF */ + struct upgt_rx_radiotap_header sc_rxtap; + int sc_rxtap_len; + struct upgt_tx_radiotap_header sc_txtap; + int sc_txtap_len; +}; + +#define UPGT_LOCK(sc) mtx_lock(&(sc)->sc_mtx) +#define UPGT_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx) +#define UPGT_ASSERT_LOCKED(sc) mtx_assert(&(sc)->sc_mtx, MA_OWNED) diff --git a/sys/dev/usb/wlan/if_ural.c b/sys/dev/usb/wlan/if_ural.c index 523cc61d40d7..7ff6a5e2bd4b 100644 --- a/sys/dev/usb/wlan/if_ural.c +++ b/sys/dev/usb/wlan/if_ural.c @@ -87,8 +87,8 @@ __FBSDID("$FreeBSD$"); #if USB_DEBUG static int ural_debug = 0; -SYSCTL_NODE(_hw_usb2, OID_AUTO, ural, CTLFLAG_RW, 0, "USB ural"); -SYSCTL_INT(_hw_usb2_ural, OID_AUTO, debug, CTLFLAG_RW, &ural_debug, 0, +SYSCTL_NODE(_hw_usb, OID_AUTO, ural, CTLFLAG_RW, 0, "USB ural"); +SYSCTL_INT(_hw_usb_ural, OID_AUTO, debug, CTLFLAG_RW, &ural_debug, 0, "Debug level"); #endif @@ -176,6 +176,7 @@ static void ural_set_chan(struct ural_softc *, struct ieee80211_channel *); static void ural_disable_rf_tune(struct ural_softc *); static void ural_enable_tsf_sync(struct ural_softc *); +static void ural_enable_tsf(struct ural_softc *); static void ural_update_slot(struct ifnet *); static void ural_set_txpreamble(struct ural_softc *); static void ural_set_basicrates(struct ural_softc *, @@ -413,7 +414,7 @@ ural_match(device_t self) { struct usb2_attach_arg *uaa = device_get_ivars(self); - if (uaa->usb2_mode != USB_MODE_HOST) + if (uaa->usb_mode != USB_MODE_HOST) return (ENXIO); if (uaa->info.bConfigIndex != 0) return (ENXIO); @@ -513,16 +514,11 @@ ural_attach(device_t self) ic->ic_vap_create = ural_vap_create; ic->ic_vap_delete = ural_vap_delete; - bpfattach(ifp, DLT_IEEE802_11_RADIO, - sizeof (struct ieee80211_frame) + sizeof(sc->sc_txtap)); - - sc->sc_rxtap_len = sizeof sc->sc_rxtap; - sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len); - sc->sc_rxtap.wr_ihdr.it_present = htole32(RAL_RX_RADIOTAP_PRESENT); - - sc->sc_txtap_len = sizeof sc->sc_txtap; - sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len); - sc->sc_txtap.wt_ihdr.it_present = htole32(RAL_TX_RADIOTAP_PRESENT); + ieee80211_radiotap_attach(ic, + &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), + RAL_TX_RADIOTAP_PRESENT, + &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), + RAL_RX_RADIOTAP_PRESENT); if (bootverbose) ieee80211_announce(ic); @@ -551,7 +547,6 @@ ural_detach(device_t self) if (ifp) { ic = ifp->if_l2com; - bpfdetach(ifp); ieee80211_ifdetach(ic); if_free(ifp); } @@ -761,9 +756,12 @@ ural_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) if (vap->iv_opmode != IEEE80211_M_MONITOR) ural_enable_tsf_sync(sc); + else + ural_enable_tsf(sc); /* enable automatic rate adaptation */ - tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_bsschan)]; + /* XXX should use ic_bsschan but not valid until after newstate call below */ + tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) ural_amrr_start(sc, ni); @@ -783,8 +781,7 @@ ural_bulk_write_callback(struct usb2_xfer *xfer) { struct ural_softc *sc = xfer->priv_sc; struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; - struct ieee80211_channel *c = ic->ic_curchan; + struct ieee80211vap *vap; struct ural_tx_data *data; struct mbuf *m; unsigned int len; @@ -819,16 +816,15 @@ tr_setup: usb2_m_copy_in(xfer->frbuffers, RAL_TX_DESC_SIZE, m, 0, m->m_pkthdr.len); - if (bpf_peers_present(ifp->if_bpf)) { + vap = data->ni->ni_vap; + if (ieee80211_radiotap_active_vap(vap)) { struct ural_tx_radiotap_header *tap = &sc->sc_txtap; tap->wt_flags = 0; tap->wt_rate = data->rate; - tap->wt_chan_freq = htole16(c->ic_freq); - tap->wt_chan_flags = htole16(c->ic_flags); tap->wt_antenna = sc->tx_ant; - bpf_mtap2(ifp->if_bpf, tap, sc->sc_txtap_len, m); + ieee80211_radiotap_tx(vap, m); } /* xfer length needs to be a multiple of two! */ @@ -877,7 +873,7 @@ ural_bulk_read_callback(struct usb2_xfer *xfer) struct ieee80211_node *ni; struct mbuf *m = NULL; uint32_t flags; - uint8_t rssi = 0; + int8_t rssi = 0, nf = 0; unsigned int len; switch (USB_GET_STATE(xfer)) { @@ -899,6 +895,7 @@ ural_bulk_read_callback(struct usb2_xfer *xfer) RAL_RX_DESC_SIZE); rssi = URAL_RSSI(sc->sc_rx_desc.rssi); + nf = RAL_NOISE_FLOOR; flags = le32toh(sc->sc_rx_desc.flags); if (flags & (RAL_RX_PHY_ERROR | RAL_RX_CRC_ERROR)) { /* @@ -923,19 +920,17 @@ ural_bulk_read_callback(struct usb2_xfer *xfer) m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = m->m_len = (flags >> 16) & 0xfff; - if (bpf_peers_present(ifp->if_bpf)) { + if (ieee80211_radiotap_active(ic)) { struct ural_rx_radiotap_header *tap = &sc->sc_rxtap; - tap->wr_flags = IEEE80211_RADIOTAP_F_FCS; + /* XXX set once */ + tap->wr_flags = 0; tap->wr_rate = ieee80211_plcp2rate(sc->sc_rx_desc.rate, (flags & RAL_RX_OFDM) ? IEEE80211_T_OFDM : IEEE80211_T_CCK); - tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq); - tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags); tap->wr_antenna = sc->rx_ant; - tap->wr_antsignal = rssi; - - bpf_mtap2(ifp->if_bpf, tap, sc->sc_rxtap_len, m); + tap->wr_antsignal = nf + rssi; + tap->wr_antnoise = nf; } /* Strip trailing 802.11 MAC FCS. */ m_adj(m, -IEEE80211_CRC_LEN); @@ -956,12 +951,10 @@ tr_setup: ni = ieee80211_find_rxnode(ic, mtod(m, struct ieee80211_frame_min *)); if (ni != NULL) { - (void) ieee80211_input(ni, m, rssi, - RAL_NOISE_FLOOR, 0); + (void) ieee80211_input(ni, m, rssi, nf); ieee80211_free_node(ni); } else - (void) ieee80211_input_all(ic, m, rssi, - RAL_NOISE_FLOOR, 0); + (void) ieee80211_input_all(ic, m, rssi, nf); RAL_LOCK(sc); } return; @@ -1799,6 +1792,14 @@ ural_enable_tsf_sync(struct ural_softc *sc) DPRINTF("enabling TSF synchronization\n"); } +static void +ural_enable_tsf(struct ural_softc *sc) +{ + /* first, disable TSF synchronization */ + ural_write(sc, RAL_TXRX_CSR19, 0); + ural_write(sc, RAL_TXRX_CSR19, RAL_ENABLE_TSF | RAL_ENABLE_TSF_SYNC(2)); +} + #define RAL_RXTX_TURNAROUND 5 /* us */ static void ural_update_slot(struct ifnet *ifp) diff --git a/sys/dev/usb/wlan/if_uralvar.h b/sys/dev/usb/wlan/if_uralvar.h index 5149f6b10d9a..663e0c178d6a 100644 --- a/sys/dev/usb/wlan/if_uralvar.h +++ b/sys/dev/usb/wlan/if_uralvar.h @@ -31,8 +31,9 @@ struct ural_rx_radiotap_header { uint8_t wr_rate; uint16_t wr_chan_freq; uint16_t wr_chan_flags; + int8_t wr_antsignal; + int8_t wr_antnoise; uint8_t wr_antenna; - uint8_t wr_antsignal; }; #define RAL_RX_RADIOTAP_PRESENT \ @@ -40,7 +41,8 @@ struct ural_rx_radiotap_header { (1 << IEEE80211_RADIOTAP_RATE) | \ (1 << IEEE80211_RADIOTAP_CHANNEL) | \ (1 << IEEE80211_RADIOTAP_ANTENNA) | \ - (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL)) + (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | \ + (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE)) struct ural_tx_radiotap_header { struct ieee80211_radiotap_header wt_ihdr; diff --git a/sys/dev/usb/wlan/if_zyd.c b/sys/dev/usb/wlan/if_zyd.c index c386ea87fb29..e08bcd0b604a 100644 --- a/sys/dev/usb/wlan/if_zyd.c +++ b/sys/dev/usb/wlan/if_zyd.c @@ -82,8 +82,8 @@ __FBSDID("$FreeBSD$"); #if USB_DEBUG static int zyd_debug = 0; -SYSCTL_NODE(_hw_usb2, OID_AUTO, zyd, CTLFLAG_RW, 0, "USB zyd"); -SYSCTL_INT(_hw_usb2_zyd, OID_AUTO, debug, CTLFLAG_RW, &zyd_debug, 0, +SYSCTL_NODE(_hw_usb, OID_AUTO, zyd, CTLFLAG_RW, 0, "USB zyd"); +SYSCTL_INT(_hw_usb_zyd, OID_AUTO, debug, CTLFLAG_RW, &zyd_debug, 0, "zyd debug level"); enum { @@ -320,7 +320,7 @@ zyd_match(device_t dev) { struct usb2_attach_arg *uaa = device_get_ivars(dev); - if (uaa->usb2_mode != USB_MODE_HOST) + if (uaa->usb_mode != USB_MODE_HOST) return (ENXIO); if (uaa->info.bConfigIndex != ZYD_CONFIG_INDEX) return (ENXIO); @@ -421,14 +421,11 @@ zyd_attach(device_t dev) ic->ic_update_mcast = zyd_update_mcast; ic->ic_update_promisc = zyd_update_mcast; - bpfattach(ifp, DLT_IEEE802_11_RADIO, - sizeof(struct ieee80211_frame) + sizeof(sc->sc_txtap)); - sc->sc_rxtap_len = sizeof(sc->sc_rxtap); - sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len); - sc->sc_rxtap.wr_ihdr.it_present = htole32(ZYD_RX_RADIOTAP_PRESENT); - sc->sc_txtap_len = sizeof(sc->sc_txtap); - sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len); - sc->sc_txtap.wt_ihdr.it_present = htole32(ZYD_TX_RADIOTAP_PRESENT); + ieee80211_radiotap_attach(ic, + &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), + ZYD_TX_RADIOTAP_PRESENT, + &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), + ZYD_RX_RADIOTAP_PRESENT); if (bootverbose) ieee80211_announce(ic); @@ -455,7 +452,6 @@ zyd_detach(device_t dev) if (ifp) { ic = ifp->if_l2com; - bpfdetach(ifp); ieee80211_ifdetach(ic); if_free(ifp); } @@ -2132,6 +2128,7 @@ zyd_rx_data(struct usb2_xfer *xfer, int offset, uint16_t len) { struct zyd_softc *sc = xfer->priv_sc; struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct zyd_plcphdr plcp; struct zyd_rx_stat stat; struct mbuf *m; @@ -2180,7 +2177,7 @@ zyd_rx_data(struct usb2_xfer *xfer, int offset, uint16_t len) usb2_copy_out(xfer->frbuffers, offset + sizeof(plcp), mtod(m, uint8_t *), rlen); - if (bpf_peers_present(ifp->if_bpf)) { + if (ieee80211_radiotap_active(ic)) { struct zyd_rx_radiotap_header *tap = &sc->sc_rxtap; tap->wr_flags = 0; @@ -2194,8 +2191,6 @@ zyd_rx_data(struct usb2_xfer *xfer, int offset, uint16_t len) IEEE80211_T_OFDM : IEEE80211_T_CCK); tap->wr_antsignal = stat.rssi + -95; tap->wr_antnoise = -95; /* XXX */ - - bpf_mtap2(ifp->if_bpf, tap, sc->sc_rxtap_len, m); } rssi = (stat.rssi > 63) ? 127 : 2 * stat.rssi; @@ -2272,10 +2267,10 @@ tr_setup: ni = ieee80211_find_rxnode(ic, mtod(m, struct ieee80211_frame_min *)); if (ni != NULL) { - (void)ieee80211_input(ni, m, rssi, nf, 0); + (void)ieee80211_input(ni, m, rssi, nf); ieee80211_free_node(ni); } else - (void)ieee80211_input_all(ic, m, rssi, nf, 0); + (void)ieee80211_input_all(ic, m, rssi, nf); } ZYD_LOCK(sc); break; @@ -2331,7 +2326,6 @@ zyd_tx_mgt(struct zyd_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) { struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; - struct ifnet *ifp = sc->sc_ifp; struct zyd_tx_desc *desc; struct zyd_tx_data *data; struct ieee80211_frame *wh; @@ -2409,13 +2403,13 @@ zyd_tx_mgt(struct zyd_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) desc->plcp_service |= ZYD_PLCP_LENGEXT; } - if (bpf_peers_present(ifp->if_bpf)) { + if (ieee80211_radiotap_active_vap(vap)) { struct zyd_tx_radiotap_header *tap = &sc->sc_txtap; tap->wt_flags = 0; tap->wt_rate = rate; - bpf_mtap2(ifp->if_bpf, tap, sc->sc_txtap_len, m0); + ieee80211_radiotap_tx(vap, m0); } DPRINTF(sc, ZYD_DEBUG_XMIT, @@ -2434,8 +2428,7 @@ zyd_bulk_write_callback(struct usb2_xfer *xfer) { struct zyd_softc *sc = xfer->priv_sc; struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; - struct ieee80211_channel *c = ic->ic_curchan; + struct ieee80211vap *vap; struct zyd_tx_data *data; struct mbuf *m; @@ -2470,15 +2463,14 @@ tr_setup: usb2_m_copy_in(xfer->frbuffers, ZYD_TX_DESC_SIZE, m, 0, m->m_pkthdr.len); - if (bpf_peers_present(ifp->if_bpf)) { + vap = data->ni->ni_vap; + if (ieee80211_radiotap_active_vap(vap)) { struct zyd_tx_radiotap_header *tap = &sc->sc_txtap; tap->wt_flags = 0; tap->wt_rate = data->rate; - tap->wt_chan_freq = htole16(c->ic_freq); - tap->wt_chan_flags = htole16(c->ic_flags); - bpf_mtap2(ifp->if_bpf, tap, sc->sc_txtap_len, m); + ieee80211_radiotap_tx(vap, m); } xfer->frlengths[0] = ZYD_TX_DESC_SIZE + m->m_pkthdr.len; |
