Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ce84bb69 authored by Daniel Drake's avatar Daniel Drake Committed by John W. Linville
Browse files

libertas USB: convert to asynchronous firmware loading

parent 66d647ef
Loading
Loading
Loading
Loading
+43 −59
Original line number Diff line number Diff line
@@ -41,6 +41,16 @@ enum {
	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[] = {
	/* Enter the device signature inside */
	{ 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_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,
			       uint8_t *payload, uint16_t nb);
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 lbs_private *priv;
	struct if_usb_card *cardp;
	int r = -ENOMEM;
	int i;

	udev = interface_to_usbdev(intf);
@@ -244,17 +257,10 @@ static int if_usb_probe(struct usb_interface *intf,
		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)))
		goto err_prog_firmware;
		goto err_add_card;

	cardp->priv = priv;
	cardp->priv->fw_ready = 1;

	priv->hw_host_to_card = if_usb_host_to_card;
	priv->enter_deep_sleep = NULL;
@@ -267,34 +273,25 @@ static int if_usb_probe(struct usb_interface *intf,

	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_set_intfdata(intf, cardp);

	/*
	 * 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;
	r = lbs_get_firmware_async(priv, &udev->dev, cardp->model,
				   fw_table, if_usb_prog_firmware);
	if (r)
		goto err_get_fw;

	return 0;

err_start_card:
err_get_fw:
	lbs_remove_card(priv);
err_prog_firmware:
err_add_card:
	if_usb_reset_device(cardp);
dealloc:
	if_usb_free(cardp);

error:
	return -ENOMEM;
	return r;
}

/**
@@ -829,49 +826,22 @@ static int check_fwfile_format(const uint8_t *data, uint32_t totlen)
	return ret;
}

/* table of firmware file names */
static const struct {
	u32 model;
	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)
static void if_usb_prog_firmware(struct lbs_private *priv, int ret,
				 const struct firmware *fw,
				 const struct firmware *unused)
{
	struct if_usb_card *cardp = priv->card;
	int i = 0;
	static int reset_count = 10;
	int ret = 0;

	lbs_deb_enter(LBS_DEB_USB);

	ret = get_fw(cardp);
	if (ret) {
		pr_err("failed to find firmware (%d)\n", ret);
		goto done;
	}

	cardp->fw = fw;
	if (check_fwfile_format(cardp->fw->data, cardp->fw->size)) {
		ret = -EINVAL;
		goto release_fw;
@@ -954,13 +924,27 @@ static int if_usb_prog_firmware(struct if_usb_card *cardp)
		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_firmware(cardp->fw);
	cardp->fw = NULL;

 done:
	lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret);
	return ret;
	lbs_deb_leave(LBS_DEB_USB);
}