. memory maps in physical memory (for /dev/mem) with new vm interface . pci complete_bars() seems to be buggy behaviour sometimes . startup script opens its own stdout, stderr and stdin so init doesn't have to do it
		
			
				
	
	
		
			2393 lines
		
	
	
		
			70 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			2393 lines
		
	
	
		
			70 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
/*
 | 
						|
 * 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_i386.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 */
 | 
						|
 | 
						|
u32_t system_hz;
 | 
						|
 | 
						|
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;
 | 
						|
 | 
						|
	system_hz = sys_hz();
 | 
						|
 | 
						|
	(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 < system_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(system_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 I386_PAGE_SIZE big: see 
 | 
						|
	 * calculation with the offset */
 | 
						|
	size = 2 * I386_PAGE_SIZE;	
 | 
						|
 | 
						|
	buf = (char *)malloc(size);
 | 
						|
	if(buf == NULL) 
 | 
						|
		panic(__FILE__, "map_hw_buffer: cannot malloc size:", size);
 | 
						|
 | 
						|
	/* Let the mapped memory by I386_PAGE_SIZE aligned */
 | 
						|
	o = I386_PAGE_SIZE - ((vir_bytes)buf % I386_PAGE_SIZE);
 | 
						|
	abuf = buf + o;
 | 
						|
 | 
						|
#if 0
 | 
						|
	r = sys_vm_map(SELF, 1, (vir_bytes)abuf, 
 | 
						|
			1 * I386_PAGE_SIZE, (phys_bytes)orp->or_base_port);
 | 
						|
#else
 | 
						|
	r = ENOSYS;
 | 
						|
#endif
 | 
						|
 | 
						|
	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(system_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);
 | 
						|
}
 | 
						|
 |