4 * This file contains the lower level access functions for Prism based
5 * wireless cards. The file is based on hermes.c of the Linux kernel
7 * Adjusted to Minix by Stevens Le Blond <slblond@few.vu.nl>
8 * and Michael Valkering <mjvalker@cs.vu.nl>
11 /* Original copyright notices from Linux hermes.c
13 * Copyright (C) 2000, David Gibson, Linuxcare Australia
14 * <hermes@gibson.dropbear.id.au>
15 * Copyright (C) 2001, David Gibson, IBM <hermes@gibson.dropbear.id.au>
17 * The contents of this file are subject to the Mozilla Public License
18 * Version 1.1 (the "License"); you may not use this file except in
19 * compliance with the License. You may obtain a copy of the License
20 * at http://www.mozilla.org/MPL/
22 * Software distributed under the License is distributed on an "AS IS"
23 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
24 * the License for the specific language governing rights and
25 * limitations under the License.
27 * Alternatively, the contents of this file may be used under the
28 * terms of the GNU General Public License version 2 (the "GPL"), in
29 * which case the provisions of the GPL are applicable instead of the
30 * above. If you wish to allow the use of your version of this file
31 * only under the terms of the GPL and not to allow others to use your
32 * version of this file under the MPL, indicate your decision by
33 * deleting the provisions above and replace them with the notice and
34 * other provisions required by the GPL. If you do not delete the
35 * provisions above, a recipient may use your version of this file
36 * under either the MPL or the GPL.
47 /*****************************************************************************
50 * Wait msecs milli seconds *
51 *****************************************************************************/
52 void milli_delay(unsigned int msecs
)
54 micro_delay((long)msecs
* 1000);
58 /*****************************************************************************
61 * Issue a command to the chip. Waiting for it to complete is the caller's *
62 * problem. The only thing we have to do first is to see whether we can *
63 * actually write something in the CMD register: is it unbusy? *
64 * Returns -EBUSY if the command register is busy, 0 on success. *
65 *****************************************************************************/
66 static int hermes_issue_cmd (hermes_t
* hw
, u16_t cmd
, u16_t param0
) {
67 int k
= HERMES_CMD_BUSY_TIMEOUT
;
70 /* First wait for the command register to unbusy */
71 reg
= hermes_read_reg (hw
, HERMES_CMD
);
72 while ((reg
& HERMES_CMD_BUSY
) && k
) {
75 reg
= hermes_read_reg (hw
, HERMES_CMD
);
77 /* it takes too long. Bailing out */
78 if (reg
& HERMES_CMD_BUSY
) {
79 printf("Hermes: HERMES_CMD_BUSY timeout\n");
83 /* write the values to the right registers */
84 hermes_write_reg (hw
, HERMES_PARAM2
, 0);
85 hermes_write_reg (hw
, HERMES_PARAM1
, 0);
86 hermes_write_reg (hw
, HERMES_PARAM0
, param0
);
87 hermes_write_reg (hw
, HERMES_CMD
, cmd
);
91 /*****************************************************************************
92 * hermes_struct_init *
94 * Initialize the hermes structure fields *
95 *****************************************************************************/
96 void hermes_struct_init (hermes_t
* hw
, u32_t address
,
97 int io_space
, int reg_spacing
) {
99 hw
->io_space
= io_space
;
100 hw
->reg_spacing
= reg_spacing
;
102 this_proc
= getprocnr();
106 /*****************************************************************************
109 * This is the first step in initializing the card's firmware and hardware: *
110 * write HERMES_PCI_COR_MASK to the Configuration Option Register *
111 *****************************************************************************/
112 int hermes_cor_reset (hermes_t
*hw
) {
116 /* Assert the reset until the card notice */
117 hermes_write_reg (hw
, HERMES_PCI_COR
, HERMES_PCI_COR_MASK
);
119 milli_delay (HERMES_PCI_COR_ONT
);
121 /* Give time for the card to recover from this hard effort */
122 hermes_write_reg (hw
, HERMES_PCI_COR
, 0x0000);
124 milli_delay (HERMES_PCI_COR_OFFT
);
126 /* The card is ready when it's no longer busy */
127 k
= HERMES_PCI_COR_BUSYT
;
128 reg
= hermes_read_reg (hw
, HERMES_CMD
);
129 while (k
&& (reg
& HERMES_CMD_BUSY
)) {
132 reg
= hermes_read_reg (hw
, HERMES_CMD
);
135 /* Did we timeout ? */
136 if (reg
& HERMES_CMD_BUSY
) {
137 printf ("Busy timeout after resetting the COR\n");
146 /*****************************************************************************
149 * Initialize the card *
150 *****************************************************************************/
151 int hermes_init (hermes_t
* hw
) {
152 u32_t status
, reg
, resp0
;
156 /* We don't want to be interrupted while resetting the chipset. By
157 * setting the control mask for hardware interrupt generation to 0,
158 * we won't be disturbed*/
160 hermes_write_reg (hw
, HERMES_INTEN
, 0);
162 /* Acknowledge any pending events waiting for acknowledgement. We
163 * assume there won't be any important to take care off */
164 hermes_write_reg (hw
, HERMES_EVACK
, 0xffff);
166 /* Normally it's a "can't happen" for the command register to
167 * be busy when we go to issue a command because we are
168 * serializing all commands. However we want to have some
169 * chance of resetting the card even if it gets into a stupid
170 * state, so we actually wait to see if the command register
171 * will unbusy itself here. */
172 k
= HERMES_CMD_BUSY_TIMEOUT
;
173 reg
= hermes_read_reg (hw
, HERMES_CMD
);
174 while (k
&& (reg
& HERMES_CMD_BUSY
)) {
176 /* Special case - the card has probably
177 * been removed, so don't wait for the
179 printf("Hermes: Card removed?\n");
185 reg
= hermes_read_reg (hw
, HERMES_CMD
);
188 /* No need to explicitly handle the timeout - if we've timed
189 * out hermes_issue_cmd() will probably return -EBUSY below.
190 * But i check to be sure :-) */
191 if (reg
& HERMES_CMD_BUSY
) {
192 printf("Hermes: Timeout waiting for the CMD_BUSY to unset\n");
196 /* According to the documentation, EVSTAT may contain
197 * obsolete event occurrence information. We have to acknowledge
198 * it by writing EVACK. */
199 reg
= hermes_read_reg (hw
, HERMES_EVSTAT
);
200 hermes_write_reg (hw
, HERMES_EVACK
, reg
);
202 err
= hermes_issue_cmd (hw
, HERMES_CMD_INIT
, 0);
204 printf("Hermes: errornr: 0x%x issueing HERMES_CMD_INIT\n",
209 /* here we start waiting for the above command,CMD_INIT, to complete.
210 * Completion is noticeable when the HERMES_EV_CMD bit in the
211 * HERMES_EVSTAT register is set to 1 */
212 reg
= hermes_read_reg (hw
, HERMES_EVSTAT
);
213 k
= HERMES_CMD_INIT_TIMEOUT
;
214 while ((!(reg
& HERMES_EV_CMD
)) && k
) {
217 reg
= hermes_read_reg (hw
, HERMES_EVSTAT
);
221 /* the software support register 0 (there are 3) is filled with a
222 * magic number. With this one can test the availability of the card */
223 hermes_write_reg (hw
, HERMES_SWSUPPORT0
, HERMES_MAGIC
);
225 if (!hermes_present (hw
)) {
226 printf("Hermes: Card not present?: got mag. nr.0x%x\n",
227 hermes_read_reg (hw
, HERMES_SWSUPPORT0
));
230 if (!(reg
& HERMES_EV_CMD
)) {
231 printf("hermes @ %x: Timeout waiting for card to reset\n",
236 status
= hermes_read_reg (hw
, HERMES_STATUS
);
237 resp0
= hermes_read_reg (hw
, HERMES_RESP0
);
239 /* after having issued the command above, the completion set a bit in
240 * the EVSTAT register. This has to be acknowledged, as follows */
241 hermes_write_reg (hw
, HERMES_EVACK
, HERMES_EV_CMD
);
243 /* Was the status, the result of the issued command, ok? */
244 /* The expression below should be zero. Non-zero means an error */
245 if (status
& HERMES_STATUS_RESULT
) {
246 printf("Hermes:Result of INIT_CMD wrong.error value: 0x%x\n",
247 (status
& HERMES_STATUS_RESULT
) >> 8);
254 /*****************************************************************************
255 * hermes_docmd_wait *
257 * Issue a command to the chip, and (busy) wait for it to complete. *
258 *****************************************************************************/
259 int hermes_docmd_wait (hermes_t
* hw
, u16_t cmd
, u16_t parm0
,
260 hermes_response_t
* resp
) {
266 err
= hermes_issue_cmd (hw
, cmd
, parm0
);
268 printf("hermes @ %x: Error %d issuing command.\n",
273 /* Reads the Event status register. When the command has completed,
274 * the fourth bit in the HERMES_EVSTAT register is a 1. We will be
275 * waiting for that to happen */
276 reg
= hermes_read_reg (hw
, HERMES_EVSTAT
);
277 k
= HERMES_CMD_COMPL_TIMEOUT
;
278 while ((!(reg
& HERMES_EV_CMD
)) && k
) {
281 reg
= hermes_read_reg (hw
, HERMES_EVSTAT
);
284 /* check for a timeout: has the command still not completed? */
285 if (!(reg
& HERMES_EV_CMD
)) {
286 printf("hermes @ %x: Timeout waiting for command \
287 completion.\n", hw
->iobase
);
292 status
= hermes_read_reg (hw
, HERMES_STATUS
);
293 /* some commands result in results residing in response registers.
294 * They have to be read before the acknowledgement below.
297 resp
->status
= status
;
298 resp
->resp0
= hermes_read_reg (hw
, HERMES_RESP0
);
299 resp
->resp1
= hermes_read_reg (hw
, HERMES_RESP1
);
300 resp
->resp2
= hermes_read_reg (hw
, HERMES_RESP2
);
303 /* After issueing a Command, the card expects an Acknowledgement */
304 hermes_write_reg (hw
, HERMES_EVACK
, HERMES_EV_CMD
);
306 /* check whether there has been a valid value in the Status register.
307 * the high order bits should have at least some value */
308 if (status
& HERMES_STATUS_RESULT
) {
309 printf("Hermes: EIO\n");
317 /*****************************************************************************
320 * Allocate bufferspace in the card, which will be then available for *
321 * writing by the host, TX buffers. The card will try to find enough memory *
322 * (creating a list of 128 byte blocks) and will return a pointer to the *
323 * first block. This pointer is a pointer to the frame identifier (fid), *
324 * holding information and data of the buffer. The fid is like a file *
325 * descriptor, a value indicating some resource *
326 *****************************************************************************/
327 int hermes_allocate (hermes_t
* hw
, u16_t size
, u16_t
* fid
) {
332 if ((size
< HERMES_ALLOC_LEN_MIN
) || (size
> HERMES_ALLOC_LEN_MAX
)) {
333 printf("Hermes: Invalid size\n");
337 /* Issue a allocation request to the card, waiting for the command
339 err
= hermes_docmd_wait (hw
, HERMES_CMD_ALLOC
, size
, NULL
);
341 printf( "Hermes: docmd_wait timeout\n");
345 /* Read the status event register to know whether the allocation
346 * succeeded. The HERMES_EV_ALLOC bit should be set */
347 reg
= hermes_read_reg (hw
, HERMES_EVSTAT
);
348 k
= HERMES_ALLOC_COMPL_TIMEOUT
;
349 while ((!(reg
& HERMES_EV_ALLOC
)) && k
) {
352 reg
= hermes_read_reg (hw
, HERMES_EVSTAT
);
355 /* tired of waiting to complete. Abort. */
356 if (!(reg
& HERMES_EV_ALLOC
)) {
357 printf("hermes @ %x:Timeout waiting for frame allocation\n",
362 /* When we come here, everything has gone well. The pointer to the
363 * fid is in the ALLOCFID register. This fid is later on used
364 * to access this buffer */
365 *fid
= hermes_read_reg (hw
, HERMES_ALLOCFID
);
367 /* always acknowledge the receipt of an event */
368 hermes_write_reg (hw
, HERMES_EVACK
, HERMES_EV_ALLOC
);
375 /*****************************************************************************
378 * Set up a Buffer Access Path (BAP) to read a particular chunk of data *
379 * from card's internal buffer. Setting a bap register is like doing a fseek *
380 * system call: setting an internal pointer to the right place in a buffer *
381 *****************************************************************************/
382 static int hermes_bap_seek (hermes_t
* hw
, int bap
, u16_t id
, u16_t offset
) {
384 /* There are 2 BAPs. This can be used to use the access buffers
385 * concurrently: 1 for writing in the TX buffer and 1 for reading
386 * a RX buffer in case of an RX interrupt.
387 * The BAP consists of 2 registers, together with which one can
388 * point to a single byte in the required buffer (additionally
389 * there is a third register, but that one is not used in this
390 * function, the data register). With the SELECT register one chooses
391 * the fid, with the OFFSET register one chooses the offset in the fid
393 int sreg
= bap
? HERMES_SELECT1
: HERMES_SELECT0
;
394 int oreg
= bap
? HERMES_OFFSET1
: HERMES_OFFSET0
;
399 /* Check whether the offset is not too large, and whether it is a
400 * number of words. Offset can't be odd */
401 if ((offset
> HERMES_BAP_OFFSET_MAX
) || (offset
% 2)) {
402 printf("Hermes: Offset error\n");
406 /* We can't write to the offset register when the busy flag is set. If
407 * it is set, wait to automatically reset*/
408 k
= HERMES_BAP_BUSY_TIMEOUT
;
409 reg
= hermes_read_reg (hw
, oreg
);
410 while ((reg
& HERMES_OFFSET_BUSY
) && k
) {
413 reg
= hermes_read_reg (hw
, oreg
);
416 /* For some reason, the busy flag didn't reset automatically. Return */
417 if (reg
& HERMES_OFFSET_BUSY
) {
418 printf("Hermes: HERMES_OFFSET_BUSY still set, oreg: 0x%x\n",
423 /* Now we actually set up the transfer. Write the fid in the select
424 * register, and the offset in the offset register */
425 hermes_write_reg (hw
, sreg
, id
);
426 hermes_write_reg (hw
, oreg
, offset
);
428 /* Wait for the BAP to be ready. This means that at first the
429 * OFFSET_BUSY bit is set by the card once we have written the values
430 * above. We wait until the card has done its internal processing and
431 * unset the OFFSET_BUSY bit */
432 k
= HERMES_BAP_BUSY_TIMEOUT
;
433 reg
= hermes_read_reg (hw
, oreg
);
434 while ((reg
& (HERMES_OFFSET_BUSY
| HERMES_OFFSET_ERR
)) && k
) {
437 reg
= hermes_read_reg (hw
, oreg
);
440 /* Busy bit didn't reset automatically */
441 if (reg
& HERMES_OFFSET_BUSY
) {
442 printf("Hermes: Error with fid 0x%x. Err: 0x%x\n", id
, reg
);
446 /* There has gone something wrong: offset is outside the buffer
447 * boundary or the fid is not correct */
448 if (reg
& HERMES_OFFSET_ERR
) {
449 printf("Hermes: Error with fid 0x%x. Err: 0x%x\n", id
, reg
);
453 /* If we arrive here, the buffer can be accessed through the data
454 * register associated with the BAP */
459 /*****************************************************************************
462 * Read a block of data from the chip's buffer, via the BAP. len must be *
464 *****************************************************************************/
465 int hermes_bap_pread (hermes_t
* hw
, int bap
, void *buf
, unsigned len
,
466 u16_t id
, u16_t offset
) {
467 /* The data register is the access point for the buffer made
468 * available by setting the BAP right. Which BAP does the user
469 * want to use? there are 2 of them */
470 int dreg
= bap
? HERMES_DATA1
: HERMES_DATA0
;
473 /* reading (and writing) data goes a word a time, so should be even */
474 if ((len
< 0) || (len
% 2)) {
475 printf("Hermes: Error in length to be read\n");
479 /* Set the cards internal pointer to the right fid and to the right
481 err
= hermes_bap_seek (hw
, bap
, id
, offset
);
483 printf("Hermes: error hermes_bap_seek in hermes_bap_pread\n");
486 /* Actually do the transfer. The length is divided by 2 because
487 * transfers go a word at a time as far as the card is concerned */
488 hermes_read_words (hw
, dreg
, buf
, len
/ 2);
493 /*****************************************************************************
494 * hermes_bap_pwrite *
496 * Write a block of data to the chip's buffer, via the BAP. len must be even.*
497 *****************************************************************************/
498 int hermes_bap_pwrite (hermes_t
* hw
, int bap
, const void *buf
, unsigned len
,
499 u16_t id
, u16_t offset
) {
501 /* This procedure is quite the same as the hermes_bap_read */
502 int dreg
= bap
? HERMES_DATA1
: HERMES_DATA0
;
505 if ((len
< 0) || (len
% 2)) {
506 printf("Hermes: Error in length to be written\n");
510 /* Set the cards internal pointer to the right fid and to the right
512 err
= hermes_bap_seek (hw
, bap
, id
, offset
);
514 printf("Hermes: hermes_bap_seek error in hermes_bap_pwrite\n");
519 /* Actually do the transfer */
520 hermes_write_words (hw
, dreg
, buf
, len
/ 2);
526 /*****************************************************************************
529 * Check whether we have access to the card. Does the SWSUPPORT0 contain the *
530 * value we put in it earlier? *
531 *****************************************************************************/
532 int hermes_present (hermes_t
* hw
) {
533 int i
= hermes_read_reg (hw
, HERMES_SWSUPPORT0
) == HERMES_MAGIC
;
535 printf("Hermes: Error, card not present?\n");
540 /*****************************************************************************
541 * hermes_set_irqmask *
543 * Which events should the card respond to with an interrupt? *
544 *****************************************************************************/
545 int hermes_set_irqmask (hermes_t
* hw
, u16_t events
) {
547 hermes_write_reg (hw
, HERMES_INTEN
, events
);
549 /* Compare written value with read value to check whether things
551 if (hermes_read_reg (hw
, HERMES_INTEN
) != events
) {
552 printf("Hermes: error setting irqmask\n");
559 /*****************************************************************************
560 * hermes_set_irqmask *
562 * Which events does the card respond to with an interrupt? *
563 *****************************************************************************/
564 u16_t
hermes_get_irqmask (hermes_t
* hw
) {
565 return hermes_read_reg (hw
, HERMES_INTEN
);
569 /*****************************************************************************
572 * Read a Length-Type-Value record from the card. These are configurable *
573 * parameters in the cards firmware, like wepkey, essid, mac address etc. *
574 * Another name for them are 'rids', Resource Identifiers. See hermes_rids.h *
575 * for all available rids *
576 * If length is NULL, we ignore the length read from the card, and *
577 * read the entire buffer regardless. This is useful because some of *
578 * the configuration records appear to have incorrect lengths in *
580 *****************************************************************************/
581 int hermes_read_ltv (hermes_t
* hw
, int bap
, u16_t rid
, unsigned bufsize
,
582 u16_t
* length
, void *buf
) {
584 int dreg
= bap
? HERMES_DATA1
: HERMES_DATA0
;
585 u16_t rlength
, rtype
;
588 if ((bufsize
< 0) || (bufsize
% 2)) {
589 printf("Hermes: error in bufsize\n");
593 err
= hermes_docmd_wait (hw
, HERMES_CMD_ACCESS
, rid
, NULL
);
595 printf("Hermes: error hermes_docmd_wait in hermes_read_ltv\n");
599 err
= hermes_bap_seek (hw
, bap
, rid
, 0);
601 printf("Hermes: error hermes_bap_seek in hermes_read_ltv\n");
605 rlength
= hermes_read_reg (hw
, dreg
);
608 printf( "Hermes: Error rlength\n");
612 rtype
= hermes_read_reg (hw
, dreg
);
618 printf("hermes @ %lx: hermes_read_ltv(): rid (0x%04x)",
620 printf("does not match type (0x%04x)\n", rid
, rtype
);
623 if (HERMES_RECLEN_TO_BYTES (rlength
) > bufsize
) {
624 printf("hermes @ %lx: Truncating LTV record from ",
626 printf("%d to %d bytes. (rid=0x%04x, len=0x%04x)\n",
627 HERMES_RECLEN_TO_BYTES (rlength
), bufsize
, rid
,
630 nwords
= MIN ((unsigned) rlength
- 1, bufsize
/ 2);
631 hermes_read_words (hw
, dreg
, buf
, nwords
);
637 /*****************************************************************************
640 * Write a Length-Type-Value record to the card. These are configurable *
641 * parameters in the cards firmware, like wepkey, essid, mac address etc. *
642 * Another name for them are 'rids', Resource Identifiers. See hermes_rids.h *
643 * for all available rids *
644 *****************************************************************************/
645 int hermes_write_ltv (hermes_t
* hw
, int bap
, u16_t rid
,
646 u16_t length
, const void *value
) {
647 int dreg
= bap
? HERMES_DATA1
: HERMES_DATA0
;
652 printf("Hermes: length==0 in hermes_write_ltv\n");
656 err
= hermes_bap_seek (hw
, bap
, rid
, 0);
658 printf("Hermes: error hermes_bap_seek in hermes_write_ltv\n");
662 hermes_write_reg (hw
, dreg
, length
);
663 hermes_write_reg (hw
, dreg
, rid
);
667 hermes_write_words (hw
, dreg
, value
, count
);
669 err
= hermes_docmd_wait (hw
, HERMES_CMD_ACCESS
| HERMES_CMD_WRITE
,
672 printf("Hermes: error hermes_docmd_wait in hermes_write_ltv\n");
678 /*****************************************************************************
679 * hermes_write_wordrec *
681 * A shorthand for hermes_write_ltv when the field is 2 bytes long *
682 *****************************************************************************/
683 int hermes_write_wordrec (hermes_t
* hw
, int bap
, u16_t rid
, u16_t word
) {
689 err
= hermes_write_ltv (hw
, bap
, rid
,
690 HERMES_BYTES_TO_RECLEN (sizeof (rec
)), &rec
);
693 printf("Hermes: error in write_wordrec\n");
698 /*****************************************************************************
699 * hermes_read_wordrec *
701 * A shorthand for hermes_read_ltv when the field is 2 bytes long *
702 *****************************************************************************/
703 int hermes_read_wordrec (hermes_t
* hw
, int bap
, u16_t rid
, u16_t
* word
) {
707 err
= hermes_read_ltv (hw
, bap
, rid
, sizeof (rec
), NULL
, &rec
);
710 printf("Hermes: Error in read_wordrec\n");
715 /*****************************************************************************
716 * hermes_read_words *
718 * Read a sequence of words from the card to the buffer *
719 *****************************************************************************/
720 void hermes_read_words (hermes_t
* hw
, int off
, void *buf
, unsigned count
) {
724 for (i
= 0; i
< count
; i
++) {
725 reg
= hermes_read_reg (hw
, off
);
726 *((u16_t
*) buf
+ i
) = (u16_t
) reg
;
730 /*****************************************************************************
731 * hermes_write_words *
733 * Write a sequence of words of the buffer to the card *
734 *****************************************************************************/
735 void hermes_write_words (hermes_t
* hw
, int off
, const void *buf
,
739 for (i
= 0; i
< count
; i
++) {
740 hermes_write_reg (hw
, off
, *((u16_t
*) buf
+ i
));
745 /*****************************************************************************
748 * Read a value from a certain register. Currently only memory mapped *
749 * registers are supported, but accessing I/O spaced registers should be *
751 *****************************************************************************/
752 u16_t
hermes_read_reg (hermes_t
* hw
, u16_t off
) {
754 v
= *((int *)(hw
->locmem
+ (off
<< hw
->reg_spacing
)));
758 /*****************************************************************************
761 * Write a value to a certain register. Currently only memory mapped *
762 * registers are supported, but accessing I/O spaced registers should be *
764 *****************************************************************************/
765 void hermes_write_reg (hermes_t
* hw
, u16_t off
, u16_t val
) {
767 *(int *)(hw
->locmem
+ (off
<< hw
->reg_spacing
)) = v
;