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.
41 /*****************************************************************************
44 * Wait msecs milli seconds *
45 *****************************************************************************/
46 static void milli_delay(unsigned int msecs
)
48 micro_delay((long)msecs
* 1000);
52 /*****************************************************************************
55 * Issue a command to the chip. Waiting for it to complete is the caller's *
56 * problem. The only thing we have to do first is to see whether we can *
57 * actually write something in the CMD register: is it unbusy? *
58 * Returns -EBUSY if the command register is busy, 0 on success. *
59 *****************************************************************************/
60 static int hermes_issue_cmd (hermes_t
* hw
, u16_t cmd
, u16_t param0
) {
61 int k
= HERMES_CMD_BUSY_TIMEOUT
;
64 /* First wait for the command register to unbusy */
65 reg
= hermes_read_reg (hw
, HERMES_CMD
);
66 while ((reg
& HERMES_CMD_BUSY
) && k
) {
69 reg
= hermes_read_reg (hw
, HERMES_CMD
);
71 /* it takes too long. Bailing out */
72 if (reg
& HERMES_CMD_BUSY
) {
73 printf("Hermes: HERMES_CMD_BUSY timeout\n");
77 /* write the values to the right registers */
78 hermes_write_reg (hw
, HERMES_PARAM2
, 0);
79 hermes_write_reg (hw
, HERMES_PARAM1
, 0);
80 hermes_write_reg (hw
, HERMES_PARAM0
, param0
);
81 hermes_write_reg (hw
, HERMES_CMD
, cmd
);
85 /*****************************************************************************
86 * hermes_struct_init *
88 * Initialize the hermes structure fields *
89 *****************************************************************************/
90 void hermes_struct_init (hermes_t
* hw
, u32_t address
,
91 int io_space
, int reg_spacing
) {
93 hw
->io_space
= io_space
;
94 hw
->reg_spacing
= reg_spacing
;
99 /*****************************************************************************
102 * This is the first step in initializing the card's firmware and hardware: *
103 * write HERMES_PCI_COR_MASK to the Configuration Option Register *
104 *****************************************************************************/
105 int hermes_cor_reset (hermes_t
*hw
) {
109 /* Assert the reset until the card notice */
110 hermes_write_reg (hw
, HERMES_PCI_COR
, HERMES_PCI_COR_MASK
);
112 milli_delay (HERMES_PCI_COR_ONT
);
114 /* Give time for the card to recover from this hard effort */
115 hermes_write_reg (hw
, HERMES_PCI_COR
, 0x0000);
117 milli_delay (HERMES_PCI_COR_OFFT
);
119 /* The card is ready when it's no longer busy */
120 k
= HERMES_PCI_COR_BUSYT
;
121 reg
= hermes_read_reg (hw
, HERMES_CMD
);
122 while (k
&& (reg
& HERMES_CMD_BUSY
)) {
125 reg
= hermes_read_reg (hw
, HERMES_CMD
);
128 /* Did we timeout ? */
129 if (reg
& HERMES_CMD_BUSY
) {
130 printf ("Busy timeout after resetting the COR\n");
138 /*****************************************************************************
141 * Check whether we have access to the card. Does the SWSUPPORT0 contain the *
142 * value we put in it earlier? *
143 *****************************************************************************/
144 static int hermes_present (hermes_t
* hw
) {
145 int i
= hermes_read_reg (hw
, HERMES_SWSUPPORT0
) == HERMES_MAGIC
;
147 printf("Hermes: Error, card not present?\n");
152 /*****************************************************************************
155 * Initialize the card *
156 *****************************************************************************/
157 int hermes_init (hermes_t
* hw
)
159 u32_t status
, reg
, resp0
;
163 /* We don't want to be interrupted while resetting the chipset. By
164 * setting the control mask for hardware interrupt generation to 0,
165 * we won't be disturbed*/
167 hermes_write_reg (hw
, HERMES_INTEN
, 0);
169 /* Acknowledge any pending events waiting for acknowledgement. We
170 * assume there won't be any important to take care off */
171 hermes_write_reg (hw
, HERMES_EVACK
, 0xffff);
173 /* Normally it's a "can't happen" for the command register to
174 * be busy when we go to issue a command because we are
175 * serializing all commands. However we want to have some
176 * chance of resetting the card even if it gets into a stupid
177 * state, so we actually wait to see if the command register
178 * will unbusy itself here. */
179 k
= HERMES_CMD_BUSY_TIMEOUT
;
180 reg
= hermes_read_reg (hw
, HERMES_CMD
);
181 while (k
&& (reg
& HERMES_CMD_BUSY
)) {
183 /* Special case - the card has probably
184 * been removed, so don't wait for the
186 printf("Hermes: Card removed?\n");
192 reg
= hermes_read_reg (hw
, HERMES_CMD
);
195 /* No need to explicitly handle the timeout - if we've timed
196 * out hermes_issue_cmd() will probably return -EBUSY below.
197 * But i check to be sure :-) */
198 if (reg
& HERMES_CMD_BUSY
) {
199 printf("Hermes: Timeout waiting for the CMD_BUSY to unset\n");
203 /* According to the documentation, EVSTAT may contain
204 * obsolete event occurrence information. We have to acknowledge
205 * it by writing EVACK. */
206 reg
= hermes_read_reg (hw
, HERMES_EVSTAT
);
207 hermes_write_reg (hw
, HERMES_EVACK
, reg
);
209 err
= hermes_issue_cmd (hw
, HERMES_CMD_INIT
, 0);
211 printf("Hermes: errornr: 0x%x issueing HERMES_CMD_INIT\n",
216 /* here we start waiting for the above command,CMD_INIT, to complete.
217 * Completion is noticeable when the HERMES_EV_CMD bit in the
218 * HERMES_EVSTAT register is set to 1 */
219 reg
= hermes_read_reg (hw
, HERMES_EVSTAT
);
220 k
= HERMES_CMD_INIT_TIMEOUT
;
221 while ((!(reg
& HERMES_EV_CMD
)) && k
) {
224 reg
= hermes_read_reg (hw
, HERMES_EVSTAT
);
228 /* the software support register 0 (there are 3) is filled with a
229 * magic number. With this one can test the availability of the card */
230 hermes_write_reg (hw
, HERMES_SWSUPPORT0
, HERMES_MAGIC
);
232 if (!hermes_present (hw
)) {
233 printf("Hermes: Card not present?: got mag. nr.0x%x\n",
234 hermes_read_reg (hw
, HERMES_SWSUPPORT0
));
237 if (!(reg
& HERMES_EV_CMD
)) {
238 printf("hermes @ %x: Timeout waiting for card to reset\n",
243 status
= hermes_read_reg (hw
, HERMES_STATUS
);
244 resp0
= hermes_read_reg (hw
, HERMES_RESP0
);
246 /* after having issued the command above, the completion set a bit in
247 * the EVSTAT register. This has to be acknowledged, as follows */
248 hermes_write_reg (hw
, HERMES_EVACK
, HERMES_EV_CMD
);
250 /* Was the status, the result of the issued command, ok? */
251 /* The expression below should be zero. Non-zero means an error */
252 if (status
& HERMES_STATUS_RESULT
) {
253 printf("Hermes:Result of INIT_CMD wrong.error value: 0x%x\n",
254 (status
& HERMES_STATUS_RESULT
) >> 8);
261 /*****************************************************************************
262 * hermes_docmd_wait *
264 * Issue a command to the chip, and (busy) wait for it to complete. *
265 *****************************************************************************/
266 int hermes_docmd_wait (hermes_t
* hw
, u16_t cmd
, u16_t parm0
,
267 hermes_response_t
* resp
) {
273 err
= hermes_issue_cmd (hw
, cmd
, parm0
);
275 printf("hermes @ %x: Error %d issuing command.\n",
280 /* Reads the Event status register. When the command has completed,
281 * the fourth bit in the HERMES_EVSTAT register is a 1. We will be
282 * waiting for that to happen */
283 reg
= hermes_read_reg (hw
, HERMES_EVSTAT
);
284 k
= HERMES_CMD_COMPL_TIMEOUT
;
285 while ((!(reg
& HERMES_EV_CMD
)) && k
) {
288 reg
= hermes_read_reg (hw
, HERMES_EVSTAT
);
291 /* check for a timeout: has the command still not completed? */
292 if (!(reg
& HERMES_EV_CMD
)) {
293 printf("hermes @ %x: Timeout waiting for command \
294 completion.\n", hw
->iobase
);
299 status
= hermes_read_reg (hw
, HERMES_STATUS
);
300 /* some commands result in results residing in response registers.
301 * They have to be read before the acknowledgement below.
304 resp
->status
= status
;
305 resp
->resp0
= hermes_read_reg (hw
, HERMES_RESP0
);
306 resp
->resp1
= hermes_read_reg (hw
, HERMES_RESP1
);
307 resp
->resp2
= hermes_read_reg (hw
, HERMES_RESP2
);
310 /* After issueing a Command, the card expects an Acknowledgement */
311 hermes_write_reg (hw
, HERMES_EVACK
, HERMES_EV_CMD
);
313 /* check whether there has been a valid value in the Status register.
314 * the high order bits should have at least some value */
315 if (status
& HERMES_STATUS_RESULT
) {
316 printf("Hermes: EIO\n");
324 /*****************************************************************************
327 * Allocate bufferspace in the card, which will be then available for *
328 * writing by the host, TX buffers. The card will try to find enough memory *
329 * (creating a list of 128 byte blocks) and will return a pointer to the *
330 * first block. This pointer is a pointer to the frame identifier (fid), *
331 * holding information and data of the buffer. The fid is like a file *
332 * descriptor, a value indicating some resource *
333 *****************************************************************************/
334 int hermes_allocate (hermes_t
* hw
, u16_t size
, u16_t
* fid
) {
339 if ((size
< HERMES_ALLOC_LEN_MIN
) || (size
> HERMES_ALLOC_LEN_MAX
)) {
340 printf("Hermes: Invalid size\n");
344 /* Issue a allocation request to the card, waiting for the command
346 err
= hermes_docmd_wait (hw
, HERMES_CMD_ALLOC
, size
, NULL
);
348 printf( "Hermes: docmd_wait timeout\n");
352 /* Read the status event register to know whether the allocation
353 * succeeded. The HERMES_EV_ALLOC bit should be set */
354 reg
= hermes_read_reg (hw
, HERMES_EVSTAT
);
355 k
= HERMES_ALLOC_COMPL_TIMEOUT
;
356 while ((!(reg
& HERMES_EV_ALLOC
)) && k
) {
359 reg
= hermes_read_reg (hw
, HERMES_EVSTAT
);
362 /* tired of waiting to complete. Abort. */
363 if (!(reg
& HERMES_EV_ALLOC
)) {
364 printf("hermes @ %x:Timeout waiting for frame allocation\n",
369 /* When we come here, everything has gone well. The pointer to the
370 * fid is in the ALLOCFID register. This fid is later on used
371 * to access this buffer */
372 *fid
= hermes_read_reg (hw
, HERMES_ALLOCFID
);
374 /* always acknowledge the receipt of an event */
375 hermes_write_reg (hw
, HERMES_EVACK
, HERMES_EV_ALLOC
);
382 /*****************************************************************************
385 * Set up a Buffer Access Path (BAP) to read a particular chunk of data *
386 * from card's internal buffer. Setting a bap register is like doing a fseek *
387 * system call: setting an internal pointer to the right place in a buffer *
388 *****************************************************************************/
389 static int hermes_bap_seek (hermes_t
* hw
, int bap
, u16_t id
, u16_t offset
) {
391 /* There are 2 BAPs. This can be used to use the access buffers
392 * concurrently: 1 for writing in the TX buffer and 1 for reading
393 * a RX buffer in case of an RX interrupt.
394 * The BAP consists of 2 registers, together with which one can
395 * point to a single byte in the required buffer (additionally
396 * there is a third register, but that one is not used in this
397 * function, the data register). With the SELECT register one chooses
398 * the fid, with the OFFSET register one chooses the offset in the fid
400 int sreg
= bap
? HERMES_SELECT1
: HERMES_SELECT0
;
401 int oreg
= bap
? HERMES_OFFSET1
: HERMES_OFFSET0
;
405 /* Check whether the offset is not too large, and whether it is a
406 * number of words. Offset can't be odd */
407 if ((offset
> HERMES_BAP_OFFSET_MAX
) || (offset
% 2)) {
408 printf("Hermes: Offset error\n");
412 /* We can't write to the offset register when the busy flag is set. If
413 * it is set, wait to automatically reset*/
414 k
= HERMES_BAP_BUSY_TIMEOUT
;
415 reg
= hermes_read_reg (hw
, oreg
);
416 while ((reg
& HERMES_OFFSET_BUSY
) && k
) {
419 reg
= hermes_read_reg (hw
, oreg
);
422 /* For some reason, the busy flag didn't reset automatically. Return */
423 if (reg
& HERMES_OFFSET_BUSY
) {
424 printf("Hermes: HERMES_OFFSET_BUSY still set, oreg: 0x%x\n",
429 /* Now we actually set up the transfer. Write the fid in the select
430 * register, and the offset in the offset register */
431 hermes_write_reg (hw
, sreg
, id
);
432 hermes_write_reg (hw
, oreg
, offset
);
434 /* Wait for the BAP to be ready. This means that at first the
435 * OFFSET_BUSY bit is set by the card once we have written the values
436 * above. We wait until the card has done its internal processing and
437 * unset the OFFSET_BUSY bit */
438 k
= HERMES_BAP_BUSY_TIMEOUT
;
439 reg
= hermes_read_reg (hw
, oreg
);
440 while ((reg
& (HERMES_OFFSET_BUSY
| HERMES_OFFSET_ERR
)) && k
) {
443 reg
= hermes_read_reg (hw
, oreg
);
446 /* Busy bit didn't reset automatically */
447 if (reg
& HERMES_OFFSET_BUSY
) {
448 printf("Hermes: Error with fid 0x%x. Err: 0x%x\n", id
, reg
);
452 /* There has gone something wrong: offset is outside the buffer
453 * boundary or the fid is not correct */
454 if (reg
& HERMES_OFFSET_ERR
) {
455 printf("Hermes: Error with fid 0x%x. Err: 0x%x\n", id
, reg
);
459 /* If we arrive here, the buffer can be accessed through the data
460 * register associated with the BAP */
465 /*****************************************************************************
468 * Read a block of data from the chip's buffer, via the BAP. len must be *
470 *****************************************************************************/
471 int hermes_bap_pread (hermes_t
* hw
, int bap
, void *buf
, unsigned len
,
472 u16_t id
, u16_t offset
) {
473 /* The data register is the access point for the buffer made
474 * available by setting the BAP right. Which BAP does the user
475 * want to use? there are 2 of them */
476 int dreg
= bap
? HERMES_DATA1
: HERMES_DATA0
;
479 /* reading (and writing) data goes a word a time, so should be even */
481 printf("Hermes: Error in length to be read\n");
485 /* Set the cards internal pointer to the right fid and to the right
487 err
= hermes_bap_seek (hw
, bap
, id
, offset
);
489 printf("Hermes: error hermes_bap_seek in hermes_bap_pread\n");
492 /* Actually do the transfer. The length is divided by 2 because
493 * transfers go a word at a time as far as the card is concerned */
494 hermes_read_words (hw
, dreg
, buf
, len
/ 2);
499 /*****************************************************************************
500 * hermes_write_words *
502 * Write a sequence of words of the buffer to the card *
503 *****************************************************************************/
504 void hermes_write_words (hermes_t
* hw
, int off
, const void *buf
,
508 for (i
= 0; i
< count
; i
++) {
509 hermes_write_reg (hw
, off
, *((u16_t
*) buf
+ i
));
513 /*****************************************************************************
514 * hermes_bap_pwrite *
516 * Write a block of data to the chip's buffer, via the BAP. len must be even.*
517 *****************************************************************************/
518 int hermes_bap_pwrite (hermes_t
* hw
, int bap
, const void *buf
, unsigned len
,
519 u16_t id
, u16_t offset
) {
521 /* This procedure is quite the same as the hermes_bap_read */
522 int dreg
= bap
? HERMES_DATA1
: HERMES_DATA0
;
526 printf("Hermes: Error in length to be written\n");
530 /* Set the cards internal pointer to the right fid and to the right
532 err
= hermes_bap_seek (hw
, bap
, id
, offset
);
534 printf("Hermes: hermes_bap_seek error in hermes_bap_pwrite\n");
539 /* Actually do the transfer */
540 hermes_write_words (hw
, dreg
, buf
, len
/ 2);
547 /*****************************************************************************
548 * hermes_set_irqmask *
550 * Which events should the card respond to with an interrupt? *
551 *****************************************************************************/
552 int hermes_set_irqmask (hermes_t
* hw
, u16_t events
) {
554 hermes_write_reg (hw
, HERMES_INTEN
, events
);
556 /* Compare written value with read value to check whether things
558 if (hermes_read_reg (hw
, HERMES_INTEN
) != events
) {
559 printf("Hermes: error setting irqmask\n");
566 /*****************************************************************************
567 * hermes_set_irqmask *
569 * Which events does the card respond to with an interrupt? *
570 *****************************************************************************/
571 u16_t
hermes_get_irqmask (hermes_t
* hw
) {
572 return hermes_read_reg (hw
, HERMES_INTEN
);
576 /*****************************************************************************
579 * Read a Length-Type-Value record from the card. These are configurable *
580 * parameters in the cards firmware, like wepkey, essid, mac address etc. *
581 * Another name for them are 'rids', Resource Identifiers. See hermes_rids.h *
582 * for all available rids *
583 * If length is NULL, we ignore the length read from the card, and *
584 * read the entire buffer regardless. This is useful because some of *
585 * the configuration records appear to have incorrect lengths in *
587 *****************************************************************************/
588 int hermes_read_ltv (hermes_t
* hw
, int bap
, u16_t rid
, unsigned bufsize
,
589 u16_t
* length
, void *buf
) {
591 int dreg
= bap
? HERMES_DATA1
: HERMES_DATA0
;
592 u16_t rlength
, rtype
;
596 printf("Hermes: error in bufsize\n");
600 err
= hermes_docmd_wait (hw
, HERMES_CMD_ACCESS
, rid
, NULL
);
602 printf("Hermes: error hermes_docmd_wait in hermes_read_ltv\n");
606 err
= hermes_bap_seek (hw
, bap
, rid
, 0);
608 printf("Hermes: error hermes_bap_seek in hermes_read_ltv\n");
612 rlength
= hermes_read_reg (hw
, dreg
);
615 printf( "Hermes: Error rlength\n");
619 rtype
= hermes_read_reg (hw
, dreg
);
625 printf("hermes @ %x: hermes_read_ltv(): rid (0x%04x)",
627 printf("does not match type (0x%04x)\n", rtype
);
630 if (HERMES_RECLEN_TO_BYTES (rlength
) > bufsize
) {
631 printf("hermes @ %x: Truncating LTV record from ",
633 printf("%d to %d bytes. (rid=0x%04x, len=0x%04x)\n",
634 HERMES_RECLEN_TO_BYTES (rlength
), bufsize
, rid
,
637 nwords
= MIN ((unsigned) rlength
- 1, bufsize
/ 2);
638 hermes_read_words (hw
, dreg
, buf
, nwords
);
644 /*****************************************************************************
647 * Write a Length-Type-Value record to the card. These are configurable *
648 * parameters in the cards firmware, like wepkey, essid, mac address etc. *
649 * Another name for them are 'rids', Resource Identifiers. See hermes_rids.h *
650 * for all available rids *
651 *****************************************************************************/
652 int hermes_write_ltv (hermes_t
* hw
, int bap
, u16_t rid
,
653 u16_t length
, const void *value
) {
654 int dreg
= bap
? HERMES_DATA1
: HERMES_DATA0
;
659 printf("Hermes: length==0 in hermes_write_ltv\n");
663 err
= hermes_bap_seek (hw
, bap
, rid
, 0);
665 printf("Hermes: error hermes_bap_seek in hermes_write_ltv\n");
669 hermes_write_reg (hw
, dreg
, length
);
670 hermes_write_reg (hw
, dreg
, rid
);
674 hermes_write_words (hw
, dreg
, value
, count
);
676 err
= hermes_docmd_wait (hw
, HERMES_CMD_ACCESS
| HERMES_CMD_WRITE
,
679 printf("Hermes: error hermes_docmd_wait in hermes_write_ltv\n");
685 /*****************************************************************************
686 * hermes_write_wordrec *
688 * A shorthand for hermes_write_ltv when the field is 2 bytes long *
689 *****************************************************************************/
690 int hermes_write_wordrec (hermes_t
* hw
, int bap
, u16_t rid
, u16_t word
) {
696 err
= hermes_write_ltv (hw
, bap
, rid
,
697 HERMES_BYTES_TO_RECLEN (sizeof (rec
)), &rec
);
700 printf("Hermes: error in write_wordrec\n");
705 /*****************************************************************************
706 * hermes_read_wordrec *
708 * A shorthand for hermes_read_ltv when the field is 2 bytes long *
709 *****************************************************************************/
710 int hermes_read_wordrec (hermes_t
* hw
, int bap
, u16_t rid
, u16_t
* word
) {
714 err
= hermes_read_ltv (hw
, bap
, rid
, sizeof (rec
), NULL
, &rec
);
717 printf("Hermes: Error in read_wordrec\n");
722 /*****************************************************************************
723 * hermes_read_words *
725 * Read a sequence of words from the card to the buffer *
726 *****************************************************************************/
727 void hermes_read_words (hermes_t
* hw
, int off
, void *buf
, unsigned count
) {
731 for (i
= 0; i
< count
; i
++) {
732 reg
= hermes_read_reg (hw
, off
);
733 *((u16_t
*) buf
+ i
) = (u16_t
) reg
;
738 /*****************************************************************************
741 * Read a value from a certain register. Currently only memory mapped *
742 * registers are supported, but accessing I/O spaced registers should be *
744 *****************************************************************************/
745 u16_t
hermes_read_reg (const hermes_t
* hw
, u16_t off
) {
747 v
= *((int *)(hw
->locmem
+ (off
<< hw
->reg_spacing
)));
751 /*****************************************************************************
754 * Write a value to a certain register. Currently only memory mapped *
755 * registers are supported, but accessing I/O spaced registers should be *
757 *****************************************************************************/
758 void hermes_write_reg (const hermes_t
* hw
, u16_t off
, u16_t val
) {
760 *(int *)(hw
->locmem
+ (off
<< hw
->reg_spacing
)) = v
;