Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 300626
b: refs/heads/master
c: 5612a50
h: refs/heads/master
v: v3
  • Loading branch information
Larry Finger authored and John W. Linville committed Apr 9, 2012
1 parent 5da2ff3 commit 76f7785
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 69 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: a9b9361dd5ef6c39703f2f0c8c18aa2e1f133fc5
refs/heads/master: 5612a508d11f81c1ca3290260f86328dfb55d513
195 changes: 127 additions & 68 deletions trunk/drivers/net/wireless/p54/p54usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,21 +117,18 @@ static const struct {
u32 intf;
enum p54u_hw_type type;
const char *fw;
const char *fw_legacy;
char hw[20];
} p54u_fwlist[__NUM_P54U_HWTYPES] = {
{
.type = P54U_NET2280,
.intf = FW_LM86,
.fw = "isl3886usb",
.fw_legacy = "isl3890usb",
.hw = "ISL3886 + net2280",
},
{
.type = P54U_3887,
.intf = FW_LM87,
.fw = "isl3887usb",
.fw_legacy = "isl3887usb_bare",
.hw = "ISL3887",
},
};
Expand Down Expand Up @@ -208,6 +205,16 @@ static void p54u_free_urbs(struct ieee80211_hw *dev)
usb_kill_anchored_urbs(&priv->submitted);
}

static void p54u_stop(struct ieee80211_hw *dev)
{
/*
* TODO: figure out how to reliably stop the 3887 and net2280 so
* the hardware is still usable next time we want to start it.
* until then, we just stop listening to the hardware..
*/
p54u_free_urbs(dev);
}

static int p54u_init_urbs(struct ieee80211_hw *dev)
{
struct p54u_priv *priv = dev->priv;
Expand Down Expand Up @@ -257,6 +264,16 @@ static int p54u_init_urbs(struct ieee80211_hw *dev)
return ret;
}

static int p54u_open(struct ieee80211_hw *dev)
{
/*
* TODO: Because we don't know how to reliably stop the 3887 and
* the isl3886+net2280, other than brutally cut off all
* communications. We have to reinitialize the urbs on every start.
*/
return p54u_init_urbs(dev);
}

static __le32 p54u_lm87_chksum(const __le32 *data, size_t length)
{
u32 chk = 0;
Expand Down Expand Up @@ -836,70 +853,137 @@ static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev)
return err;
}

static int p54u_load_firmware(struct ieee80211_hw *dev)
static int p54_find_type(struct p54u_priv *priv)
{
struct p54u_priv *priv = dev->priv;
int err, i;

BUILD_BUG_ON(ARRAY_SIZE(p54u_fwlist) != __NUM_P54U_HWTYPES);
int i;

for (i = 0; i < __NUM_P54U_HWTYPES; i++)
if (p54u_fwlist[i].type == priv->hw_type)
break;

if (i == __NUM_P54U_HWTYPES)
return -EOPNOTSUPP;

err = request_firmware(&priv->fw, p54u_fwlist[i].fw, &priv->udev->dev);
if (err) {
dev_err(&priv->udev->dev, "(p54usb) cannot load firmware %s "
"(%d)!\n", p54u_fwlist[i].fw, err);
return i;
}

err = request_firmware(&priv->fw, p54u_fwlist[i].fw_legacy,
&priv->udev->dev);
if (err)
return err;
}
static int p54u_start_ops(struct p54u_priv *priv)
{
struct ieee80211_hw *dev = priv->common.hw;
int ret;

err = p54_parse_firmware(dev, priv->fw);
if (err)
goto out;
ret = p54_parse_firmware(dev, priv->fw);
if (ret)
goto err_out;

ret = p54_find_type(priv);
if (ret < 0)
goto err_out;

if (priv->common.fw_interface != p54u_fwlist[i].intf) {
if (priv->common.fw_interface != p54u_fwlist[ret].intf) {
dev_err(&priv->udev->dev, "wrong firmware, please get "
"a firmware for \"%s\" and try again.\n",
p54u_fwlist[i].hw);
err = -EINVAL;
p54u_fwlist[ret].hw);
ret = -ENODEV;
goto err_out;
}

out:
if (err)
release_firmware(priv->fw);
ret = priv->upload_fw(dev);
if (ret)
goto err_out;

return err;
ret = p54u_open(dev);
if (ret)
goto err_out;

ret = p54_read_eeprom(dev);
if (ret)
goto err_stop;

p54u_stop(dev);

ret = p54_register_common(dev, &priv->udev->dev);
if (ret)
goto err_stop;

return 0;

err_stop:
p54u_stop(dev);

err_out:
/*
* p54u_disconnect will do the rest of the
* cleanup
*/
return ret;
}

