Search Linux Wireless

[PATCH 05/05] orinoco: Agere/Lucent firmware download

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Enable firmware download for orinoco_cs

Add module parameters download_firmware and firmware. The first option
specifies whether or not to attempt a download. The second the name of
the firmware file to use.

Signed-off-by: David Kilroy <kilroyd@xxxxxxxxx>
---
diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c
index d1e5022..db3cc95 100644
--- a/drivers/net/wireless/orinoco_cs.c
+++ b/drivers/net/wireless/orinoco_cs.c
@@ -17,12 +17,14 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/firmware.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ds.h>
 
+#include "hermes_dld.h"
 #include "orinoco.h"
 
 /********************************************************************/
@@ -41,6 +43,17 @@ static int ignore_cis_vcc; /* = 0 */
 module_param(ignore_cis_vcc, int, 0);
 MODULE_PARM_DESC(ignore_cis_vcc, "Allow voltage mismatch between card and socket");
 
+static char *firmware = "orinoco.fw";
+module_param(firmware, charp, 0644);
+MODULE_PARM_DESC(firmware, "Name of firmware file to load");
+
+static int download_firmware; /* = 0 */
+module_param(download_firmware, int, 0644);
+MODULE_PARM_DESC(download_firmware, "Attempt firmware download");
+
+#define PDA_ADDR 0x00390000
+#define PDA_SIZE 1000
+
 /********************************************************************/
 /* Data structures						    */
 /********************************************************************/
@@ -57,6 +70,20 @@ struct orinoco_pccard {
 	unsigned long hard_reset_in_progress; 
 };
 
+/* Structure used to access fields in FW
+ * Make sure LE decoding macros are used
+ */
+struct orinoco_fw_header {
+	char hdr_vers[6];       /* ASCII string for header version */
+	__le16 headersize;      /* Total length of header */
+	__le32 entry_point;     /* NIC entry point */
+	__le32 blocks;          /* Number of blocks to program */
+	__le32 block_offset;    /* Offset of block data from eof header */
+	__le32 pdr_offset;      /* Offset to PDR data from eof header */
+	__le32 pri_offset;      /* Offset to primary plug data */
+	__le32 compat_offset;   /* Offset to compatibility data*/
+	char signature[0];      /* FW signature length headersize-20 */
+} __attribute__ ((packed));
 
 /********************************************************************/
 /* Function prototypes						    */
@@ -70,6 +97,94 @@ static void orinoco_cs_detach(struct pcmcia_device *p_dev);
 /* Device methods     						    */
 /********************************************************************/
 
+/*
+ * Download the firmware into the card, this also does a PCMCIA soft
+ * reset on the card, to make sure it's in a sane state.
+ */
+static int
+orinoco_cs_dl_firmware(hermes_t *hw,
+		       struct pcmcia_device *link)
+{
+	/* Plug Data Area (PDA) */
+	__le16 pda[PDA_SIZE/sizeof(__le16)] = { 0 };
+
+	const struct firmware *fw_entry;
+	const struct orinoco_fw_header *hdr;
+	const unsigned char *first_block;
+	unsigned long len;
+	int err;
+
+#if 0
+	int i;
+	for (i = 0; i < 6; i++) {
+		/* wl_lkm driver disables these if configured as an AP */
+		err = hermes_disable_port(hw, i);
+		if (err)
+			printk(KERN_ERR PFX
+			       "WARNING: can't disable port %d. %d\n",
+			       i, err);
+	}
+#endif
+	printk(KERN_DEBUG PFX "Attempting to download firmware %s\n",
+	       firmware);
+
+	/* Read current plug data */
+	err = hermes_read_pda(hw, pda, PDA_ADDR, sizeof(pda), 0);
+	printk(KERN_DEBUG PFX "Read PDA returned %d\n", err);
+	if (err)
+		return err;
+
+	err = request_firmware(&fw_entry, firmware, &handle_to_dev(link));
+	if (err) {
+		printk(KERN_ERR PFX "Cannot find firmware %s\n",
+		       firmware);
+		return -ENOENT;
+	}
+
+	hdr = (const struct orinoco_fw_header *) fw_entry->data;
+	len = fw_entry->size;
+
+	/* Enable aux port to allow programming */
+	err = hermesi_program_init(hw, le32_to_cpu(hdr->entry_point));
+	printk(KERN_DEBUG PFX "Program init returned %d\n", err);
+	if (err != 0)
+		goto abort;
+
+	/* Program data */
+	first_block = (fw_entry->data +
+		       le16_to_cpu(hdr->headersize) +
+		       le32_to_cpu(hdr->block_offset));
+
+	err = hermes_program(hw, first_block);
+	printk(KERN_DEBUG PFX "Program returned %d\n", err);
+	if (err != 0)
+		goto abort;
+
+	/* Update production data */
+	first_block = (fw_entry->data +
+		       le16_to_cpu(hdr->headersize) +
+		       le32_to_cpu(hdr->pdr_offset));
+
+	err = hermes_apply_pda_with_defaults(hw, first_block, pda);
+	printk(KERN_DEBUG PFX "Apply PDA returned %d\n", err);
+	if (err)
+		goto abort;
+
+	/* Tell card we've finished */
+	err = hermesi_program_end(hw);
+	printk(KERN_DEBUG PFX "Program end returned %d\n", err);
+	if (err != 0)
+		goto abort;
+
+	/* Check if we're running */
+	printk(KERN_DEBUG PFX "hermes_present returned %d\n",
+	       hermes_present(hw));
+
+abort:
+	release_firmware(fw_entry);
+	return err;
+}
+
 static int
 orinoco_cs_hard_reset(struct orinoco_private *priv)
 {
@@ -85,6 +200,13 @@ orinoco_cs_hard_reset(struct orinoco_private *priv)
 		return err;
 
 	msleep(100);
+
+	/* Download firmware if necessary */
+	if (download_firmware) {
+		err = orinoco_cs_dl_firmware(&priv->hw, link);
+		if (err)
+			return err;
+	}
 	clear_bit(0, &card->hard_reset_in_progress);
 
 	return 0;
@@ -316,6 +438,12 @@ orinoco_cs_config(struct pcmcia_device *link)
 	SET_MODULE_OWNER(dev);
 	card->node.major = card->node.minor = 0;
 
+	/* Download firmware if necessary */
+	if (download_firmware) {
+		if (orinoco_cs_dl_firmware(&priv->hw, link) != 0)
+			goto failed;
+	}
+
 	SET_NETDEV_DEV(dev, &handle_to_dev(link));
 	/* Tell the stack we exist */
 	if (register_netdev(dev) != 0) {
-
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]
  Powered by Linux