Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[cascardo/linux.git] / drivers / net / wireless / brcm80211 / brcmfmac / usb.c
index d06fcb0..4572def 100644 (file)
 #include <linux/vmalloc.h>
 
 #include <brcmu_utils.h>
+#include <brcm_hw_ids.h>
 #include <brcmu_wifi.h>
-#include <dhd_bus.h>
-#include <dhd_dbg.h>
-
+#include "bus.h"
+#include "debug.h"
 #include "firmware.h"
-#include "usb_rdl.h"
 #include "usb.h"
 
-#define IOCTL_RESP_TIMEOUT  2000
+
+#define IOCTL_RESP_TIMEOUT             2000
 
 #define BRCMF_USB_RESET_GETVER_SPINWAIT        100     /* in unit of ms */
 #define BRCMF_USB_RESET_GETVER_LOOP_CNT        10
 
 #define BRCMF_POSTBOOT_ID              0xA123  /* ID to detect if dongle
                                                   has boot up */
-#define BRCMF_USB_NRXQ 50
-#define BRCMF_USB_NTXQ 50
+#define BRCMF_USB_NRXQ                 50
+#define BRCMF_USB_NTXQ                 50
+
+#define BRCMF_USB_CBCTL_WRITE          0
+#define BRCMF_USB_CBCTL_READ           1
+#define BRCMF_USB_MAX_PKT_SIZE         1600
+
+#define BRCMF_USB_43143_FW_NAME                "brcm/brcmfmac43143.bin"
+#define BRCMF_USB_43236_FW_NAME                "brcm/brcmfmac43236b.bin"
+#define BRCMF_USB_43242_FW_NAME                "brcm/brcmfmac43242a.bin"
+#define BRCMF_USB_43569_FW_NAME                "brcm/brcmfmac43569.bin"
+
+#define TRX_MAGIC              0x30524448      /* "HDR0" */
+#define TRX_MAX_OFFSET         3               /* Max number of file offsets */
+#define TRX_UNCOMP_IMAGE       0x20            /* Trx holds uncompressed img */
+#define TRX_RDL_CHUNK          1500            /* size of each dl transfer */
+#define TRX_OFFSETS_DLFWLEN_IDX        0
+
+/* Control messages: bRequest values */
+#define DL_GETSTATE    0       /* returns the rdl_state_t struct */
+#define DL_CHECK_CRC   1       /* currently unused */
+#define DL_GO          2       /* execute downloaded image */
+#define DL_START       3       /* initialize dl state */
+#define DL_REBOOT      4       /* reboot the device in 2 seconds */
+#define DL_GETVER      5       /* returns the bootrom_id_t struct */
+#define DL_GO_PROTECTED        6       /* execute the downloaded code and set reset
+                                * event to occur in 2 seconds.  It is the
+                                * responsibility of the downloaded code to
+                                * clear this event
+                                */
+#define DL_EXEC                7       /* jump to a supplied address */
+#define DL_RESETCFG    8       /* To support single enum on dongle
+                                * - Not used by bootloader
+                                */
+#define DL_DEFER_RESP_OK 9     /* Potentially defer the response to setup
+                                * if resp unavailable
+                                */
+
+/* states */
+#define DL_WAITING     0       /* waiting to rx first pkt */
+#define DL_READY       1       /* hdr was good, waiting for more of the
+                                * compressed image
+                                */
+#define DL_BAD_HDR     2       /* hdr was corrupted */
+#define DL_BAD_CRC     3       /* compressed image was corrupted */
+#define DL_RUNNABLE    4       /* download was successful,waiting for go cmd */
+#define DL_START_FAIL  5       /* failed to initialize correctly */
+#define DL_NVRAM_TOOBIG        6       /* host specified nvram data exceeds DL_NVRAM
+                                * value
+                                */
+#define DL_IMAGE_TOOBIG        7       /* firmware image too big */
 
