dec21140A ethernet driver for virtualpc, contributed by nicolas tittley.
[minix.git] / drivers / orinoco / hermes.c
blob095553be600dd579393148e85f51b33289de2324
1 /*
2 * hermes.c
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>
9 */
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.
39 #include "hermes.h"
40 #include <sys/vm.h>
41 #include "assert.h"
42 #include <ibm/pci.h>
44 #include "string.h"
45 int this_proc;
47 /*****************************************************************************
48 * milli_delay *
49 * *
50 * Wait msecs milli seconds *
51 *****************************************************************************/
52 void milli_delay(unsigned int msecs)
54 micro_delay((long)msecs * 1000);
58 /*****************************************************************************
59 * hermes_issue_cmd *
60 * *
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;
68 u16_t reg;
70 /* First wait for the command register to unbusy */
71 reg = hermes_read_reg (hw, HERMES_CMD);
72 while ((reg & HERMES_CMD_BUSY) && k) {
73 k--;
74 micro_delay (1);
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");
80 return -EBUSY;
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);
88 return 0;
91 /*****************************************************************************
92 * hermes_struct_init *
93 * *
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) {
98 hw->iobase = address;
99 hw->io_space = io_space;
100 hw->reg_spacing = reg_spacing;
101 hw->inten = 0x0;
102 this_proc = getprocnr();
106 /*****************************************************************************
107 * hermes_cor_reset *
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) {
113 int k, i;
114 u16_t reg;
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)) {
130 k--;
131 milli_delay (1);
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");
138 return -1;
141 return (0);
146 /*****************************************************************************
147 * hermes_init *
149 * Initialize the card *
150 *****************************************************************************/
151 int hermes_init (hermes_t * hw) {
152 u32_t status, reg, resp0;
153 int err = 0;
154 int k;
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*/
159 hw->inten = 0x0;
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)) {
175 if (reg == 0xffff) {
176 /* Special case - the card has probably
177 * been removed, so don't wait for the
178 * timeout */
179 printf("Hermes: Card removed?\n");
180 return -ENODEV;
183 k--;
184 micro_delay (1);
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");
193 return -EBUSY;
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);
203 if (err){
204 printf("Hermes: errornr: 0x%x issueing HERMES_CMD_INIT\n",
205 err);
206 return err;
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) {
215 k--;
216 micro_delay (10);
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",
232 hw->iobase);
233 return -ETIMEDOUT;
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);
248 err = -EIO;
251 return err;
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) {
261 int err;
262 int k;
263 u16_t reg;
264 u16_t status;
266 err = hermes_issue_cmd (hw, cmd, parm0);
267 if (err) {
268 printf("hermes @ %x: Error %d issuing command.\n",
269 hw->iobase, err);
270 return err;
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) {
279 k--;
280 micro_delay (10);
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);
288 err = -ETIMEDOUT;
289 return err;
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.
296 if (resp) {
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");
310 err = -EIO;
313 return err;
317 /*****************************************************************************
318 * hermes_allocate *
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) {
328 int err = 0;
329 int k;
330 u16_t reg;
332 if ((size < HERMES_ALLOC_LEN_MIN) || (size > HERMES_ALLOC_LEN_MAX)) {
333 printf("Hermes: Invalid size\n");
334 return -EINVAL;
337 /* Issue a allocation request to the card, waiting for the command
338 * to complete */
339 err = hermes_docmd_wait (hw, HERMES_CMD_ALLOC, size, NULL);
340 if (err) {
341 printf( "Hermes: docmd_wait timeout\n");
342 return err;
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) {
350 k--;
351 micro_delay (10);
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",
358 hw->iobase);
359 return -ETIMEDOUT;
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);
370 return 0;
375 /*****************************************************************************
376 * hermes_bap_seek *
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
392 * buffer */
393 int sreg = bap ? HERMES_SELECT1 : HERMES_SELECT0;
394 int oreg = bap ? HERMES_OFFSET1 : HERMES_OFFSET0;
395 int resp0;
396 int k;
397 u16_t reg;
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");
403 return -EINVAL;
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) {
411 k--;
412 micro_delay (1);
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",
419 reg);
420 return -ETIMEDOUT;
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) {
435 k--;
436 micro_delay (1);
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);
443 return -ETIMEDOUT;
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);
450 return -EIO;
453 /* If we arrive here, the buffer can be accessed through the data
454 * register associated with the BAP */
455 return 0;
459 /*****************************************************************************
460 * hermes_bap_pread *
462 * Read a block of data from the chip's buffer, via the BAP. len must be *
463 * even. *
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;
471 int err = 0;
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");
476 return -EINVAL;
479 /* Set the cards internal pointer to the right fid and to the right
480 * offset */
481 err = hermes_bap_seek (hw, bap, id, offset);
482 if (err) {
483 printf("Hermes: error hermes_bap_seek in hermes_bap_pread\n");
484 return err;
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);
490 return err;
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;
503 int err = 0;
505 if ((len < 0) || (len % 2)) {
506 printf("Hermes: Error in length to be written\n");
507 return -EINVAL;
510 /* Set the cards internal pointer to the right fid and to the right
511 * offset */
512 err = hermes_bap_seek (hw, bap, id, offset);
513 if (err) {
514 printf("Hermes: hermes_bap_seek error in hermes_bap_pwrite\n");
515 return err;
519 /* Actually do the transfer */
520 hermes_write_words (hw, dreg, buf, len / 2);
522 return err;
526 /*****************************************************************************
527 * hermes_present *
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;
534 if (!i)
535 printf("Hermes: Error, card not present?\n");
536 return i;
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) {
546 hw->inten = events;
547 hermes_write_reg (hw, HERMES_INTEN, events);
549 /* Compare written value with read value to check whether things
550 * succeeded */
551 if (hermes_read_reg (hw, HERMES_INTEN) != events) {
552 printf("Hermes: error setting irqmask\n");
553 return 1;
556 return (0);
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 /*****************************************************************************
570 * hermes_read_ltv *
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 *
579 * practice. *
580 *****************************************************************************/
581 int hermes_read_ltv (hermes_t * hw, int bap, u16_t rid, unsigned bufsize,
582 u16_t * length, void *buf) {
583 int err = 0;
584 int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
585 u16_t rlength, rtype;
586 unsigned nwords;
588 if ((bufsize < 0) || (bufsize % 2)) {
589 printf("Hermes: error in bufsize\n");
590 return -EINVAL;
593 err = hermes_docmd_wait (hw, HERMES_CMD_ACCESS, rid, NULL);
594 if (err) {
595 printf("Hermes: error hermes_docmd_wait in hermes_read_ltv\n");
596 return err;
599 err = hermes_bap_seek (hw, bap, rid, 0);
600 if (err) {
601 printf("Hermes: error hermes_bap_seek in hermes_read_ltv\n");
602 return err;
605 rlength = hermes_read_reg (hw, dreg);
607 if (!rlength) {
608 printf( "Hermes: Error rlength\n");
609 return -ENOENT;
612 rtype = hermes_read_reg (hw, dreg);
614 if (length)
615 *length = rlength;
617 if (rtype != rid) {
618 printf("hermes @ %lx: hermes_read_ltv(): rid (0x%04x)",
619 hw->iobase);
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 ",
625 hw->iobase);
626 printf("%d to %d bytes. (rid=0x%04x, len=0x%04x)\n",
627 HERMES_RECLEN_TO_BYTES (rlength), bufsize, rid,
628 rlength);
630 nwords = MIN ((unsigned) rlength - 1, bufsize / 2);
631 hermes_read_words (hw, dreg, buf, nwords);
633 return 0;
637 /*****************************************************************************
638 * hermes_write_ltv *
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;
648 int err = 0;
649 unsigned count;
651 if (length == 0) {
652 printf("Hermes: length==0 in hermes_write_ltv\n");
653 return -EINVAL;
656 err = hermes_bap_seek (hw, bap, rid, 0);
657 if (err) {
658 printf("Hermes: error hermes_bap_seek in hermes_write_ltv\n");
659 return err;
662 hermes_write_reg (hw, dreg, length);
663 hermes_write_reg (hw, dreg, rid);
665 count = length - 1;
667 hermes_write_words (hw, dreg, value, count);
669 err = hermes_docmd_wait (hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE,
670 rid, NULL);
671 if (err)
672 printf("Hermes: error hermes_docmd_wait in hermes_write_ltv\n");
674 return err;
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) {
685 u16_t rec;
686 int err;
687 rec = (word);
689 err = hermes_write_ltv (hw, bap, rid,
690 HERMES_BYTES_TO_RECLEN (sizeof (rec)), &rec);
692 if (err)
693 printf("Hermes: error in write_wordrec\n");
694 return err;
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) {
704 u16_t rec;
705 int err;
707 err = hermes_read_ltv (hw, bap, rid, sizeof (rec), NULL, &rec);
708 *word = (rec);
709 if (err)
710 printf("Hermes: Error in read_wordrec\n");
711 return err;
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) {
721 int i = 0;
722 u16_t reg;
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,
736 unsigned count) {
737 int i = 0;
739 for (i = 0; i < count; i++) {
740 hermes_write_reg (hw, off, *((u16_t *) buf + i));
745 /*****************************************************************************
746 * hermes_read_reg *
748 * Read a value from a certain register. Currently only memory mapped *
749 * registers are supported, but accessing I/O spaced registers should be *
750 * quite trivial *
751 *****************************************************************************/
752 u16_t hermes_read_reg (hermes_t * hw, u16_t off) {
753 int v = 0;
754 v = *((int *)(hw->locmem + (off << hw->reg_spacing)));
755 return (u16_t) v;
758 /*****************************************************************************
759 * hermes_write_reg *
761 * Write a value to a certain register. Currently only memory mapped *
762 * registers are supported, but accessing I/O spaced registers should be *
763 * quite trivial *
764 *****************************************************************************/
765 void hermes_write_reg (hermes_t * hw, u16_t off, u16_t val) {
766 int v = (int) val;
767 *(int *)(hw->locmem + (off << hw->reg_spacing)) = v;