static int p54u_open(struct ieee80211_hw *dev)
static void p54u_load_firmware_cb(const struct firmware *firmware,
void *context)
{
struct p54u_priv *priv = dev->priv;
struct p54u_priv *priv = context;
struct usb_device *udev = priv->udev;
int err;

err = p54u_init_urbs(dev);
if (err) {
return err;
complete(&priv->fw_wait_load);
if (firmware) {
priv->fw = firmware;
err = p54u_start_ops(priv);
} else {
err = -ENOENT;
dev_err(&udev->dev, "Firmware not found.\n");
}

priv->common.open = p54u_init_urbs;
if (err) {
struct device *parent = priv->udev->dev.parent;

return 0;
dev_err(&udev->dev, "failed to initialize device (%d)\n", err);

if (parent)
device_lock(parent);

device_release_driver(&udev->dev);
/*
* At this point p54u_disconnect has already freed
* the "priv" context. Do not use it anymore!
*/
priv = NULL;

if (parent)
device_unlock(parent);
}

usb_put_dev(udev);
}

static void p54u_stop(struct ieee80211_hw *dev)
static int p54u_load_firmware(struct ieee80211_hw *dev,
struct usb_interface *intf)
{
/* TODO: figure out how to reliably stop the 3887 and net2280 so
the hardware is still usable next time we want to start it.
until then, we just stop listening to the hardware.. */
p54u_free_urbs(dev);
struct usb_device *udev = interface_to_usbdev(intf);
struct p54u_priv *priv = dev->priv;
struct device *device = &udev->dev;
int err, i;

BUILD_BUG_ON(ARRAY_SIZE(p54u_fwlist) != __NUM_P54U_HWTYPES);

init_completion(&priv->fw_wait_load);
i = p54_find_type(priv);
if (i < 0)
return i;

dev_info(&priv->udev->dev, "Loading firmware file %s\n",
p54u_fwlist[i].fw);

usb_get_dev(udev);
err = request_firmware_nowait(THIS_MODULE, 1, p54u_fwlist[i].fw,
device, GFP_KERNEL, priv,
p54u_load_firmware_cb);
if (err) {
dev_err(&priv->udev->dev, "(p54usb) cannot load firmware %s "
"(%d)!\n", p54u_fwlist[i].fw, err);
}

return err;
}

static int __devinit p54u_probe(struct usb_interface *intf,
Expand Down Expand Up @@ -969,33 +1053,7 @@ static int __devinit p54u_probe(struct usb_interface *intf,
priv->common.tx = p54u_tx_net2280;
priv->upload_fw = p54u_upload_firmware_net2280;
}
err = p54u_load_firmware(dev);
if (err)
goto err_free_dev;

err = priv->upload_fw(dev);
if (err)
goto err_free_fw;

p54u_open(dev);
err = p54_read_eeprom(dev);
p54u_stop(dev);
if (err)
goto err_free_fw;

err = p54_register_common(dev, &udev->dev);
if (err)
goto err_free_fw;

return 0;

err_free_fw:
release_firmware(priv->fw);

err_free_dev:
p54_free_common(dev);
usb_set_intfdata(intf, NULL);
usb_put_dev(udev);
err = p54u_load_firmware(dev, intf);
return err;
}

Expand All @@ -1007,9 +1065,10 @@ static void __devexit p54u_disconnect(struct usb_interface *intf)
if (!dev)
return;

priv = dev->priv;
wait_for_completion(&priv->fw_wait_load);
p54_unregister_common(dev);

priv = dev->priv;
usb_put_dev(interface_to_usbdev(intf));
release_firmware(priv->fw);
p54_free_common(dev);
Expand Down
3 changes: 3 additions & 0 deletions trunk/drivers/net/wireless/p54/p54usb.h
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,9 @@ struct p54u_priv {
struct sk_buff_head rx_queue;
struct usb_anchor submitted;
const struct firmware *fw;

/* asynchronous firmware callback */
struct completion fw_wait_load;
};

#endif /* P54USB_H */

0 comments on commit 76f7785

Please sign in to comment.