]> Zhao Yanbai Git Server - minix.git/commitdiff
a driver for wireless pci cards with the Prism chipset from Intersil
authorBen Gras <ben@minix3.org>
Tue, 24 Jul 2007 14:49:09 +0000 (14:49 +0000)
committerBen Gras <ben@minix3.org>
Tue, 24 Jul 2007 14:49:09 +0000 (14:49 +0000)
Original version, by Stevens Le Blond and Michael Valkering.

drivers/Makefile
drivers/orinoco/INSTALL.txt [new file with mode: 0755]
drivers/orinoco/Makefile [new file with mode: 0755]
drivers/orinoco/hermes.c [new file with mode: 0755]
drivers/orinoco/hermes.h [new file with mode: 0755]
drivers/orinoco/hermes_rid.h [new file with mode: 0755]
drivers/orinoco/orinoco.c [new file with mode: 0755]
drivers/orinoco/orinoco.h [new file with mode: 0755]
etc/drivers.conf
etc/usr/rc

index 2315c894164229008c4e7d4d4c178101808643cc..d3b0ef8f4f8c56cdf133cd6ef2558007a8cea747 100644 (file)
@@ -21,6 +21,7 @@ all install depend clean:
        cd ./floppy && $(MAKE) $@
        cd ./printer && $(MAKE) $@
        cd ./rtl8139 && $(MAKE) $@
+       cd ./orinoco && $(MAKE) $@
        cd ./fxp && $(MAKE) $@
        cd ./dpeth && $(MAKE) $@
        cd ./log && $(MAKE) $@
