linux/drivers/net/wireless/intersil/orinoco/hermes.c
<<
>>
Prefs
   1/* hermes.c
   2 *
   3 * Driver core for the "Hermes" wireless MAC controller, as used in
   4 * the Lucent Orinoco and Cabletron RoamAbout cards. It should also
   5 * work on the hfa3841 and hfa3842 MAC controller chips used in the
   6 * Prism II chipsets.
   7 *
   8 * This is not a complete driver, just low-level access routines for
   9 * the MAC controller itself.
  10 *
  11 * Based on the prism2 driver from Absolute Value Systems' linux-wlan
  12 * project, the Linux wvlan_cs driver, Lucent's HCF-Light
  13 * (wvlan_hcf.c) library, and the NetBSD wireless driver (in no
  14 * particular order).
  15 *
  16 * Copyright (C) 2000, David Gibson, Linuxcare Australia.
  17 * (C) Copyright David Gibson, IBM Corp. 2001-2003.
  18 *
  19 * The contents of this file are subject to the Mozilla Public License
  20 * Version 1.1 (the "License"); you may not use this file except in
  21 * compliance with the License. You may obtain a copy of the License
  22 * at http://www.mozilla.org/MPL/
  23 *
  24 * Software distributed under the License is distributed on an "AS IS"
  25 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  26 * the License for the specific language governing rights and
  27 * limitations under the License.
  28 *
  29 * Alternatively, the contents of this file may be used under the
  30 * terms of the GNU General Public License version 2 (the "GPL"), in
  31 * which case the provisions of the GPL are applicable instead of the
  32 * above.  If you wish to allow the use of your version of this file
  33 * only under the terms of the GPL and not to allow others to use your
  34 * version of this file under the MPL, indicate your decision by
  35 * deleting the provisions above and replace them with the notice and
  36 * other provisions required by the GPL.  If you do not delete the
  37 * provisions above, a recipient may use your version of this file
  38 * under either the MPL or the GPL.
  39 */
  40
  41#include <linux/module.h>
  42#include <linux/kernel.h>
  43#include <linux/delay.h>
  44
  45#include "hermes.h"
  46
  47/* These are maximum timeouts. Most often, card wil react much faster */
  48#define CMD_BUSY_TIMEOUT (100) /* In iterations of ~1us */
  49#define CMD_INIT_TIMEOUT (50000) /* in iterations of ~10us */
  50#define CMD_COMPL_TIMEOUT (20000) /* in iterations of ~10us */
  51#define ALLOC_COMPL_TIMEOUT (1000) /* in iterations of ~10us */
  52
  53/*
  54 * AUX port access.  To unlock the AUX port write the access keys to the
  55 * PARAM0-2 registers, then write HERMES_AUX_ENABLE to the HERMES_CONTROL
  56 * register.  Then read it and make sure it's HERMES_AUX_ENABLED.
  57 */
  58#define HERMES_AUX_ENABLE       0x8000  /* Enable auxiliary port access */
  59#define HERMES_AUX_DISABLE      0x4000  /* Disable to auxiliary port access */
  60#define HERMES_AUX_ENABLED      0xC000  /* Auxiliary port is open */
  61#define HERMES_AUX_DISABLED     0x0000  /* Auxiliary port is closed */
  62
  63#define HERMES_AUX_PW0  0xFE01
  64#define HERMES_AUX_PW1  0xDC23
  65#define HERMES_AUX_PW2  0xBA45
  66
  67/* HERMES_CMD_DOWNLD */
  68#define HERMES_PROGRAM_DISABLE             (0x0000 | HERMES_CMD_DOWNLD)
  69#define HERMES_PROGRAM_ENABLE_VOLATILE     (0x0100 | HERMES_CMD_DOWNLD)
  70#define HERMES_PROGRAM_ENABLE_NON_VOLATILE (0x0200 | HERMES_CMD_DOWNLD)
  71#define HERMES_PROGRAM_NON_VOLATILE        (0x0300 | HERMES_CMD_DOWNLD)
  72
  73/*
  74 * Debugging helpers
  75 */
  76
  77#define DMSG(stuff...) do {printk(KERN_DEBUG "hermes @ %p: " , hw->iobase); \
  78                        printk(stuff); } while (0)
  79
  80#undef HERMES_DEBUG
  81#ifdef HERMES_DEBUG
  82#include <stdarg.h>
  83
  84#define DEBUG(lvl, stuff...) if ((lvl) <= HERMES_DEBUG) DMSG(stuff)
  85
  86#else /* ! HERMES_DEBUG */
  87
  88#define DEBUG(lvl, stuff...) do { } while (0)
  89
  90#endif /* ! HERMES_DEBUG */
  91
  92static const struct hermes_ops hermes_ops_local;
  93
  94/*
  95 * Internal functions
  96 */
  97
  98/* Issue a command to the chip. Waiting for it to complete is the caller's
  99   problem.
 100
 101   Returns -EBUSY if the command register is busy, 0 on success.
 102
 103   Callable from any context.
 104*/
 105static int hermes_issue_cmd(struct hermes *hw, u16 cmd, u16 param0,
 106                            u16 param1, u16 param2)
 107{
 108        int k = CMD_BUSY_TIMEOUT;
 109        u16 reg;
 110
 111        /* First wait for the command register to unbusy */
 112        reg = hermes_read_regn(hw, CMD);
 113        while ((reg & HERMES_CMD_BUSY) && k) {
 114                k--;
 115                udelay(1);
 116                reg = hermes_read_regn(hw, CMD);
 117        }
 118        if (reg & HERMES_CMD_BUSY)
 119                return -EBUSY;
 120
 121        hermes_write_regn(hw, PARAM2, param2);
 122        hermes_write_regn(hw, PARAM1, param1);
 123        hermes_write_regn(hw, PARAM0, param0);
 124        hermes_write_regn(hw, CMD, cmd);
 125
 126        return 0;
 127}
 128
 129/*
 130 * Function definitions
 131 */
 132
 133/* For doing cmds that wipe the magic constant in SWSUPPORT0 */
 134static int hermes_doicmd_wait(struct hermes *hw, u16 cmd,
 135                              u16 parm0, u16 parm1, u16 parm2,
 136                              struct hermes_response *resp)
 137{
 138        int err = 0;
 139        int k;
 140        u16 status, reg;
 141
 142        err = hermes_issue_cmd(hw, cmd, parm0, parm1, parm2);
 143        if (err)
 144                return err;
 145
 146        reg = hermes_read_regn(hw, EVSTAT);
 147        k = CMD_INIT_TIMEOUT;
 148        while ((!(reg & HERMES_EV_CMD)) && k) {
 149                k--;
 150                udelay(10);
 151                reg = hermes_read_regn(hw, EVSTAT);
 152        }
 153
 154        hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC);
 155
 156        if (!hermes_present(hw)) {
 157                DEBUG(0, "hermes @ 0x%x: Card removed during reset.\n",
 158                       hw->iobase);
 159                err = -ENODEV;
 160                goto out;
 161        }
 162
 163        if (!(reg & HERMES_EV_CMD)) {
 164                printk(KERN_ERR "hermes @ %p: "
 165                       "Timeout waiting for card to reset (reg=0x%04x)!\n",
 166                       hw->iobase, reg);
 167                err = -ETIMEDOUT;
 168                goto out;
 169        }
 170
 171        status = hermes_read_regn(hw, STATUS);
 172        if (resp) {
 173                resp->status = status;
 174                resp->resp0 = hermes_read_regn(hw, RESP0);
 175                resp->resp1 = hermes_read_regn(hw, RESP1);
 176                resp->resp2 = hermes_read_regn(hw, RESP2);
 177        }
 178
 179        hermes_write_regn(hw, EVACK, HERMES_EV_CMD);
 180
 181        if (status & HERMES_STATUS_RESULT)
 182                err = -EIO;
 183out:
 184        return err;
 185}
 186
 187void hermes_struct_init(struct hermes *hw, void __iomem *address,
 188                        int reg_spacing)
 189{
 190        hw->iobase = address;
 191        hw->reg_spacing = reg_spacing;
 192        hw->inten = 0x0;
 193        hw->eeprom_pda = false;
 194        hw->ops = &hermes_ops_local;
 195}
 196EXPORT_SYMBOL(hermes_struct_init);
 197
 198static int hermes_init(struct hermes *hw)
 199{
 200        u16 reg;
 201        int err = 0;
 202        int k;
 203
 204        /* We don't want to be interrupted while resetting the chipset */
 205        hw->inten = 0x0;
 206        hermes_write_regn(hw, INTEN, 0);
 207        hermes_write_regn(hw, EVACK, 0xffff);
 208
 209        /* Normally it's a "can't happen" for the command register to
 210           be busy when we go to issue a command because we are
 211           serializing all commands.  However we want to have some
 212           chance of resetting the card even if it gets into a stupid
 213           state, so we actually wait to see if the command register
 214           will unbusy itself here. */
 215        k = CMD_BUSY_TIMEOUT;
 216        reg = hermes_read_regn(hw, CMD);
 217        while (k && (reg & HERMES_CMD_BUSY)) {
 218                if (reg == 0xffff) /* Special case - the card has probably been
 219                                      removed, so don't wait for the timeout */
 220                        return -ENODEV;
 221
 222                k--;
 223                udelay(1);
 224                reg = hermes_read_regn(hw, CMD);
 225        }
 226
 227        /* No need to explicitly handle the timeout - if we've timed
 228           out hermes_issue_cmd() will probably return -EBUSY below */
 229
 230        /* According to the documentation, EVSTAT may contain
 231           obsolete event occurrence information.  We have to acknowledge
 232           it by writing EVACK. */
 233        reg = hermes_read_regn(hw, EVSTAT);
 234        hermes_write_regn(hw, EVACK, reg);
 235
 236        /* We don't use hermes_docmd_wait here, because the reset wipes
 237           the magic constant in SWSUPPORT0 away, and it gets confused */
 238        err = hermes_doicmd_wait(hw, HERMES_CMD_INIT, 0, 0, 0, NULL);
 239
 240        return err;
 241}
 242
 243/* Issue a command to the chip, and (busy!) wait for it to
 244 * complete.
 245 *
 246 * Returns:
 247 *     < 0 on internal error
 248 *       0 on success
 249 *     > 0 on error returned by the firmware
 250 *
 251 * Callable from any context, but locking is your problem. */
 252static int hermes_docmd_wait(struct hermes *hw, u16 cmd, u16 parm0,
 253                             struct hermes_response *resp)
 254{
 255        int err;
 256        int k;
 257        u16 reg;
 258        u16 status;
 259
 260        err = hermes_issue_cmd(hw, cmd, parm0, 0, 0);
 261        if (err) {
 262                if (!hermes_present(hw)) {
 263                        if (net_ratelimit())
 264                                printk(KERN_WARNING "hermes @ %p: "
 265                                       "Card removed while issuing command "
 266                                       "0x%04x.\n", hw->iobase, cmd);
 267                        err = -ENODEV;
 268                } else
 269                        if (net_ratelimit())
 270                                printk(KERN_ERR "hermes @ %p: "
 271                                       "Error %d issuing command 0x%04x.\n",
 272                                       hw->iobase, err, cmd);
 273                goto out;
 274        }
 275
 276        reg = hermes_read_regn(hw, EVSTAT);
 277        k = CMD_COMPL_TIMEOUT;
 278        while ((!(reg & HERMES_EV_CMD)) && k) {
 279                k--;
 280                udelay(10);
 281                reg = hermes_read_regn(hw, EVSTAT);
 282        }
 283
 284        if (!hermes_present(hw)) {
 285                printk(KERN_WARNING "hermes @ %p: Card removed "
 286                       "while waiting for command 0x%04x completion.\n",
 287                       hw->iobase, cmd);
 288                err = -ENODEV;
 289                goto out;
 290        }
 291
 292        if (!(reg & HERMES_EV_CMD)) {
 293                printk(KERN_ERR "hermes @ %p: Timeout waiting for "
 294                       "command 0x%04x completion.\n", hw->iobase, cmd);
 295                err = -ETIMEDOUT;
 296                goto out;
 297        }
 298
 299        status = hermes_read_regn(hw, STATUS);
 300        if (resp) {
 301                resp->status = status;
 302                resp->resp0 = hermes_read_regn(hw, RESP0);
 303                resp->resp1 = hermes_read_regn(hw, RESP1);
 304                resp->resp2 = hermes_read_regn(hw, RESP2);
 305        }
 306
 307        hermes_write_regn(hw, EVACK, HERMES_EV_CMD);
 308
 309        if (status & HERMES_STATUS_RESULT)
 310                err = -EIO;
 311
 312 out:
 313        return err;
 314}
 315
 316static int hermes_allocate(struct hermes *hw, u16 size, u16 *fid)
 317{
 318        int err = 0;
 319        int k;
 320        u16 reg;
 321
 322        if ((size < HERMES_ALLOC_LEN_MIN) || (size > HERMES_ALLOC_LEN_MAX))
 323                return -EINVAL;
 324
 325        err = hermes_docmd_wait(hw, HERMES_CMD_ALLOC, size, NULL);
 326        if (err)
 327                return err;
 328
 329        reg = hermes_read_regn(hw, EVSTAT);
 330        k = ALLOC_COMPL_TIMEOUT;
 331        while ((!(reg & HERMES_EV_ALLOC)) && k) {
 332                k--;
 333                udelay(10);
 334                reg = hermes_read_regn(hw, EVSTAT);
 335        }
 336
 337        if (!hermes_present(hw)) {
 338                printk(KERN_WARNING "hermes @ %p: "
 339                       "Card removed waiting for frame allocation.\n",
 340                       hw->iobase);
 341                return -ENODEV;
 342        }
 343
 344        if (!(reg & HERMES_EV_ALLOC)) {
 345                printk(KERN_ERR "hermes @ %p: "
 346                       "Timeout waiting for frame allocation\n",
 347                       hw->iobase);
 348                return -ETIMEDOUT;
 349        }
 350
 351        *fid = hermes_read_regn(hw, ALLOCFID);
 352        hermes_write_regn(hw, EVACK, HERMES_EV_ALLOC);
 353
 354        return 0;
 355}
 356
 357/* Set up a BAP to read a particular chunk of data from card's internal buffer.
 358 *
 359 * Returns:
 360 *     < 0 on internal failure (errno)
 361 *       0 on success
 362 *     > 0 on error
 363 * from firmware
 364 *
 365 * Callable from any context */
 366static int hermes_bap_seek(struct hermes *hw, int bap, u16 id, u16 offset)
 367{
 368        int sreg = bap ? HERMES_SELECT1 : HERMES_SELECT0;
 369        int oreg = bap ? HERMES_OFFSET1 : HERMES_OFFSET0;
 370        int k;
 371        u16 reg;
 372
 373        /* Paranoia.. */
 374        if ((offset > HERMES_BAP_OFFSET_MAX) || (offset % 2))
 375                return -EINVAL;
 376
 377        k = HERMES_BAP_BUSY_TIMEOUT;
 378        reg = hermes_read_reg(hw, oreg);
 379        while ((reg & HERMES_OFFSET_BUSY) && k) {
 380                k--;
 381                udelay(1);
 382                reg = hermes_read_reg(hw, oreg);
 383        }
 384
 385        if (reg & HERMES_OFFSET_BUSY)
 386                return -ETIMEDOUT;
 387
 388        /* Now we actually set up the transfer */
 389        hermes_write_reg(hw, sreg, id);
 390        hermes_write_reg(hw, oreg, offset);
 391
 392        /* Wait for the BAP to be ready */
 393        k = HERMES_BAP_BUSY_TIMEOUT;
 394        reg = hermes_read_reg(hw, oreg);
 395        while ((reg & (HERMES_OFFSET_BUSY | HERMES_OFFSET_ERR)) && k) {
 396                k--;
 397                udelay(1);
 398                reg = hermes_read_reg(hw, oreg);
 399        }
 400
 401        if (reg != offset) {
 402                printk(KERN_ERR "hermes @ %p: BAP%d offset %s: "
 403                       "reg=0x%x id=0x%x offset=0x%x\n", hw->iobase, bap,
 404                       (reg & HERMES_OFFSET_BUSY) ? "timeout" : "error",
 405                       reg, id, offset);
 406
 407                if (reg & HERMES_OFFSET_BUSY)
 408                        return -ETIMEDOUT;
 409
 410                return -EIO;            /* error or wrong offset */
 411        }
 412
 413        return 0;
 414}
 415
 416/* Read a block of data from the chip's buffer, via the
 417 * BAP. Synchronization/serialization is the caller's problem.  len
 418 * must be even.
 419 *
 420 * Returns:
 421 *     < 0 on internal failure (errno)
 422 *       0 on success
 423 *     > 0 on error from firmware
 424 */
 425static int hermes_bap_pread(struct hermes *hw, int bap, void *buf, int len,
 426                            u16 id, u16 offset)
 427{
 428        int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
 429        int err = 0;
 430
 431        if ((len < 0) || (len % 2))
 432                return -EINVAL;
 433
 434        err = hermes_bap_seek(hw, bap, id, offset);
 435        if (err)
 436                goto out;
 437
 438        /* Actually do the transfer */
 439        hermes_read_words(hw, dreg, buf, len / 2);
 440
 441 out:
 442        return err;
 443}
 444
 445/* Write a block of data to the chip's buffer, via the
 446 * BAP. Synchronization/serialization is the caller's problem.
 447 *
 448 * Returns:
 449 *     < 0 on internal failure (errno)
 450 *       0 on success
 451 *     > 0 on error from firmware
 452 */
 453static int hermes_bap_pwrite(struct hermes *hw, int bap, const void *buf,
 454                             int len, u16 id, u16 offset)
 455{
 456        int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
 457        int err = 0;
 458
 459        if (len < 0)
 460                return -EINVAL;
 461
 462        err = hermes_bap_seek(hw, bap, id, offset);
 463        if (err)
 464                goto out;
 465
 466        /* Actually do the transfer */
 467        hermes_write_bytes(hw, dreg, buf, len);
 468
 469 out:
 470        return err;
 471}
 472
 473/* Read a Length-Type-Value record from the card.
 474 *
 475 * If length is NULL, we ignore the length read from the card, and
 476 * read the entire buffer regardless. This is useful because some of
 477 * the configuration records appear to have incorrect lengths in
 478 * practice.
 479 *
 480 * Callable from user or bh context.  */
 481static int hermes_read_ltv(struct hermes *hw, int bap, u16 rid,
 482                           unsigned bufsize, u16 *length, void *buf)
 483{
 484        int err = 0;
 485        int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
 486        u16 rlength, rtype;
 487        unsigned nwords;
 488
 489        if (bufsize % 2)
 490                return -EINVAL;
 491
 492        err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, NULL);
 493        if (err)
 494                return err;
 495
 496        err = hermes_bap_seek(hw, bap, rid, 0);
 497        if (err)
 498                return err;
 499
 500        rlength = hermes_read_reg(hw, dreg);
 501
 502        if (!rlength)
 503                return -ENODATA;
 504
 505        rtype = hermes_read_reg(hw, dreg);
 506
 507        if (length)
 508                *length = rlength;
 509
 510        if (rtype != rid)
 511                printk(KERN_WARNING "hermes @ %p: %s(): "
 512                       "rid (0x%04x) does not match type (0x%04x)\n",
 513                       hw->iobase, __func__, rid, rtype);
 514        if (HERMES_RECLEN_TO_BYTES(rlength) > bufsize)
 515                printk(KERN_WARNING "hermes @ %p: "
 516                       "Truncating LTV record from %d to %d bytes. "
 517                       "(rid=0x%04x, len=0x%04x)\n", hw->iobase,
 518                       HERMES_RECLEN_TO_BYTES(rlength), bufsize, rid, rlength);
 519
 520        nwords = min((unsigned)rlength - 1, bufsize / 2);
 521        hermes_read_words(hw, dreg, buf, nwords);
 522
 523        return 0;
 524}
 525
 526static int hermes_write_ltv(struct hermes *hw, int bap, u16 rid,
 527                            u16 length, const void *value)
 528{
 529        int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
 530        int err = 0;
 531        unsigned count;
 532
 533        if (length == 0)
 534                return -EINVAL;
 535
 536        err = hermes_bap_seek(hw, bap, rid, 0);
 537        if (err)
 538                return err;
 539
 540        hermes_write_reg(hw, dreg, length);
 541        hermes_write_reg(hw, dreg, rid);
 542
 543        count = length - 1;
 544
 545        hermes_write_bytes(hw, dreg, value, count << 1);
 546
 547        err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE,
 548                                rid, NULL);
 549
 550        return err;
 551}
 552
 553/*** Hermes AUX control ***/
 554
 555static inline void
 556hermes_aux_setaddr(struct hermes *hw, u32 addr)
 557{
 558        hermes_write_reg(hw, HERMES_AUXPAGE, (u16) (addr >> 7));
 559        hermes_write_reg(hw, HERMES_AUXOFFSET, (u16) (addr & 0x7F));
 560}
 561
 562static inline int
 563hermes_aux_control(struct hermes *hw, int enabled)
 564{
 565        int desired_state = enabled ? HERMES_AUX_ENABLED : HERMES_AUX_DISABLED;
 566        int action = enabled ? HERMES_AUX_ENABLE : HERMES_AUX_DISABLE;
 567        int i;
 568
 569        /* Already open? */
 570        if (hermes_read_reg(hw, HERMES_CONTROL) == desired_state)
 571                return 0;
 572
 573        hermes_write_reg(hw, HERMES_PARAM0, HERMES_AUX_PW0);
 574        hermes_write_reg(hw, HERMES_PARAM1, HERMES_AUX_PW1);
 575        hermes_write_reg(hw, HERMES_PARAM2, HERMES_AUX_PW2);
 576        hermes_write_reg(hw, HERMES_CONTROL, action);
 577
 578        for (i = 0; i < 20; i++) {
 579                udelay(10);
 580                if (hermes_read_reg(hw, HERMES_CONTROL) ==
 581                    desired_state)
 582                        return 0;
 583        }
 584
 585        return -EBUSY;
 586}
 587
 588/*** Hermes programming ***/
 589
 590/* About to start programming data (Hermes I)
 591 * offset is the entry point
 592 *
 593 * Spectrum_cs' Symbol fw does not require this
 594 * wl_lkm Agere fw does
 595 * Don't know about intersil
 596 */
 597static int hermesi_program_init(struct hermes *hw, u32 offset)
 598{
 599        int err;
 600
 601        /* Disable interrupts?*/
 602        /*hw->inten = 0x0;*/
 603        /*hermes_write_regn(hw, INTEN, 0);*/
 604        /*hermes_set_irqmask(hw, 0);*/
 605
 606        /* Acknowledge any outstanding command */
 607        hermes_write_regn(hw, EVACK, 0xFFFF);
 608
 609        /* Using init_cmd_wait rather than cmd_wait */
 610        err = hw->ops->init_cmd_wait(hw,
 611                                     0x0100 | HERMES_CMD_INIT,
 612                                     0, 0, 0, NULL);
 613        if (err)
 614                return err;
 615
 616        err = hw->ops->init_cmd_wait(hw,
 617                                     0x0000 | HERMES_CMD_INIT,
 618                                     0, 0, 0, NULL);
 619        if (err)
 620                return err;
 621
 622        err = hermes_aux_control(hw, 1);
 623        pr_debug("AUX enable returned %d\n", err);
 624
 625        if (err)
 626                return err;
 627
 628        pr_debug("Enabling volatile, EP 0x%08x\n", offset);
 629        err = hw->ops->init_cmd_wait(hw,
 630                                     HERMES_PROGRAM_ENABLE_VOLATILE,
 631                                     offset & 0xFFFFu,
 632                                     offset >> 16,
 633                                     0,
 634                                     NULL);
 635        pr_debug("PROGRAM_ENABLE returned %d\n", err);
 636
 637        return err;
 638}
 639
 640/* Done programming data (Hermes I)
 641 *
 642 * Spectrum_cs' Symbol fw does not require this
 643 * wl_lkm Agere fw does
 644 * Don't know about intersil
 645 */
 646static int hermesi_program_end(struct hermes *hw)
 647{
 648        struct hermes_response resp;
 649        int rc = 0;
 650        int err;
 651
 652        rc = hw->ops->cmd_wait(hw, HERMES_PROGRAM_DISABLE, 0, &resp);
 653
 654        pr_debug("PROGRAM_DISABLE returned %d, "
 655                 "r0 0x%04x, r1 0x%04x, r2 0x%04x\n",
 656                 rc, resp.resp0, resp.resp1, resp.resp2);
 657
 658        if ((rc == 0) &&
 659            ((resp.status & HERMES_STATUS_CMDCODE) != HERMES_CMD_DOWNLD))
 660                rc = -EIO;
 661
 662        err = hermes_aux_control(hw, 0);
 663        pr_debug("AUX disable returned %d\n", err);
 664
 665        /* Acknowledge any outstanding command */
 666        hermes_write_regn(hw, EVACK, 0xFFFF);
 667
 668        /* Reinitialise, ignoring return */
 669        (void) hw->ops->init_cmd_wait(hw, 0x0000 | HERMES_CMD_INIT,
 670                                      0, 0, 0, NULL);
 671
 672        return rc ? rc : err;
 673}
 674
 675static int hermes_program_bytes(struct hermes *hw, const char *data,
 676                                u32 addr, u32 len)
 677{
 678        /* wl lkm splits the programming into chunks of 2000 bytes.
 679         * This restriction appears to come from USB. The PCMCIA
 680         * adapters can program the whole lot in one go */
 681        hermes_aux_setaddr(hw, addr);
 682        hermes_write_bytes(hw, HERMES_AUXDATA, data, len);
 683        return 0;
 684}
 685
 686/* Read PDA from the adapter */
 687static int hermes_read_pda(struct hermes *hw, __le16 *pda, u32 pda_addr,
 688                           u16 pda_len)
 689{
 690        int ret;
 691        u16 pda_size;
 692        u16 data_len = pda_len;
 693        __le16 *data = pda;
 694
 695        if (hw->eeprom_pda) {
 696                /* PDA of spectrum symbol is in eeprom */
 697
 698                /* Issue command to read EEPROM */
 699                ret = hw->ops->cmd_wait(hw, HERMES_CMD_READMIF, 0, NULL);
 700                if (ret)
 701                        return ret;
 702        } else {
 703                /* wl_lkm does not include PDA size in the PDA area.
 704                 * We will pad the information into pda, so other routines
 705                 * don't have to be modified */
 706                pda[0] = cpu_to_le16(pda_len - 2);
 707                        /* Includes CFG_PROD_DATA but not itself */
 708                pda[1] = cpu_to_le16(0x0800); /* CFG_PROD_DATA */
 709                data_len = pda_len - 4;
 710                data = pda + 2;
 711        }
 712
 713        /* Open auxiliary port */
 714        ret = hermes_aux_control(hw, 1);
 715        pr_debug("AUX enable returned %d\n", ret);
 716        if (ret)
 717                return ret;
 718
 719        /* Read PDA */
 720        hermes_aux_setaddr(hw, pda_addr);
 721        hermes_read_words(hw, HERMES_AUXDATA, data, data_len / 2);
 722
 723        /* Close aux port */
 724        ret = hermes_aux_control(hw, 0);
 725        pr_debug("AUX disable returned %d\n", ret);
 726
 727        /* Check PDA length */
 728        pda_size = le16_to_cpu(pda[0]);
 729        pr_debug("Actual PDA length %d, Max allowed %d\n",
 730                 pda_size, pda_len);
 731        if (pda_size > pda_len)
 732                return -EINVAL;
 733
 734        return 0;
 735}
 736
 737static void hermes_lock_irqsave(spinlock_t *lock,
 738                                unsigned long *flags) __acquires(lock)
 739{
 740        spin_lock_irqsave(lock, *flags);
 741}
 742
 743static void hermes_unlock_irqrestore(spinlock_t *lock,
 744                                     unsigned long *flags) __releases(lock)
 745{
 746        spin_unlock_irqrestore(lock, *flags);
 747}
 748
 749static void hermes_lock_irq(spinlock_t *lock) __acquires(lock)
 750{
 751        spin_lock_irq(lock);
 752}
 753
 754static void hermes_unlock_irq(spinlock_t *lock) __releases(lock)
 755{
 756        spin_unlock_irq(lock);
 757}
 758
 759/* Hermes operations for local buses */
 760static const struct hermes_ops hermes_ops_local = {
 761        .init = hermes_init,
 762        .cmd_wait = hermes_docmd_wait,
 763        .init_cmd_wait = hermes_doicmd_wait,
 764        .allocate = hermes_allocate,
 765        .read_ltv = hermes_read_ltv,
 766        .write_ltv = hermes_write_ltv,
 767        .bap_pread = hermes_bap_pread,
 768        .bap_pwrite = hermes_bap_pwrite,
 769        .read_pda = hermes_read_pda,
 770        .program_init = hermesi_program_init,
 771        .program_end = hermesi_program_end,
 772        .program = hermes_program_bytes,
 773        .lock_irqsave = hermes_lock_irqsave,
 774        .unlock_irqrestore = hermes_unlock_irqrestore,
 775        .lock_irq = hermes_lock_irq,
 776        .unlock_irq = hermes_unlock_irq,
 777};
 778