| 
									
										
										
										
											2011-04-26 15:25:29 -07:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * This file contains functions used in USB interface module. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2011-05-02 16:49:14 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | #include <linux/delay.h>
 | 
					
						
							| 
									
										
										
										
											2011-08-30 14:18:44 -04:00
										 |  |  | #include <linux/module.h>
 | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | #include <linux/firmware.h>
 | 
					
						
							|  |  |  | #include <linux/netdevice.h>
 | 
					
						
							| 
									
										
											  
											
												include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files.  percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed.  Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability.  As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
  http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
  only the necessary includes are there.  ie. if only gfp is used,
  gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
  blocks and try to put the new include such that its order conforms
  to its surrounding.  It's put in the include block which contains
  core kernel includes, in the same order that the rest are ordered -
  alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
  doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
  because the file doesn't have fitting include block), it prints out
  an error message indicating which .h file needs to be added to the
  file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
   over 4000 files, deleting around 700 includes and adding ~480 gfp.h
   and ~3000 slab.h inclusions.  The script emitted errors for ~400
   files.
2. Each error was manually checked.  Some didn't need the inclusion,
   some needed manual addition while adding it to implementation .h or
   embedding .c file was more appropriate for others.  This step added
   inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
   from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
   e.g. lib/decompress_*.c used malloc/free() wrappers around slab
   APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
   editing them as sprinkling gfp.h and slab.h inclusions around .h
   files could easily lead to inclusion dependency hell.  Most gfp.h
   inclusion directives were ignored as stuff from gfp.h was usually
   wildly available and often used in preprocessor macros.  Each
   slab.h inclusion directive was examined and added manually as
   necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
   were fixed.  CONFIG_GCOV_KERNEL was turned off for all tests (as my
   distributed build env didn't work with gcov compiles) and a few
   more options had to be turned off depending on archs to make things
   build (like ipr on powerpc/64 which failed due to missing writeq).
   * x86 and x86_64 UP and SMP allmodconfig and a custom test config.
   * powerpc and powerpc64 SMP allmodconfig
   * sparc and sparc64 SMP allmodconfig
   * ia64 SMP allmodconfig
   * s390 SMP allmodconfig
   * alpha SMP allmodconfig
   * um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
   a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
											
										 
											2010-03-24 17:04:11 +09:00
										 |  |  | #include <linux/slab.h>
 | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | #include <linux/usb.h>
 | 
					
						
							| 
									
										
										
										
											2012-07-11 01:16:29 -07:00
										 |  |  | #include <linux/olpc-ec.h>
 | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-20 16:48:52 +01:00
										 |  |  | #ifdef CONFIG_OLPC
 | 
					
						
							|  |  |  | #include <asm/olpc.h>
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-05-25 12:49:10 -04:00
										 |  |  | #define DRV_NAME "usb8xxx"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | #include "host.h"
 | 
					
						
							|  |  |  | #include "decl.h"
 | 
					
						
							|  |  |  | #include "defs.h"
 | 
					
						
							|  |  |  | #include "dev.h"
 | 
					
						
							| 
									
										
										
										
											2007-12-10 15:11:23 -05:00
										 |  |  | #include "cmd.h"
 | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | #include "if_usb.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | #define INSANEDEBUG	0
 | 
					
						
							|  |  |  | #define lbs_deb_usb2(...) do { if (INSANEDEBUG) lbs_deb_usbd(__VA_ARGS__); } while (0)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | #define MESSAGE_HEADER_LEN	4
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-07 21:13:57 -05:00
										 |  |  | MODULE_FIRMWARE("libertas/usb8388_v9.bin"); | 
					
						
							|  |  |  | MODULE_FIRMWARE("libertas/usb8388_v5.bin"); | 
					
						
							|  |  |  | MODULE_FIRMWARE("libertas/usb8388.bin"); | 
					
						
							|  |  |  | MODULE_FIRMWARE("libertas/usb8682.bin"); | 
					
						
							| 
									
										
										
										
											2009-11-07 22:00:03 +00:00
										 |  |  | MODULE_FIRMWARE("usb8388.bin"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-07 21:13:57 -05:00
										 |  |  | enum { | 
					
						
							|  |  |  | 	MODEL_UNKNOWN = 0x0, | 
					
						
							|  |  |  | 	MODEL_8388 = 0x1, | 
					
						
							|  |  |  | 	MODEL_8682 = 0x2 | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-16 23:53:55 +01:00
										 |  |  | /* 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 } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | static struct usb_device_id if_usb_table[] = { | 
					
						
							|  |  |  | 	/* Enter the device signature inside */ | 
					
						
							| 
									
										
										
										
											2010-08-07 21:13:57 -05:00
										 |  |  | 	{ USB_DEVICE(0x1286, 0x2001), .driver_info = MODEL_8388 }, | 
					
						
							|  |  |  | 	{ USB_DEVICE(0x05a3, 0x8388), .driver_info = MODEL_8388 }, | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 	{}	/* Terminating entry */ | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | MODULE_DEVICE_TABLE(usb, if_usb_table); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void if_usb_receive(struct urb *urb); | 
					
						
							|  |  |  | static void if_usb_receive_fwload(struct urb *urb); | 
					
						
							| 
									
										
										
										
											2012-04-16 23:53:55 +01:00
										 |  |  | static void if_usb_prog_firmware(struct lbs_private *priv, int ret, | 
					
						
							|  |  |  | 				 const struct firmware *fw, | 
					
						
							|  |  |  | 				 const struct firmware *unused); | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 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, | 
					
						
							|  |  |  | 			uint16_t nb); | 
					
						
							|  |  |  | static void if_usb_free(struct if_usb_card *cardp); | 
					
						
							|  |  |  | static int if_usb_submit_rx_urb(struct if_usb_card *cardp); | 
					
						
							|  |  |  | static int if_usb_reset_device(struct if_usb_card *cardp); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							| 
									
										
										
										
											2011-04-26 15:25:29 -07:00
										 |  |  |  * if_usb_write_bulk_callback - callback function to handle the status | 
					
						
							|  |  |  |  * of the URB | 
					
						
							|  |  |  |  * @urb:	pointer to &urb structure | 
					
						
							|  |  |  |  * returns:	N/A | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  |  */ | 
					
						
							|  |  |  | static void if_usb_write_bulk_callback(struct urb *urb) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 	struct if_usb_card *cardp = (struct if_usb_card *) urb->context; | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* handle the transmission complete validations */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-20 11:43:25 -04:00
										 |  |  | 	if (urb->status == 0) { | 
					
						
							| 
									
										
										
										
											2007-11-23 15:43:44 +01:00
										 |  |  | 		struct lbs_private *priv = cardp->priv; | 
					
						
							| 
									
										
										
										
											2007-08-20 11:43:25 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 		lbs_deb_usb2(&urb->dev->dev, "URB status is successful\n"); | 
					
						
							|  |  |  | 		lbs_deb_usb2(&urb->dev->dev, "Actual length transmitted %d\n", | 
					
						
							|  |  |  | 			     urb->actual_length); | 
					
						
							| 
									
										
										
										
											2007-08-20 11:43:25 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-21 11:02:46 -07:00
										 |  |  | 		/* Boot commands such as UPDATE_FW and UPDATE_BOOT2 are not
 | 
					
						
							|  |  |  | 		 * passed up to the lbs level. | 
					
						
							| 
									
										
										
										
											2007-08-20 11:43:25 -04:00
										 |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2008-07-21 11:02:46 -07:00
										 |  |  | 		if (priv && priv->dnld_sent != DNLD_BOOTCMD_SENT) | 
					
						
							| 
									
										
										
										
											2007-12-06 14:36:11 +00:00
										 |  |  | 			lbs_host_to_card_done(priv); | 
					
						
							| 
									
										
										
										
											2007-08-20 11:43:25 -04:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		/* print the failure status number for debug */ | 
					
						
							| 
									
										
										
										
											2011-05-02 16:49:14 -07:00
										 |  |  | 		pr_info("URB in failure status: %d\n", urb->status); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							| 
									
										
										
										
											2011-04-26 15:25:29 -07:00
										 |  |  |  * if_usb_free - free tx/rx urb, skb and rx buffer | 
					
						
							|  |  |  |  * @cardp:	pointer to &if_usb_card | 
					
						
							|  |  |  |  * returns:	N/A | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | static void if_usb_free(struct if_usb_card *cardp) | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-05-25 11:27:16 -04:00
										 |  |  | 	lbs_deb_enter(LBS_DEB_USB); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Unlink tx & rx urb */ | 
					
						
							|  |  |  | 	usb_kill_urb(cardp->tx_urb); | 
					
						
							|  |  |  | 	usb_kill_urb(cardp->rx_urb); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	usb_free_urb(cardp->tx_urb); | 
					
						
							|  |  |  | 	cardp->tx_urb = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	usb_free_urb(cardp->rx_urb); | 
					
						
							|  |  |  | 	cardp->rx_urb = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 	kfree(cardp->ep_out_buf); | 
					
						
							|  |  |  | 	cardp->ep_out_buf = NULL; | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-05-25 11:27:16 -04:00
										 |  |  | 	lbs_deb_leave(LBS_DEB_USB); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-17 14:42:33 -05:00
										 |  |  | static void if_usb_setup_firmware(struct lbs_private *priv) | 
					
						
							| 
									
										
										
										
											2007-12-06 12:51:00 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2008-01-16 15:52:58 +01:00
										 |  |  | 	struct if_usb_card *cardp = priv->card; | 
					
						
							| 
									
										
										
										
											2007-12-06 12:51:00 +00:00
										 |  |  | 	struct cmd_ds_set_boot2_ver b2_cmd; | 
					
						
							| 
									
										
										
										
											2007-12-17 14:42:33 -05:00
										 |  |  | 	struct cmd_ds_802_11_fw_wake_method wake_method; | 
					
						
							| 
									
										
										
										
											2007-12-06 12:51:00 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-15 03:46:44 -05:00
										 |  |  | 	b2_cmd.hdr.size = cpu_to_le16(sizeof(b2_cmd)); | 
					
						
							| 
									
										
										
										
											2007-12-06 12:51:00 +00:00
										 |  |  | 	b2_cmd.action = 0; | 
					
						
							| 
									
										
										
										
											2008-01-16 15:52:58 +01:00
										 |  |  | 	b2_cmd.version = cardp->boot2_version; | 
					
						
							| 
									
										
										
										
											2007-12-06 12:51:00 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-15 01:22:09 -05:00
										 |  |  | 	if (lbs_cmd_with_response(priv, CMD_SET_BOOT2_VER, &b2_cmd)) | 
					
						
							| 
									
										
										
										
											2007-12-06 12:51:00 +00:00
										 |  |  | 		lbs_deb_usb("Setting boot2 version failed\n"); | 
					
						
							| 
									
										
										
										
											2007-12-17 14:42:33 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	priv->wol_gpio = 2; /* Wake via GPIO2... */ | 
					
						
							|  |  |  | 	priv->wol_gap = 20; /* ... after 20ms    */ | 
					
						
							| 
									
										
										
										
											2008-10-20 16:46:56 -07:00
										 |  |  | 	lbs_host_sleep_cfg(priv, EHS_WAKE_ON_UNICAST_DATA, | 
					
						
							|  |  |  | 			(struct wol_config *) NULL); | 
					
						
							| 
									
										
										
										
											2007-12-17 14:42:33 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	wake_method.hdr.size = cpu_to_le16(sizeof(wake_method)); | 
					
						
							|  |  |  | 	wake_method.action = cpu_to_le16(CMD_ACT_GET); | 
					
						
							|  |  |  | 	if (lbs_cmd_with_response(priv, CMD_802_11_FW_WAKE_METHOD, &wake_method)) { | 
					
						
							| 
									
										
										
										
											2011-05-02 16:49:15 -07:00
										 |  |  | 		netdev_info(priv->dev, "Firmware does not seem to support PS mode\n"); | 
					
						
							| 
									
										
										
										
											2009-06-16 13:20:01 -07:00
										 |  |  | 		priv->fwcapinfo &= ~FW_CAPINFO_PS; | 
					
						
							| 
									
										
										
										
											2007-12-17 14:42:33 -05:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		if (le16_to_cpu(wake_method.method) == CMD_WAKE_METHOD_COMMAND_INT) { | 
					
						
							|  |  |  | 			lbs_deb_usb("Firmware seems to support PS with wake-via-command\n"); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			/* The versions which boot up this way don't seem to
 | 
					
						
							|  |  |  | 			   work even if we set it to the command interrupt */ | 
					
						
							| 
									
										
										
										
											2009-06-16 13:20:01 -07:00
										 |  |  | 			priv->fwcapinfo &= ~FW_CAPINFO_PS; | 
					
						
							| 
									
										
										
										
											2011-05-02 16:49:15 -07:00
										 |  |  | 			netdev_info(priv->dev, | 
					
						
							|  |  |  | 				    "Firmware doesn't wake via command interrupt; disabling PS mode\n"); | 
					
						
							| 
									
										
										
										
											2007-12-17 14:42:33 -05:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-12-06 12:51:00 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-11 17:44:10 -05:00
										 |  |  | static void if_usb_fw_timeo(unsigned long priv) | 
					
						
							| 
									
										
										
										
											2007-12-11 00:07:58 -05:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 	struct if_usb_card *cardp = (void *)priv; | 
					
						
							| 
									
										
										
										
											2007-12-06 12:51:00 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-11 00:07:58 -05:00
										 |  |  | 	if (cardp->fwdnldover) { | 
					
						
							|  |  |  | 		lbs_deb_usb("Download complete, no event. Assuming success\n"); | 
					
						
							|  |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2011-05-02 16:49:14 -07:00
										 |  |  | 		pr_err("Download timed out\n"); | 
					
						
							| 
									
										
										
										
											2007-12-11 00:07:58 -05:00
										 |  |  | 		cardp->surprise_removed = 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	wake_up(&cardp->fw_wq); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-20 16:48:52 +01:00
										 |  |  | #ifdef CONFIG_OLPC
 | 
					
						
							|  |  |  | static void if_usb_reset_olpc_card(struct lbs_private *priv) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	printk(KERN_CRIT "Resetting OLPC wireless via EC...\n"); | 
					
						
							|  |  |  | 	olpc_ec_cmd(0x25, NULL, 0, NULL, 0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | /**
 | 
					
						
							| 
									
										
										
										
											2011-04-26 15:25:29 -07:00
										 |  |  |  * if_usb_probe - sets the configuration values | 
					
						
							|  |  |  |  * @intf:	&usb_interface pointer | 
					
						
							|  |  |  |  * @id:	pointer to usb_device_id | 
					
						
							|  |  |  |  * returns:	0 on success, error code on failure | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  |  */ | 
					
						
							|  |  |  | static int if_usb_probe(struct usb_interface *intf, | 
					
						
							|  |  |  | 			const struct usb_device_id *id) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct usb_device *udev; | 
					
						
							|  |  |  | 	struct usb_host_interface *iface_desc; | 
					
						
							|  |  |  | 	struct usb_endpoint_descriptor *endpoint; | 
					
						
							| 
									
										
										
										
											2007-11-23 15:43:44 +01:00
										 |  |  | 	struct lbs_private *priv; | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 	struct if_usb_card *cardp; | 
					
						
							| 
									
										
										
										
											2012-04-16 23:53:55 +01:00
										 |  |  | 	int r = -ENOMEM; | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 	int i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	udev = interface_to_usbdev(intf); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 	cardp = kzalloc(sizeof(struct if_usb_card), GFP_KERNEL); | 
					
						
							| 
									
										
										
										
											2012-01-29 12:56:23 +00:00
										 |  |  | 	if (!cardp) | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 		goto error; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-11 00:07:58 -05:00
										 |  |  | 	setup_timer(&cardp->fw_timeout, if_usb_fw_timeo, (unsigned long)cardp); | 
					
						
							|  |  |  | 	init_waitqueue_head(&cardp->fw_wq); | 
					
						
							| 
									
										
										
										
											2007-12-14 22:53:41 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-05-25 12:41:52 -04:00
										 |  |  | 	cardp->udev = udev; | 
					
						
							| 
									
										
										
										
											2010-08-07 21:13:57 -05:00
										 |  |  | 	cardp->model = (uint32_t) id->driver_info; | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 	iface_desc = intf->cur_altsetting; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-05-25 11:27:16 -04:00
										 |  |  | 	lbs_deb_usbd(&udev->dev, "bcdUSB = 0x%X bDeviceClass = 0x%X" | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 		     " bDeviceSubClass = 0x%X, bDeviceProtocol = 0x%X\n", | 
					
						
							| 
									
										
										
										
											2007-05-25 23:36:54 -04:00
										 |  |  | 		     le16_to_cpu(udev->descriptor.bcdUSB), | 
					
						
							|  |  |  | 		     udev->descriptor.bDeviceClass, | 
					
						
							|  |  |  | 		     udev->descriptor.bDeviceSubClass, | 
					
						
							|  |  |  | 		     udev->descriptor.bDeviceProtocol); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { | 
					
						
							|  |  |  | 		endpoint = &iface_desc->endpoint[i].desc; | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 		if (usb_endpoint_is_bulk_in(endpoint)) { | 
					
						
							|  |  |  | 			cardp->ep_in_size = le16_to_cpu(endpoint->wMaxPacketSize); | 
					
						
							|  |  |  | 			cardp->ep_in = usb_endpoint_num(endpoint); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 			lbs_deb_usbd(&udev->dev, "in_endpoint = %d\n", cardp->ep_in); | 
					
						
							|  |  |  | 			lbs_deb_usbd(&udev->dev, "Bulk in size is %d\n", cardp->ep_in_size); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 		} else if (usb_endpoint_is_bulk_out(endpoint)) { | 
					
						
							|  |  |  | 			cardp->ep_out_size = le16_to_cpu(endpoint->wMaxPacketSize); | 
					
						
							|  |  |  | 			cardp->ep_out = usb_endpoint_num(endpoint); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			lbs_deb_usbd(&udev->dev, "out_endpoint = %d\n", cardp->ep_out); | 
					
						
							|  |  |  | 			lbs_deb_usbd(&udev->dev, "Bulk out size is %d\n", cardp->ep_out_size); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 	if (!cardp->ep_out_size || !cardp->ep_in_size) { | 
					
						
							|  |  |  | 		lbs_deb_usbd(&udev->dev, "Endpoints not found\n"); | 
					
						
							|  |  |  | 		goto dealloc; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (!(cardp->rx_urb = usb_alloc_urb(0, GFP_KERNEL))) { | 
					
						
							|  |  |  | 		lbs_deb_usbd(&udev->dev, "Rx URB allocation failed\n"); | 
					
						
							|  |  |  | 		goto dealloc; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (!(cardp->tx_urb = usb_alloc_urb(0, GFP_KERNEL))) { | 
					
						
							|  |  |  | 		lbs_deb_usbd(&udev->dev, "Tx URB allocation failed\n"); | 
					
						
							|  |  |  | 		goto dealloc; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	cardp->ep_out_buf = kmalloc(MRVDRV_ETH_TX_PACKET_BUFFER_SIZE, GFP_KERNEL); | 
					
						
							|  |  |  | 	if (!cardp->ep_out_buf) { | 
					
						
							|  |  |  | 		lbs_deb_usbd(&udev->dev, "Could not allocate buffer\n"); | 
					
						
							|  |  |  | 		goto dealloc; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-21 20:43:44 +01:00
										 |  |  | 	if (!(priv = lbs_add_card(cardp, &intf->dev))) | 
					
						
							| 
									
										
										
										
											2012-04-16 23:53:55 +01:00
										 |  |  | 		goto err_add_card; | 
					
						
							| 
									
										
										
										
											2007-05-25 12:01:42 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-20 11:43:25 -04:00
										 |  |  | 	cardp->priv = priv; | 
					
						
							| 
									
										
										
										
											2007-08-02 13:16:55 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-05-25 12:17:06 -04:00
										 |  |  | 	priv->hw_host_to_card = if_usb_host_to_card; | 
					
						
							| 
									
										
										
										
											2009-09-30 20:04:38 -07:00
										 |  |  | 	priv->enter_deep_sleep = NULL; | 
					
						
							|  |  |  | 	priv->exit_deep_sleep = NULL; | 
					
						
							|  |  |  | 	priv->reset_deep_sleep_wakeup = NULL; | 
					
						
							| 
									
										
										
										
											2008-05-20 16:48:52 +01:00
										 |  |  | #ifdef CONFIG_OLPC
 | 
					
						
							|  |  |  | 	if (machine_is_olpc()) | 
					
						
							|  |  |  | 		priv->reset_card = if_usb_reset_olpc_card; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-01-16 15:52:58 +01:00
										 |  |  | 	cardp->boot2_version = udev->descriptor.bcdDevice; | 
					
						
							| 
									
										
										
										
											2007-05-25 12:17:06 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 	usb_get_dev(udev); | 
					
						
							| 
									
										
										
										
											2007-05-25 12:41:52 -04:00
										 |  |  | 	usb_set_intfdata(intf, cardp); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-16 23:53:55 +01:00
										 |  |  | 	r = lbs_get_firmware_async(priv, &udev->dev, cardp->model, | 
					
						
							|  |  |  | 				   fw_table, if_usb_prog_firmware); | 
					
						
							|  |  |  | 	if (r) | 
					
						
							|  |  |  | 		goto err_get_fw; | 
					
						
							| 
									
										
										
										
											2010-10-31 13:40:33 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-16 23:53:55 +01:00
										 |  |  | err_get_fw: | 
					
						
							| 
									
										
										
										
											2007-11-15 18:05:47 -05:00
										 |  |  | 	lbs_remove_card(priv); | 
					
						
							| 
									
										
										
										
											2012-04-16 23:53:55 +01:00
										 |  |  | err_add_card: | 
					
						
							| 
									
										
										
										
											2007-08-20 11:43:25 -04:00
										 |  |  | 	if_usb_reset_device(cardp); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | dealloc: | 
					
						
							| 
									
										
										
										
											2007-05-25 12:41:52 -04:00
										 |  |  | 	if_usb_free(cardp); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							|  |  |  | error: | 
					
						
							| 
									
										
										
										
											2012-04-16 23:53:55 +01:00
										 |  |  | 	return r; | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							| 
									
										
										
										
											2011-04-26 15:25:29 -07:00
										 |  |  |  * if_usb_disconnect - free resource and cleanup | 
					
						
							|  |  |  |  * @intf:	USB interface structure | 
					
						
							|  |  |  |  * returns:	N/A | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  |  */ | 
					
						
							|  |  |  | static void if_usb_disconnect(struct usb_interface *intf) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 	struct if_usb_card *cardp = usb_get_intfdata(intf); | 
					
						
							| 
									
										
										
										
											2012-06-04 12:44:17 +00:00
										 |  |  | 	struct lbs_private *priv = cardp->priv; | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-20 11:43:25 -04:00
										 |  |  | 	lbs_deb_enter(LBS_DEB_MAIN); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-20 11:43:25 -04:00
										 |  |  | 	cardp->surprise_removed = 1; | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-20 11:43:25 -04:00
										 |  |  | 	if (priv) { | 
					
						
							| 
									
										
										
										
											2007-11-15 18:05:47 -05:00
										 |  |  | 		lbs_stop_card(priv); | 
					
						
							|  |  |  | 		lbs_remove_card(priv); | 
					
						
							| 
									
										
										
										
											2007-08-20 11:43:25 -04:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Unlink and free urb */ | 
					
						
							|  |  |  | 	if_usb_free(cardp); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	usb_set_intfdata(intf, NULL); | 
					
						
							|  |  |  | 	usb_put_dev(interface_to_usbdev(intf)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-20 11:43:25 -04:00
										 |  |  | 	lbs_deb_leave(LBS_DEB_MAIN); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							| 
									
										
										
										
											2011-04-26 15:25:29 -07:00
										 |  |  |  * if_usb_send_fw_pkt - download FW | 
					
						
							|  |  |  |  * @cardp:	pointer to &struct if_usb_card | 
					
						
							|  |  |  |  * returns:	0 | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | static int if_usb_send_fw_pkt(struct if_usb_card *cardp) | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 	struct fwdata *fwdata = cardp->ep_out_buf; | 
					
						
							| 
									
										
										
										
											2008-05-23 18:37:51 +01:00
										 |  |  | 	const uint8_t *firmware = cardp->fw->data; | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 	/* If we got a CRC failure on the last block, back
 | 
					
						
							|  |  |  | 	   up and retry it */ | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 	if (!cardp->CRC_OK) { | 
					
						
							|  |  |  | 		cardp->totalbytes = cardp->fwlastblksent; | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 		cardp->fwseqnum--; | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 	lbs_deb_usb2(&cardp->udev->dev, "totalbytes = %d\n", | 
					
						
							|  |  |  | 		     cardp->totalbytes); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 	/* struct fwdata (which we sent to the card) has an
 | 
					
						
							|  |  |  | 	   extra __le32 field in between the header and the data, | 
					
						
							|  |  |  | 	   which is not in the struct fwheader in the actual | 
					
						
							|  |  |  | 	   firmware binary. Insert the seqnum in the middle... */ | 
					
						
							|  |  |  | 	memcpy(&fwdata->hdr, &firmware[cardp->totalbytes], | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 	       sizeof(struct fwheader)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	cardp->fwlastblksent = cardp->totalbytes; | 
					
						
							|  |  |  | 	cardp->totalbytes += sizeof(struct fwheader); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	memcpy(fwdata->data, &firmware[cardp->totalbytes], | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 	       le32_to_cpu(fwdata->hdr.datalength)); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 	lbs_deb_usb2(&cardp->udev->dev, "Data length = %d\n", | 
					
						
							|  |  |  | 		     le32_to_cpu(fwdata->hdr.datalength)); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 	fwdata->seqnum = cpu_to_le32(++cardp->fwseqnum); | 
					
						
							|  |  |  | 	cardp->totalbytes += le32_to_cpu(fwdata->hdr.datalength); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 	usb_tx_block(cardp, cardp->ep_out_buf, sizeof(struct fwdata) + | 
					
						
							|  |  |  | 		     le32_to_cpu(fwdata->hdr.datalength)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (fwdata->hdr.dnldcmd == cpu_to_le32(FW_HAS_DATA_TO_RECV)) { | 
					
						
							|  |  |  | 		lbs_deb_usb2(&cardp->udev->dev, "There are data to follow\n"); | 
					
						
							|  |  |  | 		lbs_deb_usb2(&cardp->udev->dev, "seqnum = %d totalbytes = %d\n", | 
					
						
							|  |  |  | 			     cardp->fwseqnum, cardp->totalbytes); | 
					
						
							|  |  |  | 	} else if (fwdata->hdr.dnldcmd == cpu_to_le32(FW_HAS_LAST_BLOCK)) { | 
					
						
							|  |  |  | 		lbs_deb_usb2(&cardp->udev->dev, "Host has finished FW downloading\n"); | 
					
						
							|  |  |  | 		lbs_deb_usb2(&cardp->udev->dev, "Donwloading FW JUMP BLOCK\n"); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		cardp->fwfinalblk = 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 	lbs_deb_usb2(&cardp->udev->dev, "Firmware download done; size %d\n", | 
					
						
							|  |  |  | 		     cardp->totalbytes); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | static int if_usb_reset_device(struct if_usb_card *cardp) | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-07-27 13:08:08 -07:00
										 |  |  | 	struct cmd_header *cmd = cardp->ep_out_buf + 4; | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 	int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-05-25 12:01:42 -04:00
										 |  |  | 	lbs_deb_enter(LBS_DEB_USB); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 	*(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_REQUEST); | 
					
						
							| 
									
										
										
										
											2007-12-08 23:49:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	cmd->command = cpu_to_le16(CMD_802_11_RESET); | 
					
						
							| 
									
										
										
										
											2010-07-27 13:08:08 -07:00
										 |  |  | 	cmd->size = cpu_to_le16(sizeof(cmd)); | 
					
						
							| 
									
										
										
										
											2007-12-08 23:49:06 +00:00
										 |  |  | 	cmd->result = cpu_to_le16(0); | 
					
						
							|  |  |  | 	cmd->seqnum = cpu_to_le16(0x5a5a); | 
					
						
							| 
									
										
										
										
											2008-09-10 09:04:33 -04:00
										 |  |  | 	usb_tx_block(cardp, cardp->ep_out_buf, 4 + sizeof(struct cmd_header)); | 
					
						
							| 
									
										
										
										
											2007-12-08 23:49:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-10 18:53:34 -05:00
										 |  |  | 	msleep(100); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 	ret = usb_reset_device(cardp->udev); | 
					
						
							| 
									
										
										
										
											2007-12-10 18:53:34 -05:00
										 |  |  | 	msleep(100); | 
					
						
							| 
									
										
										
										
											2007-05-25 12:01:42 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-20 16:48:52 +01:00
										 |  |  | #ifdef CONFIG_OLPC
 | 
					
						
							|  |  |  | 	if (ret && machine_is_olpc()) | 
					
						
							|  |  |  | 		if_usb_reset_olpc_card(NULL); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-05-25 12:01:42 -04:00
										 |  |  | 	lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							| 
									
										
										
										
											2011-04-26 15:25:29 -07:00
										 |  |  |  *  usb_tx_block - transfer the data to the device | 
					
						
							|  |  |  |  *  @cardp: 	pointer to &struct if_usb_card | 
					
						
							|  |  |  |  *  @payload:	pointer to payload data | 
					
						
							|  |  |  |  *  @nb:	data length | 
					
						
							|  |  |  |  *  returns:	0 for success or negative error code | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload, uint16_t nb) | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2010-10-13 20:14:56 +01:00
										 |  |  | 	int ret; | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* check if device is removed */ | 
					
						
							| 
									
										
										
										
											2007-08-20 11:43:25 -04:00
										 |  |  | 	if (cardp->surprise_removed) { | 
					
						
							| 
									
										
										
										
											2007-05-25 11:27:16 -04:00
										 |  |  | 		lbs_deb_usbd(&cardp->udev->dev, "Device removed\n"); | 
					
						
							| 
									
										
										
										
											2010-10-13 20:14:56 +01:00
										 |  |  | 		ret = -ENODEV; | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 		goto tx_ret; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	usb_fill_bulk_urb(cardp->tx_urb, cardp->udev, | 
					
						
							|  |  |  | 			  usb_sndbulkpipe(cardp->udev, | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 					  cardp->ep_out), | 
					
						
							| 
									
										
										
										
											2007-08-20 11:43:25 -04:00
										 |  |  | 			  payload, nb, if_usb_write_bulk_callback, cardp); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	cardp->tx_urb->transfer_flags |= URB_ZERO_PACKET; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if ((ret = usb_submit_urb(cardp->tx_urb, GFP_ATOMIC))) { | 
					
						
							| 
									
										
										
										
											2007-12-07 15:12:26 +00:00
										 |  |  | 		lbs_deb_usbd(&cardp->udev->dev, "usb_submit_urb failed: %d\n", ret); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 		lbs_deb_usb2(&cardp->udev->dev, "usb_submit_urb success\n"); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 		ret = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | tx_ret: | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | static int __if_usb_submit_rx_urb(struct if_usb_card *cardp, | 
					
						
							| 
									
										
										
										
											2007-08-20 11:43:25 -04:00
										 |  |  | 				  void (*callbackfn)(struct urb *urb)) | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct sk_buff *skb; | 
					
						
							|  |  |  | 	int ret = -1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!(skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE))) { | 
					
						
							| 
									
										
										
										
											2011-05-02 16:49:14 -07:00
										 |  |  | 		pr_err("No free skb\n"); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 		goto rx_ret; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 	cardp->rx_skb = skb; | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Fill the receive configuration URB and initialise the Rx call back */ | 
					
						
							|  |  |  | 	usb_fill_bulk_urb(cardp->rx_urb, cardp->udev, | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 			  usb_rcvbulkpipe(cardp->udev, cardp->ep_in), | 
					
						
							| 
									
										
										
										
											2009-10-30 17:45:14 +00:00
										 |  |  | 			  skb->data + IPFIELD_ALIGN_OFFSET, | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 			  MRVDRV_ETH_RX_PACKET_BUFFER_SIZE, callbackfn, | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 			  cardp); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	cardp->rx_urb->transfer_flags |= URB_ZERO_PACKET; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 	lbs_deb_usb2(&cardp->udev->dev, "Pointer for rx_urb %p\n", cardp->rx_urb); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 	if ((ret = usb_submit_urb(cardp->rx_urb, GFP_ATOMIC))) { | 
					
						
							| 
									
										
										
										
											2007-12-07 15:12:26 +00:00
										 |  |  | 		lbs_deb_usbd(&cardp->udev->dev, "Submit Rx URB failed: %d\n", ret); | 
					
						
							| 
									
										
										
										
											2007-11-28 16:20:51 +00:00
										 |  |  | 		kfree_skb(skb); | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 		cardp->rx_skb = NULL; | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 		ret = -1; | 
					
						
							|  |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 		lbs_deb_usb2(&cardp->udev->dev, "Submit Rx URB success\n"); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 		ret = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | rx_ret: | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | static int if_usb_submit_rx_urb_fwload(struct if_usb_card *cardp) | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-08-20 11:43:25 -04:00
										 |  |  | 	return __if_usb_submit_rx_urb(cardp, &if_usb_receive_fwload); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | static int if_usb_submit_rx_urb(struct if_usb_card *cardp) | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-08-20 11:43:25 -04:00
										 |  |  | 	return __if_usb_submit_rx_urb(cardp, &if_usb_receive); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void if_usb_receive_fwload(struct urb *urb) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 	struct if_usb_card *cardp = urb->context; | 
					
						
							|  |  |  | 	struct sk_buff *skb = cardp->rx_skb; | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 	struct fwsyncheader *syncfwheader; | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 	struct bootcmdresp bootcmdresp; | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (urb->status) { | 
					
						
							| 
									
										
										
										
											2007-05-25 11:27:16 -04:00
										 |  |  | 		lbs_deb_usbd(&cardp->udev->dev, | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 			     "URB status is failed during fw load\n"); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 		kfree_skb(skb); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-11 13:15:25 -05:00
										 |  |  | 	if (cardp->fwdnldover) { | 
					
						
							|  |  |  | 		__le32 *tmp = (__le32 *)(skb->data + IPFIELD_ALIGN_OFFSET); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (tmp[0] == cpu_to_le32(CMD_TYPE_INDICATION) && | 
					
						
							|  |  |  | 		    tmp[1] == cpu_to_le32(MACREG_INT_CODE_FIRMWARE_READY)) { | 
					
						
							| 
									
										
										
										
											2011-05-02 16:49:14 -07:00
										 |  |  | 			pr_info("Firmware ready event received\n"); | 
					
						
							| 
									
										
										
										
											2007-12-11 13:15:25 -05:00
										 |  |  | 			wake_up(&cardp->fw_wq); | 
					
						
							|  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 			lbs_deb_usb("Waiting for confirmation; got %x %x\n", | 
					
						
							|  |  |  | 				    le32_to_cpu(tmp[0]), le32_to_cpu(tmp[1])); | 
					
						
							| 
									
										
										
										
											2007-12-11 13:15:25 -05:00
										 |  |  | 			if_usb_submit_rx_urb_fwload(cardp); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		kfree_skb(skb); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-12-10 18:53:34 -05:00
										 |  |  | 	if (cardp->bootcmdresp <= 0) { | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 		memcpy (&bootcmdresp, skb->data + IPFIELD_ALIGN_OFFSET, | 
					
						
							|  |  |  | 			sizeof(bootcmdresp)); | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-05-25 23:36:54 -04:00
										 |  |  | 		if (le16_to_cpu(cardp->udev->descriptor.bcdDevice) < 0x3106) { | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 			kfree_skb(skb); | 
					
						
							| 
									
										
										
										
											2007-08-20 11:43:25 -04:00
										 |  |  | 			if_usb_submit_rx_urb_fwload(cardp); | 
					
						
							| 
									
										
										
										
											2008-07-21 11:02:46 -07:00
										 |  |  | 			cardp->bootcmdresp = BOOT_CMD_RESP_OK; | 
					
						
							| 
									
										
										
										
											2007-05-25 11:27:16 -04:00
										 |  |  | 			lbs_deb_usbd(&cardp->udev->dev, | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 				     "Received valid boot command response\n"); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 			return; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 		if (bootcmdresp.magic != cpu_to_le32(BOOT_CMD_MAGIC_NUMBER)) { | 
					
						
							|  |  |  | 			if (bootcmdresp.magic == cpu_to_le32(CMD_TYPE_REQUEST) || | 
					
						
							|  |  |  | 			    bootcmdresp.magic == cpu_to_le32(CMD_TYPE_DATA) || | 
					
						
							|  |  |  | 			    bootcmdresp.magic == cpu_to_le32(CMD_TYPE_INDICATION)) { | 
					
						
							| 
									
										
										
										
											2007-12-11 13:15:25 -05:00
										 |  |  | 				if (!cardp->bootcmdresp) | 
					
						
							| 
									
										
										
										
											2011-05-02 16:49:14 -07:00
										 |  |  | 					pr_info("Firmware already seems alive; resetting\n"); | 
					
						
							| 
									
										
										
										
											2007-12-08 23:49:06 +00:00
										 |  |  | 				cardp->bootcmdresp = -1; | 
					
						
							|  |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2011-05-02 16:49:14 -07:00
										 |  |  | 				pr_info("boot cmd response wrong magic number (0x%x)\n", | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 					    le32_to_cpu(bootcmdresp.magic)); | 
					
						
							| 
									
										
										
										
											2007-12-08 23:49:06 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2008-07-21 11:02:46 -07:00
										 |  |  | 		} else if ((bootcmdresp.cmd != BOOT_CMD_FW_BY_USB) && | 
					
						
							|  |  |  | 			   (bootcmdresp.cmd != BOOT_CMD_UPDATE_FW) && | 
					
						
							|  |  |  | 			   (bootcmdresp.cmd != BOOT_CMD_UPDATE_BOOT2)) { | 
					
						
							| 
									
										
										
										
											2011-05-02 16:49:14 -07:00
										 |  |  | 			pr_info("boot cmd response cmd_tag error (%d)\n", | 
					
						
							|  |  |  | 				bootcmdresp.cmd); | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 		} else if (bootcmdresp.result != BOOT_CMD_RESP_OK) { | 
					
						
							| 
									
										
										
										
											2011-05-02 16:49:14 -07:00
										 |  |  | 			pr_info("boot cmd response result error (%d)\n", | 
					
						
							|  |  |  | 				bootcmdresp.result); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 		} else { | 
					
						
							|  |  |  | 			cardp->bootcmdresp = 1; | 
					
						
							| 
									
										
										
										
											2007-05-25 11:27:16 -04:00
										 |  |  | 			lbs_deb_usbd(&cardp->udev->dev, | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 				     "Received valid boot command response\n"); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		kfree_skb(skb); | 
					
						
							| 
									
										
										
										
											2007-08-20 11:43:25 -04:00
										 |  |  | 		if_usb_submit_rx_urb_fwload(cardp); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-15 23:12:28 +02:00
										 |  |  | 	syncfwheader = kmemdup(skb->data + IPFIELD_ALIGN_OFFSET, | 
					
						
							|  |  |  | 			       sizeof(struct fwsyncheader), GFP_ATOMIC); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 	if (!syncfwheader) { | 
					
						
							| 
									
										
										
										
											2007-05-25 11:27:16 -04:00
										 |  |  | 		lbs_deb_usbd(&cardp->udev->dev, "Failure to allocate syncfwheader\n"); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 		kfree_skb(skb); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!syncfwheader->cmd) { | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 		lbs_deb_usb2(&cardp->udev->dev, "FW received Blk with correct CRC\n"); | 
					
						
							|  |  |  | 		lbs_deb_usb2(&cardp->udev->dev, "FW received Blk seqnum = %d\n", | 
					
						
							|  |  |  | 			     le32_to_cpu(syncfwheader->seqnum)); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 		cardp->CRC_OK = 1; | 
					
						
							|  |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 		lbs_deb_usbd(&cardp->udev->dev, "FW received Blk with CRC error\n"); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 		cardp->CRC_OK = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	kfree_skb(skb); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-21 11:02:46 -07:00
										 |  |  | 	/* Give device 5s to either write firmware to its RAM or eeprom */ | 
					
						
							|  |  |  | 	mod_timer(&cardp->fw_timeout, jiffies + (HZ*5)); | 
					
						
							| 
									
										
										
										
											2007-12-11 00:07:58 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 	if (cardp->fwfinalblk) { | 
					
						
							|  |  |  | 		cardp->fwdnldover = 1; | 
					
						
							|  |  |  | 		goto exit; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-11 00:07:58 -05:00
										 |  |  | 	if_usb_send_fw_pkt(cardp); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-11 00:07:58 -05:00
										 |  |  |  exit: | 
					
						
							| 
									
										
										
										
											2007-12-11 13:15:25 -05:00
										 |  |  | 	if_usb_submit_rx_urb_fwload(cardp); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 	kfree(syncfwheader); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define MRVDRV_MIN_PKT_LEN	30
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline void process_cmdtypedata(int recvlength, struct sk_buff *skb, | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 				       struct if_usb_card *cardp, | 
					
						
							| 
									
										
										
										
											2007-11-23 15:43:44 +01:00
										 |  |  | 				       struct lbs_private *priv) | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 	if (recvlength > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + MESSAGE_HEADER_LEN | 
					
						
							|  |  |  | 	    || recvlength < MRVDRV_MIN_PKT_LEN) { | 
					
						
							|  |  |  | 		lbs_deb_usbd(&cardp->udev->dev, "Packet length is Invalid\n"); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 		kfree_skb(skb); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	skb_reserve(skb, IPFIELD_ALIGN_OFFSET); | 
					
						
							|  |  |  | 	skb_put(skb, recvlength); | 
					
						
							|  |  |  | 	skb_pull(skb, MESSAGE_HEADER_LEN); | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-11-15 18:05:47 -05:00
										 |  |  | 	lbs_process_rxed_packet(priv, skb); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff, | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 				      struct sk_buff *skb, | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 				      struct if_usb_card *cardp, | 
					
						
							| 
									
										
										
										
											2007-11-23 15:43:44 +01:00
										 |  |  | 				      struct lbs_private *priv) | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2008-04-01 14:50:43 +02:00
										 |  |  | 	u8 i; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-11 13:49:39 -05:00
										 |  |  | 	if (recvlength > LBS_CMD_BUFFER_SIZE) { | 
					
						
							| 
									
										
										
										
											2007-05-25 11:27:16 -04:00
										 |  |  | 		lbs_deb_usbd(&cardp->udev->dev, | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 			     "The receive buffer is too large\n"); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 		kfree_skb(skb); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-11 14:50:23 +00:00
										 |  |  | 	BUG_ON(!in_interrupt()); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-08 20:04:36 +00:00
										 |  |  | 	spin_lock(&priv->driver_lock); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-01 14:50:43 +02:00
										 |  |  | 	i = (priv->resp_idx == 0) ? 1 : 0; | 
					
						
							|  |  |  | 	BUG_ON(priv->resp_len[i]); | 
					
						
							|  |  |  | 	priv->resp_len[i] = (recvlength - MESSAGE_HEADER_LEN); | 
					
						
							|  |  |  | 	memcpy(priv->resp_buf[i], recvbuff + MESSAGE_HEADER_LEN, | 
					
						
							|  |  |  | 		priv->resp_len[i]); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 	kfree_skb(skb); | 
					
						
							| 
									
										
										
										
											2008-04-01 14:50:43 +02:00
										 |  |  | 	lbs_notify_command_response(priv, i); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-08 20:04:36 +00:00
										 |  |  | 	spin_unlock(&priv->driver_lock); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-05-25 11:27:16 -04:00
										 |  |  | 	lbs_deb_usbd(&cardp->udev->dev, | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 		    "Wake up main thread to handle cmd response\n"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							| 
									
										
										
										
											2011-04-26 15:25:29 -07:00
										 |  |  |  *  if_usb_receive - read the packet into the upload buffer, | 
					
						
							|  |  |  |  *  wake up the main thread and initialise the Rx callack | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2011-04-26 15:25:29 -07:00
										 |  |  |  *  @urb:	pointer to &struct urb | 
					
						
							|  |  |  |  *  returns:	N/A | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  |  */ | 
					
						
							|  |  |  | static void if_usb_receive(struct urb *urb) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 	struct if_usb_card *cardp = urb->context; | 
					
						
							|  |  |  | 	struct sk_buff *skb = cardp->rx_skb; | 
					
						
							| 
									
										
										
										
											2007-11-23 15:43:44 +01:00
										 |  |  | 	struct lbs_private *priv = cardp->priv; | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 	int recvlength = urb->actual_length; | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 	uint8_t *recvbuff = NULL; | 
					
						
							|  |  |  | 	uint32_t recvtype = 0; | 
					
						
							|  |  |  | 	__le32 *pkt = (__le32 *)(skb->data + IPFIELD_ALIGN_OFFSET); | 
					
						
							| 
									
										
										
										
											2008-04-01 14:50:43 +02:00
										 |  |  | 	uint32_t event; | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-05-25 11:27:16 -04:00
										 |  |  | 	lbs_deb_enter(LBS_DEB_USB); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (recvlength) { | 
					
						
							|  |  |  | 		if (urb->status) { | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 			lbs_deb_usbd(&cardp->udev->dev, "RX URB failed: %d\n", | 
					
						
							|  |  |  | 				     urb->status); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 			kfree_skb(skb); | 
					
						
							|  |  |  | 			goto setup_for_next; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		recvbuff = skb->data + IPFIELD_ALIGN_OFFSET; | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 		recvtype = le32_to_cpu(pkt[0]); | 
					
						
							| 
									
										
										
										
											2007-05-25 11:27:16 -04:00
										 |  |  | 		lbs_deb_usbd(&cardp->udev->dev, | 
					
						
							| 
									
										
										
										
											2007-08-03 09:40:55 -04:00
										 |  |  | 			    "Recv length = 0x%x, Recv type = 0x%X\n", | 
					
						
							|  |  |  | 			    recvlength, recvtype); | 
					
						
							| 
									
										
										
										
											2007-11-28 16:20:51 +00:00
										 |  |  | 	} else if (urb->status) { | 
					
						
							|  |  |  | 		kfree_skb(skb); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 		goto rx_exit; | 
					
						
							| 
									
										
										
										
											2007-11-28 16:20:51 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	switch (recvtype) { | 
					
						
							|  |  |  | 	case CMD_TYPE_DATA: | 
					
						
							|  |  |  | 		process_cmdtypedata(recvlength, skb, cardp, priv); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case CMD_TYPE_REQUEST: | 
					
						
							|  |  |  | 		process_cmdrequest(recvlength, recvbuff, skb, cardp, priv); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case CMD_TYPE_INDICATION: | 
					
						
							| 
									
										
										
										
											2008-04-01 14:50:43 +02:00
										 |  |  | 		/* Event handling */ | 
					
						
							|  |  |  | 		event = le32_to_cpu(pkt[1]); | 
					
						
							|  |  |  | 		lbs_deb_usbd(&cardp->udev->dev, "**EVENT** 0x%X\n", event); | 
					
						
							|  |  |  | 		kfree_skb(skb); | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-01 14:50:43 +02:00
										 |  |  | 		/* Icky undocumented magic special case */ | 
					
						
							|  |  |  | 		if (event & 0xffff0000) { | 
					
						
							|  |  |  | 			u32 trycount = (event & 0xffff0000) >> 16; | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-01 14:50:43 +02:00
										 |  |  | 			lbs_send_tx_feedback(priv, trycount); | 
					
						
							|  |  |  | 		} else | 
					
						
							|  |  |  | 			lbs_queue_event(priv, event & 0xFF); | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2007-08-03 09:40:55 -04:00
										 |  |  | 		lbs_deb_usbd(&cardp->udev->dev, "Unknown command type 0x%X\n", | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 			     recvtype); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 		kfree_skb(skb); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | setup_for_next: | 
					
						
							| 
									
										
										
										
											2007-08-20 11:43:25 -04:00
										 |  |  | 	if_usb_submit_rx_urb(cardp); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | rx_exit: | 
					
						
							| 
									
										
										
										
											2007-05-25 11:27:16 -04:00
										 |  |  | 	lbs_deb_leave(LBS_DEB_USB); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							| 
									
										
										
										
											2011-04-26 15:25:29 -07:00
										 |  |  |  *  if_usb_host_to_card - downloads data to FW | 
					
						
							|  |  |  |  *  @priv:	pointer to &struct lbs_private structure | 
					
						
							|  |  |  |  *  @type:	type of data | 
					
						
							|  |  |  |  *  @payload:	pointer to data buffer | 
					
						
							|  |  |  |  *  @nb:	number of bytes | 
					
						
							|  |  |  |  *  returns:	0 for success or negative error code | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type, | 
					
						
							|  |  |  | 			       uint8_t *payload, uint16_t nb) | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 	struct if_usb_card *cardp = priv->card; | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-05-25 11:27:16 -04:00
										 |  |  | 	lbs_deb_usbd(&cardp->udev->dev,"*** type = %u\n", type); | 
					
						
							|  |  |  | 	lbs_deb_usbd(&cardp->udev->dev,"size after = %d\n", nb); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (type == MVMS_CMD) { | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 		*(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_REQUEST); | 
					
						
							| 
									
										
										
										
											2007-05-25 13:05:16 -04:00
										 |  |  | 		priv->dnld_sent = DNLD_CMD_SENT; | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 		*(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_DATA); | 
					
						
							| 
									
										
										
										
											2007-05-25 13:05:16 -04:00
										 |  |  | 		priv->dnld_sent = DNLD_DATA_SENT; | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 	memcpy((cardp->ep_out_buf + MESSAGE_HEADER_LEN), payload, nb); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 	return usb_tx_block(cardp, cardp->ep_out_buf, nb + MESSAGE_HEADER_LEN); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-02 11:14:49 -04:00
										 |  |  | /**
 | 
					
						
							| 
									
										
										
										
											2011-04-26 15:25:29 -07:00
										 |  |  |  *  if_usb_issue_boot_command - issues Boot command to the Boot2 code | 
					
						
							|  |  |  |  *  @cardp:	pointer to &if_usb_card | 
					
						
							|  |  |  |  *  @ivalue:	1:Boot from FW by USB-Download | 
					
						
							|  |  |  |  *		2:Boot from FW in EEPROM | 
					
						
							|  |  |  |  *  returns:	0 for success or negative error code | 
					
						
							| 
									
										
										
										
											2007-08-02 11:14:49 -04:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | static int if_usb_issue_boot_command(struct if_usb_card *cardp, int ivalue) | 
					
						
							| 
									
										
										
										
											2007-08-02 11:14:49 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 	struct bootcmd *bootcmd = cardp->ep_out_buf; | 
					
						
							| 
									
										
										
										
											2007-08-02 11:14:49 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Prepare command */ | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 	bootcmd->magic = cpu_to_le32(BOOT_CMD_MAGIC_NUMBER); | 
					
						
							|  |  |  | 	bootcmd->cmd = ivalue; | 
					
						
							|  |  |  | 	memset(bootcmd->pad, 0, sizeof(bootcmd->pad)); | 
					
						
							| 
									
										
										
										
											2007-08-02 11:14:49 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Issue command */ | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 	usb_tx_block(cardp, cardp->ep_out_buf, sizeof(*bootcmd)); | 
					
						
							| 
									
										
										
										
											2007-08-02 11:14:49 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-20 11:43:25 -04:00
										 |  |  | /**
 | 
					
						
							| 
									
										
										
										
											2011-04-26 15:25:29 -07:00
										 |  |  |  *  check_fwfile_format - check the validity of Boot2/FW image | 
					
						
							| 
									
										
										
										
											2007-08-20 11:43:25 -04:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2011-04-26 15:25:29 -07:00
										 |  |  |  *  @data:	pointer to image | 
					
						
							|  |  |  |  *  @totlen:	image length | 
					
						
							|  |  |  |  *  returns:     0 (good) or 1 (failure) | 
					
						
							| 
									
										
										
										
											2007-08-20 11:43:25 -04:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2008-05-23 18:37:51 +01:00
										 |  |  | static int check_fwfile_format(const uint8_t *data, uint32_t totlen) | 
					
						
							| 
									
										
										
										
											2007-08-20 11:43:25 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 	uint32_t bincmd, exit; | 
					
						
							|  |  |  | 	uint32_t blksize, offset, len; | 
					
						
							| 
									
										
										
										
											2007-08-20 11:43:25 -04:00
										 |  |  | 	int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = 1; | 
					
						
							|  |  |  | 	exit = len = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	do { | 
					
						
							|  |  |  | 		struct fwheader *fwh = (void *)data; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		bincmd = le32_to_cpu(fwh->dnldcmd); | 
					
						
							|  |  |  | 		blksize = le32_to_cpu(fwh->datalength); | 
					
						
							|  |  |  | 		switch (bincmd) { | 
					
						
							|  |  |  | 		case FW_HAS_DATA_TO_RECV: | 
					
						
							|  |  |  | 			offset = sizeof(struct fwheader) + blksize; | 
					
						
							|  |  |  | 			data += offset; | 
					
						
							|  |  |  | 			len += offset; | 
					
						
							|  |  |  | 			if (len >= totlen) | 
					
						
							|  |  |  | 				exit = 1; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case FW_HAS_LAST_BLOCK: | 
					
						
							|  |  |  | 			exit = 1; | 
					
						
							|  |  |  | 			ret = 0; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			exit = 1; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} while (!exit); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (ret) | 
					
						
							| 
									
										
										
										
											2011-05-02 16:49:14 -07:00
										 |  |  | 		pr_err("firmware file format check FAIL\n"); | 
					
						
							| 
									
										
										
										
											2007-08-20 11:43:25 -04:00
										 |  |  | 	else | 
					
						
							|  |  |  | 		lbs_deb_fw("firmware file format check PASS\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-16 23:53:55 +01:00
										 |  |  | static void if_usb_prog_firmware(struct lbs_private *priv, int ret, | 
					
						
							|  |  |  | 				 const struct firmware *fw, | 
					
						
							|  |  |  | 				 const struct firmware *unused) | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-04-16 23:53:55 +01:00
										 |  |  | 	struct if_usb_card *cardp = priv->card; | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 	int i = 0; | 
					
						
							|  |  |  | 	static int reset_count = 10; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-05-25 11:27:16 -04:00
										 |  |  | 	lbs_deb_enter(LBS_DEB_USB); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-07 21:13:57 -05:00
										 |  |  | 	if (ret) { | 
					
						
							| 
									
										
										
										
											2011-05-02 16:49:14 -07:00
										 |  |  | 		pr_err("failed to find firmware (%d)\n", ret); | 
					
						
							| 
									
										
										
										
											2007-08-20 11:43:25 -04:00
										 |  |  | 		goto done; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-16 23:53:55 +01:00
										 |  |  | 	cardp->fw = fw; | 
					
						
							| 
									
										
										
										
											2008-07-21 11:02:46 -07:00
										 |  |  | 	if (check_fwfile_format(cardp->fw->data, cardp->fw->size)) { | 
					
						
							|  |  |  | 		ret = -EINVAL; | 
					
						
							| 
									
										
										
										
											2013-10-14 17:51:55 -05:00
										 |  |  | 		goto done; | 
					
						
							| 
									
										
										
										
											2008-07-21 11:02:46 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Cancel any pending usb business */ | 
					
						
							|  |  |  | 	usb_kill_urb(cardp->rx_urb); | 
					
						
							|  |  |  | 	usb_kill_urb(cardp->tx_urb); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	cardp->fwlastblksent = 0; | 
					
						
							|  |  |  | 	cardp->fwdnldover = 0; | 
					
						
							|  |  |  | 	cardp->totalbytes = 0; | 
					
						
							|  |  |  | 	cardp->fwfinalblk = 0; | 
					
						
							|  |  |  | 	cardp->bootcmdresp = 0; | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							|  |  |  | restart: | 
					
						
							| 
									
										
										
										
											2007-08-20 11:43:25 -04:00
										 |  |  | 	if (if_usb_submit_rx_urb_fwload(cardp) < 0) { | 
					
						
							| 
									
										
										
										
											2007-05-25 11:27:16 -04:00
										 |  |  | 		lbs_deb_usbd(&cardp->udev->dev, "URB submission is failed\n"); | 
					
						
							| 
									
										
										
										
											2008-07-21 11:02:46 -07:00
										 |  |  | 		ret = -EIO; | 
					
						
							| 
									
										
										
										
											2013-10-14 17:51:55 -05:00
										 |  |  | 		goto done; | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	cardp->bootcmdresp = 0; | 
					
						
							|  |  |  | 	do { | 
					
						
							|  |  |  | 		int j = 0; | 
					
						
							|  |  |  | 		i++; | 
					
						
							| 
									
										
										
										
											2012-04-16 23:52:42 +01:00
										 |  |  | 		if_usb_issue_boot_command(cardp, BOOT_CMD_FW_BY_USB); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 		/* wait for command response */ | 
					
						
							|  |  |  | 		do { | 
					
						
							|  |  |  | 			j++; | 
					
						
							|  |  |  | 			msleep_interruptible(100); | 
					
						
							|  |  |  | 		} while (cardp->bootcmdresp == 0 && j < 10); | 
					
						
							|  |  |  | 	} while (cardp->bootcmdresp == 0 && i < 5); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-21 11:02:46 -07:00
										 |  |  | 	if (cardp->bootcmdresp == BOOT_CMD_RESP_NOT_SUPPORTED) { | 
					
						
							|  |  |  | 		/* Return to normal operation */ | 
					
						
							|  |  |  | 		ret = -EOPNOTSUPP; | 
					
						
							|  |  |  | 		usb_kill_urb(cardp->rx_urb); | 
					
						
							|  |  |  | 		usb_kill_urb(cardp->tx_urb); | 
					
						
							|  |  |  | 		if (if_usb_submit_rx_urb(cardp) < 0) | 
					
						
							|  |  |  | 			ret = -EIO; | 
					
						
							| 
									
										
										
										
											2013-10-14 17:51:55 -05:00
										 |  |  | 		goto done; | 
					
						
							| 
									
										
										
										
											2008-07-21 11:02:46 -07:00
										 |  |  | 	} else if (cardp->bootcmdresp <= 0) { | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 		if (--reset_count >= 0) { | 
					
						
							| 
									
										
										
										
											2007-08-20 11:43:25 -04:00
										 |  |  | 			if_usb_reset_device(cardp); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 			goto restart; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-07-21 11:02:46 -07:00
										 |  |  | 		ret = -EIO; | 
					
						
							| 
									
										
										
										
											2013-10-14 17:51:55 -05:00
										 |  |  | 		goto done; | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	i = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	cardp->totalbytes = 0; | 
					
						
							|  |  |  | 	cardp->fwlastblksent = 0; | 
					
						
							|  |  |  | 	cardp->CRC_OK = 1; | 
					
						
							|  |  |  | 	cardp->fwdnldover = 0; | 
					
						
							|  |  |  | 	cardp->fwseqnum = -1; | 
					
						
							|  |  |  | 	cardp->totalbytes = 0; | 
					
						
							|  |  |  | 	cardp->fwfinalblk = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-11 00:07:58 -05:00
										 |  |  | 	/* Send the first firmware packet... */ | 
					
						
							|  |  |  | 	if_usb_send_fw_pkt(cardp); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-11 00:07:58 -05:00
										 |  |  | 	/* ... and wait for the process to complete */ | 
					
						
							|  |  |  | 	wait_event_interruptible(cardp->fw_wq, cardp->surprise_removed || cardp->fwdnldover); | 
					
						
							| 
									
										
										
										
											2007-12-14 22:53:41 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-11 00:07:58 -05:00
										 |  |  | 	del_timer_sync(&cardp->fw_timeout); | 
					
						
							| 
									
										
										
										
											2007-12-11 13:15:25 -05:00
										 |  |  | 	usb_kill_urb(cardp->rx_urb); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (!cardp->fwdnldover) { | 
					
						
							| 
									
										
										
										
											2011-05-02 16:49:14 -07:00
										 |  |  | 		pr_info("failed to load fw, resetting device!\n"); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 		if (--reset_count >= 0) { | 
					
						
							| 
									
										
										
										
											2007-08-20 11:43:25 -04:00
										 |  |  | 			if_usb_reset_device(cardp); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 			goto restart; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-02 16:49:14 -07:00
										 |  |  | 		pr_info("FW download failure, time = %d ms\n", i * 100); | 
					
						
							| 
									
										
										
										
											2008-07-21 11:02:46 -07:00
										 |  |  | 		ret = -EIO; | 
					
						
							| 
									
										
										
										
											2013-10-14 17:51:55 -05:00
										 |  |  | 		goto done; | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-16 23:53:55 +01:00
										 |  |  | 	cardp->priv->fw_ready = 1; | 
					
						
							|  |  |  | 	if_usb_submit_rx_urb(cardp); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (lbs_start_card(priv)) | 
					
						
							| 
									
										
										
										
											2013-10-14 17:51:55 -05:00
										 |  |  | 		goto done; | 
					
						
							| 
									
										
										
										
											2012-04-16 23:53:55 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	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; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  |  done: | 
					
						
							| 
									
										
										
										
											2013-10-14 17:51:55 -05:00
										 |  |  | 	cardp->fw = NULL; | 
					
						
							| 
									
										
										
										
											2012-04-16 23:53:55 +01:00
										 |  |  | 	lbs_deb_leave(LBS_DEB_USB); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-02 11:45:12 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | #ifdef CONFIG_PM
 | 
					
						
							|  |  |  | static int if_usb_suspend(struct usb_interface *intf, pm_message_t message) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 	struct if_usb_card *cardp = usb_get_intfdata(intf); | 
					
						
							| 
									
										
										
										
											2007-11-23 15:43:44 +01:00
										 |  |  | 	struct lbs_private *priv = cardp->priv; | 
					
						
							| 
									
										
										
										
											2007-12-12 17:40:56 -05:00
										 |  |  | 	int ret; | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-05-25 11:27:16 -04:00
										 |  |  | 	lbs_deb_enter(LBS_DEB_USB); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-16 17:44:00 +02:00
										 |  |  | 	if (priv->psstate != PS_STATE_FULL_POWER) { | 
					
						
							|  |  |  | 		ret = -1; | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-27 17:19:00 +01:00
										 |  |  | #ifdef CONFIG_OLPC
 | 
					
						
							|  |  |  | 	if (machine_is_olpc()) { | 
					
						
							|  |  |  | 		if (priv->wol_criteria == EHS_REMOVE_WAKEUP) | 
					
						
							|  |  |  | 			olpc_ec_wakeup_clear(EC_SCI_SRC_WLAN); | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 			olpc_ec_wakeup_set(EC_SCI_SRC_WLAN); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-12 17:40:56 -05:00
										 |  |  | 	ret = lbs_suspend(priv); | 
					
						
							|  |  |  | 	if (ret) | 
					
						
							|  |  |  | 		goto out; | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Unlink tx & rx urb */ | 
					
						
							|  |  |  | 	usb_kill_urb(cardp->tx_urb); | 
					
						
							|  |  |  | 	usb_kill_urb(cardp->rx_urb); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-12 17:40:56 -05:00
										 |  |  |  out: | 
					
						
							| 
									
										
										
										
											2007-05-25 11:27:16 -04:00
										 |  |  | 	lbs_deb_leave(LBS_DEB_USB); | 
					
						
							| 
									
										
										
										
											2007-12-12 17:40:56 -05:00
										 |  |  | 	return ret; | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int if_usb_resume(struct usb_interface *intf) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | 	struct if_usb_card *cardp = usb_get_intfdata(intf); | 
					
						
							| 
									
										
										
										
											2007-11-23 15:43:44 +01:00
										 |  |  | 	struct lbs_private *priv = cardp->priv; | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-05-25 11:27:16 -04:00
										 |  |  | 	lbs_deb_enter(LBS_DEB_USB); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-11 12:53:43 -05:00
										 |  |  | 	if_usb_submit_rx_urb(cardp); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-12 17:40:56 -05:00
										 |  |  | 	lbs_resume(priv); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-05-25 11:27:16 -04:00
										 |  |  | 	lbs_deb_leave(LBS_DEB_USB); | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | #define if_usb_suspend NULL
 | 
					
						
							|  |  |  | #define if_usb_resume NULL
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct usb_driver if_usb_driver = { | 
					
						
							| 
									
										
										
										
											2007-11-20 17:44:04 -05:00
										 |  |  | 	.name = DRV_NAME, | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | 	.probe = if_usb_probe, | 
					
						
							|  |  |  | 	.disconnect = if_usb_disconnect, | 
					
						
							|  |  |  | 	.id_table = if_usb_table, | 
					
						
							|  |  |  | 	.suspend = if_usb_suspend, | 
					
						
							|  |  |  | 	.resume = if_usb_resume, | 
					
						
							| 
									
										
										
										
											2008-07-01 11:43:53 -07:00
										 |  |  | 	.reset_resume = if_usb_resume, | 
					
						
							| 
									
										
										
										
											2012-04-23 10:08:51 -07:00
										 |  |  | 	.disable_hub_initiated_lpm = 1, | 
					
						
							| 
									
										
										
										
											2007-02-10 12:25:27 -02:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-18 09:44:20 -08:00
										 |  |  | module_usb_driver(if_usb_driver); | 
					
						
							| 
									
										
										
										
											2007-05-25 12:37:58 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | MODULE_DESCRIPTION("8388 USB WLAN Driver"); | 
					
						
							| 
									
										
										
										
											2007-12-14 00:47:05 -05:00
										 |  |  | MODULE_AUTHOR("Marvell International Ltd. and Red Hat, Inc."); | 
					
						
							| 
									
										
										
										
											2007-05-25 12:37:58 -04:00
										 |  |  | MODULE_LICENSE("GPL"); |