libertas USB: convert to asynchronous firmware loading
Signed-off-by: Daniel Drake <dsd@laptop.org> Acked-by: Dan Williams <dcbw@redhat.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
66d647efe5
commit
ce84bb69f5
1 changed files with 43 additions and 59 deletions
|
@ -41,6 +41,16 @@ enum {
|
||||||
MODEL_8682 = 0x2
|
MODEL_8682 = 0x2
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* table of firmware file names */
|
||||||
|
static const struct lbs_fw_table fw_table[] = {
|
||||||
|
{ MODEL_8388, "libertas/usb8388_olpc.bin", NULL },
|
||||||
|
{ MODEL_8388, "libertas/usb8388_v9.bin", NULL },
|
||||||
|
{ MODEL_8388, "libertas/usb8388_v5.bin", NULL },
|
||||||
|
{ MODEL_8388, "libertas/usb8388.bin", NULL },
|
||||||
|
{ MODEL_8388, "usb8388.bin", NULL },
|
||||||
|
{ MODEL_8682, "libertas/usb8682.bin", NULL }
|
||||||
|
};
|
||||||
|
|
||||||
static struct usb_device_id if_usb_table[] = {
|
static struct usb_device_id if_usb_table[] = {
|
||||||
/* Enter the device signature inside */
|
/* Enter the device signature inside */
|
||||||
{ USB_DEVICE(0x1286, 0x2001), .driver_info = MODEL_8388 },
|
{ USB_DEVICE(0x1286, 0x2001), .driver_info = MODEL_8388 },
|
||||||
|
@ -52,7 +62,9 @@ MODULE_DEVICE_TABLE(usb, if_usb_table);
|
||||||
|
|
||||||
static void if_usb_receive(struct urb *urb);
|
static void if_usb_receive(struct urb *urb);
|
||||||
static void if_usb_receive_fwload(struct urb *urb);
|
static void if_usb_receive_fwload(struct urb *urb);
|
||||||
static int if_usb_prog_firmware(struct if_usb_card *cardp);
|
static void if_usb_prog_firmware(struct lbs_private *priv, int ret,
|
||||||
|
const struct firmware *fw,
|
||||||
|
const struct firmware *unused);
|
||||||
static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type,
|
static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type,
|
||||||
uint8_t *payload, uint16_t nb);
|
uint8_t *payload, uint16_t nb);
|
||||||
static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload,
|
static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload,
|
||||||
|
@ -187,6 +199,7 @@ static int if_usb_probe(struct usb_interface *intf,
|
||||||
struct usb_endpoint_descriptor *endpoint;
|
struct usb_endpoint_descriptor *endpoint;
|
||||||
struct lbs_private *priv;
|
struct lbs_private *priv;
|
||||||
struct if_usb_card *cardp;
|
struct if_usb_card *cardp;
|
||||||
|
int r = -ENOMEM;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
udev = interface_to_usbdev(intf);
|
udev = interface_to_usbdev(intf);
|
||||||
|
@ -244,17 +257,10 @@ static int if_usb_probe(struct usb_interface *intf,
|
||||||
goto dealloc;
|
goto dealloc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Upload firmware */
|
|
||||||
if (if_usb_prog_firmware(cardp)) {
|
|
||||||
lbs_deb_usbd(&udev->dev, "FW upload failed\n");
|
|
||||||
goto err_prog_firmware;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(priv = lbs_add_card(cardp, &intf->dev)))
|
if (!(priv = lbs_add_card(cardp, &intf->dev)))
|
||||||
goto err_prog_firmware;
|
goto err_add_card;
|
||||||
|
|
||||||
cardp->priv = priv;
|
cardp->priv = priv;
|
||||||
cardp->priv->fw_ready = 1;
|
|
||||||
|
|
||||||
priv->hw_host_to_card = if_usb_host_to_card;
|
priv->hw_host_to_card = if_usb_host_to_card;
|
||||||
priv->enter_deep_sleep = NULL;
|
priv->enter_deep_sleep = NULL;
|
||||||
|
@ -267,34 +273,25 @@ static int if_usb_probe(struct usb_interface *intf,
|
||||||
|
|
||||||
cardp->boot2_version = udev->descriptor.bcdDevice;
|
cardp->boot2_version = udev->descriptor.bcdDevice;
|
||||||
|
|
||||||
if_usb_submit_rx_urb(cardp);
|
|
||||||
|
|
||||||
if (lbs_start_card(priv))
|
|
||||||
goto err_start_card;
|
|
||||||
|
|
||||||
if_usb_setup_firmware(priv);
|
|
||||||
|
|
||||||
usb_get_dev(udev);
|
usb_get_dev(udev);
|
||||||
usb_set_intfdata(intf, cardp);
|
usb_set_intfdata(intf, cardp);
|
||||||
|
|
||||||
/*
|
r = lbs_get_firmware_async(priv, &udev->dev, cardp->model,
|
||||||
* EHS_REMOVE_WAKEUP is not supported on all versions of the firmware.
|
fw_table, if_usb_prog_firmware);
|
||||||
*/
|
if (r)
|
||||||
priv->wol_criteria = EHS_REMOVE_WAKEUP;
|
goto err_get_fw;
|
||||||
if (lbs_host_sleep_cfg(priv, priv->wol_criteria, NULL))
|
|
||||||
priv->ehs_remove_supported = false;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_start_card:
|
err_get_fw:
|
||||||
lbs_remove_card(priv);
|
lbs_remove_card(priv);
|
||||||
err_prog_firmware:
|
err_add_card:
|
||||||
if_usb_reset_device(cardp);
|
if_usb_reset_device(cardp);
|
||||||
dealloc:
|
dealloc:
|
||||||
if_usb_free(cardp);
|
if_usb_free(cardp);
|
||||||
|
|
||||||
error:
|
error:
|
||||||
return -ENOMEM;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -829,49 +826,22 @@ static int check_fwfile_format(const uint8_t *data, uint32_t totlen)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* table of firmware file names */
|
static void if_usb_prog_firmware(struct lbs_private *priv, int ret,
|
||||||
static const struct {
|
const struct firmware *fw,
|
||||||
u32 model;
|
const struct firmware *unused)
|
||||||
const char *fwname;
|
|
||||||
} fw_table[] = {
|
|
||||||
{ MODEL_8388, "libertas/usb8388_olpc.bin" },
|
|
||||||
{ MODEL_8388, "libertas/usb8388_v9.bin" },
|
|
||||||
{ MODEL_8388, "libertas/usb8388_v5.bin" },
|
|
||||||
{ MODEL_8388, "libertas/usb8388.bin" },
|
|
||||||
{ MODEL_8388, "usb8388.bin" },
|
|
||||||
{ MODEL_8682, "libertas/usb8682.bin" }
|
|
||||||
};
|
|
||||||
|
|
||||||
static int get_fw(struct if_usb_card *cardp)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
/* Otherwise search for firmware to use */
|
|
||||||
for (i = 0; i < ARRAY_SIZE(fw_table); i++) {
|
|
||||||
if (fw_table[i].model != cardp->model)
|
|
||||||
continue;
|
|
||||||
if (request_firmware(&cardp->fw, fw_table[i].fwname,
|
|
||||||
&cardp->udev->dev) == 0)
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -ENOENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int if_usb_prog_firmware(struct if_usb_card *cardp)
|
|
||||||
{
|
{
|
||||||
|
struct if_usb_card *cardp = priv->card;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
static int reset_count = 10;
|
static int reset_count = 10;
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
lbs_deb_enter(LBS_DEB_USB);
|
lbs_deb_enter(LBS_DEB_USB);
|
||||||
|
|
||||||
ret = get_fw(cardp);
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_err("failed to find firmware (%d)\n", ret);
|
pr_err("failed to find firmware (%d)\n", ret);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cardp->fw = fw;
|
||||||
if (check_fwfile_format(cardp->fw->data, cardp->fw->size)) {
|
if (check_fwfile_format(cardp->fw->data, cardp->fw->size)) {
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto release_fw;
|
goto release_fw;
|
||||||
|
@ -954,13 +924,27 @@ restart:
|
||||||
goto release_fw;
|
goto release_fw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cardp->priv->fw_ready = 1;
|
||||||
|
if_usb_submit_rx_urb(cardp);
|
||||||
|
|
||||||
|
if (lbs_start_card(priv))
|
||||||
|
goto release_fw;
|
||||||
|
|
||||||
|
if_usb_setup_firmware(priv);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* EHS_REMOVE_WAKEUP is not supported on all versions of the firmware.
|
||||||
|
*/
|
||||||
|
priv->wol_criteria = EHS_REMOVE_WAKEUP;
|
||||||
|
if (lbs_host_sleep_cfg(priv, priv->wol_criteria, NULL))
|
||||||
|
priv->ehs_remove_supported = false;
|
||||||
|
|
||||||
release_fw:
|
release_fw:
|
||||||
release_firmware(cardp->fw);
|
release_firmware(cardp->fw);
|
||||||
cardp->fw = NULL;
|
cardp->fw = NULL;
|
||||||
|
|
||||||
done:
|
done:
|
||||||
lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret);
|
lbs_deb_leave(LBS_DEB_USB);
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue