1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * This file contains functions used in USB interface module.
4*4882a593Smuzhiyun */
5*4882a593Smuzhiyun
6*4882a593Smuzhiyun #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include <linux/delay.h>
9*4882a593Smuzhiyun #include <linux/module.h>
10*4882a593Smuzhiyun #include <linux/firmware.h>
11*4882a593Smuzhiyun #include <linux/netdevice.h>
12*4882a593Smuzhiyun #include <linux/slab.h>
13*4882a593Smuzhiyun #include <linux/usb.h>
14*4882a593Smuzhiyun #include <linux/olpc-ec.h>
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun #ifdef CONFIG_OLPC
17*4882a593Smuzhiyun #include <asm/olpc.h>
18*4882a593Smuzhiyun #endif
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun #define DRV_NAME "usb8xxx"
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun #include "host.h"
23*4882a593Smuzhiyun #include "decl.h"
24*4882a593Smuzhiyun #include "defs.h"
25*4882a593Smuzhiyun #include "dev.h"
26*4882a593Smuzhiyun #include "cmd.h"
27*4882a593Smuzhiyun #include "if_usb.h"
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun #define INSANEDEBUG 0
30*4882a593Smuzhiyun #define lbs_deb_usb2(...) do { if (INSANEDEBUG) lbs_deb_usbd(__VA_ARGS__); } while (0)
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun #define MESSAGE_HEADER_LEN 4
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun MODULE_FIRMWARE("libertas/usb8388_v9.bin");
35*4882a593Smuzhiyun MODULE_FIRMWARE("libertas/usb8388_v5.bin");
36*4882a593Smuzhiyun MODULE_FIRMWARE("libertas/usb8388.bin");
37*4882a593Smuzhiyun MODULE_FIRMWARE("libertas/usb8682.bin");
38*4882a593Smuzhiyun MODULE_FIRMWARE("usb8388.bin");
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun enum {
41*4882a593Smuzhiyun MODEL_UNKNOWN = 0x0,
42*4882a593Smuzhiyun MODEL_8388 = 0x1,
43*4882a593Smuzhiyun MODEL_8682 = 0x2
44*4882a593Smuzhiyun };
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun /* table of firmware file names */
47*4882a593Smuzhiyun static const struct lbs_fw_table fw_table[] = {
48*4882a593Smuzhiyun { MODEL_8388, "libertas/usb8388_olpc.bin", NULL },
49*4882a593Smuzhiyun { MODEL_8388, "libertas/usb8388_v9.bin", NULL },
50*4882a593Smuzhiyun { MODEL_8388, "libertas/usb8388_v5.bin", NULL },
51*4882a593Smuzhiyun { MODEL_8388, "libertas/usb8388.bin", NULL },
52*4882a593Smuzhiyun { MODEL_8388, "usb8388.bin", NULL },
53*4882a593Smuzhiyun { MODEL_8682, "libertas/usb8682.bin", NULL },
54*4882a593Smuzhiyun { 0, NULL, NULL }
55*4882a593Smuzhiyun };
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun static const struct usb_device_id if_usb_table[] = {
58*4882a593Smuzhiyun /* Enter the device signature inside */
59*4882a593Smuzhiyun { USB_DEVICE(0x1286, 0x2001), .driver_info = MODEL_8388 },
60*4882a593Smuzhiyun { USB_DEVICE(0x05a3, 0x8388), .driver_info = MODEL_8388 },
61*4882a593Smuzhiyun {} /* Terminating entry */
62*4882a593Smuzhiyun };
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun MODULE_DEVICE_TABLE(usb, if_usb_table);
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun static void if_usb_receive(struct urb *urb);
67*4882a593Smuzhiyun static void if_usb_receive_fwload(struct urb *urb);
68*4882a593Smuzhiyun static void if_usb_prog_firmware(struct lbs_private *priv, int ret,
69*4882a593Smuzhiyun const struct firmware *fw,
70*4882a593Smuzhiyun const struct firmware *unused);
71*4882a593Smuzhiyun static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type,
72*4882a593Smuzhiyun uint8_t *payload, uint16_t nb);
73*4882a593Smuzhiyun static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload,
74*4882a593Smuzhiyun uint16_t nb);
75*4882a593Smuzhiyun static void if_usb_free(struct if_usb_card *cardp);
76*4882a593Smuzhiyun static int if_usb_submit_rx_urb(struct if_usb_card *cardp);
77*4882a593Smuzhiyun static int if_usb_reset_device(struct if_usb_card *cardp);
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun /**
80*4882a593Smuzhiyun * if_usb_write_bulk_callback - callback function to handle the status
81*4882a593Smuzhiyun * of the URB
82*4882a593Smuzhiyun * @urb: pointer to &urb structure
83*4882a593Smuzhiyun * returns: N/A
84*4882a593Smuzhiyun */
if_usb_write_bulk_callback(struct urb * urb)85*4882a593Smuzhiyun static void if_usb_write_bulk_callback(struct urb *urb)
86*4882a593Smuzhiyun {
87*4882a593Smuzhiyun struct if_usb_card *cardp = (struct if_usb_card *) urb->context;
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun /* handle the transmission complete validations */
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun if (urb->status == 0) {
92*4882a593Smuzhiyun struct lbs_private *priv = cardp->priv;
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun lbs_deb_usb2(&urb->dev->dev, "URB status is successful\n");
95*4882a593Smuzhiyun lbs_deb_usb2(&urb->dev->dev, "Actual length transmitted %d\n",
96*4882a593Smuzhiyun urb->actual_length);
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun /* Boot commands such as UPDATE_FW and UPDATE_BOOT2 are not
99*4882a593Smuzhiyun * passed up to the lbs level.
100*4882a593Smuzhiyun */
101*4882a593Smuzhiyun if (priv && priv->dnld_sent != DNLD_BOOTCMD_SENT)
102*4882a593Smuzhiyun lbs_host_to_card_done(priv);
103*4882a593Smuzhiyun } else {
104*4882a593Smuzhiyun /* print the failure status number for debug */
105*4882a593Smuzhiyun pr_info("URB in failure status: %d\n", urb->status);
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun }
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun /**
110*4882a593Smuzhiyun * if_usb_free - free tx/rx urb, skb and rx buffer
111*4882a593Smuzhiyun * @cardp: pointer to &if_usb_card
112*4882a593Smuzhiyun * returns: N/A
113*4882a593Smuzhiyun */
if_usb_free(struct if_usb_card * cardp)114*4882a593Smuzhiyun static void if_usb_free(struct if_usb_card *cardp)
115*4882a593Smuzhiyun {
116*4882a593Smuzhiyun /* Unlink tx & rx urb */
117*4882a593Smuzhiyun usb_kill_urb(cardp->tx_urb);
118*4882a593Smuzhiyun usb_kill_urb(cardp->rx_urb);
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun usb_free_urb(cardp->tx_urb);
121*4882a593Smuzhiyun cardp->tx_urb = NULL;
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun usb_free_urb(cardp->rx_urb);
124*4882a593Smuzhiyun cardp->rx_urb = NULL;
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun kfree(cardp->ep_out_buf);
127*4882a593Smuzhiyun cardp->ep_out_buf = NULL;
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun
if_usb_setup_firmware(struct lbs_private * priv)130*4882a593Smuzhiyun static void if_usb_setup_firmware(struct lbs_private *priv)
131*4882a593Smuzhiyun {
132*4882a593Smuzhiyun struct if_usb_card *cardp = priv->card;
133*4882a593Smuzhiyun struct cmd_ds_set_boot2_ver b2_cmd;
134*4882a593Smuzhiyun struct cmd_ds_802_11_fw_wake_method wake_method;
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun b2_cmd.hdr.size = cpu_to_le16(sizeof(b2_cmd));
137*4882a593Smuzhiyun b2_cmd.action = 0;
138*4882a593Smuzhiyun b2_cmd.version = cardp->boot2_version;
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun if (lbs_cmd_with_response(priv, CMD_SET_BOOT2_VER, &b2_cmd))
141*4882a593Smuzhiyun lbs_deb_usb("Setting boot2 version failed\n");
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun priv->wol_gpio = 2; /* Wake via GPIO2... */
144*4882a593Smuzhiyun priv->wol_gap = 20; /* ... after 20ms */
145*4882a593Smuzhiyun lbs_host_sleep_cfg(priv, EHS_WAKE_ON_UNICAST_DATA,
146*4882a593Smuzhiyun (struct wol_config *) NULL);
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun wake_method.hdr.size = cpu_to_le16(sizeof(wake_method));
149*4882a593Smuzhiyun wake_method.action = cpu_to_le16(CMD_ACT_GET);
150*4882a593Smuzhiyun if (lbs_cmd_with_response(priv, CMD_802_11_FW_WAKE_METHOD, &wake_method)) {
151*4882a593Smuzhiyun netdev_info(priv->dev, "Firmware does not seem to support PS mode\n");
152*4882a593Smuzhiyun priv->fwcapinfo &= ~FW_CAPINFO_PS;
153*4882a593Smuzhiyun } else {
154*4882a593Smuzhiyun if (le16_to_cpu(wake_method.method) == CMD_WAKE_METHOD_COMMAND_INT) {
155*4882a593Smuzhiyun lbs_deb_usb("Firmware seems to support PS with wake-via-command\n");
156*4882a593Smuzhiyun } else {
157*4882a593Smuzhiyun /* The versions which boot up this way don't seem to
158*4882a593Smuzhiyun work even if we set it to the command interrupt */
159*4882a593Smuzhiyun priv->fwcapinfo &= ~FW_CAPINFO_PS;
160*4882a593Smuzhiyun netdev_info(priv->dev,
161*4882a593Smuzhiyun "Firmware doesn't wake via command interrupt; disabling PS mode\n");
162*4882a593Smuzhiyun }
163*4882a593Smuzhiyun }
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun
if_usb_fw_timeo(struct timer_list * t)166*4882a593Smuzhiyun static void if_usb_fw_timeo(struct timer_list *t)
167*4882a593Smuzhiyun {
168*4882a593Smuzhiyun struct if_usb_card *cardp = from_timer(cardp, t, fw_timeout);
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun if (cardp->fwdnldover) {
171*4882a593Smuzhiyun lbs_deb_usb("Download complete, no event. Assuming success\n");
172*4882a593Smuzhiyun } else {
173*4882a593Smuzhiyun pr_err("Download timed out\n");
174*4882a593Smuzhiyun cardp->surprise_removed = 1;
175*4882a593Smuzhiyun }
176*4882a593Smuzhiyun wake_up(&cardp->fw_wq);
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun #ifdef CONFIG_OLPC
if_usb_reset_olpc_card(struct lbs_private * priv)180*4882a593Smuzhiyun static void if_usb_reset_olpc_card(struct lbs_private *priv)
181*4882a593Smuzhiyun {
182*4882a593Smuzhiyun printk(KERN_CRIT "Resetting OLPC wireless via EC...\n");
183*4882a593Smuzhiyun olpc_ec_cmd(0x25, NULL, 0, NULL, 0);
184*4882a593Smuzhiyun }
185*4882a593Smuzhiyun #endif
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun /**
188*4882a593Smuzhiyun * if_usb_probe - sets the configuration values
189*4882a593Smuzhiyun * @intf: &usb_interface pointer
190*4882a593Smuzhiyun * @id: pointer to usb_device_id
191*4882a593Smuzhiyun * returns: 0 on success, error code on failure
192*4882a593Smuzhiyun */
if_usb_probe(struct usb_interface * intf,const struct usb_device_id * id)193*4882a593Smuzhiyun static int if_usb_probe(struct usb_interface *intf,
194*4882a593Smuzhiyun const struct usb_device_id *id)
195*4882a593Smuzhiyun {
196*4882a593Smuzhiyun struct usb_device *udev;
197*4882a593Smuzhiyun struct usb_host_interface *iface_desc;
198*4882a593Smuzhiyun struct usb_endpoint_descriptor *endpoint;
199*4882a593Smuzhiyun struct lbs_private *priv;
200*4882a593Smuzhiyun struct if_usb_card *cardp;
201*4882a593Smuzhiyun int r = -ENOMEM;
202*4882a593Smuzhiyun int i;
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun udev = interface_to_usbdev(intf);
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun cardp = kzalloc(sizeof(struct if_usb_card), GFP_KERNEL);
207*4882a593Smuzhiyun if (!cardp)
208*4882a593Smuzhiyun goto error;
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun timer_setup(&cardp->fw_timeout, if_usb_fw_timeo, 0);
211*4882a593Smuzhiyun init_waitqueue_head(&cardp->fw_wq);
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun cardp->udev = udev;
214*4882a593Smuzhiyun cardp->model = (uint32_t) id->driver_info;
215*4882a593Smuzhiyun iface_desc = intf->cur_altsetting;
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun lbs_deb_usbd(&udev->dev, "bcdUSB = 0x%X bDeviceClass = 0x%X"
218*4882a593Smuzhiyun " bDeviceSubClass = 0x%X, bDeviceProtocol = 0x%X\n",
219*4882a593Smuzhiyun le16_to_cpu(udev->descriptor.bcdUSB),
220*4882a593Smuzhiyun udev->descriptor.bDeviceClass,
221*4882a593Smuzhiyun udev->descriptor.bDeviceSubClass,
222*4882a593Smuzhiyun udev->descriptor.bDeviceProtocol);
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
225*4882a593Smuzhiyun endpoint = &iface_desc->endpoint[i].desc;
226*4882a593Smuzhiyun if (usb_endpoint_is_bulk_in(endpoint)) {
227*4882a593Smuzhiyun cardp->ep_in_size = le16_to_cpu(endpoint->wMaxPacketSize);
228*4882a593Smuzhiyun cardp->ep_in = usb_endpoint_num(endpoint);
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun lbs_deb_usbd(&udev->dev, "in_endpoint = %d\n", cardp->ep_in);
231*4882a593Smuzhiyun lbs_deb_usbd(&udev->dev, "Bulk in size is %d\n", cardp->ep_in_size);
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun } else if (usb_endpoint_is_bulk_out(endpoint)) {
234*4882a593Smuzhiyun cardp->ep_out_size = le16_to_cpu(endpoint->wMaxPacketSize);
235*4882a593Smuzhiyun cardp->ep_out = usb_endpoint_num(endpoint);
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun lbs_deb_usbd(&udev->dev, "out_endpoint = %d\n", cardp->ep_out);
238*4882a593Smuzhiyun lbs_deb_usbd(&udev->dev, "Bulk out size is %d\n", cardp->ep_out_size);
239*4882a593Smuzhiyun }
240*4882a593Smuzhiyun }
241*4882a593Smuzhiyun if (!cardp->ep_out_size || !cardp->ep_in_size) {
242*4882a593Smuzhiyun lbs_deb_usbd(&udev->dev, "Endpoints not found\n");
243*4882a593Smuzhiyun goto dealloc;
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun if (!(cardp->rx_urb = usb_alloc_urb(0, GFP_KERNEL))) {
246*4882a593Smuzhiyun lbs_deb_usbd(&udev->dev, "Rx URB allocation failed\n");
247*4882a593Smuzhiyun goto dealloc;
248*4882a593Smuzhiyun }
249*4882a593Smuzhiyun if (!(cardp->tx_urb = usb_alloc_urb(0, GFP_KERNEL))) {
250*4882a593Smuzhiyun lbs_deb_usbd(&udev->dev, "Tx URB allocation failed\n");
251*4882a593Smuzhiyun goto dealloc;
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun cardp->ep_out_buf = kmalloc(MRVDRV_ETH_TX_PACKET_BUFFER_SIZE, GFP_KERNEL);
254*4882a593Smuzhiyun if (!cardp->ep_out_buf) {
255*4882a593Smuzhiyun lbs_deb_usbd(&udev->dev, "Could not allocate buffer\n");
256*4882a593Smuzhiyun goto dealloc;
257*4882a593Smuzhiyun }
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun priv = lbs_add_card(cardp, &intf->dev);
260*4882a593Smuzhiyun if (IS_ERR(priv)) {
261*4882a593Smuzhiyun r = PTR_ERR(priv);
262*4882a593Smuzhiyun goto err_add_card;
263*4882a593Smuzhiyun }
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun cardp->priv = priv;
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun priv->hw_host_to_card = if_usb_host_to_card;
268*4882a593Smuzhiyun priv->enter_deep_sleep = NULL;
269*4882a593Smuzhiyun priv->exit_deep_sleep = NULL;
270*4882a593Smuzhiyun priv->reset_deep_sleep_wakeup = NULL;
271*4882a593Smuzhiyun priv->is_polling = false;
272*4882a593Smuzhiyun #ifdef CONFIG_OLPC
273*4882a593Smuzhiyun if (machine_is_olpc())
274*4882a593Smuzhiyun priv->reset_card = if_usb_reset_olpc_card;
275*4882a593Smuzhiyun #endif
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun cardp->boot2_version = udev->descriptor.bcdDevice;
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun usb_get_dev(udev);
280*4882a593Smuzhiyun usb_set_intfdata(intf, cardp);
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun r = lbs_get_firmware_async(priv, &udev->dev, cardp->model,
283*4882a593Smuzhiyun fw_table, if_usb_prog_firmware);
284*4882a593Smuzhiyun if (r)
285*4882a593Smuzhiyun goto err_get_fw;
286*4882a593Smuzhiyun
287*4882a593Smuzhiyun return 0;
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun err_get_fw:
290*4882a593Smuzhiyun usb_put_dev(udev);
291*4882a593Smuzhiyun lbs_remove_card(priv);
292*4882a593Smuzhiyun err_add_card:
293*4882a593Smuzhiyun if_usb_reset_device(cardp);
294*4882a593Smuzhiyun dealloc:
295*4882a593Smuzhiyun if_usb_free(cardp);
296*4882a593Smuzhiyun kfree(cardp);
297*4882a593Smuzhiyun
298*4882a593Smuzhiyun error:
299*4882a593Smuzhiyun return r;
300*4882a593Smuzhiyun }
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun /**
303*4882a593Smuzhiyun * if_usb_disconnect - free resource and cleanup
304*4882a593Smuzhiyun * @intf: USB interface structure
305*4882a593Smuzhiyun * returns: N/A
306*4882a593Smuzhiyun */
if_usb_disconnect(struct usb_interface * intf)307*4882a593Smuzhiyun static void if_usb_disconnect(struct usb_interface *intf)
308*4882a593Smuzhiyun {
309*4882a593Smuzhiyun struct if_usb_card *cardp = usb_get_intfdata(intf);
310*4882a593Smuzhiyun struct lbs_private *priv = cardp->priv;
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun cardp->surprise_removed = 1;
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun if (priv) {
315*4882a593Smuzhiyun lbs_stop_card(priv);
316*4882a593Smuzhiyun lbs_remove_card(priv);
317*4882a593Smuzhiyun }
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun /* Unlink and free urb */
320*4882a593Smuzhiyun if_usb_free(cardp);
321*4882a593Smuzhiyun kfree(cardp);
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun usb_set_intfdata(intf, NULL);
324*4882a593Smuzhiyun usb_put_dev(interface_to_usbdev(intf));
325*4882a593Smuzhiyun }
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun /**
328*4882a593Smuzhiyun * if_usb_send_fw_pkt - download FW
329*4882a593Smuzhiyun * @cardp: pointer to &struct if_usb_card
330*4882a593Smuzhiyun * returns: 0
331*4882a593Smuzhiyun */
if_usb_send_fw_pkt(struct if_usb_card * cardp)332*4882a593Smuzhiyun static int if_usb_send_fw_pkt(struct if_usb_card *cardp)
333*4882a593Smuzhiyun {
334*4882a593Smuzhiyun struct fwdata *fwdata = cardp->ep_out_buf;
335*4882a593Smuzhiyun const uint8_t *firmware = cardp->fw->data;
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun /* If we got a CRC failure on the last block, back
338*4882a593Smuzhiyun up and retry it */
339*4882a593Smuzhiyun if (!cardp->CRC_OK) {
340*4882a593Smuzhiyun cardp->totalbytes = cardp->fwlastblksent;
341*4882a593Smuzhiyun cardp->fwseqnum--;
342*4882a593Smuzhiyun }
343*4882a593Smuzhiyun
344*4882a593Smuzhiyun lbs_deb_usb2(&cardp->udev->dev, "totalbytes = %d\n",
345*4882a593Smuzhiyun cardp->totalbytes);
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun /* struct fwdata (which we sent to the card) has an
348*4882a593Smuzhiyun extra __le32 field in between the header and the data,
349*4882a593Smuzhiyun which is not in the struct fwheader in the actual
350*4882a593Smuzhiyun firmware binary. Insert the seqnum in the middle... */
351*4882a593Smuzhiyun memcpy(&fwdata->hdr, &firmware[cardp->totalbytes],
352*4882a593Smuzhiyun sizeof(struct fwheader));
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun cardp->fwlastblksent = cardp->totalbytes;
355*4882a593Smuzhiyun cardp->totalbytes += sizeof(struct fwheader);
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun memcpy(fwdata->data, &firmware[cardp->totalbytes],
358*4882a593Smuzhiyun le32_to_cpu(fwdata->hdr.datalength));
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun lbs_deb_usb2(&cardp->udev->dev, "Data length = %d\n",
361*4882a593Smuzhiyun le32_to_cpu(fwdata->hdr.datalength));
362*4882a593Smuzhiyun
363*4882a593Smuzhiyun fwdata->seqnum = cpu_to_le32(++cardp->fwseqnum);
364*4882a593Smuzhiyun cardp->totalbytes += le32_to_cpu(fwdata->hdr.datalength);
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun usb_tx_block(cardp, cardp->ep_out_buf, sizeof(struct fwdata) +
367*4882a593Smuzhiyun le32_to_cpu(fwdata->hdr.datalength));
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun if (fwdata->hdr.dnldcmd == cpu_to_le32(FW_HAS_DATA_TO_RECV)) {
370*4882a593Smuzhiyun lbs_deb_usb2(&cardp->udev->dev, "There are data to follow\n");
371*4882a593Smuzhiyun lbs_deb_usb2(&cardp->udev->dev, "seqnum = %d totalbytes = %d\n",
372*4882a593Smuzhiyun cardp->fwseqnum, cardp->totalbytes);
373*4882a593Smuzhiyun } else if (fwdata->hdr.dnldcmd == cpu_to_le32(FW_HAS_LAST_BLOCK)) {
374*4882a593Smuzhiyun lbs_deb_usb2(&cardp->udev->dev, "Host has finished FW downloading\n");
375*4882a593Smuzhiyun lbs_deb_usb2(&cardp->udev->dev, "Downloading FW JUMP BLOCK\n");
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun cardp->fwfinalblk = 1;
378*4882a593Smuzhiyun }
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun lbs_deb_usb2(&cardp->udev->dev, "Firmware download done; size %d\n",
381*4882a593Smuzhiyun cardp->totalbytes);
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun return 0;
384*4882a593Smuzhiyun }
385*4882a593Smuzhiyun
if_usb_reset_device(struct if_usb_card * cardp)386*4882a593Smuzhiyun static int if_usb_reset_device(struct if_usb_card *cardp)
387*4882a593Smuzhiyun {
388*4882a593Smuzhiyun struct cmd_header *cmd = cardp->ep_out_buf + 4;
389*4882a593Smuzhiyun int ret;
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun *(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_REQUEST);
392*4882a593Smuzhiyun
393*4882a593Smuzhiyun cmd->command = cpu_to_le16(CMD_802_11_RESET);
394*4882a593Smuzhiyun cmd->size = cpu_to_le16(sizeof(cmd));
395*4882a593Smuzhiyun cmd->result = cpu_to_le16(0);
396*4882a593Smuzhiyun cmd->seqnum = cpu_to_le16(0x5a5a);
397*4882a593Smuzhiyun usb_tx_block(cardp, cardp->ep_out_buf, 4 + sizeof(struct cmd_header));
398*4882a593Smuzhiyun
399*4882a593Smuzhiyun msleep(100);
400*4882a593Smuzhiyun ret = usb_reset_device(cardp->udev);
401*4882a593Smuzhiyun msleep(100);
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun #ifdef CONFIG_OLPC
404*4882a593Smuzhiyun if (ret && machine_is_olpc())
405*4882a593Smuzhiyun if_usb_reset_olpc_card(NULL);
406*4882a593Smuzhiyun #endif
407*4882a593Smuzhiyun
408*4882a593Smuzhiyun return ret;
409*4882a593Smuzhiyun }
410*4882a593Smuzhiyun
411*4882a593Smuzhiyun /**
412*4882a593Smuzhiyun * usb_tx_block - transfer the data to the device
413*4882a593Smuzhiyun * @cardp: pointer to &struct if_usb_card
414*4882a593Smuzhiyun * @payload: pointer to payload data
415*4882a593Smuzhiyun * @nb: data length
416*4882a593Smuzhiyun * returns: 0 for success or negative error code
417*4882a593Smuzhiyun */
usb_tx_block(struct if_usb_card * cardp,uint8_t * payload,uint16_t nb)418*4882a593Smuzhiyun static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload, uint16_t nb)
419*4882a593Smuzhiyun {
420*4882a593Smuzhiyun int ret;
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun /* check if device is removed */
423*4882a593Smuzhiyun if (cardp->surprise_removed) {
424*4882a593Smuzhiyun lbs_deb_usbd(&cardp->udev->dev, "Device removed\n");
425*4882a593Smuzhiyun ret = -ENODEV;
426*4882a593Smuzhiyun goto tx_ret;
427*4882a593Smuzhiyun }
428*4882a593Smuzhiyun
429*4882a593Smuzhiyun usb_fill_bulk_urb(cardp->tx_urb, cardp->udev,
430*4882a593Smuzhiyun usb_sndbulkpipe(cardp->udev,
431*4882a593Smuzhiyun cardp->ep_out),
432*4882a593Smuzhiyun payload, nb, if_usb_write_bulk_callback, cardp);
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun cardp->tx_urb->transfer_flags |= URB_ZERO_PACKET;
435*4882a593Smuzhiyun
436*4882a593Smuzhiyun if ((ret = usb_submit_urb(cardp->tx_urb, GFP_ATOMIC))) {
437*4882a593Smuzhiyun lbs_deb_usbd(&cardp->udev->dev, "usb_submit_urb failed: %d\n", ret);
438*4882a593Smuzhiyun } else {
439*4882a593Smuzhiyun lbs_deb_usb2(&cardp->udev->dev, "usb_submit_urb success\n");
440*4882a593Smuzhiyun ret = 0;
441*4882a593Smuzhiyun }
442*4882a593Smuzhiyun
443*4882a593Smuzhiyun tx_ret:
444*4882a593Smuzhiyun return ret;
445*4882a593Smuzhiyun }
446*4882a593Smuzhiyun
__if_usb_submit_rx_urb(struct if_usb_card * cardp,void (* callbackfn)(struct urb * urb))447*4882a593Smuzhiyun static int __if_usb_submit_rx_urb(struct if_usb_card *cardp,
448*4882a593Smuzhiyun void (*callbackfn)(struct urb *urb))
449*4882a593Smuzhiyun {
450*4882a593Smuzhiyun struct sk_buff *skb;
451*4882a593Smuzhiyun int ret = -1;
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun if (!(skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE))) {
454*4882a593Smuzhiyun pr_err("No free skb\n");
455*4882a593Smuzhiyun goto rx_ret;
456*4882a593Smuzhiyun }
457*4882a593Smuzhiyun
458*4882a593Smuzhiyun cardp->rx_skb = skb;
459*4882a593Smuzhiyun
460*4882a593Smuzhiyun /* Fill the receive configuration URB and initialise the Rx call back */
461*4882a593Smuzhiyun usb_fill_bulk_urb(cardp->rx_urb, cardp->udev,
462*4882a593Smuzhiyun usb_rcvbulkpipe(cardp->udev, cardp->ep_in),
463*4882a593Smuzhiyun skb->data + IPFIELD_ALIGN_OFFSET,
464*4882a593Smuzhiyun MRVDRV_ETH_RX_PACKET_BUFFER_SIZE, callbackfn,
465*4882a593Smuzhiyun cardp);
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun lbs_deb_usb2(&cardp->udev->dev, "Pointer for rx_urb %p\n", cardp->rx_urb);
468*4882a593Smuzhiyun if ((ret = usb_submit_urb(cardp->rx_urb, GFP_ATOMIC))) {
469*4882a593Smuzhiyun lbs_deb_usbd(&cardp->udev->dev, "Submit Rx URB failed: %d\n", ret);
470*4882a593Smuzhiyun kfree_skb(skb);
471*4882a593Smuzhiyun cardp->rx_skb = NULL;
472*4882a593Smuzhiyun ret = -1;
473*4882a593Smuzhiyun } else {
474*4882a593Smuzhiyun lbs_deb_usb2(&cardp->udev->dev, "Submit Rx URB success\n");
475*4882a593Smuzhiyun ret = 0;
476*4882a593Smuzhiyun }
477*4882a593Smuzhiyun
478*4882a593Smuzhiyun rx_ret:
479*4882a593Smuzhiyun return ret;
480*4882a593Smuzhiyun }
481*4882a593Smuzhiyun
if_usb_submit_rx_urb_fwload(struct if_usb_card * cardp)482*4882a593Smuzhiyun static int if_usb_submit_rx_urb_fwload(struct if_usb_card *cardp)
483*4882a593Smuzhiyun {
484*4882a593Smuzhiyun return __if_usb_submit_rx_urb(cardp, &if_usb_receive_fwload);
485*4882a593Smuzhiyun }
486*4882a593Smuzhiyun
if_usb_submit_rx_urb(struct if_usb_card * cardp)487*4882a593Smuzhiyun static int if_usb_submit_rx_urb(struct if_usb_card *cardp)
488*4882a593Smuzhiyun {
489*4882a593Smuzhiyun return __if_usb_submit_rx_urb(cardp, &if_usb_receive);
490*4882a593Smuzhiyun }
491*4882a593Smuzhiyun
if_usb_receive_fwload(struct urb * urb)492*4882a593Smuzhiyun static void if_usb_receive_fwload(struct urb *urb)
493*4882a593Smuzhiyun {
494*4882a593Smuzhiyun struct if_usb_card *cardp = urb->context;
495*4882a593Smuzhiyun struct sk_buff *skb = cardp->rx_skb;
496*4882a593Smuzhiyun struct fwsyncheader *syncfwheader;
497*4882a593Smuzhiyun struct bootcmdresp bootcmdresp;
498*4882a593Smuzhiyun
499*4882a593Smuzhiyun if (urb->status) {
500*4882a593Smuzhiyun lbs_deb_usbd(&cardp->udev->dev,
501*4882a593Smuzhiyun "URB status is failed during fw load\n");
502*4882a593Smuzhiyun kfree_skb(skb);
503*4882a593Smuzhiyun return;
504*4882a593Smuzhiyun }
505*4882a593Smuzhiyun
506*4882a593Smuzhiyun if (cardp->fwdnldover) {
507*4882a593Smuzhiyun __le32 *tmp = (__le32 *)(skb->data + IPFIELD_ALIGN_OFFSET);
508*4882a593Smuzhiyun
509*4882a593Smuzhiyun if (tmp[0] == cpu_to_le32(CMD_TYPE_INDICATION) &&
510*4882a593Smuzhiyun tmp[1] == cpu_to_le32(MACREG_INT_CODE_FIRMWARE_READY)) {
511*4882a593Smuzhiyun pr_info("Firmware ready event received\n");
512*4882a593Smuzhiyun wake_up(&cardp->fw_wq);
513*4882a593Smuzhiyun } else {
514*4882a593Smuzhiyun lbs_deb_usb("Waiting for confirmation; got %x %x\n",
515*4882a593Smuzhiyun le32_to_cpu(tmp[0]), le32_to_cpu(tmp[1]));
516*4882a593Smuzhiyun if_usb_submit_rx_urb_fwload(cardp);
517*4882a593Smuzhiyun }
518*4882a593Smuzhiyun kfree_skb(skb);
519*4882a593Smuzhiyun return;
520*4882a593Smuzhiyun }
521*4882a593Smuzhiyun if (cardp->bootcmdresp <= 0) {
522*4882a593Smuzhiyun memcpy (&bootcmdresp, skb->data + IPFIELD_ALIGN_OFFSET,
523*4882a593Smuzhiyun sizeof(bootcmdresp));
524*4882a593Smuzhiyun
525*4882a593Smuzhiyun if (le16_to_cpu(cardp->udev->descriptor.bcdDevice) < 0x3106) {
526*4882a593Smuzhiyun kfree_skb(skb);
527*4882a593Smuzhiyun if_usb_submit_rx_urb_fwload(cardp);
528*4882a593Smuzhiyun cardp->bootcmdresp = BOOT_CMD_RESP_OK;
529*4882a593Smuzhiyun lbs_deb_usbd(&cardp->udev->dev,
530*4882a593Smuzhiyun "Received valid boot command response\n");
531*4882a593Smuzhiyun return;
532*4882a593Smuzhiyun }
533*4882a593Smuzhiyun if (bootcmdresp.magic != cpu_to_le32(BOOT_CMD_MAGIC_NUMBER)) {
534*4882a593Smuzhiyun if (bootcmdresp.magic == cpu_to_le32(CMD_TYPE_REQUEST) ||
535*4882a593Smuzhiyun bootcmdresp.magic == cpu_to_le32(CMD_TYPE_DATA) ||
536*4882a593Smuzhiyun bootcmdresp.magic == cpu_to_le32(CMD_TYPE_INDICATION)) {
537*4882a593Smuzhiyun if (!cardp->bootcmdresp)
538*4882a593Smuzhiyun pr_info("Firmware already seems alive; resetting\n");
539*4882a593Smuzhiyun cardp->bootcmdresp = -1;
540*4882a593Smuzhiyun } else {
541*4882a593Smuzhiyun pr_info("boot cmd response wrong magic number (0x%x)\n",
542*4882a593Smuzhiyun le32_to_cpu(bootcmdresp.magic));
543*4882a593Smuzhiyun }
544*4882a593Smuzhiyun } else if ((bootcmdresp.cmd != BOOT_CMD_FW_BY_USB) &&
545*4882a593Smuzhiyun (bootcmdresp.cmd != BOOT_CMD_UPDATE_FW) &&
546*4882a593Smuzhiyun (bootcmdresp.cmd != BOOT_CMD_UPDATE_BOOT2)) {
547*4882a593Smuzhiyun pr_info("boot cmd response cmd_tag error (%d)\n",
548*4882a593Smuzhiyun bootcmdresp.cmd);
549*4882a593Smuzhiyun } else if (bootcmdresp.result != BOOT_CMD_RESP_OK) {
550*4882a593Smuzhiyun pr_info("boot cmd response result error (%d)\n",
551*4882a593Smuzhiyun bootcmdresp.result);
552*4882a593Smuzhiyun } else {
553*4882a593Smuzhiyun cardp->bootcmdresp = 1;
554*4882a593Smuzhiyun lbs_deb_usbd(&cardp->udev->dev,
555*4882a593Smuzhiyun "Received valid boot command response\n");
556*4882a593Smuzhiyun }
557*4882a593Smuzhiyun kfree_skb(skb);
558*4882a593Smuzhiyun if_usb_submit_rx_urb_fwload(cardp);
559*4882a593Smuzhiyun return;
560*4882a593Smuzhiyun }
561*4882a593Smuzhiyun
562*4882a593Smuzhiyun syncfwheader = kmemdup(skb->data + IPFIELD_ALIGN_OFFSET,
563*4882a593Smuzhiyun sizeof(struct fwsyncheader), GFP_ATOMIC);
564*4882a593Smuzhiyun if (!syncfwheader) {
565*4882a593Smuzhiyun lbs_deb_usbd(&cardp->udev->dev, "Failure to allocate syncfwheader\n");
566*4882a593Smuzhiyun kfree_skb(skb);
567*4882a593Smuzhiyun return;
568*4882a593Smuzhiyun }
569*4882a593Smuzhiyun
570*4882a593Smuzhiyun if (!syncfwheader->cmd) {
571*4882a593Smuzhiyun lbs_deb_usb2(&cardp->udev->dev, "FW received Blk with correct CRC\n");
572*4882a593Smuzhiyun lbs_deb_usb2(&cardp->udev->dev, "FW received Blk seqnum = %d\n",
573*4882a593Smuzhiyun le32_to_cpu(syncfwheader->seqnum));
574*4882a593Smuzhiyun cardp->CRC_OK = 1;
575*4882a593Smuzhiyun } else {
576*4882a593Smuzhiyun lbs_deb_usbd(&cardp->udev->dev, "FW received Blk with CRC error\n");
577*4882a593Smuzhiyun cardp->CRC_OK = 0;
578*4882a593Smuzhiyun }
579*4882a593Smuzhiyun
580*4882a593Smuzhiyun kfree_skb(skb);
581*4882a593Smuzhiyun
582*4882a593Smuzhiyun /* Give device 5s to either write firmware to its RAM or eeprom */
583*4882a593Smuzhiyun mod_timer(&cardp->fw_timeout, jiffies + (HZ*5));
584*4882a593Smuzhiyun
585*4882a593Smuzhiyun if (cardp->fwfinalblk) {
586*4882a593Smuzhiyun cardp->fwdnldover = 1;
587*4882a593Smuzhiyun goto exit;
588*4882a593Smuzhiyun }
589*4882a593Smuzhiyun
590*4882a593Smuzhiyun if_usb_send_fw_pkt(cardp);
591*4882a593Smuzhiyun
592*4882a593Smuzhiyun exit:
593*4882a593Smuzhiyun if_usb_submit_rx_urb_fwload(cardp);
594*4882a593Smuzhiyun
595*4882a593Smuzhiyun kfree(syncfwheader);
596*4882a593Smuzhiyun }
597*4882a593Smuzhiyun
598*4882a593Smuzhiyun #define MRVDRV_MIN_PKT_LEN 30
599*4882a593Smuzhiyun
process_cmdtypedata(int recvlength,struct sk_buff * skb,struct if_usb_card * cardp,struct lbs_private * priv)600*4882a593Smuzhiyun static inline void process_cmdtypedata(int recvlength, struct sk_buff *skb,
601*4882a593Smuzhiyun struct if_usb_card *cardp,
602*4882a593Smuzhiyun struct lbs_private *priv)
603*4882a593Smuzhiyun {
604*4882a593Smuzhiyun if (recvlength > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + MESSAGE_HEADER_LEN
605*4882a593Smuzhiyun || recvlength < MRVDRV_MIN_PKT_LEN) {
606*4882a593Smuzhiyun lbs_deb_usbd(&cardp->udev->dev, "Packet length is Invalid\n");
607*4882a593Smuzhiyun kfree_skb(skb);
608*4882a593Smuzhiyun return;
609*4882a593Smuzhiyun }
610*4882a593Smuzhiyun
611*4882a593Smuzhiyun skb_reserve(skb, IPFIELD_ALIGN_OFFSET);
612*4882a593Smuzhiyun skb_put(skb, recvlength);
613*4882a593Smuzhiyun skb_pull(skb, MESSAGE_HEADER_LEN);
614*4882a593Smuzhiyun
615*4882a593Smuzhiyun lbs_process_rxed_packet(priv, skb);
616*4882a593Smuzhiyun }
617*4882a593Smuzhiyun
process_cmdrequest(int recvlength,uint8_t * recvbuff,struct sk_buff * skb,struct if_usb_card * cardp,struct lbs_private * priv)618*4882a593Smuzhiyun static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff,
619*4882a593Smuzhiyun struct sk_buff *skb,
620*4882a593Smuzhiyun struct if_usb_card *cardp,
621*4882a593Smuzhiyun struct lbs_private *priv)
622*4882a593Smuzhiyun {
623*4882a593Smuzhiyun unsigned long flags;
624*4882a593Smuzhiyun u8 i;
625*4882a593Smuzhiyun
626*4882a593Smuzhiyun if (recvlength > LBS_CMD_BUFFER_SIZE) {
627*4882a593Smuzhiyun lbs_deb_usbd(&cardp->udev->dev,
628*4882a593Smuzhiyun "The receive buffer is too large\n");
629*4882a593Smuzhiyun kfree_skb(skb);
630*4882a593Smuzhiyun return;
631*4882a593Smuzhiyun }
632*4882a593Smuzhiyun
633*4882a593Smuzhiyun spin_lock_irqsave(&priv->driver_lock, flags);
634*4882a593Smuzhiyun
635*4882a593Smuzhiyun i = (priv->resp_idx == 0) ? 1 : 0;
636*4882a593Smuzhiyun BUG_ON(priv->resp_len[i]);
637*4882a593Smuzhiyun priv->resp_len[i] = (recvlength - MESSAGE_HEADER_LEN);
638*4882a593Smuzhiyun memcpy(priv->resp_buf[i], recvbuff + MESSAGE_HEADER_LEN,
639*4882a593Smuzhiyun priv->resp_len[i]);
640*4882a593Smuzhiyun kfree_skb(skb);
641*4882a593Smuzhiyun lbs_notify_command_response(priv, i);
642*4882a593Smuzhiyun
643*4882a593Smuzhiyun spin_unlock_irqrestore(&priv->driver_lock, flags);
644*4882a593Smuzhiyun
645*4882a593Smuzhiyun lbs_deb_usbd(&cardp->udev->dev,
646*4882a593Smuzhiyun "Wake up main thread to handle cmd response\n");
647*4882a593Smuzhiyun }
648*4882a593Smuzhiyun
649*4882a593Smuzhiyun /**
650*4882a593Smuzhiyun * if_usb_receive - read the packet into the upload buffer,
651*4882a593Smuzhiyun * wake up the main thread and initialise the Rx callack
652*4882a593Smuzhiyun *
653*4882a593Smuzhiyun * @urb: pointer to &struct urb
654*4882a593Smuzhiyun * returns: N/A
655*4882a593Smuzhiyun */
if_usb_receive(struct urb * urb)656*4882a593Smuzhiyun static void if_usb_receive(struct urb *urb)
657*4882a593Smuzhiyun {
658*4882a593Smuzhiyun struct if_usb_card *cardp = urb->context;
659*4882a593Smuzhiyun struct sk_buff *skb = cardp->rx_skb;
660*4882a593Smuzhiyun struct lbs_private *priv = cardp->priv;
661*4882a593Smuzhiyun int recvlength = urb->actual_length;
662*4882a593Smuzhiyun uint8_t *recvbuff = NULL;
663*4882a593Smuzhiyun uint32_t recvtype = 0;
664*4882a593Smuzhiyun __le32 *pkt = (__le32 *)(skb->data + IPFIELD_ALIGN_OFFSET);
665*4882a593Smuzhiyun uint32_t event;
666*4882a593Smuzhiyun
667*4882a593Smuzhiyun if (recvlength) {
668*4882a593Smuzhiyun if (urb->status) {
669*4882a593Smuzhiyun lbs_deb_usbd(&cardp->udev->dev, "RX URB failed: %d\n",
670*4882a593Smuzhiyun urb->status);
671*4882a593Smuzhiyun kfree_skb(skb);
672*4882a593Smuzhiyun goto setup_for_next;
673*4882a593Smuzhiyun }
674*4882a593Smuzhiyun
675*4882a593Smuzhiyun recvbuff = skb->data + IPFIELD_ALIGN_OFFSET;
676*4882a593Smuzhiyun recvtype = le32_to_cpu(pkt[0]);
677*4882a593Smuzhiyun lbs_deb_usbd(&cardp->udev->dev,
678*4882a593Smuzhiyun "Recv length = 0x%x, Recv type = 0x%X\n",
679*4882a593Smuzhiyun recvlength, recvtype);
680*4882a593Smuzhiyun } else if (urb->status) {
681*4882a593Smuzhiyun kfree_skb(skb);
682*4882a593Smuzhiyun return;
683*4882a593Smuzhiyun }
684*4882a593Smuzhiyun
685*4882a593Smuzhiyun switch (recvtype) {
686*4882a593Smuzhiyun case CMD_TYPE_DATA:
687*4882a593Smuzhiyun process_cmdtypedata(recvlength, skb, cardp, priv);
688*4882a593Smuzhiyun break;
689*4882a593Smuzhiyun
690*4882a593Smuzhiyun case CMD_TYPE_REQUEST:
691*4882a593Smuzhiyun process_cmdrequest(recvlength, recvbuff, skb, cardp, priv);
692*4882a593Smuzhiyun break;
693*4882a593Smuzhiyun
694*4882a593Smuzhiyun case CMD_TYPE_INDICATION:
695*4882a593Smuzhiyun /* Event handling */
696*4882a593Smuzhiyun event = le32_to_cpu(pkt[1]);
697*4882a593Smuzhiyun lbs_deb_usbd(&cardp->udev->dev, "**EVENT** 0x%X\n", event);
698*4882a593Smuzhiyun kfree_skb(skb);
699*4882a593Smuzhiyun
700*4882a593Smuzhiyun /* Icky undocumented magic special case */
701*4882a593Smuzhiyun if (event & 0xffff0000) {
702*4882a593Smuzhiyun u32 trycount = (event & 0xffff0000) >> 16;
703*4882a593Smuzhiyun
704*4882a593Smuzhiyun lbs_send_tx_feedback(priv, trycount);
705*4882a593Smuzhiyun } else
706*4882a593Smuzhiyun lbs_queue_event(priv, event & 0xFF);
707*4882a593Smuzhiyun break;
708*4882a593Smuzhiyun
709*4882a593Smuzhiyun default:
710*4882a593Smuzhiyun lbs_deb_usbd(&cardp->udev->dev, "Unknown command type 0x%X\n",
711*4882a593Smuzhiyun recvtype);
712*4882a593Smuzhiyun kfree_skb(skb);
713*4882a593Smuzhiyun break;
714*4882a593Smuzhiyun }
715*4882a593Smuzhiyun
716*4882a593Smuzhiyun setup_for_next:
717*4882a593Smuzhiyun if_usb_submit_rx_urb(cardp);
718*4882a593Smuzhiyun }
719*4882a593Smuzhiyun
720*4882a593Smuzhiyun /**
721*4882a593Smuzhiyun * if_usb_host_to_card - downloads data to FW
722*4882a593Smuzhiyun * @priv: pointer to &struct lbs_private structure
723*4882a593Smuzhiyun * @type: type of data
724*4882a593Smuzhiyun * @payload: pointer to data buffer
725*4882a593Smuzhiyun * @nb: number of bytes
726*4882a593Smuzhiyun * returns: 0 for success or negative error code
727*4882a593Smuzhiyun */
if_usb_host_to_card(struct lbs_private * priv,uint8_t type,uint8_t * payload,uint16_t nb)728*4882a593Smuzhiyun static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type,
729*4882a593Smuzhiyun uint8_t *payload, uint16_t nb)
730*4882a593Smuzhiyun {
731*4882a593Smuzhiyun struct if_usb_card *cardp = priv->card;
732*4882a593Smuzhiyun
733*4882a593Smuzhiyun lbs_deb_usbd(&cardp->udev->dev,"*** type = %u\n", type);
734*4882a593Smuzhiyun lbs_deb_usbd(&cardp->udev->dev,"size after = %d\n", nb);
735*4882a593Smuzhiyun
736*4882a593Smuzhiyun if (type == MVMS_CMD) {
737*4882a593Smuzhiyun *(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_REQUEST);
738*4882a593Smuzhiyun priv->dnld_sent = DNLD_CMD_SENT;
739*4882a593Smuzhiyun } else {
740*4882a593Smuzhiyun *(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_DATA);
741*4882a593Smuzhiyun priv->dnld_sent = DNLD_DATA_SENT;
742*4882a593Smuzhiyun }
743*4882a593Smuzhiyun
744*4882a593Smuzhiyun memcpy((cardp->ep_out_buf + MESSAGE_HEADER_LEN), payload, nb);
745*4882a593Smuzhiyun
746*4882a593Smuzhiyun return usb_tx_block(cardp, cardp->ep_out_buf, nb + MESSAGE_HEADER_LEN);
747*4882a593Smuzhiyun }
748*4882a593Smuzhiyun
749*4882a593Smuzhiyun /**
750*4882a593Smuzhiyun * if_usb_issue_boot_command - issues Boot command to the Boot2 code
751*4882a593Smuzhiyun * @cardp: pointer to &if_usb_card
752*4882a593Smuzhiyun * @ivalue: 1:Boot from FW by USB-Download
753*4882a593Smuzhiyun * 2:Boot from FW in EEPROM
754*4882a593Smuzhiyun * returns: 0 for success or negative error code
755*4882a593Smuzhiyun */
if_usb_issue_boot_command(struct if_usb_card * cardp,int ivalue)756*4882a593Smuzhiyun static int if_usb_issue_boot_command(struct if_usb_card *cardp, int ivalue)
757*4882a593Smuzhiyun {
758*4882a593Smuzhiyun struct bootcmd *bootcmd = cardp->ep_out_buf;
759*4882a593Smuzhiyun
760*4882a593Smuzhiyun /* Prepare command */
761*4882a593Smuzhiyun bootcmd->magic = cpu_to_le32(BOOT_CMD_MAGIC_NUMBER);
762*4882a593Smuzhiyun bootcmd->cmd = ivalue;
763*4882a593Smuzhiyun memset(bootcmd->pad, 0, sizeof(bootcmd->pad));
764*4882a593Smuzhiyun
765*4882a593Smuzhiyun /* Issue command */
766*4882a593Smuzhiyun usb_tx_block(cardp, cardp->ep_out_buf, sizeof(*bootcmd));
767*4882a593Smuzhiyun
768*4882a593Smuzhiyun return 0;
769*4882a593Smuzhiyun }
770*4882a593Smuzhiyun
771*4882a593Smuzhiyun
772*4882a593Smuzhiyun /**
773*4882a593Smuzhiyun * check_fwfile_format - check the validity of Boot2/FW image
774*4882a593Smuzhiyun *
775*4882a593Smuzhiyun * @data: pointer to image
776*4882a593Smuzhiyun * @totlen: image length
777*4882a593Smuzhiyun * returns: 0 (good) or 1 (failure)
778*4882a593Smuzhiyun */
check_fwfile_format(const uint8_t * data,uint32_t totlen)779*4882a593Smuzhiyun static int check_fwfile_format(const uint8_t *data, uint32_t totlen)
780*4882a593Smuzhiyun {
781*4882a593Smuzhiyun uint32_t bincmd, exit;
782*4882a593Smuzhiyun uint32_t blksize, offset, len;
783*4882a593Smuzhiyun int ret;
784*4882a593Smuzhiyun
785*4882a593Smuzhiyun ret = 1;
786*4882a593Smuzhiyun exit = len = 0;
787*4882a593Smuzhiyun
788*4882a593Smuzhiyun do {
789*4882a593Smuzhiyun struct fwheader *fwh = (void *)data;
790*4882a593Smuzhiyun
791*4882a593Smuzhiyun bincmd = le32_to_cpu(fwh->dnldcmd);
792*4882a593Smuzhiyun blksize = le32_to_cpu(fwh->datalength);
793*4882a593Smuzhiyun switch (bincmd) {
794*4882a593Smuzhiyun case FW_HAS_DATA_TO_RECV:
795*4882a593Smuzhiyun offset = sizeof(struct fwheader) + blksize;
796*4882a593Smuzhiyun data += offset;
797*4882a593Smuzhiyun len += offset;
798*4882a593Smuzhiyun if (len >= totlen)
799*4882a593Smuzhiyun exit = 1;
800*4882a593Smuzhiyun break;
801*4882a593Smuzhiyun case FW_HAS_LAST_BLOCK:
802*4882a593Smuzhiyun exit = 1;
803*4882a593Smuzhiyun ret = 0;
804*4882a593Smuzhiyun break;
805*4882a593Smuzhiyun default:
806*4882a593Smuzhiyun exit = 1;
807*4882a593Smuzhiyun break;
808*4882a593Smuzhiyun }
809*4882a593Smuzhiyun } while (!exit);
810*4882a593Smuzhiyun
811*4882a593Smuzhiyun if (ret)
812*4882a593Smuzhiyun pr_err("firmware file format check FAIL\n");
813*4882a593Smuzhiyun else
814*4882a593Smuzhiyun lbs_deb_fw("firmware file format check PASS\n");
815*4882a593Smuzhiyun
816*4882a593Smuzhiyun return ret;
817*4882a593Smuzhiyun }
818*4882a593Smuzhiyun
if_usb_prog_firmware(struct lbs_private * priv,int ret,const struct firmware * fw,const struct firmware * unused)819*4882a593Smuzhiyun static void if_usb_prog_firmware(struct lbs_private *priv, int ret,
820*4882a593Smuzhiyun const struct firmware *fw,
821*4882a593Smuzhiyun const struct firmware *unused)
822*4882a593Smuzhiyun {
823*4882a593Smuzhiyun struct if_usb_card *cardp = priv->card;
824*4882a593Smuzhiyun int i = 0;
825*4882a593Smuzhiyun static int reset_count = 10;
826*4882a593Smuzhiyun
827*4882a593Smuzhiyun if (ret) {
828*4882a593Smuzhiyun pr_err("failed to find firmware (%d)\n", ret);
829*4882a593Smuzhiyun goto done;
830*4882a593Smuzhiyun }
831*4882a593Smuzhiyun
832*4882a593Smuzhiyun cardp->fw = fw;
833*4882a593Smuzhiyun if (check_fwfile_format(cardp->fw->data, cardp->fw->size)) {
834*4882a593Smuzhiyun ret = -EINVAL;
835*4882a593Smuzhiyun goto done;
836*4882a593Smuzhiyun }
837*4882a593Smuzhiyun
838*4882a593Smuzhiyun /* Cancel any pending usb business */
839*4882a593Smuzhiyun usb_kill_urb(cardp->rx_urb);
840*4882a593Smuzhiyun usb_kill_urb(cardp->tx_urb);
841*4882a593Smuzhiyun
842*4882a593Smuzhiyun cardp->fwlastblksent = 0;
843*4882a593Smuzhiyun cardp->fwdnldover = 0;
844*4882a593Smuzhiyun cardp->totalbytes = 0;
845*4882a593Smuzhiyun cardp->fwfinalblk = 0;
846*4882a593Smuzhiyun cardp->bootcmdresp = 0;
847*4882a593Smuzhiyun
848*4882a593Smuzhiyun restart:
849*4882a593Smuzhiyun if (if_usb_submit_rx_urb_fwload(cardp) < 0) {
850*4882a593Smuzhiyun lbs_deb_usbd(&cardp->udev->dev, "URB submission is failed\n");
851*4882a593Smuzhiyun ret = -EIO;
852*4882a593Smuzhiyun goto done;
853*4882a593Smuzhiyun }
854*4882a593Smuzhiyun
855*4882a593Smuzhiyun cardp->bootcmdresp = 0;
856*4882a593Smuzhiyun do {
857*4882a593Smuzhiyun int j = 0;
858*4882a593Smuzhiyun i++;
859*4882a593Smuzhiyun if_usb_issue_boot_command(cardp, BOOT_CMD_FW_BY_USB);
860*4882a593Smuzhiyun /* wait for command response */
861*4882a593Smuzhiyun do {
862*4882a593Smuzhiyun j++;
863*4882a593Smuzhiyun msleep_interruptible(100);
864*4882a593Smuzhiyun } while (cardp->bootcmdresp == 0 && j < 10);
865*4882a593Smuzhiyun } while (cardp->bootcmdresp == 0 && i < 5);
866*4882a593Smuzhiyun
867*4882a593Smuzhiyun if (cardp->bootcmdresp == BOOT_CMD_RESP_NOT_SUPPORTED) {
868*4882a593Smuzhiyun /* Return to normal operation */
869*4882a593Smuzhiyun ret = -EOPNOTSUPP;
870*4882a593Smuzhiyun usb_kill_urb(cardp->rx_urb);
871*4882a593Smuzhiyun usb_kill_urb(cardp->tx_urb);
872*4882a593Smuzhiyun if (if_usb_submit_rx_urb(cardp) < 0)
873*4882a593Smuzhiyun ret = -EIO;
874*4882a593Smuzhiyun goto done;
875*4882a593Smuzhiyun } else if (cardp->bootcmdresp <= 0) {
876*4882a593Smuzhiyun if (--reset_count >= 0) {
877*4882a593Smuzhiyun if_usb_reset_device(cardp);
878*4882a593Smuzhiyun goto restart;
879*4882a593Smuzhiyun }
880*4882a593Smuzhiyun ret = -EIO;
881*4882a593Smuzhiyun goto done;
882*4882a593Smuzhiyun }
883*4882a593Smuzhiyun
884*4882a593Smuzhiyun i = 0;
885*4882a593Smuzhiyun
886*4882a593Smuzhiyun cardp->totalbytes = 0;
887*4882a593Smuzhiyun cardp->fwlastblksent = 0;
888*4882a593Smuzhiyun cardp->CRC_OK = 1;
889*4882a593Smuzhiyun cardp->fwdnldover = 0;
890*4882a593Smuzhiyun cardp->fwseqnum = -1;
891*4882a593Smuzhiyun cardp->totalbytes = 0;
892*4882a593Smuzhiyun cardp->fwfinalblk = 0;
893*4882a593Smuzhiyun
894*4882a593Smuzhiyun /* Send the first firmware packet... */
895*4882a593Smuzhiyun if_usb_send_fw_pkt(cardp);
896*4882a593Smuzhiyun
897*4882a593Smuzhiyun /* ... and wait for the process to complete */
898*4882a593Smuzhiyun wait_event_interruptible(cardp->fw_wq, cardp->surprise_removed || cardp->fwdnldover);
899*4882a593Smuzhiyun
900*4882a593Smuzhiyun del_timer_sync(&cardp->fw_timeout);
901*4882a593Smuzhiyun usb_kill_urb(cardp->rx_urb);
902*4882a593Smuzhiyun
903*4882a593Smuzhiyun if (!cardp->fwdnldover) {
904*4882a593Smuzhiyun pr_info("failed to load fw, resetting device!\n");
905*4882a593Smuzhiyun if (--reset_count >= 0) {
906*4882a593Smuzhiyun if_usb_reset_device(cardp);
907*4882a593Smuzhiyun goto restart;
908*4882a593Smuzhiyun }
909*4882a593Smuzhiyun
910*4882a593Smuzhiyun pr_info("FW download failure, time = %d ms\n", i * 100);
911*4882a593Smuzhiyun ret = -EIO;
912*4882a593Smuzhiyun goto done;
913*4882a593Smuzhiyun }
914*4882a593Smuzhiyun
915*4882a593Smuzhiyun cardp->priv->fw_ready = 1;
916*4882a593Smuzhiyun if_usb_submit_rx_urb(cardp);
917*4882a593Smuzhiyun
918*4882a593Smuzhiyun if (lbs_start_card(priv))
919*4882a593Smuzhiyun goto done;
920*4882a593Smuzhiyun
921*4882a593Smuzhiyun if_usb_setup_firmware(priv);
922*4882a593Smuzhiyun
923*4882a593Smuzhiyun /*
924*4882a593Smuzhiyun * EHS_REMOVE_WAKEUP is not supported on all versions of the firmware.
925*4882a593Smuzhiyun */
926*4882a593Smuzhiyun priv->wol_criteria = EHS_REMOVE_WAKEUP;
927*4882a593Smuzhiyun if (lbs_host_sleep_cfg(priv, priv->wol_criteria, NULL))
928*4882a593Smuzhiyun priv->ehs_remove_supported = false;
929*4882a593Smuzhiyun
930*4882a593Smuzhiyun done:
931*4882a593Smuzhiyun cardp->fw = NULL;
932*4882a593Smuzhiyun }
933*4882a593Smuzhiyun
934*4882a593Smuzhiyun
935*4882a593Smuzhiyun #ifdef CONFIG_PM
if_usb_suspend(struct usb_interface * intf,pm_message_t message)936*4882a593Smuzhiyun static int if_usb_suspend(struct usb_interface *intf, pm_message_t message)
937*4882a593Smuzhiyun {
938*4882a593Smuzhiyun struct if_usb_card *cardp = usb_get_intfdata(intf);
939*4882a593Smuzhiyun struct lbs_private *priv = cardp->priv;
940*4882a593Smuzhiyun int ret;
941*4882a593Smuzhiyun
942*4882a593Smuzhiyun if (priv->psstate != PS_STATE_FULL_POWER) {
943*4882a593Smuzhiyun ret = -1;
944*4882a593Smuzhiyun goto out;
945*4882a593Smuzhiyun }
946*4882a593Smuzhiyun
947*4882a593Smuzhiyun #ifdef CONFIG_OLPC
948*4882a593Smuzhiyun if (machine_is_olpc()) {
949*4882a593Smuzhiyun if (priv->wol_criteria == EHS_REMOVE_WAKEUP)
950*4882a593Smuzhiyun olpc_ec_wakeup_clear(EC_SCI_SRC_WLAN);
951*4882a593Smuzhiyun else
952*4882a593Smuzhiyun olpc_ec_wakeup_set(EC_SCI_SRC_WLAN);
953*4882a593Smuzhiyun }
954*4882a593Smuzhiyun #endif
955*4882a593Smuzhiyun
956*4882a593Smuzhiyun ret = lbs_suspend(priv);
957*4882a593Smuzhiyun if (ret)
958*4882a593Smuzhiyun goto out;
959*4882a593Smuzhiyun
960*4882a593Smuzhiyun /* Unlink tx & rx urb */
961*4882a593Smuzhiyun usb_kill_urb(cardp->tx_urb);
962*4882a593Smuzhiyun usb_kill_urb(cardp->rx_urb);
963*4882a593Smuzhiyun
964*4882a593Smuzhiyun out:
965*4882a593Smuzhiyun return ret;
966*4882a593Smuzhiyun }
967*4882a593Smuzhiyun
if_usb_resume(struct usb_interface * intf)968*4882a593Smuzhiyun static int if_usb_resume(struct usb_interface *intf)
969*4882a593Smuzhiyun {
970*4882a593Smuzhiyun struct if_usb_card *cardp = usb_get_intfdata(intf);
971*4882a593Smuzhiyun struct lbs_private *priv = cardp->priv;
972*4882a593Smuzhiyun
973*4882a593Smuzhiyun if_usb_submit_rx_urb(cardp);
974*4882a593Smuzhiyun
975*4882a593Smuzhiyun lbs_resume(priv);
976*4882a593Smuzhiyun
977*4882a593Smuzhiyun return 0;
978*4882a593Smuzhiyun }
979*4882a593Smuzhiyun #else
980*4882a593Smuzhiyun #define if_usb_suspend NULL
981*4882a593Smuzhiyun #define if_usb_resume NULL
982*4882a593Smuzhiyun #endif
983*4882a593Smuzhiyun
984*4882a593Smuzhiyun static struct usb_driver if_usb_driver = {
985*4882a593Smuzhiyun .name = DRV_NAME,
986*4882a593Smuzhiyun .probe = if_usb_probe,
987*4882a593Smuzhiyun .disconnect = if_usb_disconnect,
988*4882a593Smuzhiyun .id_table = if_usb_table,
989*4882a593Smuzhiyun .suspend = if_usb_suspend,
990*4882a593Smuzhiyun .resume = if_usb_resume,
991*4882a593Smuzhiyun .reset_resume = if_usb_resume,
992*4882a593Smuzhiyun .disable_hub_initiated_lpm = 1,
993*4882a593Smuzhiyun };
994*4882a593Smuzhiyun
995*4882a593Smuzhiyun module_usb_driver(if_usb_driver);
996*4882a593Smuzhiyun
997*4882a593Smuzhiyun MODULE_DESCRIPTION("8388 USB WLAN Driver");
998*4882a593Smuzhiyun MODULE_AUTHOR("Marvell International Ltd. and Red Hat, Inc.");
999*4882a593Smuzhiyun MODULE_LICENSE("GPL");
1000