aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/usb
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/usb')
-rw-r--r--sys/dev/usb/README.TXT411
-rw-r--r--sys/dev/usb/bluetooth/ng_ubt.c2
-rw-r--r--sys/dev/usb/bluetooth/ubtbcmfw.c2
-rw-r--r--sys/dev/usb/controller/at91dci.c15
-rw-r--r--sys/dev/usb/controller/at91dci.h1
-rw-r--r--sys/dev/usb/controller/atmegadci.c54
-rw-r--r--sys/dev/usb/controller/atmegadci.h17
-rw-r--r--sys/dev/usb/controller/avr32dci.c2065
-rw-r--r--sys/dev/usb/controller/avr32dci.h254
-rw-r--r--sys/dev/usb/controller/ehci.c21
-rw-r--r--sys/dev/usb/controller/musb_otg.c15
-rw-r--r--sys/dev/usb/controller/musb_otg.h1
-rw-r--r--sys/dev/usb/controller/ohci.c8
-rw-r--r--sys/dev/usb/controller/uhci.c10
-rw-r--r--sys/dev/usb/controller/usb_controller.c6
-rw-r--r--sys/dev/usb/controller/uss820dci.c92
-rw-r--r--sys/dev/usb/controller/uss820dci.h26
-rw-r--r--sys/dev/usb/controller/uss820dci_atmelarm.c3
-rw-r--r--sys/dev/usb/input/uhid.c6
-rw-r--r--sys/dev/usb/input/ukbd.c6
-rw-r--r--sys/dev/usb/input/ums.c6
-rw-r--r--sys/dev/usb/misc/udbp.c6
-rw-r--r--sys/dev/usb/misc/ufm.c2
-rw-r--r--sys/dev/usb/net/if_aue.c6
-rw-r--r--sys/dev/usb/net/if_axe.c6
-rw-r--r--sys/dev/usb/net/if_cdce.c10
-rw-r--r--sys/dev/usb/net/if_cue.c6
-rw-r--r--sys/dev/usb/net/if_kue.c6
-rw-r--r--sys/dev/usb/net/if_rue.c6
-rw-r--r--sys/dev/usb/net/if_udav.c6
-rw-r--r--sys/dev/usb/serial/u3g.c217
-rw-r--r--sys/dev/usb/serial/uark.c2
-rw-r--r--sys/dev/usb/serial/ubsa.c6
-rw-r--r--sys/dev/usb/serial/ubser.c6
-rw-r--r--sys/dev/usb/serial/uchcom.c6
-rw-r--r--sys/dev/usb/serial/ucycom.c2
-rw-r--r--sys/dev/usb/serial/ufoma.c2
-rw-r--r--sys/dev/usb/serial/uftdi.c6
-rw-r--r--sys/dev/usb/serial/ugensa.c2
-rw-r--r--sys/dev/usb/serial/uipaq.c6
-rw-r--r--sys/dev/usb/serial/ulpt.c6
-rw-r--r--sys/dev/usb/serial/umct.c4
-rw-r--r--sys/dev/usb/serial/umodem.c6
-rw-r--r--sys/dev/usb/serial/umoscom.c6
-rw-r--r--sys/dev/usb/serial/uplcom.c6
-rw-r--r--sys/dev/usb/serial/usb_serial.c4
-rw-r--r--sys/dev/usb/serial/uslcom.c6
-rw-r--r--sys/dev/usb/serial/uvisor.c6
-rw-r--r--sys/dev/usb/serial/uvscom.c6
-rw-r--r--sys/dev/usb/storage/umass.c153
-rw-r--r--sys/dev/usb/storage/urio.c6
-rw-r--r--sys/dev/usb/storage/ustorage_fs.c12
-rw-r--r--sys/dev/usb/template/usb_template.c16
-rw-r--r--sys/dev/usb/usb_bus.h2
-rw-r--r--sys/dev/usb/usb_busdma.c2
-rw-r--r--sys/dev/usb/usb_compat_linux.c4
-rw-r--r--sys/dev/usb/usb_compat_linux.h2
-rw-r--r--sys/dev/usb/usb_controller.h2
-rw-r--r--sys/dev/usb/usb_core.h21
-rw-r--r--sys/dev/usb/usb_debug.c4
-rw-r--r--sys/dev/usb/usb_debug.h2
-rw-r--r--sys/dev/usb/usb_dev.c12
-rw-r--r--sys/dev/usb/usb_device.c50
-rw-r--r--sys/dev/usb/usb_device.h12
-rw-r--r--sys/dev/usb/usb_generic.c22
-rw-r--r--sys/dev/usb/usb_hid.c15
-rw-r--r--sys/dev/usb/usb_hub.c28
-rw-r--r--sys/dev/usb/usb_hub.h3
-rw-r--r--sys/dev/usb/usb_process.c4
-rw-r--r--sys/dev/usb/usb_request.c10
-rw-r--r--sys/dev/usb/usb_revision.h25
-rw-r--r--sys/dev/usb/usb_transfer.c50
-rw-r--r--sys/dev/usb/usb_transfer.h2
-rw-r--r--sys/dev/usb/usbdevs12
-rw-r--r--sys/dev/usb/wlan/if_rum.c61
-rw-r--r--sys/dev/usb/wlan/if_rumvar.h7
-rw-r--r--sys/dev/usb/wlan/if_uath.c91
-rw-r--r--sys/dev/usb/wlan/if_uathvar.h31
-rw-r--r--sys/dev/usb/wlan/if_upgt.c2395
-rw-r--r--sys/dev/usb/wlan/if_upgtvar.h482
-rw-r--r--sys/dev/usb/wlan/if_ural.c67
-rw-r--r--sys/dev/usb/wlan/if_uralvar.h6
-rw-r--r--sys/dev/usb/wlan/if_zyd.c44
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;