forget difference between big and small commands - obsolete with vm.
[minix.git] / drivers / orinoco / hermes.c
blob8a65b8a0351d4e793da481f47442133fe52d12f5
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"
41 PRIVATE int this_proc;
43 /*****************************************************************************
44 * milli_delay *
45 * *
46 * Wait msecs milli seconds *
47 *****************************************************************************/
48 void milli_delay(unsigned int msecs)
50 micro_delay((long)msecs * 1000);
54 /*****************************************************************************
55 * hermes_issue_cmd *
56 * *
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;
64 u16_t reg;
66 /* First wait for the command register to unbusy */
67 reg = hermes_read_reg (hw, HERMES_CMD);
68 while ((reg & HERMES_CMD_BUSY) && k) {
69 k--;
70 micro_delay (1);
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");
76 return -EBUSY;
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);
84 return 0;
87 /*****************************************************************************
88 * hermes_struct_init *
89 * *
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) {
94 hw->iobase = address;
95 hw->io_space = io_space;
96 hw->reg_spacing = reg_spacing;
97 hw->inten = 0x0;
98 this_proc = getprocnr();
102 /*****************************************************************************
103 * hermes_cor_reset *
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) {
109 int k, i;
110 u16_t reg;
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)) {
126 k--;
127 milli_delay (1);
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");
134 return -1;
137 return (0);
142 /*****************************************************************************
143 * hermes_init *
145 * Initialize the card *
146 *****************************************************************************/
147 int hermes_init (hermes_t * hw) {
148 u32_t status, reg, resp0;
149 int err = 0;
150 int k;
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*/
155 hw->inten = 0x0;
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)) {
171 if (reg == 0xffff) {
172 /* Special case - the card has probably
173 * been removed, so don't wait for the
174 * timeout */
175 printf("Hermes: Card removed?\n");
176 return -ENODEV;
179 k--;
180 micro_delay (1);
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");
189 return -EBUSY;
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);
199 if (err){
200 printf("Hermes: errornr: 0x%x issueing HERMES_CMD_INIT\n",
201 err);
202 return err;
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) {
211 k--;
212 micro_delay (10);
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",
228 hw->iobase);
229 return -ETIMEDOUT;
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);
244 err = -EIO;
247 return err;
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) {
257 int err;
258 int k;
259 u16_t reg;
260 u16_t status;
262 err = hermes_issue_cmd (hw, cmd, parm0);
263 if (err) {
264 printf("hermes @ %x: Error %d issuing command.\n",
265 hw->iobase, err);
266 return err;
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) {
275 k--;
276 micro_delay (10);
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);
284 err = -ETIMEDOUT;
285 return err;
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.
292 if (resp) {
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");
306 err = -EIO;
309 return err;
313 /*****************************************************************************
314 * hermes_allocate *
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) {
324 int err = 0;
325 int k;
326 u16_t reg;
328 if ((size < HERMES_ALLOC_LEN_MIN) || (size > HERMES_ALLOC_LEN_MAX)) {
329 printf("Hermes: Invalid size\n");
330 return -EINVAL;
333 /* Issue a allocation request to the card, waiting for the command
334 * to complete */
335 err = hermes_docmd_wait (hw, HERMES_CMD_ALLOC, size, NULL);
336 if (err) {
337 printf( "Hermes: docmd_wait timeout\n");
338 return err;
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) {
346 k--;
347 micro_delay (10);
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",
354 hw->iobase);
355 return -ETIMEDOUT;
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);
366 return 0;
371 /*****************************************************************************
372 * hermes_bap_seek *
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
388 * buffer */
389 int sreg = bap ? HERMES_SELECT1 : HERMES_SELECT0;
390 int oreg = bap ? HERMES_OFFSET1 : HERMES_OFFSET0;
391 int resp0;
392 int k;
393 u16_t reg;
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");
399 return -EINVAL;
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) {
407 k--;
408 micro_delay (1);
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",
415 reg);
416 return -ETIMEDOUT;
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) {
431 k--;
432 micro_delay (1);
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);
439 return -ETIMEDOUT;
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);
446 return -EIO;
449 /* If we arrive here, the buffer can be accessed through the data
450 * register associated with the BAP */
451 return 0;
455 /*****************************************************************************
456 * hermes_bap_pread *
458 * Read a block of data from the chip's buffer, via the BAP. len must be *
459 * even. *
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;
467 int err = 0;
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");
472 return -EINVAL;
475 /* Set the cards internal pointer to the right fid and to the right
476 * offset */
477 err = hermes_bap_seek (hw, bap, id, offset);
478 if (err) {
479 printf("Hermes: error hermes_bap_seek in hermes_bap_pread\n");
480 return err;
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);
486 return err;
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;
499 int err = 0;
501 if ((len < 0) || (len % 2)) {
502 printf("Hermes: Error in length to be written\n");
503 return -EINVAL;
506 /* Set the cards internal pointer to the right fid and to the right
507 * offset */
508 err = hermes_bap_seek (hw, bap, id, offset);
509 if (err) {
510 printf("Hermes: hermes_bap_seek error in hermes_bap_pwrite\n");
511 return err;
515 /* Actually do the transfer */
516 hermes_write_words (hw, dreg, buf, len / 2);
518 return err;
522 /*****************************************************************************
523 * hermes_present *
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;
530 if (!i)
531 printf("Hermes: Error, card not present?\n");
532 return i;
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) {
542 hw->inten = events;
543 hermes_write_reg (hw, HERMES_INTEN, events);
545 /* Compare written value with read value to check whether things
546 * succeeded */
547 if (hermes_read_reg (hw, HERMES_INTEN) != events) {
548 printf("Hermes: error setting irqmask\n");
549 return 1;
552 return (0);
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 /*****************************************************************************
566 * hermes_read_ltv *
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 *
575 * practice. *
576 *****************************************************************************/
577 int hermes_read_ltv (hermes_t * hw, int bap, u16_t rid, unsigned bufsize,
578 u16_t * length, void *buf) {
579 int err = 0;
580 int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
581 u16_t rlength, rtype;
582 unsigned nwords;
584 if ((bufsize < 0) || (bufsize % 2)) {
585 printf("Hermes: error in bufsize\n");
586 return -EINVAL;
589 err = hermes_docmd_wait (hw, HERMES_CMD_ACCESS, rid, NULL);
590 if (err) {
591 printf("Hermes: error hermes_docmd_wait in hermes_read_ltv\n");
592 return err;
595 err = hermes_bap_seek (hw, bap, rid, 0);
596 if (err) {
597 printf("Hermes: error hermes_bap_seek in hermes_read_ltv\n");
598 return err;
601 rlength = hermes_read_reg (hw, dreg);
603 if (!rlength) {
604 printf( "Hermes: Error rlength\n");
605 return -ENOENT;
608 rtype = hermes_read_reg (hw, dreg);
610 if (length)
611 *length = rlength;
613 if (rtype != rid) {
614 printf("hermes @ %lx: hermes_read_ltv(): rid (0x%04x)",
615 hw->iobase);
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 ",
621 hw->iobase);
622 printf("%d to %d bytes. (rid=0x%04x, len=0x%04x)\n",
623 HERMES_RECLEN_TO_BYTES (rlength), bufsize, rid,
624 rlength);
626 nwords = MIN ((unsigned) rlength - 1, bufsize / 2);
627 hermes_read_words (hw, dreg, buf, nwords);
629 return 0;
633 /*****************************************************************************
634 * hermes_write_ltv *
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;
644 int err = 0;
645 unsigned count;
647 if (length == 0) {
648 printf("Hermes: length==0 in hermes_write_ltv\n");
649 return -EINVAL;
652 err = hermes_bap_seek (hw, bap, rid, 0);
653 if (err) {
654 printf("Hermes: error hermes_bap_seek in hermes_write_ltv\n");
655 return err;
658 hermes_write_reg (hw, dreg, length);
659 hermes_write_reg (hw, dreg, rid);
661 count = length - 1;
663 hermes_write_words (hw, dreg, value, count);
665 err = hermes_docmd_wait (hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE,
666 rid, NULL);
667 if (err)
668 printf("Hermes: error hermes_docmd_wait in hermes_write_ltv\n");
670 return err;
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) {
681 u16_t rec;
682 int err;
683 rec = (word);
685 err = hermes_write_ltv (hw, bap, rid,
686 HERMES_BYTES_TO_RECLEN (sizeof (rec)), &rec);
688 if (err)
689 printf("Hermes: error in write_wordrec\n");
690 return err;
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) {
700 u16_t rec;
701 int err;
703 err = hermes_read_ltv (hw, bap, rid, sizeof (rec), NULL, &rec);
704 *word = (rec);
705 if (err)
706 printf("Hermes: Error in read_wordrec\n");
707 return err;
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) {
717 int i = 0;
718 u16_t reg;
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,
732 unsigned count) {
733 int i = 0;
735 for (i = 0; i < count; i++) {
736 hermes_write_reg (hw, off, *((u16_t *) buf + i));
741 /*****************************************************************************
742 * hermes_read_reg *
744 * Read a value from a certain register. Currently only memory mapped *
745 * registers are supported, but accessing I/O spaced registers should be *
746 * quite trivial *
747 *****************************************************************************/
748 u16_t hermes_read_reg (hermes_t * hw, u16_t off) {
749 int v = 0;
750 v = *((int *)(hw->locmem + (off << hw->reg_spacing)));
751 return (u16_t) v;
754 /*****************************************************************************
755 * hermes_write_reg *
757 * Write a value to a certain register. Currently only memory mapped *
758 * registers are supported, but accessing I/O spaced registers should be *
759 * quite trivial *
760 *****************************************************************************/
761 void hermes_write_reg (hermes_t * hw, u16_t off, u16_t val) {
762 int v = (int) val;
763 *(int *)(hw->locmem + (off << hw->reg_spacing)) = v;