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>
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2010-03-22 22:25:22 +01:00
|
|
|
#include <minix/drivers.h>
|
2010-04-08 15:41:35 +02:00
|
|
|
#include <minix/netdriver.h>
|
2007-07-24 16:49:09 +02:00
|
|
|
#include <string.h>
|
|
|
|
#include <minix/syslib.h>
|
|
|
|
#include <minix/type.h>
|
|
|
|
#include <minix/sysutil.h>
|
|
|
|
#include <timers.h>
|
2010-03-08 12:04:59 +01:00
|
|
|
#include <machine/pci.h>
|
2007-07-24 16:49:09 +02:00
|
|
|
#include <minix/ds.h>
|
2009-09-29 20:47:56 +02:00
|
|
|
#include <minix/endpoint.h>
|
2010-04-02 00:22:33 +02: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 }
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
#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>
|
2010-03-08 12:04:59 +01:00
|
|
|
#include <machine/vm.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-05-18 00:22:53 +02:00
|
|
|
PRIVATE t_or or_state;
|
|
|
|
PRIVATE int or_instance;
|
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_s, (message * mp, int from_int));
|
|
|
|
_PROTOTYPE (static void or_readv_s, (message * mp, int from_int));
|
2010-05-18 00:22:53 +02:00
|
|
|
_PROTOTYPE (static void reply, (t_or * orp));
|
2010-05-10 22:19:55 +02:00
|
|
|
_PROTOTYPE (static int or_probe, (t_or *, int skip));
|
2007-07-24 16:49:09 +02:00
|
|
|
_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_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 or_reset, (void));
|
|
|
|
_PROTOTYPE (static void or_watchdog_f, (timer_t *tp) );
|
|
|
|
_PROTOTYPE (static void setup_wepkey, (t_or *orp, char *wepkey0) );
|
2010-03-22 21:43:06 +01:00
|
|
|
_PROTOTYPE (static void do_hard_int, (void));
|
2007-07-24 16:49:09 +02:00
|
|
|
_PROTOTYPE (static void check_int_events, (void));
|
2010-03-22 21:43:06 +01:00
|
|
|
_PROTOTYPE (static void or_handler, (t_or *orp));
|
2007-07-24 16:49:09 +02:00
|
|
|
_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
|
|
|
|
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) );
|
New RS and new signal handling for system processes.
UPDATING INFO:
20100317:
/usr/src/etc/system.conf updated to ignore default kernel calls: copy
it (or merge it) to /etc/system.conf.
The hello driver (/dev/hello) added to the distribution:
# cd /usr/src/commands/scripts && make clean install
# cd /dev && MAKEDEV hello
KERNEL CHANGES:
- Generic signal handling support. The kernel no longer assumes PM as a signal
manager for every process. The signal manager of a given process can now be
specified in its privilege slot. When a signal has to be delivered, the kernel
performs the lookup and forwards the signal to the appropriate signal manager.
PM is the default signal manager for user processes, RS is the default signal
manager for system processes. To enable ptrace()ing for system processes, it
is sufficient to change the default signal manager to PM. This will temporarily
disable crash recovery, though.
- sys_exit() is now split into sys_exit() (i.e. exit() for system processes,
which generates a self-termination signal), and sys_clear() (i.e. used by PM
to ask the kernel to clear a process slot when a process exits).
- Added a new kernel call (i.e. sys_update()) to swap two process slots and
implement live update.
PM CHANGES:
- Posix signal handling is no longer allowed for system processes. System
signals are split into two fixed categories: termination and non-termination
signals. When a non-termination signaled is processed, PM transforms the signal
into an IPC message and delivers the message to the system process. When a
termination signal is processed, PM terminates the process.
- PM no longer assumes itself as the signal manager for system processes. It now
makes sure that every system signal goes through the kernel before being
actually processes. The kernel will then dispatch the signal to the appropriate
signal manager which may or may not be PM.
SYSLIB CHANGES:
- Simplified SEF init and LU callbacks.
- Added additional predefined SEF callbacks to debug crash recovery and
live update.
- Fixed a temporary ack in the SEF init protocol. SEF init reply is now
completely synchronous.
- Added SEF signal event type to provide a uniform interface for system
processes to deal with signals. A sef_cb_signal_handler() callback is
available for system processes to handle every received signal. A
sef_cb_signal_manager() callback is used by signal managers to process
system signals on behalf of the kernel.
- Fixed a few bugs with memory mapping and DS.
VM CHANGES:
- Page faults and memory requests coming from the kernel are now implemented
using signals.
- Added a new VM call to swap two process slots and implement live update.
- The call is used by RS at update time and in turn invokes the kernel call
sys_update().
RS CHANGES:
- RS has been reworked with a better functional decomposition.
- Better kernel call masks. com.h now defines the set of very basic kernel calls
every system service is allowed to use. This makes system.conf simpler and
easier to maintain. In addition, this guarantees a higher level of isolation
for system libraries that use one or more kernel calls internally (e.g. printf).
- RS is the default signal manager for system processes. By default, RS
intercepts every signal delivered to every system process. This makes crash
recovery possible before bringing PM and friends in the loop.
- RS now supports fast rollback when something goes wrong while initializing
the new version during a live update.
- Live update is now implemented by keeping the two versions side-by-side and
swapping the process slots when the old version is ready to update.
- Crash recovery is now implemented by keeping the two versions side-by-side
and cleaning up the old version only when the recovery process is complete.
DS CHANGES:
- Fixed a bug when the process doing ds_publish() or ds_delete() is not known
by DS.
- Fixed the completely broken support for strings. String publishing is now
implemented in the system library and simply wraps publishing of memory ranges.
Ideally, we should adopt a similar approach for other data types as well.
- Test suite fixed.
DRIVER CHANGES:
- The hello driver has been added to the Minix distribution to demonstrate basic
live update and crash recovery functionalities.
- Other drivers have been adapted to conform the new SEF interface.
2010-03-17 02:15:29 +01:00
|
|
|
FORWARD _PROTOTYPE( void sef_cb_signal_handler, (int signo) );
|
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
|
|
|
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;
|
2010-04-08 15:41:35 +02:00
|
|
|
int ipc_status;
|
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) {
|
2010-04-08 15:41:35 +02:00
|
|
|
if ((r = netdriver_receive (ANY, &m, &ipc_status)) != OK)
|
|
|
|
panic("orinoco: netdriver_receive failed");
|
2007-07-24 16:49:09 +02:00
|
|
|
|
2010-04-08 15:41:35 +02:00
|
|
|
if (is_ipc_notify(ipc_status)) {
|
2009-09-29 20:47:56 +02:00
|
|
|
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;
|
|
|
|
default:
|
2010-03-05 16:05:11 +01:00
|
|
|
panic("orinoco: illegal notify from: %d",
|
2009-09-29 20:47:56 +02:00
|
|
|
m.m_source);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* done, get new message */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2007-07-24 16:49:09 +02:00
|
|
|
switch (m.m_type) {
|
|
|
|
case DL_WRITEV_S:
|
|
|
|
or_writev_s (&m, FALSE);
|
|
|
|
break;
|
|
|
|
case DL_READV_S:
|
|
|
|
or_readv_s (&m, FALSE);
|
|
|
|
break;
|
|
|
|
case DL_CONF:
|
|
|
|
or_init (&m);
|
|
|
|
break;
|
|
|
|
case DL_GETSTAT_S:
|
|
|
|
or_getstat_s (&m);
|
|
|
|
break;
|
|
|
|
default:
|
2010-03-05 16:05:11 +01:00
|
|
|
panic("orinoco: illegal message: %d", m.m_type);
|
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 *
|
|
|
|
*===========================================================================*/
|
|
|
|
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);
|
2010-04-08 15:41:35 +02:00
|
|
|
sef_setcb_init_lu(sef_cb_init_fresh);
|
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_setcb_init_restart(sef_cb_init_fresh);
|
|
|
|
|
2010-04-08 15:41:35 +02:00
|
|
|
/* Register live update callbacks. */
|
|
|
|
sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready);
|
|
|
|
sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_workfree);
|
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
|
|
|
|
New RS and new signal handling for system processes.
UPDATING INFO:
20100317:
/usr/src/etc/system.conf updated to ignore default kernel calls: copy
it (or merge it) to /etc/system.conf.
The hello driver (/dev/hello) added to the distribution:
# cd /usr/src/commands/scripts && make clean install
# cd /dev && MAKEDEV hello
KERNEL CHANGES:
- Generic signal handling support. The kernel no longer assumes PM as a signal
manager for every process. The signal manager of a given process can now be
specified in its privilege slot. When a signal has to be delivered, the kernel
performs the lookup and forwards the signal to the appropriate signal manager.
PM is the default signal manager for user processes, RS is the default signal
manager for system processes. To enable ptrace()ing for system processes, it
is sufficient to change the default signal manager to PM. This will temporarily
disable crash recovery, though.
- sys_exit() is now split into sys_exit() (i.e. exit() for system processes,
which generates a self-termination signal), and sys_clear() (i.e. used by PM
to ask the kernel to clear a process slot when a process exits).
- Added a new kernel call (i.e. sys_update()) to swap two process slots and
implement live update.
PM CHANGES:
- Posix signal handling is no longer allowed for system processes. System
signals are split into two fixed categories: termination and non-termination
signals. When a non-termination signaled is processed, PM transforms the signal
into an IPC message and delivers the message to the system process. When a
termination signal is processed, PM terminates the process.
- PM no longer assumes itself as the signal manager for system processes. It now
makes sure that every system signal goes through the kernel before being
actually processes. The kernel will then dispatch the signal to the appropriate
signal manager which may or may not be PM.
SYSLIB CHANGES:
- Simplified SEF init and LU callbacks.
- Added additional predefined SEF callbacks to debug crash recovery and
live update.
- Fixed a temporary ack in the SEF init protocol. SEF init reply is now
completely synchronous.
- Added SEF signal event type to provide a uniform interface for system
processes to deal with signals. A sef_cb_signal_handler() callback is
available for system processes to handle every received signal. A
sef_cb_signal_manager() callback is used by signal managers to process
system signals on behalf of the kernel.
- Fixed a few bugs with memory mapping and DS.
VM CHANGES:
- Page faults and memory requests coming from the kernel are now implemented
using signals.
- Added a new VM call to swap two process slots and implement live update.
- The call is used by RS at update time and in turn invokes the kernel call
sys_update().
RS CHANGES:
- RS has been reworked with a better functional decomposition.
- Better kernel call masks. com.h now defines the set of very basic kernel calls
every system service is allowed to use. This makes system.conf simpler and
easier to maintain. In addition, this guarantees a higher level of isolation
for system libraries that use one or more kernel calls internally (e.g. printf).
- RS is the default signal manager for system processes. By default, RS
intercepts every signal delivered to every system process. This makes crash
recovery possible before bringing PM and friends in the loop.
- RS now supports fast rollback when something goes wrong while initializing
the new version during a live update.
- Live update is now implemented by keeping the two versions side-by-side and
swapping the process slots when the old version is ready to update.
- Crash recovery is now implemented by keeping the two versions side-by-side
and cleaning up the old version only when the recovery process is complete.
DS CHANGES:
- Fixed a bug when the process doing ds_publish() or ds_delete() is not known
by DS.
- Fixed the completely broken support for strings. String publishing is now
implemented in the system library and simply wraps publishing of memory ranges.
Ideally, we should adopt a similar approach for other data types as well.
- Test suite fixed.
DRIVER CHANGES:
- The hello driver has been added to the Minix distribution to demonstrate basic
live update and crash recovery functionalities.
- Other drivers have been adapted to conform the new SEF interface.
2010-03-17 02:15:29 +01:00
|
|
|
/* Register signal callbacks. */
|
|
|
|
sef_setcb_signal_handler(sef_cb_signal_handler);
|
|
|
|
|
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
|
|
|
/* 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. */
|
2010-05-18 00:22:53 +02:00
|
|
|
long v;
|
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 fkeys, sfkeys, r;
|
|
|
|
|
|
|
|
system_hz = sys_hz();
|
|
|
|
|
2010-05-18 00:22:53 +02:00
|
|
|
v = 0;
|
|
|
|
(void) env_parse("instance", "d", 0, &v, 0, 255);
|
|
|
|
or_instance = (int) v;
|
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
|
|
|
|
|
|
|
/* 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);
|
|
|
|
|
2010-04-08 15:41:35 +02:00
|
|
|
/* Announce we are up! */
|
|
|
|
netdriver_announce();
|
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);
|
|
|
|
}
|
|
|
|
|
New RS and new signal handling for system processes.
UPDATING INFO:
20100317:
/usr/src/etc/system.conf updated to ignore default kernel calls: copy
it (or merge it) to /etc/system.conf.
The hello driver (/dev/hello) added to the distribution:
# cd /usr/src/commands/scripts && make clean install
# cd /dev && MAKEDEV hello
KERNEL CHANGES:
- Generic signal handling support. The kernel no longer assumes PM as a signal
manager for every process. The signal manager of a given process can now be
specified in its privilege slot. When a signal has to be delivered, the kernel
performs the lookup and forwards the signal to the appropriate signal manager.
PM is the default signal manager for user processes, RS is the default signal
manager for system processes. To enable ptrace()ing for system processes, it
is sufficient to change the default signal manager to PM. This will temporarily
disable crash recovery, though.
- sys_exit() is now split into sys_exit() (i.e. exit() for system processes,
which generates a self-termination signal), and sys_clear() (i.e. used by PM
to ask the kernel to clear a process slot when a process exits).
- Added a new kernel call (i.e. sys_update()) to swap two process slots and
implement live update.
PM CHANGES:
- Posix signal handling is no longer allowed for system processes. System
signals are split into two fixed categories: termination and non-termination
signals. When a non-termination signaled is processed, PM transforms the signal
into an IPC message and delivers the message to the system process. When a
termination signal is processed, PM terminates the process.
- PM no longer assumes itself as the signal manager for system processes. It now
makes sure that every system signal goes through the kernel before being
actually processes. The kernel will then dispatch the signal to the appropriate
signal manager which may or may not be PM.
SYSLIB CHANGES:
- Simplified SEF init and LU callbacks.
- Added additional predefined SEF callbacks to debug crash recovery and
live update.
- Fixed a temporary ack in the SEF init protocol. SEF init reply is now
completely synchronous.
- Added SEF signal event type to provide a uniform interface for system
processes to deal with signals. A sef_cb_signal_handler() callback is
available for system processes to handle every received signal. A
sef_cb_signal_manager() callback is used by signal managers to process
system signals on behalf of the kernel.
- Fixed a few bugs with memory mapping and DS.
VM CHANGES:
- Page faults and memory requests coming from the kernel are now implemented
using signals.
- Added a new VM call to swap two process slots and implement live update.
- The call is used by RS at update time and in turn invokes the kernel call
sys_update().
RS CHANGES:
- RS has been reworked with a better functional decomposition.
- Better kernel call masks. com.h now defines the set of very basic kernel calls
every system service is allowed to use. This makes system.conf simpler and
easier to maintain. In addition, this guarantees a higher level of isolation
for system libraries that use one or more kernel calls internally (e.g. printf).
- RS is the default signal manager for system processes. By default, RS
intercepts every signal delivered to every system process. This makes crash
recovery possible before bringing PM and friends in the loop.
- RS now supports fast rollback when something goes wrong while initializing
the new version during a live update.
- Live update is now implemented by keeping the two versions side-by-side and
swapping the process slots when the old version is ready to update.
- Crash recovery is now implemented by keeping the two versions side-by-side
and cleaning up the old version only when the recovery process is complete.
DS CHANGES:
- Fixed a bug when the process doing ds_publish() or ds_delete() is not known
by DS.
- Fixed the completely broken support for strings. String publishing is now
implemented in the system library and simply wraps publishing of memory ranges.
Ideally, we should adopt a similar approach for other data types as well.
- Test suite fixed.
DRIVER CHANGES:
- The hello driver has been added to the Minix distribution to demonstrate basic
live update and crash recovery functionalities.
- Other drivers have been adapted to conform the new SEF interface.
2010-03-17 02:15:29 +01:00
|
|
|
/*===========================================================================*
|
|
|
|
* sef_cb_signal_handler *
|
|
|
|
*===========================================================================*/
|
|
|
|
PRIVATE void sef_cb_signal_handler(int signo)
|
|
|
|
{
|
|
|
|
t_or *orp;
|
|
|
|
|
|
|
|
/* Only check for termination signal, ignore anything else. */
|
|
|
|
if (signo != SIGTERM) return;
|
|
|
|
|
2010-05-18 00:22:53 +02:00
|
|
|
orp = &or_state;
|
|
|
|
|
|
|
|
if (orp->or_mode == OR_M_ENABLED) {
|
New RS and new signal handling for system processes.
UPDATING INFO:
20100317:
/usr/src/etc/system.conf updated to ignore default kernel calls: copy
it (or merge it) to /etc/system.conf.
The hello driver (/dev/hello) added to the distribution:
# cd /usr/src/commands/scripts && make clean install
# cd /dev && MAKEDEV hello
KERNEL CHANGES:
- Generic signal handling support. The kernel no longer assumes PM as a signal
manager for every process. The signal manager of a given process can now be
specified in its privilege slot. When a signal has to be delivered, the kernel
performs the lookup and forwards the signal to the appropriate signal manager.
PM is the default signal manager for user processes, RS is the default signal
manager for system processes. To enable ptrace()ing for system processes, it
is sufficient to change the default signal manager to PM. This will temporarily
disable crash recovery, though.
- sys_exit() is now split into sys_exit() (i.e. exit() for system processes,
which generates a self-termination signal), and sys_clear() (i.e. used by PM
to ask the kernel to clear a process slot when a process exits).
- Added a new kernel call (i.e. sys_update()) to swap two process slots and
implement live update.
PM CHANGES:
- Posix signal handling is no longer allowed for system processes. System
signals are split into two fixed categories: termination and non-termination
signals. When a non-termination signaled is processed, PM transforms the signal
into an IPC message and delivers the message to the system process. When a
termination signal is processed, PM terminates the process.
- PM no longer assumes itself as the signal manager for system processes. It now
makes sure that every system signal goes through the kernel before being
actually processes. The kernel will then dispatch the signal to the appropriate
signal manager which may or may not be PM.
SYSLIB CHANGES:
- Simplified SEF init and LU callbacks.
- Added additional predefined SEF callbacks to debug crash recovery and
live update.
- Fixed a temporary ack in the SEF init protocol. SEF init reply is now
completely synchronous.
- Added SEF signal event type to provide a uniform interface for system
processes to deal with signals. A sef_cb_signal_handler() callback is
available for system processes to handle every received signal. A
sef_cb_signal_manager() callback is used by signal managers to process
system signals on behalf of the kernel.
- Fixed a few bugs with memory mapping and DS.
VM CHANGES:
- Page faults and memory requests coming from the kernel are now implemented
using signals.
- Added a new VM call to swap two process slots and implement live update.
- The call is used by RS at update time and in turn invokes the kernel call
sys_update().
RS CHANGES:
- RS has been reworked with a better functional decomposition.
- Better kernel call masks. com.h now defines the set of very basic kernel calls
every system service is allowed to use. This makes system.conf simpler and
easier to maintain. In addition, this guarantees a higher level of isolation
for system libraries that use one or more kernel calls internally (e.g. printf).
- RS is the default signal manager for system processes. By default, RS
intercepts every signal delivered to every system process. This makes crash
recovery possible before bringing PM and friends in the loop.
- RS now supports fast rollback when something goes wrong while initializing
the new version during a live update.
- Live update is now implemented by keeping the two versions side-by-side and
swapping the process slots when the old version is ready to update.
- Crash recovery is now implemented by keeping the two versions side-by-side
and cleaning up the old version only when the recovery process is complete.
DS CHANGES:
- Fixed a bug when the process doing ds_publish() or ds_delete() is not known
by DS.
- Fixed the completely broken support for strings. String publishing is now
implemented in the system library and simply wraps publishing of memory ranges.
Ideally, we should adopt a similar approach for other data types as well.
- Test suite fixed.
DRIVER CHANGES:
- The hello driver has been added to the Minix distribution to demonstrate basic
live update and crash recovery functionalities.
- Other drivers have been adapted to conform the new SEF interface.
2010-03-17 02:15:29 +01:00
|
|
|
/* TODO: send a signal to the card to shut it down */
|
|
|
|
}
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
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) {
|
|
|
|
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 */
|
2010-05-18 00:22:53 +02:00
|
|
|
orp = &or_state;
|
2007-07-24 16:49:09 +02:00
|
|
|
|
2010-05-18 00:22:53 +02:00
|
|
|
if (orp->or_mode != OR_M_ENABLED)
|
|
|
|
return;
|
|
|
|
if (!orp->or_got_int)
|
|
|
|
return;
|
|
|
|
orp->or_got_int = 0;
|
|
|
|
assert (orp->or_flags & OR_F_ENABLED);
|
|
|
|
or_check_ints (orp);
|
2007-07-24 16:49:09 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
* do_hard_int *
|
|
|
|
* *
|
|
|
|
* Process the interrupts which the card generated *
|
|
|
|
*****************************************************************************/
|
2010-03-22 21:43:06 +01:00
|
|
|
static void do_hard_int(void)
|
|
|
|
{
|
2010-05-18 00:22:53 +02:00
|
|
|
int s;
|
2007-07-24 16:49:09 +02:00
|
|
|
|
2010-05-18 00:22:53 +02:00
|
|
|
/* Run interrupt handler at driver level. */
|
|
|
|
or_handler(&or_state);
|
2007-07-24 16:49:09 +02:00
|
|
|
|
2010-05-18 00:22:53 +02:00
|
|
|
/* Reenable interrupts for this hook. */
|
|
|
|
if ((s=sys_irqenable(&or_state.or_hook_id)) != OK) {
|
|
|
|
printf("orinoco: error, couldn't enable");
|
|
|
|
printf(" interrupts: %d\n", s);
|
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;
|
2010-05-18 00:22:53 +02:00
|
|
|
int i, r;
|
2007-07-24 16:49:09 +02:00
|
|
|
|
|
|
|
if (OK != (r = getuptime(&now)))
|
2010-03-05 16:05:11 +01:00
|
|
|
panic("orinoco: getuptime() failed: %d", r);
|
2007-07-24 16:49:09 +02:00
|
|
|
|
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);
|
|
|
|
}
|
2010-05-18 00:22:53 +02:00
|
|
|
|
|
|
|
last_reset = now;
|
2007-07-24 16:49:09 +02:00
|
|
|
|
2010-05-18 00:22:53 +02:00
|
|
|
orp = &or_state;
|
2007-07-24 16:49:09 +02:00
|
|
|
|
2010-05-18 00:22:53 +02:00
|
|
|
if(orp->or_mode == OR_M_DISABLED)
|
|
|
|
printf("orinoco instance %d is disabled\n", or_instance);
|
|
|
|
|
|
|
|
if(orp->or_mode != OR_M_ENABLED) {
|
|
|
|
return;
|
|
|
|
}
|
2007-07-24 16:49:09 +02:00
|
|
|
|
2010-05-18 00:22:53 +02:00
|
|
|
orp->or_need_reset = 0;
|
|
|
|
or_init_hw(orp);
|
2007-07-24 16:49:09 +02:00
|
|
|
|
2010-05-18 00:22:53 +02:00
|
|
|
orp->rx_last = orp->rx_first = 0;
|
|
|
|
for(i = 0; i < NR_RX_BUFS; i++) {
|
|
|
|
orp->rx_length[0] = 0;
|
2007-07-24 16:49:09 +02:00
|
|
|
}
|
|
|
|
|
2010-05-18 00:22:53 +02:00
|
|
|
if(orp->or_flags & OR_F_SEND_AVAIL) {
|
|
|
|
orp->or_tx.ret_busy = FALSE;
|
|
|
|
orp->or_send_int = TRUE;
|
|
|
|
}
|
2007-07-24 16:49:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
* or_dump *
|
|
|
|
* *
|
|
|
|
* Dump interesting information about the card on F-key pressed. *
|
|
|
|
* Not implemented yet *
|
|
|
|
*****************************************************************************/
|
2010-02-19 11:00:32 +01:00
|
|
|
static void or_dump (message *m)
|
|
|
|
{
|
2007-07-24 16:49:09 +02:00
|
|
|
t_or *orp;
|
2010-05-18 00:22:53 +02:00
|
|
|
|
|
|
|
orp = &or_state;
|
2007-07-24 16:49:09 +02:00
|
|
|
|
2010-05-18 00:22:53 +02:00
|
|
|
if(orp->or_mode == OR_M_DISABLED) {
|
|
|
|
printf("%s is disabled\n", orp->or_name);
|
|
|
|
}
|
2007-07-24 16:49:09 +02:00
|
|
|
|
2010-05-18 00:22:53 +02:00
|
|
|
if(orp->or_mode != OR_M_ENABLED)
|
|
|
|
return;
|
2007-07-24 16:49:09 +02:00
|
|
|
|
2010-05-18 00:22:53 +02:00
|
|
|
m->m_type = FKEY_CONTROL;
|
|
|
|
m->FKEY_REQUEST = FKEY_EVENTS;
|
|
|
|
if(OK!=(sendrec(TTY_PROC_NR,m)) )
|
|
|
|
printf("Contacting the TTY failed\n");
|
2007-07-24 16:49:09 +02:00
|
|
|
|
2010-05-18 00:22:53 +02:00
|
|
|
if(bit_isset(m->FKEY_SFKEYS, 11)) {
|
|
|
|
print_linkstatus(orp, orp->last_linkstatus);
|
2007-07-24 16:49:09 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
* or_init *
|
|
|
|
* *
|
|
|
|
* The main initialization function, called when a DL_INIT message comes in. *
|
|
|
|
*****************************************************************************/
|
|
|
|
static void or_init (message * mp) {
|
|
|
|
t_or *orp;
|
|
|
|
message reply;
|
|
|
|
static int first_time = 1;
|
|
|
|
|
|
|
|
if (first_time) {
|
|
|
|
first_time = 0;
|
|
|
|
or_pci_conf (); /* Configure PCI devices. */
|
|
|
|
|
|
|
|
/* 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
|
|
|
}
|
|
|
|
|
2010-05-18 00:22:53 +02:00
|
|
|
orp = &or_state;
|
2007-07-24 16:49:09 +02:00
|
|
|
|
|
|
|
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;
|
2010-05-18 00:22:53 +02:00
|
|
|
reply.DL_STAT = ENXIO;
|
2007-07-24 16:49:09 +02:00
|
|
|
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;
|
|
|
|
|
|
|
|
or_rec_mode (orp);
|
|
|
|
|
|
|
|
/* reply the caller that the configuration succeeded */
|
|
|
|
reply.m_type = DL_CONF_REPLY;
|
2010-05-18 00:22:53 +02:00
|
|
|
reply.DL_STAT = OK;
|
|
|
|
*(ether_addr_t *) reply.DL_HWADDR = orp->or_address;
|
2007-07-24 16:49:09 +02:00
|
|
|
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;
|
|
|
|
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 */
|
2010-05-18 00:22:53 +02:00
|
|
|
orp = &or_state;
|
|
|
|
|
|
|
|
strncpy (orp->or_name, OR_NAME, sizeof(OR_NAME));
|
|
|
|
orp->or_name[sizeof(OR_NAME) - 2] = or_instance + '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' + or_instance;
|
|
|
|
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;
|
2007-07-24 16:49:09 +02:00
|
|
|
|
|
|
|
/* Initialize the pci bus, bridges and cards, if not yet done */
|
|
|
|
pci_init ();
|
|
|
|
|
2010-05-18 00:22:53 +02:00
|
|
|
/* Try to find out where the card is in the pci bus */
|
|
|
|
if (or_probe (orp, or_instance))
|
|
|
|
orp->or_seen = TRUE;
|
2007-07-24 16:49:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
* or_probe *
|
|
|
|
* *
|
|
|
|
* Try to find the card based on information provided by pci and get irq and *
|
|
|
|
* bar *
|
|
|
|
*****************************************************************************/
|
2010-05-10 22:19:55 +02:00
|
|
|
static int or_probe (t_or * orp, int skip)
|
2010-04-07 13:25:51 +02:00
|
|
|
{
|
2007-07-24 16:49:09 +02:00
|
|
|
u8_t ilr;
|
2010-04-07 13:25:51 +02:00
|
|
|
u32_t bar;
|
2007-07-24 16:49:09 +02:00
|
|
|
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) {
|
2010-03-05 16:05:11 +01:00
|
|
|
panic("or_probe:class check not implmnted");
|
2007-07-24 16:49:09 +02:00
|
|
|
}
|
|
|
|
/* we have found the card in the pci bus */
|
|
|
|
break;
|
|
|
|
}
|
2010-05-10 22:19:55 +02:00
|
|
|
|
|
|
|
/* unless we are looking for a specific device, we may have to
|
|
|
|
* skip a number of cards because they are already reserved for
|
|
|
|
* other (lower) ports of this driver */
|
|
|
|
if (pcitab[i].vid != 0) {
|
|
|
|
if (just_one || !skip)
|
|
|
|
break;
|
|
|
|
skip--;
|
|
|
|
}
|
2007-07-24 16:49:09 +02:00
|
|
|
|
|
|
|
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 *
|
|
|
|
*****************************************************************************/
|
2010-04-07 13:25:51 +02:00
|
|
|
static void map_hw_buffer(t_or *orp)
|
|
|
|
{
|
2007-07-24 16:49:09 +02:00
|
|
|
int r;
|
2010-04-07 13:25:51 +02:00
|
|
|
size_t o, size;
|
2007-07-24 16:49:09 +02:00
|
|
|
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)
|
2010-03-05 16:05:11 +01:00
|
|
|
panic("map_hw_buffer: cannot malloc size: %d", size);
|
2007-07-24 16:49:09 +02:00
|
|
|
|
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)
|
2010-03-05 16:05:11 +01:00
|
|
|
panic("map_hw_buffer: sys_vm_map failed: %d", r);
|
2007-07-24 16:49:09 +02:00
|
|
|
|
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. *
|
|
|
|
*****************************************************************************/
|
2010-04-07 13:25:51 +02:00
|
|
|
static u32_t or_get_bar (int devind, t_or * orp)
|
|
|
|
{
|
|
|
|
u32_t bar;
|
|
|
|
int is_iospace;
|
2007-07-24 16:49:09 +02:00
|
|
|
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)
|
2010-03-05 16:05:11 +01:00
|
|
|
panic("base address isn't properly configured");
|
2007-07-24 16:49:09 +02:00
|
|
|
|
|
|
|
/* 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);
|
|
|
|
}
|
|
|
|
|
2010-05-18 00:22:53 +02:00
|
|
|
panic("Not implemented yet");
|
2007-07-24 16:49:09 +02:00
|
|
|
/* 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 *
|
|
|
|
*****************************************************************************/
|
2010-04-07 13:25:51 +02:00
|
|
|
static void or_init_struct (t_or * orp)
|
|
|
|
{
|
2007-07-24 16:49:09 +02:00
|
|
|
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 *
|
|
|
|
*****************************************************************************/
|
2010-04-07 13:25:51 +02:00
|
|
|
static void or_init_hw (t_or * orp)
|
|
|
|
{
|
2007-07-24 16:49:09 +02:00
|
|
|
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! ;) */
|
2010-05-18 00:22:53 +02:00
|
|
|
if ((err = hermes_init (hw)) != 0) {
|
2007-07-24 16:49:09 +02:00
|
|
|
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 *
|
|
|
|
*****************************************************************************/
|
|
|
|
|
2010-04-07 13:25:51 +02:00
|
|
|
static void or_readrids (hermes_t * hw, t_or * orp)
|
|
|
|
{
|
2007-07-24 16:49:09 +02:00
|
|
|
/* Read the MAC address */
|
2010-04-07 13:25:51 +02:00
|
|
|
int err = hermes_read_ltv (hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
|
2007-07-24 16:49:09 +02:00
|
|
|
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 *
|
|
|
|
*****************************************************************************/
|
2010-04-07 13:25:51 +02:00
|
|
|
static void or_writerids (hermes_t * hw, t_or * orp)
|
|
|
|
{
|
2007-07-24 16:49:09 +02:00
|
|
|
int err;
|
|
|
|
struct hermes_idstring idbuf;
|
2010-04-07 13:25:51 +02:00
|
|
|
u16_t port_type;
|
2007-07-24 16:49:09 +02:00
|
|
|
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 *
|
|
|
|
*****************************************************************************/
|
2010-03-22 21:43:06 +01:00
|
|
|
static void or_handler (t_or *orp)
|
|
|
|
{
|
2010-04-07 13:25:51 +02:00
|
|
|
int length;
|
2007-07-24 16:49:09 +02:00
|
|
|
u16_t evstat, events, fid;
|
2010-04-07 13:25:51 +02:00
|
|
|
hermes_t *hw = &(orp->hw);
|
2007-07-24 16:49:09 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
* or_watchdog_f *
|
|
|
|
* *
|
|
|
|
* Will be called regularly to see whether the driver has crashed. If that *
|
|
|
|
* condition is detected, reset the driver and card *
|
|
|
|
*****************************************************************************/
|
2010-04-07 13:25:51 +02:00
|
|
|
static void or_watchdog_f(timer_t *tp)
|
|
|
|
{
|
2007-07-24 16:49:09 +02:00
|
|
|
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
|
|
|
|
2010-05-18 00:22:53 +02:00
|
|
|
orp = &or_state;
|
2007-07-24 16:49:09 +02:00
|
|
|
|
2010-05-18 00:22:53 +02:00
|
|
|
if (orp->or_mode != OR_M_ENABLED)
|
|
|
|
return;
|
2007-07-24 16:49:09 +02:00
|
|
|
|
2010-05-18 00:22:53 +02:00
|
|
|
if (!(orp->or_flags & OR_F_SEND_AVAIL)) {
|
|
|
|
/* Assume that an idle system is alive */
|
|
|
|
orp->or_tx_alive= TRUE;
|
|
|
|
return;
|
2007-07-24 16:49:09 +02:00
|
|
|
}
|
2010-05-18 00:22:53 +02:00
|
|
|
|
|
|
|
if (orp->connected == 0) {
|
|
|
|
orp->or_tx_alive= TRUE;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (orp->or_tx_alive) {
|
|
|
|
orp->or_tx_alive= FALSE;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
printf("or_watchdog_f: resetting instance %d\n", or_instance);
|
|
|
|
|
|
|
|
orp->or_need_reset= TRUE;
|
|
|
|
orp->or_got_int= TRUE;
|
|
|
|
check_int_events();
|
2007-07-24 16:49:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
* mess_reply *
|
|
|
|
*****************************************************************************/
|
2010-04-07 13:25:51 +02:00
|
|
|
static void mess_reply (message * req, message * reply_mess)
|
|
|
|
{
|
2007-07-24 16:49:09 +02:00
|
|
|
if (send (req->m_source, reply_mess) != 0)
|
2010-03-05 16:05:11 +01:00
|
|
|
panic("orinoco: unable to mess_reply");
|
2007-07-24 16:49:09 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
* 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) {
|
2010-05-18 00:22:53 +02:00
|
|
|
int count, size, err, data_len, data_off;
|
2007-07-24 16:49:09 +02:00
|
|
|
int o, j, n, i, s, p, cps ;
|
|
|
|
struct ethhdr *eh;
|
|
|
|
t_or *orp;
|
|
|
|
hermes_t *hw;
|
|
|
|
struct hermes_tx_descriptor desc;
|
|
|
|
int iov_offset = 0;
|
|
|
|
struct header_struct hdr;
|
|
|
|
iovec_s_t *iovp;
|
|
|
|
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);
|
|
|
|
|
2010-05-18 00:22:53 +02:00
|
|
|
orp = &or_state;
|
|
|
|
|
2007-07-24 16:49:09 +02:00
|
|
|
count = mp->DL_COUNT;
|
|
|
|
|
2010-05-18 00:22:53 +02:00
|
|
|
orp->or_client = mp->m_source;
|
2007-07-24 16:49:09 +02:00
|
|
|
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;
|
|
|
|
|
2010-05-18 00:22:53 +02:00
|
|
|
cps = sys_safecopyfrom(mp->DL_ENDPT, mp->DL_GRANT, iov_offset,
|
2007-07-24 16:49:09 +02:00
|
|
|
(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");
|
|
|
|
}
|
|
|
|
|
2010-05-18 00:22:53 +02:00
|
|
|
cps = sys_safecopyfrom(mp->DL_ENDPT, iovp->iov_grant,
|
|
|
|
0, (vir_bytes) databuf + o, s, D);
|
2007-07-24 16:49:09 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2010-05-18 00:22:53 +02:00
|
|
|
reply (orp);
|
2007-07-24 16:49:09 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
suspend_write_s:
|
|
|
|
orp->or_tx_mess = *mp;
|
|
|
|
|
2010-05-18 00:22:53 +02:00
|
|
|
reply (orp);
|
2007-07-24 16:49:09 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
* reply *
|
|
|
|
* *
|
|
|
|
* Send a message back to the caller, informing it about the data received *
|
|
|
|
* or sent *
|
|
|
|
*****************************************************************************/
|
2010-05-18 00:22:53 +02:00
|
|
|
static void reply (t_or * orp) {
|
2007-07-24 16:49:09 +02:00
|
|
|
message reply;
|
2010-05-18 00:22:53 +02:00
|
|
|
int flags = DL_NOFLAGS, r;
|
2007-07-24 16:49:09 +02:00
|
|
|
|
|
|
|
if (orp->or_flags & OR_F_PACK_SENT)
|
2010-05-18 00:22:53 +02:00
|
|
|
flags |= DL_PACK_SEND;
|
2007-07-24 16:49:09 +02:00
|
|
|
if (orp->or_flags & OR_F_PACK_RECV)
|
2010-05-18 00:22:53 +02:00
|
|
|
flags |= DL_PACK_RECV;
|
2007-07-24 16:49:09 +02:00
|
|
|
|
|
|
|
reply.m_type = DL_TASK_REPLY;
|
2010-05-18 00:22:53 +02:00
|
|
|
reply.DL_FLAGS = flags;
|
2007-07-24 16:49:09 +02:00
|
|
|
reply.DL_COUNT = orp->or_read_s;
|
|
|
|
|
|
|
|
r = send (orp->or_client, &reply);
|
|
|
|
|
|
|
|
if (r < 0)
|
2010-03-05 16:05:11 +01:00
|
|
|
panic("orinoco: send failed: %d", r);
|
2007-07-24 16:49:09 +02:00
|
|
|
|
|
|
|
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 *
|
|
|
|
*****************************************************************************/
|
2010-04-07 13:25:51 +02:00
|
|
|
static void or_ev_info (t_or * orp)
|
|
|
|
{
|
2007-07-24 16:49:09 +02:00
|
|
|
u16_t infofid;
|
2010-04-07 13:25:51 +02:00
|
|
|
int err, len, type;
|
2007-07-24 16:49:09 +02:00
|
|
|
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;
|
|
|
|
}
|
2010-05-18 00:22:53 +02:00
|
|
|
printf("channel: %d, freq: %ld MHz ",
|
2007-07-24 16:49:09 +02:00
|
|
|
d, (channel_frequency[d-1]));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
* or_check_ints *
|
|
|
|
* *
|
|
|
|
* Process events which have been postponed in the interrupt handler *
|
|
|
|
*****************************************************************************/
|
2010-04-07 13:25:51 +02:00
|
|
|
static void or_check_ints (t_or * orp)
|
|
|
|
{
|
2007-07-24 16:49:09 +02:00
|
|
|
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;
|
2010-05-18 00:22:53 +02:00
|
|
|
or_readv_s (&orp->or_rx_mess, TRUE);
|
2007-07-24 16:49:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (orp->or_send_int) {
|
2010-05-18 00:22:53 +02:00
|
|
|
or_writev_s (&orp->or_tx_mess, TRUE);
|
2007-07-24 16:49:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (orp->or_flags & (OR_F_PACK_SENT | OR_F_PACK_RECV)) {
|
2010-05-18 00:22:53 +02:00
|
|
|
reply (orp);
|
2007-07-24 16:49:09 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
* 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_s *
|
|
|
|
* *
|
|
|
|
* Copy the data which is stored in orp->rx_buf[orp->rx_first] in the vector *
|
|
|
|
* which was given with the message *mp *
|
|
|
|
*****************************************************************************/
|
2010-04-07 13:25:51 +02:00
|
|
|
static void or_readv_s (message * mp, int from_int)
|
|
|
|
{
|
2010-05-18 00:22:53 +02:00
|
|
|
int i, j, n, o, s, count, size, cps;
|
2010-04-07 13:25:51 +02:00
|
|
|
int iov_offset = 0, length;
|
2007-07-24 16:49:09 +02:00
|
|
|
t_or *orp;
|
|
|
|
iovec_s_t *iovp;
|
|
|
|
u8_t *databuf;
|
|
|
|
|
2010-05-18 00:22:53 +02:00
|
|
|
orp = &or_state;
|
2007-07-24 16:49:09 +02:00
|
|
|
|
2010-05-18 00:22:53 +02:00
|
|
|
orp->or_client = mp->m_source;
|
|
|
|
count = mp->DL_COUNT;
|
2007-07-24 16:49:09 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
2010-05-18 00:22:53 +02:00
|
|
|
cps = sys_safecopyfrom(mp->DL_ENDPT, mp->DL_GRANT, iov_offset,
|
2007-07-24 16:49:09 +02:00
|
|
|
(vir_bytes)orp->or_iovec_s,
|
|
|
|
n * sizeof(orp->or_iovec_s[0]), D);
|
|
|
|
if (cps != OK)
|
2010-03-05 16:05:11 +01:00
|
|
|
panic("orinoco: warning: sys_safecopytp failed: %d", cps);
|
2007-07-24 16:49:09 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2010-05-18 00:22:53 +02:00
|
|
|
cps = sys_safecopyto(mp->DL_ENDPT, iovp->iov_grant, 0,
|
2007-07-24 16:49:09 +02:00
|
|
|
(vir_bytes) databuf + o, s, D);
|
|
|
|
if (cps != OK)
|
2010-03-05 16:05:11 +01:00
|
|
|
panic("orinoco: warning: sys_safecopy failed: %d", cps);
|
2007-07-24 16:49:09 +02:00
|
|
|
|
|
|
|
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) {
|
|
|
|
/* There was data in the orp->rx_buf[x] which is now copied to
|
|
|
|
* the inet sever. Tell the inet server */
|
2010-05-18 00:22:53 +02:00
|
|
|
reply (orp);
|
2007-07-24 16:49:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2010-05-18 00:22:53 +02:00
|
|
|
reply (orp);
|
2007-07-24 16:49:09 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
* 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;
|
|
|
|
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)) {
|
|
|
|
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_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) {
|
2010-05-18 00:22:53 +02:00
|
|
|
int r;
|
2007-07-24 16:49:09 +02:00
|
|
|
eth_stat_t stats;
|
|
|
|
t_or *orp;
|
|
|
|
|
2010-05-18 00:22:53 +02:00
|
|
|
orp = &or_state;
|
2007-07-24 16:49:09 +02:00
|
|
|
|
|
|
|
assert (orp->or_mode == OR_M_ENABLED);
|
|
|
|
assert (orp->or_flags & OR_F_ENABLED);
|
|
|
|
|
|
|
|
stats = orp->or_stat;
|
|
|
|
|
2010-05-18 00:22:53 +02:00
|
|
|
r = sys_safecopyto(mp->DL_ENDPT, mp->DL_GRANT, 0,
|
2007-07-24 16:49:09 +02:00
|
|
|
(vir_bytes) &stats, sizeof(stats), D);
|
|
|
|
if(r != OK) {
|
2010-03-05 16:05:11 +01:00
|
|
|
panic("or_getstat_s: sys_safecopyto failed: %d", r);
|
2007-07-24 16:49:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
mp->m_type = DL_STAT_REPLY;
|
|
|
|
|
|
|
|
r = send(mp->m_source, mp);
|
|
|
|
if(r != OK)
|
2010-03-05 16:05:11 +01:00
|
|
|
panic("orinoco: getstat_s failed: %d", r);
|
2007-07-24 16:49:09 +02:00
|
|
|
}
|
|
|
|
|