diff --git a/drivers/orinoco/INSTALL.txt b/drivers/orinoco/INSTALL.txt
new file mode 100755 (executable)
index 0000000..b8d554a
--- /dev/null
@@ -0,0 +1,40 @@
+The driver has been tested on Minix 3.1.3, svn revision 2928:\r
+       http://derelict.cs.vu.nl/images/minix3_1_3_ide_r2928.iso.bz2\r
+\r
+\r
+To install the driver do:\r
+#sh install_script\r
+\r
+This script will patch, compile and install 2 code files in Minix:\r
+       /usr/src/services/rs/service.c\r
+       /usr/src/commands/dhcpd/devices.c\r
+       (see the docs directory for more information)\r
+Furthermore, the script will patch 1 configuration file:\r
+       /etc/drivers.conf\r
+       (adding an entry for 'orinoco')\r
+and 1 script file:\r
+       /usr/etc/rc\r
+       (adding an entry in a for-loop to start orinoco)\r
+Finally, the script will copy the orinoco driver into the drivers directory,\r
+compile and install it.\r
+\r
+When the script completes successfully, the inet.conf file has to be adjusted \r
+so that Minix will use the orinoco driver. Add an entry like:\r
+\r
+       eth0 orinoco 0 {default;};\r
+\r
+The last step is to set the essid and WEP key of the network in the boot \r
+monitor. When in the boot monitor, type:\r
+       essid=<essid>\r
+       wep=<WEP key>\r
+       save\r
+\r
+The essid is the name of the wireless network\r
+The WEP key is a string of 13 ASCII characters, being the key of the wireless \r
+network. This variable shouldn't be set when the network is not WEP protected.\r
+If the essid is not set, the card will just try connect a network quite at random\r
+\r
+N.B.: WPA is not supported\r
+N.B.: WEP seems to be buggy. At my place it works, at the VU it doesnt. So if \r
+things don't work, try without WEP\r
+\r
diff --git a/drivers/orinoco/Makefile b/drivers/orinoco/Makefile
new file mode 100755 (executable)
index 0000000..256fed9
--- /dev/null
@@ -0,0 +1,42 @@
+# Makefile for the Orinoco wireless card (Prism chipset)
+DRIVER = orinoco
+
+# directories
+u = /usr
+i = $u/include
+s = $i/sys
+m = $i/minix
+b = $i/ibm
+d = ..
+
+# programs, flags, etc.
+CC =   exec cc
+CFLAGS = -I$i $(CPROFILE)
+LDFLAGS = -i
+LIBS = -lsysutil -lsys -ltimers
+
+OBJ = orinoco.o hermes.o
+# build local binary
+all build:     $(DRIVER)
+$(DRIVER):     $(OBJ) 
+       $(CC) -o $@ $(LDFLAGS) $(OBJ) $(LIBS)
+       install -S 100kw $(DRIVER)
+
+# install with other drivers
+install:       /usr/sbin/$(DRIVER)
+/usr/sbin/$(DRIVER):   $(DRIVER)
+       install -o root -cs $? $@
+
+# clean up local files
+clean:
+       rm -f $(DRIVER) *.o *.bak 
+
+depend: 
+       mkdep "$(CC) -E $(CPPFLAGS)" *.c > .depend
+
+# Include generated dependencies.
+include .depend
+
+
+
diff --git a/drivers/orinoco/hermes.c b/drivers/orinoco/hermes.c
new file mode 100755 (executable)
index 0000000..4f904e2
--- /dev/null
@@ -0,0 +1,789 @@
+/*
+ * hermes.c
+ *
+ * This file contains the lower level access functions for Prism based 
+ * wireless cards. The file is based on hermes.c of the Linux kernel
+ *
+ * Adjusted to Minix by Stevens Le Blond <slblond@few.vu.nl> 
+ *                 and Michael Valkering <mjvalker@cs.vu.nl>
+ */
+
+/* Original copyright notices from Linux hermes.c
+ * 
+ * Copyright (C) 2000, David Gibson, Linuxcare Australia 
+ * <hermes@gibson.dropbear.id.au>
+ * Copyright (C) 2001, David Gibson, IBM <hermes@gibson.dropbear.id.au>
+ * 
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in
+ * which case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use your
+ * version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#include "hermes.h"
+#include <sys/vm.h>
+#include "assert.h"
+#include <ibm/pci.h>
+
+#include "string.h"
+int this_proc;
+
+#define MICROS_TO_TICKS(m)  (((m)*HZ/1000000)+1)       
+
+/*****************************************************************************
+ *            milli_delay                                                    *
+ *                                                                           *
+ * Wait usecs micro seconds. Clearly needs revision                          *
+ *****************************************************************************/
+static void micro_delay(unsigned long usecs)
+{
+       int i, j;
+
+       if(usecs >= 100) {
+               /* If the delay is long, we might as well use ticks */
+               tickdelay(MICROS_TO_TICKS(usecs));
+       } else {
+               /* use another type of hack :-), or a proper implementation */
+               for(i=0; i < 1000 * usecs; i++){j+=1;}
+       }
+}
+
+/*****************************************************************************
+ *            milli_delay                                                    *
+ *                                                                           *
+ * Wait msecs milli seconds                                                  *
+ *****************************************************************************/
+void milli_delay(unsigned int msecs)
+{
+       micro_delay((long)msecs * 1000);
+}
+
+
+/*****************************************************************************
+ *            hermes_issue_cmd                                               *
+ *                                                                           *
+ * Issue a command to the chip. Waiting for it to complete is the caller's   *
+ * problem. The only thing we have to do first is to see whether we can      *
+ * actually write something in the CMD register: is it unbusy?               *
+ * Returns -EBUSY if the command register is busy, 0 on success.             *
+ *****************************************************************************/
+static int hermes_issue_cmd (hermes_t * hw, u16_t cmd, u16_t param0) {
+       int k = HERMES_CMD_BUSY_TIMEOUT;
+       u16_t reg;
+
+       /* First wait for the command register to unbusy */
+       reg = hermes_read_reg (hw, HERMES_CMD);
+       while ((reg & HERMES_CMD_BUSY) && k) {
+               k--;
+               micro_delay (1);
+               reg = hermes_read_reg (hw, HERMES_CMD);
+       }
+       /* it takes too long. Bailing out */
+       if (reg & HERMES_CMD_BUSY) {
+               printf("Hermes: HERMES_CMD_BUSY timeout\n");
+               return -EBUSY;
+       }
+
+       /* write the values to the right registers */
+       hermes_write_reg (hw, HERMES_PARAM2, 0);
+       hermes_write_reg (hw, HERMES_PARAM1, 0);
+       hermes_write_reg (hw, HERMES_PARAM0, param0);
+       hermes_write_reg (hw, HERMES_CMD, cmd);
+       return 0;
+}
+
+/*****************************************************************************
+ *            hermes_struct_init                                             *
+ *                                                                           *
+ * Initialize the hermes structure fields                                    *
+ *****************************************************************************/
+void hermes_struct_init (hermes_t * hw, u32_t address,
+                   int io_space, int reg_spacing) {
+       hw->iobase = address;
+       hw->io_space = io_space;
+       hw->reg_spacing = reg_spacing;
+       hw->inten = 0x0;
+       this_proc = getprocnr();
+}
+
+
+/*****************************************************************************
+ *            hermes_cor_reset                                               *
+ *                                                                           *
+ * This is the first step in initializing the card's firmware and hardware:  *
+ * write HERMES_PCI_COR_MASK to the Configuration Option Register            *
+ *****************************************************************************/
+int hermes_cor_reset (hermes_t *hw) {
+       int k, i;
+       u16_t reg;
+
+       /* Assert the reset until the card notice */
+       hermes_write_reg (hw, HERMES_PCI_COR, HERMES_PCI_COR_MASK);
+
+       milli_delay (HERMES_PCI_COR_ONT);
+
+       /* Give time for the card to recover from this hard effort */
+       hermes_write_reg (hw, HERMES_PCI_COR, 0x0000);
+
+       milli_delay (HERMES_PCI_COR_OFFT);
+
+       /* The card is ready when it's no longer busy */
+       k = HERMES_PCI_COR_BUSYT;
+       reg = hermes_read_reg (hw, HERMES_CMD);
+       while (k && (reg & HERMES_CMD_BUSY)) {
+               k--;
+               milli_delay (1);
+               reg = hermes_read_reg (hw, HERMES_CMD);
+       }
+
+       /* Did we timeout ? */
+       if (reg & HERMES_CMD_BUSY) {
+               printf ("Busy timeout after resetting the COR\n");
+               return -1;
+       }
+
+       return (0);
+}
+
+
+
+/*****************************************************************************
+ *            hermes_init                                                    *
+ *                                                                           *
+ * Initialize the card                                                       *
+ *****************************************************************************/
+int hermes_init (hermes_t * hw) {
+       u32_t status, reg, resp0;
+       int err = 0;
+       int k;
+
+       /* We don't want to be interrupted while resetting the chipset. By 
+        * setting the control mask for hardware interrupt generation to 0,
+        * we won't be disturbed*/
+       hw->inten = 0x0;
+       hermes_write_reg (hw, HERMES_INTEN, 0);
+
+       /* Acknowledge any pending events waiting for acknowledgement. We 
+        * assume there won't be any important to take care off */
+       hermes_write_reg (hw, HERMES_EVACK, 0xffff);
+
+       /* Normally it's a "can't happen" for the command register to
+        * be busy when we go to issue a command because we are
+        * serializing all commands.  However we want to have some
+        * chance of resetting the card even if it gets into a stupid
+        * state, so we actually wait to see if the command register
+        * will unbusy itself here. */
+       k = HERMES_CMD_BUSY_TIMEOUT;
+       reg = hermes_read_reg (hw, HERMES_CMD);
+       while (k && (reg & HERMES_CMD_BUSY)) {
+               if (reg == 0xffff) {
+                       /* Special case - the card has probably 
+                        *  been removed, so don't wait for the 
+                        *  timeout */
+                       printf("Hermes: Card removed?\n");
+                       return -ENODEV;
+               }
+
+               k--;
+               micro_delay (1);
+               reg = hermes_read_reg (hw, HERMES_CMD);
+       }
+
+       /* No need to explicitly handle the timeout - if we've timed
+        * out hermes_issue_cmd() will probably return -EBUSY below.
+        * But i check to be sure :-) */
+       if (reg & HERMES_CMD_BUSY) {
+               printf("Hermes: Timeout waiting for the CMD_BUSY to unset\n");
+               return -EBUSY;
+       }
+
+       /* According to the documentation, EVSTAT may contain
+        * obsolete event occurrence information.  We have to acknowledge
+        * it by writing EVACK. */
+       reg = hermes_read_reg (hw, HERMES_EVSTAT);
+       hermes_write_reg (hw, HERMES_EVACK, reg);
+
+       err = hermes_issue_cmd (hw, HERMES_CMD_INIT, 0);
+       if (err){
+               printf("Hermes: errornr: 0x%x issueing HERMES_CMD_INIT\n",
+                        err);
+               return err;
+       }
+
+       /* here we start waiting for the above command,CMD_INIT, to complete.
+        * Completion is noticeable when the HERMES_EV_CMD bit in the 
+        * HERMES_EVSTAT register is set to 1 */
+       reg = hermes_read_reg (hw, HERMES_EVSTAT);
+       k = HERMES_CMD_INIT_TIMEOUT;
+       while ((!(reg & HERMES_EV_CMD)) && k) {
+               k--;
+               micro_delay (10);
+               reg = hermes_read_reg (hw, HERMES_EVSTAT);
+       }
+
+
+       /* the software support register 0 (there are 3) is filled with a 
+        * magic number. With this one can test the availability of the card */
+       hermes_write_reg (hw, HERMES_SWSUPPORT0, HERMES_MAGIC);
+
+       if (!hermes_present (hw)) {
+               printf("Hermes: Card not present?: got mag. nr.0x%x\n",
+                        hermes_read_reg (hw, HERMES_SWSUPPORT0));
+       }
+
+       if (!(reg & HERMES_EV_CMD)) {
+               printf("hermes @ %x: Timeout waiting for card to reset\n",
+                       hw->iobase);
+               return -ETIMEDOUT;
+       }
+
+       status = hermes_read_reg (hw, HERMES_STATUS);
+       resp0 = hermes_read_reg (hw, HERMES_RESP0);
+
+       /* after having issued the command above, the completion set a bit in 
+        * the EVSTAT register. This has to be acknowledged, as follows */
+       hermes_write_reg (hw, HERMES_EVACK, HERMES_EV_CMD);
+
+       /* Was the status, the result of the issued command, ok? */
+       /* The expression below should be zero. Non-zero means an error */
+       if (status & HERMES_STATUS_RESULT) {
+               printf("Hermes:Result of INIT_CMD wrong.error value: 0x%x\n",
+                       (status & HERMES_STATUS_RESULT) >> 8);
+               err = -EIO;
+       }
+
+       return err;
+}
+
+/*****************************************************************************
+ *            hermes_docmd_wait                                              *
+ *                                                                           *
+ * Issue a command to the chip, and (busy) wait for it to complete.          *
+ *****************************************************************************/
+int hermes_docmd_wait (hermes_t * hw, u16_t cmd, u16_t parm0,
+                  hermes_response_t * resp) {
+       int err;
+       int k;
+       u16_t reg;
+       u16_t status;
+
+       err = hermes_issue_cmd (hw, cmd, parm0);
+       if (err) {
+               printf("hermes @ %x: Error %d issuing command.\n",
+                        hw->iobase, err);
+               return err;
+       }
+
+       /* Reads the Event status register. When the command has completed,
+        * the fourth bit in the HERMES_EVSTAT register is a 1. We will be
+        * waiting for that to happen */
+       reg = hermes_read_reg (hw, HERMES_EVSTAT);
+       k = HERMES_CMD_COMPL_TIMEOUT;
+       while ((!(reg & HERMES_EV_CMD)) && k) {
+               k--;
+               micro_delay (10);
+               reg = hermes_read_reg (hw, HERMES_EVSTAT);
+       }
+
+       /* check for a timeout: has the command still not completed? */
+       if (!(reg & HERMES_EV_CMD)) {
+               printf("hermes @ %x: Timeout waiting for command \
+               completion.\n", hw->iobase);
+               err = -ETIMEDOUT;
+               return err;
+       }
+
+       status = hermes_read_reg (hw, HERMES_STATUS);
+       /* some commands result in results residing in response registers.
+        * They have to be read before the acknowledgement below.
+        */
+       if (resp) {
+               resp->status = status;
+               resp->resp0 = hermes_read_reg (hw, HERMES_RESP0);
+               resp->resp1 = hermes_read_reg (hw, HERMES_RESP1);
+               resp->resp2 = hermes_read_reg (hw, HERMES_RESP2);
+       }
+
+       /* After issueing a Command, the card expects an Acknowledgement */
+       hermes_write_reg (hw, HERMES_EVACK, HERMES_EV_CMD);
+
+       /* check whether there has been a valid value in the Status register. 
+        * the high order bits should have at least some value */
+       if (status & HERMES_STATUS_RESULT) {
+               printf("Hermes: EIO\n");
+               err = -EIO;
+       }
+
+       return err;
+}
+
+
+/*****************************************************************************
+ *            hermes_allocate                                                *
+ *                                                                           *
+ * Allocate bufferspace in the card, which will be then available for        *
+ * writing by the host, TX buffers. The card will try to find enough memory  *
+ * (creating a list of 128 byte blocks) and will return a pointer to the     *
+ * first block. This pointer is a pointer to the frame identifier (fid),     *
+ * holding information and data of the buffer. The fid is like a file        *
+ * descriptor, a value indicating some resource                              *
+ *****************************************************************************/
+int hermes_allocate (hermes_t * hw, u16_t size, u16_t * fid) {
+       int err = 0;
+       int k;
+       u16_t reg;
+
+       if ((size < HERMES_ALLOC_LEN_MIN) || (size > HERMES_ALLOC_LEN_MAX))     {
+               printf("Hermes: Invalid size\n");
+               return -EINVAL;
+       }
+
+       /* Issue a allocation request to the card, waiting for the command 
+        * to complete */
+       err = hermes_docmd_wait (hw, HERMES_CMD_ALLOC, size, NULL);
+       if (err) {
+               printf( "Hermes: docmd_wait timeout\n");
+               return err;
+       }
+
+       /* Read the status event register to know whether the allocation
+        * succeeded. The HERMES_EV_ALLOC bit should be set */
+       reg = hermes_read_reg (hw, HERMES_EVSTAT);
+       k = HERMES_ALLOC_COMPL_TIMEOUT;
+       while ((!(reg & HERMES_EV_ALLOC)) && k) {
+               k--;
+               micro_delay (10);
+               reg = hermes_read_reg (hw, HERMES_EVSTAT);
+       }
+
+       /* tired of waiting to complete. Abort. */
+       if (!(reg & HERMES_EV_ALLOC)) {
+               printf("hermes @ %x:Timeout waiting for frame allocation\n",
+                        hw->iobase);
+               return -ETIMEDOUT;
+       }
+
+       /* When we come here, everything has gone well. The pointer to the
+        * fid is in the ALLOCFID register. This fid is later on used
+        * to access this buffer */
+       *fid = hermes_read_reg (hw, HERMES_ALLOCFID);
+
+       /* always acknowledge the receipt of an event */
+       hermes_write_reg (hw, HERMES_EVACK, HERMES_EV_ALLOC);
+
+       return 0;
+}
+
+
+
+/*****************************************************************************
+ *            hermes_bap_seek                                                *
+ *                                                                           *
+ * Set up a Buffer Access Path (BAP) to read a particular chunk of data      *
+ * from card's internal buffer. Setting a bap register is like doing a fseek *
+ * system call: setting an internal pointer to the right place in a buffer   *
+ *****************************************************************************/
+static int hermes_bap_seek (hermes_t * hw, int bap, u16_t id, u16_t offset) {
+
+       /* There are 2 BAPs. This can be used to use the access buffers
+        * concurrently: 1 for writing in the TX buffer and 1 for reading
+        * a RX buffer in case of an RX interrupt.
+        * The BAP consists of 2 registers, together with which one can
+        * point to a single byte in the required buffer (additionally 
+        * there is a third register, but that one is not used in this 
+        * function, the data register). With the SELECT register one chooses 
+        * the fid, with the OFFSET register one chooses the offset in the fid 
+        * buffer */
+       int sreg = bap ? HERMES_SELECT1 : HERMES_SELECT0;
+       int oreg = bap ? HERMES_OFFSET1 : HERMES_OFFSET0;
+       int resp0;
+       int k;
+       u16_t reg;
+
+       /* Check whether the offset is not too large, and whether it is a
+        * number of words. Offset can't be odd */
+       if ((offset > HERMES_BAP_OFFSET_MAX) || (offset % 2)) {
+               printf("Hermes: Offset error\n");
+               return -EINVAL;
+       }
+
+       /* We can't write to the offset register when the busy flag is set. If 
+        * it is set, wait to automatically reset*/
+       k = HERMES_BAP_BUSY_TIMEOUT;
+       reg = hermes_read_reg (hw, oreg);
+       while ((reg & HERMES_OFFSET_BUSY) && k) {
+               k--;
+               micro_delay (1);
+               reg = hermes_read_reg (hw, oreg);
+       }
+
+       /* For some reason, the busy flag didn't reset automatically. Return */
+       if (reg & HERMES_OFFSET_BUSY) {
+               printf("Hermes: HERMES_OFFSET_BUSY still set, oreg: 0x%x\n",
+                                reg);
+               return -ETIMEDOUT;
+       }
+
+       /* Now we actually set up the transfer. Write the fid in the select 
+        * register, and the offset in the offset register */
+       hermes_write_reg (hw, sreg, id);
+       hermes_write_reg (hw, oreg, offset);
+
+       /* Wait for the BAP to be ready. This means that at first the 
+        * OFFSET_BUSY bit is set by the card once we have written the values 
+        * above. We wait until the card has done its internal processing and 
+        * unset the OFFSET_BUSY bit */
+       k = HERMES_BAP_BUSY_TIMEOUT;
+       reg = hermes_read_reg (hw, oreg);
+       while ((reg & (HERMES_OFFSET_BUSY | HERMES_OFFSET_ERR)) && k) {
+               k--;
+               micro_delay (1);
+               reg = hermes_read_reg (hw, oreg);
+       }
+
+       /* Busy bit didn't reset automatically */
+       if (reg & HERMES_OFFSET_BUSY) {
+               printf("Hermes: Error with fid 0x%x. Err: 0x%x\n", id, reg);
+               return -ETIMEDOUT;
+       }
+
+       /* There has gone something wrong: offset is outside the buffer 
+        * boundary or the fid is not correct */
+       if (reg & HERMES_OFFSET_ERR) {
+               printf("Hermes: Error with fid 0x%x. Err: 0x%x\n", id, reg);
+               return -EIO;
+       }
+
+       /* If we arrive here, the buffer can be accessed through the data 
+        * register associated with the BAP */
+       return 0;
+}
+
+
+/*****************************************************************************
+ *            hermes_bap_pread                                               *
+ *                                                                           *
+ * Read a block of data from the chip's buffer, via the BAP. len must be     *
+ * even.                                                                     *
+ *****************************************************************************/
+int hermes_bap_pread (hermes_t * hw, int bap, void *buf, unsigned len,
+                 u16_t id, u16_t offset) {
+       /* The data register is the access point for the buffer made
+        * available by setting the BAP right. Which BAP does the user 
+        * want to use? there are 2 of them */
+       int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
+       int err = 0;
+
+       /* reading (and writing) data goes a word a time, so should be even */
+       if ((len < 0) || (len % 2))     {
+               printf("Hermes: Error in length to be read\n");
+               return -EINVAL;
+       }
+
+       /* Set the cards internal pointer to the right fid and to the right
+        * offset */
+       err = hermes_bap_seek (hw, bap, id, offset);
+       if (err) {
+               printf("Hermes: error hermes_bap_seek in hermes_bap_pread\n");
+               return err;
+       }
+       /* Actually do the transfer. The length is divided by 2 because
+        * transfers go a word at a time as far as the card is concerned */
+       hermes_read_words (hw, dreg, buf, len / 2);
+
+       return err;
+}
+
+/*****************************************************************************
+ *            hermes_bap_pwrite                                              *
+ *                                                                           *
+ * Write a block of data to the chip's buffer, via the BAP. len must be even.*
+ *****************************************************************************/
+int hermes_bap_pwrite (hermes_t * hw, int bap, const void *buf, unsigned len,
+                  u16_t id, u16_t offset) {
+
+       /* This procedure is quite the same as the hermes_bap_read */
+       int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
+       int err = 0;
+
+       if ((len < 0) || (len % 2)) {
+               printf("Hermes: Error in length to be written\n");
+               return -EINVAL;
+       }
+
+       /* Set the cards internal pointer to the right fid and to the right
+        * offset */
+       err = hermes_bap_seek (hw, bap, id, offset);
+       if (err) {
+               printf("Hermes: hermes_bap_seek error in hermes_bap_pwrite\n");
+               return err;
+
+       }
+
+       /* Actually do the transfer */
+       hermes_write_words (hw, dreg, buf, len / 2);
+
+       return err;
+}
+
+
+/*****************************************************************************
+ *            hermes_present                                                 *
+ *                                                                           *
+ * Check whether we have access to the card. Does the SWSUPPORT0 contain the *
+ * value we put in it earlier?                                               *
+ *****************************************************************************/
+int hermes_present (hermes_t * hw) {
+       int i = hermes_read_reg (hw, HERMES_SWSUPPORT0) == HERMES_MAGIC;
+       if (!i)
+               printf("Hermes: Error, card not present?\n");
+       return i;
+}
+
+
+/*****************************************************************************
+ *            hermes_set_irqmask                                             *
+ *                                                                           *
+ * Which events should the card respond to with an interrupt?                *
+ *****************************************************************************/
+int hermes_set_irqmask (hermes_t * hw, u16_t events) {
+       hw->inten = events;
+       hermes_write_reg (hw, HERMES_INTEN, events);
+       
+       /* Compare written value with read value to check whether things 
+        * succeeded */
+       if (hermes_read_reg (hw, HERMES_INTEN) != events) {
+               printf("Hermes: error setting irqmask\n");
+               return 1;
+       }
+
+       return (0);
+}
+
+/*****************************************************************************
+ *            hermes_set_irqmask                                             *
+ *                                                                           *
+ * Which events does the card respond to with an interrupt?                  *
+ *****************************************************************************/
+u16_t hermes_get_irqmask (hermes_t * hw) {
+       return hermes_read_reg (hw, HERMES_INTEN);
+}
+
+
+/*****************************************************************************
+ *            hermes_read_ltv                                                *
+ *                                                                           *
+ * Read a Length-Type-Value record from the card. These are configurable     *
+ * parameters in the cards firmware, like wepkey, essid, mac address etc.    *
+ * Another name for them are 'rids', Resource Identifiers. See hermes_rids.h *
+ * for all available rids                                                    *
+ * If length is NULL, we ignore the length read from the card, and           *
+ * read the entire buffer regardless. This is useful because some of         *
+ * the configuration records appear to have incorrect lengths in             *
+ * practice.                                                                 *
+ *****************************************************************************/
+int hermes_read_ltv (hermes_t * hw, int bap, u16_t rid, unsigned bufsize,
+                u16_t * length, void *buf) {
+       int err = 0;
+       int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
+       u16_t rlength, rtype;
+       unsigned nwords;
+
+       if ((bufsize < 0) || (bufsize % 2))     {
+               printf("Hermes: error in bufsize\n");
+               return -EINVAL;
+       }
+
+       err = hermes_docmd_wait (hw, HERMES_CMD_ACCESS, rid, NULL);
+       if (err) {
+               printf("Hermes: error hermes_docmd_wait in hermes_read_ltv\n");
+               return err;
+       }
+
+       err = hermes_bap_seek (hw, bap, rid, 0);
+       if (err) {
+               printf("Hermes: error hermes_bap_seek in hermes_read_ltv\n");
+               return err;
+       }
+
+       rlength = hermes_read_reg (hw, dreg);
+
+       if (!rlength) {
+               printf( "Hermes: Error rlength\n");
+               return -ENOENT;
+       }
+
+       rtype = hermes_read_reg (hw, dreg);
+
+       if (length)
+               *length = rlength;
+
+       if (rtype != rid) {
+               printf("hermes @ %lx: hermes_read_ltv(): rid  (0x%04x)",
+                       hw->iobase);
+               printf("does not match type (0x%04x)\n", rid, rtype);
+       }
+
+       if (HERMES_RECLEN_TO_BYTES (rlength) > bufsize) {
+               printf("hermes @ %lx: Truncating LTV record from ",
+                       hw->iobase);
+               printf("%d to %d bytes. (rid=0x%04x, len=0x%04x)\n",
+                       HERMES_RECLEN_TO_BYTES (rlength), bufsize, rid,
+                       rlength);
+       }
+       nwords = MIN ((unsigned) rlength - 1, bufsize / 2);
+       hermes_read_words (hw, dreg, buf, nwords);
+
+       return 0;
+}
+
+
+/*****************************************************************************
+ *            hermes_write_ltv                                               *
+ *                                                                           *
+ * Write a Length-Type-Value record to the card. These are configurable      *
+ * parameters in the cards firmware, like wepkey, essid, mac address etc.    *
+ * Another name for them are 'rids', Resource Identifiers. See hermes_rids.h *
+ * for all available rids                                                    *
+ *****************************************************************************/
+int hermes_write_ltv (hermes_t * hw, int bap, u16_t rid,
+                 u16_t length, const void *value) {
+       int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
+       int err = 0;
+       unsigned count;
+
+       if (length == 0) {
+               printf("Hermes: length==0 in hermes_write_ltv\n");
+               return -EINVAL;
+       }
+
+       err = hermes_bap_seek (hw, bap, rid, 0);
+       if (err) {
+               printf("Hermes: error hermes_bap_seek in hermes_write_ltv\n");
+               return err;
+       }
+
+       hermes_write_reg (hw, dreg, length);
+       hermes_write_reg (hw, dreg, rid);
+
+       count = length - 1;
+
+       hermes_write_words (hw, dreg, value, count);
+
+       err = hermes_docmd_wait (hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE,
+                                rid, NULL);
+       if (err)
+               printf("Hermes: error hermes_docmd_wait in hermes_write_ltv\n");
+
+       return err;
+}
+
+
+/*****************************************************************************
+ *            hermes_write_wordrec                                           *
+ *                                                                           *
+ * A shorthand for hermes_write_ltv when the field is 2 bytes long           *
+ *****************************************************************************/
+int hermes_write_wordrec (hermes_t * hw, int bap, u16_t rid, u16_t word) {
+
+       u16_t rec;
+       int err;
+       rec = (word);
+
+       err = hermes_write_ltv (hw, bap, rid,
+                               HERMES_BYTES_TO_RECLEN (sizeof (rec)), &rec);
+
+       if (err)
+               printf("Hermes: error in write_wordrec\n");
+       return err;
+}
+
+
+/*****************************************************************************
+ *            hermes_read_wordrec                                            *
+ *                                                                           *
+ * A shorthand for hermes_read_ltv when the field is 2 bytes long            *
+ *****************************************************************************/
+int hermes_read_wordrec (hermes_t * hw, int bap, u16_t rid, u16_t * word) {
+       u16_t rec;
+       int err;
+
+       err = hermes_read_ltv (hw, bap, rid, sizeof (rec), NULL, &rec);
+       *word = (rec);
+       if (err)
+               printf("Hermes: Error in read_wordrec\n");
+       return err;
+}
+
+
+/*****************************************************************************
+ *            hermes_read_words                                              *
+ *                                                                           *
+ * Read a sequence of words from the card to the buffer                      *
+ *****************************************************************************/
+void hermes_read_words (hermes_t * hw, int off, void *buf, unsigned count) {
+       int i = 0;
+       u16_t reg;
+
+       for (i = 0; i < count; i++)     {
+               reg = hermes_read_reg (hw, off);
+               *((u16_t *) buf + i) = (u16_t) reg;
+       }
+}
+
+/*****************************************************************************
+ *            hermes_write_words                                             *
+ *                                                                           *
+ * Write a sequence of words of the buffer to the card                       *
+ *****************************************************************************/
+void hermes_write_words (hermes_t * hw, int off, const void *buf, 
+                                               unsigned count) {
+       int i = 0;
+
+       for (i = 0; i < count; i++)     {
+               hermes_write_reg (hw, off, *((u16_t *) buf + i));
+       }
+}
+
+
+/*****************************************************************************
+ *            hermes_read_reg                                                *
+ *                                                                           *
+ * Read a value from a certain register. Currently only memory mapped        *
+ * registers are supported, but accessing I/O spaced registers should be     *
+ * quite trivial                                                             *
+ *****************************************************************************/
+u16_t hermes_read_reg (hermes_t * hw, u16_t off) {
+       int v = 0;
+       v = *((int *)(hw->locmem + (off << hw->reg_spacing)));
+       return (u16_t) v;
+}
+
+/*****************************************************************************
+ *            hermes_write_reg                                               *
+ *                                                                           *
+ * Write a value to a certain register. Currently only memory mapped         *
+ * registers are supported, but accessing I/O spaced registers should be     *
+ * quite trivial                                                             *
+ *****************************************************************************/
+void hermes_write_reg (hermes_t * hw, u16_t off, u16_t val) {
+       int v = (int) val;      
+       *(int *)(hw->locmem + (off << hw->reg_spacing)) = v;
+}
+
diff --git a/drivers/orinoco/hermes.h b/drivers/orinoco/hermes.h
new file mode 100755 (executable)
index 0000000..0d56075
--- /dev/null
@@ -0,0 +1,339 @@
+/*
+ * hermes.h
+ *
+ * Constants, structures and prototypes needed for the low level access of 
+ * Prism cards. The hermes.h file was used as the basis of this file
+ *
+ * Adjusted to Minix by Stevens Le Blond <slblond@few.vu.nl> 
+ *                 and Michael Valkering <mjvalker@cs.vu.nl>
+ */
+
+/* Original copyright notices from hermes.h of the Linux kernel 
+ *
+ * Copyright (C) 2000, David Gibson, Linuxcare Australia 
+ * <hermes@gibson.dropbear.id.au>
+ * Portions taken from hfa384x.h, Copyright (C) 1999 AbsoluteValue Systems, Inc. 
+ * All Rights Reserved.
+ * This file distributed under the GPL, version 2.
+ */
+#ifndef _HERMES_H
+#define _HERMES_H
+
+#include "../drivers.h"
+#include <net/gen/ether.h>
+#include <net/gen/eth_io.h>
+#include <net/hton.h>
+#include <stdarg.h>
+
+/*****************************************************************************
+ *              HERMES CONSTANTS                                             *
+ *****************************************************************************/
+#define                HERMES_ALLOC_LEN_MIN            (4)
+#define                HERMES_ALLOC_LEN_MAX            (2400)
+#define                HERMES_LTV_LEN_MAX              (34)
+#define                HERMES_BAP_DATALEN_MAX          (4096)
+#define                HERMES_BAP_OFFSET_MAX           (4096)
+#define                HERMES_PORTID_MAX               (7)
+#define                HERMES_NUMPORTS_MAX             (HERMES_PORTID_MAX+1)
+#define                HERMES_PDR_LEN_MAX              (260)   
+#define                HERMES_PDA_RECS_MAX             (200)   
+#define                HERMES_PDA_LEN_MAX              (1024)  
+#define                HERMES_SCANRESULT_MAX           (35)
+#define                HERMES_CHINFORESULT_MAX         (8)
+#define                HERMES_MAX_MULTICAST            (16)
+#define                HERMES_MAGIC                    (0x69ff)
+
+/* 
+ * Hermes register offsets
+ */
+#define                HERMES_CMD                      (0x00)
+#define                HERMES_PARAM0                   (0x02)
+#define                HERMES_PARAM1                   (0x04)
+#define                HERMES_PARAM2                   (0x06)
+#define                HERMES_STATUS                   (0x08)
+#define                HERMES_RESP0                    (0x0A)
+#define                HERMES_RESP1                    (0x0C)
+#define                HERMES_RESP2                    (0x0E)
+#define                HERMES_INFOFID                  (0x10)
+#define                HERMES_RXFID                    (0x20)
+#define                HERMES_ALLOCFID                 (0x22)
+#define                HERMES_TXCOMPLFID               (0x24)
+#define                HERMES_SELECT0                  (0x18)
+#define                HERMES_OFFSET0                  (0x1C)
+#define                HERMES_DATA0                    (0x36)
+#define                HERMES_SELECT1                  (0x1A)
+#define                HERMES_OFFSET1                  (0x1E)
+#define                HERMES_DATA1                    (0x38)
+#define                HERMES_EVSTAT                   (0x30)
+#define                HERMES_INTEN                    (0x32)
+#define                HERMES_EVACK                    (0x34)
+#define                HERMES_CONTROL                  (0x14)
+#define                HERMES_SWSUPPORT0               (0x28)
+#define                HERMES_SWSUPPORT1               (0x2A)
+#define                HERMES_SWSUPPORT2               (0x2C)
+#define                HERMES_AUXPAGE                  (0x3A)
+#define                HERMES_AUXOFFSET                (0x3C)
+#define                HERMES_AUXDATA                  (0x3E)
+
+/* 
+ * CMD register bitmasks
+ */
+#define                HERMES_CMD_BUSY                 (0x8000)
+#define                HERMES_CMD_AINFO                (0x7f00)
+#define                HERMES_CMD_MACPORT              (0x0700)
+#define                HERMES_CMD_RECL                 (0x0100)
+#define                HERMES_CMD_WRITE                (0x0100)
+#define                HERMES_CMD_PROGMODE             (0x0300)
+#define                HERMES_CMD_CMDCODE              (0x003f)
+
+/* 
+ * STATUS register bitmasks
+ */
+#define                HERMES_STATUS_RESULT            (0x7f00)
+#define                HERMES_STATUS_CMDCODE           (0x003f)
+
+/* 
+ * OFFSET register bitmasks
+ */
+#define                HERMES_OFFSET_BUSY              (0x8000)
+#define                HERMES_OFFSET_ERR               (0x4000)
+#define                HERMES_OFFSET_DATAOFF           (0x0ffe)
+
+/* 
+ * Event register bitmasks (INTEN, EVSTAT, EVACK)
+ */
+#define                HERMES_EV_TICK                  (0x8000)
+#define                HERMES_EV_WTERR                 (0x4000)
+#define                HERMES_EV_INFDROP               (0x2000)
+#define                HERMES_EV_INFO                  (0x0080)
+#define                HERMES_EV_DTIM                  (0x0020)
+#define                HERMES_EV_CMD                   (0x0010)
+#define                HERMES_EV_ALLOC                 (0x0008)
+#define                HERMES_EV_TXEXC                 (0x0004)
+#define                HERMES_EV_TX                    (0x0002)
+#define                HERMES_EV_RX                    (0x0001)
+
+/*
+ * COR reset options 
+ */
+#define                HERMES_PCI_COR                  (0x26)
+#define                HERMES_PCI_COR_MASK             (0x0080)
+/* It appears that the card needs quite some time to recover: */
+#define                HERMES_PCI_COR_ONT              (250) /* ms */
+#define                HERMES_PCI_COR_OFFT             (500) /* ms */
+#define                HERMES_PCI_COR_BUSYT            (500) /* ms */
+/* 
+ * Command codes
+ */
+/*--- Controller Commands --------------------------*/
+#define                HERMES_CMD_INIT                 (0x0000)
+#define                HERMES_CMD_ENABLE               (0x0001)
+#define                HERMES_CMD_DISABLE              (0x0002)
+#define                HERMES_CMD_DIAG                 (0x0003)
+
+/*--- Buffer Mgmt Commands --------------------------*/
+#define                HERMES_CMD_ALLOC                (0x000A)
+#define                HERMES_CMD_TX                   (0x000B)
+#define                HERMES_CMD_CLRPRST              (0x0012)
+
+/*--- Regulate Commands --------------------------*/
+#define                HERMES_CMD_NOTIFY               (0x0010)
+#define                HERMES_CMD_INQUIRE              (0x0011)
+
+/*--- Configure Commands --------------------------*/
+#define                HERMES_CMD_ACCESS               (0x0021)
+#define                HERMES_CMD_DOWNLD               (0x0022)
+
+/*--- Debugging Commands -----------------------------*/
+#define        HERMES_CMD_MONITOR              (0x0038)
+#define                HERMES_MONITOR_ENABLE           (0x000b)
+#define                HERMES_MONITOR_DISABLE          (0x000f)
+
+/* 
+ * Frame structures and constants
+ */
+
+#define        HERMES_DESCRIPTOR_OFFSET        (0)
+#define        HERMES_802_11_OFFSET            (14)
+#define        HERMES_802_3_OFFSET             (14+32)
+#define        HERMES_802_2_OFFSET             (14+32+14)
+
+struct hermes_rx_descriptor
+{
+       u16_t status;
+       u16_t time_lefthalf;
+       u16_t time_righthalf;
+       u8_t silence;
+       u8_t signal;
+       u8_t rate;
+       u8_t rxflow;
+       u16_t reserved1;
+       u16_t reserved2;
+};
+
+#define HERMES_RXSTAT_ERR              (0x0003)
+#define        HERMES_RXSTAT_BADCRC            (0x0001)
+#define        HERMES_RXSTAT_UNDECRYPTABLE     (0x0002)
+#define        HERMES_RXSTAT_MACPORT           (0x0700)
+#define HERMES_RXSTAT_PCF              (0x1000)        
+#define        HERMES_RXSTAT_MSGTYPE           (0xE000)
+#define        HERMES_RXSTAT_1042              (0x2000)        /* RFC-1042 frame */
+#define        HERMES_RXSTAT_TUNNEL            (0x4000)        /* bridge-tunnel
+                                                        * encoded frame */
+#define        HERMES_RXSTAT_WMP               (0x6000)        /* Wavelan-II
+                                                        * Management
+                                                        * Protocol frame */
+
+struct hermes_tx_descriptor
+{
+       u16_t status;
+       u16_t reserved1;
+       u16_t reserved2;
+       u16_t sw_support_lefthalf;
+       u16_t sw_support_righthalf;
+       u8_t retry_count;
+       u8_t tx_rate;
+       u16_t tx_control;
+};
+
+#define HERMES_TXSTAT_RETRYERR         (0x0001)
+#define HERMES_TXSTAT_AGEDERR          (0x0002)
+#define HERMES_TXSTAT_DISCON           (0x0004)
+#define HERMES_TXSTAT_FORMERR          (0x0008)
+
+#define HERMES_TXCTRL_TX_OK            (0x0002)        
+#define HERMES_TXCTRL_TX_EX            (0x0004)        
+#define HERMES_TXCTRL_802_11           (0x0008)        
+#define HERMES_TXCTRL_ALT_RTRY         (0x0020)
+
+/* Inquiry constants and data types */
+
+#define HERMES_INQ_TALLIES             (0xF100)
+#define HERMES_INQ_SCAN                        (0xF101)
+#define HERMES_INQ_LINKSTATUS          (0xF200)
+
+
+/* The tallies are retrieved, but these fields are not processed until now */
+struct hermes_tallies_frame
+{
+       u16_t TxUnicastFrames;
+       u16_t TxMulticastFrames;
+       u16_t TxFragments;
+       u16_t TxUnicastOctets;
+       u16_t TxMulticastOctets;
+       u16_t TxDeferredTransmissions;
+       u16_t TxSingleRetryFrames;
+       u16_t TxMultipleRetryFrames;
+       u16_t TxRetryLimitExceeded;
+       u16_t TxDiscards;
+       u16_t RxUnicastFrames;
+       u16_t RxMulticastFrames;
+       u16_t RxFragments;
+       u16_t RxUnicastOctets;
+       u16_t RxMulticastOctets;
+       u16_t RxFCSErrors;
+       u16_t RxDiscards_NoBuffer;
+       u16_t TxDiscardsWrongSA;
+       u16_t RxWEPUndecryptable;
+       u16_t RxMsgInMsgFragments;
+       u16_t RxMsgInBadMsgFragments;
+       u16_t RxDiscards_WEPICVError;
+       u16_t RxDiscards_WEPExcluded;
+};
+
+#define HERMES_LINKSTATUS_NOT_CONNECTED   (0x0000)
+#define HERMES_LINKSTATUS_CONNECTED       (0x0001)
+#define HERMES_LINKSTATUS_DISCONNECTED    (0x0002)
+#define HERMES_LINKSTATUS_AP_CHANGE       (0x0003)
+#define HERMES_LINKSTATUS_AP_OUT_OF_RANGE (0x0004)
+#define HERMES_LINKSTATUS_AP_IN_RANGE     (0x0005)
+#define HERMES_LINKSTATUS_ASSOC_FAILED    (0x0006)
+
+struct hermes_linkstatus
+{
+       u16_t linkstatus;       /* Link status */
+};
+
+/* Timeouts. These are maximum timeouts. Most often, card wil react 
+ * much faster */
+#define HERMES_BAP_BUSY_TIMEOUT        (10000) /* In iterations of ~1us */
+#define HERMES_CMD_BUSY_TIMEOUT        (100)   /* In iterations of ~1us */
+#define HERMES_CMD_INIT_TIMEOUT        (50000) /* in iterations of ~10us */
+#define HERMES_CMD_COMPL_TIMEOUT       (20000) /* in iterations of ~10us */
+#define HERMES_ALLOC_COMPL_TIMEOUT     (1000)  /* in iterations of ~10us */
+
+/* WEP settings */
+#define HERMES_AUTH_OPEN               (1)
+#define HERMES_AUTH_SHARED_KEY         (2)
+#define HERMES_WEP_PRIVACY_INVOKED     (0x0001)
+#define HERMES_WEP_EXCL_UNENCRYPTED    (0x0002)
+#define HERMES_WEP_HOST_ENCRYPT                (0x0010)
+#define HERMES_WEP_HOST_DECRYPT                (0x0080)
+
+
+/* Basic control structure */
+typedef struct hermes
+{
+       u32_t iobase;
+       int io_space;           /* 1 if we IO-mapped IO, 0 for memory-mapped
+                                * IO */
+#define HERMES_IO      1
+#define HERMES_MEM     0
+       int reg_spacing;
+#define HERMES_16BIT_REGSPACING        0
+#define HERMES_32BIT_REGSPACING        1
+       u16_t inten;            /* Which interrupts should be enabled? */
+       char *locmem;
+} hermes_t;
+
+typedef struct hermes_response
+{
+       u16_t status, resp0, resp1, resp2;
+} hermes_response_t;
+
+struct hermes_idstring
+{
+       u16_t len;
+       u16_t val[16];
+};
+
+#define HERMES_BYTES_TO_RECLEN(n) ( (((n)+1)/2) + 1 )
+#define HERMES_RECLEN_TO_BYTES(n) ( ((n)-1) * 2 )
+
+/* Function prototypes */
+_PROTOTYPE (u16_t hermes_read_reg, (hermes_t * hw, u16_t off));
+_PROTOTYPE (void  hermes_write_reg, (hermes_t * hw, u16_t off, u16_t val));
+_PROTOTYPE (void  hermes_struct_init, (hermes_t * hw, u32_t address,
+                                       int io_space, int reg_spacing));
+_PROTOTYPE (int  hermes_init, (hermes_t * hw));
+_PROTOTYPE (int  hermes_docmd_wait, (hermes_t * hw, u16_t cmd,
+                                       u16_t parm0, hermes_response_t * resp));
+_PROTOTYPE (int  hermes_allocate, (hermes_t * hw, u16_t size, u16_t * fid));
+_PROTOTYPE (int  hermes_bap_pread, (hermes_t * hw, int bap, void *buf,
+                                       unsigned len, u16_t id, u16_t offset));
+_PROTOTYPE (int  hermes_bap_pwrite, (hermes_t * hw, int bap,
+                                       const void *buf, unsigned len, u16_t id,
+                                   u16_t offset));
+_PROTOTYPE (void hermes_read_words, (hermes_t * hw, int off, void *buf,
+                                       unsigned count));
+_PROTOTYPE (void hermes_write_words, (hermes_t * hw, int off,
+                                       const void *buf, unsigned count));
+_PROTOTYPE (int  hermes_read_ltv, (hermes_t * hw, int bap, u16_t rid,
+                                       unsigned buflen, u16_t * length,
+                                       void *buf));
+_PROTOTYPE (int  hermes_write_ltv, (hermes_t * hw, int bap, u16_t rid,
+                                       u16_t length, const void *value));
+_PROTOTYPE (int  hermes_present, (hermes_t * hw));
+_PROTOTYPE (int  myfunc_read, (vir_bytes src));
+_PROTOTYPE (void myfunc_write, (vir_bytes dst, int val));
+_PROTOTYPE (void hermes_print_ioarea, (hermes_t * hw, int first_reg,
+                                       int last_reg));
+_PROTOTYPE (int  hermes_set_irqmask, (hermes_t * hw, u16_t events));
+_PROTOTYPE (u16_t hermes_get_irqmask, (hermes_t * hw));
+_PROTOTYPE (int  hermes_read_wordrec, (hermes_t * hw, int bap, u16_t rid,
+                                       u16_t * word));
+_PROTOTYPE (int  hermes_write_wordrec, (hermes_t * hw, int bap, u16_t rid,
+                                       u16_t word));
+_PROTOTYPE (int  hermes_cor_reset, (hermes_t *hw));
+_PROTOTYPE (void milli_delay, (unsigned int msecs));
+#endif /* _HERMES_H */
diff --git a/drivers/orinoco/hermes_rid.h b/drivers/orinoco/hermes_rid.h
new file mode 100755 (executable)
index 0000000..23b0308
--- /dev/null
@@ -0,0 +1,149 @@
+/* hermes_rid.h
+ *
+ * This file contains the RIDs (Resource IDentifiers). These are data items
+ * which are configurable in the card. Most of them are not used in our driver
+ * currently, as you can see there are really a lot which can be configured. 
+ */
+
+
+#ifndef _HERMES_RID_H
+#define _HERMES_RID_H
+
+#define HERMES_RID_CNFPORTTYPE                         0xFC00
+#define HERMES_RID_CNFOWNMACADDR                       0xFC01
+#define HERMES_RID_CNFDESIREDSSID                      0xFC02
+#define HERMES_RID_CNFOWNCHANNEL                       0xFC03
+#define HERMES_RID_CNFOWNSSID                          0xFC04
+#define HERMES_RID_CNFOWNATIMWINDOW                    0xFC05
+#define HERMES_RID_CNFSYSTEMSCALE                      0xFC06
+#define HERMES_RID_CNFMAXDATALEN                       0xFC07
+#define HERMES_RID_CNFWDSADDRESS                       0xFC08
+#define HERMES_RID_CNFPMENABLED                                0xFC09
+#define HERMES_RID_CNFPMEPS                            0xFC0A
+#define HERMES_RID_CNFMULTICASTRECEIVE                 0xFC0B
+#define HERMES_RID_CNFMAXSLEEPDURATION                 0xFC0C
+#define HERMES_RID_CNFPMHOLDOVERDURATION               0xFC0D
+#define HERMES_RID_CNFOWNNAME                          0xFC0E
+#define HERMES_RID_CNFOWNDTIMPERIOD                    0xFC10
+#define HERMES_RID_CNFWDSADDRESS1                      0xFC11
+#define HERMES_RID_CNFWDSADDRESS2                      0xFC12
+#define HERMES_RID_CNFWDSADDRESS3                      0xFC13
+#define HERMES_RID_CNFWDSADDRESS4                      0xFC14
+#define HERMES_RID_CNFWDSADDRESS5                      0xFC15
+#define HERMES_RID_CNFWDSADDRESS6                      0xFC16
+#define HERMES_RID_CNFMULTICASTPMBUFFERING             0xFC17
+#define HERMES_RID_CNFWEPENABLED_AGERE                 0xFC20
+#define HERMES_RID_CNFAUTHENTICATION_AGERE             0xFC21
+#define HERMES_RID_CNFMANDATORYBSSID_SYMBOL            0xFC21
+#define HERMES_RID_CNFWEPDEFAULTKEYID                  0xFC23
+#define HERMES_RID_CNFDEFAULTKEY0                      0xFC24
+#define HERMES_RID_CNFDEFAULTKEY1                      0xFC25
+#define HERMES_RID_CNFMWOROBUST_AGERE                  0xFC25
+#define HERMES_RID_CNFDEFAULTKEY2                      0xFC26
+#define HERMES_RID_CNFDEFAULTKEY3                      0xFC27
+#define HERMES_RID_CNFWEPFLAGS_INTERSIL                        0xFC28
+#define HERMES_RID_CNFWEPKEYMAPPINGTABLE               0xFC29
+#define HERMES_RID_CNFAUTHENTICATION                   0xFC2A
+#define HERMES_RID_CNFMAXASSOCSTA                      0xFC2B
+#define        HERMES_RID_CNFKEYLENGTH_SYMBOL                  0xFC2B
+#define HERMES_RID_CNFTXCONTROL                                0xFC2C
+#define HERMES_RID_CNFROAMINGMODE                      0xFC2D
+#define HERMES_RID_CNFHOSTAUTHENTICATION               0xFC2E
+#define HERMES_RID_CNFRCVCRCERROR                      0xFC30
+#define HERMES_RID_CNFMMLIFE                           0xFC31
+#define HERMES_RID_CNFALTRETRYCOUNT                    0xFC32
+#define HERMES_RID_CNFBEACONINT                                0xFC33
+#define HERMES_RID_CNFAPPCFINFO                                0xFC34
+#define HERMES_RID_CNFSTAPCFINFO                       0xFC35
+#define HERMES_RID_CNFPRIORITYQUSAGE                   0xFC37
+#define HERMES_RID_CNFTIMCTRL                          0xFC40
+#define HERMES_RID_CNFTHIRTY2TALLY                     0xFC42
+#define HERMES_RID_CNFENHSECURITY                      0xFC43
+#define HERMES_RID_CNFGROUPADDRESSES                   0xFC80
+#define HERMES_RID_CNFCREATEIBSS                       0xFC81
+#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD           0xFC82
+#define HERMES_RID_CNFRTSTHRESHOLD                     0xFC83
+#define HERMES_RID_CNFTXRATECONTROL                    0xFC84
+#define HERMES_RID_CNFPROMISCUOUSMODE                  0xFC85
+#define HERMES_RID_CNFBASICRATES_SYMBOL                        0xFC8A
+#define HERMES_RID_CNFPREAMBLE_SYMBOL                  0xFC8C
+#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD0          0xFC90
+#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD1          0xFC91
+#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD2          0xFC92
+#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD3          0xFC93
+#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD4          0xFC94
+#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD5          0xFC95
+#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD6          0xFC96
+#define HERMES_RID_CNFRTSTHRESHOLD0                    0xFC97
+#define HERMES_RID_CNFRTSTHRESHOLD1                    0xFC98
+#define HERMES_RID_CNFRTSTHRESHOLD2                    0xFC99
+#define HERMES_RID_CNFRTSTHRESHOLD3                    0xFC9A
+#define HERMES_RID_CNFRTSTHRESHOLD4                    0xFC9B
+#define HERMES_RID_CNFRTSTHRESHOLD5                    0xFC9C
+#define HERMES_RID_CNFRTSTHRESHOLD6                    0xFC9D
+#define HERMES_RID_CNFHOSTSCAN_SYMBOL                  0xFCAB
+#define HERMES_RID_CNFSHORTPREAMBLE                    0xFCB0
+#define HERMES_RID_CNFWEPKEYS_AGERE                    0xFCB0
+#define HERMES_RID_CNFEXCLUDELONGPREAMBLE              0xFCB1
+#define HERMES_RID_CNFTXKEY_AGERE                      0xFCB1
+#define HERMES_RID_CNFAUTHENTICATIONRSPTO              0xFCB2
+#define HERMES_RID_CNFSCANSSID_AGERE                   0xFCB2
+#define HERMES_RID_CNFBASICRATES                       0xFCB3
+#define HERMES_RID_CNFSUPPORTEDRATES                   0xFCB4
+#define HERMES_RID_CNFTICKTIME                         0xFCE0
+#define HERMES_RID_CNFSCANREQUEST                      0xFCE1
+#define HERMES_RID_CNFJOINREQUEST                      0xFCE2
+#define HERMES_RID_CNFAUTHENTICATESTATION              0xFCE3
+#define HERMES_RID_CNFCHANNELINFOREQUEST               0xFCE4
+#define HERMES_RID_CNFHOSTSCAN                         0xFCE5
+#define HERMES_RID_MAXLOADTIME                         0xFD00
+#define HERMES_RID_DOWNLOADBUFFER                      0xFD01
+#define HERMES_RID_PRIID                               0xFD02
+#define HERMES_RID_PRISUPRANGE                         0xFD03
+#define HERMES_RID_CFIACTRANGES                                0xFD04
+#define HERMES_RID_NICSERNUM                           0xFD0A
+#define HERMES_RID_NICID                               0xFD0B
+#define HERMES_RID_MFISUPRANGE                         0xFD0C
+#define HERMES_RID_CFISUPRANGE                         0xFD0D
+#define HERMES_RID_CHANNELLIST                         0xFD10
+#define HERMES_RID_REGULATORYDOMAINS                   0xFD11
+#define HERMES_RID_TEMPTYPE                            0xFD12
+#define HERMES_RID_CIS                                 0xFD13
+#define HERMES_RID_STAID                               0xFD20
+#define HERMES_RID_STASUPRANGE                         0xFD21
+#define HERMES_RID_MFIACTRANGES                                0xFD22
+#define HERMES_RID_CFIACTRANGES2                       0xFD23
+#define HERMES_RID_SECONDARYVERSION_SYMBOL             0xFD24
+#define HERMES_RID_PORTSTATUS                          0xFD40
+#define HERMES_RID_CURRENTSSID                         0xFD41
+#define HERMES_RID_CURRENTBSSID                                0xFD42
+#define HERMES_RID_COMMSQUALITY                                0xFD43
+#define HERMES_RID_CURRENTTXRATE                       0xFD44
+#define HERMES_RID_CURRENTBEACONINTERVAL               0xFD45
+#define HERMES_RID_CURRENTSCALETHRESHOLDS              0xFD46
+#define HERMES_RID_PROTOCOLRSPTIME                     0xFD47
+#define HERMES_RID_SHORTRETRYLIMIT                     0xFD48
+#define HERMES_RID_LONGRETRYLIMIT                      0xFD49
+#define HERMES_RID_MAXTRANSMITLIFETIME                 0xFD4A
+#define HERMES_RID_MAXRECEIVELIFETIME                  0xFD4B
+#define HERMES_RID_CFPOLLABLE                          0xFD4C
+#define HERMES_RID_AUTHENTICATIONALGORITHMS            0xFD4D
+#define HERMES_RID_PRIVACYOPTIONIMPLEMENTED            0xFD4F
+#define HERMES_RID_DBMCOMMSQUALITY_INTERSIL            0xFD51
+#define HERMES_RID_CURRENTTXRATE1                      0xFD80
+#define HERMES_RID_CURRENTTXRATE2                      0xFD81
+#define HERMES_RID_CURRENTTXRATE3                      0xFD82
+#define HERMES_RID_CURRENTTXRATE4                      0xFD83
+#define HERMES_RID_CURRENTTXRATE5                      0xFD84
+#define HERMES_RID_CURRENTTXRATE6                      0xFD85
+#define HERMES_RID_OWNMACADDR                          0xFD86
+#define HERMES_RID_SCANRESULTSTABLE                    0xFD88
+#define HERMES_RID_PHYTYPE                             0xFDC0
+#define HERMES_RID_CURRENTCHANNEL                      0xFDC1
+#define HERMES_RID_CURRENTPOWERSTATE                   0xFDC2
+#define HERMES_RID_CCAMODE                             0xFDC3
+#define HERMES_RID_SUPPORTEDDATARATES                  0xFDC6
+#define HERMES_RID_BUILDSEQ                            0xFFFE
+#define HERMES_RID_FWID                                        0xFFFF
+
+#endif
diff --git a/drivers/orinoco/orinoco.c b/drivers/orinoco/orinoco.c
new file mode 100755 (executable)
index 0000000..c26056d
--- /dev/null
@@ -0,0 +1,2383 @@
+/*
+ * orinoco.c
+ *
+ * This file contains a wireless device driver for Prism based wireless
+ * cards. 
+ *
+ * Created by Stevens Le Blond <slblond@few.vu.nl> 
+ *        and Michael Valkering <mjvalker@cs.vu.nl>
+ *
+ * * The valid messages and their parameters are:
+ *
+ *   m_type      DL_PORT    DL_PROC   DL_COUNT   DL_MODE   DL_ADDR   DL_GRANT
+ * |------------+----------+---------+----------+---------+---------+---------|
+ * | HARDINT   |          |         |          |         |         |         |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * | DL_WRITE  | port nr  | proc nr | count    | mode    | address |         |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * | DL_WRITEV | port nr  | proc nr | count    | mode    | address |         |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * | DL_WRITEV_S| port nr  | proc nr | count    | mode    |         |  grant  |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * | DL_READ   | port nr  | proc nr | count    |         | address |         |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * | DL_READV  | port nr  | proc nr | count    |         | address |         |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * | DL_READV_S        | port nr  | proc nr | count    |         |         |  grant  |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * | DL_CONF   | port nr  | proc nr |          | mode    | address |         |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * | DL_GETSTAT        | port nr  | proc nr |          |         | address |         |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * |DL_GETSTAT_S| port nr  | proc nr |          |         |         |  grant  |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ * | DL_STOP   | port_nr  |         |          |         |         |         |
+ * |------------|----------|---------|----------|---------|---------|---------|
+ *
+ * The messages sent are:
+ *
+ *   m_type      DL_PORT    DL_PROC   DL_COUNT   DL_STAT   DL_CLCK
+ * |------------|----------|---------|----------|---------|---------|
+ * |DL_TASK_REPL| port nr  | proc nr | rd-count | err|stat| clock   |
+ * |------------|----------|---------|----------|---------|---------|
+ *
+ *   m_type      m3_i1     m3_i2       m3_ca1
+ * |------------|---------|-----------|---------------|
+ * |DL_CONF_REPL| port nr | last port | ethernet addr |
+ * |------------|---------|-----------|---------------|
+ *
+ *   m_type      DL_PORT    DL_STAT       
+ * |------------|---------|-----------|
+ * |DL_STAT_REPL| port nr |   err     |
+ * |------------|---------|-----------|
+ *
+ */
+
+#include       "../drivers.h" 
+#include       <string.h>
+#include       <stddef.h>
+#include       <minix/keymap.h>
+#include       <minix/syslib.h>
+#include       <minix/type.h>
+#include       <minix/sysutil.h>
+#include       <timers.h>
+#include       <sys/ioc_memory.h>
+#include       <ibm/pci.h>
+#include       <minix/ds.h>
+#include       "../../kernel/const.h"
+#include       "../../kernel/config.h"
+#include       "../../kernel/type.h"
+
+#define                tmra_ut                 timer_t
+#define                tmra_inittimer(tp)      tmr_inittimer(tp)
+#define                VERBOSE         1       /* display message during init */
+
+PRIVATE struct pcitab {
+       u16_t vid;
+       u16_t did;
+       int checkclass;
+} pcitab[]=
+{
+       { 0x1260, 0x3873, 0 },  
+       { 0x1186, 0x1300, 0 },  
+       { 0x0000, 0x0000, 0 }
+};
+
+
+static tmra_ut or_watchdog;
+
+#include       <stdio.h>
+#include       <stdlib.h>
+#include       <minix/com.h>
+#include       <minix/portio.h>
+#include       <net/hton.h>
+#include       <net/gen/ether.h>
+#include       <net/gen/eth_io.h>
+#include       <sys/vm.h>
+#include       <sys/types.h>
+#include       <fcntl.h>
+#include       <unistd.h>
+#include       <errno.h>
+
+#include       "assert.h"
+#include       "hermes.h"
+#include       "hermes_rid.h"
+#include       "orinoco.h"
+
+#define        ERR -1
+
+#define                debug 0
+
+#define                OR_M_ENABLED 1
+#define                OR_M_DISABLED 0
+#define                OR_F_EMPTY 0
+#define                OR_F_MULTI 1
+#define                OR_F_BROAD (1<<1)
+#define                OR_F_ENABLED (1<<2)
+#define                OR_F_PROMISC (1<<3)
+#define                OR_F_READING (1<<4)
+#define                OR_F_SEND_AVAIL (1<<5)
+#define                OR_F_PACK_SENT (1<<6)
+#define                OR_F_PACK_RECV (1<<7)
+#define        ORINOCO_INTEN ( HERMES_EV_RX | HERMES_EV_ALLOC |\
+                                       HERMES_EV_WTERR | HERMES_EV_TXEXC|\
+                                       HERMES_EV_INFO | HERMES_EV_INFDROP|\
+                                       HERMES_EV_TX)
+
+#define                NO_FID (-1)
+#define                ETH_ALEN 6
+#define                USER_BAP 0
+#define        IRQ_BAP 1
+#define                ETH_HLEN                14
+
+static int or_nr_task = ANY;
+static t_or or_table[OR_PORT_NR];
+
+struct ethhdr {
+       u8_t h_dest[ETH_ALEN];
+       u8_t h_src[ETH_ALEN];
+       u16_t h_proto;
+};
+
+struct header_struct {
+       /* 802.3 */
+       u8_t dest[ETH_ALEN];
+       u8_t src[ETH_ALEN];
+       u16_t len;
+       /* 802.2 */
+       u8_t dsap;
+       u8_t ssap;
+       u8_t ctrl;
+       /* SNAP */
+       u8_t oui[3];
+       u16_t ethertype;
+};
+
+#define                        RUP_EVEN(x)     (((x) + 1) & (~1))
+
+u8_t encaps_hdr[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+#define        ENCAPS_OVERHEAD (sizeof (encaps_hdr) + 2)
+
+/********************************************************************
+ *              Data tables                                         *
+ ********************************************************************/
+
+/* The frequency of each channel in MHz */
+const long channel_frequency[] = {
+       2412, 2417, 2422, 2427, 2432, 2437, 2442,
+       2447, 2452, 2457, 2462, 2467, 2472, 2484
+};
+
+#define NUM_CHANNELS (sizeof(channel_frequency) / sizeof(channel_frequency[0]))
+
+/* This tables gives the actual meanings of the bitrate IDs returned by the 
+ * firmware. Not used yet */
+struct {
+       int bitrate;            /* in 100s of kilobits */
+       int automatic;
+       u16_t txratectrl;
+} bitrate_table[] =
+{
+       {110, 1, 15},           /* Entry 0 is the default */
+       {10, 0, 1},
+       {10, 1, 1},
+       {20, 0, 2},
+       {20, 1, 3},
+       {55, 0, 4},
+       {55, 1, 7},
+       {110, 0, 8},};
+
+#define BITRATE_TABLE_SIZE (sizeof(bitrate_table) / sizeof(bitrate_table[0]))
+
+
+_PROTOTYPE (static void sig_handler, (void));
+_PROTOTYPE (static void or_writev, (message * mp, int from_int, int vectored));
+_PROTOTYPE (static void or_readv, (message * mp, int from_int, int vectored));
+_PROTOTYPE (static void or_writev_s, (message * mp, int from_int));
+_PROTOTYPE (static void or_readv_s, (message * mp, int from_int));
+_PROTOTYPE (static void reply, (t_or * orp, int err, int may_block));
+_PROTOTYPE (static int  or_probe, (t_or *));
+_PROTOTYPE (static void or_ev_info, (t_or *));
+_PROTOTYPE (static void or_init, (message *));
+_PROTOTYPE (static void or_pci_conf, (void));
+_PROTOTYPE (static void or_init_struct, (t_or *));
+_PROTOTYPE (static void map_hw_buffer, (t_or *));
+_PROTOTYPE (static void or_init_hw, (t_or *));
+_PROTOTYPE (static void or_check_ints, (t_or *));
+_PROTOTYPE (static void or_writerids, (hermes_t *, t_or *));
+_PROTOTYPE (static void or_readrids, (hermes_t *, t_or *));
+_PROTOTYPE (static void or_rec_mode, (t_or *));
+_PROTOTYPE (static void mess_reply, (message *, message *));
+_PROTOTYPE (static u32_t or_get_bar, (int devind, t_or * orp));
+_PROTOTYPE (static void or_getstat, (message * mp));
+_PROTOTYPE (static void or_getstat_s, (message * mp));
+_PROTOTYPE (static void print_linkstatus, (t_or * orp, u16_t status));
+_PROTOTYPE (static int  or_get_recvd_packet, (t_or *orp, u16_t rxfid, 
+                                       u8_t *databuf));
+_PROTOTYPE (static void orinoco_stop, (void));
+_PROTOTYPE (static void or_reset, (void));
+_PROTOTYPE (static void or_watchdog_f, (timer_t *tp) );
+_PROTOTYPE (static void setup_wepkey, (t_or *orp, char *wepkey0) );
+_PROTOTYPE (static void or_getstat, (message *m));
+_PROTOTYPE (static int  do_hard_int, (void));
+_PROTOTYPE (static void check_int_events, (void));
+_PROTOTYPE (static void or_getname, (message *m));
+_PROTOTYPE (static int or_handler, (t_or *orp));
+_PROTOTYPE (static void or_dump, (message *m));
+
+/* The message used in the main loop is made global, so that rl_watchdog_f()
+ * can change its message type to fake a HARD_INT message.
+ */
+PRIVATE message m;
+PRIVATE int int_event_check;           /* set to TRUE if events arrived */
+
+static char *progname;
+extern int errno;
+
+/*****************************************************************************
+ *            main                                                           *
+ *                                                                           *
+ *                                                                           *
+ * The main function of the driver, receiving and processing messages        *
+ *****************************************************************************/
+int main(int argc, char *argv[]) {
+       int fkeys, sfkeys, r, i, ret;
+       u32_t inet_proc_nr;
+       long v = 0;
+       t_or *orp;
+
+       (progname=strrchr(argv[0],'/')) ? progname++ : (progname=argv[0]);
+
+       env_setargs(argc, argv);
+
+       /* Observe some function key for debug dumps. */
+       fkeys = sfkeys = 0; bit_set(sfkeys, 11);
+       if ((r=fkey_map(&fkeys, &sfkeys)) != OK) 
+           printf("Warning: orinoco couldn't observe F-key(s): %d\n",r);
+
+       /* Try to notify INET that we are present (again). If INET cannot
+        * be found, assume this is the first time we started and INET is
+        * not yet alive. */
+       r = ds_retrieve_u32("inet", &inet_proc_nr);
+       if (r == OK) 
+               notify(inet_proc_nr);
+       else if (r != ESRCH)
+               printf("orinoco: ds_retrieve_u32 failed for 'inet': %d\n", r);
+
+       while (42) {
+               if ((r = receive (ANY, &m)) != OK)
+                       panic(__FILE__, "orinoco: receive failed", NO_NUM);
+
+               switch (m.m_type) {
+               case DEV_PING: 
+                       notify(m.m_source);     
+                       break;
+               case DL_WRITEV:
+                       or_writev (&m, FALSE, TRUE);
+                       break;
+               case DL_WRITEV_S:
+                       or_writev_s (&m, FALSE);
+                       break;
+               case DL_WRITE:
+                       or_writev (&m, FALSE, FALSE);
+                       break;
+               case DL_READ:
+                       or_readv (&m, FALSE, FALSE);
+                       break;
+               case DL_READV:
+                       or_readv (&m, FALSE, TRUE);
+                       break;
+               case DL_READV_S:
+                       or_readv_s (&m, FALSE);
+                       break;
+               case DL_CONF:
+                       or_init (&m);
+                       break;
+               case DL_GETSTAT:
+                       or_getstat (&m);
+                       break;
+               case DL_GETSTAT_S:
+                       or_getstat_s (&m);
+                       break;
+               case DL_GETNAME: 
+                       or_getname(&m);
+                       break;
+               case SYN_ALARM:
+                       or_watchdog_f(NULL);     
+                       break;           
+               case HARD_INT:
+                       do_hard_int();
+                       if (int_event_check)
+                               check_int_events();
+                       break ;
+               case FKEY_PRESSED: 
+                       or_dump(&m);    
+                       break;
+               case PROC_EVENT:
+                       sig_handler();
+                       break;
+               default:
+                       panic(__FILE__,"orinoco: illegal message:", m.m_type);
+               }
+       }
+}
+
+/*****************************************************************************
+ *                    sig_handler                                            *
+ *                                                                           *
+ * Handles signals to the driver.                                            *
+ *****************************************************************************/
+PRIVATE void sig_handler() {
+       sigset_t sigset;
+       int sig;
+       
+       if(getsigset(&sigset) != 0) return;
+       
+       if(sigismember(&sigset, SIGTERM)) {
+               orinoco_stop();
+       }
+}
+
+
+/*****************************************************************************
+ *                    check_int_events                                       *
+ *                                                                           *
+ * If a hard interrupt message came in, call the or_check_ints for the right *
+ * card                                                                      *
+ *****************************************************************************/
+static void check_int_events(void) {
+       int i;
+       t_or *orp;
+
+       /* the HARD_INT message doesn't contain information about the port, try
+         * to find it */
+       for (orp = or_table;
+                orp < or_table + OR_PORT_NR; orp++) {
+               if (orp->or_mode != OR_M_ENABLED)
+                       continue;
+               if (!orp->or_got_int)
+                       continue;
+               orp->or_got_int = 0;
+               assert (orp->or_flags & OR_F_ENABLED);
+               or_check_ints (orp);
+       }
+
+}
+
+/****************************************************************************
+ *                    or_getname                                            *
+ *                                                                          *
+ * Gets the drivers name, orinoco                                           *
+ ****************************************************************************/
+static void or_getname(message *mp) {
+       int r;
+       
+       strncpy(mp->DL_NAME, progname, sizeof(mp->DL_NAME));
+       mp->DL_NAME[sizeof(mp->DL_NAME) - 1] = '\0';
+       mp->m_type = DL_NAME_REPLY;
+
+       r = send(mp->m_source, mp);
+       if(r != OK) {
+               panic(__FILE__, "or_getname: send failed", r);
+       }
+}
+
+/*****************************************************************************
+ *                do_hard_int                                                *
+ *                                                                           *
+ * Process the interrupts which the card generated                           *
+ *****************************************************************************/
+static int do_hard_int(void) {
+       u16_t evstat;
+       hermes_t *hw;
+       int i,s;
+       t_or *orp;
+
+       for (i=0; i < OR_PORT_NR; i ++) {
+               /* Run interrupt handler at driver level. */
+               or_handler( &or_table[i]);
+
+               /* Reenable interrupts for this hook. */
+               if ((s=sys_irqenable(&or_table[i].or_hook_id)) != OK) {
+                       printf("orinoco: error, couldn't enable");
+                       printf(" interrupts: %d\n", s);
+               }
+       }
+}
+
+
+
+/*****************************************************************************
+ *                orinoco_stop                                               *
+ *                                                                           *
+ * Stops the card. The signal to the card itself is not implemented yet.     *
+ *****************************************************************************/
+static void orinoco_stop () {
+       int i;
+       t_or *orp;
+
+       for (i= 0, orp= &or_table[0]; i<OR_PORT_NR; i++, orp++) {
+               if (orp->or_mode != OR_M_ENABLED)
+                       continue;
+               /* TODO: send a signal to the card to shut it down */
+       }
+       sys_exit(0);
+}
+
+/*****************************************************************************
+ *                or_reset                                                   *
+ *                                                                           *
+ * Sometime the card gets screwed, behaving erratically. Solution: reset the *
+ * card. This is actually largely redoing the initialization                 *
+ *****************************************************************************/
+static void or_reset() {
+       static clock_t last_reset, now; 
+       t_or *orp;
+       int i, j, r;
+       u16_t irqmask;
+       hermes_t *hw = &(orp->hw);
+
+       if (OK != (r = getuptime(&now)))
+               panic(__FILE__, "orinoco: getuptime() failed:", r);
+
+       if(now - last_reset < HZ * 10) {
+               printf("Resetting card too often. Going to reset driver\n");
+               exit(1);
+       }
+       
+       for (i = 0, orp = or_table; orp < or_table + OR_PORT_NR; i++, orp++) {
+               if(orp->or_mode == OR_M_DISABLED) 
+                       printf("orinoco port %d is disabled\n", i);
+               
+               if(orp->or_mode != OR_M_ENABLED) {
+                       continue;
+               }
+
+               orp->or_need_reset = 0;
+               or_init_hw(orp);
+
+               orp->rx_last = orp->rx_first = 0;
+               for(j = 0; j < NR_RX_BUFS; j++) {
+                       orp->rx_length[0] = 0;
+               }
+
+               if(orp->or_flags & OR_F_SEND_AVAIL) {
+                       orp->or_tx.ret_busy = FALSE;
+                       orp->or_send_int = TRUE;
+               }
+       }
+
+       last_reset = now;
+
+}
+
+/*****************************************************************************
+ *                or_dump                                                    *
+ *                                                                           *
+ * Dump interesting information about the card on F-key pressed.             *
+ * Not implemented yet                                                       *
+ *****************************************************************************/
+static void or_dump (message *m) {
+       t_or *orp;
+       int i, err;
+       u16_t evstat =0, d;
+       hermes_t *hw;
+
+       for (i = 0, orp = or_table; orp < or_table + OR_PORT_NR; i++, orp++) {
+               if(orp->or_mode == OR_M_DISABLED) {
+                       printf("%s is disabled\n", orp->or_name);
+               }
+               
+               if(orp->or_mode != OR_M_ENABLED)
+                       continue;
+
+               m->m_type = FKEY_CONTROL;
+               m->FKEY_REQUEST = FKEY_EVENTS;
+               if(OK!=(sendrec(TTY_PROC_NR,m)) )
+                       printf("Contacting the TTY failed\n");
+               
+               if(bit_isset(m->FKEY_SFKEYS, 11)) {
+                       print_linkstatus(orp, orp->last_linkstatus);
+               }
+       }
+}
+
+/*****************************************************************************
+ *                or_init                                                    *
+ *                                                                           *
+ * The main initialization function, called when a DL_INIT message comes in. *
+ *****************************************************************************/
+static void or_init (message * mp) {
+       int port, err, i;
+       t_or *orp;
+       message reply;
+       static int first_time = 1;
+       hermes_t *hw;
+       clock_t t0,t1;
+
+       if (first_time) {
+               first_time = 0;
+               or_pci_conf (); /* Configure PCI devices. */
+       
+               tmra_inittimer(&or_watchdog);
+               /* Use a synchronous alarm instead of a watchdog timer. */
+               sys_setalarm(HZ, 0);
+       }       
+
+       port = mp->DL_PORT;
+       if (port < 0 || port >= OR_PORT_NR)     {
+               /* illegal port in message */
+               reply.m_type = DL_CONF_REPLY;
+               reply.m3_i1 = ENXIO;
+               mess_reply (mp, &reply);
+               return;
+       }
+
+       /* the port resolves to the main orinoco structure */
+       orp = &or_table[port];
+       /* resolving to the main hardware structure */
+       hw = &(orp->hw);
+
+       if (orp->or_mode == OR_M_DISABLED) {
+               /* Initialize the orp structure */
+               or_init_struct (orp);
+               if (orp->or_mode == OR_M_DISABLED) {
+                       reply.m_type = DL_CONF_REPLY;
+                       reply.m3_i1 = ENXIO;
+                       mess_reply (mp, &reply);
+                       return;
+               }
+               if (orp->or_mode == OR_M_ENABLED) {
+                       /* initialize card, hardware/firmware */
+                       orp->or_flags |= OR_F_ENABLED;
+                       or_init_hw (orp);
+               }
+       }
+
+       assert (orp->or_mode == OR_M_ENABLED);
+       assert (orp->or_flags & OR_F_ENABLED);
+
+       /* Not supported by the driver yet, but set a couple of options:
+        * multicasting, promiscuity, broadcasting, depending on the users 
+         * needs */
+       orp->or_flags &= ~(OR_F_PROMISC | OR_F_MULTI | OR_F_BROAD);
+       if (mp->DL_MODE & DL_PROMISC_REQ)
+               orp->or_flags |= OR_F_PROMISC;
+       if (mp->DL_MODE & DL_MULTI_REQ)
+               orp->or_flags |= OR_F_MULTI;
+       if (mp->DL_MODE & DL_BROAD_REQ)
+               orp->or_flags |= OR_F_BROAD;
+
+       orp->or_client = mp->m_source;
+       or_rec_mode (orp);
+
+       /* reply the caller that the configuration succeeded */
+       reply.m_type = DL_CONF_REPLY;
+       reply.m3_i1 = mp->DL_PORT;
+       reply.m3_i2 = OR_PORT_NR;
+       *(ether_addr_t *) reply.m3_ca1 = orp->or_address;
+       mess_reply (mp, &reply);
+}
+
+/*****************************************************************************
+ *                or_pci_conf                                                *
+ *                                                                           *
+ * Configure the pci related issues of the card, e.g. finding out where the  *
+ * card is in the pci configuration, it's assigned irq, etc. This can be     *
+ * done if the boot monitor is provided with information, or the pci bus     *
+ * can be searched (at the end: or_probe function)                           *
+ *****************************************************************************/
+static void or_pci_conf () {
+       long v;
+       t_or *orp;
+       int i, h;
+       static char envfmt[] = "*:d.d.d";
+       static char envvar[] = OR_ENVVAR "#";
+       static char val[128];
+
+       /* extract information from the boot monitor about the pci 
+        * configuration if provided */
+       for (i = 0, orp = or_table; i < OR_PORT_NR; i++, orp++) {
+               strncpy (orp->or_name, OR_NAME, sizeof(OR_NAME));
+               orp->or_name[sizeof(OR_NAME) - 2] = i + '0';
+               orp->or_seen = FALSE;
+               /* whats this envvar; whats the definition;*/
+               /* i guess this whole loop could be removed*/
+               envvar[sizeof (OR_ENVVAR) - 1] = '0' + i;
+               if (0 == env_get_param(envvar, val, sizeof(val)) && 
+                       ! env_prefix(envvar, "pci")) {
+                       env_panic(envvar);
+               }
+               v = 0;
+               (void) env_parse (envvar, envfmt, 1, &v, 0, 255);
+               orp->or_pci_bus = v;
+               v = 0;
+               (void) env_parse (envvar, envfmt, 2, &v, 0, 255);
+               orp->or_pci_dev = v;
+               v = 0;
+               (void) env_parse (envvar, envfmt, 3, &v, 0, 255);
+               orp->or_pci_func = v;
+       }
+
+       /* Initialize the pci bus, bridges and cards, if not yet done */
+       pci_init ();
+       
+       /* Try to find out where the card(s) are in the pci bus */
+       for (h = 1; h >= 0; h--)
+               for (i = 0, orp = or_table; i < OR_PORT_NR; i++, orp++) {
+                       if (((orp->or_pci_bus | orp->or_pci_dev |
+                             orp->or_pci_func) != 0) != h)     {
+                               continue;
+                       }
+                       if (or_probe (orp))
+                               orp->or_seen = TRUE;
+               }
+}
+
+/*****************************************************************************
+ *                or_probe                                                   *
+ *                                                                           *
+ * Try to find the card based on information provided by pci and get irq and *
+ * bar                                                                       *
+ *****************************************************************************/
+static int or_probe (t_or * orp) {
+       u8_t ilr;
+       u32_t bar, reg, cpuspace_bar;
+       char *dname;
+       u16_t vid, did;
+       int i, r, devind, just_one;
+
+       if ((orp->or_pci_bus | orp->or_pci_dev | orp->or_pci_func) != 0) {
+               /* The monitor has provided us with clues about where the 
+                 * device is. Try to find it at that place */
+               r = pci_find_dev (orp->or_pci_bus, orp->or_pci_dev,
+                                 orp->or_pci_func, &devind);
+               if (r == 0)     {
+                       printf ("%s: no PCI found at %d.%d.%d\n",
+                               orp->or_name, orp->or_pci_bus,
+                               orp->or_pci_dev, orp->or_pci_func);
+                       return (0);
+               }
+               /* get the information about the card, vendor id and device
+                * id */
+               pci_ids (devind, &vid, &did);
+               just_one = TRUE;
+       } else {
+               /* no clue where the card is. Start looking from the
+                * beginning */
+               r = pci_first_dev (&devind, &vid, &did);
+               if (r == 0)
+                       return (0);
+               just_one = FALSE;
+       }
+
+       while (42) {
+               /* loop through the pcitab to find a maching entry. The match
+                * being between one of the values in pcitab and the 
+                * information provided by the pci bus */
+               for (i = 0; pcitab[i].vid != 0; i++) {
+                       if (pcitab[i].vid != vid)
+                               continue;
+                       if (pcitab[i].did != did)
+                               continue;
+                       if (pcitab[i].checkclass) {
+                           panic(__FILE__, "or_probe:class check not implmnted", 
+                                 NO_NUM);
+                       }
+                       /* we have found the card in the pci bus */
+                       break;
+               }
+               if (pcitab[i].vid != 0)
+                       break;
+
+               if (just_one) {
+                       printf ("%s: wrong PCI device", orp->or_name);
+                       printf (" (%04x/%04x) found at %d.%d.%d\n", vid, did,
+                               orp->or_pci_bus, orp->or_pci_dev,
+                               orp->or_pci_func);
+                       return (0);
+               }
+
+               /* if the pci device which was under consideration was not
+                * of the desired brand or type, get the next device */
+               r = pci_next_dev (&devind, &vid, &did);
+               if (!r)
+                       return (0);
+       }
+
+       /* Get the name as advertised by pci */
+       dname = pci_dev_name (vid, did);
+       if (!dname)
+               dname = "unknow device";
+       printf ("%s: %s (%04x/%04x) at %s\n",
+               orp->or_name, dname, vid, did, pci_slot_name (devind));
+
+       pci_reserve (devind);
+
+       orp->devind = devind;   
+       /* Get the irq */
+       ilr = pci_attr_r8 (devind, PCI_ILR);
+       orp->or_irq = ilr;
+
+       /* Get the base address */
+       bar = or_get_bar (devind, orp);
+       orp->or_base_port = bar;
+
+       map_hw_buffer(orp);
+       return TRUE;
+}
+
+/*****************************************************************************
+ *                map_hw_buffer                                              *
+ *                                                                           *
+ * Map the memory mapped registers into user space memory                    *
+ *****************************************************************************/
+static void map_hw_buffer(t_or *orp) {
+       int r;
+       size_t o, size, reg_size;
+       char *buf, *abuf;       
+       hermes_t *hw = &(orp->hw);      
+
+       /* This way, the buffer will be at least PAGE_SIZE big: see 
+        * calculation with the offset */
+       size = 2 * PAGE_SIZE;   
+
+       buf = (char *)malloc(size);
+       if(buf == NULL) 
+               panic(__FILE__, "map_hw_buffer: cannot malloc size:", size);
+
+       /* Let the mapped memory by PAGE_SIZE aligned */
+       o = PAGE_SIZE - ((vir_bytes)buf % PAGE_SIZE);
+       abuf = buf + o;
+
+       r = sys_vm_map(SELF, 1, (vir_bytes)abuf, 
+                       1 * PAGE_SIZE, (phys_bytes)orp->or_base_port);
+
+       if(r!=OK) 
+               panic(__FILE__, "map_hw_buffer: sys_vm_map failed:", r);
+
+       hw->locmem = abuf;
+}
+
+
+
+/*****************************************************************************
+ *                or_get_bar                                                 *
+ *                                                                           *
+ * Get the base address from pci (from Base Address Register) and find out   * 
+ * whether the card is memory mapped or in I/O space. Currently, only        *
+ * memmory mapped is supported.                                              *
+ *****************************************************************************/
+static u32_t or_get_bar (int devind, t_or * orp) {
+
+       u32_t bar, desired_bar;
+       int is_iospace, i;
+       u16_t check, check2;
+       hermes_t *hw = &(orp->hw);
+
+       /* bit 1 off the PCI_BAR register indicates whether the cards registers
+        * are mapped in io-space or shared memory */
+       is_iospace = pci_attr_r32 (devind, PCI_BAR) & 1;
+
+       if (is_iospace) {
+               /* read where the base address is in I/O space */
+               bar = pci_attr_r32 (devind, PCI_BAR) & 0xffffffe0;
+
+               if ((bar & 0x3ff) >= 0x100 - 32 || bar < 0x400)
+                       panic(__FILE__,"base address isn't properly configured",
+                              NO_NUM);
+
+               /* In I/O space registers are 2 bytes wide, without any spacing
+                * in between */
+               hermes_struct_init (hw, bar, is_iospace,
+                                   HERMES_16BIT_REGSPACING);
+
+               if (debug) {
+                       printf ("%s: using I/O space address 0x%lx, IRQ %d\n",
+                               orp->or_name, bar, orp->or_irq);
+               }
+
+               panic(__FILE__, "Not implemente yet", NO_NUM);
+               /* Although we are able to find the desired bar and irq for an 
+                * I/O spaced card, we haven't implemented the right register 
+                * accessing functions. This wouldn't be difficult, but we were
+                * not able to test them. Therefore, give an alert here */
+
+               return bar;
+       } else {
+               /* read where the base address is in shared memory */
+               bar = pci_attr_r32 (devind, PCI_BAR) & 0xfffffff0;
+               /* maybe some checking whether the address is legal... */
+
+               /* Memory mapped registers are 2 bytes wide, aligned on 4 
+                * bytes */
+               hermes_struct_init (hw, bar, is_iospace,
+                                   HERMES_32BIT_REGSPACING);
+
+               if (debug){
+                       printf ("%s: using shared memory address",
+                               orp->or_name);
+                       printf (" 0x%lx, IRQ %d\n", bar, orp->or_irq);
+               }
+
+               return bar;
+
+       }
+}
+
+/*****************************************************************************
+ *                or_init_struct                                             *
+ *                                                                           *
+ * Set the orinoco structure to default values                               *
+ *****************************************************************************/
+static void or_init_struct (t_or * orp) {
+       int i = 0;
+       static eth_stat_t empty_stat = { 0, 0, 0, 0, 0, 0 };
+
+       orp->or_mode = OR_M_DISABLED;
+
+       if (orp->or_seen)
+               orp->or_mode = OR_M_ENABLED;
+
+       if (orp->or_mode != OR_M_ENABLED)
+               return;
+
+       orp->or_got_int = 0;
+       orp->or_link_up = -1;
+       orp->or_send_int = 0;
+       orp->or_clear_rx = 0;
+       orp->or_tx_alive = 0;
+       orp->or_need_reset = 0;
+
+       orp->or_read_s = 0;
+       orp->or_tx_head = 0;
+       orp->or_tx_tail = 0;
+       orp->connected = 0;
+       
+       orp->or_tx.ret_busy = FALSE;
+       orp->or_tx.or_txfid = NO_FID;
+
+       for(i = 0; i < NR_RX_BUFS; i++) {
+               orp->rxfid[i] = NO_FID;
+               orp->rx_length[i] = 0;
+       }
+       orp->rx_current = 0;
+       orp->rx_first = 0;
+       orp->rx_last = 0;
+       
+       orp->or_stat = empty_stat;
+       orp->or_flags = OR_F_EMPTY;
+
+       /* Keep an administration in the driver whether the internal
+          buffer is in use. That's what ret_busy is for */
+       orp->or_tx.ret_busy = FALSE;
+
+       orp->or_nicbuf_size = IEEE802_11_FRAME_LEN + ETH_HLEN;
+
+}
+
+/*****************************************************************************
+ *                or_init_hw                                                 *
+ *                                                                           *
+ * Initialize hardware and prepare for intercepting the interrupts. At the   *
+ * end, the card is up and running                                           *
+ *****************************************************************************/
+static void or_init_hw (t_or * orp) {
+       int i, err, s;
+       hermes_t *hw = &(orp->hw);
+       static int first_time = TRUE;
+
+       /* first step in starting the card */
+       if (hermes_cor_reset(hw) != 0) {
+               printf ("%s: Failed to start the card\n", orp->or_name);
+       }
+
+       /* here begins the real things, yeah! ;) */
+       if (err = hermes_init (hw))     {
+               printf ("error value of hermes_init(): %d\n", err);
+       }
+
+       /* Get the MAC address (which is a data item in the card)*/
+       or_readrids (hw, orp);
+
+       /* Write a few rids to the card, e.g. WEP key*/
+       or_writerids (hw, orp);
+
+       if (debug) {
+               printf ("%s: Ethernet address ", orp->or_name);
+               for (i = 0; i < 6; i++) {
+                       printf ("%x%c", orp->or_address.ea_addr[i],
+                               i < 5 ? ':' : '\n');
+               }
+       }
+
+       /* Prepare internal TX buffer in the card */
+       err = hermes_allocate (hw,
+                                  orp->or_nicbuf_size,
+                                  &(orp->or_tx.or_txfid));
+
+       if (err)
+               printf ("%s:Error %d allocating Tx buffer\n",
+                       orp->or_name, err);
+
+       /* Establish event handle */
+       if(first_time) {
+               orp->or_hook_id = orp->or_irq;  
+               if ((s=sys_irqsetpolicy(orp->or_irq, 0, 
+                       &orp->or_hook_id)) != OK)
+                       printf("orinoco: couldn't set IRQ policy: %d\n", s);
+
+               if ((s=sys_irqenable(&orp->or_hook_id)) != OK)
+                       printf("orinoco: couldn't enable interrupts: %d\n", s);
+               first_time = FALSE;
+       }
+
+       /* Tell the card which events should raise an interrupt to the OS */
+       hermes_set_irqmask (hw, ORINOCO_INTEN);
+
+       /* Enable operation */
+       err = hermes_docmd_wait (hw, HERMES_CMD_ENABLE, 0, NULL);
+       if (err) {
+               printf ("%s: Error %d enabling MAC port\n", orp->or_name, err);
+       }
+}
+
+
+/*****************************************************************************
+ *                or_readrids                                                *
+ *                                                                           *
+ * Read some default rids from the card. A rid (resource identifier)         *
+ * is a data item in the firmware, some configuration variable.              *
+ * In our case, we are mostly interested in the MAC address for now          *
+ *****************************************************************************/
+
+static void or_readrids (hermes_t * hw, t_or * orp) {
+       int err, len, i;
+       struct hermes_idstring nickbuf;
+       u16_t reclen, d;
+
+       /* Read the MAC address */
+       err = hermes_read_ltv (hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
+                              ETH_ALEN, NULL, &orp->or_address);
+       if (err) {
+               printf ("%s: failed to read MAC address!\n", orp->or_name);
+               return;
+       }
+
+}
+
+/*****************************************************************************
+ *                or_writerids                                               *
+ *                                                                           *
+ * Write some default rids to the card. A rid (resource identifier)          *
+ * is a data item in the firmware, some configuration variable, e.g. WEP key *
+ *****************************************************************************/
+static void or_writerids (hermes_t * hw, t_or * orp) {
+       int err;
+       struct hermes_idstring idbuf;
+       u16_t port_type, max_data_len, reclen;
+       static char essid[IW_ESSID_MAX_SIZE + 1];
+       static char wepkey0[LARGE_KEY_LENGTH + 1];
+
+       /* Set the MAC port */
+       port_type = 1;
+       err = hermes_write_wordrec (hw, USER_BAP, HERMES_RID_CNFPORTTYPE,
+                                   port_type);
+       if (err) {
+               printf ("%s: Error %d setting port type\n", orp->or_name, err);
+               return;
+       }
+
+       if (OK != env_get_param("essid", essid, sizeof(essid))) {
+               essid[0] = 0;
+       }
+
+       if(strlen(essid) == 0) {
+               printf("%s: no essid provided in boot monitor!\n",
+                       orp->or_name);
+               printf("Hope you'll connect to the right network... \n");
+       }
+
+       /* Set the desired ESSID */
+       idbuf.len = strlen (essid);
+       memcpy (&idbuf.val, essid, sizeof (idbuf.val));
+
+       err = hermes_write_ltv (hw, USER_BAP, HERMES_RID_CNFDESIREDSSID,
+                               HERMES_BYTES_TO_RECLEN (strlen (essid) + 2),
+                                &idbuf);
+       if (err) {
+               printf ("%s: Error %d setting DESIREDSSID\n", 
+                               orp->or_name, err);
+               return;
+       }
+
+       if (OK != env_get_param("wep", wepkey0, sizeof(wepkey0))) {
+               wepkey0[0] = 0;
+       }
+
+       switch(strlen(wepkey0)) {
+               case 0:
+                       /* No key found in monitor, using no encryption */
+               break;
+               case LARGE_KEY_LENGTH:
+                       setup_wepkey(orp, wepkey0);
+               break;
+               default:
+                       printf("unvalid key provided. Has to be 13 chars\n");
+               break;
+       }
+}
+
+/*****************************************************************************
+ *                setup_wepkey                                               *
+ *                                                                           *
+ * If a wepkey is provided in the boot monitor, set the necessary rids so    *
+ * that the card will decrypt received data and encrypt data to send by      *
+ * by default with this key.                                                 *
+ * It appears that there is a severe bug in setting up WEP. If the driver    *
+ * doesnt function properly, please turn WEP off.                            *
+ *****************************************************************************/
+static void setup_wepkey(t_or *orp, char *wepkey0) {
+       int default_key = 0, err = 0;
+       hermes_t *hw = &(orp->hw);
+
+       err = hermes_write_wordrec (hw, USER_BAP,
+                                       HERMES_RID_CNFWEPDEFAULTKEYID,
+                                       default_key);
+       if (err)
+               printf ("%s: Error %d setting the default WEP-key entry\n",
+                               orp->or_name, err);     
+       
+       err = hermes_write_ltv (hw, USER_BAP, 
+                               HERMES_RID_CNFDEFAULTKEY0,
+                               HERMES_BYTES_TO_RECLEN(LARGE_KEY_LENGTH),
+                               wepkey0);
+       if (err) 
+               printf ("%s: Error %d setting the WEP-key0\n",
+                               orp->or_name, err);     
+       
+       err = hermes_write_wordrec (hw, USER_BAP, 
+                                       HERMES_RID_CNFAUTHENTICATION,
+                                       HERMES_AUTH_OPEN);
+       if (err)
+               printf ("%s: Error %d setting the authentication flag\n",
+                       orp->or_name, err);     
+
+       err = hermes_write_wordrec (hw, USER_BAP, 
+                                       HERMES_RID_CNFWEPFLAGS_INTERSIL,
+                                       HERMES_WEP_PRIVACY_INVOKED);
+       if (err)
+               printf ("%s: Error %d setting the master wep setting flag\n",
+                       orp->or_name, err);     
+       
+}
+
+
+/*****************************************************************************
+ *                or_rec_mode                                                *
+ *                                                                           *
+ * Set the desired receive mode, e.g. promiscuous mode. Not implemented yet   *
+ *****************************************************************************/
+static void or_rec_mode (t_or * orp) {
+       /* TODO */
+}
+
+/*****************************************************************************
+ *                or_handler                                                 *
+ *                                                                           *
+ * The handler which is called when the card generated an interrupt. Events  *
+ * like EV_INFO and EV_RX have to be handled before an acknowledgement for   *
+ * the event is returned to the card. See also the documentation             *
+ *****************************************************************************/
+static int or_handler (t_or *orp) {
+       int i, err, length, nr = 0;
+       u16_t evstat, events, fid;
+       hermes_t *hw;
+       struct hermes_tx_descriptor desc;
+       
+       hw = &(orp->hw);
+       
+beginning:
+       /* Retrieve which kind of event happened */
+       evstat = hermes_read_reg (hw, HERMES_EVSTAT);
+       events = evstat;
+
+       /* There are plenty of events possible. The more interesting events
+          are actually implemented. Whether the following events actually
+          raise an interrupt depends on the value of ORINOCO_INTEN. For more
+          information about the events, see the specification in pdf */
+
+       /* Occurs at each tick of the auxiliary time */
+       if (events & HERMES_EV_TICK) {
+               events &= ~HERMES_EV_TICK;
+       }
+       /* Occurs when a wait time-out error is detected */
+       if (events & HERMES_EV_WTERR) {
+               events &= ~HERMES_EV_WTERR;
+       }
+
+       /* Occurs when an info frame is dropped because there is not enough
+          buffer space available */
+       if (events & HERMES_EV_INFDROP) {
+               events &= ~(HERMES_EV_INFDROP);
+       }
+       
+       /* This AP-only event will be asserted at the beacon interval prior to 
+          the DTIM interval */
+       if (events & HERMES_EV_DTIM) {
+               events &= ~(HERMES_EV_DTIM);
+       }
+
+       /* Occurs when a command execution is completed */
+       if (events & HERMES_EV_CMD) {
+               events &= ~(HERMES_EV_CMD);
+       }
+
+       /* Occurs when the asynchronous transmission process is unsuccessfully
+          completed */
+       if (events & HERMES_EV_TXEXC) {
+
+               /* What buffer generated the event? Represented by an fid */
+               fid = hermes_read_reg(hw, HERMES_TXCOMPLFID);
+               if(fid == 0xFFFF) {
+                       /* Illegal fid found */
+                       printf("unexpected txexc_fid interrupted\n");
+               }
+
+               orp->or_tx.ret_busy = FALSE;
+
+               if(orp->or_flags & OR_F_SEND_AVAIL)     {
+                       orp->or_send_int = TRUE;
+                       if (!orp->or_got_int){
+                               orp->or_got_int = TRUE;
+                               int_event_check = TRUE;
+                       }
+               }
+
+               /* To detect illegal fids */
+               hermes_write_reg(hw, HERMES_TXCOMPLFID, 0xFFFF);
+               events &= ~(HERMES_EV_TXEXC);
+               /* We don't do anything else yet. 
+                * Could be used for statistics */
+       }
+
+       /* Occurs when the asynchronous transmission process is successfully
+          completed */
+       if (events & HERMES_EV_TX) {
+               events &= ~(HERMES_EV_TX);
+               /* Which buffer was sent, represented by an fid */
+               fid = hermes_read_reg (hw, HERMES_TXCOMPLFID);
+               if(fid == 0xFFFF) {
+                       /* Illegal fid found */
+                       printf("unexpected tx_fid interrupted\n");
+               }
+
+               orp->or_tx.ret_busy = FALSE;
+
+               if(orp->or_flags & OR_F_SEND_AVAIL)     {
+                       orp->or_send_int = TRUE;
+                       if (!orp->or_got_int){
+                               orp->or_got_int = TRUE;
+                               int_event_check = TRUE;
+                       }
+               }
+
+               /* To detect illegal fids */
+               hermes_write_reg(hw, HERMES_TXCOMPLFID, 0xFFFF);
+               /* We don't do anything else when such event happens */
+       }
+
+       /* Occurs when an info frame is available in the card */
+       if (events & HERMES_EV_INFO) {
+               events &= ~(HERMES_EV_INFO);
+               /* Process the information, inside the handler (!) */
+               or_ev_info(orp);
+       }
+
+       /* Occurs when a TX buffer is available again for usage */
+       if (events & HERMES_EV_ALLOC) {
+               /* Which frame is now marked as free? */
+               fid = hermes_read_reg (hw, HERMES_ALLOCFID);
+               if (fid == 0xFFFF){
+                       /* An illegal frame identifier is found. Ignore */
+                       printf("Allocate event on unexpected fid\n");
+                       return ;
+               }
+
+               /* To be able to detect illegal fids */
+               hermes_write_reg(hw, HERMES_ALLOCFID, 0xFFFF);
+               
+               events &= ~(HERMES_EV_ALLOC);
+       }
+
+
+       /* Occurs when a frame is received by the asynchronous reception 
+        * process */
+
+       if (events & HERMES_EV_RX) {
+               orp->or_ev_rx = TRUE;
+               events &= ~(HERMES_EV_RX);
+
+               /* If the last buffer is still filled with data, then we don't 
+                * have any buffers available to store the data */
+               if(orp->rx_length[orp->rx_last] != 0) {
+                       /* indeed, we are going to overwrite information
+                        * in a buffer */
+               }
+
+               /* Which buffer is storing the data (represented by a fid) */
+               orp->rxfid[orp->rx_last]
+                                = hermes_read_reg (hw, HERMES_RXFID);
+
+               /* Get the packet from the card and store it in 
+                * orp->rx_buf[orp->rx_last]. The length is returned by this 
+                * function */
+               length = or_get_recvd_packet(orp, orp->rxfid[orp->rx_last],
+                                               (orp->rx_buf[orp->rx_last]));
+
+               if(length < 0) {
+                       /* Error happened. */
+                       printf("length < 0\n");
+                       goto next;
+               } else {
+                       orp->rx_length[orp->rx_last] = length;
+               }
+
+               /* The next buffer will be used the next time, circularly */
+               orp->rx_last++;
+               orp->rx_last %= NR_RX_BUFS;
+
+               if (!orp->or_got_int){
+                       orp->or_got_int = TRUE;
+               }
+               int_event_check = TRUE;
+       }
+next:
+       if (events)     {
+               printf("Unknown event: 0x%x\n", events);
+       }
+
+       /* Acknowledge to the card that the events have been processed. After 
+        * this the card will assume we have processed any buffer which were in
+        * use for this event. */
+       hermes_write_reg (hw, HERMES_EVACK, evstat);
+
+       evstat = hermes_read_reg (hw, HERMES_EVSTAT);
+       if(evstat != 0 && !(evstat & HERMES_EV_TICK)) {
+               goto beginning;
+       }
+
+       return (1);
+}
+
+
+/*****************************************************************************
+ *                or_watchdog_f                                              *
+ *                                                                           *
+ * Will be called regularly to see whether the driver has crashed. If that   *
+ * condition is detected, reset the driver and card                          *
+ *****************************************************************************/
+static void or_watchdog_f(timer_t *tp) {
+       int i;
+       t_or *orp;
+       
+       /* Use a synchronous alarm instead of a watchdog timer. */
+       sys_setalarm(HZ, 0);
+
+       for (i= 0, orp = &or_table[0]; i<OR_PORT_NR; i++, orp++) {
+               if (orp->or_mode != OR_M_ENABLED)
+                       continue;
+
+               if (!(orp->or_flags & OR_F_SEND_AVAIL)) {
+                       /* Assume that an idle system is alive */
+                       orp->or_tx_alive= TRUE;
+                       continue;
+               }
+
+               if (orp->connected == 0) {
+                       orp->or_tx_alive= TRUE;
+                       continue;
+               }
+               if (orp->or_tx_alive) {
+                       orp->or_tx_alive= FALSE;
+                       continue;
+               }
+               
+               printf("or_watchdog_f: resetting port %d\n", i);
+               
+               orp->or_need_reset= TRUE;
+               orp->or_got_int= TRUE;
+               check_int_events();
+       }
+}
+
+/*****************************************************************************
+ *                mess_reply                                                 *
+ *****************************************************************************/
+
+static void mess_reply (message * req, message * reply_mess) {
+       if (send (req->m_source, reply_mess) != 0)
+               panic(__FILE__, "orinoco: unable to mess_reply", NO_NUM);
+
+}
+
+/*****************************************************************************
+ *                or_writev                                                  *
+ *                                                                           *
+ * As far as we can see, this function is never called from 3.1.3. However,  *
+ * it is still in rtl8139, so we'll keep it here as well. It's almost a copy *
+ * of or_writev_s. We left out the comments. For an explanation, see         *
+ * or_writev_s                                                               *
+******************************************************************************/
+static void or_writev (message * mp, int from_int, int vectored) {
+       int port, or_client, count, size, err, data_len, data_off, tx_head;
+       int o, j, n, i, s, p, cps ;
+       struct ethhdr *eh;
+       t_or *orp;
+       clock_t timebefore, t0; 
+       phys_bytes phys_user, iov_src;
+       hermes_t *hw;
+       struct hermes_tx_descriptor desc;
+       struct header_struct hdr;
+
+       iovec_t *iovp;
+       phys_bytes phys_databuf;
+       u16_t txfid;
+       static u8_t databuf[IEEE802_11_DATA_LEN + ETH_HLEN + 2 + 1];
+       memset (databuf, 0, IEEE802_11_DATA_LEN + ETH_HLEN + 3);
+
+       port = mp->DL_PORT;
+       count = mp->DL_COUNT;
+       if (port < 0 || port >= OR_PORT_NR)
+               panic(__FILE__, "orinoco: illegal port", NO_NUM);
+       
+       or_client = mp->DL_PROC;
+       orp = &or_table[port];
+       orp->or_client = or_client;
+       hw = &(orp->hw);
+
+       if (from_int) {
+               assert (orp->or_flags & OR_F_SEND_AVAIL);
+               orp->or_flags &= ~OR_F_SEND_AVAIL;
+               orp->or_send_int = FALSE;
+               orp->or_tx_alive = TRUE;
+       }
+
+       if (orp->or_tx.ret_busy) {
+               assert(!(orp->or_flags & OR_F_SEND_AVAIL));
+               orp->or_flags |= OR_F_SEND_AVAIL;
+               goto suspend_write;
+       }
+
+       assert (orp->or_mode == OR_M_ENABLED);
+       assert (orp->or_flags & OR_F_ENABLED);
+
+       if (vectored) {
+
+               int iov_offset = 0;
+               size = 0;
+               o = 0;
+
+               for (i = 0; i < count; i += IOVEC_NR,
+                    iov_src += IOVEC_NR * sizeof (orp->or_iovec[0]), 
+                        iov_offset += IOVEC_NR * sizeof (orp->or_iovec[0])) {
+
+                       n = IOVEC_NR;
+                       if (i + n > count)
+                               n = count - i;
+                       cps = sys_vircopy(or_client, D, 
+                               ((vir_bytes) mp->DL_ADDR) + iov_offset,
+                               SELF, D, (vir_bytes) orp->or_iovec,
+                               n * sizeof(orp->or_iovec[0]));
+                       if (cps != OK) printf("sys_vircopy failed: %d\n", cps);
+
+                       for (j = 0, iovp = orp->or_iovec; j < n; j++, iovp++) {
+                               s = iovp->iov_size;
+                               if (size + s > ETH_MAX_PACK_SIZE_TAGGED) {
+                                       printf("invalid packet size\n");
+                               }
+                               cps = sys_vircopy(or_client, D, iovp->iov_addr,
+                                       SELF, D, (vir_bytes) databuf + o, s);
+                               if (cps != OK) 
+                                       printf("sys_vircopy failed: %d\n",cps);
+
+                               size += s;
+                               o += s;
+                       }
+               }
+               if (size < ETH_MIN_PACK_SIZE)
+                       printf("invalid packet size %d\n", size);
+       } else {
+               size = mp->DL_COUNT;
+               if (size < ETH_MIN_PACK_SIZE
+                   || size > ETH_MAX_PACK_SIZE_TAGGED)
+                       printf("invalid packet size %d\n", size);
+
+               cps = sys_vircopy(or_client, D, (vir_bytes)mp->DL_ADDR, 
+                       SELF, D, (vir_bytes) databuf, size);
+               if (cps != OK) printf("sys_abscopy failed: %d\n", cps);
+       }
+
+       memset (&desc, 0, sizeof (desc));
+       desc.tx_control = HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX;
+
+       err = hermes_bap_pwrite (hw, USER_BAP, &desc, sizeof (desc), txfid,
+                                0);
+       if (err) {
+               or_reset();
+               goto fail;
+       }
+
+       eh = (struct ethhdr *) databuf;
+       if (ntohs (eh->h_proto) > 1500) {
+
+               data_len = size - ETH_HLEN;
+               data_off = HERMES_802_3_OFFSET + sizeof (hdr);
+
+               memcpy (hdr.dest, eh->h_dest, ETH_ALEN);
+               memcpy (hdr.src, eh->h_src, ETH_ALEN);
+               hdr.len = htons (data_len + ENCAPS_OVERHEAD);
+
+               memcpy (&hdr.dsap, &encaps_hdr, sizeof (encaps_hdr));
+               hdr.ethertype = eh->h_proto;
+
+               err = hermes_bap_pwrite (hw, USER_BAP, &hdr, sizeof (hdr),
+                                        txfid, HERMES_802_3_OFFSET);
+               if (err) {
+                       printf ("%s: Error %d writing packet header to BAP\n",
+                               orp->or_name, err);
+                       goto fail;
+               }
+
+               p = ETH_HLEN;
+       } else {
+               data_len = size + ETH_HLEN;
+               data_off = HERMES_802_3_OFFSET;
+               p = 0;
+       }
+
+       err = hermes_bap_pwrite (hw, USER_BAP,
+                                (void *) &(databuf[p]), RUP_EVEN (data_len),
+                                txfid, data_off);
+       if (err) {
+               printf ("hermes_bap_pwrite(data): error %d\n", err);
+               goto fail;
+       }
+
+       orp->or_tx.ret_busy = TRUE;
+       
+       err = hermes_docmd_wait (hw, HERMES_CMD_TX | HERMES_CMD_RECL,
+                                txfid, NULL);
+       if (err) {
+               orp->or_tx.ret_busy = FALSE;
+               printf ("hermes_docmd_wait(TX|RECL): error %d\n", err);
+               goto fail;
+       }
+
+fail:
+       orp->or_flags |= OR_F_PACK_SENT;
+
+       if (from_int) {
+               return;
+       }
+
+       reply (orp, OK, FALSE);
+       return;
+
+suspend_write:
+       orp->or_tx_mess = *mp;
+       reply (orp, OK, FALSE);
+       return;
+}
+
+
+
+/*****************************************************************************
+ *                or_writev_s                                                *
+ *                                                                           *
+ * Write data which is denoted by the message to the card and send it.       *
+ *****************************************************************************/
+static void or_writev_s (message * mp, int from_int) {
+       int port, or_client, count, size, err, data_len, data_off, tx_head;
+       int o, j, n, i, s, p, cps ;
+       struct ethhdr *eh;
+       t_or *orp;
+       clock_t timebefore, t0; 
+       phys_bytes phys_user, iov_src;
+       hermes_t *hw;
+       struct hermes_tx_descriptor desc;
+       int iov_offset = 0;
+       struct header_struct hdr;
+       iovec_s_t *iovp;
+       phys_bytes phys_databuf;
+       u16_t txfid;
+
+       /* We need space for the max packet size itself, plus an ethernet
+        * header, plus 2 bytes so we can align the IP header on a
+        * 32bit boundary, plus 1 byte so we can read in odd length
+        * packets from the card, which has an IO granularity of 16
+        * bits */
+       static u8_t databuf[IEEE802_11_DATA_LEN + ETH_HLEN + 2 + 1];
+       memset (databuf, 0, IEEE802_11_DATA_LEN + ETH_HLEN + 3);
+
+       port = mp->DL_PORT;
+       count = mp->DL_COUNT;
+       if (port < 0 || port >= OR_PORT_NR)
+               panic(__FILE__, "orinoco: illegal port", NO_NUM);
+
+       or_client = mp->DL_PROC;
+       orp = &or_table[port];
+       orp->or_client = or_client;
+       hw = &(orp->hw);
+
+       /* Switch off interrupts. The card is accessable via 2 BAPs, one for
+        * reading and one for writing. In theory these BAPs should be 
+        * independent, but in practice, the are not. By switching off the
+        * interrupts of the card, the chances of one interfering with the
+        * other should be less */
+       if (from_int){
+               /* We were called with from_int, meaning that the last time we 
+                * were called, no tx buffers were available, and we had to 
+                * suspend. Now, we'll try again to find an empty buffer in the
+                * card */
+               assert (orp->or_flags & OR_F_SEND_AVAIL);
+               orp->or_flags &= ~OR_F_SEND_AVAIL;
+               orp->or_send_int = FALSE;
+               orp->or_tx_alive = TRUE;
+       }
+
+       txfid = orp->or_tx.or_txfid;
+
+       if (orp->or_tx.ret_busy || orp->connected == 0) {
+               /* there is no buffer in the card available */
+               assert(!(orp->or_flags & OR_F_SEND_AVAIL));
+               /* Remember that there is a packet to be sent available */
+               orp->or_flags |= OR_F_SEND_AVAIL;
+               goto suspend_write_s;
+       }
+
+       assert (orp->or_mode == OR_M_ENABLED);
+       assert (orp->or_flags & OR_F_ENABLED);
+
+
+       /* Copy the data to be send from the vector to the databuf */
+       size = 0;
+       o = 0;
+       for (i = 0; i < count; i += IOVEC_NR,
+            iov_src += IOVEC_NR * sizeof (orp->or_iovec_s[0]),
+                iov_offset += IOVEC_NR * sizeof (orp->or_iovec_s[0])) {
+
+               n = IOVEC_NR;
+               if (i + n > count)
+                       n = count - i;
+
+               cps = sys_safecopyfrom(or_client, mp->DL_GRANT, iov_offset,
+                       (vir_bytes) orp->or_iovec_s, 
+                       n * sizeof(orp->or_iovec_s[0]), D);
+               if (cps != OK) 
+                       printf("orinoco: sys_safecopyfrom failed: %d\n", cps);
+
+               for (j = 0, iovp = orp->or_iovec_s; j < n; j++, iovp++) {
+                       s = iovp->iov_size;
+                       if (size + s > ETH_MAX_PACK_SIZE_TAGGED) {
+                               printf("Orinoco: invalid pkt size\n");
+                       }
+
+                       cps = sys_safecopyfrom(or_client, iovp->iov_grant, 0,
+                                               (vir_bytes) databuf + o, s, D);
+                       if (cps != OK) 
+                               printf("orinoco: sys_safecopyfrom failed:%d\n",
+                                               cps);
+
+                       size += s;
+                       o += s;
+               }
+       }
+
+       assert(size >= ETH_MIN_PACK_SIZE); 
+
+       memset (&desc, 0, sizeof (desc));
+       /* Reclaim the tx buffer once the data is sent (OK), or it is clear 
+        * that transmission failed (EX). Reclaiming means that we can reuse 
+        * the buffer again for transmission */
+       desc.tx_control = HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX;
+       /* Actually, this reclaim bit is the only thing which needs to be set 
+        * in the descriptor */
+       err = hermes_bap_pwrite (hw, USER_BAP, &desc, sizeof (desc), txfid,
+                                0);
+       if (err) {
+               printf("hermes_bap_pwrite() descriptor error:resetting card\n");
+               /* When this happens, the card is quite confused: it will not 
+                * recover. Reset it */
+               or_reset();
+               goto fail;
+       }
+
+       eh = (struct ethhdr *) databuf;
+       /* Encapsulate Ethernet-II frames */
+       if (ntohs (eh->h_proto) > 1500) {
+               /* Ethernet-II frame */
+               data_len = size - ETH_HLEN;
+               data_off = HERMES_802_3_OFFSET + sizeof (hdr);
+
+               /* 802.3 header */
+               memcpy (hdr.dest, eh->h_dest, ETH_ALEN);
+               memcpy (hdr.src, eh->h_src, ETH_ALEN);
+               hdr.len = htons (data_len + ENCAPS_OVERHEAD);
+
+               /* 802.2 header */
+               memcpy (&hdr.dsap, &encaps_hdr, sizeof (encaps_hdr));
+               hdr.ethertype = eh->h_proto;
+
+               err = hermes_bap_pwrite (hw, USER_BAP, &hdr, sizeof (hdr),
+                                        txfid, HERMES_802_3_OFFSET);
+               if (err) {
+                       printf ("%s: Error %d writing packet header to BAP\n",
+                               orp->or_name, err);
+                       goto fail;
+               }
+
+               p = ETH_HLEN;
+       } else {
+               /* IEEE 802.3 frame */
+               data_len = size + ETH_HLEN;
+               data_off = HERMES_802_3_OFFSET;
+               p = 0;
+       }
+
+       /* Round up for odd length packets */
+       err = hermes_bap_pwrite (hw, USER_BAP,
+                                (void *) &(databuf[p]), RUP_EVEN (data_len),
+                                txfid, data_off);
+       if (err) {
+               printf ("hermes_bap_pwrite(data): error %d\n", err);
+               goto fail;
+       }
+
+       /* this should be before the docmd_wait. Cause otherwise the bit can 
+               be cleared in the handler (if irq's not off) before it is set
+               and then 1 reset (ret_busy=false) is lost */
+       orp->or_tx.ret_busy = TRUE;
+
+       /* Send the packet which was constructed in txfid */
+       err = hermes_docmd_wait (hw, HERMES_CMD_TX | HERMES_CMD_RECL,
+                                txfid, NULL);
+       if (err) {
+               printf ("hermes_docmd_wait(TX|RECL): error %d\n", err);
+               /* Mark the buffer as available again */
+               orp->or_tx.ret_busy = FALSE;
+               goto fail;
+       } 
+       
+fail:
+       /* If the interrupt handler called, don't send a reply. The reply
+        * will be sent after all interrupts are handled. 
+        */
+       orp->or_flags |= OR_F_PACK_SENT;
+
+       if (from_int) {
+               return;
+       }
+
+       reply (orp, OK, FALSE);
+       return;
+
+suspend_write_s:
+       orp->or_tx_mess = *mp;
+
+       reply (orp, OK, FALSE);
+       return;
+}
+
+
+/*****************************************************************************
+ *                reply                                                      *
+ *                                                                           *
+ * Send a message back to the caller, informing it about the data received   *
+ * or sent                                                                   *
+ *****************************************************************************/
+static void reply (t_or * orp, int err, int may_block) {
+       message reply;
+       int status = 0, r;
+       clock_t now;
+
+       if (orp->or_flags & OR_F_PACK_SENT)
+               status |= DL_PACK_SEND;
+       if (orp->or_flags & OR_F_PACK_RECV)
+               status |= DL_PACK_RECV;
+
+       reply.m_type = DL_TASK_REPLY;
+       reply.DL_PORT = orp - or_table;
+       assert(reply.DL_PORT == 0);
+       reply.DL_PROC = orp->or_client;
+       reply.DL_STAT = status | ((u32_t) err << 16);
+       reply.DL_COUNT = orp->or_read_s;
+
+       if (OK != (r = getuptime(&now)))
+               panic(__FILE__, "orinoco: getuptime() failed:", r);
+
+       reply.DL_CLCK = now;
+       r = send (orp->or_client, &reply);
+
+       if (r == ELOCKED && may_block) {
+               return;
+       }
+
+       if (r < 0)
+               panic(__FILE__, "orinoco: send failed:", r);
+
+       orp->or_read_s = 0;
+       orp->or_flags &= ~(OR_F_PACK_SENT | OR_F_PACK_RECV);
+}
+
+
+
+/*****************************************************************************
+ *                or_ev_info                                                 *
+ *                                                                           *
+ * Process information which comes in from the card                          *
+ *****************************************************************************/
+static void or_ev_info (t_or * orp) {
+       u16_t infofid;
+       int err, len, type, i;
+       hermes_t *hw = &orp->hw;
+
+       struct {
+               u16_t len;
+               u16_t type;
+       } info;
+
+       infofid = hermes_read_reg (hw, HERMES_INFOFID);
+       err = hermes_bap_pread (hw, IRQ_BAP, &info, sizeof (info), infofid,
+                               0);
+       if (err) {
+               printf ("%s: error %d reading info frame.\n", orp->or_name,
+                       err);
+               return;
+       }
+
+       len = HERMES_RECLEN_TO_BYTES (info.len);
+       type = info.type;
+
+       switch (type) {
+       case HERMES_INQ_TALLIES:
+               {
+                       struct hermes_tallies_frame tallies;
+
+                       if (len > sizeof (tallies))     {
+                               printf ("%s: Tallies frame too long ",
+                                       orp->or_name);
+                               printf ("(%d bytes)\n", len);
+                               len = sizeof (tallies);
+                       }
+                       hermes_read_words (hw, HERMES_DATA1,
+                                          (void *) &tallies, len / 2);
+                       /* TODO: do something with the tallies structure */
+               }
+               break;
+
+       case HERMES_INQ_LINKSTATUS: {
+                       u16_t newstatus;
+                       struct hermes_linkstatus linkstatus;
+
+                       if (len != sizeof (linkstatus)) {
+                               printf ("%s: Unexpected size for linkstatus ",
+                                       orp->or_name);
+                               printf ("frame (%d bytes)\n", len);
+                       }
+
+                       hermes_read_words (hw, HERMES_DATA1,
+                                          (void *) &linkstatus, len / 2);
+                       newstatus = linkstatus.linkstatus;
+
+                       if ((newstatus == HERMES_LINKSTATUS_CONNECTED)
+                           || (newstatus == HERMES_LINKSTATUS_AP_CHANGE)
+                           || (newstatus == HERMES_LINKSTATUS_AP_IN_RANGE)) {
+                               orp->connected = 1;
+
+               if(orp->or_flags & OR_F_SEND_AVAIL)     {
+                       orp->or_send_int = TRUE;
+                       orp->or_got_int = TRUE;
+                       int_event_check = TRUE;
+               }
+
+
+                       }
+                       else if ((newstatus ==
+                                 HERMES_LINKSTATUS_NOT_CONNECTED)
+                                || (newstatus ==
+                                    HERMES_LINKSTATUS_DISCONNECTED)
+                                || (newstatus ==
+                                    HERMES_LINKSTATUS_AP_OUT_OF_RANGE)
+                                || (newstatus ==
+                                    HERMES_LINKSTATUS_ASSOC_FAILED)) {
+                               orp->connected = 0;
+                       }
+
+                       if (newstatus != orp->last_linkstatus)
+                               print_linkstatus(orp, newstatus);
+
+                       orp->last_linkstatus = newstatus;
+               }
+               break;
+       default:
+               printf ("%s:Unknown information frame received(type %04x).\n",
+                       orp->or_name, type);
+               break;
+       }
+}
+
+/*****************************************************************************
+ *                or_print_linkstatus                                        *
+ *                                                                           *
+ * Process information which comes in from the card                          *
+ *****************************************************************************/
+static void print_linkstatus (t_or * orp, u16_t status) {
+       int err;
+       u16_t d;
+       char *s;
+       hermes_t *hw = &(orp->hw);
+
+       switch (status) {
+       case HERMES_LINKSTATUS_NOT_CONNECTED:
+               s = "Not Connected";
+               break;
+       case HERMES_LINKSTATUS_CONNECTED:
+               s = "Connected";
+               break;
+       case HERMES_LINKSTATUS_DISCONNECTED:
+               s = "Disconnected";
+               break;
+       case HERMES_LINKSTATUS_AP_CHANGE:
+               s = "AP Changed";
+               break;
+       case HERMES_LINKSTATUS_AP_OUT_OF_RANGE:
+               s = "AP Out of Range";
+               break;
+       case HERMES_LINKSTATUS_AP_IN_RANGE:
+               s = "AP In Range";
+               break;
+       case HERMES_LINKSTATUS_ASSOC_FAILED:
+               s = "Association Failed";
+               break;
+       default:
+               s = "UNKNOWN";
+       }
+
+       printf ("%s: link status: %s, ", orp->or_name, s);
+
+       err = hermes_read_wordrec (hw, USER_BAP, 
+                       HERMES_RID_CURRENTCHANNEL, &d);
+       if (err) {
+               printf ("%s: Error %d \n", orp->or_name, err);
+               return;
+       }
+       printf("channel: %d, freq: %d MHz ", 
+               d, (channel_frequency[d-1]));
+
+}
+
+
+/*****************************************************************************
+ *                or_check_ints                                              *
+ *                                                                           *
+ * Process events which have been postponed in the interrupt handler         *
+ *****************************************************************************/
+static void or_check_ints (t_or * orp) {
+       int or_flags;
+       hermes_t *hw = &orp->hw;
+
+       if (orp->or_need_reset)
+               or_reset();
+       if ((orp->rx_first!=orp->rx_last) && (orp->or_flags & OR_F_READING)) {
+               orp->or_ev_rx = 0;
+               if (orp->or_rx_mess.m_type == DL_READV) {
+                       or_readv (&orp->or_rx_mess, TRUE, TRUE);
+               } else if(orp->or_rx_mess.m_type == DL_READV_S) {
+                       or_readv_s (&orp->or_rx_mess, TRUE);
+               } else {
+                       assert(orp->or_rx_mess.m_type == DL_READ);
+                       or_readv (&orp->or_rx_mess, TRUE, FALSE);
+               }
+       }
+
+       if (orp->or_send_int) {
+               if (orp->or_tx_mess.m_type == DL_WRITEV) {
+                       or_writev (&orp->or_tx_mess, TRUE, TRUE);
+               }
+               else if(orp->or_tx_mess.m_type == DL_WRITEV_S) {
+                       or_writev_s (&orp->or_tx_mess, TRUE);
+               } else {
+                       assert(orp->or_tx_mess.m_type == DL_WRITE);
+                       or_writev (&orp->or_tx_mess, TRUE, FALSE);
+               }
+       }
+
+       if (orp->or_flags & (OR_F_PACK_SENT | OR_F_PACK_RECV)) {
+               reply (orp, OK, TRUE);
+       }
+}
+
+
+/*****************************************************************************
+ *                is_ethersnap                                               *
+ *                                                                           *
+ * is there an LLC and SNAP header in the ethernet packet? The inet task     *
+ * isn't very interested in it...                                            *
+ *****************************************************************************/
+static int is_ethersnap(struct header_struct *hdr)  {
+
+       /* We de-encapsulate all packets which, a) have SNAP headers
+        * (i.e. SSAP=DSAP=0xaa and CTRL=0x3 in the 802.2 LLC header
+        * and where b) the OUI of the SNAP header is 00:00:00 or
+        * 00:00:f8 - we need both because different APs appear to use
+        * different OUIs for some reason */
+       return (memcmp(&hdr->dsap, &encaps_hdr, 5) == 0)
+               && ( (hdr->oui[2] == 0x00) || (hdr->oui[2] == 0xf8) );
+}
+       
+/*****************************************************************************
+ *                or_readv                                                   *
+ *                                                                           *
+ * As far as we can see, this function is never called from 3.1.3. However,  *
+ * it is still in rtl8139, so we'll keep it here as well. It's almost a copy *
+ * of or_readv_s. We left out the comments. For an explanation, see          *
+ * or_readv_s                                                                *
+ *****************************************************************************/
+static void or_readv (message * mp, int from_int, int vectored) {
+       int i, j, n, o, s, s1, dl_port, or_client, count, size, err, yep, cps;
+       port_t port;
+       clock_t timebefore;
+       unsigned amount, totlen, packlen;
+       struct hermes_rx_descriptor desc;
+       phys_bytes dst_phys, iov_src;
+       u16_t d_start, d_end, rxfid, status;
+       struct header_struct hdr;
+       int length, offset;
+       u32_t l, rxstat;
+       struct ethhdr *eh;
+       struct header_struct *h;
+       t_or *orp;
+       hermes_t *hw;
+       iovec_t *iovp;
+       u8_t *databuf;
+
+       dl_port = mp->DL_PORT;
+       count = mp->DL_COUNT;
+       if (dl_port < 0 || dl_port >= OR_PORT_NR)
+               panic(__FILE__, "orinoco: illegal port:", dl_port);
+
+       orp = &or_table[dl_port];
+       or_client = mp->DL_PROC;
+       orp->or_client = or_client;
+       hw = &(orp->hw);
+
+       assert (orp->or_mode == OR_M_ENABLED);
+       assert (orp->or_flags & OR_F_ENABLED);
+
+       if (!from_int && (orp->rx_first==orp->rx_last)) {
+               goto suspend_readv;
+       }
+
+       rxfid = orp->rxfid[orp->rx_first];
+       databuf = &(orp->rx_buf[orp->rx_first][0]);
+       length = orp->rx_length[orp->rx_first];
+
+       orp->rxfid[orp->rx_first] = NO_FID;
+       orp->rx_length[orp->rx_first] = 0;
+
+       orp->rx_first++;
+       orp->rx_first %= NR_RX_BUFS;
+
+       o = 0;
+       
+       if (vectored) {
+               int iov_offset = 0;
+               size = 0;
+
+               for (i = 0; i < count; i += IOVEC_NR,
+                       iov_src += IOVEC_NR * sizeof (orp->or_iovec[0]),
+                       iov_offset += IOVEC_NR * sizeof(orp->or_iovec[0])) {
+
+                       n = IOVEC_NR;
+                       if (i + n > count)
+                               n = count - i;
+                       
+                       cps = sys_vircopy(or_client, D, 
+                                       (vir_bytes) mp->DL_ADDR + iov_offset,
+                                       SELF, D, (vir_bytes) orp->or_iovec, 
+                                       n * sizeof(orp->or_iovec[0]));
+                       if (cps != OK) printf("sys_vircopy failed: %d (%d)\n", 
+                                                       cps, __LINE__);
+
+                       for (j = 0, iovp = orp->or_iovec; j < n; j++, iovp++) {
+                               s = iovp->iov_size;
+                               if (size + s > length) {
+                                       assert (length > size);
+                                       s = length - size;
+                               }
+
+                               cps = sys_vircopy(SELF, D, 
+                                               (vir_bytes) databuf + o,
+                                               or_client, D, 
+                                               iovp->iov_addr, s);
+                               if (cps != OK) 
+                                       printf("sys_vircopy failed:%d (%d)\n", 
+                                               cps, __LINE__);
+
+                               size += s;
+                               if (size == length)
+                                       break;
+                               o += s;
+                       }
+                       if (size == length)
+                               break;
+               }
+               assert (size >= length);
+       } 
+
+       orp->or_stat.ets_packetR++;
+       orp->or_read_s = length;
+       orp->or_flags &= ~OR_F_READING;
+       orp->or_flags |= OR_F_PACK_RECV;
+
+       if (!from_int)
+               reply (orp, OK, FALSE);
+
+       return;
+
+suspend_readv :
+       if (from_int) {
+               assert (orp->or_flags & OR_F_READING);
+               return;
+       }
+
+       orp->or_rx_mess = *mp;
+       assert (!(orp->or_flags & OR_F_READING));
+       orp->or_flags |= OR_F_READING;
+
+       reply (orp, OK, FALSE);
+}
+
+
+/*****************************************************************************
+ *                or_readv_s                                                 *
+ *                                                                           *
+ * Copy the data which is stored in orp->rx_buf[orp->rx_first] in the vector *
+ * which was given with the message *mp                                      *
+ *****************************************************************************/
+static void or_readv_s (message * mp, int from_int) {
+       int i, j, n, o, s, s1, dl_port, or_client, count, size, err, cps;
+       int iov_offset = 0, length, offset;
+       port_t port;
+       clock_t timebefore;
+       unsigned amount, totlen, packlen;
+       struct hermes_rx_descriptor desc;
+       phys_bytes dst_phys, iov_src;
+       u16_t d_start, d_end, rxfid, status;
+       struct header_struct hdr;
+       u32_t l, rxstat;
+       struct ethhdr *eh;
+       struct header_struct *h;
+       t_or *orp;
+       hermes_t *hw;
+
+       iovec_s_t *iovp;
+       phys_bytes databuf_phys;
+
+       u8_t *databuf;
+
+       dl_port = mp->DL_PORT;
+       count = mp->DL_COUNT;
+       if (dl_port < 0 || dl_port >= OR_PORT_NR)
+               panic(__FILE__, "orinoco: illegal port:", dl_port);
+
+       orp = &or_table[dl_port];
+       or_client = mp->DL_PROC;
+       orp->or_client = or_client;
+       hw = &(orp->hw);
+
+       assert (orp->or_mode == OR_M_ENABLED);
+       assert (orp->or_flags & OR_F_ENABLED);
+
+       if (!from_int && (orp->rx_first==orp->rx_last))
+
+       {
+       /* if we are not called from a hard int (data is not yet available) and
+        * there are no buffers (or->rx_buf[x]) which contain any data, we cant
+        * copy any data to the inet server. Goto suspend, and wait for data 
+        * to arrive */
+               goto suspend_readv_s;
+       }
+       
+
+
+       /* get the buffer which contains new data */
+       rxfid = orp->rxfid[orp->rx_first];
+       /* and store the pointer to this data in databuf */
+       databuf = &(orp->rx_buf[orp->rx_first][0]);
+       length = orp->rx_length[orp->rx_first];
+
+       orp->rxfid[orp->rx_first] = NO_FID;
+       orp->rx_length[orp->rx_first] = 0;
+
+       /* Next time, the next buffer with data will be retrieved */
+       orp->rx_first++;
+       orp->rx_first %= NR_RX_BUFS;
+
+       o = 0;
+       /* The data which we want to be copied to the vector starts at 
+        * *databuf and will be copied to the vecor below */
+       size = 0;
+       for (i = 0; i < count; i += IOVEC_NR,
+               iov_src += IOVEC_NR * sizeof (orp->or_iovec_s[0]),
+               iov_offset += IOVEC_NR * sizeof(orp->or_iovec_s[0])) {
+               n = IOVEC_NR;
+               if (i + n > count)
+                       n = count - i;
+
+               cps = sys_safecopyfrom(or_client, mp->DL_GRANT, iov_offset, 
+                               (vir_bytes)orp->or_iovec_s,
+                               n * sizeof(orp->or_iovec_s[0]), D);
+               if (cps != OK) 
+                       panic(__FILE__, 
+                       "orinoco: warning, sys_safecopytp failed:", cps);
+
+               for (j = 0, iovp = orp->or_iovec_s; j < n; j++, iovp++) {
+                       s = iovp->iov_size;
+                       if (size + s > length) {
+                               assert (length > size);
+                               s = length - size;
+                       }
+                       cps = sys_safecopyto(or_client, iovp->iov_grant, 0, 
+                                       (vir_bytes) databuf + o, s, D);
+                       if (cps != OK) 
+                               panic(__FILE__, 
+                               "orinoco: warning, sys_safecopy failed:", 
+                               cps);
+
+                       size += s;
+                       if (size == length)
+                               break;
+                       o += s;
+               }
+               if (size == length)
+                       break;
+       }
+
+       assert(size >= length);
+
+       orp->or_stat.ets_packetR++;
+drop:
+       orp->or_read_s = length;
+       orp->or_flags &= ~OR_F_READING;
+       orp->or_flags |= OR_F_PACK_RECV;
+
+       if (!from_int) {
+               /* There was data in the orp->rx_buf[x] which is now copied to 
+                * the inet sever. Tell the inet server */
+               reply (orp, OK, FALSE);
+       }
+
+       return;
+suspend_readv_s:
+       if (from_int) {
+               assert (orp->or_flags & OR_F_READING);
+               /* No need to store any state */
+               return;
+       }
+
+       /* We want to store the message, so that next time when we are called 
+        * by hard int, we know where to copy the received data */
+       orp->or_rx_mess = *mp;
+       assert (!(orp->or_flags & OR_F_READING));
+       orp->or_flags |= OR_F_READING;
+
+       reply (orp, OK, FALSE);
+
+}
+
+
+/*****************************************************************************
+ *            or_get_recvd_packet                                            *
+ *                                                                           *
+ * The card has received data. Retrieve the data from the card and put it    *
+ * in a buffer in the driver (in the orp structure)                          *
+ *****************************************************************************/
+static int or_get_recvd_packet(t_or *orp, u16_t rxfid, u8_t *databuf) {
+       struct hermes_rx_descriptor desc;
+       hermes_t *hw;
+       struct header_struct hdr;
+       int err, length, offset;
+       struct ethhdr *eh;
+       u16_t status;
+       
+       memset(databuf, 0, IEEE802_11_FRAME_LEN);
+
+       hw = &(orp->hw);
+
+       /* Read the data from the buffer in the card which holds the data. 
+        * First get the descriptor which will tell us whether the packet is 
+        * healthy*/
+       err = hermes_bap_pread (hw, IRQ_BAP, &desc, sizeof (desc), rxfid, 0);
+       if (err) {
+               printf("Orinoco: error %d reading Rx descriptor. "
+                       "Frame dropped\n", err);
+               orp->or_stat.ets_recvErr++;
+               return -1;
+       }
+
+       status = desc.status;
+
+       if (status & HERMES_RXSTAT_ERR) {
+               if (status & HERMES_RXSTAT_UNDECRYPTABLE) {
+                       printf("Error reading Orinoco Rx descriptor.Dropped");
+               } else {
+                       orp->or_stat.ets_CRCerr++;
+                       printf("Orinoco: Bad CRC on Rx. Frame dropped\n");
+               }
+               orp->or_stat.ets_recvErr++;
+               return -1;
+       }
+
+       /* For now we ignore the 802.11 header completely, assuming
+          that the card's firmware has handled anything vital. The only
+          thing we want to know is the length of the received data */
+       err = hermes_bap_pread (hw, IRQ_BAP, &hdr, sizeof (hdr),
+                               rxfid, HERMES_802_3_OFFSET);
+
+       if (err) {
+               printf("Orinoco: error %d reading frame header. "
+                       "Frame dropped\n", err);
+               orp->or_stat.ets_recvErr++;
+               return -1;
+       }
+
+       length = ntohs (hdr.len);
+       
+       /* Sanity checks */
+       if (length < 3) {
+               /* No for even an 802.2 LLC header */
+               printf("Orinoco: error in frame length: length = %d\n",
+                       length);
+               /* orp->or_stat.ets_recvErr++; */
+               return -1;
+       }
+
+       if (length > IEEE802_11_DATA_LEN) {
+               printf("Orinoco: Oversized frame received (%d bytes)\n",
+                       length);
+               orp->or_stat.ets_recvErr++;
+               return -1;
+       }
+
+       length += sizeof (struct ethhdr);
+       offset = HERMES_802_3_OFFSET;
+
+       /* Read the interesting parts of the data to the drivers memory. This
+        * would be everything from the 802.3 layer and up */
+       err = hermes_bap_pread (hw,
+                               IRQ_BAP, (void *) databuf, RUP_EVEN (length),
+                               rxfid, offset);
+
+       if (err) {
+               printf("Orinoco: error doing hermes_bap_pread()\n");
+               orp->or_stat.ets_recvErr++;
+               return -1;
+       }
+
+       /* Some types of firmware give us the SNAP and OUI headers. Remove these.
+        */
+       if (is_ethersnap(&hdr)) {
+               eh = (struct ethhdr *) databuf;
+               length -= 8;
+
+               
+               memcpy (databuf + ETH_ALEN * 2, 
+                       databuf + sizeof(struct header_struct) - 2, 
+                       length - ETH_ALEN * 2);
+       }
+
+       if(length<60) length=60;
+       
+       return length;
+}
+
+/*****************************************************************************
+ *            or_getstat                                                     *
+ *                                                                           *
+ * Return the statistics structure. The statistics aren't updated until now, *
+ * so this won't return much interesting yet.                                *
+ *****************************************************************************/
+static void or_getstat (message * mp) {
+       int r, port;
+       eth_stat_t stats;
+       t_or *orp;
+
+       port = mp->DL_PORT;
+       if (port < 0 || port >= OR_PORT_NR)
+               panic(__FILE__, "orinoco: illegal port:", port);
+       orp = &or_table[port];
+       orp->or_client = mp->DL_PROC;
+
+       assert (orp->or_mode == OR_M_ENABLED);
+       assert (orp->or_flags & OR_F_ENABLED);
+
+       stats = orp->or_stat;
+
+       r = sys_datacopy(SELF, (vir_bytes)&stats, mp->DL_PROC,
+                       (vir_bytes) mp->DL_ADDR, sizeof(stats));
+       if(r != OK) {
+               panic(__FILE__, "or_getstat: send failed:", r); 
+       }
+
+       mp->m_type = DL_STAT_REPLY;
+       mp->DL_PORT = port;
+       mp->DL_STAT = OK;
+
+       r = send(mp->m_source, mp);
+       if(r != OK)
+               panic(__FILE__, "orinoco: getstat failed:", r);
+
+       /*reply (orp, OK, FALSE);*/
+
+}
+
+/*****************************************************************************
+ *            or_getstat_s                                                   *
+ *                                                                           *
+ * Return the statistics structure. The statistics aren't updated until now, *
+ * so this won't return much interesting yet.                                *
+ *****************************************************************************/
+static void or_getstat_s (message * mp) {
+       int r, port;
+       eth_stat_t stats;
+       t_or *orp;
+
+       port = mp->DL_PORT;
+       if (port < 0 || port >= OR_PORT_NR)
+               panic(__FILE__, "orinoco: illegal port:", port);
+       assert(port==0);
+       orp = &or_table[port];
+       orp->or_client = mp->DL_PROC;
+
+       assert (orp->or_mode == OR_M_ENABLED);
+       assert (orp->or_flags & OR_F_ENABLED);
+
+       stats = orp->or_stat;
+
+       r = sys_safecopyto(mp->DL_PROC, mp->DL_GRANT, 0, 
+                               (vir_bytes) &stats, sizeof(stats), D);
+       if(r != OK) {
+               panic(__FILE__, "or_getstat_s: sys_safecopyto failed:", r);
+       }
+
+       mp->m_type = DL_STAT_REPLY;
+       mp->DL_PORT = port;
+       mp->DL_STAT = OK;
+
+       r = send(mp->m_source, mp);
+       if(r != OK)
+               panic(__FILE__, "orinoco: getstat_s failed:", r);
+}
+
diff --git a/drivers/orinoco/orinoco.h b/drivers/orinoco/orinoco.h
new file mode 100755 (executable)
index 0000000..45daee7
--- /dev/null
@@ -0,0 +1,104 @@
+/* 
+ * orinoco.h
+ *
+ * This file contains the most important structure for the driver: t_or
+ * and some configurable definitions
+ *
+ * Created by Stevens Le Blond <slblond@few.vu.nl> 
+ *       and Michael Valkering <mjvalker@cs.vu.nl>
+ */
+
+#include               <net/gen/ether.h>
+#include               <net/gen/eth_io.h>
+
+#define                NR_RX_BUFS 32
+
+#define                        LARGE_KEY_LENGTH 13
+#define                 IW_ESSID_MAX_SIZE 32
+#define                        OR_PORT_NR 1
+#define                        IOVEC_NR 16     
+#define                        OR_ENVVAR "ORETH"
+#define                        OR_NAME "orinoco#n"
+
+#define                        IEEE802_11_HLEN         30
+#define                        IEEE802_11_DATA_LEN     (2304)
+#define                        IEEE802_11_FRAME_LEN    (IEEE802_11_DATA_LEN + IEEE802_11_HLEN + 3) 
+
+typedef struct s_or
+{
+       int or_irq;
+       int or_hook_id;
+       int or_mode;
+       int or_flags;
+       char *or_model;
+       int or_client;
+       int or_link_up;
+       int or_got_int;
+       int or_tx_alive;
+       int or_send_int;
+       int or_clear_rx;
+       u32_t or_base_port;
+       int or_need_reset;
+       int or_report_link;
+
+       /* Events */
+       int or_ev_rx;
+       int or_ev_tx;
+       int or_ev_info;
+       int or_ev_txexc;
+       int or_ev_alloc;
+       int connected;
+       u16_t channel_mask;
+       u16_t channel;
+       u16_t ap_density;
+       u16_t rts_thresh;
+       int bitratemode;
+       int last_linkstatus;
+       int max_data_len;
+       int port_type;
+
+       /* Rx */
+       phys_bytes or_rx_buf;
+       vir_bytes or_read_s;
+       u16_t rxfid[NR_RX_BUFS];
+       int rx_length[NR_RX_BUFS];
+       u8_t rx_buf[NR_RX_BUFS][IEEE802_11_FRAME_LEN];
+       u8_t rx_offset[NR_RX_BUFS];
+       int rx_first;
+       int rx_last;
+       int rx_current;
+
+       /* Tx */
+       u16_t or_nicbuf_size;
+       vir_bytes or_transm_s;
+       int or_tx_head;
+       int or_tx_tail;
+
+       struct
+       {
+               int ret_busy;
+               u16_t or_txfid;
+       } or_tx;
+       u32_t or_ertxth;        
+
+       /* PCI related */
+       int or_seen;            
+       u8_t or_pci_bus;
+       u8_t or_pci_dev;
+       u8_t or_pci_func;
+       int devind;
+
+       /* 'large' items */
+       irq_hook_t or_hook;
+       eth_stat_t or_stat;
+       message or_rx_mess;
+       message or_tx_mess;
+       ether_addr_t or_address;
+       iovec_t or_iovec[IOVEC_NR];
+       iovec_s_t or_iovec_s[IOVEC_NR];
+       char or_name[sizeof (OR_NAME)];
+       hermes_t hw;
+       char nick[IW_ESSID_MAX_SIZE + 1];
+
+
+} t_or;
index 4e3c51d0ee4997c6d836da63285e0868ca6791a0..21511aeac3b57296d4e3ef3ef7d16ed3f3427db4 100644 (file)
@@ -207,3 +207,27 @@ driver printer
                SAFECOPYTO      # 32
        ;
 };
