From: Dave <kilroyd@googlemail.com>
To: orinoco-devel@lists.sourceforge.net,
orinoco-users@lists.sourceforge.net,
linux-wireless@vger.kernel.org, proski@gnu.org,
hermes@gibson.dropbear.id.au
Subject: [PATCH 05/05] orinoco: Agere/Lucent firmware download
Date: Wed, 12 Sep 2007 22:10:02 +0100 [thread overview]
Message-ID: <46E855AA.5090702@gmail.com> (raw)
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@gmail.com>
---
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) {
reply other threads:[~2007-09-12 21:05 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=46E855AA.5090702@gmail.com \
--to=kilroyd@googlemail.com \
--cc=hermes@gibson.dropbear.id.au \
--cc=linux-wireless@vger.kernel.org \
--cc=orinoco-devel@lists.sourceforge.net \
--cc=orinoco-users@lists.sourceforge.net \
--cc=proski@gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.