aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/orinoco/hermes_dld.c
diff options
context:
space:
mode:
authorDavid Kilroy <kilroyd@googlemail.com>2010-05-01 09:05:43 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-05-03 14:53:09 -0400
commit07cefe7ac983374ee4c369f1d4aee3093bf3b44f (patch)
treec4db80ac5a3f28bda1a5c93fb9b88b7db728898e /drivers/net/wireless/orinoco/hermes_dld.c
parentfc97431a50962e66c052ec6909d4b2582efd3554 (diff)
orinoco_usb: implement fw download
This involves some refactorring of the common fw download code to substitute ezusb versions of various functions. Note that WPA-enabled firmwares (9.xx series) will not work fully with orinoco_usb yet. Signed-off-by: David Kilroy <kilroyd@googlemail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/orinoco/hermes_dld.c')
-rw-r--r--drivers/net/wireless/orinoco/hermes_dld.c243
1 files changed, 9 insertions, 234 deletions
diff --git a/drivers/net/wireless/orinoco/hermes_dld.c b/drivers/net/wireless/orinoco/hermes_dld.c
index 8f22e2026a82..6da85e75fce0 100644
--- a/drivers/net/wireless/orinoco/hermes_dld.c
+++ b/drivers/net/wireless/orinoco/hermes_dld.c
@@ -46,37 +46,11 @@
46 46
47#define PFX "hermes_dld: " 47#define PFX "hermes_dld: "
48 48
49/*
50 * AUX port access. To unlock the AUX port write the access keys to the
51 * PARAM0-2 registers, then write HERMES_AUX_ENABLE to the HERMES_CONTROL
52 * register. Then read it and make sure it's HERMES_AUX_ENABLED.
53 */
54#define HERMES_AUX_ENABLE 0x8000 /* Enable auxiliary port access */
55#define HERMES_AUX_DISABLE 0x4000 /* Disable to auxiliary port access */
56#define HERMES_AUX_ENABLED 0xC000 /* Auxiliary port is open */
57#define HERMES_AUX_DISABLED 0x0000 /* Auxiliary port is closed */
58
59#define HERMES_AUX_PW0 0xFE01
60#define HERMES_AUX_PW1 0xDC23
61#define HERMES_AUX_PW2 0xBA45
62
63/* HERMES_CMD_DOWNLD */
64#define HERMES_PROGRAM_DISABLE (0x0000 | HERMES_CMD_DOWNLD)
65#define HERMES_PROGRAM_ENABLE_VOLATILE (0x0100 | HERMES_CMD_DOWNLD)
66#define HERMES_PROGRAM_ENABLE_NON_VOLATILE (0x0200 | HERMES_CMD_DOWNLD)
67#define HERMES_PROGRAM_NON_VOLATILE (0x0300 | HERMES_CMD_DOWNLD)
68
69/* End markers used in dblocks */ 49/* End markers used in dblocks */
70#define PDI_END 0x00000000 /* End of PDA */ 50#define PDI_END 0x00000000 /* End of PDA */
71#define BLOCK_END 0xFFFFFFFF /* Last image block */ 51#define BLOCK_END 0xFFFFFFFF /* Last image block */
72#define TEXT_END 0x1A /* End of text header */ 52#define TEXT_END 0x1A /* End of text header */
73 53
74/* Limit the amout we try to download in a single shot.
75 * Size is in bytes.
76 */
77#define MAX_DL_SIZE 1024
78#define LIMIT_PROGRAM_SIZE 0
79
80/* 54/*
81 * The following structures have little-endian fields denoted by 55 * The following structures have little-endian fields denoted by
82 * the leading underscore. Don't access them directly - use inline 56 * the leading underscore. Don't access them directly - use inline
@@ -165,41 +139,6 @@ pdi_len(const struct pdi *pdi)
165 return 2 * (le16_to_cpu(pdi->len) - 1); 139 return 2 * (le16_to_cpu(pdi->len) - 1);
166} 140}
167 141
168/*** Hermes AUX control ***/
169
170static inline void
171hermes_aux_setaddr(hermes_t *hw, u32 addr)
172{
173 hermes_write_reg(hw, HERMES_AUXPAGE, (u16) (addr >> 7));
174 hermes_write_reg(hw, HERMES_AUXOFFSET, (u16) (addr & 0x7F));
175}
176
177static inline int
178hermes_aux_control(hermes_t *hw, int enabled)
179{
180 int desired_state = enabled ? HERMES_AUX_ENABLED : HERMES_AUX_DISABLED;
181 int action = enabled ? HERMES_AUX_ENABLE : HERMES_AUX_DISABLE;
182 int i;
183
184 /* Already open? */
185 if (hermes_read_reg(hw, HERMES_CONTROL) == desired_state)
186 return 0;
187
188 hermes_write_reg(hw, HERMES_PARAM0, HERMES_AUX_PW0);
189 hermes_write_reg(hw, HERMES_PARAM1, HERMES_AUX_PW1);
190 hermes_write_reg(hw, HERMES_PARAM2, HERMES_AUX_PW2);
191 hermes_write_reg(hw, HERMES_CONTROL, action);
192
193 for (i = 0; i < 20; i++) {
194 udelay(10);
195 if (hermes_read_reg(hw, HERMES_CONTROL) ==
196 desired_state)
197 return 0;
198 }
199
200 return -EBUSY;
201}
202
203/*** Plug Data Functions ***/ 142/*** Plug Data Functions ***/
204 143
205/* 144/*
@@ -271,62 +210,7 @@ hermes_plug_pdi(hermes_t *hw, const struct pdr *first_pdr,
271 return -EINVAL; 210 return -EINVAL;
272 211
273 /* do the actual plugging */ 212 /* do the actual plugging */
274 hermes_aux_setaddr(hw, pdr_addr(pdr)); 213 hw->ops->program(hw, pdi->data, pdr_addr(pdr), pdi_len(pdi));
275 hermes_write_bytes(hw, HERMES_AUXDATA, pdi->data, pdi_len(pdi));
276
277 return 0;
278}
279
280/* Read PDA from the adapter */
281int hermes_read_pda(hermes_t *hw,
282 __le16 *pda,
283 u32 pda_addr,
284 u16 pda_len,
285 int use_eeprom) /* can we get this into hw? */
286{
287 int ret;
288 u16 pda_size;
289 u16 data_len = pda_len;
290 __le16 *data = pda;
291
292 if (use_eeprom) {
293 /* PDA of spectrum symbol is in eeprom */
294
295 /* Issue command to read EEPROM */
296 ret = hw->ops->cmd_wait(hw, HERMES_CMD_READMIF, 0, NULL);
297 if (ret)
298 return ret;
299 } else {
300 /* wl_lkm does not include PDA size in the PDA area.
301 * We will pad the information into pda, so other routines
302 * don't have to be modified */
303 pda[0] = cpu_to_le16(pda_len - 2);
304 /* Includes CFG_PROD_DATA but not itself */
305 pda[1] = cpu_to_le16(0x0800); /* CFG_PROD_DATA */
306 data_len = pda_len - 4;
307 data = pda + 2;
308 }
309
310 /* Open auxiliary port */
311 ret = hermes_aux_control(hw, 1);
312 pr_debug(PFX "AUX enable returned %d\n", ret);
313 if (ret)
314 return ret;
315
316 /* read PDA from EEPROM */
317 hermes_aux_setaddr(hw, pda_addr);
318 hermes_read_words(hw, HERMES_AUXDATA, data, data_len / 2);
319
320 /* Close aux port */
321 ret = hermes_aux_control(hw, 0);
322 pr_debug(PFX "AUX disable returned %d\n", ret);
323
324 /* Check PDA length */
325 pda_size = le16_to_cpu(pda[0]);
326 pr_debug(PFX "Actual PDA length %d, Max allowed %d\n",
327 pda_size, pda_len);
328 if (pda_size > pda_len)
329 return -EINVAL;
330 214
331 return 0; 215 return 0;
332} 216}
@@ -389,101 +273,13 @@ hermes_blocks_length(const char *first_block, const void *end)
389 273
390/*** Hermes programming ***/ 274/*** Hermes programming ***/
391 275
392/* About to start programming data (Hermes I)
393 * offset is the entry point
394 *
395 * Spectrum_cs' Symbol fw does not require this
396 * wl_lkm Agere fw does
397 * Don't know about intersil
398 */
399int hermesi_program_init(hermes_t *hw, u32 offset)
400{
401 int err;
402
403 /* Disable interrupts?*/
404 /*hw->inten = 0x0;*/
405 /*hermes_write_regn(hw, INTEN, 0);*/
406 /*hermes_set_irqmask(hw, 0);*/
407
408 /* Acknowledge any outstanding command */
409 hermes_write_regn(hw, EVACK, 0xFFFF);
410
411 /* Using init_cmd_wait rather than cmd_wait */
412 err = hw->ops->init_cmd_wait(hw,
413 0x0100 | HERMES_CMD_INIT,
414 0, 0, 0, NULL);
415 if (err)
416 return err;
417
418 err = hw->ops->init_cmd_wait(hw,
419 0x0000 | HERMES_CMD_INIT,
420 0, 0, 0, NULL);
421 if (err)
422 return err;
423
424 err = hermes_aux_control(hw, 1);
425 pr_debug(PFX "AUX enable returned %d\n", err);
426
427 if (err)
428 return err;
429
430 pr_debug(PFX "Enabling volatile, EP 0x%08x\n", offset);
431 err = hw->ops->init_cmd_wait(hw,
432 HERMES_PROGRAM_ENABLE_VOLATILE,
433 offset & 0xFFFFu,
434 offset >> 16,
435 0,
436 NULL);
437 pr_debug(PFX "PROGRAM_ENABLE returned %d\n", err);
438
439 return err;
440}
441
442/* Done programming data (Hermes I)
443 *
444 * Spectrum_cs' Symbol fw does not require this
445 * wl_lkm Agere fw does
446 * Don't know about intersil
447 */
448int hermesi_program_end(hermes_t *hw)
449{
450 struct hermes_response resp;
451 int rc = 0;
452 int err;
453
454 rc = hw->ops->cmd_wait(hw, HERMES_PROGRAM_DISABLE, 0, &resp);
455
456 pr_debug(PFX "PROGRAM_DISABLE returned %d, "
457 "r0 0x%04x, r1 0x%04x, r2 0x%04x\n",
458 rc, resp.resp0, resp.resp1, resp.resp2);
459
460 if ((rc == 0) &&
461 ((resp.status & HERMES_STATUS_CMDCODE) != HERMES_CMD_DOWNLD))
462 rc = -EIO;
463
464 err = hermes_aux_control(hw, 0);
465 pr_debug(PFX "AUX disable returned %d\n", err);
466
467 /* Acknowledge any outstanding command */
468 hermes_write_regn(hw, EVACK, 0xFFFF);
469
470 /* Reinitialise, ignoring return */
471 (void) hw->ops->init_cmd_wait(hw, 0x0000 | HERMES_CMD_INIT,
472 0, 0, 0, NULL);
473
474 return rc ? rc : err;
475}
476
477/* Program the data blocks */ 276/* Program the data blocks */
478int hermes_program(hermes_t *hw, const char *first_block, const void *end) 277int hermes_program(hermes_t *hw, const char *first_block, const void *end)
479{ 278{
480 const struct dblock *blk; 279 const struct dblock *blk;
481 u32 blkaddr; 280 u32 blkaddr;
482 u32 blklen; 281 u32 blklen;
483#if LIMIT_PROGRAM_SIZE 282 int err = 0;
484 u32 addr;
485 u32 len;
486#endif
487 283
488 blk = (const struct dblock *) first_block; 284 blk = (const struct dblock *) first_block;
489 285
@@ -498,30 +294,10 @@ int hermes_program(hermes_t *hw, const char *first_block, const void *end)
498 pr_debug(PFX "Programming block of length %d " 294 pr_debug(PFX "Programming block of length %d "
499 "to address 0x%08x\n", blklen, blkaddr); 295 "to address 0x%08x\n", blklen, blkaddr);
500 296
501#if !LIMIT_PROGRAM_SIZE 297 err = hw->ops->program(hw, blk->data, blkaddr, blklen);
502 /* wl_lkm driver splits this into writes of 2000 bytes */ 298 if (err)
503 hermes_aux_setaddr(hw, blkaddr); 299 break;
504 hermes_write_bytes(hw, HERMES_AUXDATA, blk->data, 300
505 blklen);
506#else
507 len = (blklen < MAX_DL_SIZE) ? blklen : MAX_DL_SIZE;
508 addr = blkaddr;
509
510 while (addr < (blkaddr + blklen)) {
511 pr_debug(PFX "Programming subblock of length %d "
512 "to address 0x%08x. Data @ %p\n",
513 len, addr, &blk->data[addr - blkaddr]);
514
515 hermes_aux_setaddr(hw, addr);
516 hermes_write_bytes(hw, HERMES_AUXDATA,
517 &blk->data[addr - blkaddr],
518 len);
519
520 addr += len;
521 len = ((blkaddr + blklen - addr) < MAX_DL_SIZE) ?
522 (blkaddr + blklen - addr) : MAX_DL_SIZE;
523 }
524#endif
525 blk = (const struct dblock *) &blk->data[blklen]; 301 blk = (const struct dblock *) &blk->data[blklen];
526 302
527 if ((void *) blk > (end - sizeof(*blk))) 303 if ((void *) blk > (end - sizeof(*blk)))
@@ -530,7 +306,7 @@ int hermes_program(hermes_t *hw, const char *first_block, const void *end)
530 blkaddr = dblock_addr(blk); 306 blkaddr = dblock_addr(blk);
531 blklen = dblock_len(blk); 307 blklen = dblock_len(blk);
532 } 308 }
533 return 0; 309 return err;
534} 310}
535 311
536/*** Default plugging data for Hermes I ***/ 312/*** Default plugging data for Hermes I ***/
@@ -690,9 +466,8 @@ int hermes_apply_pda_with_defaults(hermes_t *hw,
690 if ((pdi_len(pdi) == pdr_len(pdr)) && 466 if ((pdi_len(pdi) == pdr_len(pdr)) &&
691 ((void *) pdi->data + pdi_len(pdi) < pda_end)) { 467 ((void *) pdi->data + pdi_len(pdi) < pda_end)) {
692 /* do the actual plugging */ 468 /* do the actual plugging */
693 hermes_aux_setaddr(hw, pdr_addr(pdr)); 469 hw->ops->program(hw, pdi->data, pdr_addr(pdr),
694 hermes_write_bytes(hw, HERMES_AUXDATA, 470 pdi_len(pdi));
695 pdi->data, pdi_len(pdi));
696 } 471 }
697 } 472 }
698 473