-#define CONFIGDESC(usb)         (&((usb)->actconfig)->desc)
-#define IFPTR(usb, idx)         ((usb)->actconfig->interface[(idx)])
-#define IFALTS(usb, idx)        (IFPTR((usb), (idx))->altsetting[0])
-#define IFDESC(usb, idx)        IFALTS((usb), (idx)).desc
-#define IFEPDESC(usb, idx, ep)  (IFALTS((usb), (idx)).endpoint[(ep)]).desc
 
-#define CONTROL_IF              0
-#define BULK_IF                 0
+struct trx_header_le {
+       __le32 magic;           /* "HDR0" */
+       __le32 len;             /* Length of file including header */
+       __le32 crc32;           /* CRC from flag_version to end of file */
+       __le32 flag_version;    /* 0:15 flags, 16:31 version */
+       __le32 offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of
+                                        * header
+                                        */
+};
 
-#define BRCMF_USB_CBCTL_WRITE  0
-#define BRCMF_USB_CBCTL_READ   1
-#define BRCMF_USB_MAX_PKT_SIZE 1600
+struct rdl_state_le {
+       __le32 state;
+       __le32 bytes;
+};
 
-#define BRCMF_USB_43143_FW_NAME        "brcm/brcmfmac43143.bin"
-#define BRCMF_USB_43236_FW_NAME        "brcm/brcmfmac43236b.bin"
-#define BRCMF_USB_43242_FW_NAME        "brcm/brcmfmac43242a.bin"
+struct bootrom_id_le {
+       __le32 chip;            /* Chip id */
+       __le32 chiprev;         /* Chip rev */
+       __le32 ramsize;         /* Size of  RAM */
+       __le32 remapbase;       /* Current remap base address */
+       __le32 boardtype;       /* Type of board */
+       __le32 boardrev;        /* Board revision */
+};
 
 struct brcmf_usb_image {
        struct list_head list;
@@ -70,7 +127,7 @@ struct brcmf_usbdev_info {
        struct list_head rx_postq;
        struct list_head tx_freeq;
        struct list_head tx_postq;
-       uint rx_pipe, tx_pipe, rx_pipe2;
+       uint rx_pipe, tx_pipe;
 
        int rx_low_watermark;
        int tx_low_watermark;
@@ -97,8 +154,11 @@ struct brcmf_usbdev_info {
        int ctl_completed;
        wait_queue_head_t ioctl_resp_wait;
        ulong ctl_op;
+       u8 ifnum;
 
        struct urb *bulk_urb; /* used for FW download */
+
+       bool wowl_enabled;
 };
 
 static void brcmf_usb_rx_refill(struct brcmf_usbdev_info *devinfo,
@@ -576,7 +636,6 @@ fail:
 static int brcmf_usb_up(struct device *dev)
 {
        struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
-       u16 ifnum;
 
        brcmf_dbg(USB, "Enter\n");
        if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP)
@@ -589,26 +648,34 @@ static int brcmf_usb_up(struct device *dev)
                devinfo->ctl_in_pipe = usb_rcvctrlpipe(devinfo->usbdev, 0);
                devinfo->ctl_out_pipe = usb_sndctrlpipe(devinfo->usbdev, 0);
 
-               ifnum = IFDESC(devinfo->usbdev, CONTROL_IF).bInterfaceNumber;
-
                /* CTL Write */
                devinfo->ctl_write.bRequestType =
                        USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
                devinfo->ctl_write.bRequest = 0;
                devinfo->ctl_write.wValue = cpu_to_le16(0);
-               devinfo->ctl_write.wIndex = cpu_to_le16p(&ifnum);
+               devinfo->ctl_write.wIndex = cpu_to_le16(devinfo->ifnum);
 
                /* CTL Read */
                devinfo->ctl_read.bRequestType =
                        USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
                devinfo->ctl_read.bRequest = 1;
                devinfo->ctl_read.wValue = cpu_to_le16(0);
-               devinfo->ctl_read.wIndex = cpu_to_le16p(&ifnum);
+               devinfo->ctl_read.wIndex = cpu_to_le16(devinfo->ifnum);
        }
        brcmf_usb_rx_fill_all(devinfo);
        return 0;
 }
 
+static void brcmf_cancel_all_urbs(struct brcmf_usbdev_info *devinfo)
+{
+       if (devinfo->ctl_urb)
+               usb_kill_urb(devinfo->ctl_urb);
+       if (devinfo->bulk_urb)
+               usb_kill_urb(devinfo->bulk_urb);
+       brcmf_usb_free_q(&devinfo->tx_postq, true);
+       brcmf_usb_free_q(&devinfo->rx_postq, true);
+}
+
 static void brcmf_usb_down(struct device *dev)
 {
        struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
@@ -622,14 +689,7 @@ static void brcmf_usb_down(struct device *dev)
 
        brcmf_usb_state_change(devinfo, BRCMFMAC_USB_STATE_DOWN);
 
-       if (devinfo->ctl_urb)
-               usb_kill_urb(devinfo->ctl_urb);
-
-       if (devinfo->bulk_urb)
-               usb_kill_urb(devinfo->bulk_urb);
-       brcmf_usb_free_q(&devinfo->tx_postq, true);
-
-       brcmf_usb_free_q(&devinfo->rx_postq, true);
+       brcmf_cancel_all_urbs(devinfo);
 }
 
 static void
@@ -642,19 +702,19 @@ brcmf_usb_sync_complete(struct urb *urb)
        brcmf_usb_ioctl_resp_wake(devinfo);
 }
 
