panic() cleanup.
[minix.git] / drivers / orinoco / hermes.c
bloba33dd917604c514392c98d01eee3516055267f50
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 /*****************************************************************************
42 * milli_delay *
43 * *
44 * Wait msecs milli seconds *
45 *****************************************************************************/
46 PRIVATE void milli_delay(unsigned int msecs)
48 micro_delay((long)msecs * 1000);
52 /*****************************************************************************
53 * hermes_issue_cmd *
54 * *
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;
62 u16_t reg;
64 /* First wait for the command register to unbusy */
65 reg = hermes_read_reg (hw, HERMES_CMD);
66 while ((reg & HERMES_CMD_BUSY) && k) {
67 k--;
68 micro_delay (1);
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");
74 return -EBUSY;
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);
82 return 0;
85 /*****************************************************************************
86 * hermes_struct_init *
87 * *
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) {
92 hw->iobase = address;
93 hw->io_space = io_space;
94 hw->reg_spacing = reg_spacing;
95 hw->inten = 0x0;
99 /*****************************************************************************
100 * hermes_cor_reset *
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) {
106 int k, i;
107 u16_t reg;
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)) {
123 k--;
124 milli_delay (1);
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");
131 return -1;
134 return (0);
138 /*****************************************************************************
139 * hermes_present *
141 * Check whether we have access to the card. Does the SWSUPPORT0 contain the *
142 * value we put in it earlier? *
143 *****************************************************************************/
144 PRIVATE int hermes_present (hermes_t * hw) {
145 int i = hermes_read_reg (hw, HERMES_SWSUPPORT0) == HERMES_MAGIC;
146 if (!i)
147 printf("Hermes: Error, card not present?\n");
148 return i;
152 /*****************************************************************************
153 * hermes_init *
155 * Initialize the card *
156 *****************************************************************************/
157 int hermes_init (hermes_t * hw)
159 u32_t status, reg, resp0;
160 int err = 0;
161 int k;
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*/
166 hw->inten = 0x0;
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)) {
182 if (reg == 0xffff) {
183 /* Special case - the card has probably
184 * been removed, so don't wait for the
185 * timeout */
186 printf("Hermes: Card removed?\n");
187 return -ENODEV;
190 k--;
191 micro_delay (1);
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");
200 return -EBUSY;
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);
210 if (err){
211 printf("Hermes: errornr: 0x%x issueing HERMES_CMD_INIT\n",
212 err);
213 return err;
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) {
222 k--;
223 micro_delay (10);
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",
239 hw->iobase);
240 return -ETIMEDOUT;
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);
255 err = -EIO;
258 return err;
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) {
268 int err;
269 int k;
270 u16_t reg;
271 u16_t status;
273 err = hermes_issue_cmd (hw, cmd, parm0);
274 if (err) {
275 printf("hermes @ %x: Error %d issuing command.\n",
276 hw->iobase, err);
277 return err;
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) {
286 k--;
287 micro_delay (10);
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);
295 err = -ETIMEDOUT;
296 return err;
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.
303 if (resp) {
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");
317 err = -EIO;
320 return err;
324 /*****************************************************************************
325 * hermes_allocate *
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) {
335 int err = 0;
336 int k;
337 u16_t reg;
339 if ((size < HERMES_ALLOC_LEN_MIN) || (size > HERMES_ALLOC_LEN_MAX)) {
340 printf("Hermes: Invalid size\n");
341 return -EINVAL;
344 /* Issue a allocation request to the card, waiting for the command
345 * to complete */
346 err = hermes_docmd_wait (hw, HERMES_CMD_ALLOC, size, NULL);
347 if (err) {
348 printf( "Hermes: docmd_wait timeout\n");
349 return err;
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) {
357 k--;
358 micro_delay (10);
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",
365 hw->iobase);
366 return -ETIMEDOUT;
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);
377 return 0;
382 /*****************************************************************************
383 * hermes_bap_seek *
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
399 * buffer */
400 int sreg = bap ? HERMES_SELECT1 : HERMES_SELECT0;
401 int oreg = bap ? HERMES_OFFSET1 : HERMES_OFFSET0;
402 int resp0;
403 int k;
404 u16_t reg;
406 /* Check whether the offset is not too large, and whether it is a
407 * number of words. Offset can't be odd */
408 if ((offset > HERMES_BAP_OFFSET_MAX) || (offset % 2)) {
409 printf("Hermes: Offset error\n");
410 return -EINVAL;
413 /* We can't write to the offset register when the busy flag is set. If
414 * it is set, wait to automatically reset*/
415 k = HERMES_BAP_BUSY_TIMEOUT;
416 reg = hermes_read_reg (hw, oreg);
417 while ((reg & HERMES_OFFSET_BUSY) && k) {
418 k--;
419 micro_delay (1);
420 reg = hermes_read_reg (hw, oreg);
423 /* For some reason, the busy flag didn't reset automatically. Return */
424 if (reg & HERMES_OFFSET_BUSY) {
425 printf("Hermes: HERMES_OFFSET_BUSY still set, oreg: 0x%x\n",
426 reg);
427 return -ETIMEDOUT;
430 /* Now we actually set up the transfer. Write the fid in the select
431 * register, and the offset in the offset register */
432 hermes_write_reg (hw, sreg, id);
433 hermes_write_reg (hw, oreg, offset);
435 /* Wait for the BAP to be ready. This means that at first the
436 * OFFSET_BUSY bit is set by the card once we have written the values
437 * above. We wait until the card has done its internal processing and
438 * unset the OFFSET_BUSY bit */
439 k = HERMES_BAP_BUSY_TIMEOUT;
440 reg = hermes_read_reg (hw, oreg);
441 while ((reg & (HERMES_OFFSET_BUSY | HERMES_OFFSET_ERR)) && k) {
442 k--;
443 micro_delay (1);
444 reg = hermes_read_reg (hw, oreg);
447 /* Busy bit didn't reset automatically */
448 if (reg & HERMES_OFFSET_BUSY) {
449 printf("Hermes: Error with fid 0x%x. Err: 0x%x\n", id, reg);
450 return -ETIMEDOUT;
453 /* There has gone something wrong: offset is outside the buffer
454 * boundary or the fid is not correct */
455 if (reg & HERMES_OFFSET_ERR) {
456 printf("Hermes: Error with fid 0x%x. Err: 0x%x\n", id, reg);
457 return -EIO;
460 /* If we arrive here, the buffer can be accessed through the data
461 * register associated with the BAP */
462 return 0;
466 /*****************************************************************************
467 * hermes_bap_pread *
469 * Read a block of data from the chip's buffer, via the BAP. len must be *
470 * even. *
471 *****************************************************************************/
472 int hermes_bap_pread (hermes_t * hw, int bap, void *buf, unsigned len,
473 u16_t id, u16_t offset) {
474 /* The data register is the access point for the buffer made
475 * available by setting the BAP right. Which BAP does the user
476 * want to use? there are 2 of them */
477 int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
478 int err = 0;
480 /* reading (and writing) data goes a word a time, so should be even */
481 if ((len < 0) || (len % 2)) {
482 printf("Hermes: Error in length to be read\n");
483 return -EINVAL;
486 /* Set the cards internal pointer to the right fid and to the right
487 * offset */
488 err = hermes_bap_seek (hw, bap, id, offset);
489 if (err) {
490 printf("Hermes: error hermes_bap_seek in hermes_bap_pread\n");
491 return err;
493 /* Actually do the transfer. The length is divided by 2 because
494 * transfers go a word at a time as far as the card is concerned */
495 hermes_read_words (hw, dreg, buf, len / 2);
497 return err;
500 /*****************************************************************************
501 * hermes_write_words *
503 * Write a sequence of words of the buffer to the card *
504 *****************************************************************************/
505 void hermes_write_words (hermes_t * hw, int off, const void *buf,
506 unsigned count) {
507 int i = 0;
509 for (i = 0; i < count; i++) {
510 hermes_write_reg (hw, off, *((u16_t *) buf + i));
514 /*****************************************************************************
515 * hermes_bap_pwrite *
517 * Write a block of data to the chip's buffer, via the BAP. len must be even.*
518 *****************************************************************************/
519 int hermes_bap_pwrite (hermes_t * hw, int bap, const void *buf, unsigned len,
520 u16_t id, u16_t offset) {
522 /* This procedure is quite the same as the hermes_bap_read */
523 int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
524 int err = 0;
526 if ((len < 0) || (len % 2)) {
527 printf("Hermes: Error in length to be written\n");
528 return -EINVAL;
531 /* Set the cards internal pointer to the right fid and to the right
532 * offset */
533 err = hermes_bap_seek (hw, bap, id, offset);
534 if (err) {
535 printf("Hermes: hermes_bap_seek error in hermes_bap_pwrite\n");
536 return err;
540 /* Actually do the transfer */
541 hermes_write_words (hw, dreg, buf, len / 2);
543 return err;
548 /*****************************************************************************
549 * hermes_set_irqmask *
551 * Which events should the card respond to with an interrupt? *
552 *****************************************************************************/
553 int hermes_set_irqmask (hermes_t * hw, u16_t events) {
554 hw->inten = events;
555 hermes_write_reg (hw, HERMES_INTEN, events);
557 /* Compare written value with read value to check whether things
558 * succeeded */
559 if (hermes_read_reg (hw, HERMES_INTEN) != events) {
560 printf("Hermes: error setting irqmask\n");
561 return 1;
564 return (0);
567 /*****************************************************************************
568 * hermes_set_irqmask *
570 * Which events does the card respond to with an interrupt? *
571 *****************************************************************************/
572 u16_t hermes_get_irqmask (hermes_t * hw) {
573 return hermes_read_reg (hw, HERMES_INTEN);
577 /*****************************************************************************
578 * hermes_read_ltv *
580 * Read a Length-Type-Value record from the card. These are configurable *
581 * parameters in the cards firmware, like wepkey, essid, mac address etc. *
582 * Another name for them are 'rids', Resource Identifiers. See hermes_rids.h *
583 * for all available rids *
584 * If length is NULL, we ignore the length read from the card, and *
585 * read the entire buffer regardless. This is useful because some of *
586 * the configuration records appear to have incorrect lengths in *
587 * practice. *
588 *****************************************************************************/
589 int hermes_read_ltv (hermes_t * hw, int bap, u16_t rid, unsigned bufsize,
590 u16_t * length, void *buf) {
591 int err = 0;
592 int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
593 u16_t rlength, rtype;
594 unsigned nwords;
596 if ((bufsize < 0) || (bufsize % 2)) {
597 printf("Hermes: error in bufsize\n");
598 return -EINVAL;
601 err = hermes_docmd_wait (hw, HERMES_CMD_ACCESS, rid, NULL);
602 if (err) {
603 printf("Hermes: error hermes_docmd_wait in hermes_read_ltv\n");
604 return err;
607 err = hermes_bap_seek (hw, bap, rid, 0);
608 if (err) {
609 printf("Hermes: error hermes_bap_seek in hermes_read_ltv\n");
610 return err;
613 rlength = hermes_read_reg (hw, dreg);
615 if (!rlength) {
616 printf( "Hermes: Error rlength\n");
617 return -ENOENT;
620 rtype = hermes_read_reg (hw, dreg);
622 if (length)
623 *length = rlength;
625 if (rtype != rid) {
626 printf("hermes @ %lx: hermes_read_ltv(): rid (0x%04x)",
627 hw->iobase);
628 printf("does not match type (0x%04x)\n", rid, rtype);
631 if (HERMES_RECLEN_TO_BYTES (rlength) > bufsize) {
632 printf("hermes @ %lx: Truncating LTV record from ",
633 hw->iobase);
634 printf("%d to %d bytes. (rid=0x%04x, len=0x%04x)\n",
635 HERMES_RECLEN_TO_BYTES (rlength), bufsize, rid,
636 rlength);
638 nwords = MIN ((unsigned) rlength - 1, bufsize / 2);
639 hermes_read_words (hw, dreg, buf, nwords);
641 return 0;
645 /*****************************************************************************
646 * hermes_write_ltv *
648 * Write a Length-Type-Value record to the card. These are configurable *
649 * parameters in the cards firmware, like wepkey, essid, mac address etc. *
650 * Another name for them are 'rids', Resource Identifiers. See hermes_rids.h *
651 * for all available rids *
652 *****************************************************************************/
653 int hermes_write_ltv (hermes_t * hw, int bap, u16_t rid,
654 u16_t length, const void *value) {
655 int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
656 int err = 0;
657 unsigned count;
659 if (length == 0) {
660 printf("Hermes: length==0 in hermes_write_ltv\n");
661 return -EINVAL;
664 err = hermes_bap_seek (hw, bap, rid, 0);
665 if (err) {
666 printf("Hermes: error hermes_bap_seek in hermes_write_ltv\n");
667 return err;
670 hermes_write_reg (hw, dreg, length);
671 hermes_write_reg (hw, dreg, rid);
673 count = length - 1;
675 hermes_write_words (hw, dreg, value, count);
677 err = hermes_docmd_wait (hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE,
678 rid, NULL);
679 if (err)
680 printf("Hermes: error hermes_docmd_wait in hermes_write_ltv\n");
682 return err;
686 /*****************************************************************************
687 * hermes_write_wordrec *
689 * A shorthand for hermes_write_ltv when the field is 2 bytes long *
690 *****************************************************************************/
691 int hermes_write_wordrec (hermes_t * hw, int bap, u16_t rid, u16_t word) {
693 u16_t rec;
694 int err;
695 rec = (word);
697 err = hermes_write_ltv (hw, bap, rid,
698 HERMES_BYTES_TO_RECLEN (sizeof (rec)), &rec);
700 if (err)
701 printf("Hermes: error in write_wordrec\n");
702 return err;
706 /*****************************************************************************
707 * hermes_read_wordrec *
709 * A shorthand for hermes_read_ltv when the field is 2 bytes long *
710 *****************************************************************************/
711 int hermes_read_wordrec (hermes_t * hw, int bap, u16_t rid, u16_t * word) {
712 u16_t rec;
713 int err;
715 err = hermes_read_ltv (hw, bap, rid, sizeof (rec), NULL, &rec);
716 *word = (rec);
717 if (err)
718 printf("Hermes: Error in read_wordrec\n");
719 return err;
723 /*****************************************************************************
724 * hermes_read_words *
726 * Read a sequence of words from the card to the buffer *
727 *****************************************************************************/
728 void hermes_read_words (hermes_t * hw, int off, void *buf, unsigned count) {
729 int i = 0;
730 u16_t reg;
732 for (i = 0; i < count; i++) {
733 reg = hermes_read_reg (hw, off);
734 *((u16_t *) buf + i) = (u16_t) reg;
739 /*****************************************************************************
740 * hermes_read_reg *
742 * Read a value from a certain register. Currently only memory mapped *
743 * registers are supported, but accessing I/O spaced registers should be *
744 * quite trivial *
745 *****************************************************************************/
746 u16_t hermes_read_reg (hermes_t * hw, u16_t off) {
747 int v = 0;
748 v = *((int *)(hw->locmem + (off << hw->reg_spacing)));
749 return (u16_t) v;
752 /*****************************************************************************
753 * hermes_write_reg *
755 * Write a value to a certain register. Currently only memory mapped *
756 * registers are supported, but accessing I/O spaced registers should be *
757 * quite trivial *
758 *****************************************************************************/
759 void hermes_write_reg (hermes_t * hw, u16_t off, u16_t val) {
760 int v = (int) val;
761 *(int *)(hw->locmem + (off << hw->reg_spacing)) = v;