+
+driver orinoco
+{
+       system
+               PRIVCTL         #  4
+               DEVIO           # 21
+               GETINFO         # 26
+               UMAP            # 14
+               IRQCTL          # 19
+               DEVIO           # 21
+               #SDEVIO         # 22
+               SETALARM        # 24
+               TIMES           # 25
+               GETINFO         # 26
+               SAFECOPYFROM    # 31
+               SAFECOPYTO      # 32
+               SETGRANT        # 34
+               VM_MAP          # 30
+       ;
+       pci device      1260/3873;
+       uid     0;
+};
+
+
index f4aa98d19436ab6d867c174a6f5309aac63f4b45..e41e3d7e3c7780bfffebede71ade7989b0da43e4 100644 (file)
@@ -91,7 +91,7 @@ start)
     fi
 
     # start only network drivers that are in use
-    for driver in lance rtl8139 fxp dpeth dp8390
+    for driver in lance rtl8139 fxp dpeth dp8390 orinoco
     do
         if grep " $driver " /etc/inet.conf > /dev/null  2>&1
         then 
@@ -135,7 +135,8 @@ start)
            echo -n "Starting networking:"
            if grep -s 'psip0.*default' /etc/inet.conf 
            then        ifconfig -h 10.0.0.1
-           else        daemonize dhcpd
+           else        sleep 5
+                       daemonize dhcpd
            fi
            daemonize nonamed -L
            if [ -f "$DAEMONS" ]