-static bool brcmf_usb_dl_cmd(struct brcmf_usbdev_info *devinfo, u8 cmd,
-                            void *buffer, int buflen)
+static int brcmf_usb_dl_cmd(struct brcmf_usbdev_info *devinfo, u8 cmd,
+                           void *buffer, int buflen)
 {
-       int ret = 0;
+       int ret;
        char *tmpbuf;
        u16 size;
 
        if ((!devinfo) || (devinfo->ctl_urb == NULL))
-               return false;
+               return -EINVAL;
 
        tmpbuf = kmalloc(buflen, GFP_ATOMIC);
        if (!tmpbuf)
-               return false;
+               return -ENOMEM;
 
        size = buflen;
        devinfo->ctl_urb->transfer_buffer_length = size;
@@ -675,14 +735,18 @@ static bool brcmf_usb_dl_cmd(struct brcmf_usbdev_info *devinfo, u8 cmd,
        ret = usb_submit_urb(devinfo->ctl_urb, GFP_ATOMIC);
        if (ret < 0) {
                brcmf_err("usb_submit_urb failed %d\n", ret);
-               kfree(tmpbuf);
-               return false;
+               goto finalize;
        }
 
-       ret = brcmf_usb_ioctl_resp_wait(devinfo);
-       memcpy(buffer, tmpbuf, buflen);
-       kfree(tmpbuf);
+       if (!brcmf_usb_ioctl_resp_wait(devinfo)) {
+               usb_kill_urb(devinfo->ctl_urb);
+               ret = -ETIMEDOUT;
+       } else {
+               memcpy(buffer, tmpbuf, buflen);
+       }
 
+finalize:
+       kfree(tmpbuf);
        return ret;
 }
 
@@ -724,6 +788,7 @@ brcmf_usb_resetcfg(struct brcmf_usbdev_info *devinfo)
 {
        struct bootrom_id_le id;
        u32 loop_cnt;
+       int err;
 
        brcmf_dbg(USB, "Enter\n");
 
@@ -732,7 +797,9 @@ brcmf_usb_resetcfg(struct brcmf_usbdev_info *devinfo)
                mdelay(BRCMF_USB_RESET_GETVER_SPINWAIT);
                loop_cnt++;
                id.chip = cpu_to_le32(0xDEAD);       /* Get the ID */
-               brcmf_usb_dl_cmd(devinfo, DL_GETVER, &id, sizeof(id));
+               err = brcmf_usb_dl_cmd(devinfo, DL_GETVER, &id, sizeof(id));
+               if ((err) && (err != -ETIMEDOUT))
+                       return err;
                if (id.chip == cpu_to_le32(BRCMF_POSTBOOT_ID))
                        break;
        } while (loop_cnt < BRCMF_USB_RESET_GETVER_LOOP_CNT);
@@ -787,15 +854,14 @@ brcmf_usb_dl_writeimage(struct brcmf_usbdev_info *devinfo, u8 *fw, int fwlen)
 
        brcmf_dbg(USB, "Enter, fw %p, len %d\n", fw, fwlen);
 
-       bulkchunk = kmalloc(RDL_CHUNK, GFP_ATOMIC);
+       bulkchunk = kmalloc(TRX_RDL_CHUNK, GFP_ATOMIC);
        if (bulkchunk == NULL) {
                err = -ENOMEM;
                goto fail;
        }
 
        /* 1) Prepare USB boot loader for runtime image */
-       brcmf_usb_dl_cmd(devinfo, DL_START, &state,
-                        sizeof(struct rdl_state_le));
+       brcmf_usb_dl_cmd(devinfo, DL_START, &state, sizeof(state));
 
        rdlstate = le32_to_cpu(state.state);
        rdlbytes = le32_to_cpu(state.bytes);
@@ -815,10 +881,10 @@ brcmf_usb_dl_writeimage(struct brcmf_usbdev_info *devinfo, u8 *fw, int fwlen)
                /* Wait until the usb device reports it received all
                 * the bytes we sent */
                if ((rdlbytes == sent) && (rdlbytes != dllen)) {
-                       if ((dllen-sent) < RDL_CHUNK)
+                       if ((dllen-sent) < TRX_RDL_CHUNK)
                                sendlen = dllen-sent;
                        else
-                               sendlen = RDL_CHUNK;
+                               sendlen = TRX_RDL_CHUNK;
 
                        /* simply avoid having to send a ZLP by ensuring we
                         * never have an even
@@ -839,10 +905,10 @@ brcmf_usb_dl_writeimage(struct brcmf_usbdev_info *devinfo, u8 *fw, int fwlen)
                        dlpos += sendlen;
                        sent += sendlen;
                }
-               if (!brcmf_usb_dl_cmd(devinfo, DL_GETSTATE, &state,
-                                     sizeof(struct rdl_state_le))) {
-                       brcmf_err("DL_GETSTATE Failed xxxx\n");
-                       err = -EINVAL;
+               err = brcmf_usb_dl_cmd(devinfo, DL_GETSTATE, &state,
+                                      sizeof(state));
+               if (err) {
+                       brcmf_err("DL_GETSTATE Failed\n");
                        goto fail;
                }
 
@@ -898,13 +964,12 @@ static int brcmf_usb_dlrun(struct brcmf_usbdev_info *devinfo)
                return -EINVAL;
 
        /* Check we are runnable */
-       brcmf_usb_dl_cmd(devinfo, DL_GETSTATE, &state,
-               sizeof(struct rdl_state_le));
+       state.state = 0;
+       brcmf_usb_dl_cmd(devinfo, DL_GETSTATE, &state, sizeof(state));
 
        /* Start the image */
        if (state.state == cpu_to_le32(DL_RUNNABLE)) {
-               if (!brcmf_usb_dl_cmd(devinfo, DL_GO, &state,
-                       sizeof(struct rdl_state_le)))
+               if (brcmf_usb_dl_cmd(devinfo, DL_GO, &state, sizeof(state)))
                        return -ENODEV;
                if (brcmf_usb_resetcfg(devinfo))
                        return -ENODEV;
@@ -920,13 +985,16 @@ static int brcmf_usb_dlrun(struct brcmf_usbdev_info *devinfo)
 static bool brcmf_usb_chip_support(int chipid, int chiprev)
 {
        switch(chipid) {
-       case 43143:
+       case BRCM_CC_43143_CHIP_ID:
                return true;
-       case 43235:
-       case 43236:
-       case 43238:
+       case BRCM_CC_43235_CHIP_ID:
+       case BRCM_CC_43236_CHIP_ID:
+       case BRCM_CC_43238_CHIP_ID:
                return (chiprev == 3);
-       case 43242:
+       case BRCM_CC_43242_CHIP_ID:
+               return true;
+       case BRCM_CC_43566_CHIP_ID:
+       case BRCM_CC_43569_CHIP_ID:
                return true;
        default:
                break;
@@ -981,21 +1049,6 @@ static void brcmf_usb_detach(struct brcmf_usbdev_info *devinfo)
        kfree(devinfo->rx_reqs);
 }
 
-#define TRX_MAGIC       0x30524448      /* "HDR0" */
-#define TRX_VERSION     1               /* Version 1 */
-#define TRX_MAX_LEN     0x3B0000        /* Max length */
-#define TRX_NO_HEADER   1               /* Do not write TRX header */
-#define TRX_MAX_OFFSET  3               /* Max number of individual files */
-#define TRX_UNCOMP_IMAGE        0x20    /* Trx contains uncompressed image */
-
-struct trx_header_le {
-       __le32 magic;           /* "HDR0" */
-       __le32 len;             /* Length of file including header */
-       __le32 crc32;           /* CRC from flag_version to end of file */
-       __le32 flag_version;    /* 0:15 flags, 16:31 version */
-       __le32 offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of
-                                        * header */
-};
 
 static int check_file(const u8 *headers)
 {
@@ -1020,14 +1073,17 @@ static int check_file(const u8 *headers)
 static const char *brcmf_usb_get_fwname(struct brcmf_usbdev_info *devinfo)
 {
        switch (devinfo->bus_pub.devid) {
-       case 43143:
+       case BRCM_CC_43143_CHIP_ID:
                return BRCMF_USB_43143_FW_NAME;
-       case 43235:
-       case 43236:
-       case 43238:
+       case BRCM_CC_43235_CHIP_ID:
+       case BRCM_CC_43236_CHIP_ID:
+       case BRCM_CC_43238_CHIP_ID:
                return BRCMF_USB_43236_FW_NAME;
-       case 43242:
+       case BRCM_CC_43242_CHIP_ID:
                return BRCMF_USB_43242_FW_NAME;
+       case BRCM_CC_43566_CHIP_ID:
+       case BRCM_CC_43569_CHIP_ID:
+               return BRCMF_USB_43569_FW_NAME;
        default:
                return NULL;
        }
@@ -1094,11 +1150,24 @@ error:
        return NULL;
 }
 
+static void brcmf_usb_wowl_config(struct device *dev, bool enabled)
+{
+       struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
+
+       brcmf_dbg(USB, "Configuring WOWL, enabled=%d\n", enabled);
+       devinfo->wowl_enabled = enabled;
+       if (enabled)
+               device_set_wakeup_enable(devinfo->dev, true);
+       else
+               device_set_wakeup_enable(devinfo->dev, false);
+}
+
 static struct brcmf_bus_ops brcmf_usb_bus_ops = {
        .txdata = brcmf_usb_tx,
        .stop = brcmf_usb_down,
        .txctl = brcmf_usb_tx_ctlpkt,
        .rxctl = brcmf_usb_rx_ctlpkt,
+       .wowl_config = brcmf_usb_wowl_config,
 };
 
 static int brcmf_usb_bus_setup(struct brcmf_usbdev_info *devinfo)
@@ -1186,6 +1255,9 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo)
        bus->ops = &brcmf_usb_bus_ops;
        bus->proto_type = BRCMF_PROTO_BCDC;
        bus->always_use_fws_queue = true;
+#ifdef CONFIG_PM
+       bus->wowl_supported = true;
+#endif
 
        if (!brcmf_usb_dlneeded(devinfo)) {
                ret = brcmf_usb_bus_setup(devinfo);
@@ -1222,15 +1294,15 @@ brcmf_usb_disconnect_cb(struct brcmf_usbdev_info *devinfo)
 static int
 brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
 {
-       int ep;
-       struct usb_endpoint_descriptor *endpoint;
-       int ret = 0;
        struct usb_device *usb = interface_to_usbdev(intf);
-       int num_of_eps;
-       u8 endpoint_num;
        struct brcmf_usbdev_info *devinfo;
+       struct usb_interface_descriptor *desc;
+       struct usb_endpoint_descriptor *endpoint;
+       int ret = 0;
+       u32 num_of_eps;
+       u8 endpoint_num, ep;
 
-       brcmf_dbg(USB, "Enter\n");
+       brcmf_dbg(USB, "Enter 0x%04x:0x%04x\n", id->idVendor, id->idProduct);
 
        devinfo = kzalloc(sizeof(*devinfo), GFP_ATOMIC);
        if (devinfo == NULL)
@@ -1238,92 +1310,71 @@ brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
 
        devinfo->usbdev = usb;
        devinfo->dev = &usb->dev;
-
        usb_set_intfdata(intf, devinfo);
 
        /* Check that the device supports only one configuration */
        if (usb->descriptor.bNumConfigurations != 1) {
-               ret = -1;
+               brcmf_err("Number of configurations: %d not supported\n",
+                         usb->descriptor.bNumConfigurations);
+               ret = -ENODEV;
                goto fail;
        }
 
-       if (usb->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC) {
-               ret = -1;
+       if ((usb->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC) &&
+           (usb->descriptor.bDeviceClass != USB_CLASS_MISC) &&
+           (usb->descriptor.bDeviceClass != USB_CLASS_WIRELESS_CONTROLLER)) {
+               brcmf_err("Device class: 0x%x not supported\n",
+                         usb->descriptor.bDeviceClass);
+               ret = -ENODEV;
                goto fail;
        }
 
-       /*
-        * Only the BDC interface configuration is supported:
-        *      Device class: USB_CLASS_VENDOR_SPEC
-        *      if0 class: USB_CLASS_VENDOR_SPEC
-        *      if0/ep0: control
-        *      if0/ep1: bulk in
-        *      if0/ep2: bulk out (ok if swapped with bulk in)
-        */
-       if (CONFIGDESC(usb)->bNumInterfaces != 1) {
-               ret = -1;
+       desc = &intf->altsetting[0].desc;
+       if ((desc->bInterfaceClass != USB_CLASS_VENDOR_SPEC) ||
+           (desc->bInterfaceSubClass != 2) ||
+           (desc->bInterfaceProtocol != 0xff)) {
+               brcmf_err("non WLAN interface %d: 0x%x:0x%x:0x%x\n",
+                         desc->bInterfaceNumber, desc->bInterfaceClass,
+                         desc->bInterfaceSubClass, desc->bInterfaceProtocol);
+               ret = -ENODEV;
                goto fail;
        }
 
-       /* Check interface */
-       if (IFDESC(usb, CONTROL_IF).bInterfaceClass != USB_CLASS_VENDOR_SPEC ||
-           IFDESC(usb, CONTROL_IF).bInterfaceSubClass != 2 ||
-           IFDESC(usb, CONTROL_IF).bInterfaceProtocol != 0xff) {
-               brcmf_err("invalid control interface: class %d, subclass %d, proto %d\n",
-                         IFDESC(usb, CONTROL_IF).bInterfaceClass,
-                         IFDESC(usb, CONTROL_IF).bInterfaceSubClass,
-                         IFDESC(usb, CONTROL_IF).bInterfaceProtocol);
-               ret = -1;
-               goto fail;
-       }
-
-       /* Check control endpoint */
-       endpoint = &IFEPDESC(usb, CONTROL_IF, 0);
-       if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
-               != USB_ENDPOINT_XFER_INT) {
-               brcmf_err("invalid control endpoint %d\n",
-                         endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
-               ret = -1;
-               goto fail;
-       }
-
-       devinfo->rx_pipe = 0;
-       devinfo->rx_pipe2 = 0;
-       devinfo->tx_pipe = 0;
-       num_of_eps = IFDESC(usb, BULK_IF).bNumEndpoints - 1;
-
-       /* Check data endpoints and get pipes */
-       for (ep = 1; ep <= num_of_eps; ep++) {
-               endpoint = &IFEPDESC(usb, BULK_IF, ep);
-               if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
-                   USB_ENDPOINT_XFER_BULK) {
-                       brcmf_err("invalid data endpoint %d\n", ep);
-                       ret = -1;
-                       goto fail;
-               }
-
-               endpoint_num = endpoint->bEndpointAddress &
-                              USB_ENDPOINT_NUMBER_MASK;
-               if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
-                       == USB_DIR_IN) {
-                       if (!devinfo->rx_pipe) {
+       num_of_eps = desc->bNumEndpoints;
+       for (ep = 0; ep < num_of_eps; ep++) {
+               endpoint = &intf->altsetting[0].endpoint[ep].desc;
+               endpoint_num = usb_endpoint_num(endpoint);
+               if (!usb_endpoint_xfer_bulk(endpoint))
+                       continue;
+               if (usb_endpoint_dir_in(endpoint)) {
+                       if (!devinfo->rx_pipe)
                                devinfo->rx_pipe =
                                        usb_rcvbulkpipe(usb, endpoint_num);
-                       } else {
-                               devinfo->rx_pipe2 =
-                                       usb_rcvbulkpipe(usb, endpoint_num);
-                       }
                } else {
-                       devinfo->tx_pipe = usb_sndbulkpipe(usb, endpoint_num);
+                       if (!devinfo->tx_pipe)
+                               devinfo->tx_pipe =
+                                       usb_sndbulkpipe(usb, endpoint_num);
                }
        }
+       if (devinfo->rx_pipe == 0) {
+               brcmf_err("No RX (in) Bulk EP found\n");
+               ret = -ENODEV;
+               goto fail;
+       }
+       if (devinfo->tx_pipe == 0) {
+               brcmf_err("No TX (out) Bulk EP found\n");
+               ret = -ENODEV;
+               goto fail;
+       }
+
+       devinfo->ifnum = desc->bInterfaceNumber;
 
        if (usb->speed == USB_SPEED_SUPER)
-               brcmf_dbg(USB, "Broadcom super speed USB wireless device detected\n");
+               brcmf_dbg(USB, "Broadcom super speed USB WLAN interface detected\n");
        else if (usb->speed == USB_SPEED_HIGH)
-               brcmf_dbg(USB, "Broadcom high speed USB wireless device detected\n");
+               brcmf_dbg(USB, "Broadcom high speed USB WLAN interface detected\n");
        else
-               brcmf_dbg(USB, "Broadcom full speed USB wireless device detected\n");
+               brcmf_dbg(USB, "Broadcom full speed USB WLAN interface detected\n");
 
        ret = brcmf_usb_probe_cb(devinfo);
        if (ret)
@@ -1333,11 +1384,9 @@ brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
        return 0;
 
 fail:
-       brcmf_err("failed with errno %d\n", ret);
        kfree(devinfo);
        usb_set_intfdata(intf, NULL);
        return ret;
-
 }
 
 static void
@@ -1362,7 +1411,10 @@ static int brcmf_usb_suspend(struct usb_interface *intf, pm_message_t state)
 
        brcmf_dbg(USB, "Enter\n");
        devinfo->bus_pub.state = BRCMFMAC_USB_STATE_SLEEP;
-       brcmf_detach(&usb->dev);
+       if (devinfo->wowl_enabled)
+               brcmf_cancel_all_urbs(devinfo);
+       else
+               brcmf_detach(&usb->dev);
        return 0;
 }
 
@@ -1375,13 +1427,19 @@ static int brcmf_usb_resume(struct usb_interface *intf)
        struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev);
 
        brcmf_dbg(USB, "Enter\n");
-       return brcmf_usb_bus_setup(devinfo);
+       if (!devinfo->wowl_enabled)
+               return brcmf_usb_bus_setup(devinfo);
+
+       devinfo->bus_pub.state = BRCMFMAC_USB_STATE_UP;
+       brcmf_usb_rx_fill_all(devinfo);
+       return 0;
 }
 
 static int brcmf_usb_reset_resume(struct usb_interface *intf)
 {
        struct usb_device *usb = interface_to_usbdev(intf);
        struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev);
+
        brcmf_dbg(USB, "Enter\n");
 
        return brcmf_fw_get_firmwares(&usb->dev, 0,
@@ -1389,25 +1447,24 @@ static int brcmf_usb_reset_resume(struct usb_interface *intf)
                                      brcmf_usb_probe_phase2);
 }
 
-#define BRCMF_USB_VENDOR_ID_BROADCOM   0x0a5c
-#define BRCMF_USB_DEVICE_ID_43143      0xbd1e
-#define BRCMF_USB_DEVICE_ID_43236      0xbd17
-#define BRCMF_USB_DEVICE_ID_43242      0xbd1f
-#define BRCMF_USB_DEVICE_ID_BCMFW      0x0bdc
+#define BRCMF_USB_DEVICE(dev_id)       \
+       { USB_DEVICE(BRCM_USB_VENDOR_ID_BROADCOM, dev_id) }
 
 static struct usb_device_id brcmf_usb_devid_table[] = {
-       { USB_DEVICE(BRCMF_USB_VENDOR_ID_BROADCOM, BRCMF_USB_DEVICE_ID_43143) },
-       { USB_DEVICE(BRCMF_USB_VENDOR_ID_BROADCOM, BRCMF_USB_DEVICE_ID_43236) },
-       { USB_DEVICE(BRCMF_USB_VENDOR_ID_BROADCOM, BRCMF_USB_DEVICE_ID_43242) },
+       BRCMF_USB_DEVICE(BRCM_USB_43143_DEVICE_ID),
+       BRCMF_USB_DEVICE(BRCM_USB_43236_DEVICE_ID),
+       BRCMF_USB_DEVICE(BRCM_USB_43242_DEVICE_ID),
+       BRCMF_USB_DEVICE(BRCM_USB_43569_DEVICE_ID),
        /* special entry for device with firmware loaded and running */
-       { USB_DEVICE(BRCMF_USB_VENDOR_ID_BROADCOM, BRCMF_USB_DEVICE_ID_BCMFW) },
-       { }
+       BRCMF_USB_DEVICE(BRCM_USB_BCMFW_DEVICE_ID),
+       { /* end: all zeroes */ }
 };
 
 MODULE_DEVICE_TABLE(usb, brcmf_usb_devid_table);
 MODULE_FIRMWARE(BRCMF_USB_43143_FW_NAME);
 MODULE_FIRMWARE(BRCMF_USB_43236_FW_NAME);
 MODULE_FIRMWARE(BRCMF_USB_43242_FW_NAME);
+MODULE_FIRMWARE(BRCMF_USB_43569_FW_NAME);
 
 static struct usb_driver brcmf_usbdrvr = {
        .name = KBUILD_MODNAME,