2007-07-24 16:49:09 +02:00
|
|
|
/*
|
|
|
|
* 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 <minix/syslib.h>
|
|
|
|
#include <minix/type.h>
|
|
|
|
#include <minix/sysutil.h>
|
|
|
|
#include <timers.h>
|
|
|
|
#include <ibm/pci.h>
|
|
|
|
#include <minix/ds.h>
|
2009-09-29 20:47:56 +02:00
|
|
|
#include <minix/endpoint.h>
|
2010-02-09 17:43:34 +01:00
|
|
|
#include "../../kernel/const.h"
|
|
|
|
#include "../../kernel/config.h"
|
|
|
|
#include "../../kernel/type.h"
|
2007-07-24 16:49:09 +02:00
|
|
|
|
|
|
|
#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 }
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2010-02-09 16:23:38 +01:00
|
|
|
static timer_t or_watchdog;
|
2007-07-24 16:49:09 +02:00
|
|
|
|
|
|
|
#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>
|
2008-11-19 13:26:10 +01:00
|
|
|
#include <sys/vm_i386.h>
|
2007-07-24 16:49:09 +02:00
|
|
|
#include <sys/types.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
|
|
|
|
|
2010-02-09 16:23:38 +01:00
|
|
|
PRIVATE t_or or_table[OR_PORT_NR];
|
2007-07-24 16:49:09 +02:00
|
|
|
|
|
|
|
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 */
|
2010-02-09 16:23:38 +01:00
|
|
|
PRIVATE const long channel_frequency[] = {
|
2007-07-24 16:49:09 +02:00
|
|
|
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 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()
|
2009-09-29 20:47:56 +02:00
|
|
|
* can change its message type to fake an interrupt message.
|
2007-07-24 16:49:09 +02:00
|
|
|
*/
|
|
|
|
PRIVATE message m;
|
|
|
|
PRIVATE int int_event_check; /* set to TRUE if events arrived */
|
|
|
|
|
2010-02-09 16:23:38 +01:00
|
|
|
PRIVATE u32_t system_hz;
|
2008-12-11 15:42:23 +01:00
|
|
|
|
2010-02-09 16:23:38 +01:00
|
|
|
PRIVATE const char *progname;
|
2007-07-24 16:49:09 +02:00
|
|
|
|
Basic System Event Framework (SEF) with ping and live update.
SYSLIB CHANGES:
- SEF must be used by every system process and is thereby part of the system
library.
- The framework provides a receive() interface (sef_receive) for system
processes to automatically catch known system even messages and process them.
- SEF provides a default behavior for each type of system event, but allows
system processes to register callbacks to override the default behavior.
- Custom (local to the process) or predefined (provided by SEF) callback
implementations can be registered to SEF.
- SEF currently includes support for 2 types of system events:
1. SEF Ping. The event occurs every time RS sends a ping to figure out
whether a system process is still alive. The default callback implementation
provided by SEF is to notify RS back to let it know the process is alive
and kicking.
2. SEF Live update. The event occurs every time RS sends a prepare to update
message to let a system process know an update is available and to prepare
for it. The live update support is very basic for now. SEF only deals with
verifying if the prepare state can be supported by the process, dumping the
state for debugging purposes, and providing an event-driven programming
model to the process to react to state changes check-in when ready to update.
- SEF should be extended in the future to integrate support for more types of
system events. Ideally, all the cross-cutting concerns should be integrated into
SEF to avoid duplicating code and ease extensibility. Examples include:
* PM notify messages primarily used at shutdown.
* SYSTEM notify messages primarily used for signals.
* CLOCK notify messages used for system alarms.
* Debug messages. IS could still be in charge of fkey handling but would
forward the debug message to the target process (e.g. PM, if the user
requested debug information about PM). SEF would then catch the message and
do nothing unless the process has registered an appropriate callback to
deal with the event. This simplifies the programming model to print debug
information, avoids duplicating code, and reduces the effort to print
debug information.
SYSTEM PROCESSES CHANGES:
- Every system process registers SEF callbacks it needs to override the default
system behavior and calls sef_startup() right after being started.
- sef_startup() does almost nothing now, but will be extended in the future to
support callbacks of its own to let RS control and synchronize with every
system process at initialization time.
- Every system process calls sef_receive() now rather than receive() directly,
to let SEF handle predefined system events.
RS CHANGES:
- RS supports a basic single-component live update protocol now, as follows:
* When an update command is issued (via "service update *"), RS notifies the
target system process to prepare for a specific update state.
* If the process doesn't respond back in time, the update is aborted.
* When the process responds back, RS kills it and marks it for refreshing.
* The process is then automatically restarted as for a buggy process and can
start running again.
* Live update is currently prototyped as a controlled failure.
2009-12-21 15:12:21 +01:00
|
|
|
/* SEF functions and variables. */
|
|
|
|
FORWARD _PROTOTYPE( void sef_local_startup, (void) );
|
Initialization protocol for system services.
SYSLIB CHANGES:
- SEF framework now supports a new SEF Init request type from RS. 3 different
callbacks are available (init_fresh, init_lu, init_restart) to specify
initialization code when a service starts fresh, starts after a live update,
or restarts.
SYSTEM SERVICE CHANGES:
- Initialization code for system services is now enclosed in a callback SEF will
automatically call at init time. The return code of the callback will
tell RS whether the initialization completed successfully.
- Each init callback can access information passed by RS to initialize. As of
now, each system service has access to the public entries of RS's system process
table to gather all the information required to initialize. This design
eliminates many existing or potential races at boot time and provides a uniform
initialization interface to system services. The same interface will be reused
for the upcoming publish/subscribe model to handle dynamic
registration / deregistration of system services.
VM CHANGES:
- Uniform privilege management for all system services. Every service uses the
same call mask format. For boot services, VM copies the call mask from init
data. For dynamic services, VM still receives the call mask via rs_set_priv
call that will be soon replaced by the upcoming publish/subscribe model.
RS CHANGES:
- The system process table has been reorganized and split into private entries
and public entries. Only the latter ones are exposed to system services.
- VM call masks are now entirely configured in rs/table.c
- RS has now its own slot in the system process table. Only kernel tasks and
user processes not included in the boot image are now left out from the system
process table.
- RS implements the initialization protocol for system services.
- For services in the boot image, RS blocks till initialization is complete and
panics when failure is reported back. Services are initialized in their order of
appearance in the boot image priv table and RS blocks to implements synchronous
initialization for every system service having the flag SF_SYNCH_BOOT set.
- For services started dynamically, the initialization protocol is implemented
as though it were the first ping for the service. In this case, if the
system service fails to report back (or reports failure), RS brings the service
down rather than trying to restart it.
2010-01-08 02:20:42 +01:00
|
|
|
FORWARD _PROTOTYPE( int sef_cb_init_fresh, (int type, sef_init_info_t *info) );
|
|
|
|
EXTERN char **env_argv;
|
Basic System Event Framework (SEF) with ping and live update.
SYSLIB CHANGES:
- SEF must be used by every system process and is thereby part of the system
library.
- The framework provides a receive() interface (sef_receive) for system
processes to automatically catch known system even messages and process them.
- SEF provides a default behavior for each type of system event, but allows
system processes to register callbacks to override the default behavior.
- Custom (local to the process) or predefined (provided by SEF) callback
implementations can be registered to SEF.
- SEF currently includes support for 2 types of system events:
1. SEF Ping. The event occurs every time RS sends a ping to figure out
whether a system process is still alive. The default callback implementation
provided by SEF is to notify RS back to let it know the process is alive
and kicking.
2. SEF Live update. The event occurs every time RS sends a prepare to update
message to let a system process know an update is available and to prepare
for it. The live update support is very basic for now. SEF only deals with
verifying if the prepare state can be supported by the process, dumping the
state for debugging purposes, and providing an event-driven programming
model to the process to react to state changes check-in when ready to update.
- SEF should be extended in the future to integrate support for more types of
system events. Ideally, all the cross-cutting concerns should be integrated into
SEF to avoid duplicating code and ease extensibility. Examples include:
* PM notify messages primarily used at shutdown.
* SYSTEM notify messages primarily used for signals.
* CLOCK notify messages used for system alarms.
* Debug messages. IS could still be in charge of fkey handling but would
forward the debug message to the target process (e.g. PM, if the user
requested debug information about PM). SEF would then catch the message and
do nothing unless the process has registered an appropriate callback to
deal with the event. This simplifies the programming model to print debug
information, avoids duplicating code, and reduces the effort to print
debug information.
SYSTEM PROCESSES CHANGES:
- Every system process registers SEF callbacks it needs to override the default
system behavior and calls sef_startup() right after being started.
- sef_startup() does almost nothing now, but will be extended in the future to
support callbacks of its own to let RS control and synchronize with every
system process at initialization time.
- Every system process calls sef_receive() now rather than receive() directly,
to let SEF handle predefined system events.
RS CHANGES:
- RS supports a basic single-component live update protocol now, as follows:
* When an update command is issued (via "service update *"), RS notifies the
target system process to prepare for a specific update state.
* If the process doesn't respond back in time, the update is aborted.
* When the process responds back, RS kills it and marks it for refreshing.
* The process is then automatically restarted as for a buggy process and can
start running again.
* Live update is currently prototyped as a controlled failure.
2009-12-21 15:12:21 +01:00
|
|
|
|
2007-07-24 16:49:09 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
* main *
|
|
|
|
* *
|
|
|
|
* *
|
|
|
|
* The main function of the driver, receiving and processing messages *
|
|
|
|
*****************************************************************************/
|
|
|
|
int main(int argc, char *argv[]) {
|
Initialization protocol for system services.
SYSLIB CHANGES:
- SEF framework now supports a new SEF Init request type from RS. 3 different
callbacks are available (init_fresh, init_lu, init_restart) to specify
initialization code when a service starts fresh, starts after a live update,
or restarts.
SYSTEM SERVICE CHANGES:
- Initialization code for system services is now enclosed in a callback SEF will
automatically call at init time. The return code of the callback will
tell RS whether the initialization completed successfully.
- Each init callback can access information passed by RS to initialize. As of
now, each system service has access to the public entries of RS's system process
table to gather all the information required to initialize. This design
eliminates many existing or potential races at boot time and provides a uniform
initialization interface to system services. The same interface will be reused
for the upcoming publish/subscribe model to handle dynamic
registration / deregistration of system services.
VM CHANGES:
- Uniform privilege management for all system services. Every service uses the
same call mask format. For boot services, VM copies the call mask from init
data. For dynamic services, VM still receives the call mask via rs_set_priv
call that will be soon replaced by the upcoming publish/subscribe model.
RS CHANGES:
- The system process table has been reorganized and split into private entries
and public entries. Only the latter ones are exposed to system services.
- VM call masks are now entirely configured in rs/table.c
- RS has now its own slot in the system process table. Only kernel tasks and
user processes not included in the boot image are now left out from the system
process table.
- RS implements the initialization protocol for system services.
- For services in the boot image, RS blocks till initialization is complete and
panics when failure is reported back. Services are initialized in their order of
appearance in the boot image priv table and RS blocks to implements synchronous
initialization for every system service having the flag SF_SYNCH_BOOT set.
- For services started dynamically, the initialization protocol is implemented
as though it were the first ping for the service. In this case, if the
system service fails to report back (or reports failure), RS brings the service
down rather than trying to restart it.
2010-01-08 02:20:42 +01:00
|
|
|
int r;
|
2007-07-24 16:49:09 +02:00
|
|
|
|
Basic System Event Framework (SEF) with ping and live update.
SYSLIB CHANGES:
- SEF must be used by every system process and is thereby part of the system
library.
- The framework provides a receive() interface (sef_receive) for system
processes to automatically catch known system even messages and process them.
- SEF provides a default behavior for each type of system event, but allows
system processes to register callbacks to override the default behavior.
- Custom (local to the process) or predefined (provided by SEF) callback
implementations can be registered to SEF.
- SEF currently includes support for 2 types of system events:
1. SEF Ping. The event occurs every time RS sends a ping to figure out
whether a system process is still alive. The default callback implementation
provided by SEF is to notify RS back to let it know the process is alive
and kicking.
2. SEF Live update. The event occurs every time RS sends a prepare to update
message to let a system process know an update is available and to prepare
for it. The live update support is very basic for now. SEF only deals with
verifying if the prepare state can be supported by the process, dumping the
state for debugging purposes, and providing an event-driven programming
model to the process to react to state changes check-in when ready to update.
- SEF should be extended in the future to integrate support for more types of
system events. Ideally, all the cross-cutting concerns should be integrated into
SEF to avoid duplicating code and ease extensibility. Examples include:
* PM notify messages primarily used at shutdown.
* SYSTEM notify messages primarily used for signals.
* CLOCK notify messages used for system alarms.
* Debug messages. IS could still be in charge of fkey handling but would
forward the debug message to the target process (e.g. PM, if the user
requested debug information about PM). SEF would then catch the message and
do nothing unless the process has registered an appropriate callback to
deal with the event. This simplifies the programming model to print debug
information, avoids duplicating code, and reduces the effort to print
debug information.
SYSTEM PROCESSES CHANGES:
- Every system process registers SEF callbacks it needs to override the default
system behavior and calls sef_startup() right after being started.
- sef_startup() does almost nothing now, but will be extended in the future to
support callbacks of its own to let RS control and synchronize with every
system process at initialization time.
- Every system process calls sef_receive() now rather than receive() directly,
to let SEF handle predefined system events.
RS CHANGES:
- RS supports a basic single-component live update protocol now, as follows:
* When an update command is issued (via "service update *"), RS notifies the
target system process to prepare for a specific update state.
* If the process doesn't respond back in time, the update is aborted.
* When the process responds back, RS kills it and marks it for refreshing.
* The process is then automatically restarted as for a buggy process and can
start running again.
* Live update is currently prototyped as a controlled failure.
2009-12-21 15:12:21 +01:00
|
|
|
/* SEF local startup. */
|
2007-07-24 16:49:09 +02:00
|
|
|
env_setargs(argc, argv);
|
Initialization protocol for system services.
SYSLIB CHANGES:
- SEF framework now supports a new SEF Init request type from RS. 3 different
callbacks are available (init_fresh, init_lu, init_restart) to specify
initialization code when a service starts fresh, starts after a live update,
or restarts.
SYSTEM SERVICE CHANGES:
- Initialization code for system services is now enclosed in a callback SEF will
automatically call at init time. The return code of the callback will
tell RS whether the initialization completed successfully.
- Each init callback can access information passed by RS to initialize. As of
now, each system service has access to the public entries of RS's system process
table to gather all the information required to initialize. This design
eliminates many existing or potential races at boot time and provides a uniform
initialization interface to system services. The same interface will be reused
for the upcoming publish/subscribe model to handle dynamic
registration / deregistration of system services.
VM CHANGES:
- Uniform privilege management for all system services. Every service uses the
same call mask format. For boot services, VM copies the call mask from init
data. For dynamic services, VM still receives the call mask via rs_set_priv
call that will be soon replaced by the upcoming publish/subscribe model.
RS CHANGES:
- The system process table has been reorganized and split into private entries
and public entries. Only the latter ones are exposed to system services.
- VM call masks are now entirely configured in rs/table.c
- RS has now its own slot in the system process table. Only kernel tasks and
user processes not included in the boot image are now left out from the system
process table.
- RS implements the initialization protocol for system services.
- For services in the boot image, RS blocks till initialization is complete and
panics when failure is reported back. Services are initialized in their order of
appearance in the boot image priv table and RS blocks to implements synchronous
initialization for every system service having the flag SF_SYNCH_BOOT set.
- For services started dynamically, the initialization protocol is implemented
as though it were the first ping for the service. In this case, if the
system service fails to report back (or reports failure), RS brings the service
down rather than trying to restart it.
2010-01-08 02:20:42 +01:00
|
|
|
sef_local_startup();
|
2007-07-24 16:49:09 +02:00
|
|
|
|
2009-04-22 14:42:37 +02:00
|
|
|
while (TRUE) {
|
Basic System Event Framework (SEF) with ping and live update.
SYSLIB CHANGES:
- SEF must be used by every system process and is thereby part of the system
library.
- The framework provides a receive() interface (sef_receive) for system
processes to automatically catch known system even messages and process them.
- SEF provides a default behavior for each type of system event, but allows
system processes to register callbacks to override the default behavior.
- Custom (local to the process) or predefined (provided by SEF) callback
implementations can be registered to SEF.
- SEF currently includes support for 2 types of system events:
1. SEF Ping. The event occurs every time RS sends a ping to figure out
whether a system process is still alive. The default callback implementation
provided by SEF is to notify RS back to let it know the process is alive
and kicking.
2. SEF Live update. The event occurs every time RS sends a prepare to update
message to let a system process know an update is available and to prepare
for it. The live update support is very basic for now. SEF only deals with
verifying if the prepare state can be supported by the process, dumping the
state for debugging purposes, and providing an event-driven programming
model to the process to react to state changes check-in when ready to update.
- SEF should be extended in the future to integrate support for more types of
system events. Ideally, all the cross-cutting concerns should be integrated into
SEF to avoid duplicating code and ease extensibility. Examples include:
* PM notify messages primarily used at shutdown.
* SYSTEM notify messages primarily used for signals.
* CLOCK notify messages used for system alarms.
* Debug messages. IS could still be in charge of fkey handling but would
forward the debug message to the target process (e.g. PM, if the user
requested debug information about PM). SEF would then catch the message and
do nothing unless the process has registered an appropriate callback to
deal with the event. This simplifies the programming model to print debug
information, avoids duplicating code, and reduces the effort to print
debug information.
SYSTEM PROCESSES CHANGES:
- Every system process registers SEF callbacks it needs to override the default
system behavior and calls sef_startup() right after being started.
- sef_startup() does almost nothing now, but will be extended in the future to
support callbacks of its own to let RS control and synchronize with every
system process at initialization time.
- Every system process calls sef_receive() now rather than receive() directly,
to let SEF handle predefined system events.
RS CHANGES:
- RS supports a basic single-component live update protocol now, as follows:
* When an update command is issued (via "service update *"), RS notifies the
target system process to prepare for a specific update state.
* If the process doesn't respond back in time, the update is aborted.
* When the process responds back, RS kills it and marks it for refreshing.
* The process is then automatically restarted as for a buggy process and can
start running again.
* Live update is currently prototyped as a controlled failure.
2009-12-21 15:12:21 +01:00
|
|
|
if ((r = sef_receive (ANY, &m)) != OK)
|
|
|
|
panic(__FILE__, "orinoco: sef_receive failed", NO_NUM);
|
2007-07-24 16:49:09 +02:00
|
|
|
|
2009-09-29 20:47:56 +02:00
|
|
|
if (is_notify(m.m_type)) {
|
|
|
|
switch (_ENDPOINT_P(m.m_source)) {
|
|
|
|
case CLOCK:
|
|
|
|
or_watchdog_f(NULL);
|
|
|
|
break;
|
|
|
|
case HARDWARE:
|
|
|
|
do_hard_int();
|
|
|
|
if (int_event_check)
|
|
|
|
check_int_events();
|
|
|
|
break ;
|
|
|
|
case TTY_PROC_NR:
|
|
|
|
or_dump(&m);
|
|
|
|
break;
|
|
|
|
case PM_PROC_NR:
|
Merge of David's ptrace branch. Summary:
o Support for ptrace T_ATTACH/T_DETACH and T_SYSCALL
o PM signal handling logic should now work properly, even with debuggers
being present
o Asynchronous PM/VFS protocol, full IPC support for senda(), and
AMF_NOREPLY senda() flag
DETAILS
Process stop and delay call handling of PM:
o Added sys_runctl() kernel call with sys_stop() and sys_resume()
aliases, for PM to stop and resume a process
o Added exception for sending/syscall-traced processes to sys_runctl(),
and matching SIGKREADY pseudo-signal to PM
o Fixed PM signal logic to deal with requests from a process after
stopping it (so-called "delay calls"), using the SIGKREADY facility
o Fixed various PM panics due to race conditions with delay calls versus
VFS calls
o Removed special PRIO_STOP priority value
o Added SYS_LOCK RTS kernel flag, to stop an individual process from
running while modifying its process structure
Signal and debugger handling in PM:
o Fixed debugger signals being dropped if a second signal arrives when
the debugger has not retrieved the first one
o Fixed debugger signals being sent to the debugger more than once
o Fixed debugger signals unpausing process in VFS; removed PM_UNPAUSE_TR
protocol message
o Detached debugger signals from general signal logic and from being
blocked on VFS calls, meaning that even VFS can now be traced
o Fixed debugger being unable to receive more than one pending signal in
one process stop
o Fixed signal delivery being delayed needlessly when multiple signals
are pending
o Fixed wait test for tracer, which was returning for children that were
not waited for
o Removed second parallel pending call from PM to VFS for any process
o Fixed process becoming runnable between exec() and debugger trap
o Added support for notifying the debugger before the parent when a
debugged child exits
o Fixed debugger death causing child to remain stopped forever
o Fixed consistently incorrect use of _NSIG
Extensions to ptrace():
o Added T_ATTACH and T_DETACH ptrace request, to attach and detach a
debugger to and from a process
o Added T_SYSCALL ptrace request, to trace system calls
o Added T_SETOPT ptrace request, to set trace options
o Added TO_TRACEFORK trace option, to attach automatically to children
of a traced process
o Added TO_ALTEXEC trace option, to send SIGSTOP instead of SIGTRAP upon
a successful exec() of the tracee
o Extended T_GETUSER ptrace support to allow retrieving a process's priv
structure
o Removed T_STOP ptrace request again, as it does not help implementing
debuggers properly
o Added MINIX3-specific ptrace test (test42)
o Added proper manual page for ptrace(2)
Asynchronous PM/VFS interface:
o Fixed asynchronous messages not being checked when receive() is called
with an endpoint other than ANY
o Added AMF_NOREPLY senda() flag, preventing such messages from
satisfying the receive part of a sendrec()
o Added asynsend3() that takes optional flags; asynsend() is now a
#define passing in 0 as third parameter
o Made PM/VFS protocol asynchronous; reintroduced tell_fs()
o Made PM_BASE request/reply number range unique
o Hacked in a horrible temporary workaround into RS to deal with newly
revealed RS-PM-VFS race condition triangle until VFS is asynchronous
System signal handling:
o Fixed shutdown logic of device drivers; removed old SIGKSTOP signal
o Removed is-superuser check from PM's do_procstat() (aka getsigset())
o Added sigset macros to allow system processes to deal with the full
signal set, rather than just the POSIX subset
Miscellaneous PM fixes:
o Split do_getset into do_get and do_set, merging common code and making
structure clearer
o Fixed setpriority() being able to put to sleep processes using an
invalid parameter, or revive zombie processes
o Made find_proc() global; removed obsolete proc_from_pid()
o Cleanup here and there
Also included:
o Fixed false-positive boot order kernel warning
o Removed last traces of old NOTIFY_FROM code
THINGS OF POSSIBLE INTEREST
o It should now be possible to run PM at any priority, even lower than
user processes
o No assumptions are made about communication speed between PM and VFS,
although communication must be FIFO
o A debugger will now receive incoming debuggee signals at kill time
only; the process may not yet be fully stopped
o A first step has been made towards making the SYSTEM task preemptible
2009-09-30 11:57:22 +02:00
|
|
|
{
|
|
|
|
sigset_t set;
|
|
|
|
|
|
|
|
if (getsigset(&set) != 0) break;
|
|
|
|
|
|
|
|
if (sigismember(&set, SIGTERM))
|
|
|
|
orinoco_stop();
|
|
|
|
|
2009-09-29 20:47:56 +02:00
|
|
|
break;
|
Merge of David's ptrace branch. Summary:
o Support for ptrace T_ATTACH/T_DETACH and T_SYSCALL
o PM signal handling logic should now work properly, even with debuggers
being present
o Asynchronous PM/VFS protocol, full IPC support for senda(), and
AMF_NOREPLY senda() flag
DETAILS
Process stop and delay call handling of PM:
o Added sys_runctl() kernel call with sys_stop() and sys_resume()
aliases, for PM to stop and resume a process
o Added exception for sending/syscall-traced processes to sys_runctl(),
and matching SIGKREADY pseudo-signal to PM
o Fixed PM signal logic to deal with requests from a process after
stopping it (so-called "delay calls"), using the SIGKREADY facility
o Fixed various PM panics due to race conditions with delay calls versus
VFS calls
o Removed special PRIO_STOP priority value
o Added SYS_LOCK RTS kernel flag, to stop an individual process from
running while modifying its process structure
Signal and debugger handling in PM:
o Fixed debugger signals being dropped if a second signal arrives when
the debugger has not retrieved the first one
o Fixed debugger signals being sent to the debugger more than once
o Fixed debugger signals unpausing process in VFS; removed PM_UNPAUSE_TR
protocol message
o Detached debugger signals from general signal logic and from being
blocked on VFS calls, meaning that even VFS can now be traced
o Fixed debugger being unable to receive more than one pending signal in
one process stop
o Fixed signal delivery being delayed needlessly when multiple signals
are pending
o Fixed wait test for tracer, which was returning for children that were
not waited for
o Removed second parallel pending call from PM to VFS for any process
o Fixed process becoming runnable between exec() and debugger trap
o Added support for notifying the debugger before the parent when a
debugged child exits
o Fixed debugger death causing child to remain stopped forever
o Fixed consistently incorrect use of _NSIG
Extensions to ptrace():
o Added T_ATTACH and T_DETACH ptrace request, to attach and detach a
debugger to and from a process
o Added T_SYSCALL ptrace request, to trace system calls
o Added T_SETOPT ptrace request, to set trace options
o Added TO_TRACEFORK trace option, to attach automatically to children
of a traced process
o Added TO_ALTEXEC trace option, to send SIGSTOP instead of SIGTRAP upon
a successful exec() of the tracee
o Extended T_GETUSER ptrace support to allow retrieving a process's priv
structure
o Removed T_STOP ptrace request again, as it does not help implementing
debuggers properly
o Added MINIX3-specific ptrace test (test42)
o Added proper manual page for ptrace(2)
Asynchronous PM/VFS interface:
o Fixed asynchronous messages not being checked when receive() is called
with an endpoint other than ANY
o Added AMF_NOREPLY senda() flag, preventing such messages from
satisfying the receive part of a sendrec()
o Added asynsend3() that takes optional flags; asynsend() is now a
#define passing in 0 as third parameter
o Made PM/VFS protocol asynchronous; reintroduced tell_fs()
o Made PM_BASE request/reply number range unique
o Hacked in a horrible temporary workaround into RS to deal with newly
revealed RS-PM-VFS race condition triangle until VFS is asynchronous
System signal handling:
o Fixed shutdown logic of device drivers; removed old SIGKSTOP signal
o Removed is-superuser check from PM's do_procstat() (aka getsigset())
o Added sigset macros to allow system processes to deal with the full
signal set, rather than just the POSIX subset
Miscellaneous PM fixes:
o Split do_getset into do_get and do_set, merging common code and making
structure clearer
o Fixed setpriority() being able to put to sleep processes using an
invalid parameter, or revive zombie processes
o Made find_proc() global; removed obsolete proc_from_pid()
o Cleanup here and there
Also included:
o Fixed false-positive boot order kernel warning
o Removed last traces of old NOTIFY_FROM code
THINGS OF POSSIBLE INTEREST
o It should now be possible to run PM at any priority, even lower than
user processes
o No assumptions are made about communication speed between PM and VFS,
although communication must be FIFO
o A debugger will now receive incoming debuggee signals at kill time
only; the process may not yet be fully stopped
o A first step has been made towards making the SYSTEM task preemptible
2009-09-30 11:57:22 +02:00
|
|
|
}
|
2009-09-29 20:47:56 +02:00
|
|
|
default:
|
|
|
|
panic(__FILE__,
|
|
|
|
"orinoco: illegal notify from:",
|
|
|
|
m.m_source);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* done, get new message */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2007-07-24 16:49:09 +02:00
|
|
|
switch (m.m_type) {
|
|
|
|
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;
|
|
|
|
default:
|
|
|
|
panic(__FILE__,"orinoco: illegal message:", m.m_type);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Basic System Event Framework (SEF) with ping and live update.
SYSLIB CHANGES:
- SEF must be used by every system process and is thereby part of the system
library.
- The framework provides a receive() interface (sef_receive) for system
processes to automatically catch known system even messages and process them.
- SEF provides a default behavior for each type of system event, but allows
system processes to register callbacks to override the default behavior.
- Custom (local to the process) or predefined (provided by SEF) callback
implementations can be registered to SEF.
- SEF currently includes support for 2 types of system events:
1. SEF Ping. The event occurs every time RS sends a ping to figure out
whether a system process is still alive. The default callback implementation
provided by SEF is to notify RS back to let it know the process is alive
and kicking.
2. SEF Live update. The event occurs every time RS sends a prepare to update
message to let a system process know an update is available and to prepare
for it. The live update support is very basic for now. SEF only deals with
verifying if the prepare state can be supported by the process, dumping the
state for debugging purposes, and providing an event-driven programming
model to the process to react to state changes check-in when ready to update.
- SEF should be extended in the future to integrate support for more types of
system events. Ideally, all the cross-cutting concerns should be integrated into
SEF to avoid duplicating code and ease extensibility. Examples include:
* PM notify messages primarily used at shutdown.
* SYSTEM notify messages primarily used for signals.
* CLOCK notify messages used for system alarms.
* Debug messages. IS could still be in charge of fkey handling but would
forward the debug message to the target process (e.g. PM, if the user
requested debug information about PM). SEF would then catch the message and
do nothing unless the process has registered an appropriate callback to
deal with the event. This simplifies the programming model to print debug
information, avoids duplicating code, and reduces the effort to print
debug information.
SYSTEM PROCESSES CHANGES:
- Every system process registers SEF callbacks it needs to override the default
system behavior and calls sef_startup() right after being started.
- sef_startup() does almost nothing now, but will be extended in the future to
support callbacks of its own to let RS control and synchronize with every
system process at initialization time.
- Every system process calls sef_receive() now rather than receive() directly,
to let SEF handle predefined system events.
RS CHANGES:
- RS supports a basic single-component live update protocol now, as follows:
* When an update command is issued (via "service update *"), RS notifies the
target system process to prepare for a specific update state.
* If the process doesn't respond back in time, the update is aborted.
* When the process responds back, RS kills it and marks it for refreshing.
* The process is then automatically restarted as for a buggy process and can
start running again.
* Live update is currently prototyped as a controlled failure.
2009-12-21 15:12:21 +01:00
|
|
|
/*===========================================================================*
|
|
|
|
* sef_local_startup *
|
|
|
|
*===========================================================================*/
|
|
|
|
PRIVATE void sef_local_startup()
|
|
|
|
{
|
Initialization protocol for system services.
SYSLIB CHANGES:
- SEF framework now supports a new SEF Init request type from RS. 3 different
callbacks are available (init_fresh, init_lu, init_restart) to specify
initialization code when a service starts fresh, starts after a live update,
or restarts.
SYSTEM SERVICE CHANGES:
- Initialization code for system services is now enclosed in a callback SEF will
automatically call at init time. The return code of the callback will
tell RS whether the initialization completed successfully.
- Each init callback can access information passed by RS to initialize. As of
now, each system service has access to the public entries of RS's system process
table to gather all the information required to initialize. This design
eliminates many existing or potential races at boot time and provides a uniform
initialization interface to system services. The same interface will be reused
for the upcoming publish/subscribe model to handle dynamic
registration / deregistration of system services.
VM CHANGES:
- Uniform privilege management for all system services. Every service uses the
same call mask format. For boot services, VM copies the call mask from init
data. For dynamic services, VM still receives the call mask via rs_set_priv
call that will be soon replaced by the upcoming publish/subscribe model.
RS CHANGES:
- The system process table has been reorganized and split into private entries
and public entries. Only the latter ones are exposed to system services.
- VM call masks are now entirely configured in rs/table.c
- RS has now its own slot in the system process table. Only kernel tasks and
user processes not included in the boot image are now left out from the system
process table.
- RS implements the initialization protocol for system services.
- For services in the boot image, RS blocks till initialization is complete and
panics when failure is reported back. Services are initialized in their order of
appearance in the boot image priv table and RS blocks to implements synchronous
initialization for every system service having the flag SF_SYNCH_BOOT set.
- For services started dynamically, the initialization protocol is implemented
as though it were the first ping for the service. In this case, if the
system service fails to report back (or reports failure), RS brings the service
down rather than trying to restart it.
2010-01-08 02:20:42 +01:00
|
|
|
/* Register init callbacks. */
|
|
|
|
sef_setcb_init_fresh(sef_cb_init_fresh);
|
|
|
|
sef_setcb_init_restart(sef_cb_init_fresh);
|
|
|
|
|
Basic System Event Framework (SEF) with ping and live update.
SYSLIB CHANGES:
- SEF must be used by every system process and is thereby part of the system
library.
- The framework provides a receive() interface (sef_receive) for system
processes to automatically catch known system even messages and process them.
- SEF provides a default behavior for each type of system event, but allows
system processes to register callbacks to override the default behavior.
- Custom (local to the process) or predefined (provided by SEF) callback
implementations can be registered to SEF.
- SEF currently includes support for 2 types of system events:
1. SEF Ping. The event occurs every time RS sends a ping to figure out
whether a system process is still alive. The default callback implementation
provided by SEF is to notify RS back to let it know the process is alive
and kicking.
2. SEF Live update. The event occurs every time RS sends a prepare to update
message to let a system process know an update is available and to prepare
for it. The live update support is very basic for now. SEF only deals with
verifying if the prepare state can be supported by the process, dumping the
state for debugging purposes, and providing an event-driven programming
model to the process to react to state changes check-in when ready to update.
- SEF should be extended in the future to integrate support for more types of
system events. Ideally, all the cross-cutting concerns should be integrated into
SEF to avoid duplicating code and ease extensibility. Examples include:
* PM notify messages primarily used at shutdown.
* SYSTEM notify messages primarily used for signals.
* CLOCK notify messages used for system alarms.
* Debug messages. IS could still be in charge of fkey handling but would
forward the debug message to the target process (e.g. PM, if the user
requested debug information about PM). SEF would then catch the message and
do nothing unless the process has registered an appropriate callback to
deal with the event. This simplifies the programming model to print debug
information, avoids duplicating code, and reduces the effort to print
debug information.
SYSTEM PROCESSES CHANGES:
- Every system process registers SEF callbacks it needs to override the default
system behavior and calls sef_startup() right after being started.
- sef_startup() does almost nothing now, but will be extended in the future to
support callbacks of its own to let RS control and synchronize with every
system process at initialization time.
- Every system process calls sef_receive() now rather than receive() directly,
to let SEF handle predefined system events.
RS CHANGES:
- RS supports a basic single-component live update protocol now, as follows:
* When an update command is issued (via "service update *"), RS notifies the
target system process to prepare for a specific update state.
* If the process doesn't respond back in time, the update is aborted.
* When the process responds back, RS kills it and marks it for refreshing.
* The process is then automatically restarted as for a buggy process and can
start running again.
* Live update is currently prototyped as a controlled failure.
2009-12-21 15:12:21 +01:00
|
|
|
/* No live update support for now. */
|
|
|
|
|
|
|
|
/* Let SEF perform startup. */
|
|
|
|
sef_startup();
|
|
|
|
}
|
|
|
|
|
Initialization protocol for system services.
SYSLIB CHANGES:
- SEF framework now supports a new SEF Init request type from RS. 3 different
callbacks are available (init_fresh, init_lu, init_restart) to specify
initialization code when a service starts fresh, starts after a live update,
or restarts.
SYSTEM SERVICE CHANGES:
- Initialization code for system services is now enclosed in a callback SEF will
automatically call at init time. The return code of the callback will
tell RS whether the initialization completed successfully.
- Each init callback can access information passed by RS to initialize. As of
now, each system service has access to the public entries of RS's system process
table to gather all the information required to initialize. This design
eliminates many existing or potential races at boot time and provides a uniform
initialization interface to system services. The same interface will be reused
for the upcoming publish/subscribe model to handle dynamic
registration / deregistration of system services.
VM CHANGES:
- Uniform privilege management for all system services. Every service uses the
same call mask format. For boot services, VM copies the call mask from init
data. For dynamic services, VM still receives the call mask via rs_set_priv
call that will be soon replaced by the upcoming publish/subscribe model.
RS CHANGES:
- The system process table has been reorganized and split into private entries
and public entries. Only the latter ones are exposed to system services.
- VM call masks are now entirely configured in rs/table.c
- RS has now its own slot in the system process table. Only kernel tasks and
user processes not included in the boot image are now left out from the system
process table.
- RS implements the initialization protocol for system services.
- For services in the boot image, RS blocks till initialization is complete and
panics when failure is reported back. Services are initialized in their order of
appearance in the boot image priv table and RS blocks to implements synchronous
initialization for every system service having the flag SF_SYNCH_BOOT set.
- For services started dynamically, the initialization protocol is implemented
as though it were the first ping for the service. In this case, if the
system service fails to report back (or reports failure), RS brings the service
down rather than trying to restart it.
2010-01-08 02:20:42 +01:00
|
|
|
/*===========================================================================*
|
|
|
|
* sef_cb_init_fresh *
|
|
|
|
*===========================================================================*/
|
|
|
|
PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info)
|
|
|
|
{
|
|
|
|
/* Initialize the orinoco driver. */
|
|
|
|
int fkeys, sfkeys, r;
|
|
|
|
u32_t inet_proc_nr;
|
|
|
|
|
|
|
|
system_hz = sys_hz();
|
|
|
|
|
|
|
|
(progname=strrchr(env_argv[0],'/')) ? progname++
|
|
|
|
: (progname=env_argv[0]);
|
|
|
|
|
|
|
|
/* 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. */
|
2010-01-14 16:24:16 +01:00
|
|
|
r = ds_retrieve_label_num("inet", &inet_proc_nr);
|
Initialization protocol for system services.
SYSLIB CHANGES:
- SEF framework now supports a new SEF Init request type from RS. 3 different
callbacks are available (init_fresh, init_lu, init_restart) to specify
initialization code when a service starts fresh, starts after a live update,
or restarts.
SYSTEM SERVICE CHANGES:
- Initialization code for system services is now enclosed in a callback SEF will
automatically call at init time. The return code of the callback will
tell RS whether the initialization completed successfully.
- Each init callback can access information passed by RS to initialize. As of
now, each system service has access to the public entries of RS's system process
table to gather all the information required to initialize. This design
eliminates many existing or potential races at boot time and provides a uniform
initialization interface to system services. The same interface will be reused
for the upcoming publish/subscribe model to handle dynamic
registration / deregistration of system services.
VM CHANGES:
- Uniform privilege management for all system services. Every service uses the
same call mask format. For boot services, VM copies the call mask from init
data. For dynamic services, VM still receives the call mask via rs_set_priv
call that will be soon replaced by the upcoming publish/subscribe model.
RS CHANGES:
- The system process table has been reorganized and split into private entries
and public entries. Only the latter ones are exposed to system services.
- VM call masks are now entirely configured in rs/table.c
- RS has now its own slot in the system process table. Only kernel tasks and
user processes not included in the boot image are now left out from the system
process table.
- RS implements the initialization protocol for system services.
- For services in the boot image, RS blocks till initialization is complete and
panics when failure is reported back. Services are initialized in their order of
appearance in the boot image priv table and RS blocks to implements synchronous
initialization for every system service having the flag SF_SYNCH_BOOT set.
- For services started dynamically, the initialization protocol is implemented
as though it were the first ping for the service. In this case, if the
system service fails to report back (or reports failure), RS brings the service
down rather than trying to restart it.
2010-01-08 02:20:42 +01:00
|
|
|
if (r == OK)
|
|
|
|
notify(inet_proc_nr);
|
|
|
|
else if (r != ESRCH)
|
2010-01-14 16:24:16 +01:00
|
|
|
printf("orinoco: ds_retrieve_label_num failed for 'inet': %d\n", r);
|
Initialization protocol for system services.
SYSLIB CHANGES:
- SEF framework now supports a new SEF Init request type from RS. 3 different
callbacks are available (init_fresh, init_lu, init_restart) to specify
initialization code when a service starts fresh, starts after a live update,
or restarts.
SYSTEM SERVICE CHANGES:
- Initialization code for system services is now enclosed in a callback SEF will
automatically call at init time. The return code of the callback will
tell RS whether the initialization completed successfully.
- Each init callback can access information passed by RS to initialize. As of
now, each system service has access to the public entries of RS's system process
table to gather all the information required to initialize. This design
eliminates many existing or potential races at boot time and provides a uniform
initialization interface to system services. The same interface will be reused
for the upcoming publish/subscribe model to handle dynamic
registration / deregistration of system services.
VM CHANGES:
- Uniform privilege management for all system services. Every service uses the
same call mask format. For boot services, VM copies the call mask from init
data. For dynamic services, VM still receives the call mask via rs_set_priv
call that will be soon replaced by the upcoming publish/subscribe model.
RS CHANGES:
- The system process table has been reorganized and split into private entries
and public entries. Only the latter ones are exposed to system services.
- VM call masks are now entirely configured in rs/table.c
- RS has now its own slot in the system process table. Only kernel tasks and
user processes not included in the boot image are now left out from the system
process table.
- RS implements the initialization protocol for system services.
- For services in the boot image, RS blocks till initialization is complete and
panics when failure is reported back. Services are initialized in their order of
appearance in the boot image priv table and RS blocks to implements synchronous
initialization for every system service having the flag SF_SYNCH_BOOT set.
- For services started dynamically, the initialization protocol is implemented
as though it were the first ping for the service. In this case, if the
system service fails to report back (or reports failure), RS brings the service
down rather than trying to restart it.
2010-01-08 02:20:42 +01:00
|
|
|
|
|
|
|
return(OK);
|
|
|
|
}
|
|
|
|
|
2007-07-24 16:49:09 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
* 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;
|
|
|
|
|
2009-09-29 20:47:56 +02:00
|
|
|
/* the interrupt message doesn't contain information about the port, try
|
|
|
|
* to find it */
|
2007-07-24 16:49:09 +02:00
|
|
|
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 */
|
|
|
|
}
|
Merge of David's ptrace branch. Summary:
o Support for ptrace T_ATTACH/T_DETACH and T_SYSCALL
o PM signal handling logic should now work properly, even with debuggers
being present
o Asynchronous PM/VFS protocol, full IPC support for senda(), and
AMF_NOREPLY senda() flag
DETAILS
Process stop and delay call handling of PM:
o Added sys_runctl() kernel call with sys_stop() and sys_resume()
aliases, for PM to stop and resume a process
o Added exception for sending/syscall-traced processes to sys_runctl(),
and matching SIGKREADY pseudo-signal to PM
o Fixed PM signal logic to deal with requests from a process after
stopping it (so-called "delay calls"), using the SIGKREADY facility
o Fixed various PM panics due to race conditions with delay calls versus
VFS calls
o Removed special PRIO_STOP priority value
o Added SYS_LOCK RTS kernel flag, to stop an individual process from
running while modifying its process structure
Signal and debugger handling in PM:
o Fixed debugger signals being dropped if a second signal arrives when
the debugger has not retrieved the first one
o Fixed debugger signals being sent to the debugger more than once
o Fixed debugger signals unpausing process in VFS; removed PM_UNPAUSE_TR
protocol message
o Detached debugger signals from general signal logic and from being
blocked on VFS calls, meaning that even VFS can now be traced
o Fixed debugger being unable to receive more than one pending signal in
one process stop
o Fixed signal delivery being delayed needlessly when multiple signals
are pending
o Fixed wait test for tracer, which was returning for children that were
not waited for
o Removed second parallel pending call from PM to VFS for any process
o Fixed process becoming runnable between exec() and debugger trap
o Added support for notifying the debugger before the parent when a
debugged child exits
o Fixed debugger death causing child to remain stopped forever
o Fixed consistently incorrect use of _NSIG
Extensions to ptrace():
o Added T_ATTACH and T_DETACH ptrace request, to attach and detach a
debugger to and from a process
o Added T_SYSCALL ptrace request, to trace system calls
o Added T_SETOPT ptrace request, to set trace options
o Added TO_TRACEFORK trace option, to attach automatically to children
of a traced process
o Added TO_ALTEXEC trace option, to send SIGSTOP instead of SIGTRAP upon
a successful exec() of the tracee
o Extended T_GETUSER ptrace support to allow retrieving a process's priv
structure
o Removed T_STOP ptrace request again, as it does not help implementing
debuggers properly
o Added MINIX3-specific ptrace test (test42)
o Added proper manual page for ptrace(2)
Asynchronous PM/VFS interface:
o Fixed asynchronous messages not being checked when receive() is called
with an endpoint other than ANY
o Added AMF_NOREPLY senda() flag, preventing such messages from
satisfying the receive part of a sendrec()
o Added asynsend3() that takes optional flags; asynsend() is now a
#define passing in 0 as third parameter
o Made PM/VFS protocol asynchronous; reintroduced tell_fs()
o Made PM_BASE request/reply number range unique
o Hacked in a horrible temporary workaround into RS to deal with newly
revealed RS-PM-VFS race condition triangle until VFS is asynchronous
System signal handling:
o Fixed shutdown logic of device drivers; removed old SIGKSTOP signal
o Removed is-superuser check from PM's do_procstat() (aka getsigset())
o Added sigset macros to allow system processes to deal with the full
signal set, rather than just the POSIX subset
Miscellaneous PM fixes:
o Split do_getset into do_get and do_set, merging common code and making
structure clearer
o Fixed setpriority() being able to put to sleep processes using an
invalid parameter, or revive zombie processes
o Made find_proc() global; removed obsolete proc_from_pid()
o Cleanup here and there
Also included:
o Fixed false-positive boot order kernel warning
o Removed last traces of old NOTIFY_FROM code
THINGS OF POSSIBLE INTEREST
o It should now be possible to run PM at any priority, even lower than
user processes
o No assumptions are made about communication speed between PM and VFS,
although communication must be FIFO
o A debugger will now receive incoming debuggee signals at kill time
only; the process may not yet be fully stopped
o A first step has been made towards making the SYSTEM task preemptible
2009-09-30 11:57:22 +02:00
|
|
|
exit(0);
|
2007-07-24 16:49:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
* 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;
|
|
|
|
|
|
|
|
if (OK != (r = getuptime(&now)))
|
|
|
|
panic(__FILE__, "orinoco: getuptime() failed:", r);
|
|
|
|
|
2008-12-11 15:42:23 +01:00
|
|
|
if(now - last_reset < system_hz * 10) {
|
2007-07-24 16:49:09 +02:00
|
|
|
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;
|
|
|
|
|
|
|
|
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. */
|
|
|
|
|
2010-02-09 16:23:38 +01:00
|
|
|
tmr_inittimer(&or_watchdog);
|
2007-07-24 16:49:09 +02:00
|
|
|
/* Use a synchronous alarm instead of a watchdog timer. */
|
2008-12-11 15:42:23 +01:00
|
|
|
sys_setalarm(system_hz, 0);
|
2007-07-24 16:49:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-04-22 14:42:37 +02:00
|
|
|
while (TRUE) {
|
2007-07-24 16:49:09 +02:00
|
|
|
/* 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)
|
2009-04-22 14:42:37 +02:00
|
|
|
dname = "unknown device";
|
2007-07-24 16:49:09 +02:00
|
|
|
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);
|
|
|
|
|
2008-11-19 13:26:10 +01:00
|
|
|
/* This way, the buffer will be at least I386_PAGE_SIZE big: see
|
2007-07-24 16:49:09 +02:00
|
|
|
* calculation with the offset */
|
2008-11-19 13:26:10 +01:00
|
|
|
size = 2 * I386_PAGE_SIZE;
|
2007-07-24 16:49:09 +02:00
|
|
|
|
|
|
|
buf = (char *)malloc(size);
|
|
|
|
if(buf == NULL)
|
|
|
|
panic(__FILE__, "map_hw_buffer: cannot malloc size:", size);
|
|
|
|
|
2008-11-19 13:26:10 +01:00
|
|
|
/* Let the mapped memory by I386_PAGE_SIZE aligned */
|
|
|
|
o = I386_PAGE_SIZE - ((vir_bytes)buf % I386_PAGE_SIZE);
|
2007-07-24 16:49:09 +02:00
|
|
|
abuf = buf + o;
|
|
|
|
|
2008-11-19 13:26:10 +01:00
|
|
|
#if 0
|
2007-07-24 16:49:09 +02:00
|
|
|
r = sys_vm_map(SELF, 1, (vir_bytes)abuf,
|
2008-11-19 13:26:10 +01:00
|
|
|
1 * I386_PAGE_SIZE, (phys_bytes)orp->or_base_port);
|
|
|
|
#else
|
|
|
|
r = ENOSYS;
|
|
|
|
#endif
|
2007-07-24 16:49:09 +02:00
|
|
|
|
|
|
|
if(r!=OK)
|
|
|
|
panic(__FILE__, "map_hw_buffer: sys_vm_map failed:", r);
|
|
|
|
|
2008-11-19 13:26:10 +01:00
|
|
|
|
2007-07-24 16:49:09 +02:00
|
|
|
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:
|
2009-04-22 14:42:37 +02:00
|
|
|
printf("Invalid key provided. Has to be 13 chars\n");
|
2007-07-24 16:49:09 +02:00
|
|
|
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. */
|
2008-12-11 15:42:23 +01:00
|
|
|
sys_setalarm(system_hz, 0);
|
2007-07-24 16:49:09 +02:00
|
|
|
|
|
|
|
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;
|
2010-01-20 18:59:48 +01:00
|
|
|
phys_bytes phys_user;
|
2007-07-24 16:49:09 +02:00
|
|
|
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_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;
|
2010-01-20 18:59:48 +01:00
|
|
|
phys_bytes phys_user;
|
2007-07-24 16:49:09 +02:00
|
|
|
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_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;
|
2010-01-20 18:59:48 +01:00
|
|
|
phys_bytes dst_phys;
|
2007-07-24 16:49:09 +02:00
|
|
|
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_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;
|
2010-01-20 18:59:48 +01:00
|
|
|
phys_bytes dst_phys;
|
2007-07-24 16:49:09 +02:00
|
|
|
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_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);
|
|
|
|
}
|
|
|
|
|