brcmfmac: assure USB dongle firmware is reset upon module unload
authorArend van Spriel <arend@broadcom.com>
Wed, 2 Jan 2013 14:22:40 +0000 (15:22 +0100)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 7 Jan 2013 20:16:56 +0000 (15:16 -0500)
Upon unloading the brcmfmac module the USB firmware should be reset
as the device remains powered. The reset assures a known device
state when a new brcmfmac driver load is being done.

Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/brcm80211/brcmfmac/dhd.h
drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
drivers/net/wireless/brcm80211/brcmfmac/usb.c

index fd672bf53867f6b7aac803fae15686d0d750ccee..7245b171190a16058df001a9bd9a9467c652236d 100644 (file)
@@ -39,6 +39,7 @@
 #define BRCMF_C_GET_BSSID                      23
 #define BRCMF_C_GET_SSID                       25
 #define BRCMF_C_SET_SSID                       26
+#define BRCMF_C_TERMINATED                     28
 #define BRCMF_C_GET_CHANNEL                    29
 #define BRCMF_C_SET_CHANNEL                    30
 #define BRCMF_C_GET_SRL                                31
index dd38b78a9726f75861bcb1f92ef3d511a81b92db..358b54fff79517966fa349fa1a7c179301330ef0 100644 (file)
@@ -154,7 +154,8 @@ static inline void brcmf_rx_packet(struct device *dev, int ifidx,
 extern int brcmf_attach(uint bus_hdrlen, struct device *dev);
 /* Indication from bus module regarding removal/absence of dongle */
 extern void brcmf_detach(struct device *dev);
-
+/* Indication from bus module that dongle should be reset */
+extern void brcmf_dev_reset(struct device *dev);
 /* Indication from bus module to change flow-control state */
 extern void brcmf_txflowblock(struct device *dev, bool state);
 
index 74a616b4de8e027c5f877f2910a526fed9d29aa3..16efcb48dfbc352abc3b7d7a1de91814dfdd1c93 100644 (file)
@@ -845,6 +845,17 @@ static void brcmf_bus_detach(struct brcmf_pub *drvr)
        }
 }
 
+void brcmf_dev_reset(struct device *dev)
+{
+       struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+       struct brcmf_pub *drvr = bus_if->drvr;
+
+       if (drvr == NULL)
+               return;
+
+       brcmf_fil_cmd_int_set(drvr->iflist[0], BRCMF_C_TERMINATED, 1);
+}
+
 void brcmf_detach(struct device *dev)
 {
        int i;
index 22eae57d9546645489814c0f302eb5aaca583539..1df85955ad935b113e9ba4842429e5aa311ed944 100644 (file)
@@ -1524,10 +1524,23 @@ static void brcmf_release_fw(struct list_head *q)
        }
 }
 
+static int brcmf_usb_reset_device(struct device *dev, void *notused)
+{
+       /* device past is the usb interface so we
+        * need to use parent here.
+        */
+       brcmf_dev_reset(dev->parent);
+       return 0;
+}
 
 void brcmf_usb_exit(void)
 {
+       struct device_driver *drv = &brcmf_usbdrvr.drvwrap.driver;
+       int ret;
+
        brcmf_dbg(USB, "Enter\n");
+       ret = driver_for_each_device(drv, NULL, NULL,
+                                    brcmf_usb_reset_device);
        usb_deregister(&brcmf_usbdrvr);
        brcmf_release_fw(&fw_image_list);
 }