summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c')
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c315
1 files changed, 182 insertions, 133 deletions
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
index a4308c6e72d7..f0129d10d2b9 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2011 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or 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 <linux/kernel.h>
@@ -128,13 +117,6 @@ struct bootrom_id_le {
__le32 boardrev; /* Board revision */
};
-struct brcmf_usb_image {
- struct list_head list;
- s8 *fwname;
- u8 *image;
- int image_len;
-};
-
struct brcmf_usbdev_info {
struct brcmf_usbdev bus_pub; /* MUST BE FIRST */
spinlock_t qlock;
@@ -160,7 +142,7 @@ struct brcmf_usbdev_info {
struct usb_device *usbdev;
struct device *dev;
- struct mutex dev_init_lock;
+ struct completion dev_init_done;
int ctl_in_pipe, ctl_out_pipe;
struct urb *ctl_urb; /* URB for control endpoint */
@@ -175,7 +157,6 @@ struct brcmf_usbdev_info {
struct urb *bulk_urb; /* used for FW download */
- bool wowl_enabled;
struct brcmf_mp_device *settings;
};
@@ -323,27 +304,43 @@ static int brcmf_usb_tx_ctlpkt(struct device *dev, u8 *buf, u32 len)
int err = 0;
int timeout = 0;
struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
+ struct usb_interface *intf = to_usb_interface(dev);
brcmf_dbg(USB, "Enter\n");
- if (devinfo->bus_pub.state != BRCMFMAC_USB_STATE_UP)
- return -EIO;
- if (test_and_set_bit(0, &devinfo->ctl_op))
- return -EIO;
+ err = usb_autopm_get_interface(intf);
+ if (err)
+ goto out;
+
+ if (devinfo->bus_pub.state != BRCMFMAC_USB_STATE_UP) {
+ err = -EIO;
+ goto fail;
+ }
+
+ if (test_and_set_bit(0, &devinfo->ctl_op)) {
+ err = -EIO;
+ goto fail;
+ }
devinfo->ctl_completed = false;
err = brcmf_usb_send_ctl(devinfo, buf, len);
if (err) {
brcmf_err("fail %d bytes: %d\n", err, len);
clear_bit(0, &devinfo->ctl_op);
- return err;
+ goto fail;
}
timeout = brcmf_usb_ioctl_resp_wait(devinfo);
- clear_bit(0, &devinfo->ctl_op);
if (!timeout) {
brcmf_err("Txctl wait timed out\n");
+ usb_kill_urb(devinfo->ctl_urb);
err = -EIO;
+ goto fail;
}
+ clear_bit(0, &devinfo->ctl_op);
+
+fail:
+ usb_autopm_put_interface(intf);
+out:
return err;
}
@@ -352,32 +349,46 @@ static int brcmf_usb_rx_ctlpkt(struct device *dev, u8 *buf, u32 len)
int err = 0;
int timeout = 0;
struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
+ struct usb_interface *intf = to_usb_interface(dev);
brcmf_dbg(USB, "Enter\n");
- if (devinfo->bus_pub.state != BRCMFMAC_USB_STATE_UP)
- return -EIO;
- if (test_and_set_bit(0, &devinfo->ctl_op))
- return -EIO;
+ err = usb_autopm_get_interface(intf);
+ if (err)
+ goto out;
+
+ if (devinfo->bus_pub.state != BRCMFMAC_USB_STATE_UP) {
+ err = -EIO;
+ goto fail;
+ }
+
+ if (test_and_set_bit(0, &devinfo->ctl_op)) {
+ err = -EIO;
+ goto fail;
+ }
devinfo->ctl_completed = false;
err = brcmf_usb_recv_ctl(devinfo, buf, len);
if (err) {
brcmf_err("fail %d bytes: %d\n", err, len);
clear_bit(0, &devinfo->ctl_op);
- return err;
+ goto fail;
}
timeout = brcmf_usb_ioctl_resp_wait(devinfo);
err = devinfo->ctl_urb_status;
- clear_bit(0, &devinfo->ctl_op);
if (!timeout) {
brcmf_err("rxctl wait timed out\n");
+ usb_kill_urb(devinfo->ctl_urb);
err = -EIO;
+ goto fail;
}
+ clear_bit(0, &devinfo->ctl_op);
+fail:
+ usb_autopm_put_interface(intf);
if (!err)
return devinfo->ctl_urb_actual_length;
- else
- return err;
+out:
+ return err;
}
static struct brcmf_usbreq *brcmf_usb_deq(struct brcmf_usbdev_info *devinfo,
@@ -441,26 +452,22 @@ fail:
usb_free_urb(req->urb);
list_del(q->next);
}
+ kfree(reqs);
return NULL;
}
-static void brcmf_usb_free_q(struct list_head *q, bool pending)
+static void brcmf_usb_free_q(struct list_head *q)
{
struct brcmf_usbreq *req, *next;
- int i = 0;
+
list_for_each_entry_safe(req, next, q, list) {
if (!req->urb) {
brcmf_err("bad req\n");
break;
}
- i++;
- if (pending) {
- usb_kill_urb(req->urb);
- } else {
- usb_free_urb(req->urb);
- list_del_init(&req->list);
- }
+ usb_free_urb(req->urb);
+ list_del_init(&req->list);
}
}
@@ -508,17 +515,19 @@ static void brcmf_usb_rx_complete(struct urb *urb)
skb = req->skb;
req->skb = NULL;
- /* zero lenght packets indicate usb "failure". Do not refill */
+ /* zero length packets indicate usb "failure". Do not refill */
if (urb->status != 0 || !urb->actual_length) {
brcmu_pkt_buf_free_skb(skb);
brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req, NULL);
return;
}
- if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP) {
+ if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP ||
+ devinfo->bus_pub.state == BRCMFMAC_USB_STATE_SLEEP) {
skb_put(skb, urb->actual_length);
- brcmf_rx_frame(devinfo->dev, skb, true);
+ brcmf_rx_frame(devinfo->dev, skb, true, true);
brcmf_usb_rx_refill(devinfo, req);
+ usb_mark_last_busy(urb->dev);
} else {
brcmu_pkt_buf_free_skb(skb);
brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req, NULL);
@@ -575,7 +584,6 @@ static void
brcmf_usb_state_change(struct brcmf_usbdev_info *devinfo, int state)
{
struct brcmf_bus *bcmf_bus = devinfo->bus_pub.bus;
- int old_state;
brcmf_dbg(USB, "Enter, current state=%d, new state=%d\n",
devinfo->bus_pub.state, state);
@@ -583,7 +591,6 @@ brcmf_usb_state_change(struct brcmf_usbdev_info *devinfo, int state)
if (devinfo->bus_pub.state == state)
return;
- old_state = devinfo->bus_pub.state;
devinfo->bus_pub.state = state;
/* update state of upper layer */
@@ -604,6 +611,11 @@ static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb)
struct brcmf_usbreq *req;
int ret;
unsigned long flags;
+ struct usb_interface *intf = to_usb_interface(dev);
+
+ ret = usb_autopm_get_interface(intf);
+ if (ret)
+ goto out;
brcmf_dbg(USB, "Enter, skb=%p\n", skb);
if (devinfo->bus_pub.state != BRCMFMAC_USB_STATE_UP) {
@@ -642,9 +654,10 @@ static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb)
devinfo->tx_flowblock = true;
}
spin_unlock_irqrestore(&devinfo->tx_flowblock_lock, flags);
- return 0;
fail:
+ usb_autopm_put_interface(intf);
+out:
return ret;
}
@@ -684,12 +697,18 @@ static int brcmf_usb_up(struct device *dev)
static void brcmf_cancel_all_urbs(struct brcmf_usbdev_info *devinfo)
{
+ int i;
+
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);
+ if (devinfo->tx_reqs)
+ for (i = 0; i < devinfo->bus_pub.ntxq; i++)
+ usb_kill_urb(devinfo->tx_reqs[i].urb);
+ if (devinfo->rx_reqs)
+ for (i = 0; i < devinfo->bus_pub.nrxq; i++)
+ usb_kill_urb(devinfo->rx_reqs[i].urb);
}
static void brcmf_usb_down(struct device *dev)
@@ -722,15 +741,19 @@ static int brcmf_usb_dl_cmd(struct brcmf_usbdev_info *devinfo, u8 cmd,
void *buffer, int buflen)
{
int ret;
- char *tmpbuf;
+ char *tmpbuf = NULL;
u16 size;
- if ((!devinfo) || (devinfo->ctl_urb == NULL))
- return -EINVAL;
+ if (!devinfo || !devinfo->ctl_urb) {
+ ret = -EINVAL;
+ goto err;
+ }
tmpbuf = kmalloc(buflen, GFP_ATOMIC);
- if (!tmpbuf)
- return -ENOMEM;
+ if (!tmpbuf) {
+ ret = -ENOMEM;
+ goto err;
+ }
size = buflen;
devinfo->ctl_urb->transfer_buffer_length = size;
@@ -751,18 +774,23 @@ static int 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);
- goto finalize;
+ goto err;
}
if (!brcmf_usb_ioctl_resp_wait(devinfo)) {
usb_kill_urb(devinfo->ctl_urb);
ret = -ETIMEDOUT;
+ goto err;
} else {
memcpy(buffer, tmpbuf, buflen);
}
-finalize:
kfree(tmpbuf);
+ return 0;
+
+err:
+ kfree(tmpbuf);
+ brcmf_err("dl cmd %u failed: err=%d\n", cmd, ret);
return ret;
}
@@ -877,14 +905,16 @@ brcmf_usb_dl_writeimage(struct brcmf_usbdev_info *devinfo, u8 *fw, int fwlen)
}
/* 1) Prepare USB boot loader for runtime image */
- brcmf_usb_dl_cmd(devinfo, DL_START, &state, sizeof(state));
+ err = brcmf_usb_dl_cmd(devinfo, DL_START, &state, sizeof(state));
+ if (err)
+ goto fail;
rdlstate = le32_to_cpu(state.state);
rdlbytes = le32_to_cpu(state.bytes);
/* 2) Check we are in the Waiting state */
if (rdlstate != DL_WAITING) {
- brcmf_err("Failed to DL_START\n");
+ brcmf_err("Invalid DL state: %u\n", rdlstate);
err = -EINVAL;
goto fail;
}
@@ -897,10 +927,7 @@ 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) < TRX_RDL_CHUNK)
- sendlen = dllen-sent;
- else
- sendlen = TRX_RDL_CHUNK;
+ sendlen = min(dllen - sent, TRX_RDL_CHUNK);
/* simply avoid having to send a ZLP by ensuring we
* never have an even
@@ -1002,20 +1029,32 @@ static int
brcmf_usb_fw_download(struct brcmf_usbdev_info *devinfo)
{
int err;
+ struct usb_interface *intf;
brcmf_dbg(USB, "Enter\n");
- if (devinfo == NULL)
- return -ENODEV;
+ if (!devinfo) {
+ err = -ENODEV;
+ goto out;
+ }
if (!devinfo->image) {
brcmf_err("No firmware!\n");
- return -ENOENT;
+ err = -ENOENT;
+ goto out;
}
+ intf = to_usb_interface(devinfo->dev);
+ err = usb_autopm_get_interface(intf);
+ if (err)
+ goto out;
+
err = brcmf_usb_dlstart(devinfo,
(u8 *)devinfo->image, devinfo->image_len);
if (err == 0)
err = brcmf_usb_dlrun(devinfo);
+
+ usb_autopm_put_interface(intf);
+out:
return err;
}
@@ -1025,8 +1064,8 @@ static void brcmf_usb_detach(struct brcmf_usbdev_info *devinfo)
brcmf_dbg(USB, "Enter, devinfo %p\n", devinfo);
/* free the URBS */
- brcmf_usb_free_q(&devinfo->rx_freeq, false);
- brcmf_usb_free_q(&devinfo->tx_freeq, false);
+ brcmf_usb_free_q(&devinfo->rx_freeq);
+ brcmf_usb_free_q(&devinfo->tx_freeq);
usb_free_urb(devinfo->ctl_urb);
usb_free_urb(devinfo->bulk_urb);
@@ -1116,36 +1155,11 @@ error:
return NULL;
}
-static void brcmf_usb_wowl_config(struct device *dev, bool enabled)
+static int brcmf_usb_get_blob(struct device *dev, const struct firmware **fw,
+ enum brcmf_blob_type type)
{
- 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
-int brcmf_usb_get_fwname(struct device *dev, const char *ext, u8 *fw_name)
-{
- struct brcmf_bus *bus = dev_get_drvdata(dev);
- struct brcmf_fw_request *fwreq;
- struct brcmf_fw_name fwnames[] = {
- { ext, fw_name },
- };
-
- fwreq = brcmf_fw_alloc_request(bus->chip, bus->chiprev,
- brcmf_usb_fwnames,
- ARRAY_SIZE(brcmf_usb_fwnames),
- fwnames, ARRAY_SIZE(fwnames));
- if (!fwreq)
- return -ENOMEM;
-
- kfree(fwreq);
- return 0;
+ /* No blobs for USB devices... */
+ return -ENOENT;
}
static const struct brcmf_bus_ops brcmf_usb_bus_ops = {
@@ -1154,8 +1168,7 @@ static const struct brcmf_bus_ops brcmf_usb_bus_ops = {
.txdata = brcmf_usb_tx,
.txctl = brcmf_usb_tx_ctlpkt,
.rxctl = brcmf_usb_rx_ctlpkt,
- .wowl_config = brcmf_usb_wowl_config,
- .get_fwname = brcmf_usb_get_fwname,
+ .get_blob = brcmf_usb_get_blob,
};
#define BRCMF_USB_FW_CODE 0
@@ -1190,16 +1203,20 @@ static void brcmf_usb_probe_phase2(struct device *dev, int ret,
if (ret)
goto error;
+ ret = brcmf_alloc(devinfo->dev, devinfo->settings);
+ if (ret)
+ goto error;
+
/* Attach to the common driver interface */
- ret = brcmf_attach(devinfo->dev, devinfo->settings);
+ ret = brcmf_attach(devinfo->dev);
if (ret)
goto error;
- mutex_unlock(&devinfo->dev_init_lock);
+ complete(&devinfo->dev_init_done);
return;
error:
brcmf_dbg(TRACE, "failed: dev=%s, err=%d\n", dev_name(dev), ret);
- mutex_unlock(&devinfo->dev_init_lock);
+ complete(&devinfo->dev_init_done);
device_release_driver(dev);
}
@@ -1224,10 +1241,11 @@ brcmf_usb_prepare_fw_request(struct brcmf_usbdev_info *devinfo)
return fwreq;
}
-static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo)
+static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo,
+ enum brcmf_fwvendor fwvid)
{
- struct brcmf_bus *bus = NULL;
- struct brcmf_usbdev *bus_pub = NULL;
+ struct brcmf_bus *bus;
+ struct brcmf_usbdev *bus_pub;
struct device *dev = devinfo->dev;
struct brcmf_fw_request *fwreq;
int ret;
@@ -1237,7 +1255,7 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo)
if (!bus_pub)
return -ENODEV;
- bus = kzalloc(sizeof(struct brcmf_bus), GFP_ATOMIC);
+ bus = kzalloc(sizeof(*bus), GFP_ATOMIC);
if (!bus) {
ret = -ENOMEM;
goto fail;
@@ -1249,6 +1267,7 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo)
dev_set_drvdata(dev, bus);
bus->ops = &brcmf_usb_bus_ops;
bus->proto_type = BRCMF_PROTO_BCDC;
+ bus->fwvid = fwvid;
bus->always_use_fws_queue = true;
#ifdef CONFIG_PM
bus->wowl_supported = true;
@@ -1261,13 +1280,19 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo)
ret = -ENOMEM;
goto fail;
}
+ ret = PTR_ERR_OR_ZERO(devinfo->settings);
+ if (ret < 0)
+ goto fail;
if (!brcmf_usb_dlneeded(devinfo)) {
- ret = brcmf_attach(devinfo->dev, devinfo->settings);
+ ret = brcmf_alloc(devinfo->dev, devinfo->settings);
+ if (ret)
+ goto fail;
+ ret = brcmf_attach(devinfo->dev);
if (ret)
goto fail;
/* we are done */
- mutex_unlock(&devinfo->dev_init_lock);
+ complete(&devinfo->dev_init_done);
return 0;
}
bus->chip = bus_pub->devid;
@@ -1291,6 +1316,7 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo)
fail:
/* Release resources in reverse order */
+ brcmf_free(devinfo->dev);
kfree(bus);
brcmf_usb_detach(devinfo);
return ret;
@@ -1304,10 +1330,14 @@ brcmf_usb_disconnect_cb(struct brcmf_usbdev_info *devinfo)
brcmf_dbg(USB, "Enter, bus_pub %p\n", devinfo);
brcmf_detach(devinfo->dev);
+ brcmf_free(devinfo->dev);
kfree(devinfo->bus_pub.bus);
brcmf_usb_detach(devinfo);
}
+/* Forward declaration for usb_match_id() call */
+static const struct usb_device_id brcmf_usb_devid_table[];
+
static int
brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
@@ -1319,6 +1349,14 @@ brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
u32 num_of_eps;
u8 endpoint_num, ep;
+ if (!id) {
+ id = usb_match_id(intf, brcmf_usb_devid_table);
+ if (!id) {
+ dev_err(&intf->dev, "Error could not find matching usb_device_id\n");
+ return -ENODEV;
+ }
+ }
+
brcmf_dbg(USB, "Enter 0x%04x:0x%04x\n", id->idVendor, id->idProduct);
devinfo = kzalloc(sizeof(*devinfo), GFP_ATOMIC);
@@ -1327,14 +1365,15 @@ brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
devinfo->usbdev = usb;
devinfo->dev = &usb->dev;
- /* Take an init lock, to protect for disconnect while still loading.
+ /* Init completion, to protect for disconnect while still loading.
* Necessary because of the asynchronous firmware load construction
*/
- mutex_init(&devinfo->dev_init_lock);
- mutex_lock(&devinfo->dev_init_lock);
+ init_completion(&devinfo->dev_init_done);
usb_set_intfdata(intf, devinfo);
+ intf->needs_remote_wakeup = 1;
+
/* Check that the device supports only one configuration */
if (usb->descriptor.bNumConfigurations != 1) {
brcmf_err("Number of configurations: %d not supported\n",
@@ -1352,7 +1391,7 @@ brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
goto fail;
}
- desc = &intf->altsetting[0].desc;
+ desc = &intf->cur_altsetting->desc;
if ((desc->bInterfaceClass != USB_CLASS_VENDOR_SPEC) ||
(desc->bInterfaceSubClass != 2) ||
(desc->bInterfaceProtocol != 0xff)) {
@@ -1365,7 +1404,7 @@ brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
num_of_eps = desc->bNumEndpoints;
for (ep = 0; ep < num_of_eps; ep++) {
- endpoint = &intf->altsetting[0].endpoint[ep].desc;
+ endpoint = &intf->cur_altsetting->endpoint[ep].desc;
endpoint_num = usb_endpoint_num(endpoint);
if (!usb_endpoint_xfer_bulk(endpoint))
continue;
@@ -1401,7 +1440,7 @@ brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
else
brcmf_dbg(USB, "Broadcom full speed USB WLAN interface detected\n");
- ret = brcmf_usb_probe_cb(devinfo);
+ ret = brcmf_usb_probe_cb(devinfo, id->driver_info);
if (ret)
goto fail;
@@ -1409,7 +1448,7 @@ brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
return 0;
fail:
- mutex_unlock(&devinfo->dev_init_lock);
+ complete(&devinfo->dev_init_done);
kfree(devinfo);
usb_set_intfdata(intf, NULL);
return ret;
@@ -1424,7 +1463,7 @@ brcmf_usb_disconnect(struct usb_interface *intf)
devinfo = (struct brcmf_usbdev_info *)usb_get_intfdata(intf);
if (devinfo) {
- mutex_lock(&devinfo->dev_init_lock);
+ wait_for_completion(&devinfo->dev_init_done);
/* Make sure that devinfo still exists. Firmware probe routines
* may have released the device and cleared the intfdata.
*/
@@ -1448,10 +1487,8 @@ 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;
- if (devinfo->wowl_enabled)
- brcmf_cancel_all_urbs(devinfo);
- else
- brcmf_detach(&usb->dev);
+ brcmf_cancel_all_urbs(devinfo);
+ device_set_wakeup_enable(devinfo->dev, true);
return 0;
}
@@ -1464,11 +1501,10 @@ 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");
- if (!devinfo->wowl_enabled)
- return brcmf_attach(devinfo->dev, devinfo->settings);
devinfo->bus_pub.state = BRCMFMAC_USB_STATE_UP;
brcmf_usb_rx_fill_all(devinfo);
+ device_set_wakeup_enable(devinfo->dev, false);
return 0;
}
@@ -1492,14 +1528,23 @@ static int brcmf_usb_reset_resume(struct usb_interface *intf)
return ret;
}
-#define BRCMF_USB_DEVICE(dev_id) \
- { USB_DEVICE(BRCM_USB_VENDOR_ID_BROADCOM, dev_id) }
+#define BRCMF_USB_DEVICE(dev_id) \
+ { \
+ USB_DEVICE(BRCM_USB_VENDOR_ID_BROADCOM, dev_id), \
+ .driver_info = BRCMF_FWVENDOR_WCC \
+ }
-#define LINKSYS_USB_DEVICE(dev_id) \
- { USB_DEVICE(BRCM_USB_VENDOR_ID_LINKSYS, dev_id) }
+#define LINKSYS_USB_DEVICE(dev_id) \
+ { \
+ USB_DEVICE(BRCM_USB_VENDOR_ID_LINKSYS, dev_id), \
+ .driver_info = BRCMF_FWVENDOR_WCC \
+ }
-#define CYPRESS_USB_DEVICE(dev_id) \
- { USB_DEVICE(CY_USB_VENDOR_ID_CYPRESS, dev_id) }
+#define CYPRESS_USB_DEVICE(dev_id) \
+ { \
+ USB_DEVICE(CY_USB_VENDOR_ID_CYPRESS, dev_id), \
+ .driver_info = BRCMF_FWVENDOR_WCC \
+ }
static const struct usb_device_id brcmf_usb_devid_table[] = {
BRCMF_USB_DEVICE(BRCM_USB_43143_DEVICE_ID),
@@ -1525,6 +1570,7 @@ static struct usb_driver brcmf_usbdrvr = {
.suspend = brcmf_usb_suspend,
.resume = brcmf_usb_resume,
.reset_resume = brcmf_usb_reset_resume,
+ .supports_autosuspend = true,
.disable_hub_initiated_lpm = 1,
};
@@ -1539,17 +1585,20 @@ static int brcmf_usb_reset_device(struct device *dev, void *notused)
void brcmf_usb_exit(void)
{
- struct device_driver *drv = &brcmf_usbdrvr.drvwrap.driver;
+ struct device_driver *drv = &brcmf_usbdrvr.driver;
int ret;
brcmf_dbg(USB, "Enter\n");
ret = driver_for_each_device(drv, NULL, NULL,
brcmf_usb_reset_device);
+ if (ret)
+ brcmf_err("failed to reset all usb devices %d\n", ret);
+
usb_deregister(&brcmf_usbdrvr);
}
-void brcmf_usb_register(void)
+int brcmf_usb_register(void)
{
brcmf_dbg(USB, "Enter\n");
- usb_register(&brcmf_usbdrvr);
+ return usb_register(&brcmf_usbdrvr);
}