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 PRIVATE
int this_proc
;
43 /*****************************************************************************
46 * Wait msecs milli seconds *
47 *****************************************************************************/
48 void milli_delay(unsigned int msecs
)
50 micro_delay((long)msecs
* 1000);
54 /*****************************************************************************
57 * Issue a command to the chip. Waiting for it to complete is the caller's *
58 * problem. The only thing we have to do first is to see whether we can *
59 * actually write something in the CMD register: is it unbusy? *
60 * Returns -EBUSY if the command register is busy, 0 on success. *
61 *****************************************************************************/
62 static int hermes_issue_cmd (hermes_t
* hw
, u16_t cmd
, u16_t param0
) {
63 int k
= HERMES_CMD_BUSY_TIMEOUT
;
66 /* First wait for the command register to unbusy */
67 reg
= hermes_read_reg (hw
, HERMES_CMD
);
68 while ((reg
& HERMES_CMD_BUSY
) && k
) {
71 reg
= hermes_read_reg (hw
, HERMES_CMD
);
73 /* it takes too long. Bailing out */
74 if (reg
& HERMES_CMD_BUSY
) {
75 printf("Hermes: HERMES_CMD_BUSY timeout\n");
79 /* write the values to the right registers */
80 hermes_write_reg (hw
, HERMES_PARAM2
, 0);
81 hermes_write_reg (hw
, HERMES_PARAM1
, 0);
82 hermes_write_reg (hw
, HERMES_PARAM0
, param0
);
83 hermes_write_reg (hw
, HERMES_CMD
, cmd
);
87 /*****************************************************************************
88 * hermes_struct_init *
90 * Initialize the hermes structure fields *
91 *****************************************************************************/
92 void hermes_struct_init (hermes_t
* hw
, u32_t address
,
93 int io_space
, int reg_spacing
) {
95 hw
->io_space
= io_space
;
96 hw
->reg_spacing
= reg_spacing
;
98 this_proc
= getprocnr();
102 /*****************************************************************************
105 * This is the first step in initializing the card's firmware and hardware: *
106 * write HERMES_PCI_COR_MASK to the Configuration Option Register *
107 *****************************************************************************/
108 int hermes_cor_reset (hermes_t
*hw
) {
112 /* Assert the reset until the card notice */
113 hermes_write_reg (hw
, HERMES_PCI_COR
, HERMES_PCI_COR_MASK
);
115 milli_delay (HERMES_PCI_COR_ONT
);
117 /* Give time for the card to recover from this hard effort */
118 hermes_write_reg (hw
, HERMES_PCI_COR
, 0x0000);
120 milli_delay (HERMES_PCI_COR_OFFT
);
122 /* The card is ready when it's no longer busy */
123 k
= HERMES_PCI_COR_BUSYT
;
124 reg
= hermes_read_reg (hw
, HERMES_CMD
);
125 while (k
&& (reg
& HERMES_CMD_BUSY
)) {
128 reg
= hermes_read_reg (hw
, HERMES_CMD
);
131 /* Did we timeout ? */
132 if (reg
& HERMES_CMD_BUSY
) {
133 printf ("Busy timeout after resetting the COR\n");
142 /*****************************************************************************
145 * Initialize the card *
146 *****************************************************************************/
147 int hermes_init (hermes_t
* hw
) {
148 u32_t status
, reg
, resp0
;
152 /* We don't want to be interrupted while resetting the chipset. By
153 * setting the control mask for hardware interrupt generation to 0,
154 * we won't be disturbed*/
156 hermes_write_reg (hw
, HERMES_INTEN
, 0);
158 /* Acknowledge any pending events waiting for acknowledgement. We
159 * assume there won't be any important to take care off */
160 hermes_write_reg (hw
, HERMES_EVACK
, 0xffff);
162 /* Normally it's a "can't happen" for the command register to
163 * be busy when we go to issue a command because we are
164 * serializing all commands. However we want to have some
165 * chance of resetting the card even if it gets into a stupid
166 * state, so we actually wait to see if the command register
167 * will unbusy itself here. */
168 k
= HERMES_CMD_BUSY_TIMEOUT
;
169 reg
= hermes_read_reg (hw
, HERMES_CMD
);
170 while (k
&& (reg
& HERMES_CMD_BUSY
)) {
172 /* Special case - the card has probably
173 * been removed, so don't wait for the
175 printf("Hermes: Card removed?\n");
181 reg
= hermes_read_reg (hw
, HERMES_CMD
);
184 /* No need to explicitly handle the timeout - if we've timed
185 * out hermes_issue_cmd() will probably return -EBUSY below.
186 * But i check to be sure :-) */
187 if (reg
& HERMES_CMD_BUSY
) {
188 printf("Hermes: Timeout waiting for the CMD_BUSY to unset\n");
192 /* According to the documentation, EVSTAT may contain
193 * obsolete event occurrence information. We have to acknowledge
194 * it by writing EVACK. */
195 reg
= hermes_read_reg (hw
, HERMES_EVSTAT
);
196 hermes_write_reg (hw
, HERMES_EVACK
, reg
);
198 err
= hermes_issue_cmd (hw
, HERMES_CMD_INIT
, 0);
200 printf("Hermes: errornr: 0x%x issueing HERMES_CMD_INIT\n",
205 /* here we start waiting for the above command,CMD_INIT, to complete.
206 * Completion is noticeable when the HERMES_EV_CMD bit in the
207 * HERMES_EVSTAT register is set to 1 */
208 reg
= hermes_read_reg (hw
, HERMES_EVSTAT
);
209 k
= HERMES_CMD_INIT_TIMEOUT
;
210 while ((!(reg
& HERMES_EV_CMD
)) && k
) {
213 reg
= hermes_read_reg (hw
, HERMES_EVSTAT
);
217 /* the software support register 0 (there are 3) is filled with a
218 * magic number. With this one can test the availability of the card */
219 hermes_write_reg (hw
, HERMES_SWSUPPORT0
, HERMES_MAGIC
);
221 if (!hermes_present (hw
)) {
222 printf("Hermes: Card not present?: got mag. nr.0x%x\n",
223 hermes_read_reg (hw
, HERMES_SWSUPPORT0
));
226 if (!(reg
& HERMES_EV_CMD
)) {
227 printf("hermes @ %x: Timeout waiting for card to reset\n",
232 status
= hermes_read_reg (hw
, HERMES_STATUS
);
233 resp0
= hermes_read_reg (hw
, HERMES_RESP0
);
235 /* after having issued the command above, the completion set a bit in
236 * the EVSTAT register. This has to be acknowledged, as follows */
237 hermes_write_reg (hw
, HERMES_EVACK
, HERMES_EV_CMD
);
239 /* Was the status, the result of the issued command, ok? */
240 /* The expression below should be zero. Non-zero means an error */
241 if (status
& HERMES_STATUS_RESULT
) {
242 printf("Hermes:Result of INIT_CMD wrong.error value: 0x%x\n",
243 (status
& HERMES_STATUS_RESULT
) >> 8);
250 /*****************************************************************************
251 * hermes_docmd_wait *
253 * Issue a command to the chip, and (busy) wait for it to complete. *
254 *****************************************************************************/
255 int hermes_docmd_wait (hermes_t
* hw
, u16_t cmd
, u16_t parm0
,
256 hermes_response_t
* resp
) {
262 err
= hermes_issue_cmd (hw
, cmd
, parm0
);
264 printf("hermes @ %x: Error %d issuing command.\n",
269 /* Reads the Event status register. When the command has completed,
270 * the fourth bit in the HERMES_EVSTAT register is a 1. We will be
271 * waiting for that to happen */
272 reg
= hermes_read_reg (hw
, HERMES_EVSTAT
);
273 k
= HERMES_CMD_COMPL_TIMEOUT
;
274 while ((!(reg
& HERMES_EV_CMD
)) && k
) {
277 reg
= hermes_read_reg (hw
, HERMES_EVSTAT
);
280 /* check for a timeout: has the command still not completed? */
281 if (!(reg
& HERMES_EV_CMD
)) {
282 printf("hermes @ %x: Timeout waiting for command \
283 completion.\n", hw
->iobase
);
288 status
= hermes_read_reg (hw
, HERMES_STATUS
);
289 /* some commands result in results residing in response registers.
290 * They have to be read before the acknowledgement below.
293 resp
->status
= status
;
294 resp
->resp0
= hermes_read_reg (hw
, HERMES_RESP0
);
295 resp
->resp1
= hermes_read_reg (hw
, HERMES_RESP1
);
296 resp
->resp2
= hermes_read_reg (hw
, HERMES_RESP2
);
299 /* After issueing a Command, the card expects an Acknowledgement */
300 hermes_write_reg (hw
, HERMES_EVACK
, HERMES_EV_CMD
);
302 /* check whether there has been a valid value in the Status register.
303 * the high order bits should have at least some value */
304 if (status
& HERMES_STATUS_RESULT
) {
305 printf("Hermes: EIO\n");
313 /*****************************************************************************
316 * Allocate bufferspace in the card, which will be then available for *
317 * writing by the host, TX buffers. The card will try to find enough memory *
318 * (creating a list of 128 byte blocks) and will return a pointer to the *
319 * first block. This pointer is a pointer to the frame identifier (fid), *
320 * holding information and data of the buffer. The fid is like a file *
321 * descriptor, a value indicating some resource *
322 *****************************************************************************/
323 int hermes_allocate (hermes_t
* hw
, u16_t size
, u16_t
* fid
) {
328 if ((size
< HERMES_ALLOC_LEN_MIN
) || (size
> HERMES_ALLOC_LEN_MAX
)) {
329 printf("Hermes: Invalid size\n");
333 /* Issue a allocation request to the card, waiting for the command
335 err
= hermes_docmd_wait (hw
, HERMES_CMD_ALLOC
, size
, NULL
);
337 printf( "Hermes: docmd_wait timeout\n");
341 /* Read the status event register to know whether the allocation
342 * succeeded. The HERMES_EV_ALLOC bit should be set */
343 reg
= hermes_read_reg (hw
, HERMES_EVSTAT
);
344 k
= HERMES_ALLOC_COMPL_TIMEOUT
;
345 while ((!(reg
& HERMES_EV_ALLOC
)) && k
) {
348 reg
= hermes_read_reg (hw
, HERMES_EVSTAT
);
351 /* tired of waiting to complete. Abort. */
352 if (!(reg
& HERMES_EV_ALLOC
)) {
353 printf("hermes @ %x:Timeout waiting for frame allocation\n",
358 /* When we come here, everything has gone well. The pointer to the
359 * fid is in the ALLOCFID register. This fid is later on used
360 * to access this buffer */
361 *fid
= hermes_read_reg (hw
, HERMES_ALLOCFID
);
363 /* always acknowledge the receipt of an event */
364 hermes_write_reg (hw
, HERMES_EVACK
, HERMES_EV_ALLOC
);
371 /*****************************************************************************
374 * Set up a Buffer Access Path (BAP) to read a particular chunk of data *
375 * from card's internal buffer. Setting a bap register is like doing a fseek *
376 * system call: setting an internal pointer to the right place in a buffer *
377 *****************************************************************************/
378 static int hermes_bap_seek (hermes_t
* hw
, int bap
, u16_t id
, u16_t offset
) {
380 /* There are 2 BAPs. This can be used to use the access buffers
381 * concurrently: 1 for writing in the TX buffer and 1 for reading
382 * a RX buffer in case of an RX interrupt.
383 * The BAP consists of 2 registers, together with which one can
384 * point to a single byte in the required buffer (additionally
385 * there is a third register, but that one is not used in this
386 * function, the data register). With the SELECT register one chooses
387 * the fid, with the OFFSET register one chooses the offset in the fid
389 int sreg
= bap
? HERMES_SELECT1
: HERMES_SELECT0
;
390 int oreg
= bap
? HERMES_OFFSET1
: HERMES_OFFSET0
;
395 /* Check whether the offset is not too large, and whether it is a
396 * number of words. Offset can't be odd */
397 if ((offset
> HERMES_BAP_OFFSET_MAX
) || (offset
% 2)) {
398 printf("Hermes: Offset error\n");
402 /* We can't write to the offset register when the busy flag is set. If
403 * it is set, wait to automatically reset*/
404 k
= HERMES_BAP_BUSY_TIMEOUT
;
405 reg
= hermes_read_reg (hw
, oreg
);
406 while ((reg
& HERMES_OFFSET_BUSY
) && k
) {
409 reg
= hermes_read_reg (hw
, oreg
);
412 /* For some reason, the busy flag didn't reset automatically. Return */
413 if (reg
& HERMES_OFFSET_BUSY
) {
414 printf("Hermes: HERMES_OFFSET_BUSY still set, oreg: 0x%x\n",
419 /* Now we actually set up the transfer. Write the fid in the select
420 * register, and the offset in the offset register */
421 hermes_write_reg (hw
, sreg
, id
);
422 hermes_write_reg (hw
, oreg
, offset
);
424 /* Wait for the BAP to be ready. This means that at first the
425 * OFFSET_BUSY bit is set by the card once we have written the values
426 * above. We wait until the card has done its internal processing and
427 * unset the OFFSET_BUSY bit */
428 k
= HERMES_BAP_BUSY_TIMEOUT
;
429 reg
= hermes_read_reg (hw
, oreg
);
430 while ((reg
& (HERMES_OFFSET_BUSY
| HERMES_OFFSET_ERR
)) && k
) {
433 reg
= hermes_read_reg (hw
, oreg
);
436 /* Busy bit didn't reset automatically */
437 if (reg
& HERMES_OFFSET_BUSY
) {
438 printf("Hermes: Error with fid 0x%x. Err: 0x%x\n", id
, reg
);
442 /* There has gone something wrong: offset is outside the buffer
443 * boundary or the fid is not correct */
444 if (reg
& HERMES_OFFSET_ERR
) {
445 printf("Hermes: Error with fid 0x%x. Err: 0x%x\n", id
, reg
);
449 /* If we arrive here, the buffer can be accessed through the data
450 * register associated with the BAP */
455 /*****************************************************************************
458 * Read a block of data from the chip's buffer, via the BAP. len must be *
460 *****************************************************************************/
461 int hermes_bap_pread (hermes_t
* hw
, int bap
, void *buf
, unsigned len
,
462 u16_t id
, u16_t offset
) {
463 /* The data register is the access point for the buffer made
464 * available by setting the BAP right. Which BAP does the user
465 * want to use? there are 2 of them */
466 int dreg
= bap
? HERMES_DATA1
: HERMES_DATA0
;
469 /* reading (and writing) data goes a word a time, so should be even */
470 if ((len
< 0) || (len
% 2)) {
471 printf("Hermes: Error in length to be read\n");
475 /* Set the cards internal pointer to the right fid and to the right
477 err
= hermes_bap_seek (hw
, bap
, id
, offset
);
479 printf("Hermes: error hermes_bap_seek in hermes_bap_pread\n");
482 /* Actually do the transfer. The length is divided by 2 because
483 * transfers go a word at a time as far as the card is concerned */
484 hermes_read_words (hw
, dreg
, buf
, len
/ 2);
489 /*****************************************************************************
490 * hermes_bap_pwrite *
492 * Write a block of data to the chip's buffer, via the BAP. len must be even.*
493 *****************************************************************************/
494 int hermes_bap_pwrite (hermes_t
* hw
, int bap
, const void *buf
, unsigned len
,
495 u16_t id
, u16_t offset
) {
497 /* This procedure is quite the same as the hermes_bap_read */
498 int dreg
= bap
? HERMES_DATA1
: HERMES_DATA0
;
501 if ((len
< 0) || (len
% 2)) {
502 printf("Hermes: Error in length to be written\n");
506 /* Set the cards internal pointer to the right fid and to the right
508 err
= hermes_bap_seek (hw
, bap
, id
, offset
);
510 printf("Hermes: hermes_bap_seek error in hermes_bap_pwrite\n");
515 /* Actually do the transfer */
516 hermes_write_words (hw
, dreg
, buf
, len
/ 2);
522 /*****************************************************************************
525 * Check whether we have access to the card. Does the SWSUPPORT0 contain the *
526 * value we put in it earlier? *
527 *****************************************************************************/
528 int hermes_present (hermes_t
* hw
) {
529 int i
= hermes_read_reg (hw
, HERMES_SWSUPPORT0
) == HERMES_MAGIC
;
531 printf("Hermes: Error, card not present?\n");
536 /*****************************************************************************
537 * hermes_set_irqmask *
539 * Which events should the card respond to with an interrupt? *
540 *****************************************************************************/
541 int hermes_set_irqmask (hermes_t
* hw
, u16_t events
) {
543 hermes_write_reg (hw
, HERMES_INTEN
, events
);
545 /* Compare written value with read value to check whether things
547 if (hermes_read_reg (hw
, HERMES_INTEN
) != events
) {
548 printf("Hermes: error setting irqmask\n");
555 /*****************************************************************************
556 * hermes_set_irqmask *
558 * Which events does the card respond to with an interrupt? *
559 *****************************************************************************/
560 u16_t
hermes_get_irqmask (hermes_t
* hw
) {
561 return hermes_read_reg (hw
, HERMES_INTEN
);
565 /*****************************************************************************
568 * Read a Length-Type-Value record from the card. These are configurable *
569 * parameters in the cards firmware, like wepkey, essid, mac address etc. *
570 * Another name for them are 'rids', Resource Identifiers. See hermes_rids.h *
571 * for all available rids *
572 * If length is NULL, we ignore the length read from the card, and *
573 * read the entire buffer regardless. This is useful because some of *
574 * the configuration records appear to have incorrect lengths in *
576 *****************************************************************************/
577 int hermes_read_ltv (hermes_t
* hw
, int bap
, u16_t rid
, unsigned bufsize
,
578 u16_t
* length
, void *buf
) {
580 int dreg
= bap
? HERMES_DATA1
: HERMES_DATA0
;
581 u16_t rlength
, rtype
;
584 if ((bufsize
< 0) || (bufsize
% 2)) {
585 printf("Hermes: error in bufsize\n");
589 err
= hermes_docmd_wait (hw
, HERMES_CMD_ACCESS
, rid
, NULL
);
591 printf("Hermes: error hermes_docmd_wait in hermes_read_ltv\n");
595 err
= hermes_bap_seek (hw
, bap
, rid
, 0);
597 printf("Hermes: error hermes_bap_seek in hermes_read_ltv\n");
601 rlength
= hermes_read_reg (hw
, dreg
);
604 printf( "Hermes: Error rlength\n");
608 rtype
= hermes_read_reg (hw
, dreg
);
614 printf("hermes @ %lx: hermes_read_ltv(): rid (0x%04x)",
616 printf("does not match type (0x%04x)\n", rid
, rtype
);
619 if (HERMES_RECLEN_TO_BYTES (rlength
) > bufsize
) {
620 printf("hermes @ %lx: Truncating LTV record from ",
622 printf("%d to %d bytes. (rid=0x%04x, len=0x%04x)\n",
623 HERMES_RECLEN_TO_BYTES (rlength
), bufsize
, rid
,
626 nwords
= MIN ((unsigned) rlength
- 1, bufsize
/ 2);
627 hermes_read_words (hw
, dreg
, buf
, nwords
);
633 /*****************************************************************************
636 * Write a Length-Type-Value record to the card. These are configurable *
637 * parameters in the cards firmware, like wepkey, essid, mac address etc. *
638 * Another name for them are 'rids', Resource Identifiers. See hermes_rids.h *
639 * for all available rids *
640 *****************************************************************************/
641 int hermes_write_ltv (hermes_t
* hw
, int bap
, u16_t rid
,
642 u16_t length
, const void *value
) {
643 int dreg
= bap
? HERMES_DATA1
: HERMES_DATA0
;
648 printf("Hermes: length==0 in hermes_write_ltv\n");
652 err
= hermes_bap_seek (hw
, bap
, rid
, 0);
654 printf("Hermes: error hermes_bap_seek in hermes_write_ltv\n");
658 hermes_write_reg (hw
, dreg
, length
);
659 hermes_write_reg (hw
, dreg
, rid
);
663 hermes_write_words (hw
, dreg
, value
, count
);
665 err
= hermes_docmd_wait (hw
, HERMES_CMD_ACCESS
| HERMES_CMD_WRITE
,
668 printf("Hermes: error hermes_docmd_wait in hermes_write_ltv\n");
674 /*****************************************************************************
675 * hermes_write_wordrec *
677 * A shorthand for hermes_write_ltv when the field is 2 bytes long *
678 *****************************************************************************/
679 int hermes_write_wordrec (hermes_t
* hw
, int bap
, u16_t rid
, u16_t word
) {
685 err
= hermes_write_ltv (hw
, bap
, rid
,
686 HERMES_BYTES_TO_RECLEN (sizeof (rec
)), &rec
);
689 printf("Hermes: error in write_wordrec\n");
694 /*****************************************************************************
695 * hermes_read_wordrec *
697 * A shorthand for hermes_read_ltv when the field is 2 bytes long *
698 *****************************************************************************/
699 int hermes_read_wordrec (hermes_t
* hw
, int bap
, u16_t rid
, u16_t
* word
) {
703 err
= hermes_read_ltv (hw
, bap
, rid
, sizeof (rec
), NULL
, &rec
);
706 printf("Hermes: Error in read_wordrec\n");
711 /*****************************************************************************
712 * hermes_read_words *
714 * Read a sequence of words from the card to the buffer *
715 *****************************************************************************/
716 void hermes_read_words (hermes_t
* hw
, int off
, void *buf
, unsigned count
) {
720 for (i
= 0; i
< count
; i
++) {
721 reg
= hermes_read_reg (hw
, off
);
722 *((u16_t
*) buf
+ i
) = (u16_t
) reg
;
726 /*****************************************************************************
727 * hermes_write_words *
729 * Write a sequence of words of the buffer to the card *
730 *****************************************************************************/
731 void hermes_write_words (hermes_t
* hw
, int off
, const void *buf
,
735 for (i
= 0; i
< count
; i
++) {
736 hermes_write_reg (hw
, off
, *((u16_t
*) buf
+ i
));
741 /*****************************************************************************
744 * Read a value from a certain register. Currently only memory mapped *
745 * registers are supported, but accessing I/O spaced registers should be *
747 *****************************************************************************/
748 u16_t
hermes_read_reg (hermes_t
* hw
, u16_t off
) {
750 v
= *((int *)(hw
->locmem
+ (off
<< hw
->reg_spacing
)));
754 /*****************************************************************************
757 * Write a value to a certain register. Currently only memory mapped *
758 * registers are supported, but accessing I/O spaced registers should be *
760 *****************************************************************************/
761 void hermes_write_reg (hermes_t
* hw
, u16_t off
, u16_t val
) {
763 *(int *)(hw
->locmem
+ (off
<< hw
->reg_spacing
)) = v
;