Merge ../scsi-misc-2.6
[linux-2.6] / drivers / net / wireless / hermes.c
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/init.h>
44 #include <linux/delay.h>
45
46 #include "hermes.h"
47
48 MODULE_DESCRIPTION("Low-level driver helper for Lucent Hermes chipset and Prism II HFA384x wireless MAC controller");
49 MODULE_AUTHOR("Pavel Roskin <proski@gnu.org>"
50         " & David Gibson <hermes@gibson.dropbear.id.au>");
51 MODULE_LICENSE("Dual MPL/GPL");
52
53 /* These are maximum timeouts. Most often, card wil react much faster */
54 #define CMD_BUSY_TIMEOUT (100) /* In iterations of ~1us */
55 #define CMD_INIT_TIMEOUT (50000) /* in iterations of ~10us */
56 #define CMD_COMPL_TIMEOUT (20000) /* in iterations of ~10us */
57 #define ALLOC_COMPL_TIMEOUT (1000) /* in iterations of ~10us */
58
59 /*
60  * Debugging helpers
61  */
62
63 #define DMSG(stuff...) do {printk(KERN_DEBUG "hermes @ %p: " , hw->iobase); \
64                         printk(stuff);} while (0)
65
66 #undef HERMES_DEBUG
67 #ifdef HERMES_DEBUG
68 #include <stdarg.h>
69
70 #define DEBUG(lvl, stuff...) if ( (lvl) <= HERMES_DEBUG) DMSG(stuff)
71
72 #else /* ! HERMES_DEBUG */
73
74 #define DEBUG(lvl, stuff...) do { } while (0)
75
76 #endif /* ! HERMES_DEBUG */
77
78
79 /*
80  * Internal functions
81  */
82
83 /* Issue a command to the chip. Waiting for it to complete is the caller's
84    problem.
85
86    Returns -EBUSY if the command register is busy, 0 on success.
87
88    Callable from any context.
89 */
90 static int hermes_issue_cmd(hermes_t *hw, u16 cmd, u16 param0)
91 {
92         int k = CMD_BUSY_TIMEOUT;
93         u16 reg;
94
95         /* First wait for the command register to unbusy */
96         reg = hermes_read_regn(hw, CMD);
97         while ( (reg & HERMES_CMD_BUSY) && k ) {
98                 k--;
99                 udelay(1);
100                 reg = hermes_read_regn(hw, CMD);
101         }
102         if (reg & HERMES_CMD_BUSY) {
103                 return -EBUSY;
104         }
105
106         hermes_write_regn(hw, PARAM2, 0);
107         hermes_write_regn(hw, PARAM1, 0);
108         hermes_write_regn(hw, PARAM0, param0);
109         hermes_write_regn(hw, CMD, cmd);
110         
111         return 0;
112 }
113
114 /*
115  * Function definitions
116  */
117
118 void hermes_struct_init(hermes_t *hw, void __iomem *address, int reg_spacing)
119 {
120         hw->iobase = address;
121         hw->reg_spacing = reg_spacing;
122         hw->inten = 0x0;
123 }
124
125 int hermes_init(hermes_t *hw)
126 {
127         u16 status, reg;
128         int err = 0;
129         int k;
130
131         /* We don't want to be interrupted while resetting the chipset */
132         hw->inten = 0x0;
133         hermes_write_regn(hw, INTEN, 0);
134         hermes_write_regn(hw, EVACK, 0xffff);
135
136         /* Normally it's a "can't happen" for the command register to
137            be busy when we go to issue a command because we are
138            serializing all commands.  However we want to have some
139            chance of resetting the card even if it gets into a stupid
140            state, so we actually wait to see if the command register
141            will unbusy itself here. */
142         k = CMD_BUSY_TIMEOUT;
143         reg = hermes_read_regn(hw, CMD);
144         while (k && (reg & HERMES_CMD_BUSY)) {
145                 if (reg == 0xffff) /* Special case - the card has probably been removed,
146                                       so don't wait for the timeout */
147                         return -ENODEV;
148
149                 k--;
150                 udelay(1);
151                 reg = hermes_read_regn(hw, CMD);
152         }
153         
154         /* No need to explicitly handle the timeout - if we've timed
155            out hermes_issue_cmd() will probably return -EBUSY below */
156
157         /* According to the documentation, EVSTAT may contain
158            obsolete event occurrence information.  We have to acknowledge
159            it by writing EVACK. */
160         reg = hermes_read_regn(hw, EVSTAT);
161         hermes_write_regn(hw, EVACK, reg);
162
163         /* We don't use hermes_docmd_wait here, because the reset wipes
164            the magic constant in SWSUPPORT0 away, and it gets confused */
165         err = hermes_issue_cmd(hw, HERMES_CMD_INIT, 0);
166         if (err)
167                 return err;
168
169         reg = hermes_read_regn(hw, EVSTAT);
170         k = CMD_INIT_TIMEOUT;
171         while ( (! (reg & HERMES_EV_CMD)) && k) {
172                 k--;
173                 udelay(10);
174                 reg = hermes_read_regn(hw, EVSTAT);
175         }
176
177         hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC);
178
179         if (! hermes_present(hw)) {
180                 DEBUG(0, "hermes @ 0x%x: Card removed during reset.\n",
181                        hw->iobase);
182                 err = -ENODEV;
183                 goto out;
184         }
185                 
186         if (! (reg & HERMES_EV_CMD)) {
187                 printk(KERN_ERR "hermes @ %p: " 
188                        "Timeout waiting for card to reset (reg=0x%04x)!\n",
189                        hw->iobase, reg);
190                 err = -ETIMEDOUT;
191                 goto out;
192         }
193
194         status = hermes_read_regn(hw, STATUS);
195
196         hermes_write_regn(hw, EVACK, HERMES_EV_CMD);
197
198         if (status & HERMES_STATUS_RESULT)
199                 err = -EIO;
200
201  out:
202         return err;
203 }
204
205 /* Issue a command to the chip, and (busy!) wait for it to
206  * complete.
207  *
208  * Returns: < 0 on internal error, 0 on success, > 0 on error returned by the firmware
209  *
210  * Callable from any context, but locking is your problem. */
211 int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0,
212                       struct hermes_response *resp)
213 {
214         int err;
215         int k;
216         u16 reg;
217         u16 status;
218
219         err = hermes_issue_cmd(hw, cmd, parm0);
220         if (err) {
221                 if (! hermes_present(hw)) {
222                         if (net_ratelimit())
223                                 printk(KERN_WARNING "hermes @ %p: "
224                                        "Card removed while issuing command "
225                                        "0x%04x.\n", hw->iobase, cmd);
226                         err = -ENODEV;
227                 } else 
228                         if (net_ratelimit())
229                                 printk(KERN_ERR "hermes @ %p: "
230                                        "Error %d issuing command 0x%04x.\n",
231                                        hw->iobase, err, cmd);
232                 goto out;
233         }
234
235         reg = hermes_read_regn(hw, EVSTAT);
236         k = CMD_COMPL_TIMEOUT;
237         while ( (! (reg & HERMES_EV_CMD)) && k) {
238                 k--;
239                 udelay(10);
240                 reg = hermes_read_regn(hw, EVSTAT);
241         }
242
243         if (! hermes_present(hw)) {
244                 printk(KERN_WARNING "hermes @ %p: Card removed "
245                        "while waiting for command 0x%04x completion.\n",
246                        hw->iobase, cmd);
247                 err = -ENODEV;
248                 goto out;
249         }
250                 
251         if (! (reg & HERMES_EV_CMD)) {
252                 printk(KERN_ERR "hermes @ %p: Timeout waiting for "
253                        "command 0x%04x completion.\n", hw->iobase, cmd);
254                 err = -ETIMEDOUT;
255                 goto out;
256         }
257
258         status = hermes_read_regn(hw, STATUS);
259         if (resp) {
260                 resp->status = status;
261                 resp->resp0 = hermes_read_regn(hw, RESP0);
262                 resp->resp1 = hermes_read_regn(hw, RESP1);
263                 resp->resp2 = hermes_read_regn(hw, RESP2);
264         }
265
266         hermes_write_regn(hw, EVACK, HERMES_EV_CMD);
267
268         if (status & HERMES_STATUS_RESULT)
269                 err = -EIO;
270
271  out:
272         return err;
273 }
274
275 int hermes_allocate(hermes_t *hw, u16 size, u16 *fid)
276 {
277         int err = 0;
278         int k;
279         u16 reg;
280         
281         if ( (size < HERMES_ALLOC_LEN_MIN) || (size > HERMES_ALLOC_LEN_MAX) )
282                 return -EINVAL;
283
284         err = hermes_docmd_wait(hw, HERMES_CMD_ALLOC, size, NULL);
285         if (err) {
286                 return err;
287         }
288
289         reg = hermes_read_regn(hw, EVSTAT);
290         k = ALLOC_COMPL_TIMEOUT;
291         while ( (! (reg & HERMES_EV_ALLOC)) && k) {
292                 k--;
293                 udelay(10);
294                 reg = hermes_read_regn(hw, EVSTAT);
295         }
296         
297         if (! hermes_present(hw)) {
298                 printk(KERN_WARNING "hermes @ %p: "
299                        "Card removed waiting for frame allocation.\n",
300                        hw->iobase);
301                 return -ENODEV;
302         }
303                 
304         if (! (reg & HERMES_EV_ALLOC)) {
305                 printk(KERN_ERR "hermes @ %p: "
306                        "Timeout waiting for frame allocation\n",
307                        hw->iobase);
308                 return -ETIMEDOUT;
309         }
310
311         *fid = hermes_read_regn(hw, ALLOCFID);
312         hermes_write_regn(hw, EVACK, HERMES_EV_ALLOC);
313         
314         return 0;
315 }
316
317
318 /* Set up a BAP to read a particular chunk of data from card's internal buffer.
319  *
320  * Returns: < 0 on internal failure (errno), 0 on success, >0 on error
321  * from firmware
322  *
323  * Callable from any context */
324 static int hermes_bap_seek(hermes_t *hw, int bap, u16 id, u16 offset)
325 {
326         int sreg = bap ? HERMES_SELECT1 : HERMES_SELECT0;
327         int oreg = bap ? HERMES_OFFSET1 : HERMES_OFFSET0;
328         int k;
329         u16 reg;
330
331         /* Paranoia.. */
332         if ( (offset > HERMES_BAP_OFFSET_MAX) || (offset % 2) )
333                 return -EINVAL;
334
335         k = HERMES_BAP_BUSY_TIMEOUT;
336         reg = hermes_read_reg(hw, oreg);
337         while ((reg & HERMES_OFFSET_BUSY) && k) {
338                 k--;
339                 udelay(1);
340                 reg = hermes_read_reg(hw, oreg);
341         }
342
343         if (reg & HERMES_OFFSET_BUSY)
344                 return -ETIMEDOUT;
345
346         /* Now we actually set up the transfer */
347         hermes_write_reg(hw, sreg, id);
348         hermes_write_reg(hw, oreg, offset);
349
350         /* Wait for the BAP to be ready */
351         k = HERMES_BAP_BUSY_TIMEOUT;
352         reg = hermes_read_reg(hw, oreg);
353         while ( (reg & (HERMES_OFFSET_BUSY | HERMES_OFFSET_ERR)) && k) {
354                 k--;
355                 udelay(1);
356                 reg = hermes_read_reg(hw, oreg);
357         }
358
359         if (reg != offset) {
360                 printk(KERN_ERR "hermes @ %p: BAP%d offset %s: "
361                        "reg=0x%x id=0x%x offset=0x%x\n", hw->iobase, bap,
362                        (reg & HERMES_OFFSET_BUSY) ? "timeout" : "error",
363                        reg, id, offset);
364
365                 if (reg & HERMES_OFFSET_BUSY) {
366                         return -ETIMEDOUT;
367                 }
368
369                 return -EIO;            /* error or wrong offset */
370         }
371
372         return 0;
373 }
374
375 /* Read a block of data from the chip's buffer, via the
376  * BAP. Synchronization/serialization is the caller's problem.  len
377  * must be even.
378  *
379  * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware
380  */
381 int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len,
382                      u16 id, u16 offset)
383 {
384         int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
385         int err = 0;
386
387         if ( (len < 0) || (len % 2) )
388                 return -EINVAL;
389
390         err = hermes_bap_seek(hw, bap, id, offset);
391         if (err)
392                 goto out;
393
394         /* Actually do the transfer */
395         hermes_read_words(hw, dreg, buf, len/2);
396
397  out:
398         return err;
399 }
400
401 /* Write a block of data to the chip's buffer, via the
402  * BAP. Synchronization/serialization is the caller's problem.
403  *
404  * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware
405  */
406 int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len,
407                       u16 id, u16 offset)
408 {
409         int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
410         int err = 0;
411
412         if (len < 0)
413                 return -EINVAL;
414
415         err = hermes_bap_seek(hw, bap, id, offset);
416         if (err)
417                 goto out;
418         
419         /* Actually do the transfer */
420         hermes_write_bytes(hw, dreg, buf, len);
421
422  out:   
423         return err;
424 }
425
426 /* Read a Length-Type-Value record from the card.
427  *
428  * If length is NULL, we ignore the length read from the card, and
429  * read the entire buffer regardless. This is useful because some of
430  * the configuration records appear to have incorrect lengths in
431  * practice.
432  *
433  * Callable from user or bh context.  */
434 int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned bufsize,
435                     u16 *length, void *buf)
436 {
437         int err = 0;
438         int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
439         u16 rlength, rtype;
440         unsigned nwords;
441
442         if ( (bufsize < 0) || (bufsize % 2) )
443                 return -EINVAL;
444
445         err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, NULL);
446         if (err)
447                 return err;
448
449         err = hermes_bap_seek(hw, bap, rid, 0);
450         if (err)
451                 return err;
452
453         rlength = hermes_read_reg(hw, dreg);
454
455         if (! rlength)
456                 return -ENODATA;
457
458         rtype = hermes_read_reg(hw, dreg);
459
460         if (length)
461                 *length = rlength;
462
463         if (rtype != rid)
464                 printk(KERN_WARNING "hermes @ %p: %s(): "
465                        "rid (0x%04x) does not match type (0x%04x)\n",
466                        hw->iobase, __FUNCTION__, rid, rtype);
467         if (HERMES_RECLEN_TO_BYTES(rlength) > bufsize)
468                 printk(KERN_WARNING "hermes @ %p: "
469                        "Truncating LTV record from %d to %d bytes. "
470                        "(rid=0x%04x, len=0x%04x)\n", hw->iobase,
471                        HERMES_RECLEN_TO_BYTES(rlength), bufsize, rid, rlength);
472
473         nwords = min((unsigned)rlength - 1, bufsize / 2);
474         hermes_read_words(hw, dreg, buf, nwords);
475
476         return 0;
477 }
478
479 int hermes_write_ltv(hermes_t *hw, int bap, u16 rid, 
480                      u16 length, const void *value)
481 {
482         int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
483         int err = 0;
484         unsigned count;
485
486         if (length == 0)
487                 return -EINVAL;
488
489         err = hermes_bap_seek(hw, bap, rid, 0);
490         if (err)
491                 return err;
492
493         hermes_write_reg(hw, dreg, length);
494         hermes_write_reg(hw, dreg, rid);
495
496         count = length - 1;
497
498         hermes_write_bytes(hw, dreg, value, count << 1);
499
500         err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE, 
501                                 rid, NULL);
502
503         return err;
504 }
505
506 EXPORT_SYMBOL(hermes_struct_init);
507 EXPORT_SYMBOL(hermes_init);
508 EXPORT_SYMBOL(hermes_docmd_wait);
509 EXPORT_SYMBOL(hermes_allocate);
510
511 EXPORT_SYMBOL(hermes_bap_pread);
512 EXPORT_SYMBOL(hermes_bap_pwrite);
513 EXPORT_SYMBOL(hermes_read_ltv);
514 EXPORT_SYMBOL(hermes_write_ltv);
515
516 static int __init init_hermes(void)
517 {
518         return 0;
519 }
520
521 static void __exit exit_hermes(void)
522 {
523 }
524
525 module_init(init_hermes);
526 module_exit(exit_hermes);