diff -u --recursive --new-file linux/drivers/net/pcmcia/Config.in linux-2.4.1-wavelan/drivers/net/pcmcia/Config.in --- linux/drivers/net/pcmcia/Config.in Sat Nov 11 20:56:58 2000 +++ linux-2.4.1-wavelan/drivers/net/pcmcia/Config.in Tue Jan 30 17:55:09 2001 @@ -28,6 +28,7 @@ dep_tristate ' Aviator/Raytheon 2.4MHz wireless support' CONFIG_PCMCIA_RAYCS $CONFIG_PCMCIA dep_tristate ' Xircom Netwave AirSurfer wireless support' CONFIG_PCMCIA_NETWAVE $CONFIG_PCMCIA dep_tristate ' AT&T/Lucent Wavelan wireless support' CONFIG_PCMCIA_WAVELAN $CONFIG_PCMCIA + dep_tristate ' WaveLAN/IEEE 802.11 wireless support' CONFIG_PCMCIA_WVLAN $CONFIG_PCMCIA dep_tristate ' Aironet 4500/4800 PCMCIA support' CONFIG_AIRONET4500_CS $CONFIG_AIRONET4500 $CONFIG_PCMCIA fi fi @@ -37,7 +38,7 @@ "$CONFIG_PCMCIA_NMCLAN" = "y" -o "$CONFIG_PCMCIA_SMC91C92" = "y" -o \ "$CONFIG_PCMCIA_XIRC2PS" = "y" -o "$CONFIG_PCMCIA_RAYCS" = "y" -o \ "$CONFIG_PCMCIA_NETWAVE" = "y" -o "$CONFIG_PCMCIA_WAVELAN" = "y" -o \ - "$CONFIG_PCMCIA_XIRTULIP" = "y" ]; then + "$CONFIG_PCMCIA_XIRTULIP" = "y" -o "$CONFIG_PCMCIA_WVLAN" = "y" ]; then define_bool CONFIG_PCMCIA_NETCARD y fi diff -u --recursive --new-file linux/drivers/net/pcmcia/Makefile linux-2.4.1-wavelan/drivers/net/pcmcia/Makefile --- linux/drivers/net/pcmcia/Makefile Fri Dec 29 16:07:22 2000 +++ linux-2.4.1-wavelan/drivers/net/pcmcia/Makefile Wed Jan 31 19:08:01 2001 @@ -28,6 +28,7 @@ obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o obj-$(CONFIG_PCMCIA_NETWAVE) += netwave_cs.o obj-$(CONFIG_PCMCIA_WAVELAN) += wavelan_cs.o +obj-$(CONFIG_PCMCIA_WVLAN) += wvlan_cs.o obj-$(CONFIG_AIRONET4500_CS) += aironet4500_cs.o # Cardbus client drivers @@ -43,3 +44,8 @@ ibmtr_cs.o: tmp-ibmtr.o ibmtr_cs.c $(CC) $(CFLAGS) -DPCMCIA -c -o tmp-$@ ibmtr_cs.c $(LD) -r -o $@ tmp-$@ tmp-ibmtr.o + +wvlan_cs.o: wvlan_cs.c wvlan_hcf.o wvlan_hcfio.o + $(CC) $(CFLAGS) -DMODULE -c -o .$@ $< + $(LD) -r -o $@ .$@ wvlan_hcf.o wvlan_hcfio.o + rm -f .$@ diff -u --recursive --new-file linux/drivers/net/pcmcia/wvlan_cs.c linux-2.4.1-wavelan/drivers/net/pcmcia/wvlan_cs.c --- linux/drivers/net/pcmcia/wvlan_cs.c Wed Dec 31 18:00:00 1969 +++ linux-2.4.1-wavelan/drivers/net/pcmcia/wvlan_cs.c Sun Feb 4 15:04:49 2001 @@ -0,0 +1,3303 @@ +/******************************************************************** + * WaveLAN/IEEE PCMCIA Linux network device driver + * + * by Andreas Neuhaus + * http://www.fasta.fh-dortmund.de/users/andy/wvlan/ + * + * This driver is free software; you can redistribute and/or + * modify it under the terms of the GNU General Public License; + * either version 2 of the license, or (at your option) any + * later version. + * Please send comments/bugfixes/patches to the above address. + * + * Based on the Linux PCMCIA Programmer's Guide + * and Lucent Technologies' HCF-Light library (wvlan47). + * + * See 'man 4 wvlan_cs' for more information. + * + * TODO + * We should use multiple Tx buffers to gain performance. + * Have a closer look to the endianess (PPC problems). + * + * HISTORY + * v1.0.6k 02/04/2001 - Eric Molitor (eric@molitor.org) + * Integrated into Linux Kernel 2.4.1 + * Removed unused functions and wrapped a debug only function in + * an ifdef to remove compiler warnings + * + * v1.0.6 7/12/2000 - David Hinds, Anton Blanchard, Jean II and others + * Endianess fix for PPC users, first try (David) + * Fix some ranges (power management, key size, ...) (me) + * Auto rate up to a maximum (for ex. up to 5.5) (me) + * Remove error on IW_ENCODE_RESTRICTED (me) + * Better error messages to catch stupid users (me) + * --- + * Oups ! Firmware 6.06 *do* support port3 (me) + * Oups ! ibss mode is not fully functional in firmware 6.04 (me) + * Match Windows driver for selecting Ad-Hoc mode (me) + * Get MAC address earlier, so that if module parameters are + * invalid, we can still use wireless.opts... (me) + * Use ethX and not wvlanX by default (me) + * Minimal support for some PrismII cards (me) + * Check out of bound in getratelist (Paul Mackerras) + * Finish up the endianess fix for PPC and test it + * (Paul Mackerras and Hugh Blemings) + * Check Cabletron Firmware 4.32 support (Anton) + * + * v1.0.5 19/10/2000 - David Hinds, Jean II and others + * Support for 6.00 firmware (remove fragmentation - ? + me) + * Add Microwave Oven Robustness support (me) + * Fix a bug preventing RARP from working (?) + * --- + * Fix SMP support (fix all those spinlocks - me) + * Add IBSS support, to enable 802.11 ad-hoc mode (Ross Finlayson) + * Integrate IBSS support with Wireless Extensions (me) + * Clean-up Wireless Extensions (#define and other stuff - me) + * Multi-card support for Wireless Extensions (me) + * Firmware madness support - Arghhhhh !!!!!! (me) + * --- + * Proper firmware detection routines (me) + * Aggregate configuration change when closed (me) + * wireless.opts now works on old firmware (me) + * Integrate MWO robust to frag setting (me) + * copy_to/from in ioctl with irq on (me, requested by Alan) + * Add a few "static" and "inline" there and there (me) + * Update to new module init/cleanup procedures (me) + * + * v1.0.4 2000/02/26 + * Some changes to fit into kernel 2.3.x. + * Some changes to better fit into the new net API. + * Use of spinlocks for disabling interrupts. + * Conditional to allow ignoring tx timeouts. + * Disable interrupts during config/shutdown/reset. + * Credits go to Jean Tourrilhes for all the following: + * Promiscuous mode (tcpdump now work correctly). + * Set multicast Rx list (RTP now work correctly). + * Hook up watchdog timer in new net API. + * Update frag/rts to new W-Ext. + * Operating mode support + W-Ext (Neat...). + * Power Saving support + W-Ext (useless...). + * WEP (Privacy - Silver+Gold) support + W-Ext (yeah !!!). + * Disable interupts during reading wireless stats. + * (New quality indicator not included, need more work) + * Plus a few cleanups, comments and fixes... + * + * v1.0.3 Skipped to not confuse with kernel 2.3.x driver + * + * v1.0.2 2000/01/07 + * Merged driver into the PCMCIA Card Services package + * (thanks to David Hinds). + * Removed README, added man page (man 4 wvlan_cs). + * + * v1.0.1 1999/09/02 + * Interrupts are now disabled during ioctl to prevent being + * disturbed during our fiddling with the NIC (occured + * when using wireless tools while heavy loaded link). + * Fixed a problem with more than 6 spy addresses (thanks to + * Thomas Ekstrom). + * Hopefully fixed problems with bigger packet sizes than 1500. + * When you changed parameters that were specified at module + * load time later with wireless_tools and the card was + * reset afterward (e.g. by a Tx timeout), all changes + * were lost. Changes will stay now after a reset. + * Rewrote some parts of this README, added card LEDs description. + * Added medium_reservation, ap_density, frag_threshold and + * transmit_rate to module parameters. + * Applying the patch now also modifies the files SUPPORTED.CARDS + * and MAINTAINERS. + * Signal/noise levels are now reported in dBm (-102..-10). + * Added support for the new wireless extension (get wireless_ + * tools 19). Credits go to Jean Tourrilhes for all + * the following: + * Setting channel by giving frequency value is now available. + * Setting/getting ESSID/BSSID/station-name is now possible + * via iwconfig. + * Support to set/get the desired/current bitrate. + * Support to set/get RTS threshold. + * Support to set/get fragmentation threshold. + * Support to set/get AP density. + * Support to set/get port type. + * Fixed a problem with ioctl calls when setting station/network + * name, where the new name string wasn't in kernel space + * (thanks to Danton Nunes). + * Driver sucessful tested on AlphaLinux (thanks to Peter Olson). + * Driver sucessful tested with WaveLAN Turbo cards. + * + * v0.2.7 1999/07/20 + * Changed release/detach code to fix hotswapping with 2.2/2.3 + * kernels (thanks to Derrick J Brashear). + * Fixed wrong adjustment of receive buffer length. This was only + * a problem when a higher level protocol relies on correct + * length information, so it never occured with IPv4 + * (thanks to Henrik Gulbrandsen). + * + * v0.2.6 1999/05/04 + * Added wireless spy and histogram support. Signal levels + * are now reported in ad-hoc mode correctly, but you + * need to use iwspy for it, because we can 'hear' more + * than one remote host in ad-hoc mode (thanks + * to Albert K T Hui for the code and to Richard van + * Leeuwen for the technical details). + * Fixed a bug with wrong tx_bytes count. + * Added GPL file wvlan.COPYING. + * + * v0.2.5 1999/03/12 + * Hopefully fixed problems with the Makefile patch. + * Changed the interrupt service routine to do never lock up + * in an endless loop (if this ever would happen...). + * Missed a conditional which made the driver unable to compile + * on 2.0.x kernels (thanks to Glenn D. Golden). + * + * v0.2.4 1999/03/10 + * Tested in ad-hoc mode and with access point (many thanks + * to Frank Bruegmann, who made some hardware available + * to me so that I can now test it myself). + * Change the interrupt service routine to repeat on frame + * reception and deallocate the NICs receiving frame + * buffer correctly (thanks to Glenn D. Golden). + * Fixed a problem with checksums where under some circumstances + * an incorrect packet wasn't recognized. Switched + * on the kernel checksum checking (thanks to Glenn D. Golden). + * Setting the channel value is now checked against valid channel + * values which are read from the card. + * Added private ioctl (iwconfig priv) station_name, network_name + * and current_network. It needs an iwconfig capable of + * setting and gettings strings (thanks to Justin Seger). + * Ioctl (iwconfig) should now return the real current used channel. + * Setting the channel value is now only valid using ad-hoc mode. + * It's useless when using an access points. + * Renamed the ssid parameter to network_name and made it work + * correctly for all port_types. It should work now + * in ad-hoc networks as well as with access points. + * Added entries for the NCR WaveLAN/IEEE and the Cabletron + * RoamAbout 802.11 DS card (thanks to Richard van Leeuwen) + * Support to count the received and transmitted bytes + * if kernel version >2.1.25. + * Changed the reset method in case of Tx-timeouts. + * PM suspend/resume should work now (thanks to Dave Kristol). + * Changed installation and driver package. Read INSTALL in this + * file for information how it works now. + * + * v0.2.3 1999/02/25 + * Added support to set the own SSID + * Changed standard channel setting to 3 so that it works + * with Windows without specifying a channel (the + * Windows driver seem to default to channel 3). + * Fixed two problems with the Ethernet-II frame de/encapsulation. + * + * v0.2.2 1999/02/07 + * First public beta release. + * Added support to get link quality via iwconfig. + * Added support to change channel via iwconfig. + * Added changeable MTU setting (thanks to Tomasz Motylewski). + * Added Ethernet-II frame de/encapsulation, because + * HCF-Light doesn't support it. + * + * v0.2.1 1999/02/03 + * Added channel parameter. + * Rewrote the driver with information made public + * in Lucent's HCF-Light library. The HCF was + * slightly modified to get rid of the compiler + * warnings. The filenames were prefixed with + * wvlan_ to better fit into the pcmcia package. + * + * v0.1d 1998/12/21 + * Fixed a problem where the NIC was crashing during heavy + * loaded transmissions. Interrupts are now disabled + * during wvlan_tx() function. Seems to work fine now. + * + * v0.1c 1998/12/20 + * Driver works fine with ad-hoc network. + * + * v0.1b 1998/12/19 + * First successful send-tests. + * + * v0.1a 1998/12/18 + * First tests with card functions. + */ + +#include +#include +#ifndef KERNEL_VERSION +#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) +#endif + +#ifdef __IN_PCMCIA_PACKAGE__ +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#ifdef MODULE +#ifdef MODVERSIONS +#include +#endif +#include +#else +#define MOD_INC_USE_COUNT +#define MOD_DEC_USE_COUNT +#endif + +#include +/* Note : v6 is included in : 2.0.37+ and 2.2.4+, adds ESSID */ +/* Note : v8 is included in : 2.2.11+ and 2.3.14+, adds frag/rts/rate/nick */ +/* Note : v9 is included in : 2.2.14+ and 2.3.25+, adds mode/ps/wep */ +#if WIRELESS_EXT < 6 +#warning "Wireless extension v8 or newer required - please upgrade your kernel" +#undef WIRELESS_EXT +#endif +#if WIRELESS_EXT < 9 +#warning "Wireless extension v9 or newer prefered - please upgrade your kernel" +#endif +#define WIRELESS_SPY // enable iwspy support +#undef HISTOGRAM // disable histogram of signal levels + +// This is needed for station_name, but we may not compile WIRELESS_EXT +#ifndef IW_ESSID_MAX_SIZE +#define IW_ESSID_MAX_SIZE 32 +#endif /* IW_ESSID_MAX_SIZE */ + +#include "wvlan_hcf.h" + +/* #define PCMCIA_DEBUG 1 // For developer only :-) */ + +// Undefine this if you want to ignore Tx timeouts +// (i.e. card will not be reset on Tx timeouts) +#define WVLAN_RESET_ON_TX_TIMEOUT + + +/******************************************************************** + * DEBUG + */ +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +MODULE_PARM(pc_debug, "i"); +#define DEBUG(n, args...) if (pc_debug>=(n)) printk(KERN_DEBUG args); +#else +#define DEBUG(n, args...) {} +#endif +#define DEBUG_INFO 1 +#define DEBUG_NOISY 2 +#define DEBUG_TXRX 3 +#define DEBUG_CALLTRACE 4 +#define DEBUG_INTERRUPT 5 + +/******************************************************************** + * MISC + */ +static char *version = "1.0.6"; +static dev_info_t dev_info = "wvlan_cs"; +static dev_link_t *dev_list = NULL; + +// Module parameters +static u_int irq_mask = 0xdeb8; // Interrupt mask +static int irq_list[4] = { -1 }; // Interrupt list (alternative) +static int eth = 1; // use ethX devname +static int mtu = 1500; +// Note : the following parameters can be also modified through Wireless +// Extension, and additional parameters are also available this way... +static int port_type = 1; // Port-type [1] +static int allow_ibss = 0; // Allow a IBSS [0] +static char network_name[IW_ESSID_MAX_SIZE+1] = "\0"; // Name of network [] +static int channel = 3; // Channel [3] +MODULE_PARM(irq_mask, "i"); +MODULE_PARM(irq_list, "1-4i"); +MODULE_PARM(eth, "i"); +MODULE_PARM(mtu, "i"); +MODULE_PARM(port_type, "i"); +MODULE_PARM(allow_ibss, "i"); +MODULE_PARM(network_name, "c" __MODULE_STRING(IW_ESSID_MAX_SIZE)); +MODULE_PARM(channel, "i"); +// Backward compatibility - This one is obsolete and will be removed soon +static char station_name[IW_ESSID_MAX_SIZE+1] = "\0"; // Name of station [] +MODULE_PARM(station_name, "c" __MODULE_STRING(IW_ESSID_MAX_SIZE)); + +// Useful macros we have in pcmcia-cs but not in the kernel +#ifndef __IN_PCMCIA_PACKAGE__ +#define DEV_KFREE_SKB(skb) dev_kfree_skb(skb); +#define skb_tx_check(dev, skb) +#define add_rx_bytes(stats, n) (stats)->rx_bytes += n; +#define add_tx_bytes(stats, n) (stats)->tx_bytes += n; +#endif + +// Ethernet timeout is ((400*HZ)/1000), but we should use a higher +// value, because wireless transmissions are much slower +#define TX_TIMEOUT ((4000*HZ)/1000) + +// Ethernet-II snap header +static char snap_header[] = { 0x00, 0x00, 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; + +// Valid MTU values (HCF_MAX_MSG (2304) is the max hardware frame size) +#define WVLAN_MIN_MTU 256 +#define WVLAN_MAX_MTU (HCF_MAX_MSG - sizeof(snap_header)) + +// Max number of multicast addresses that the filter can accept +#define WVLAN_MAX_MULTICAST GROUP_ADDR_SIZE/6 + +// Frequency list (map channels to frequencies) +const long frequency_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, + 2447, 2452, 2457, 2462, 2467, 2472, 2484 }; + +// Bit-rate list in 1/2 Mb/s (first is dummy - not for original turbo) +const int rate_list[] = { 0, 2, 4, -22, 11, 22, -4, -11, 0, 0, 0, 0 }; + +// A few details needed for WEP (Wireless Equivalent Privacy) +#define MAX_KEY_SIZE 13 // 128/104 (?) bits +#define MIN_KEY_SIZE 5 // 40 bits RC4 - WEP +#define MAX_KEYS 4 // 4 different keys + +// Keep track of wvlanX devices +#define MAX_WVLAN_CARDS 16 +static struct net_device *wvlandev_index[MAX_WVLAN_CARDS]; + +// Local data for netdevice +struct net_local { + dev_node_t node; + struct net_device *dev; // backtrack device + dev_link_t *link; // backtrack link + spinlock_t slock; // spinlock + int interrupt; // interrupt + IFB_STRCT ifb; // WaveLAN HCF structure + struct net_device_stats stats; // device stats + u_char promiscuous; // Promiscuous mode + u_char allmulticast; // All multicast mode + int mc_count; // Number of multicast addrs + int need_commit; // Need to set config + /* Capabilities : what the firmware do support */ + int has_port3; // Ad-Hoc demo mode + int has_ibssid; // IBSS Ad-Hoc mode + int has_mwo; // MWO robust support + int has_wep; // Lucent WEP support + int has_pwep; // Prism WEP support + int has_pm; // Power Management support + /* Configuration : what is the current state of the hardware */ + int port_type; // Port-type [1] + int allow_ibss; // Allow a IBSS [0] + char network_name[IW_ESSID_MAX_SIZE+1]; // Name of network [] + int channel; // Channel [3] +#ifdef WIRELESS_EXT + char station_name[IW_ESSID_MAX_SIZE+1]; // Name of station [] + int ap_density; // AP density [1] + int medium_reservation; // RTS threshold [2347] + int frag_threshold; // Frag. threshold [2346] + int mwo_robust; // MWO robustness [0] + int transmit_rate; // Transmit rate [3] + int wep_on; // WEP enabled + int transmit_key; // Key used for transmissions + KEY_STRCT key[MAX_KEYS]; // WEP keys & size + int pm_on; // Power Management enabled + int pm_multi; // Receive multicasts + int pm_period; // Power Management period +#ifdef WIRELESS_SPY + int spy_number; + u_char spy_address[IW_MAX_SPY][MAC_ADDR_SIZE]; + struct iw_quality spy_stat[IW_MAX_SPY]; +#endif +#ifdef HISTOGRAM + int his_number; + u_char his_range[16]; + u_long his_sum[16]; +#endif + struct iw_statistics wstats; // wireless stats +#endif /* WIRELESS_EXT */ +}; + +// Shortcuts +#ifdef WIRELESS_EXT +typedef struct iw_statistics iw_stats; +typedef struct iw_quality iw_qual; +typedef struct iw_freq iw_freq; +#endif /* WIRELESS_EXT */ + +// Show CardServices error message (syslog) +static void cs_error (client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret }; + CardServices(ReportError, handle, &err); +} + + +/******************************************************************** + * FUNCTION PROTOTYPES + */ +static int wvlan_hw_setmaxdatalen (IFBP ifbp, int maxlen); +static int wvlan_hw_getmacaddr (IFBP ifbp, char *mac, int len); +static int wvlan_hw_getchannellist (IFBP ifbp); +static int wvlan_hw_setporttype (IFBP ifbp, int ptype); +static int wvlan_hw_getporttype (IFBP ifbp); +static int wvlan_hw_setallowibssflag (IFBP ifbp, int flag); +static int wvlan_hw_getallowibssflag (IFBP ifbp); +static int wvlan_hw_setstationname (IFBP ifbp, char *name); +static int wvlan_hw_getstationname (IFBP ifbp, char *name, int len); +static int wvlan_hw_setssid (IFBP ifbp, char *name, int ptype); +static int wvlan_hw_getssid (IFBP ifbp, char *name, int len, int cur, int ptype); +static int wvlan_hw_getbssid (IFBP ifbp, char *mac, int len); +static int wvlan_hw_setchannel (IFBP ifbp, int channel); +static int wvlan_hw_getcurrentchannel (IFBP ifbp); +static int wvlan_hw_setthreshold (IFBP ifbp, int thrh, int cmd); +static int wvlan_hw_getthreshold (IFBP ifbp, int cmd); +static int wvlan_hw_getbitrate (IFBP ifbp, int cur); +static int wvlan_hw_getratelist (IFBP ifbp, char *brlist, int len); +#ifdef WIRELESS_EXT +static int wvlan_hw_getfrequencylist (IFBP ifbp, iw_freq *list, int max); +static int wvlan_getbitratelist (IFBP ifbp, __s32 *list, int max); +static int wvlan_hw_setpower (IFBP ifbp, int enabled, int cmd); +static int wvlan_hw_getpower (IFBP ifbp, int cmd); +static int wvlan_hw_setpmsleep (IFBP ifbp, int duration); +static int wvlan_hw_getpmsleep (IFBP ifbp); +static int wvlan_hw_getprivacy (IFBP ifbp); +static int wvlan_hw_setprivacy (IFBP ifbp, int mode, int transmit, KEY_STRCT *keys); +#endif /* WIRELESS_EXT */ +static int wvlan_hw_setpromisc (IFBP ifbp, int promisc); +static int wvlan_hw_getfirmware (IFBP ifbp, int *first, int *major, int *minor); + +static int wvlan_hw_config (struct net_device *dev); +static int wvlan_hw_shutdown (struct net_device *dev); +#ifdef PCMCIA_DEBUG +static int wvlan_hw_reset (struct net_device *dev); +#endif +struct net_device_stats *wvlan_get_stats (struct net_device *dev); +#ifdef WIRELESS_EXT +int wvlan_ioctl (struct net_device *dev, struct ifreq *rq, int cmd); +struct iw_statistics *wvlan_get_wireless_stats (struct net_device *dev); +#ifdef WIRELESS_SPY +static inline void wvlan_spy_gather (struct net_device *dev, u_char *mac, u_char *stats); +#endif +#ifdef HISTOGRAM +static inline void wvlan_his_gather (struct net_device *dev, u_char *stats); +#endif +#endif /* WIRELESS_EXT */ +int wvlan_change_mtu (struct net_device *dev, int new_mtu); +static void wvlan_set_multicast_list (struct net_device *dev); + +static void wvlan_watchdog (struct net_device *dev); +int wvlan_tx (struct sk_buff *skb, struct net_device *dev); +void wvlan_rx (struct net_device *dev, int len); + +static int wvlan_open (struct net_device *dev); +static int wvlan_close (struct net_device *dev); + +static void wvlan_interrupt (int irq, void *dev_id, struct pt_regs *regs); + +static int wvlan_config (dev_link_t *link); +static void wvlan_release (u_long arg); + +static dev_link_t *wvlan_attach (void); +static void wvlan_detach (dev_link_t *link); + +static int wvlan_event (event_t event, int priority, event_callback_args_t *args); + +extern int init_wvlan_cs (void); +extern void exit_wvlan_cs (void); + + +/********************** SPIN LOCK SUBROUTINES **********************/ +/* + * These 2 routines help to see what's happening with spinlock. + * They are inline, so optimised away ;-) + */ + +/*------------------------------------------------------------------*/ +/* + * Wrapper for disabling interrupts. Useful for debugging ;-) + * (note : inline, so optimised away) + */ +static inline void +wv_driver_lock(struct net_local * local, + unsigned long * pflags) +{ + /* Disable interrupts and aquire the lock */ + spin_lock_irqsave(&local->slock, *pflags); +} + +/*------------------------------------------------------------------*/ +/* + * Wrapper for re-enabling interrupts. + */ +static inline void +wv_driver_unlock(struct net_local * local, + unsigned long * pflags) +{ + /* Release the lock and reenable interrupts */ + spin_unlock_irqrestore(&local->slock, *pflags); +} + +/******************************************************************** + * HARDWARE SETTINGS + */ +/* Note : most function below are called once in the code, so I added + * the "inline" modifier. If a function is used more than once, please + * remove the "inline"... + * Jean II */ +// Stupid constants helping clarity +#define WVLAN_CURRENT 1 +#define WVLAN_DESIRED 0 + +static inline int wvlan_hw_setmaxdatalen (IFBP ifbp, int maxlen) +{ + CFG_ID_STRCT ltv; + int rc; + + ltv.len = 2; + ltv.typ = CFG_CNF_MAX_DATA_LEN; + ltv.id[0] = cpu_to_le16(maxlen); + rc = hcf_put_info(ifbp, (LTVP) <v); + DEBUG(DEBUG_NOISY, "%s: hcf_put_info(CFG_CNF_MAX_DATA_LEN:0x%x) returned 0x%x\n", dev_info, maxlen, rc); + return rc; +} + +static inline int wvlan_hw_getmacaddr (IFBP ifbp, char *mac, int len) +{ + CFG_MAC_ADDR_STRCT ltv; + int rc, l; + + ltv.len = 4; + ltv.typ = CFG_CNF_OWN_MAC_ADDR; + rc = hcf_get_info(ifbp, (LTVP) <v); + DEBUG(DEBUG_NOISY, "%s: hcf_get_info(CFG_CNF_OWN_MAC_ADDR) returned 0x%x\n", dev_info, rc); + if (rc) + return rc; + l = min(len, ltv.len*2); + memcpy(mac, (char *)ltv.mac_addr, l); + return 0; +} + +static int wvlan_hw_getchannellist (IFBP ifbp) +{ + CFG_ID_STRCT ltv; + int rc, chlist; + + ltv.len = 2; + ltv.typ = CFG_CHANNEL_LIST; + rc = hcf_get_info(ifbp, (LTVP) <v); + chlist = le16_to_cpup(<v.id[0]); + DEBUG(DEBUG_NOISY, "%s: hcf_get_info(CFG_CHANNEL_LIST):0x%x returned 0x%x\n", dev_info, chlist, rc); + return rc ? 0 : chlist; +} + +static inline int wvlan_hw_setporttype (IFBP ifbp, int ptype) +{ + CFG_ID_STRCT ltv; + int rc; + + ltv.len = 2; + ltv.typ = CFG_CNF_PORT_TYPE; + ltv.id[0] = cpu_to_le16(ptype); + rc = hcf_put_info(ifbp, (LTVP) <v); + DEBUG(DEBUG_NOISY, "%s: hcf_put_info(CFG_CNF_PORT_TYPE:0x%x) returned 0x%x\n", dev_info, ptype, rc); + return rc; +} + +static inline int wvlan_hw_getporttype (IFBP ifbp) +{ + CFG_ID_STRCT ltv; + int rc, ptype; + + ltv.len = 2; + ltv.typ = CFG_CNF_PORT_TYPE; + rc = hcf_get_info(ifbp, (LTVP) <v); + ptype = le16_to_cpup(<v.id[0]); + DEBUG(DEBUG_NOISY, "%s: hcf_get_info(CFG_CNF_PORT_TYPE):0x%x returned 0x%x\n", dev_info, ptype, rc); + return rc ? 0 : ptype; +} + +static inline int wvlan_hw_setallowibssflag (IFBP ifbp, int flag) +{ + CFG_ID_STRCT ltv; + int rc; + + ltv.len = 2; + ltv.typ = CFG_CREATE_IBSS; + ltv.id[0] = cpu_to_le16(flag); + rc = hcf_put_info(ifbp, (LTVP) <v); + DEBUG(DEBUG_NOISY, "%s: hcf_put_info(CFG_CREATE_IBSS:0x%x) returned 0x%x\n", dev_info, flag, rc); + return rc; +} + +static inline int wvlan_hw_getallowibssflag (IFBP ifbp) +{ + CFG_ID_STRCT ltv; + int rc, flag; + + ltv.len = 2; + ltv.typ = CFG_CREATE_IBSS; + rc = hcf_get_info(ifbp, (LTVP) <v); + flag = le16_to_cpup(<v.id[0]); + DEBUG(DEBUG_NOISY, "%s: hcf_get_info(CFG_CREATE_IBSS):0x%x returned 0x%x\n", dev_info, flag, rc); + return rc ? 0 : flag; +} + +static inline int wvlan_hw_setstationname (IFBP ifbp, char *name) +{ + CFG_ID_STRCT ltv; + int rc, l; + + ltv.len = 18; + ltv.typ = CFG_CNF_OWN_NAME; + l = min(strlen(name), ltv.len*2); + ltv.id[0] = cpu_to_le16(l); + memcpy((char *) <v.id[1], name, l); + rc = hcf_put_info(ifbp, (LTVP) <v); + DEBUG(DEBUG_NOISY, "%s: hcf_put_info(CFG_CNF_OWN_NAME:'%s') returned 0x%x\n", dev_info, name, rc); + return rc; +} + +static inline int wvlan_hw_getstationname (IFBP ifbp, char *name, int len) +{ + CFG_ID_STRCT ltv; + int rc, l; + + ltv.len = 18; + ltv.typ = CFG_CNF_OWN_NAME; + rc = hcf_get_info(ifbp, (LTVP) <v); + DEBUG(DEBUG_NOISY, "%s: hcf_get_info(CFG_CNF_OWN_NAME) returned 0x%x\n", dev_info, rc); + if (rc) + return rc; + l = le16_to_cpup(<v.id[0]); + if (l) + l = min(len, l); + else + l = min(len, ltv.len*2); /* It's a feature */ + memcpy(name, (char *) <v.id[1], l); + name[l] = 0; + DEBUG(DEBUG_NOISY, "%s: hcf_get_info(CFG_CNF_OWN_NAME):'%s'\n", dev_info, name); + return 0; +} + +static inline int wvlan_hw_setssid (IFBP ifbp, char *name, int ptype) +{ + CFG_ID_STRCT ltv; + int rc, l; + + ltv.len = 18; + if (ptype == 3) + ltv.typ = CFG_CNF_OWN_SSID; + else + ltv.typ = CFG_CNF_DESIRED_SSID; + l = min(strlen(name), ltv.len*2); + ltv.id[0] = cpu_to_le16(l); + memcpy((char *) <v.id[1], name, l); + rc = hcf_put_info(ifbp, (LTVP) <v); + DEBUG(DEBUG_NOISY, "%s: hcf_put_info(CFG_CNF_OWN/DESIRED_SSID:'%s') returned 0x%x\n", dev_info, name, rc); + return rc; +} + +static int wvlan_hw_getssid (IFBP ifbp, char *name, int len, int cur, int ptype) +{ + CFG_ID_STRCT ltv; + int rc, l; + + ltv.len = 18; + if (cur) + ltv.typ = CFG_CURRENT_SSID; + else + if (ptype == 3) + ltv.typ = CFG_CNF_OWN_SSID; + else + ltv.typ = CFG_CNF_DESIRED_SSID; + rc = hcf_get_info(ifbp, (LTVP) <v); + DEBUG(DEBUG_NOISY, "%s: hcf_get_info(CFG_CNF_OWN/DESIRED/CURRENT_SSID) returned 0x%x\n", dev_info, rc); + if (rc) + return rc; + l = le16_to_cpup(<v.id[0]); + if (l) + { + l = min(len, l); + memcpy(name, (char *) <v.id[1], l); + } + name[l] = '\0'; + DEBUG(DEBUG_NOISY, "%s: hcf_get_info(CFG_CNF_OWN/DESIRED/CURRENT_SSID):'%s'\n", dev_info, name); + return 0; +} + +static inline int wvlan_hw_getbssid (IFBP ifbp, char *mac, int len) +{ + CFG_MAC_ADDR_STRCT ltv; + int rc, l; + + ltv.len = 4; + ltv.typ = CFG_CURRENT_BSSID; + rc = hcf_get_info(ifbp, (LTVP) <v); + DEBUG(DEBUG_NOISY, "%s: hcf_get_info(CFG_CURRENT_BSSID) returned 0x%x\n", dev_info, rc); + if (rc) + return rc; + l = min(len, ltv.len*2); + memcpy(mac, (char *)ltv.mac_addr, l); + return 0; +} + +static inline int wvlan_hw_setchannel (IFBP ifbp, int channel) +{ + CFG_ID_STRCT ltv; + int rc; + + ltv.len = 2; + ltv.typ = CFG_CNF_OWN_CHANNEL; + ltv.id[0] = cpu_to_le16(channel); + rc = hcf_put_info(ifbp, (LTVP) <v); + DEBUG(DEBUG_NOISY, "%s: hcf_put_info(CFG_CNF_OWN_CHANNEL:0x%x) returned 0x%x\n", dev_info, channel, rc); + return rc; +} + +static int wvlan_hw_getcurrentchannel (IFBP ifbp) +{ + CFG_ID_STRCT ltv; + int rc, channel; + + ltv.len = 2; + ltv.typ = CFG_CURRENT_CHANNEL; + rc = hcf_get_info(ifbp, (LTVP) <v); + channel = le16_to_cpup(<v.id[0]); + DEBUG(DEBUG_NOISY, "%s: hcf_get_info(CFG_CURRENT_CHANNEL):0x%x returned 0x%x\n", dev_info, channel, rc); + return rc ? 0 : channel; +} + +static int wvlan_hw_setthreshold (IFBP ifbp, int thrh, int cmd) +{ + CFG_ID_STRCT ltv; + int rc; + + ltv.len = 2; + ltv.typ = cmd; + ltv.id[0] = cpu_to_le16(thrh); + rc = hcf_put_info(ifbp, (LTVP) <v); + DEBUG(DEBUG_NOISY, "%s: hcf_put_info(0x%x:0x%x) returned 0x%x\n", dev_info, cmd, thrh, rc); + return rc; +} + +static int wvlan_hw_getthreshold (IFBP ifbp, int cmd) +{ + CFG_ID_STRCT ltv; + int rc, thrh; + + ltv.len = 2; + ltv.typ = cmd; + rc = hcf_get_info(ifbp, (LTVP) <v); + thrh = le16_to_cpup(<v.id[0]); + DEBUG(DEBUG_NOISY, "%s: hcf_get_info(0x%x):0x%x returned 0x%x\n", dev_info, cmd, thrh, rc); + return rc ? 0 : thrh; +} + +static int wvlan_hw_getbitrate (IFBP ifbp, int cur) +{ + CFG_ID_STRCT ltv; + int rc, brate; + + ltv.len = 2; + ltv.typ = cur ? CFG_CURRENT_TX_RATE : CFG_TX_RATE_CONTROL; + rc = hcf_get_info(ifbp, (LTVP) <v); + brate = le16_to_cpup(<v.id[0]); + DEBUG(DEBUG_NOISY, "%s: hcf_get_info(CFG_TX_RATE_CONTROL):0x%x returned 0x%x\n", dev_info, brate, rc); + return rc ? 0 : brate; +} + +static int wvlan_hw_getratelist(IFBP ifbp, char *brlist, int brmaxlen) +{ + CFG_ID_STRCT ltv; + int rc, brnum; + + ltv.len = 10; + ltv.typ = CFG_SUPPORTED_DATA_RATES; + rc = hcf_get_info(ifbp, (LTVP) <v); + brnum = le16_to_cpup(<v.id[0]); + if (brnum > brmaxlen) + brnum = brmaxlen; + memcpy(brlist, (char *) <v.id[1], brnum); + DEBUG(DEBUG_NOISY, "%s: hcf_get_info(CFG_CHANNEL_LIST):0x%x returned 0x%x\n", dev_info, brnum, rc); + return rc ? 0 : brnum; +} + +#ifdef WIRELESS_EXT +static inline int wvlan_hw_getfrequencylist(IFBP ifbp, iw_freq *list, int max) +{ + int chlist = wvlan_hw_getchannellist(ifbp); + int i, k = 0; + + /* Compute maximum number of freq to scan */ + if(max > 15) + max = 15; + + /* Check availability */ + for(i = 0; i < max; i++) + if((1 << i) & chlist) + { +#if WIRELESS_EXT > 7 + list[k].i = i + 1; /* Set the list index */ +#endif /* WIRELESS_EXT */ + list[k].m = frequency_list[i] * 100000; + list[k++].e = 1; /* Values in table in MHz -> * 10^5 * 10 */ + } + + return k; +} + +static inline int wvlan_getbitratelist(IFBP ifbp, __s32 *list, int max) +{ + char brlist[9]; + int brnum = wvlan_hw_getratelist(ifbp, brlist, sizeof(brlist)); + int i; + + /* Compute maximum number of freq to scan */ + if(brnum > max) + brnum = max; + + /* Convert to Mb/s */ + for(i = 0; i < max; i++) + list[i] = (brlist[i] & 0x7F) * 500000; + + return brnum; +} + +static int wvlan_hw_setpower (IFBP ifbp, int enabled, int cmd) +{ + CFG_ID_STRCT ltv; + int rc; + + ltv.len = 2; + ltv.typ = cmd; + ltv.id[0] = cpu_to_le16(enabled); + rc = hcf_put_info(ifbp, (LTVP) <v); + DEBUG(DEBUG_NOISY, "%s: hcf_put_info(0x%x:0x%x) returned 0x%x\n", dev_info, cmd, enabled, rc); + return rc; +} + +static int wvlan_hw_getpower (IFBP ifbp, int cmd) +{ + CFG_ID_STRCT ltv; + int rc, enabled; + + ltv.len = 2; + ltv.typ = cmd; + rc = hcf_get_info(ifbp, (LTVP) <v); + enabled = le16_to_cpup(<v.id[0]); + DEBUG(DEBUG_NOISY, "%s: hcf_get_info(0x%x):0x%x returned 0x%x\n", dev_info, cmd, enabled, rc); + return rc ? 0 : enabled; +} + +static inline int wvlan_hw_setpmsleep (IFBP ifbp, int duration) +{ + CFG_ID_STRCT ltv; + int rc; + + ltv.len = 2; + ltv.typ = CFG_CNF_MAX_SLEEP_DURATION; + ltv.id[0] = cpu_to_le16(duration); + rc = hcf_put_info(ifbp, (LTVP) <v); + DEBUG(DEBUG_NOISY, "%s: hcf_put_info(CNF_MAX_SLEEP_DURATION:0x%x) returned 0x%x\n", dev_info, duration, rc); + return rc; +} + +static inline int wvlan_hw_getpmsleep (IFBP ifbp) +{ + CFG_ID_STRCT ltv; + int rc, duration; + + ltv.len = 2; + ltv.typ = CFG_CNF_MAX_SLEEP_DURATION; + rc = hcf_get_info(ifbp, (LTVP) <v); + duration = le16_to_cpup(<v.id[0]); + DEBUG(DEBUG_NOISY, "%s: hcf_get_info(CNF_MAX_SLEEP_DURATION):0x%x returned 0x%x\n", dev_info, duration, rc); + return rc ? 0 : duration; +} + +static int wvlan_hw_getprivacy (IFBP ifbp) +{ + CFG_ID_STRCT ltv; + int rc, privacy; + + // This function allow to distiguish bronze cards from other + // types, to know if WEP exist... + // This is stupid, we have no way to distinguish the silver + // and gold cards, because the call below return 1 in all + // cases. Yuk... + ltv.len = 2; + ltv.typ = CFG_PRIVACY_OPTION_IMPLEMENTED; + rc = hcf_get_info(ifbp, (LTVP) <v); + privacy = le16_to_cpup(<v.id[0]); + DEBUG(DEBUG_NOISY, "%s: hcf_get_info(CFG_PRIVACY_OPTION_IMPLEMENTED):0x%x returned 0x%x\n", dev_info, privacy, rc); + return rc ? 0 : privacy; +} + +static int wvlan_hw_setprivacy (IFBP ifbp, int mode, int transmit, KEY_STRCT *keys) +{ + CFG_ID_STRCT ltv; + CFG_CNF_DEFAULT_KEYS_STRCT ltv_key; + int rc; + int i; + + if (mode) + { + // Set the index of the key used for transmission + ltv.len = 2; + ltv.typ = CFG_CNF_TX_KEY_ID; + ltv.id[0] = cpu_to_le16(transmit); + rc = hcf_put_info(ifbp, (LTVP) <v); + DEBUG(DEBUG_NOISY, "%s: hcf_put_info(CFG_CNF_TX_KEY_ID:0x%x) returned 0x%x\n", dev_info, mode, rc); + if (rc) + return rc; + + // Set the keys themselves (all in on go !) + ltv_key.len = sizeof(KEY_STRCT)*MAX_KEYS/2 + 1; + ltv_key.typ = CFG_CNF_DEFAULT_KEYS; + memcpy((char *) <v_key.key, (char *) keys, sizeof(KEY_STRCT)*MAX_KEYS); + for (i = 0; i < MAX_KEYS; ++i) + cpu_to_le16s(<v_key.key[i].len); + rc = hcf_put_info(ifbp, (LTVP) <v_key); + DEBUG(DEBUG_NOISY, "%s: hcf_put_info(CFG_CNF_TX_KEY_ID:0x%x) returned 0x%x\n", dev_info, mode, rc); + if (rc) + return rc; + } + // enable/disable encryption + ltv.len = 2; + ltv.typ = CFG_CNF_ENCRYPTION; + ltv.id[0] = cpu_to_le16(mode); + rc = hcf_put_info(ifbp, (LTVP) <v); + DEBUG(DEBUG_NOISY, "%s: hcf_put_info(CFG_CNF_ENCRYPTION:0x%x) returned 0x%x\n", dev_info, mode, rc); + return rc; +} +#endif /* WIRELESS_EXT */ + +static int wvlan_hw_setpromisc (IFBP ifbp, int promisc) +{ + CFG_ID_STRCT ltv; + int rc; + + ltv.len = 2; + ltv.typ = CFG_PROMISCUOUS_MODE; + ltv.id[0] = cpu_to_le16(promisc); + rc = hcf_put_info(ifbp, (LTVP) <v); + DEBUG(DEBUG_NOISY, "%s: hcf_put_info(CFG_PROMISCUOUS_MODE:0x%x) returned 0x%x\n", dev_info, promisc, rc); + return rc; +} + +static inline int wvlan_hw_getfirmware (IFBP ifbp, int *vendor, int *major, int *minor) +{ + CFG_ID_STRCT ltv; + int rc; + + ltv.len = 32; + ltv.typ = CFG_STA_IDENTITY; + rc = hcf_get_info(ifbp, (LTVP) <v); + DEBUG(DEBUG_NOISY, "%s: hcf_get_info(CFG_STA_IDENTITY) returned 0x%x\n", dev_info, rc); + if (rc) + return rc; + + /* Get the data we need (note : 16 bits operations) */ + *vendor = le16_to_cpup(<v.id[1]); + *major = le16_to_cpup(<v.id[2]); + *minor = le16_to_cpup(<v.id[3]); + /* There is more data after that, but I can't guess its use */ + + DEBUG(DEBUG_NOISY, "%s: hcf_get_info(CFG_STA_IDENTITY):%d-%d.%d\n", dev_info, *vendor, *major, *minor); + + return 0; +} + + +/******************************************************************** + * HARDWARE CONFIG / SHUTDOWN / RESET + */ + +/*------------------------------------------------------------------*/ +/* + * Hardware configuration of the Wavelan + * The caller *must* disable IRQs by himself before comming here. + */ +static int wvlan_hw_config (struct net_device *dev) +{ + struct net_local *local = (struct net_local *) dev->priv; + int rc, i, chlist; + int vendor, major, minor; /* Firmware revision */ + int firmware; + + DEBUG(DEBUG_CALLTRACE, "-> wvlan_hw_config(%s)\n", dev->name); + + // Init the HCF library + hcf_connect(&local->ifb, dev->base_addr); + + // Init hardware and turn on interrupts + rc = hcf_action(&local->ifb, HCF_ACT_CARD_IN); + DEBUG(DEBUG_NOISY, "%s: hcf_action(HCF_ACT_CARD_IN) returned 0x%x\n", dev_info, rc); +#if defined(PCMCIA_DEBUG) && (PCMCIA_DEBUG>=DEBUG_INTERRUPT) + local->ifb.IFB_IntEnMask |= HREG_EV_TICK; +#endif + rc = hcf_action(&local->ifb, HCF_ACT_INT_ON); + DEBUG(DEBUG_NOISY, "%s: hcf_action(HCF_ACT_INT_ON) returned 0x%x\n", dev_info, rc); + + /* Get MAC address (before we get a chance to fail) */ + if (!rc) { + rc = wvlan_hw_getmacaddr(&local->ifb, dev->dev_addr, ETH_ALEN); + printk(KERN_INFO "%s: MAC address on %s is ", dev_info, dev->name); + for (i=0; idev_addr[i]); + printk("\n"); + } + + /* Get firmware revision of the card */ + if (!rc) + rc = wvlan_hw_getfirmware(&local->ifb, &vendor, &major, &minor); + + /* Process firmware info to know what it supports */ + firmware = (major << 16) + minor; + if(!rc) { + switch(vendor) { + case 0x1: + /* This is a Lucent card : Wavelan IEEE, Orinoco, + * Cabletron/Enterasys Roamabout or ELSA cards. + * This is what we mainly support... + * Note : this will work at least for Lucent + * firmwares */ + local->has_port3 = (firmware <= 0x60006); + local->has_ibssid = (firmware >= 0x60006); + local->has_mwo = (firmware >= 0x60000); + local->has_wep = (firmware >= 0x40020); + local->has_pwep = 0; + local->has_pm = (firmware >= 0x40020); + /* Note : I've tested the following firmwares : + * 1.16 ; 4.08 ; 4.52 ; 6.04 and 6.06 + * Jean II */ + /* Tested CableTron 4.32 - Anton */ + break; + case 0x6: + /* This is a LinkSys/D-Link card. This is not a Lucent + * card, but a PrismII card. It is is *very* similar + * to the Lucent, and the the driver work 95%, + * therefore, we attempt to support it... */ + printk(KERN_NOTICE "%s: This is LinkSys/D-Link card, not a Wavelan IEEE card :-( +You may want report firmare revision (0x%X) and what the card support. +I will try to make it work, but you should look for a better driver.\n", dev_info, firmware); + local->has_port3 = 1; + local->has_ibssid = 0; + local->has_mwo = 0; + local->has_wep = 0; + local->has_pwep = 1; + local->has_pm = 1; + /* Would need to reverse engineer encryption support, + * somebody with a card should do that... */ + /* Transmit rate also seem to be different. */ + /* Note : currently untested... Jean II */ + break; + default: + printk(KERN_NOTICE "%s: Unrecognised card, card return vendor = 0x%04X, please report...\n", dev_info, vendor); + break; + } + } + + DEBUG(DEBUG_INFO, "%s: Found firmware 0x%X (%d) - Firmware capabilities : %d-%d-%d-%d-%d\n", + dev_info, firmware, first, local->has_port3, local->has_ibssid, + local->has_mwo, local->has_wep, local->has_pm); + + if(!rc) { + /* Check for a few user mistakes... Cut down on support ;-) */ + if((!local->has_port3) && (local->port_type == 3)) { + printk(KERN_NOTICE "%s: This firmware doesn't support ``port_type=3'', please use iwconfig.\n", dev_info); + rc = 255; + } + if((!local->has_ibssid) && (local->allow_ibss)) { + printk(KERN_NOTICE "%s: This firmware doesn't support ``allow_ibss=1'', please update it.\n", dev_info); + rc = 255; + } + if((local->allow_ibss) && (local->network_name[0] == '\0')) { + printk(KERN_NOTICE "%s: This firmware require an ESSID in Ad-Hoc mode, please use iwconfig.\n", dev_info); + rc = 255; + } + if((local->has_ibssid) && (local->port_type == 3)) { + printk(KERN_NOTICE "%s: Warning, you are using the old proprietary Ad-Hoc mode (not the IBSS Ad-Hoc mode).\n", dev_info); + } + } + + // Set hardware parameters + if (!rc) + rc = wvlan_hw_setmaxdatalen(&local->ifb, HCF_MAX_MSG); + if (!rc) + rc = wvlan_hw_setporttype(&local->ifb, local->port_type); + if (!rc && *(local->network_name)) + rc = wvlan_hw_setssid(&local->ifb, local->network_name, + local->port_type); + /* Firmware 4.08 doesn't like that at all :-( */ + if (!rc && (local->has_ibssid)) + rc = wvlan_hw_setallowibssflag(&local->ifb, local->allow_ibss); + +#ifdef WIRELESS_EXT + // Set other hardware parameters + if (!rc && *(local->station_name)) + rc = wvlan_hw_setstationname(&local->ifb, local->station_name); + if (!rc) + rc = wvlan_hw_setthreshold(&local->ifb, local->ap_density, CFG_CNF_SYSTEM_SCALE); + if (!rc) + rc = wvlan_hw_setthreshold(&local->ifb, local->transmit_rate, CFG_TX_RATE_CONTROL); + if (!rc) + rc = wvlan_hw_setthreshold(&local->ifb, local->medium_reservation, CFG_RTS_THRH); + /* Normal fragmentation for v4 and earlier */ + if (!rc && (!local->has_mwo)) + rc = wvlan_hw_setthreshold(&local->ifb, local->frag_threshold, CFG_FRAGMENTATION_THRH); + /* MWO robustness for v6 and later */ + if (!rc && (local->has_mwo)) + rc = wvlan_hw_setthreshold(&local->ifb, local->mwo_robust, CFG_CNF_MICRO_WAVE); + /* Firmware 4.08 doesn't like those at all :-( */ + if (!rc && (local->has_wep)) + rc = wvlan_hw_setprivacy(&local->ifb, local->wep_on, local->transmit_key, local->key); + if (!rc && (local->has_pm)) + rc = wvlan_hw_setpower(&local->ifb, local->pm_on, CFG_CNF_PM_ENABLED); + if (!rc && (local->has_pm) && (local->pm_on)) + rc = wvlan_hw_setpower(&local->ifb, local->pm_multi, CFG_CNF_MCAST_RX); + if (!rc && (local->has_pm) && (local->pm_on)) + rc = wvlan_hw_setpmsleep(&local->ifb, local->pm_period); +#endif /* WIRELESS_EXT */ + + // Check valid channel settings + if (!rc && ((local->port_type == 3) || (local->allow_ibss))) { + chlist = wvlan_hw_getchannellist(&local->ifb); + printk(KERN_INFO "%s: Valid channels: ", dev_info); + for (i=1; i<17; i++) + if (1<<(i-1) & chlist) + printk("%d ", i); + printk("\n"); + if (local->channel < 1 || local->channel > 16 + || !(1 << (local->channel - 1) & chlist)) + printk(KERN_WARNING "%s: Channel value of %d is invalid!\n", dev_info, local->channel); + else + rc = wvlan_hw_setchannel(&local->ifb, local->channel); + } + + // Enable hardware + if (!rc) + { + rc = hcf_enable(&local->ifb, 0); + DEBUG(DEBUG_NOISY, "%s: hcf_enable(0) returned 0x%x\n", dev_info, rc); + } + + // Report error if any + if (rc) + printk(KERN_WARNING "%s: Initialization failed!\n", dev_info); + + DEBUG(DEBUG_CALLTRACE, "<- wvlan_hw_config()\n"); + return rc; +} + +/*------------------------------------------------------------------*/ +/* + * Wrapper for calling wvlan_hw_config() with irq disabled + */ +static inline int wvlan_hw_config_locked (struct net_device *dev) +{ + struct net_local *local = (struct net_local *) dev->priv; + unsigned long flags; + int ret; + + wv_driver_lock(local, &flags); + ret = wvlan_hw_config(dev); + wv_driver_unlock(local, &flags); + + return ret; +} + +/*------------------------------------------------------------------*/ +/* + * Hardware de-configuration of the Wavelan (switch off the device) + * The caller *must* disable IRQs by himself before comming here. + */ +static int wvlan_hw_shutdown (struct net_device *dev) +{ + struct net_local *local = (struct net_local *) dev->priv; + int rc; + + DEBUG(DEBUG_CALLTRACE, "-> wvlan_hw_shutdown(%s)\n", dev->name); + + // Disable and shutdown hardware + rc = hcf_disable(&local->ifb, 0); + DEBUG(DEBUG_NOISY, "%s: hcf_disable(0) returned 0x%x\n", dev_info, rc); + rc = hcf_action(&local->ifb, HCF_ACT_INT_OFF); + DEBUG(DEBUG_NOISY, "%s: hcf_action(HCF_ACT_INT_OFF) returned 0x%x\n", dev_info, rc); + rc = hcf_action(&local->ifb, HCF_ACT_CARD_OUT); + DEBUG(DEBUG_NOISY, "%s: hcf_action(HCF_ACT_CARD_OUT) returned 0x%x\n", dev_info, rc); + + // Release HCF library + hcf_disconnect(&local->ifb); + + DEBUG(DEBUG_CALLTRACE, "<- wvlan_hw_shutdown()\n"); + return 0; +} + +#ifdef PCMCIA_DEBUG +/*------------------------------------------------------------------*/ +/* + * "light" hardware reset of the Wavelan + * The caller *must* disable IRQs by himself before comming here. + */ +static int wvlan_hw_reset (struct net_device *dev) +{ + struct net_local *local = (struct net_local *) dev->priv; + int rc; + + DEBUG(DEBUG_CALLTRACE, "-> wvlan_hw_reset(%s)\n", dev->name); + + // Disable hardware + rc = hcf_disable(&local->ifb, 0); + DEBUG(DEBUG_NOISY, "%s: hcf_disable(0) returned 0x%x\n", dev_info, rc); + rc = hcf_action(&local->ifb, HCF_ACT_INT_OFF); + DEBUG(DEBUG_NOISY, "%s: hcf_action(HCF_ACT_INT_OFF) returned 0x%x\n", dev_info, rc); + + // Re-Enable hardware + rc = hcf_action(&local->ifb, HCF_ACT_INT_ON); + DEBUG(DEBUG_NOISY, "%s: hcf_action(HCF_ACT_INT_ON) returned 0x%x\n", dev_info, rc); + rc = hcf_enable(&local->ifb, 0); + DEBUG(DEBUG_NOISY, "%s: hcf_enable(0) returned 0x%x\n", dev_info, rc); + + DEBUG(DEBUG_CALLTRACE, "<- wvlan_hw_reset()\n"); + return rc; +} +#endif + +/******************************************************************** + * NET STATS / IOCTL + */ +struct net_device_stats *wvlan_get_stats (struct net_device *dev) +{ + DEBUG(DEBUG_CALLTRACE, "<> wvlan_get_stats(%s)\n", dev->name); + return(&((struct net_local *) dev->priv)->stats); +} + +#ifdef WIRELESS_EXT +int wvlan_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct net_local *local = (struct net_local *) dev->priv; + struct iwreq *wrq = (struct iwreq *) rq; + unsigned long flags; + int rc = 0; + + DEBUG(DEBUG_CALLTRACE, "-> wvlan_ioctl(%s, cmd=0x%x)\n", dev->name, cmd); + + // Disable interrupts + wv_driver_lock(local, &flags); + + switch (cmd) + { + // Get name + case SIOCGIWNAME: + strcpy(wrq->u.name, "IEEE 802.11-DS"); + break; + + // Set frequency/channel + case SIOCSIWFREQ: + // If setting by frequency, convert to a channel + if((wrq->u.freq.e == 1) && + (wrq->u.freq.m >= (int) 2.412e8) && + (wrq->u.freq.m <= (int) 2.487e8)) + { + int f = wrq->u.freq.m / 100000; + int c = 0; + while((c < 14) && (f != frequency_list[c])) + c++; + // Hack to fall through... + wrq->u.freq.e = 0; + wrq->u.freq.m = c + 1; + } + // Setting by channel number + if (((local->port_type != 3) && (!local->allow_ibss)) + || (wrq->u.freq.m > 1000) || (wrq->u.freq.e > 0)) + rc = -EOPNOTSUPP; + else + { + int channel = wrq->u.freq.m; + int chlist = wvlan_hw_getchannellist(&local->ifb); + if (channel<1 || channel>16 || !(1<<(channel-1) & chlist)) + { + DEBUG(DEBUG_INFO, "%s: New channel value of %d for %s is invalid!\n", dev_info, wrq->u.freq.m, dev->name); + rc = -EINVAL; + } + else + { + local->channel = wrq->u.freq.m; + local->need_commit = 1; + } + } + break; + + // Get frequency/channel + case SIOCGIWFREQ: +#ifdef WEXT_USECHANNELS + wrq->u.freq.m = wvlan_hw_getcurrentchannel(&local->ifb); + wrq->u.freq.e = 0; +#else + { + int f = wvlan_hw_getcurrentchannel(&local->ifb); + wrq->u.freq.m = frequency_list[f-1] * 100000; + wrq->u.freq.e = 1; + } +#endif + break; + + // Set desired network name (ESSID) + case SIOCSIWESSID: + if (wrq->u.data.pointer) + { + char essid[IW_ESSID_MAX_SIZE + 1]; + + /* Check if we asked for `any' */ + if(wrq->u.data.flags == 0) + { + essid[0] = '\0'; + } + else + { + /* Check the size of the string */ + if(wrq->u.data.length > + IW_ESSID_MAX_SIZE + 1) + { + rc = -E2BIG; + break; + } + wv_driver_unlock(local, &flags); + copy_from_user(essid, + wrq->u.data.pointer, + wrq->u.data.length); + wv_driver_lock(local, &flags); + essid[IW_ESSID_MAX_SIZE] = '\0'; + } + strncpy(local->network_name, essid, sizeof(local->network_name)-1); + local->need_commit = 1; + } + break; + + // Get current network name (ESSID) + case SIOCGIWESSID: + if (wrq->u.data.pointer) + { + char essid[IW_ESSID_MAX_SIZE + 1]; + /* Get the essid that was set */ + wvlan_hw_getssid(&local->ifb, essid, + IW_ESSID_MAX_SIZE, + WVLAN_DESIRED, + local->port_type); + /* If it was set to any, get the current one */ + if(strlen(essid) == 0) + wvlan_hw_getssid(&local->ifb, essid, + IW_ESSID_MAX_SIZE, + WVLAN_CURRENT, + local->port_type); + + /* Push it out ! */ + wrq->u.data.length = strlen(essid) + 1; + wrq->u.data.flags = 1; /* active */ + wv_driver_unlock(local, &flags); + copy_to_user(wrq->u.data.pointer, essid, sizeof(essid)); + wv_driver_lock(local, &flags); + } + break; + + // Get current Access Point (BSSID) + case SIOCGIWAP: + wvlan_hw_getbssid(&local->ifb, wrq->u.ap_addr.sa_data, ETH_ALEN); + wrq->u.ap_addr.sa_family = ARPHRD_ETHER; + break; + +#if WIRELESS_EXT > 7 + // Set desired station name + case SIOCSIWNICKN: + if (wrq->u.data.pointer) + { + char name[IW_ESSID_MAX_SIZE + 1]; + + /* Check the size of the string */ + if(wrq->u.data.length > IW_ESSID_MAX_SIZE + 1) + { + rc = -E2BIG; + break; + } + wv_driver_unlock(local, &flags); + copy_from_user(name, wrq->u.data.pointer, wrq->u.data.length); + wv_driver_lock(local, &flags); + name[IW_ESSID_MAX_SIZE] = '\0'; + strncpy(local->station_name, name, sizeof(local->station_name)-1); + local->need_commit = 1; + } + break; + + // Get current station name + case SIOCGIWNICKN: + if (wrq->u.data.pointer) + { + char name[IW_ESSID_MAX_SIZE + 1]; + wvlan_hw_getstationname(&local->ifb, name, IW_ESSID_MAX_SIZE); + wrq->u.data.length = strlen(name) + 1; + wv_driver_unlock(local, &flags); + copy_to_user(wrq->u.data.pointer, name, sizeof(name)); + wv_driver_lock(local, &flags); + } + break; + + // Set the desired bit-rate + case SIOCSIWRATE: + { + // Start the magic... + char brlist[9]; + int brnum = wvlan_hw_getratelist(&local->ifb, brlist, sizeof(brlist)); + int brate = wrq->u.bitrate.value/500000; + int wvrate = 0; + + // Auto or fixed ? + if(wrq->u.bitrate.fixed == 0) { + // Is there a valid value ? + if(wrq->u.bitrate.value == -1) + wvrate = 3; + else { + // Setting by rate value + // Find index in magic table + while((rate_list[wvrate] != -brate) && + (wvrate < (brnum * 2))) + wvrate++; + } + } else + if((wrq->u.bitrate.value <= (brnum * 2 - 1)) && + (wrq->u.bitrate.value > 0)) + { + // Setting by rate index + wvrate = wrq->u.bitrate.value; + } else { + // Setting by rate value + // Find index in magic table + while((rate_list[wvrate] != brate) && + (wvrate < (brnum * 2))) + wvrate++; + } + + // Check if in range + if((wvrate < 1) || (wvrate >= (brnum * 2))) + { + rc = -EINVAL; + break; + } + local->transmit_rate = wvrate; + local->need_commit = 1; + break; + } + + // Get the current bit-rate + case SIOCGIWRATE: + { + int wvrate = wvlan_hw_getbitrate(&local->ifb, WVLAN_DESIRED); + int brate = rate_list[wvrate]; + + // Auto ? + if (brate < 0) + { + wrq->u.bitrate.fixed = 0; + wvrate = wvlan_hw_getbitrate(&local->ifb, WVLAN_CURRENT); + brate = 2 * wvrate; + // Mandatory kludge! + if (wvrate == 6) + brate = 11; + } + else + wrq->u.bitrate.fixed = 1; + + wrq->u.bitrate.value = brate * 500000; + } + break; + + // Set the desired AP density + case SIOCSIWSENS: + { + int dens = wrq->u.sens.value; + if((dens < 1) || (dens > 3)) + { + rc = -EINVAL; + break; + } + local->ap_density = dens; + local->need_commit = 1; + } + break; + + // Get the current AP density + case SIOCGIWSENS: + wrq->u.sens.value = wvlan_hw_getthreshold(&local->ifb, CFG_CNF_SYSTEM_SCALE); + wrq->u.sens.fixed = 0; /* auto */ + break; +#endif /* WIRELESS_EXT > 7 */ + +#if WIRELESS_EXT > 8 + // Set the desired RTS threshold + case SIOCSIWRTS: + { + int rthr = wrq->u.rts.value; + // if(wrq->u.rts.fixed == 0) we should complain + if(wrq->u.rts.disabled) + rthr = 2347; + if((rthr < 0) || (rthr > 2347)) + { + rc = -EINVAL; + break; + } + local->medium_reservation = rthr; + local->need_commit = 1; + } + break; + + // Get the current RTS threshold + case SIOCGIWRTS: + wrq->u.rts.value = wvlan_hw_getthreshold(&local->ifb, CFG_RTS_THRH); + wrq->u.rts.disabled = (wrq->u.rts.value == 2347); + wrq->u.rts.fixed = 1; + break; + + // Set the desired fragmentation threshold + case SIOCSIWFRAG: + /* Check if firmware v4 or v6 */ + if(local->has_mwo) { + int fthr = wrq->u.frag.value; + /* v6 : fragmentation is now controlled by + * MWO robust setting */ + // if(wrq->u.frag.fixed == 1) should complain + if(wrq->u.frag.disabled) + fthr = 0; + if((fthr < 0) || (fthr > 2347)) { + rc = -EINVAL; + } else { + local->mwo_robust = (fthr > 0); + local->need_commit = 1; + } + } else { + int fthr = wrq->u.frag.value; + /* v4 : we can set frag threshold */ + // if(wrq->u.frag.fixed == 0) should complain + if(wrq->u.frag.disabled) + fthr = 2346; + if((fthr < 256) || (fthr > 2346)) { + rc = -EINVAL; + } else { + fthr &= ~0x1; // Get an even value + local->frag_threshold = fthr; + local->need_commit = 1; + } + } + break; + + // Get the current fragmentation threshold + case SIOCGIWFRAG: + /* Check if firmware v4 or v6 */ + if(local->has_mwo) { + if(wvlan_hw_getthreshold(&local->ifb, CFG_CNF_MICRO_WAVE)) + wrq->u.frag.value = 2347; + else + wrq->u.frag.value = 0; + wrq->u.frag.disabled = !(wrq->u.frag.value); + wrq->u.frag.fixed = 0; + } else { + wrq->u.frag.value = wvlan_hw_getthreshold(&local->ifb, CFG_FRAGMENTATION_THRH); + wrq->u.frag.disabled = (wrq->u.frag.value >= 2346); + wrq->u.frag.fixed = 1; + } + break; + + // Set port type + case SIOCSIWMODE: + /* Big firmware trouble here ! + * In v4 and v6.04, the ad-hoc mode supported is the + * Lucent proprietary Ad-Hoc demo mode. + * Starting with v6.06, the ad-hoc mode supported is + * the standard 802.11 IBSS Ad-Hoc mode. + * Jean II + */ + if(local->has_ibssid) { + /* v6 : set the IBSS flag */ + char ibss = 0; + + /* Paranoia */ + if(local->port_type != 1) + local->port_type = 1; + + switch (wrq->u.mode) + { + case IW_MODE_ADHOC: + ibss = 1; + // Fall through + case IW_MODE_INFRA: + local->allow_ibss = ibss; + local->need_commit = 1; + break; + default: + rc = -EINVAL; + } + } else { + /* v4 : set the correct port type */ + char ptype = 1; + + /* Note : this now works properly with + * all firmware ;-) */ + + /* Paranoia */ + if(local->allow_ibss) + local->allow_ibss = 0; + + switch (wrq->u.mode) + { + case IW_MODE_ADHOC: + ptype = 3; + // Fall through + case IW_MODE_INFRA: + local->port_type = ptype; + local->need_commit = 1; + break; + default: + rc = -EINVAL; + } + } + break; + + // Get port type + case SIOCGIWMODE: + /* Check for proprietary Ad-Hoc demo mode */ + if (wvlan_hw_getporttype(&local->ifb) == 1) + wrq->u.mode = IW_MODE_INFRA; + else + wrq->u.mode = IW_MODE_ADHOC; + /* Check for compliant 802.11 IBSS Ad-Hoc mode */ + if ((local->has_ibssid) && + (wvlan_hw_getallowibssflag(&local->ifb) == 1)) + wrq->u.mode = IW_MODE_ADHOC; + break; + + // Set the desired Power Management mode + case SIOCSIWPOWER: + // Disable it ? + if(wrq->u.power.disabled) { + local->pm_on = 0; + local->need_commit = 1; + } else { + // Check mode + switch(wrq->u.power.flags & IW_POWER_MODE) + { + case IW_POWER_UNICAST_R: + local->pm_multi = 0; + local->need_commit = 1; + break; + case IW_POWER_ALL_R: + local->pm_multi = 1; + local->need_commit = 1; + break; + case IW_POWER_ON: // None = ok + break; + default: // Invalid + rc = -EINVAL; + } + // Set period + if (wrq->u.power.flags & IW_POWER_PERIOD) + { + // Activate PM + local->pm_on = 1; + // Hum: check max/min values ? + local->pm_period = wrq->u.power.value/1000; + local->need_commit = 1; + } + if (wrq->u.power.flags & IW_POWER_TIMEOUT) + rc = -EINVAL; // Invalid + } + break; + + // Get the power management settings + case SIOCGIWPOWER: + wrq->u.power.disabled = !wvlan_hw_getpower(&local->ifb, CFG_CNF_PM_ENABLED); + wrq->u.power.flags = IW_POWER_PERIOD; + wrq->u.power.value = wvlan_hw_getpmsleep (&local->ifb) * 1000; + if (wvlan_hw_getpower(&local->ifb, CFG_CNF_MCAST_RX)) + wrq->u.power.flags |= IW_POWER_ALL_R; + else + wrq->u.power.flags |= IW_POWER_UNICAST_R; + break; + + // Set WEP keys and mode + case SIOCSIWENCODE: + // Is it supported? + if (!wvlan_hw_getprivacy(&local->ifb)) + { + rc = -EOPNOTSUPP; + break; + } + // Basic checking: do we have a key to set? + if (wrq->u.encoding.pointer != (caddr_t) 0) + { + int index = (wrq->u.encoding.flags & IW_ENCODE_INDEX) - 1; + // Check the size of the key + if (wrq->u.encoding.length > MAX_KEY_SIZE) + { + rc = -EINVAL; + break; + } + // Check the index + if ((index < 0) || (index >= MAX_KEYS)) + index = local->transmit_key; + // Cleanup + memset(local->key[index].key, 0, MAX_KEY_SIZE); + // Copy the key in the driver + if (copy_from_user(local->key[index].key, wrq->u.encoding.pointer, wrq->u.encoding.length)) + { + local->key[index].len = 0; + rc = -EFAULT; + break; + } + // Set the length + if (wrq->u.encoding.length > MIN_KEY_SIZE) + local->key[index].len = MAX_KEY_SIZE; + else + if (wrq->u.encoding.length > 0) + local->key[index].len = MIN_KEY_SIZE; + else + local->key[index].len = 0; + // Enable WEP (if possible) + if ((index == local->transmit_key) && (local->key[local->transmit_key].len > 0)) + local->wep_on = 1; + } + else + { + int index = (wrq->u.encoding.flags & IW_ENCODE_INDEX) - 1; + // Do we want to just set the current transmit key? + if ((index >= 0) && (index < MAX_KEYS)) + { + if (local->key[index].len > 0) + { + local->transmit_key = index; + local->wep_on = 1; + } + else + rc = -EINVAL; + } + } + // Read the flags + if (wrq->u.encoding.flags & IW_ENCODE_DISABLED) + local->wep_on = 0; // disable encryption + if (wrq->u.encoding.flags & IW_ENCODE_RESTRICTED) + rc = -EINVAL; // Invalid + // Commit the changes + if (rc == 0) + local->need_commit = 1; + break; + + // Get the WEP keys and mode + case SIOCGIWENCODE: + // Is it supported? + if (!wvlan_hw_getprivacy(&local->ifb)) + { + rc = -EOPNOTSUPP; + break; + } + // Only super-user can see WEP key + if (!capable(CAP_NET_ADMIN)) + { + rc = -EPERM; + break; + } + // Basic checking... + if (wrq->u.encoding.pointer != (caddr_t) 0) + { + int index = (wrq->u.encoding.flags & IW_ENCODE_INDEX) - 1; + // Note: should read from adapter(?), and check if WEP capable + // Set the flags + wrq->u.encoding.flags = 0; + if (local->wep_on == 0) + wrq->u.encoding.flags |= IW_ENCODE_DISABLED; + // Which key do we want + if ((index < 0) || (index >= MAX_KEYS)) + index = local->transmit_key; + wrq->u.encoding.flags |= index + 1; + // Copy the key to the user buffer + wrq->u.encoding.length = local->key[index].len; + if (copy_to_user(wrq->u.encoding.pointer, local->key[index].key, local->key[index].len)) + rc = -EFAULT; + } + break; +#endif /* WIRELESS_EXT > 8 */ + + // Get range of parameters + case SIOCGIWRANGE: + if (wrq->u.data.pointer) + { + struct iw_range range; + rc = verify_area(VERIFY_WRITE, wrq->u.data.pointer, sizeof(struct iw_range)); + if (rc) + break; + wrq->u.data.length = sizeof(range); + // Throughput is no way near 2 Mb/s ! + // This value should be : + // 1.6 Mb/s for the 2 Mb/s card + // ~5 Mb/s for the 11 Mb/s card + // Jean II + range.throughput = 1.6 * 1024 * 1024; + range.min_nwid = 0x0000; + range.max_nwid = 0x0000; + range.num_channels = 14; + range.num_frequency = wvlan_hw_getfrequencylist(&local->ifb, + range.freq, + IW_MAX_FREQUENCIES); + range.sensitivity = 3; + if (local->port_type == 3 && + local->spy_number == 0) + { + range.max_qual.qual = 0; + range.max_qual.level = 0; + range.max_qual.noise = 0; + } + else + { + range.max_qual.qual = 0x8b - 0x2f; + range.max_qual.level = 0x2f - 0x95 - 1; + range.max_qual.noise = 0x2f - 0x95 - 1; + } +#if WIRELESS_EXT > 7 + range.num_bitrates = wvlan_getbitratelist(&local->ifb, + range.bitrate, + IW_MAX_BITRATES); + range.min_rts = 0; + range.max_rts = 2347; + range.min_frag = 256; + range.max_frag = 2346; +#endif /* WIRELESS_EXT > 7 */ +#if WIRELESS_EXT > 8 + // Is WEP it supported? + if (wvlan_hw_getprivacy(&local->ifb)) + { + // WEP: RC4 40 bits + range.encoding_size[0] = MIN_KEY_SIZE; + // RC4 ~128 bits + range.encoding_size[1] = MAX_KEY_SIZE; + range.num_encoding_sizes = 2; + range.max_encoding_tokens = 4; // 4 keys + } + else + { + range.num_encoding_sizes = 0; + range.max_encoding_tokens = 0; + } +#endif /* WIRELESS_EXT > 8 */ +#if WIRELESS_EXT > 9 + range.min_pmp = 0; /* ??? */ + range.max_pmp = 65535000; /* ??? */ + range.pmp_flags = IW_POWER_PERIOD; + range.pmt_flags = 0; + range.pm_capa = IW_POWER_PERIOD | + IW_POWER_UNICAST_R; +#endif /* WIRELESS_EXT > 9 */ + wv_driver_unlock(local, &flags); + copy_to_user(wrq->u.data.pointer, &range, sizeof(struct iw_range)); + wv_driver_lock(local, &flags); + } + break; + +#ifdef WIRELESS_SPY + // Set the spy list + case SIOCSIWSPY: + if (wrq->u.data.length > IW_MAX_SPY) + { + rc = -E2BIG; + break; + } + local->spy_number = wrq->u.data.length; + if (local->spy_number > 0) + { + struct sockaddr address[IW_MAX_SPY]; + int i; + rc = verify_area(VERIFY_READ, wrq->u.data.pointer, sizeof(struct sockaddr) * local->spy_number); + if (rc) + break; + wv_driver_unlock(local, &flags); + copy_from_user(address, wrq->u.data.pointer, sizeof(struct sockaddr) * local->spy_number); + wv_driver_lock(local, &flags); + for (i=0; ispy_number; i++) + memcpy(local->spy_address[i], address[i].sa_data, MAC_ADDR_SIZE); + memset(local->spy_stat, 0, sizeof(struct iw_quality) * IW_MAX_SPY); + DEBUG(DEBUG_INFO, "%s: New spy list:\n", dev_info); + for (i=0; iu.data.length; i++) + DEBUG(DEBUG_INFO, "%s: %d - %02x:%02x:%02x:%02x:%02x:%02x\n", dev_info, i+1, + local->spy_address[i][0], local->spy_address[i][1], + local->spy_address[i][2], local->spy_address[i][3], + local->spy_address[i][4], local->spy_address[i][5]); + } + break; + + // Get the spy list + case SIOCGIWSPY: + wrq->u.data.length = local->spy_number; + if ((local->spy_number > 0) && (wrq->u.data.pointer)) + { + struct sockaddr address[IW_MAX_SPY]; + int i; + rc = verify_area(VERIFY_WRITE, wrq->u.data.pointer, (sizeof(struct iw_quality)+sizeof(struct sockaddr)) * IW_MAX_SPY); + if (rc) + break; + for (i=0; ispy_number; i++) + { + memcpy(address[i].sa_data, local->spy_address[i], MAC_ADDR_SIZE); + address[i].sa_family = AF_UNIX; + } + wv_driver_unlock(local, &flags); + copy_to_user(wrq->u.data.pointer, address, sizeof(struct sockaddr) * local->spy_number); + copy_to_user(wrq->u.data.pointer + (sizeof(struct sockaddr)*local->spy_number), local->spy_stat, sizeof(struct iw_quality) * local->spy_number); + wv_driver_lock(local, &flags); + for (i=0; ispy_number; i++) + local->spy_stat[i].updated = 0; + } + break; +#endif /* WIRELESS_SPY */ + +#ifdef HISTOGRAM + // Set the histogram range + case SIOCDEVPRIVATE + 0xd: + // Only super-user can set histogram data + if (!capable(CAP_NET_ADMIN)) + { + rc = -EPERM; + break; + } + if (wrq->u.data.length > 16) + { + rc = -E2BIG; + break; + } + local->his_number = wrq->u.data.length; + if (local->his_number > 0) + { + rc = verify_area(VERIFY_READ, wrq->u.data.pointer, sizeof(char) * local->his_number); + if (rc) + break; + wv_driver_unlock(local, &flags); + copy_from_user(local->his_range, wrq->u.data.pointer, sizeof(char) * local->his_number); + wv_driver_lock(local, &flags); + memset(local->his_sum, 0, sizeof(long) * 16); + } + break; + + // Get the histogram statistic + case SIOCDEVPRIVATE + 0xe: + wrq->u.data.length = local->his_number; + if ((local->his_number > 0) && (wrq->u.data.pointer)) + { + rc = verify_area(VERIFY_WRITE, wrq->u.data.pointer, sizeof(long) * 16); + if (rc) + break; + wv_driver_unlock(local, &flags); + copy_to_user(wrq->u.data.pointer, local->his_sum, sizeof(long) * local->his_number); + wv_driver_lock(local, &flags); + } + break; +#endif /* HISTOGRAM */ + + // Get valid private ioctl calls + case SIOCGIWPRIV: + if (wrq->u.data.pointer) + { + struct iw_priv_args priv[] = { +#ifdef HISTOGRAM + { SIOCDEVPRIVATE + 0xd, IW_PRIV_TYPE_BYTE | 16, 0, "sethisto" }, + { SIOCDEVPRIVATE + 0xe, 0, IW_PRIV_TYPE_INT | 16, "gethisto" }, +#endif +#ifdef PCMCIA_DEBUG + { SIOCDEVPRIVATE + 0x0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "force_reset" }, + { SIOCDEVPRIVATE + 0x1, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "debug_getinfo" }, +#endif + }; + rc = verify_area(VERIFY_WRITE, wrq->u.data.pointer, sizeof(priv)); + if (rc) + break; + wrq->u.data.length = sizeof(priv) / sizeof(priv[0]); + wv_driver_unlock(local, &flags); + copy_to_user(wrq->u.data.pointer, priv, sizeof(priv)); + wv_driver_lock(local, &flags); + } + break; + +#ifdef PCMCIA_DEBUG + // Force card reset (debug purpose only) + case SIOCDEVPRIVATE + 0x0: + // Only super-user can reset the card... + if (!capable(CAP_NET_ADMIN)) + { + rc = -EPERM; + break; + } + if (*((int *) wrq->u.name) > 0) + { + // 'hard' reset + printk(KERN_DEBUG "%s: Forcing hard reset\n", dev_info); + /* IRQ already disabled, don't do it again */ + wvlan_hw_shutdown(dev); + wvlan_hw_config(dev); + } + else + { + // 'soft' reset + printk(KERN_DEBUG "%s: Forcing soft reset\n", dev_info); + /* IRQ already disabled, don't do it again */ + wvlan_hw_reset(dev); + } + break; + + // Get info from card and dump answer to syslog (debug purpose only) + case SIOCDEVPRIVATE + 0x1: + { + CFG_ID_STRCT ltv; + char *p; + int typ = *((int *) wrq->u.name); + ltv.len = 18; + ltv.typ = typ; + rc = hcf_get_info(&local->ifb, (LTVP) <v); + if (rc) + printk(KERN_DEBUG "%s: hcf_get_info(0x%x) returned error 0x%x\n", dev_info, typ, rc); + else + { + p = (char *) <v.id; + printk(KERN_DEBUG "%s: hcf_get_info(0x%x) returned %d words:\n", dev_info, ltv.typ, ltv.len); + printk(KERN_DEBUG "%s: hex-dump: ", dev_info); + for (rc=0; rc<(ltv.len); rc++) + printk("%04x ", le16_to_cpup(<v.id[rc])); + printk("\n"); + printk(KERN_DEBUG "%s: ascii-dump: '", dev_info); + for (rc=0; rc<(ltv.len*2); rc++) + printk("%c", (p[rc]>31) ? p[rc] : '.'); + printk("'\n"); + } + } + break; +#endif /* PCMCIA_DEBUG */ + + // All other calls are currently unsupported + default: + rc = -EOPNOTSUPP; + } + + /* Some of the "set" function may have modified some of the + * parameters. It's now time to commit them in the card */ + if(local->need_commit) { + /* Is the driver active ? + * Here, we optimise. If the driver is not active, we don't + * commit the individual changes, and all the changes will + * be committed together in wvlan_open(). This significantely + * speed up the card startup when using wireless.opts + * Jean II */ + if((local->link->open) || (cmd == SIOCSIWESSID)) { + /* IRQ are already disabled */ + wvlan_hw_shutdown(dev); + wvlan_hw_config(dev); + local->need_commit = 0; + } + } + + // Re-enable interrupts + wv_driver_unlock(local, &flags); + + DEBUG(DEBUG_CALLTRACE, "<- wvlan_ioctl()\n"); + return rc; +} + +struct iw_statistics *wvlan_get_wireless_stats (struct net_device *dev) +{ + struct net_local *local = (struct net_local *) dev->priv; + CFG_COMMS_QUALITY_STRCT ltv; + unsigned long flags; + int rc; + + DEBUG(DEBUG_CALLTRACE, "-> wvlan_get_wireless_stats(%s)\n", dev->name); + + // Disable interrupts + wv_driver_lock(local, &flags); + + local->wstats.status = 0; + if (local->port_type != 3) + { + ltv.len = 4; + ltv.typ = CFG_COMMS_QUALITY; + rc = hcf_get_info(&local->ifb, (LTVP) <v); + DEBUG(DEBUG_NOISY, "%s: hcf_get_info(CFG_COMMS_QUALITY) returned 0x%x\n", dev_info, rc); + local->wstats.qual.qual = max(min(le16_to_cpup(<v.coms_qual), 0x8b-0x2f), 0); + local->wstats.qual.level = max(min(le16_to_cpup(<v.signal_lvl), 0x8a), 0x2f) - 0x95; + local->wstats.qual.noise = max(min(le16_to_cpup(<v.noise_lvl), 0x8a), 0x2f) - 0x95; + local->wstats.qual.updated = 7; + } + else + { + // Quality levels cannot be determined in ad-hoc mode, + // because we can 'hear' more that one remote station. + // If a spy address is defined, we report stats of the + // first spy address + local->wstats.qual.qual = 0; + local->wstats.qual.level = 0; + local->wstats.qual.noise = 0; + local->wstats.qual.updated = 0; +#ifdef WIRELESS_SPY + if (local->spy_number > 0) + { + local->wstats.qual.qual = local->spy_stat[0].qual; + local->wstats.qual.level = local->spy_stat[0].level; + local->wstats.qual.noise = local->spy_stat[0].noise; + local->wstats.qual.updated = local->spy_stat[0].updated; + } +#endif /* WIRELESS_SPY */ + } + + // Packets discarded in the wireless adapter due to wireless specific problems + local->wstats.discard.nwid = 0; + local->wstats.discard.code = local->ifb.IFB_NIC_Tallies.RxWEPUndecryptable; + local->wstats.discard.misc = local->ifb.IFB_NIC_Tallies.RxFCSErrors + + local->ifb.IFB_NIC_Tallies.RxDiscards_NoBuffer + + local->ifb.IFB_NIC_Tallies.TxDiscardsWrongSA; + + // Re-enable interrupts + wv_driver_unlock(local, &flags); + + DEBUG(DEBUG_CALLTRACE, "<- wvlan_get_wireless_stats()\n"); + return (&local->wstats); +} + +#ifdef WIRELESS_SPY +static inline void wvlan_spy_gather (struct net_device *dev, u_char *mac, u_char *stats) +{ + struct net_local *local = (struct net_local *)dev->priv; + int i; + + // Gather wireless spy statistics: for each packet, compare the + // source address with out list, and if match, get the stats... + for (i=0; ispy_number; i++) + if (!memcmp(mac, local->spy_address[i], MAC_ADDR_SIZE)) + { + local->spy_stat[i].qual = stats[2]; + local->spy_stat[i].level = stats[0] - 0x95; + local->spy_stat[i].noise = stats[1] - 0x95; + local->spy_stat[i].updated = 7; + } +} +#endif /* WIRELESS_SPY */ + +#ifdef HISTOGRAM +static inline void wvlan_his_gather (struct net_device *dev, u_char *stats) +{ + struct net_local *local = (struct net_local *)dev->priv; + u_char level = stats[0] - 0x2f; + int i; + + // Calculate a histogram of the signal level. Each time the + // level goes into our defined set of interval, we increment + // the count. + i = 0; + while ((i < (local->his_number-1)) && (level >= local->his_range[i++])); + local->his_sum[i]++; +} +#endif /* HISTOGRAM */ +#endif /* WIRELESS_EXT */ + +int wvlan_change_mtu (struct net_device *dev, int new_mtu) +{ + if (new_mtu < WVLAN_MIN_MTU || new_mtu > WVLAN_MAX_MTU) + { + DEBUG(DEBUG_INFO, "%s: New MTU of %d for %s out of range!\n", dev_info, new_mtu, dev->name); + return -EINVAL; + } + dev->mtu = new_mtu; + DEBUG(DEBUG_INFO, "%s: MTU of %s set to %d bytes\n", dev_info, dev->name, new_mtu); + return 0; +} + +static void wvlan_set_multicast_list (struct net_device *dev) +{ + struct net_local *local = (struct net_local *)dev->priv; + unsigned long flags; + + // Note: check if hardware up & running? + + // Disable interrupts + wv_driver_lock(local, &flags); + + DEBUG(DEBUG_INFO, "%s: setting multicast Rx mode %02X to %d addresses.\n", dev->name, dev->flags, dev->mc_count); + + // Ok, what do we want? + if (dev->flags & IFF_PROMISC) + { + // Enable promiscuous mode: receive all packets. + if (!local->promiscuous) + { + local->promiscuous = 1; + local->mc_count = 0; + wvlan_hw_setpromisc(&local->ifb, local->promiscuous); + dev->flags |= IFF_PROMISC; + } + } + else + // If all multicast addresses + // or too many multicast addresses for the hardware filter + if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > WVLAN_MAX_MULTICAST)) + { + // Disable promiscuous mode, but active the all multicast mode + if (!local->promiscuous) { + // The Wavelan IEEE doesn't seem to have a + // "receive all multicast" flag, which allow to + // grab all multicast frames. So we go for + // promiscuous and let TCP filter packets, + // which is *very* far from optimal. + // Note that CNF_MCAST_RX is quite different, + // as it specify if the Wavelan will wake up for + // the broadcast announcements from the AP (DTIM) + local->promiscuous = 1; + local->mc_count = 0; + wvlan_hw_setpromisc(&local->ifb, local->promiscuous); + // Tell the kernel that we are doing a really bad job... + dev->flags |= IFF_PROMISC; + } + } + else + // If there is some multicast addresses to send + if (dev->mc_list != (struct dev_mc_list *) NULL) + { + // Disable promiscuous mode, but receive all packets + // in multicast list +#ifdef MULTICAST_AVOID + if (local->promiscuous || local->allmulticast || (dev->mc_count != local->mc_count)) +#endif + { + struct dev_mc_list *dmi; + int i; + CFG_GROUP_ADDR_STRCT ltv; + int rc; + + local->promiscuous = 0; + local->mc_count = dev->mc_count; + // Disable promiscuous + wvlan_hw_setpromisc(&local->ifb, local->promiscuous); + dev->flags &= ~IFF_PROMISC; + // Write multicast addresses in the adapter + for (i=0, dmi=dev->mc_list; dmi; dmi=dmi->next) + memcpy(ltv.mac_addr[i++], dmi->dmi_addr, dmi->dmi_addrlen); + ltv.len = (ETH_ALEN * local->mc_count / 2) + 1; + ltv.typ = CFG_GROUP_ADDR; + rc = hcf_put_info(&local->ifb, (LTVP) <v); + DEBUG(DEBUG_NOISY, "%s: hcf_put_info(CFG_GROUP_ADDR:0x%x) returned 0x%x\n", dev_info, local->mc_count, rc); + } + } + else + { + // Switch to normal mode: disable promiscuous mode and + // clear the multicast list. + if (local->promiscuous || local->mc_count != 0) + { + CFG_GROUP_ADDR_STRCT ltv; + int rc; + local->promiscuous = 0; + local->mc_count = 0; + wvlan_hw_setpromisc(&local->ifb, local->promiscuous); + // Clear multicast list + ltv.len = 1; + ltv.typ = CFG_GROUP_ADDR; + rc = hcf_put_info(&local->ifb, (LTVP) <v); + DEBUG(DEBUG_NOISY, "%s: hcf_put_info(CFG_GROUP_ADDR:0x%x) returned 0x%x\n", dev_info, local->mc_count, rc); + } + } + // Re-enable interrupts + wv_driver_unlock(local, &flags); + + return; +} + + + +/******************************************************************** + * NET TX / RX + */ +static void wvlan_watchdog (struct net_device *dev) +{ + struct net_local *local = (struct net_local *) dev->priv; + unsigned long flags; + + DEBUG(DEBUG_CALLTRACE, "-> wvlan_wathdog(%s)\n", dev->name); + + // In theory, we could try to abort the current Tx command here, + // this would avoid to go through a long reset process in many + // cases (obstruction of the channel, very high contention)... + + // Reset card in case of Tx timeout +#ifdef WVLAN_RESET_ON_TX_TIMEOUT + printk(KERN_WARNING "%s: %s Tx timed out! Resetting card\n", dev_info, dev->name); + /* IRQ currently enabled, so disable it */ + wv_driver_lock(local, &flags); + wvlan_hw_shutdown(dev); + wvlan_hw_config(dev); + wv_driver_unlock(local, &flags); +#else + printk(KERN_WARNING "%s: %s Tx timed out! Ignoring...\n", dev_info, dev->name); +#endif + + DEBUG(DEBUG_CALLTRACE, "<- wvlan_watchdog()\n"); +} + +int wvlan_tx (struct sk_buff *skb, struct net_device *dev) +{ + struct net_local *local = (struct net_local *)dev->priv; + unsigned long flags; + int rc, len; + char *p; + + DEBUG(DEBUG_CALLTRACE, "-> wvlan_tx(%s)\n", dev->name); + +#if (KERNEL_VERSION_CODE < KERNEL_VERSION(2,3,42)) + // We normally shouldn't be called if queue is stopped (transmitter busy) + // but older kernel code does anyway. So we'll check if the last + // transmission has timed out and reset the device in case + if (netif_queue_stopped(dev)) + { + DEBUG(DEBUG_TXRX, "%s: wvlan_tx(%s) called while busy!\n", dev_info, dev->name); + if ((jiffies - dev->trans_start) < TX_TIMEOUT) + return 1; + if (!netif_running(dev)) + { + printk(KERN_WARNING "%s: %s Tx on stopped device!\n", dev_info, dev->name); + return 1; + } + wvlan_watchdog(dev); + } +#endif + + skb_tx_check(dev, skb); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,79)) + skb->arp = 1; +#endif + + // Tell queueing layer to stop sending + // TODO: We should use multiple Tx buffers and + // re-enable the queue (netif_wake_queue()) if + // there's space left in the Tx buffers. + netif_stop_queue(dev); + + // Disable interrupts + wv_driver_lock(local, &flags); + + // Prepare packet + p = skb->data; + len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; + + // Add Ethernet-II frame encapsulation, because + // HCF-light doesn't support that. + if (p[13] + (p[12] << 8) > 1500) + { + hcf_put_data(&local->ifb, p, 12, 0); + len += sizeof(snap_header); + snap_header[1] = (len-0x0e) & 0xff; + snap_header[0] = (char)((len-0x0e) >> 8); + hcf_put_data(&local->ifb, snap_header, sizeof(snap_header), 0); + hcf_put_data(&local->ifb, p+12, len-12-sizeof(snap_header), 0); + } + else + hcf_put_data(&local->ifb, p, len, 0); + + // Send packet + rc = hcf_send(&local->ifb, 0); + + // Remeber time transmission and count tx bytes + dev->trans_start = jiffies; + add_tx_bytes(&local->stats, len); + + // Re-enable interrupts + wv_driver_unlock(local, &flags); + + // It might be no good idea doing a printk() debug output during + // disabled interrupts (I'm not sure...). So better do it here. + DEBUG(DEBUG_TXRX, "%s: Sending 0x%x octets\n", dev_info, len); + DEBUG(DEBUG_NOISY, "%s: hcf_send() returned 0x%x\n", dev_info, rc); + + DEV_KFREE_SKB(skb); + DEBUG(DEBUG_CALLTRACE, "<- wvlan_tx()\n"); + return 0; +} + +void wvlan_rx (struct net_device *dev, int len) +{ + struct net_local *local = (struct net_local *)dev->priv; + struct sk_buff *skb; + char *p; + + DEBUG(DEBUG_CALLTRACE, "-> wvlan_rx(%s)\n", dev->name); + + // Create skb packet + skb = dev_alloc_skb(len+2); + if (!skb) + { + printk(KERN_WARNING "%s: %s Rx cannot allocate buffer for new packet\n", dev_info, dev->name); + local->stats.rx_dropped++; + return; + } + DEBUG(DEBUG_TXRX, "%s: Receiving 0x%x octets\n", dev_info, len); + + // Align IP on 16b boundary + skb_reserve(skb, 2); + p = skb_put(skb, len); + dev->last_rx = jiffies; + + // Add Ethernet-II frame decapsulation, because + // HCF-light doesn't support that. + if (local->ifb.IFB_RxStat == 0x2000 || local->ifb.IFB_RxStat == 0x4000) + { + hcf_get_data(&local->ifb, 0, p, 12); + hcf_get_data(&local->ifb, 12+sizeof(snap_header), p+12, len-12-sizeof(snap_header)); + skb_trim(skb, len-sizeof(snap_header)); + } + else + hcf_get_data(&local->ifb, 0, p, len); + + skb->dev = dev; + skb->protocol = eth_type_trans(skb, dev); + skb->ip_summed = CHECKSUM_NONE; + + // Hand the packet over to the kernel + netif_rx(skb); + local->stats.rx_packets++; + add_rx_bytes(&local->stats, len); + +#ifdef WIRELESS_EXT +#if defined(WIRELESS_SPY) || defined(HISTOGRAM) + if ( +#ifdef WIRELESS_SPY + (local->spy_number > 0) || +#endif +#ifdef HISTOGRAM + (local->his_number > 0) || +#endif + 0 ) + { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(1,3,0)) + char *srcaddr = skb->mac.raw + MAC_ADDR_SIZE; +#else + char *srcaddr = skb->data + MAX_ADDR_SIZE; +#endif + u_char stats[3]; + int rc, i; + local->wstats.status = 0; + + // Using spy support with port_type==1 will really + // slow down everything, because the signal quality + // must be queried for each packet here. + // If the user really asks for it (set some address in the + // spy list), we do it, but he will pay the price. + // Note that to get here, you need both WIRELESS_SPY + // compiled in AND some addresses in the list !!! + // TODO: Get and cache stats here so that they + // are available but don't need to be retreived + // every time a packet is received. +#if defined(HISTOGRAM) + // We can't be clever... + rc = hcf_get_data(&local->ifb, HFS_Q_INFO, stats, 2); + DEBUG(DEBUG_NOISY, "%s: hcf_get_data(HFS_Q_INFO) returned 0x%x\n", dev_info, rc); +#else // Therefore WIRELESS_SPY only !!! + memset(&stats, 0, sizeof(stats)); + // Query only for addresses in our list ! + for (i=0; ispy_number; i++) + if (!memcmp(srcaddr, local->spy_address[i], MAC_ADDR_SIZE)) + { + rc = hcf_get_data(&local->ifb, HFS_Q_INFO, stats, 2); + break; + } +#endif + stats[2] = stats[0]; + stats[0] = max(min(stats[1], 0x8a), 0x2f); + stats[1] = max(min(stats[2], 0x8a), 0x2f); + stats[2] = stats[0] - stats[1]; +#ifdef WIRELESS_SPY + wvlan_spy_gather(dev, srcaddr, stats); +#endif +#ifdef HISTOGRAM + wvlan_his_gather(dev, stats); +#endif + } +#endif /* WIRELESS_SPY || HISTOGRAM */ +#endif /* WIRELESS_EXT */ + + DEBUG(DEBUG_CALLTRACE, "<- wvlan_rx()\n"); +} + + +/******************************************************************** + * NET OPEN / CLOSE + */ + +static int wvlan_open (struct net_device *dev) +{ + struct net_local *local = (struct net_local *) dev->priv; + struct dev_link_t *link = local->link; + + DEBUG(DEBUG_CALLTRACE, "-> wvlan_open(%s)\n", dev->name); + + /* Check if we need to re-setup the card */ + if(local->need_commit) { + unsigned long flags; + wv_driver_lock(local, &flags); + wvlan_hw_shutdown(dev); + wvlan_hw_config(dev); + local->need_commit = 0; + wv_driver_unlock(local, &flags); + } + + // TODO: Power up the card here and power down on close? + // For now this is done on device init, not on open + // Might be better placed here so that some settings can + // be made by shutting down the device without removing + // the driver (iwconfig). + // But this is no real problem for now :-) + + // Start reception and declare the driver ready + if (!local->ifb.IFB_CardStat) + return -ENODEV; + netif_device_attach(dev); + netif_start_queue(dev); + local->interrupt = 0; + link->open++; + MOD_INC_USE_COUNT; + + DEBUG(DEBUG_CALLTRACE, "<- wvlan_open()\n"); + return 0; +} + +static int wvlan_close (struct net_device *dev) +{ + struct net_local *local = (struct net_local *) dev->priv; + struct dev_link_t *link = local->link; + + // If the device isn't open, then nothing to do + if (!link->open) + { + DEBUG(DEBUG_CALLTRACE, "<> wvlan_close(%s)\n", dev->name); + return 0; + } + + DEBUG(DEBUG_CALLTRACE, "-> wvlan_close(%s)\n", dev->name); + + // Close the device + link->open--; + MOD_DEC_USE_COUNT; + + // Check if card is still present + if (netif_running(dev)) + { + netif_stop_queue(dev); + netif_device_detach(dev); + // TODO: Shutdown hardware (see wvlan_open) + } + else + if (link->state & DEV_STALE_CONFIG) + mod_timer(&link->release, jiffies + HZ/20); + + DEBUG(DEBUG_CALLTRACE, "<- wvlan_close()\n"); + return -EINVAL; +} + + +/******************************************************************** + * INTERRUPT HANDLER + */ +static void wvlan_interrupt (int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) dev_id; + struct net_local *local = (struct net_local *) dev->priv; + int rc, cnt, ev, len; + + DEBUG(DEBUG_INTERRUPT, "-> wvlan_interrupt(%d)\n", irq); + + // Check device + if (!dev) + { + printk(KERN_WARNING "%s: IRQ %d for unknown device!\n", dev_info, irq); + return; + } + + /* Prevent reentrancy. We need to do that because we may have + * multiple interrupt handler running concurently. + * It is safe because wv_driver_lock() disable interrupts before + * aquiring the spinlock. */ + spin_lock(&local->slock); + + // Turn off interrupts + rc = hcf_action(&local->ifb, HCF_ACT_INT_OFF); + DEBUG(DEBUG_NOISY, "%s: hcf_action(HCF_ACT_INT_OFF) returned 0x%x\n", dev_info, rc); + /* Check state of interrupt */ + if (test_and_set_bit(0, (void *)&local->interrupt)) + printk(KERN_DEBUG "%s: Warning: IRQ %d Reentering interrupt handler!\n", dev_info, irq); + + // Process pending interrupts. + // We continue until hcf_service_nic tells that no received + // frames are pending. However we should check to not lock up + // here in an endless loop. + cnt = 7; + while (cnt--) + { + // Ask NIC why interrupt occured + ev = hcf_service_nic(&local->ifb); + DEBUG(DEBUG_NOISY, "%s: hcf_service_nic() returned 0x%x RscInd 0x%x\n", dev_info, ev, local->ifb.IFB_PIFRscInd); + + // Transmission completion seem to be also signalled with ev==0 + // better check that out with RscInd and complete transfer also + if (local->ifb.IFB_PIFRscInd && netif_queue_stopped(dev)) + ev |= HREG_EV_TX; + + // HREG_EV_TICK: WMAC controller auxiliary timer tick + if (ev & HREG_EV_TICK) + { + DEBUG(DEBUG_INFO,"%s: Auxiliary timer tick\n", dev_info); + } + + // HREG_EV_RES: WMAC controller H/W error (wait timeout) + if (ev & HREG_EV_RES) + { + // This message seems to occur often on heavy load + // but it seem to don't have any effects on transmission + // so we simply ignore it. + //printk(KERN_WARNING "%s: WMAC H/W error (wait timeout, ignoring)!\n", dev_info); + } + + // HREG_EV_INFO_DROP: WMAC did not have sufficient RAM to build unsollicited frame + if (ev & HREG_EV_INFO_DROP) + printk(KERN_WARNING "%s: WMAC did not have sufficient RAM to build unsollicited frame!\n", dev_info); + + // HREG_EV_INFO: WMAC controller asynchronous information frame + if (ev & HREG_EV_INFO) + { + DEBUG(DEBUG_INFO, "%s: WMAC controller asynchronous information frame\n", dev_info); + } + + // HREG_EV_CMD: WMAC controller command completed, status and response available + // unnecessary to handle here, it's handled by polling in HCF + + // HREG_EV_ALLOC: WMAC controller asynchronous part of allocation/reclaim completed + // also unnecessary to handle here, it's handled by polling in HCF + + // HREG_EV_TX_EXC: WMAC controller asynchronous transmission unsuccessful completed + if (ev & HREG_EV_TX_EXC) + { + printk(KERN_WARNING "%s: WMAC controller asynchronous transmission unsuccessful completed\n", dev_info); + local->stats.tx_errors++; + netif_wake_queue(dev); + } + + // HREG_EV_TX: WMAC controller asynchronous transmission successful completed + if (ev & HREG_EV_TX) + { + DEBUG(DEBUG_TXRX, "%s: Transmission successful completed\n", dev_info); + local->stats.tx_packets++; + netif_wake_queue(dev); + } + + // HREG_EV_RX: WMAC controller asynchronous receive frame + // Break loop if no frame was received. + if (!(ev & HREG_EV_RX)) + break; + + // If a frame was received, we process it and wrap back + // up to the top of the while() loop so that hcf_service_nic() + // gets called again after the frame drained from the NIC. + // This allows us to find out if yet another frame has + // arrived, and also to immediately acknowledge the just- + // processed frame so that the NIC's buffer gets de- + // allocated right away. + len = local->ifb.IFB_RxLen; + if (len) + { + DEBUG(DEBUG_INTERRUPT, "%s: Frame received. rx_len=0x%x\n", dev_info, len); + wvlan_rx(dev, len); + } + } + if (!cnt) + printk(KERN_WARNING "%s: Maximum interrupt loops reached!\n", dev_info); + + // From now on, we don't care if we re-enter the interrupt handler + local->interrupt = 0; + + // Turn back interrupts on (unlock) + rc = hcf_action(&local->ifb, HCF_ACT_INT_ON); + DEBUG(DEBUG_NOISY, "%s: hcf_action(HCF_ACT_INT_ON) returned 0x%x\n", dev_info, rc); + + /* Release spinlock */ + spin_unlock (&local->slock); + + DEBUG(DEBUG_INTERRUPT, "<- wvlan_interrupt()\n"); +} + + +/******************************************************************** + * PCMCIA CONFIG / RELEASE + */ +#define CS_CHECK(fn, args...) while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed +#define CFG_CHECK(fn, args...) if (CardServices(fn, args) != 0) goto next_entry +static int wvlan_config (dev_link_t *link) +{ + client_handle_t handle = link->handle; + tuple_t tuple; + cisparse_t parse; + struct net_device *dev = (struct net_device *) link->priv; + struct net_local *local = (struct net_local *) dev->priv; + int last_fn, last_ret; + u_char buf[64]; + win_req_t req; + memreq_t map; + int rc, i; + + DEBUG(DEBUG_CALLTRACE, "-> wvlan_config(0x%p)\n", link); + + // This reads the card's CONFIG tuple to find its configuration registers. + tuple.DesiredTuple = CISTPL_CONFIG; + tuple.Attributes = 0; + tuple.TupleData = buf; + tuple.TupleDataMax = sizeof(buf); + tuple.TupleOffset = 0; + CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetTupleData, handle, &tuple); + CS_CHECK(ParseTuple, handle, &tuple, &parse); + link->conf.ConfigBase = parse.config.base; + link->conf.Present = parse.config.rmask[0]; + + // Configure card + link->state |= DEV_CONFIG; + + // In this loop, we scan the CIS for configuration table entries, + // each of which describes a valid card configuration, including + // voltage, IO window, memory window, and interrupt settings. + // We make no assumptions about the card to be configured: we use + // just the information available in the CIS. In an ideal world, + // this would work for any PCMCIA card, but it requires a complete + // and accurate CIS. In practice, a driver usually "knows" most of + // these things without consulting the CIS, and most client drivers + // will only use the CIS to fill in implementation-defined details. + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + CS_CHECK(GetFirstTuple, handle, &tuple); + while (1) { + cistpl_cftable_entry_t dflt = { 0 }; + cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); + CFG_CHECK(GetTupleData, handle, &tuple); + CFG_CHECK(ParseTuple, handle, &tuple, &parse); + + if (cfg->index == 0) goto next_entry; + link->conf.ConfigIndex = cfg->index; + + // Does this card need audio output? + if (cfg->flags & CISTPL_CFTABLE_AUDIO) + { + link->conf.Attributes |= CONF_ENABLE_SPKR; + link->conf.Status = CCSR_AUDIO_ENA; + } + + // Use power settings for Vcc and Vpp if present + // Note that the CIS values need to be rescaled + if (cfg->vcc.present & (1<conf.Vcc = cfg->vcc.param[CISTPL_POWER_VNOM]/10000; + else if (dflt.vcc.present & (1<conf.Vcc = dflt.vcc.param[CISTPL_POWER_VNOM]/10000; + + if (cfg->vpp1.present & (1<conf.Vpp1 = link->conf.Vpp2 = cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; + else if (dflt.vpp1.present & (1<conf.Vpp1 = link->conf.Vpp2 = dflt.vpp1.param[CISTPL_POWER_VNOM]/10000; + + // Do we need to allocate an interrupt? + if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) + link->conf.Attributes |= CONF_ENABLE_IRQ; + + // IO window settings + link->io.NumPorts1 = link->io.NumPorts2 = 0; + if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { + cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + if (!(io->flags & CISTPL_IO_8BIT)) + link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; + if (!(io->flags & CISTPL_IO_16BIT)) + link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + link->io.BasePort1 = io->win[0].base; + link->io.NumPorts1 = io->win[0].len; + if (io->nwin > 1) { + link->io.Attributes2 = link->io.Attributes1; + link->io.BasePort2 = io->win[1].base; + link->io.NumPorts2 = io->win[1].len; + } + } + + // This reserves IO space but doesn't actually enable it + CFG_CHECK(RequestIO, link->handle, &link->io); + + // Now set up a common memory window, if needed. There is room + // in the dev_link_t structure for one memory window handle, + // but if the base addresses need to be saved, or if multiple + // windows are needed, the info should go in the private data + // structure for this device. + // Note that the memory window base is a physical address, and + // needs to be mapped to virtual space with ioremap() before it + // is used. + if ((cfg->mem.nwin > 0) || (dflt.mem.nwin > 0)) { + cistpl_mem_t *mem = (cfg->mem.nwin) ? &cfg->mem : &dflt.mem; + req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM; + req.Base = mem->win[0].host_addr; + req.Size = mem->win[0].len; + req.AccessSpeed = 0; + link->win = (window_handle_t)link->handle; + CFG_CHECK(RequestWindow, &link->win, &req); + map.Page = 0; map.CardOffset = mem->win[0].card_addr; + CFG_CHECK(MapMemPage, link->win, &map); + } + + // If we got this far, we're cool! + break; + +next_entry: + if (cfg->flags & CISTPL_CFTABLE_DEFAULT) + dflt = *cfg; + CS_CHECK(GetNextTuple, handle, &tuple); + } + + // Allocate an interrupt line. Note that this does not assign a + // handler to the interrupt, unless the 'Handler' member of the + // irq structure is initialized. + if (link->conf.Attributes & CONF_ENABLE_IRQ) + { + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; + if (irq_list[0] == -1) + link->irq.IRQInfo2 = irq_mask; + else + for (i=0; i<4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + link->irq.Handler = wvlan_interrupt; + link->irq.Instance = dev; + CS_CHECK(RequestIRQ, link->handle, &link->irq); + } + + // This actually configures the PCMCIA socket -- setting up + // the I/O windows and the interrupt mapping, and putting the + // card and host interface into "Memory and IO" mode. + CS_CHECK(RequestConfiguration, link->handle, &link->conf); + + // Feed the netdevice with this info + dev->irq = link->irq.AssignedIRQ; + dev->base_addr = link->io.BasePort1; + netif_start_queue(dev); + + // Report what we've done + printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d", dev_info, link->conf.ConfigIndex, link->conf.Vcc/10, link->conf.Vcc%10); + if (link->conf.Vpp1) + printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10); + if (link->conf.Attributes & CONF_ENABLE_IRQ) + printk(", irq %d", link->irq.AssignedIRQ); + if (link->io.NumPorts1) + printk(", io 0x%04x-0x%04x", link->io.BasePort1, link->io.BasePort1+link->io.NumPorts1-1); + if (link->io.NumPorts2) + printk(" & 0x%04x-0x%04x", link->io.BasePort2, link->io.BasePort2+link->io.NumPorts2-1); + if (link->win) + printk(", mem 0x%06lx-0x%06lx", req.Base, req.Base+req.Size-1); + printk("\n"); + + link->state &= ~DEV_CONFIG_PENDING; + + // Make netdevice's name (if not ethX) and remember the device + // Not very efficient here, this should go somewhere into dev_list, + // but it works for now (taken from register_netdevice in kernel) + /* Note : may fail if other drivers are also using this name */ + if(!eth) + { + for (i=0; iname, "wvlan%d", i); + wvlandev_index[i] = dev; + break; + } + } + + // Register the netdevice + rc = register_netdev(dev); + if (rc) + { + printk(KERN_WARNING "%s: register_netdev() failed!\n", dev_info); + wvlan_release((u_long)link); + return 0; + } + printk(KERN_INFO "%s: Registered netdevice %s\n", dev_info, dev->name); + strcpy(local->node.dev_name, dev->name); + link->dev = &local->node; + + // Success! + DEBUG(DEBUG_CALLTRACE, "<- wvlan_config()\n"); + return 1; + +cs_failed: + cs_error(link->handle, last_fn, last_ret); + wvlan_release((u_long)link); + DEBUG(DEBUG_CALLTRACE, "<- wvlan_config()\n"); + return 0; +} + +static void wvlan_release (u_long arg) +{ + dev_link_t *link = (dev_link_t *) arg; + struct net_device *dev = (struct net_device *) link->priv; + struct net_local *local = (struct net_local *) dev->priv; + unsigned long flags; + int i; + + DEBUG(DEBUG_CALLTRACE, "-> wvlan_release(0x%p)\n", link); + + // If the device is currently in use, we won't release + // until it's actually closed. + if (link->open) + { + DEBUG(DEBUG_INFO, "%s: wvlan_release: release postponed, %s still locked\n", dev_info, link->dev->dev_name); + link->state |= DEV_STALE_CONFIG; + return; + } + + // Power down - IRQ currently enabled, so disable it + wv_driver_lock(local, &flags); + wvlan_hw_shutdown(dev); + wv_driver_unlock(local, &flags); + + // Remove our device from index (only devices named wvlanX) + for (i=0; iwin) + CardServices(ReleaseWindow, link->win); + CardServices(ReleaseConfiguration, link->handle); + if (link->io.NumPorts1) + CardServices(ReleaseIO, link->handle, &link->io); + if (link->irq.AssignedIRQ) + CardServices(ReleaseIRQ, link->handle, &link->irq); + + link->state &= ~DEV_CONFIG; + + DEBUG(DEBUG_CALLTRACE, "<- wvlan_release()\n"); +} + + +/******************************************************************** + * PCMCIA ATTACH / DETACH + */ +static dev_link_t *wvlan_attach (void) +{ + dev_link_t *link; + struct net_device *dev; + struct net_local *local; + int rc; + client_reg_t client_reg; + + DEBUG(DEBUG_CALLTRACE, "-> wvlan_attach()\n"); + + // Flush stale links + for (link=dev_list; link; link=link->next) + if (link->state & DEV_STALE_LINK) + wvlan_detach(link); + + // Initialize the dev_link_t structure + link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); + memset(link, 0, sizeof(struct dev_link_t)); + link->release.function = &wvlan_release; + link->release.data = (u_long) link; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + + // Allocate space for netdevice (private data of link) + dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); + memset(dev, 0, sizeof(struct net_device)); + link->priv = dev; + + // Allocate space for netdevice priv (private data of netdevice) + local = kmalloc(sizeof(struct net_local), GFP_KERNEL); + memset(local, 0, sizeof(struct net_local)); + dev->priv = local; + + // Initialize specific data + local->link = link; + local->dev = dev; + spin_lock_init(&local->slock); + // Copy modules parameters to private struct + local->port_type = port_type; + local->allow_ibss = allow_ibss; + strcpy(local->network_name, network_name); + local->channel = channel; + // Initialise Wireless Extension stuff +#ifdef WIRELESS_EXT + local->station_name[0] = '\0'; + local->ap_density = 1; + local->medium_reservation = 2347; + local->frag_threshold = 2346; + local->mwo_robust = 0; + local->transmit_rate = 3; + local->wep_on = 0; + local->pm_on = 0; + local->pm_multi = 1; + local->pm_period = 100000; + // Check obsolete module parameters + if(*(station_name)) { + strcpy(local->station_name, station_name); + printk(KERN_INFO "%s: ``station_name'' is an obsolete module parameter, please use iwconfig.", dev_info); + } +#endif /* WIRELESS_EXT */ + + // Standard setup for generic data + ether_setup(dev); + + // kernel callbacks + dev->open = wvlan_open; + dev->stop = wvlan_close; + dev->hard_start_xmit = wvlan_tx; + dev->get_stats = wvlan_get_stats; +#ifdef WIRELESS_EXT + dev->do_ioctl = wvlan_ioctl; + dev->get_wireless_stats = wvlan_get_wireless_stats; +#endif /* WIRELESS_EXT */ + dev->change_mtu = wvlan_change_mtu; + dev->set_multicast_list = wvlan_set_multicast_list; +// dev->set_mac_address = wvlan_set_mac_address; +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,42)) + dev->tx_timeout = &wvlan_watchdog; + dev->watchdog_timeo = TX_TIMEOUT; +#endif + + // Other netdevice data + //eric@molitor.org changed to compile with 2.4.0 + //init_dev_name(dev, local->node); + strcpy (dev->name, local->node.dev_name); + dev->mtu = mtu; + netif_stop_queue(dev); + + // Register with CardServices + link->next = dev_list; + dev_list = link; + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT; + client_reg.EventMask = CS_EVENT_REGISTRATION_COMPLETE | + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.event_handler = &wvlan_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + + rc = CardServices(RegisterClient, &link->handle, &client_reg); + if (rc) + { + cs_error(link->handle, RegisterClient, rc); + wvlan_detach(link); + return NULL; + } + + DEBUG(DEBUG_CALLTRACE, "<- wvlan_attach()\n"); + return link; +} + +static void wvlan_detach (dev_link_t *link) +{ + dev_link_t **linkp; + + DEBUG(DEBUG_CALLTRACE, "-> wvlan_detach(0x%p)\n", link); + + // Locate device structure + for (linkp=&dev_list; *linkp; linkp=&(*linkp)->next) + if (*linkp == link) + break; + if (!*linkp) + { + printk(KERN_WARNING "%s: Attempt to detach non-existing PCMCIA client!\n", dev_info); + return; + } + + // If the device is currently configured and active, we won't + // actually delete it yet. Instead, it is marked so that when the + // release() function is called, that will trigger a proper + // detach() + del_timer(&link->release); + if (link->state & DEV_CONFIG) + { + DEBUG(DEBUG_INFO, "%s: wvlan_detach: detach postponed, %s still locked\n", dev_info, link->dev->dev_name); + wvlan_release((u_long)link); + if (link->state & DEV_STALE_CONFIG) + { + link->state |= DEV_STALE_LINK; + return; + } + } + + // Break the line with CardServices + if (link->handle) + CardServices(DeregisterClient, link->handle); + + // Unlink device structure, free pieces + *linkp = link->next; + if (link->priv) + { + struct net_device *dev = (struct net_device *) link->priv; + if (link->dev) + { + unregister_netdev(dev); + DEBUG(DEBUG_INFO, "%s: Netdevice unregistered\n", dev_info); + } + if (dev->priv) + kfree(dev->priv); + kfree(link->priv); + } + kfree(link); + + DEBUG(DEBUG_CALLTRACE, "<- wvlan_detach()\n"); +} + + +/******************************************************************** + * PCMCIA EVENT HANDLER + */ +static int wvlan_event (event_t event, int priority, event_callback_args_t *args) +{ + dev_link_t *link = (dev_link_t *) args->client_data; + struct net_device *dev = (struct net_device *) link->priv; + + DEBUG(DEBUG_CALLTRACE, "-> wvlan_event(%s, %d, 0x%p)\n", + ((event==CS_EVENT_REGISTRATION_COMPLETE) ? "registration complete" : + ((event==CS_EVENT_CARD_INSERTION) ? "card insertion" : + ((event==CS_EVENT_CARD_REMOVAL) ? "card removal" : + ((event==CS_EVENT_RESET_PHYSICAL) ? "physical physical" : + ((event==CS_EVENT_CARD_RESET) ? "card reset" : + ((event==CS_EVENT_PM_SUSPEND) ? "pm suspend" : + ((event==CS_EVENT_PM_RESUME) ? "pm resume" : + "unknown"))))))), priority, args); + + switch (event) + { + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + if (!wvlan_config(link) || wvlan_hw_config_locked(dev)) + dev->irq = 0; + break; + + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) + { + netif_stop_queue(dev); + netif_device_detach(dev); + mod_timer(&link->release, jiffies + HZ/20); + } + break; + + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + case CS_EVENT_RESET_PHYSICAL: + if (link->state & DEV_CONFIG) + { + if (link->open) + { + netif_stop_queue(dev); + netif_device_detach(dev); + } + CardServices(ReleaseConfiguration, link->handle); + } + break; + + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + // Fall through + case CS_EVENT_CARD_RESET: + if (link->state & DEV_CONFIG) + { + CardServices(RequestConfiguration, link->handle, &link->conf); + if (link->open) + { + struct net_local *local = + (struct net_local *) dev->priv; + unsigned long flags; + + /* IRQ currently enabled, + * so disable it */ + wv_driver_lock(local, &flags); + wvlan_hw_shutdown(dev); + wvlan_hw_config(dev); + wv_driver_unlock(local, &flags); + netif_device_attach(dev); + netif_start_queue(dev); + } + } + break; + } + + DEBUG(DEBUG_CALLTRACE, "<- wvlan_event()\n"); + return 0; +} + + +/******************************************************************** + * MODULE INSERTION / REMOVAL + */ +extern int __init init_wvlan_cs (void) +{ + servinfo_t serv; + + DEBUG(DEBUG_CALLTRACE, "-> init_module()\n"); + + printk(KERN_INFO "%s: WaveLAN/IEEE PCMCIA driver v%s\n", dev_info, version); + printk(KERN_INFO "%s: (c) Andreas Neuhaus \n", dev_info); + + // Check CardServices release + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) + { + printk(KERN_WARNING "%s: CardServices release does not match!\n", dev_info); + return -1; + } + + // Register PCMCIA driver + register_pcmcia_driver(&dev_info, &wvlan_attach, &wvlan_detach); + + DEBUG(DEBUG_CALLTRACE, "<- init_module()\n"); + return 0; +} + +extern void __exit exit_wvlan_cs (void) +{ + DEBUG(DEBUG_CALLTRACE, "-> cleanup_module()\n"); + + // Unregister PCMCIA driver + unregister_pcmcia_driver(&dev_info); + + // Remove leftover devices + if (dev_list) + DEBUG(DEBUG_INFO, "%s: Removing leftover devices!\n", dev_info); + while (dev_list) + { + if (dev_list->state & DEV_CONFIG) + wvlan_release((u_long)dev_list); + wvlan_detach(dev_list); + } + + printk(KERN_INFO "%s: Driver unloaded\n", dev_info); + DEBUG(DEBUG_CALLTRACE, "<- cleanup_module()\n"); +} + +module_init(init_wvlan_cs); +module_exit(exit_wvlan_cs); + +/******************************************************************** + * EOF + */ diff -u --recursive --new-file linux/drivers/net/pcmcia/wvlan_hcf.c linux-2.4.1-wavelan/drivers/net/pcmcia/wvlan_hcf.c --- linux/drivers/net/pcmcia/wvlan_hcf.c Wed Dec 31 18:00:00 1969 +++ linux-2.4.1-wavelan/drivers/net/pcmcia/wvlan_hcf.c Tue Jan 30 17:50:35 2001 @@ -0,0 +1,1978 @@ +/* This file is part of the Hardware Control Functions Light (HCF-light) library + to control the Lucent Technologies WaveLAN/IEEE Network I/F Card. + The HCF is the implementation of the Wireless Connection I/F (WCI). + + The HCF-light files are a subset of the HCF files. The complete set offers a + number of additional facilities, e.g. firmware download, Etherner-II encapsulation, + additional diagnostic facilities, ASSERT logic to support debugging, 802.11 support, + Configuration Management. + This complete set is explicitely not in the Public Domain but can be made + available under certain restriction. (see the pointer below for support) + + The HCF-light files are free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + At the time of this writing, you can request for support at: + betasupport@wavelan.com + + Documentation is expected to be available in the week of 8 Februari 1999 + +*/ + + +/************************************************************************************************************** +* +* FILE : HCF.CPP *************** 2.0 *********************************************************************** +* +* DATE : 2000/01/06 23:30:52 1.2 +* +* AUTHOR : Nico Valster +* +* DESC : HCF Routines hcf_action, hcf_connect, hcf_disable +* hcf_disconnect, hcf_download, hcf_enable, hcf_generate_int +* hcf_get_info, hcf_get_data, hcf_service_nic +* hcf_put_info, hcf_put_data, hcf_register_mailbox, hcf_send, +* hcf_send_diag_msg +* Local Support Routines for above procedures +* +* Customizable via HCFCFG.H, which is included by HCF.H +* +*************************************************************************************************************** +* COPYRIGHT (c) 1995 by AT&T. All Rights Reserved +* COPYRIGHT (c) 1996, 1997, 1998 by Lucent Technologies. All Rights Reserved +* +* At the sole discretion of Lucent Technologies parts of this source may be extracted +* and placed in the Public Domain under the GPL. +* This extraction takes place by means of an AWK-script acting on embedded tags. +* The AWK script is: + * BEGIN { c = 0 } + * { if ( c == 0 ) i = 1} #if in @HCF_L>..@HCF_L< block, skip + * { if (name != FILENAME ) name = FILENAME } + * + * { if ( i && c == 0 ) { print ; hcf_l_cnt++ } } + * #{ if ( i ) { print ; hcf_l_cnt++ } } + * #{if ( c == 0 ) { printf("N%d", c) ; hcf_l_cnt++ } } + * #{if ( c == 1 ) { printf("E%d", c) ; hcf_l_cnt++ } } + * + * #END { printf("%s:: HCF lines: %d, HCF_Light lines: %d", name, NR, hcf_l_cnt ) } +* +* and is not in any sense derived from the extracted source. +* +**************************************************************************************************************/ + + + + + +/**************************************************************************** +wvlan_hcf.c,v +Revision 1.2 2000/01/06 23:30:52 root +*** empty log message *** + + * + * Rev 1.0 02 Feb 1999 14:32:28 NVALST + * Initial revision. +Revision 1.3 1999/02/01 22:58:40 nico +*** empty log message *** + * + * Rev 2.12 29 Jan 1999 10:48:40 NVALST + * + * Rev 1.108 28 Jan 1999 14:43:18 NVALST + * intermediate, once more correction of loop in hcf_service_nic + download + * passed to Marc + * +****************************************************************************/ + +/************************************************************************************************************** +* +* CHANGE HISTORY +* + + 960702 - NV + Original Entry - derived from WaveLAN-I HCF 2.12 + + +* +* ToDo +* + 1: For all/most functions, update "MSF-accessible fields of Result Block:" entry + 2: Use the "numbered comments" in the NARRATIVE consistently, i.e. hcf_put_info + 3: hcf_put_data, hcf_send, hcf_send_diag_msg + once the dust is settled whether hcf_put_data or hcf_send is the appropriate place is to specify port, + it can be considered whether part of the hcf_send_diag_msg and hcf_send can be isolated in a common + routine. + 4: hcf_send_diag_msg: + - what are the appropriate return values + - once the dust is settled whether type should or shouldn't be parameter of hcf_send_diag_msg, it can + be decided whether the HFX_TX_CNTL_ABS update at each call is needed + 5: hcf_service_nic, hcf_send, hcf_send_diag_msg etc + check for a CONSISTENT strategy for the testing of IFB_CardStat, for presence, enabled, ports + 6: Decide on the relative merits of HCF_ACT_ASSERT_OFF/_ON versus CFG_REG_MSF_ASSERT + + +* +* Implementation Notes +* + - C++ style cast is not used to keep DA-C happy + - a leading marker of //! is used. The purpose of such a sequence is to help the + (maintenance) programmer to understand the flow + An example in hcf_action( HCF_ACT_802_3 ) is + //! ifbp->IFB_RxFence = 0; + which is superfluous because IFB_RxFence gets set at every hcf_service_nic but + it shows to the (maintenance) programmer it is an intentional omission at + the place where someone could consider it most appropriate at first glance + - using near pointers in a model where ss!=ds is an invitation for disaster, so be aware of how you specify + your model and how you define variables which are used at interrupt time + - Once the comment "the value of -1 for parameter len is meaningless but it guarantees that the next call + to bap_ini is interpreted as an initial call, causing the BAP to be really initialized." was considered + useful information. Does this trick still lingers somewhere;? + - remember that sign extension on 32 bit platforms may cause problems unless code is carefully constructed, + e.g. use "(hcf_16)~foo" rather than "~foo" + + +* +* Miscellaneous Notes +* + - AccessPoint performance could be improved by adding a hcf_send_pif_msg equivalent of hcf_send_diag_msg + + +*************************************************************************************************************/ + +#include "wvlan_hcf.h" // HCF and MSF common include file +#include "wvlan_hcfdef.h" // HCF specific include file + +/*************************************************************************************************************/ +/*************************************** PROTOTYPES ********************************************************/ +/*************************************************************************************************************/ +// moving these prototypes to HCFDEF.H turned out to be less attractive in the HCF-light generation +STATIC int aux_cntl( IFBP ifbp, hcf_16 cmd ); +STATIC int calibrate( IFBP ifbp ); +STATIC int cmd_wait( IFBP ifbp, int cmd_code, int par_0 ); +STATIC void enable_int(IFBP ifbp, int event ); + int hcf_initialize( IFBP ifbp ); +STATIC int ini_hermes( IFBP ifbp ); +STATIC void isr_info( IFBP ifbp ); +STATIC int put_info( IFBP ifbp, LTVP ltvp ); +STATIC hcf_16 alloc( IFBP ifbp, int len ); + + +/************************************************************************************************************** +******************************* D A T A D E F I N I T I O N S ********************************************** +**************************************************************************************************************/ + +STATIC hcf_8 BASED hcf_rev[] = "\nHCF1.2\n"; + +/* Note that the "BASED" construction (supposedly) only amounts to something in the small memory model. + * In that case CS and DS are equal, so we can ignore the consequences of casting the BASED cfg_drv_... + * structure to hcf_16 + * Note that the whole BASED riggamarole is needlessly complicated because both the Microsoft Compiler and + * Linker are unnecessary restrictive in what far pointer manipulation they allow + */ + + +/* + The below table accessed via a computed index was the original implementation for hcf_get_info with + CFG_DRV_IDENTITY, CFG_DRV_SUP_RANGE, CFG_DRV_ACT_RANGE_PRI, CFG_DRV_ACT_RANGE_STA, CFG_DRV_ACT_RANGE_HSI + as type. However it was reported that the 68K compiler for MAC OS is unable to initialize pointers. + Accepting this story at face value, the HCF is coded around this problem by implementing a direct access.. + To save part of the invested effort, the original table is kept as comment. + +STATIC LTV_STRCT* BASED xxxx[ ] = { + (LTV_STRCT*)&cfg_drv_identity, //CFG_DRV_IDENTITY 0x0826 + (LTV_STRCT*)&cfg_drv_sup_range, //CFG_DRV_SUP_RANGE 0x0827 + (LTV_STRCT*)&cfg_drv_act_range_pri, //CFG_DRV_ACT_RANGE_PRI 0x0828 + (LTV_STRCT*)&cfg_drv_act_range_sta //CFG_DRV_ACT_RANGE_STA 0x0829 + (LTV_STRCT*)&cfg_drv_act_range_hsi //CFG_DRV_ACT_RANGE_HSI 0x082A + }; +*/ + + +/************************************************************************************************************** +************************** T O P L E V E L H C F R O U T I N E S **************************************** +**************************************************************************************************************/ + + +/******************************************************************************************************************* + + +.MODULE hcf_action +.LIBRARY HCF +.TYPE function +.SYSTEM msdos +.SYSTEM NW4 +.APPLICATION Card configuration +.DESCRIPTION Changes the run-time Card behavior + +.ARGUMENTS + int hcf_action(IFBP ifbp, hcf_action_cmd action ) +.RETURNS + int + + MSF-accessible fields of Result Block: - + +.NARRATIVE + + Name: hcf_action + + Summary: Changes the run-time Card behavior + + Parameters: + ifbp address of the Interface Block + + action number identifying the type of change + + o HCF_ACT_INT_ON enable interrupt generation by WaveLAN NIC + o HCF_ACT_INT_OFF disable interrupt generation by WaveLAN NIC + o HCF_ACT_CARD_IN MSF reported Card insertion + o HCF_ACT_CARD_OUT MSF reported Card removal + + Returns: + o HCF_ACT_INT_OFF + 0: no interrupt pending + 1: interrupt pending + o all other + 0 (((however, see the special treatment for HCF_ACT_INT_ON))) + + Remarks: + o HCF_ACT_INT_OFF/HCF_ACT_INT_ON codes may be nested but must be balanced. The INT_OFF/INT_ON housekeeping + is initialized by hcf_connect with a call of hcf_action with INT_OFF, causing the interrupt generation + mechanism to be disabled at first. This suits MSF implementation based on a polling strategy. An MSFT + based on a interrupt strategy must call hcf_action with INT_ON in its initialization logic. + + o To prevent I/O while the I/O space is no longer owned by the HCF, due to a card swap, no I/O is allowed + when the CARD_STAT_PRESENT bit of IFB_CardStat is off. + +.DIAGRAM + 2: IFB_IntOffCnt is used to balance the INT_OFF and INT_ON calls. + 4: Disabling of the interrupts is simply achieved by writing a zero to the Hermes IntEn register + 5: To be able to return the information to the MSF whether an interrupt is actually pending, the Hermes + EvStat register is sampled and compared against the current IFB_IntEnMask value + 6: Originally the construction "if ( ifbp->IFB_IntOffCnt-- <= 1 )" was used in stead of + "if ( --ifbp->IFB_IntOffCnt == 0 )". This serviced to get around the unsigned logic, but as additional + "benefit" it seemed the most optimal "fail safe" code (in the sense of shortest/quickest path in error + free flows, fail safe in the sense of too many INT_ON invocations compared to INT_OFF). However when a + real life MSF programmer ran to a MSF sequence problem, exactly causing that problem, he was annoyed + with this fail safe code. As a consequence it is taken out. As a side-effect of this unhappy MSF programmer + adventures to find his problem, the return status is defined to reflect the IFBIntOffCnt, Note that this + is solely intended for aid debugging, no MSF logic should depend on this feature, No garuantees for the + future are given. + Enabling of the interrupts is achieved by writing the contents of IFB_IntEnMask to the Hermes IntEn + register. + 7: Since the card is present again, it must be re-initialized. Since this may be another card we may as well + clear all bits in IFB_CardStat and set only the "present" bit. + The first call to hcf_enable will restore the contents of HREG_INT_EN register taking the + HCF_ACT_IN_ON/OFF history in account. + 9: The MSF must call hcf_action with HCF_ACT_CARD_OUT when the MSF detects a card removal (e.g. when the MSF + is notified by the CAD). As a minimum, the "present" bit in IFB_CardStat must be reset, however since + the card insertion will clear all other bits, the simplest solution is to clear IFB_CardStat here as well. + As a result of the resetting of the CARD_STAT_PRESENT bit, no hcf-function except hcf_action with + HCF_ACT_CARD_IN results in card I/O anymore. However hcf_functions may still perform their other + activities, e.g. hcf_get_info_mb still supplies a MBIB if one is available. + As a result of the resetting of the CARD_STAT_INI bit, the call to hcf_initialize by hcf_action with + HCF_ACT_CARD_IN results in re-initialization of the NIC. +.ENDOC END DOCUMENTATION + + +**************************************************************************************************************/ +int hcf_action( IFBP ifbp, //address of the Interface Block + hcf_action_cmd action /*number identifying the type of change + */ + ) { + +int rc = HCF_SUCCESS; +//int i, j; +//hcf_16 scratch[2]; + + + + switch (action) { + case HCF_ACT_INT_OFF: // Disable Interrupt generation + ifbp->IFB_IntOffCnt++; /* 2 */ + if ( ifbp->IFB_CardStat & CARD_STAT_PRESENT ) { + OUT_PORT_WORD( ifbp->IFB_IOBase + HREG_INT_EN, 0 ); /* 4 */ + if ( IN_PORT_WORD( ifbp->IFB_IOBase + HREG_EV_STAT ) & ifbp->IFB_IntEnMask ) { /* 5 */ + rc = HCF_INT_PENDING; + } + } + break; + + case HCF_ACT_INT_ON: // Enable Interrupt generation + if ( --ifbp->IFB_IntOffCnt == 0 ) { /* 6 */ + if ( ifbp->IFB_CardStat & CARD_STAT_PRESENT ) { + OUT_PORT_WORD( ifbp->IFB_IOBase + HREG_INT_EN, ifbp->IFB_IntEnMask ); + } + } + rc = ifbp->IFB_IntOffCnt; + break; + + case HCF_ACT_CARD_IN: // MSF reported Card insertion /* 7 */ + ifbp->IFB_CardStat = CARD_STAT_PRESENT; + hcf_initialize ( ifbp ); + + if ( ifbp->IFB_CardStat & CARD_STAT_ENABLED ) { + (void)hcf_enable( ifbp, 0 ); + } + break; + + case HCF_ACT_CARD_OUT: // MSF reported Card removal /* 9 */ + ifbp->IFB_CardStat = 0; + break; + + + case HCF_ACT_TALLIES: // Hermes Inquire Tallies (F100) command /*12 */ + action = (hcf_action_cmd)(action - HCF_ACT_TALLIES + CFG_TALLIES); + if ( ifbp->IFB_CardStat & CARD_STAT_ENABLED ) { + rc = cmd_wait( ifbp, HCMD_INQUIRE, action ); + } + break; + + + + + default: + break; + } + return rc; +}/* hcf_action */ + + + +/******************************************************************************************************************* + +.MODULE hcf_connect +.LIBRARY HCF +.TYPE function +.SYSTEM msdos +.SYSTEM unix +.SYSTEM NW4 +.APPLICATION Card Initialization Group for WaveLAN based drivers and utilities +.DESCRIPTION Initializes Card and HCF housekeeping + +.ARGUMENTS + void hcf_connect( IFBP ifbp, hcf_io io_base ) + +.RETURNS + n.a. + + MSF-accessible fields of Result Block: + IFB_IOBase entry parameter io_base + IFB_IORange HREG_IO_RANGE (0x40) + IFB_HCFVersionMajor the major part of the PVCS maintained version number + IFB_HCFVersionMinor the minor part of the PVCS maintained version number + IFB_Version version of the IFB layout (0x01 for this release) + +.NARRATIVE + + Parameters: + ifbp address of the Interface Block + io_base I/O Base address of the NIC + + + Hcf_connect grants access right for the HCF to the IFB and initializes the HCF housekeeping part of the + IFB. Hcf_connect does not perform any I/O. + + The HCF-Version fields are set dynamically, because I do not know of any C mechanism to have the compiler + and the version control system (PVCS) cooperate to achieve this at compile time. The HCFVersions fields are + constructed by collecting and shifting the low order nibbles of the PVCS controlled ASCII representation. + Note that the low order nibble of a space (0x20) nicely coincides with the low order nibble of an ASCII '0' + (0x30). Also note that the code breaks when major or minor number exceeds 99. + + +.DIAGRAM + 1: patch_catch is called as early in the flow as the C-entry code allows to help the HCF debugger as much as + possible. The philosophy behind patch_catch versus a simple direct usage of the INT_3 macro is explained + in the description of patch_catch + 2: The IFB is zero-filled. + This presets IFB_CardStat and IFB_TickIni at appropriate values for hcf_initialize. +10: In addition to the MSF readable fields mentioned in the description section, the following HCF specific + fields are given their actual value: + - a number of fields as side effect of the calls of hcf_action (see item 14) + - IFB_Magic + IFB_VERSION, which reflects the version of the IFB layout, is defined in HCF.H +14: Hcf_connect defaults to "no interrupt generation" (by calling hcf_action with the appropriate parameter), + "802.3 frame type" and "no card present" (implicitly achieved by the zero-filling of the IFB). + Depending on HCFL, the 802.3 frame type is either initialized in line or by calling hcf_action. + +.NOTICE + If io_base ever needs to be dynamic, it may be more logical to pass + - io_base at hcf_enable or + - have a separate hcf_put_config command or + - demand a hcf_disconnect - hcf_connect sequence + +.NOTICE + On platforms where the NULL-pointer is not a bit-pattern of all zeros, the zero-filling of the IFB results + in an seemingly incorrect initialization of IFB_MBp. The implementation of the MailBox manipulation in + put_mb_info protects against the absence of a MailBox based on IFB_MBSize, IFB_MBWp and ifbp->IFB_MBRp. This + has ramifications on the initialization of the MailBox via hcf_put_info with the CFG_REG_MB type. + +.ENDOC END DOCUMENTATION +-------------------------------------------------------------------------------------------------------------*/ +void hcf_connect( IFBP ifbp, //address of the Interface Block + hcf_io io_base //I/O Base address of the NIC + ) { + +hcf_8 *q; + +#if defined _M_I86TM +#endif // _M_I86TM + + + for ( q = (hcf_8*)&ifbp[1]; q > (hcf_8*)ifbp; *--q = 0) /*NOP*/; /* 2 */ + + ifbp->IFB_Version = IFB_VERSION; /* 10*/ + ifbp->IFB_IOBase = io_base; + ifbp->IFB_IORange = HREG_IO_RANGE; + ifbp->IFB_Magic = HCF_MAGIC; + ifbp->IFB_HCFVersionMajor = (hcf_8)( (hcf_rev[REV_OFFSET] << 4 | hcf_rev[REV_OFFSET+1]) & 0x0F ); + ifbp->IFB_HCFVersionMinor = (hcf_8)( hcf_rev[REV_OFFSET+4] == ' ' ? + hcf_rev[REV_OFFSET+3] & 0x0F : + (hcf_rev[REV_OFFSET+3] << 4 | hcf_rev[REV_OFFSET+4]) & 0x0F ); + + (void)hcf_action(ifbp, HCF_ACT_INT_OFF ); /* 14*/ + ifbp->IFB_FSBase = HFS_ADDR_DEST_ABS; + return; +}/* hcf_connect */ + + + + + +/******************************************************************************************************************* + +.MODULE hcf_disable +.LIBRARY HCF +.TYPE function +.SYSTEM msdos +.SYSTEM unix +.SYSTEM NW4 +.APPLICATION Card Initialization Group for WaveLAN based drivers and utilities +.DESCRIPTION Disables data transmission and reception +.ARGUMENTS + int hcf_disable( IFBP ifbp, hcf_16 port ) + +.RETURNS + HCF_SUCCESS + HCF_ERR_NO_NIC + HCF_ERR_TIME_OUT (via cmd_wait) + HCF_FAILURE (via cmd_wait) + + MSF-accessible fields of Result Block: + IFB_CardStat - reset CARD_STAT_ENABLED bit iff at completion no port enabled anymore + +.NARRATIVE + + Parameters: + ifbp address of the Interface Block + + Condition Settings: + Card Interrupts - Unchanged + - Disabled (Note that the value of IFB_IntOffCnt is unchanged) + + +.NOTICE + o hcf_disable may disable the card interrupts, however it does NOT influence IFB_IntOffCnt. + This way it is symmetrical with hcf_enable, which does NOT enable the card interrupts. + +**************************************************************************************************************/ +int hcf_disable( IFBP ifbp, hcf_16 port ) { + +int rc; +//hcf_16 p_bit; + + rc = cmd_wait( ifbp, HCMD_DISABLE | (port << 8 ), 0 ); + ifbp->IFB_CardStat &= (hcf_16)~CARD_STAT_ENABLED; + (void)hcf_action( ifbp, HCF_ACT_INT_OFF ); /* 40 */ + ifbp->IFB_IntOffCnt--; + return rc; +}/* hcf_disable */ + + + +/******************************************************************************************************************* + + +.MODULE hcf_disconnect +.LIBRARY HCF +.TYPE function +.SYSTEM msdos +.SYSTEM NW4 +.APPLICATION Card Connection for WaveLAN based drivers and utilities +.DESCRIPTION + Disable transmission and reception, release the IFB +.ARGUMENTS + void hcf_disconnect( IFBP ifbp ) +.RETURNS + void + + MSF-accessible fields of Result Block: + IFB_CardStat cleared + +.NARRATIVE + Parameters: + ifbp address of the Interface Block + + Description: + Brings the NIC in quiescent state by calling hcf_initialize, thus preventing any interrupts in the future. + +.DIAGRAM + 1: hcf_initialize gives a justification to execute the Hermes Initialize command only when really needed. + Despite this basic philosophy and although the HCF can determine whether the NIC is initialized based + on IFB_CardStat, the minimal set of actions to initialize the Hermes is always done by calling + ini_hermes. + 5: clear all IFB fields + The clearing of IFB_CardStat prevents I/O on any subsequent hcf_function + +.ENDOC END DOCUMENTATION +-------------------------------------------------------------------------------------------------------------*/ +void hcf_disconnect( IFBP ifbp ) { + +hcf_8 *q; + + + ini_hermes( ifbp ); + + for ( q = (hcf_8*)&ifbp[1]; q > (hcf_8*)ifbp; *--q = 0) /*NOP*/; /* 5 */ + +}/* hcf_disconnect */ + + + + + +/******************************************************************************************************************* + + +.MODULE hcf_enable +.LIBRARY HCF +.TYPE function +.SYSTEM msdos +.SYSTEM unix +.SYSTEM NW4 +.APPLICATION Card Initialization Group for WaveLAN based drivers and utilities +.DESCRIPTION Enables data transmission and reception +.ARGUMENTS + int hcf_enable( IFBP ifbp, hcf_16 port ) +.RETURNS + HCF_SUCCESS + HCF_ERR_TIME_OUT (via cmd_wait) + HCF_FAILURE (via cmd_wait) + + MSF-accessible fields of Result Block + + Condition Settings: + Card Interrupts: Off if IFB_IntOffCnt > 0; On if IFB_IntOffCnt == 0 + (Note that the value of IFB_IntOffCnt is unchanged) + +.NARRATIVE + Parameters: + ifbp address of the Interface Block + + Description: + + hcf_enable takes successively the following actions: + 6: If the requested port is disabled and if the NIC is present, the Hermes Enable command is executed. + If CARD_STAT_PRESENT is off, the body of hcf_enable must be skipped to prevent I/O because the I/O space + may no longer owned by the HCF, due to a card swap. + The IFB_IntEnMask is set to allow Info events, Receive events and Allocate events to generate interrupts + and effectuated if appropriate based on IFB_IntOffCnt by calling enable_int. + Note that since the effect of interrupt enabling has no effect on IFB_IntOffCnt, this code may + be called not only at the transition from disabled to enabled but whenever a port is enabled. +12: When the port successfully changes from disabled to enabled - including the case when no NIC is + present - , the NIC status as reflected by IFB_CardStat must change to enabled + +.DIAGRAM + +.NOTICE + When the Hermes enable cmd is given, the static configuration of the Hermes is done. +.ENDOC END DOCUMENTATION + +-------------------------------------------------------------------------------------------------------------*/ +int hcf_enable( IFBP ifbp, hcf_16 port ) { + +int rc; + + + + if ( (ifbp->IFB_CardStat & CARD_STAT_PRESENT) == 0 + ) { rc = HCF_ERR_NO_NIC; } /* 6 */ + else { + rc = HCF_SUCCESS; + rc = cmd_wait( ifbp, HCMD_ENABLE | ( port << 8 ), 0 ); + if ( rc == HCF_SUCCESS ) enable_int( ifbp, HREG_EV_INFO | HREG_EV_RX | HREG_EV_ALLOC ); /* 8 */ + } + if ( rc == HCF_SUCCESS || rc == HCF_ERR_NO_NIC ) { + ifbp->IFB_CardStat |= CARD_STAT_ENABLED; + } + return rc; + +}/* hcf_enable */ + + + +/******************************************************************************************************************* + + +.MODULE hcf_get_data +.LIBRARY HCF +.TYPE function +.SYSTEM msdos +.SYSTEM unix +.APPLICATION Data Transfer Function for WaveLAN based drivers and utilities +.DESCRIPTION + Obtains received message data parts from NIC RAM +.ARGUMENTS + int hcf_get_data( IFBP ifbp, int offset, wci_bufp bufp, int len ) + Card Interrupts disabled +.RETURNS + hcf_16 + zero NIC not removed during data copying process + HCF_ERR_NO_NIC NIC removed during data copying process + ...... + + MSF-accessible fields of Result Block: - + +.NARRATIVE + parameters: + ifbp address of the Interface Block + offset offset (in bytes) in buffer in NIC RAM to start copy process + len length (in bytes) of data to be copied + bufp char pointer, address of buffer in PC RAM + + When hcf_service_nic reports the availability of data, hcf_get_data can be + called to copy that data from NIC RAM to PC RAM. + + Hcf_get_data copies the number of bytes requested by the parameter len from + NIC RAM to PC RAM. If len is larger than the (remaining) length of the + message, undefined data is appended to the message. This implies that if + hcf_get_data is called while the last hcf_service_nic reported no data + available, undefined data is copied. + + Hcf_get_data starts the copy process at the offset requested by the + parameter offset, e.g. offset HFS_ADDR_DEST will start copying from the + Destination Address, the very begin of the 802.3 framemessage. + In case of a fragmented PC RAM buffer, it is the responsibility of the MSF, + to specify as offset the cumulative values of the len parameters of the + preceeding hcf_get_data calls. This I/F gives a MSF the facility to read + (part of) a message and then read it again. + +.DIAGRAM +.ENDOC END DOCUMENTATION + + +-------------------------------------------------------------------------------------------------------------*/ +int hcf_get_data( IFBP ifbp, int offset, wci_bufp bufp, int len ) { + +int rc = HCF_SUCCESS; +//int tlen; + + + if ( ifbp->IFB_CardStat & CARD_STAT_PRESENT ) { + if ( offset < 0 ) offset -= HFS_STAT; + else { + offset += ifbp->IFB_FSBase; + } + if ( rc == HCF_SUCCESS ) rc = hcfio_string( ifbp, BAP_1, ifbp->IFB_RxFID, offset, bufp, 0, len, IO_IN ); + } + return rc; +}/* hcf_get_data */ + + + + +/************************************************************************************************************** + + + Name: hcf_get_info + + Summary: Obtains transient and persistent configuration information from the + Card and from the HCF + + Parameters: + ifbp address of the Interface Block + + ltvp address of LengthTypeValue structure specifying the "what" and the "how much" of the information + to be collected from the HCF or from the Hermes + + Returns: + int + ..... ???????????????? + + Remarks: Transfers operation information and transient and persistent + configuration information from the Card and from the HCF to the MSF. + The exact layout of the provided data structure + depends on the action code. Copying stops if either the complete + Configuration Information is copied or if the number of bytes indicated + by len is copied. Len acts as a safe guard against Configuration + Information blocks which have different sizes for different Hermes + versions, e.g. when later versions support more tallies than earlier + versions. It is a consious decision that unused parts of the PC RAM buffer are not cleared. + + Remarks: The only error against which is protected is the "Read error" + as result of Card removal. Only the last hcf_io_string need + to be protected because if the first fails the second will fail + as well. Checking for cmd_wait errors is supposed superfluous because + problems in cmd_wait are already caught or will be caught by + hcf_enable. + + + 3: tallying of "No inquire space" is done by cmd_wait + + Note: + the codes for type are "cleverly" chosen to be identical to the RID + + + 7: The return status of cmd_wait and the first hcfio_in_string can be ignored, because when one fails, the + other fails via the IFB_TimStat mechanism + +**************************************************************************************************************/ +int hcf_get_info(IFBP ifbp, LTVP ltvp ) { + +int rc = HCF_ERR_LEN; +//hcf_io reg; +hcf_16 i, len; +hcf_16 type; //don't change type to unsigned cause of "is it a RID" test +hcf_16 *q; //source pointer (Tally-part of IFB) +//hcf_16 FAR *bq; //source pointer (Identity or Range records) ;?why bq and not e.g. wq +wci_recordp p = ltvp->val; //destination word pointer (in LTV record) +//wci_bufp cp = (wci_bufp)ltvp->val; //destination char pointer (in LTV record) + + + len = ltvp->len; + type = ltvp->typ; + + if ( len > 1 ) { + + rc = HCF_SUCCESS; + switch ( type ) { + +#if MSF_COMPONENT_ID != COMP_ID_AP1 + case CFG_TALLIES: /* 3 */ + ltvp->len = len = min( len, (hcf_16)(HCF_TOT_TAL_CNT + HCF_TOT_TAL_CNT + 1) ); + q = (hcf_16*)/*(wci_recordp)*/&ifbp->IFB_NIC_Tallies; //.TxUnicastFrames; + while ( --len ) *p++ = *q++; + (void)hcf_action( ifbp, HCF_ACT_TALLIES ); + break; +#endif //COMP_ID_AP1 + + + + + + default: + rc = HCF_ERR_NO_NIC; + if ( ifbp->IFB_CardStat & CARD_STAT_PRESENT ) { + rc = HCF_ERR_TIME_OUT; + if ( type < CFG_RID_CFG_MIN ) { + ltvp->len = 0; + } else { + (void)cmd_wait( ifbp, HCMD_ACCESS, type ); /* 7 */ + (void)hcfio_string( ifbp, BAP_1, type, 0, (wci_bufp)&i, 1, sizeof(hcf_16), IO_IN ); + ltvp->len = min( i, len ); + rc = hcfio_string( ifbp, BAP_1, type, sizeof(hcf_16), (wci_bufp)<vp->typ, 1, MUL_BY_2(ltvp->len), IO_IN ); + if ( rc == HCF_SUCCESS && i > len ) rc = HCF_ERR_LEN; + } + } + } + } + return rc; + +}/* hcf_get_info */ + + +/******************************************************************************************************************* + +.MODULE hcf_initialize ;?in fact an hcf-support routine, given an hcf_... name just in case we want to + export it over the WCI later +.LIBRARY HCF +.TYPE function +.SYSTEM msdos +.SYSTEM unix +.SYSTEM NW4 +.APPLICATION Card Initialization Group for WaveLAN based drivers and utilities +.DESCRIPTION ..........., in addition, a light-weight diagnostic test of the NIC +.ARGUMENTS + int hcf_initialize( IFBP ifbp ) + +.RETURNS + HCF_SUCCESS + HCF_ERR_NO_NIC + HCF_ERR_TIME_OUT; + HCF_FAILURE (via cmd_wait) + (via hcf_get_info) + HCF_ERR_INCOMP_PRI + HCF_ERR_INCOMP_STA + + MSF-accessible fields of Result Block: + IFB_DUIFRscInd, IFB_NotifyRscInd, IFB_PIFRscInd cleared + IFB_MBInfoLen, IFB_RxLen, IFB_RxStat cleared + IFB_CardStat - CARD_STAT_ENA_0 through CARD_STAT_ENA_6 + - CARD_STAT_INCOMP_PRI + - CARD_STAT_INCOMP_STA + + +.NARRATIVE + + Parameters: + ifbp address of the Interface Block + + hcf_initialize will successively: + - initialize the NIC by calling ini_hermes + - calibrate the S/W protection timer against the Hermes Timer by calling calibrate + + Condition Settings: + Card Interrupts: Disabled (Note that the value of IFB_IntOffCnt is unchanged) + + Remarks: since hcf_initialize is the first step in the initialization of the card and since the strategy is to + detect problems as a side effect of "necessary" actions, hcf_initialize has, in deviation of the general + strategy, an additional "wait for busy bit drop" at all places where Hermes commands are executed. An + additional complication is that no calibrated value for the protection count can be assumed since it is + part of the first execution of hcf_disable to determine this calibrated value (a catch 22). The initial + value (set at INI_TICK_INI by hcf_connect) of the protection count is considered safe, because: + o the HCF does not use the pipeline mechanism of Hermes commands. + o the likelihood of failure (the only time when protection count is relevant) is small. + o the time will be sufficiently large on a fast machine (busy bit drops on good NIC before counter expires) + o the time will be sufficiently small on a slow machine (counter expires on bad NIC before the enduser + switches the power off in despair + IFB_TickIni is used in cmd_wait to protect the Initialize command. The time needed to wrap a 32 bit counter + around is longer than many humans want to wait, hence the more or less arbitrary value of 0x10000L is + chosen, assuming it does not take too long on an XT and is not too short on a scream-machine. + Once we passed the CARD_STAT_PRESENT test on IFB_CardStat, the other bits can be reset. This is needed + to have a dynamical adjustment of the Station/Primary Incompatibility flags. + Especially IFB_TimStat must be cleared (new round, new chances) + + Remarks: First the HCF disables the generation of card interrupts. Next it waits for the Busy bit in the + Command register to drop (the additional safety required for hcf_initialize as described above). If the Hermes + passes this superficial health test, the Hermes Initialize command is executed. The Initialize command acts + as the "best possible" reset under HCF control. A more "severe/reliable" reset is under MSF control via the + COR register. + + Remarks: If the Initialize of the Hermes succeeds, the S/W protection counter is calibrated if not already + calibrated. This calibration is "reasonably" accurate because the Hermes is in a quiet state as a result of + the Initialize command. The hcf_put_info function is used to program the Hermes Tick for its minimum + interval (1024 microseconds). Programming the Tick interval terminates the old interval timing immediately + and starts the new interval. Due to this ad-hoc switch the first interval has a larger inaccuracy. By + timing immediately a second interval the accuracy improves due to the synchronization of HCF and Hermes. + After this second interval, the Hermes Tick is programmed for its default value of 1 second again. + +.NARRATIVE + 2: Clear all fields of the IFB except those which need to survive hcf_initialize. This is intended to make + the behavior and - as a consequence - the debugging of the HCF more reproduceable. + + 3: Disable the interrupt generation facility (see also #30) + 5: Depending on whether there is selective disabling of a single port or a collective disabling of + all ports a specific bit or all bits representing the enabled ports are reset. In case of "all ports" + none of the other bits except CARD_STAT_ENABLED is relevant, so as an easy implementation all those + other bits are cleared. + The individual bits conveyed in IFB_CardStat are historically grown. To leave the WCI unchanged, the + individual "port enabled" bits are scattered through IFB_CardStat. As a consequence there is some bit + arithmetic involved to convert a port number to a bit flag + The masking of port with HCF_PORT_MASK is a cheap safeguard against I/F violations by the MSF. If the MSF + supplies an invalid bit pattern, unwanted bits may end up in Hermes Command register via Disable command + with unpredictable effects. + 7: Check whether CARD_STAT_PRESENT bit of IFB_CardStat is on. If not the remainder of hcf_initialize must be + skipped to prevent I/O because the I/O space may no longer owned by the HCF, due to a card swap. +12: When a single port must be disabled AND it is not the only enabled port, that port is selectively + disabled. If all ports or the only enabled port is to be disabled, the disabling is skipped and the + Hermes Initiate command is supposed to take care of it all. +16: perform a superficial Hermes health test. Note that in hcf_initialize all (or at least most) activities are + checked for conditions like "Busy bit should drop". If such a condition is not met in time, hcf_initialize + returns an error code. Hcf_functions which are only called during "normal" operations may ignore such + events. Their only obligation is to prevent that the code hangs. + Note that early models of the Hermes needed some arbitrary read before the first write activity to operate + stable (ref tracker 27). This code achieves that function as a side effect. +18: Initialize the Hermes. The results of this way of initialization depends on the capabilities of the Hermes + firmware. Therefore, the Hermes H/W controlled bits, like those in the evitable register are not guaranteed + to be cleared as result of the initialize command. However it is guaranteed that no more events are in the + pipeline. Ack-ing indiscriminately all events resolves this problem. An alternative would be to use the + resulting value of "IN_PORT_WORD( ifbp->IFB_IOBase + HREG_EV_STAT )" rather than 0xFFFF to specifically + only reset those events which are set. This strategy is considered to be only more aesthetically pleasing + (if that). +20: Perform some housekeeping tasks + - Write HCF_MAGIC as signature to S/W support register 0. This signature is used to detect card removal + wherever the presence of the card is critical while HCF may not yet have been informed by the MSF of the + removal of the card. Note that this task can not be postponed because that would cause the hcfio_in_string + called by hcf_get_info to fail +22: + + - IFB_TickIni must be initialized (at INI_TICK_INI) to prevent that actions like hcf_put_info immediately + after hcf_connect (that is without intervening hcf_disable) at an absent (or failing) NIC take too + long. Note that this is a legal hcf-sequence according to the WCI-specification. + + + + + IFB_TickIni is the value used to initialize the S/W protection counter in a way which makes the + expiration period more or less independent of the processor speed. If IFB_TickIni is not yet calibrated, + it is done now. + First off all the Hermes Tick period is programmed for a "reasonable" interval, currently 8092 or 8k + microseconds, by means of hcf_put_info. Note that IFB_DLTarget, which is guaranteed to get the correct + value later on in hcf_enable, is misused as re-entrant storage for the RID used to program the Tick period. + The HCF synchronizes itself with the Hermes timer by waiting for the first timer tick. This synchronizing is done by + ack-ing the Tick regardless of its current value. This guarantees Tick becomes low. Then Tick is sampled + till it is high, which guarantees a new complete interval starts in the Hermes. Tick is acked again and + another Tick is awaited. This period is as accurate as we can get. + To diminish the chance that in a pre-emptive environment IFB_TickIni is calibrated too low because the HCF + just happens to loose control during this calibration, the calibration is performed 10 times and the + largest value is used. + IFB_TickIni is then set at approximately 1 second by multiplying that largest value by 128. The 8k + microseconds interval and the multiplication by 128 are chosen as a compromise between accuracy of + the calibration. time consumed by the calibration and possibilities for the compiler to optimize + the arithmetic. +26: Finally the Hermes Tick period is programmed for a "reasonable" runtime interval, currently 1 second + (1,000,000/1,024 kilo-microseconds), by means of hcf_put_info (again the available CONCATENATED storage + is misused) + Note that in case of failure, IFB_TickIni ends up as INI_TICK_INI, which is a supposedly acceptable + value to handle the rare case of a broken card. +30: The Supplier Range of the Primary Firmware function is retrieved from the Hermes and checked against + the Top and Bottom level supported by this HCF. + If the primary firmware does not supply this RID or supplies the "old" HardwareStructure Info, the + Primary Compatibility check is skipped. These conditions are recognized based on the length field supplied + by the Hermes. ;?is this wise in the post-GCA area +32: In case of a HCF compiled for station functionality, the Supplier Range of the Station Firmware function + is retrieved from the Hermes and checked against the Top and Bottom level supported by this HCF. + Note that the Firmware can have multiple Variants, but that the HCF currently only supports a single + variant. +40: Perform some more housekeeping tasks + - Decrement ifbp->IFB_IntOffCnt to compensate side effect of ACT_INT_OFF action at begin of hcf_initialize (see + #2). This can not be handled by calling hcf_action with HCF_ACT_ON, because this could as undesirable + side effect actually enable interrupts + +.NOTICE + o For all practical WCI purposes there is no practical difference between a Hermes disable command at all + individual ports and an hermes initialize command + o hcf_initialize disables the card interrupts, however it does NOT influence IFB_IntOffCnt. + This way it is symmetrical with hcf_enable, which does NOT enable the card interrupts. + + + IFB_CardStat - CARD_STAT_INCOMP_PRI + - CARD_STAT_INCOMP_STA + + 5: The house keeping is done, consisting of the steps: + - allocate a Tx Frame Structure for the protocol stack + - allocate a Tx Frame Structure for the utility + - allocate a Information Frame Structure for the Notify command + Note that a subsequent allocate is only performed if the preceding one + succeeded + - if all allocates succeeded, the Resource Indicators corresponding + with the Tx Frames are set + + +**************************************************************************************************************/ +int hcf_initialize( IFBP ifbp ) { + +int rc; +//hcf_16 *p; +hcf_8 *q; + + + for ( q = (hcf_8*)&ifbp->IFB_PIFRscInd; q < (hcf_8*)&ifbp[1]; *q++ = 0) /*NOP*/; /* 2 */ + +// if ( (ifbp->IFB_CardStat & CARD_STAT_INI) == 0 ) { //present but not initialized /* 7 */ + do { //;?CARD_STAT_PRESENT check superfluous as long as hcf_initialize is not defined on the WCI + rc = ini_hermes( ifbp ); + if ( rc != HCF_SUCCESS ) break; /* 32*/ + OUT_PORT_WORD( ifbp->IFB_IOBase + HREG_SW_0, HCF_MAGIC ); /* 20*/ + rc = calibrate( ifbp ); /* 22*/ + if ( rc != HCF_SUCCESS ) break; + +#if defined MSF_COMPONENT_ID //;?interesting question at which level HCFL interacts +#endif // MSF_COMPONENT_ID + ifbp->IFB_CardStat |= CARD_STAT_INI; //consider this as sufficient to reach CARD_STAT_INI? /* 24*/ + if ( rc != HCF_SUCCESS ) break; //;? apparently this still should follow the moved IFB_DLTarget logic but + //;? think this over for the different scenarios + if ( ( ifbp->IFB_PIF_FID = alloc( ifbp, HFS_TX_ALLOC_SIZE ) ) == 0 || /* 5 */ + ( ifbp->IFB_DUIF_FID = alloc( ifbp, HFS_TX_ALLOC_SIZE ) ) == 0 ) { + rc = HCF_FAILURE; + } else { + ifbp->IFB_PIFRscInd = ifbp->IFB_DUIFRscInd = 1; + + } + } while ( 0 ); //pseudo goto-less, accept "warning: conditional expression is constant" + + return rc; +}/* hcf_initialize */ + + +/******************************************************************************************************************* + + +.MODULE hcf_put_data +.LIBRARY HCF +.TYPE function +.SYSTEM msdos +.SYSTEM unix +.SYSTEM NW4 +.APPLICATION Data Transfer Function for WaveLAN based drivers and utilities +.ARGUMENTS + void hcf_put_data( IFBP ifbp, wci_bufp bufp, int len, hcf_16 port ) + Card Interrupts disabled + +.RETURNS + void + + MSF-accessible fields of Result Block: - + +.DESCRIPTION Transfers (part of) transmit message to the NIC and handles + the Ethernet-II encapsulation if applicable +.NARRATIVE + parameters: + ifbp address of the Interface Block + bufp char pointer, address of buffer in PC RAM + len length (in bytes) of data to be copied + port HCF_PORT_0 - HCF_PORT_6 .........;? + HCF_PUT_DATA_RESET + + + Refer to hcf_service;?non-existing reference, for a concise description about possible + relation/sequencing of hcf_put_data in the Interrupt Service Routine + + In essence, hcf_put_data copies the number of bytes specified by parameter len from the location in PC + RAM specified by bufp to the NIC RAM buffer associated with the Protocol Stack dedicated FID. + The first call succeeding hcf_send (or hcf_enable), writes the first byte at offset HFS_ADDR_DEST in + the transmit data buffer, successive hcf_put_data calls continue where the preceeding hcf_put_data stopped. + + IFB_FrameType determines whether the message in the PC RAM buffer is interpreted as an 802.3 or 802.11 + frame. This influences: + o the position where the first byte of the initial hcf_put_data is stored + o Only in case of the 802.3 frame type, hcf_put_data checks whether the frame is an Ethernet-II rather + than an "official" 802.3 frame. The E-II check is based on the length/type field in the MAC header. If + this field has a value larger than 1500, E-II is assumed. The implementation of this test fails if the + length/type field is split over 2 hcf_put_data calls. + If E-II is recognized, the length field HFS_LEN_ABS is skipped for the time being and a SNAP header is + inserted starting at HFS_DAT_ABS. This SNAP header represents either RFC1042 or Bridge-Tunnel + encapsulation, depending on whether the type is absent or present in enc_trans_tbl. + o In case of the 802.11 frame type, hcf_put_data checks whether the complete header + length field is + written (note that part of the header may be written by previous hcf_put_data calls and part may be + written by this call). If so, the next byte is written at HFS_DAT_ABS (the 802.3 header area is skipped) + + It is allowed to write the 802.3 header, 802.11 header and/or data in fragments, e.g. the first + hcf_put_data call writes 18 bytes starting at location HFS_ADDR_1_ABS and the second call writes 6 more + bytes starting at location HFS_ADDR_4. Although Address part #4 is not present in some 802.11 headers, + all 4 addressing parts and the length field must be written in case of 802.11. Once the complete header + is written, the data part is written starting from offset HFS_DAT_ABS. + + Hcf_put_data does not check for transmit buffer overflow because the Hermes does this protection. + In case of a transmit buffer overflow, the surplus which does not fit in the buffer is simply dropped. + Note that this possibly results in the transmission of incomplete frames. + +.DIAGRAM +1*: If the card is not present, prevent all I/O because "our" I/O base may have been given away to someone + else in a CS/SS environment. Also no I/O should be performed if the NIC is not enabled. However + an MSF which calls hcf_put_data while the NIC is not enabled probably contains a logic flaw (or has a + strategy which was not foreseen at the time this was written) +10* HCF_PUT_DATA_RESET discards all the data put by preceeding hcf_put_data calls and resets the HCF + housekeeping just the same as after an hcf_send triggered allocate event. + Note: To make the WCI fail-safe, invalid port numbers are silently rejected by treating them as + HCF_PUT_DATA_RESET. Note that the assumption is that this should never ever occure in a debugged MSF and + that during debugging the ASSERT is sufficient support to help the MSF programmer. +2*: This statement is only true at the first hcf_put_data call after an hcf_send result or hcf_enable + The housekeeping is done. + o the PIFRscInd is cleared, so the MSF can not begin another hcf_put_data/hcf_send sequence + before completing the current one + o the Tx Encoding flag (TxFrameType) is cleared + o the index to the first free position in the FID (IFB_PIFLoadIdx) is initialized based on IFB_FSBase. + IFB_FSBase is initialized when hcf_action is called with HCF_ACT_802_3 or HCF_ACT_802_11 +3*: Pay Attention: it may seem attractive to change this code, e.g. to save the superfluous call to + hcfio_out_string when the Destination and Source address are written by the preceeding call and the + current call starts at the length/type field. However this code is "reasonably carefully" crafted + to take in account all boundary conditions. It is very easy to make a change which does not work under + all feasible split ups of the message in fragments. + First IFB_PIFLoadIdx is checked. + - If IFB_PIFLoadIdx points past HFS_LEN_ABS, the preceeding call(s) to hcf_put_data already passed the + length/type field. As a consequence the fragment can be concatenated to the data already copied to + NIC RAM. + - If IFB_PIFLoadIdx does not point past HFS_LEN_ABS, the current fragment may or may not contain part of + the Destination and/or Source Address and it may or may not contain the length/type field. + If the fragment contains addressing information or -in case of 802.11- length info , this information + is copied/concatenated to the NIC RAM buffer. The working variables (pointer and length of fragment) as + well as the IFB_PIFLoadIdx are adjusted. + The semi-obscure differences in the boundary testing are caused by: + o 802.11: the "below the boundary" area is Addr1, Addr2, Addr3, Ctrl, Adrr4 + DataLen and the "above" + area is the "real" data + o 802.3: the "below the boundary" area is DestAddr + SrcAddr and the "above" area is the length + + "real" data + o E-II: the "below the boundary" area is DestAddr + SrcAddr, then there is a "virtual" area with the + SNAP header (which will in the end include the HCF calculated length) and the "above" area is the + "protocol stack length" (is in reality the type code) + "real" data +4*: If there is still data left, IFB_PIFLoadIdx may need adjustment (802.11 and E-II encapsulation). Again + note that this length check is crucial to prevent mis-manipulation of IFB_PIFLoadIdx in case the header + is written in multiple fragments. + In case of 802.3, the E-II check is done. In case of E-II, the encapsulation type (RFC1042 versus + Bridge-Tunnel) is determined and the corresponding SNAP header is written to NIC RAM and + IFB_PIFLoadIdx is adjusted. +6*: All data which is not already copied under 3*, is copied here. + In case of 802.11, the HFS_DAT field is the first field written by this code. + In case of 802.3, the HFS_LEN field is the first field written by this code. + In case of E-II encapsulation, the HFS_TYPE field is the first field written by this code. + Note that in case of E-II encapsulation, the HFS_LEN field is not written by hcf_put_data at all, but by + hcf_send because the data length is not known till all fragments have been processed. + +.NOTE + The possible split of a single hcf_put_data call into 2 calls to hcfio_out_string results in 2 calls + to bap_ini, which may be unexpected while you are debugging, but is never the less the intended behavior. + Along the same line a call of hcfio_out_string with a value of 0 for parameter len may be unexpected, e.g. + when the len parameter of hcf_put_data is either 1 or 2, the latter depending on the odd/even aspects of + IFB_PIFLoadIdx. + + + +.NOTE + The test on PIFRscInd to distinguish the initial hcf_put_data from subsequent calls is not thread safe. + It is assumed that threaded MSFs have their own mechanism to assure that hcf_put_data calls belonging to + a single frame are atomic with respect to each other. It is also assumed that the MSF takes care that + the hcf_put_data calls of multiple frames do not run concurrent + + +.ENDOC END DOCUMENTATION + + +-------------------------------------------------------------------------------------------------------------*/ +void hcf_put_data( IFBP ifbp, wci_bufp bufp, int len, hcf_16 port ) { + +int idx; //working index into Tx Frame structure, presume MSF control +//int tlen; //working type/length of frame, working length for partial copy of frame + + + if ( ifbp->IFB_CardStat & CARD_STAT_PRESENT ) { /* 1 */ + if ( ifbp->IFB_PIFRscInd ) { /* 2 */ + ifbp->IFB_PIFRscInd = 0; + ifbp->IFB_PIFLoadIdx = ifbp->IFB_FSBase; //;? should result in 0 + } + + idx = ifbp->IFB_PIFLoadIdx; + ifbp->IFB_PIFLoadIdx += (hcf_16)len; + (void)hcfio_string( ifbp, BAP_0, ifbp->IFB_PIF_FID, idx, bufp, 0, len, IO_OUT); /* 6 */ + } + return; +}/* hcf_put_data */ + + +/************************************************************************************************************** + + + Name: hcf_put_info + + Summary: Transfers operation information and transient and persistent + configuration information to the Card. + + Parameters: + ifbp address of the Interface Block + + type specifies the RID (as defined by Hermes I/F) + + bufp address in NIC RAM where record data is located + + len length of data (in bytes) + +.NARRATIVE + + Remarks: + CFG_NOTIFY: only runs after hcf_enable + + Remarks: Configuration information is copied from the provided data + structure into the Card. The exact layout of the provided data + structure depends on the action code. Also the mechanism used to copy + the data to the card depends on the action code. In order to make the + changes which are based on the Access command (see support routine put_info) + sustain over activities like hcf_diagnose and recovery from PCMCIA card + insertion, the data associated with these particular action codes, is + saved in the IF-block. The codes for this type are "cleverly" chosen to + be identical to the RID. + + bufp is defined as a pointer to items of type hcf_16 because of the + correlation with the Hermes definition + + +.DIAGRAM + +.NOTICE + Future enhancements in the functionality offered by the WCI and/or implementation aspects of the HCF + may warrant filtering on the type-field of the LTV to recognize non-MSF accessible records, e.g. CFG_TICK + +**************************************************************************************************************/ + +int hcf_put_info( IFBP ifbp, + LTVP ltvp /*number identifying the type of change +
+									CFG_INFO_FRAME_MIN	lowest value representing an Information Frame
+									CFG_NOTIFY			Handover Address
+										
+									CFG_TALLIES			Communications Tallies
+									CFG_SCAN			Scan results
+										                        	
+									CFG_LINK_STAT 		Link Status
+									CFG_ASSOC_STAT		Association Status
+								
+
*/ + ) { + +//int cnt = 3; +//hcf_16 i = ltvp->len - 1; +int rc = HCF_SUCCESS; + + + if ( CFG_RID_CFG_MIN <= ltvp->typ && ltvp->typ <= CFG_RID_CFG_MAX ) { + //all codes between 0xFC00 and 0xFCFF are passed to Hermes) +// if ( ( ifbp->IFB_CardStat & CARD_STAT_PRI_STA_PRES ) == CARD_STAT_PRESENT ) { +// do { +// rc = hcfio_string( ifbp, BAP_1, +// ltvp->typ, 0, (wci_bufp)ltvp, 2, MUL_BY_2(ltvp->len + 1), IO_OUT_CHECK ); +// } while ( cnt-- && rc != HCF_SUCCESS ); +// if ( rc == HCF_SUCCESS ) rc = cmd_wait( ifbp, HCMD_ACCESS + HCMD_ACCESS_WRITE, ltvp->typ ); +// if ( rc == HCF_SUCCESS ) rc = put_info( ifbp, ltvp ); + + rc = put_info( ifbp, ltvp ); +// } + } + return rc; +}/* hcf_put_info */ + + + + + +/****************************************************************************************************************** + +.MODULE hcf_send +.LIBRARY HCF +.TYPE function +.SYSTEM msdos +.SYSTEM unix +.SYSTEM NW4 +.APPLICATION Data Transfer Function for WaveLAN based drivers and utilities +.DESCRIPTION Transmit a message on behalf of the protocol stack +.ARGUMENTS + void hcf_send( IFBP ifbp , hcf_send_type type ) + Card Interrupts disabled + +.RETURNS + void + + MSF-accessible fields of Result Block: - + +.NARRATIVE + Hcf_send transmits the Protocol Stack message loaded in NIC RAM by the + preceeding hcf_put_data calls. + +.DIAGRAM +1: The actual data length (the number of bytes in the Tx Frame structure + following the 802.3/802.11 Header Info blocks, is determined by + IFB_PIFLoadIdx, the index in the Transmit Frame Structure to store the + "next" byte. Note that this value must be compensated for the header info + by subtracting HFS_DAT. +2/3:TxFrameType - which is based on the preceding hcf_put_data calls - defines + whether the actual data length is written to the 802.11 or 802.3 Header Info + block. +2: In case of 802.11, the entry parameter type is augmented to reflect 802.11 + before it is written to the Control Field block. +3: In case of 802.3, the actual length must be converted from the native + format of the Host (Little Endian in case of an 80x86) to Big Endian before + it is written to the 802.3 Header Info block. +4: The actual send+reclaim command is performed by the routine send. +7: The return status of hcfio_in_string can be ignored, because when it fails, cmd_wait will fail via the + IFB_TimStat mechanism +.NOTICE + ;?This comment is definitely out of date + The choice to let hcf_send calculate the actual data length as + IFB_PIFLoadIdx - HFS_DAT, implies that hcf_put_data with the HFS_LUCENT + mechanism MUST be used to write the Data Info Block. A change in this I/F + will impact hcf_send as well. + An alternative would be to have a parameter datlen. If datlen is zero, the + current behavior is used. If datlen has a non-zero value, its value is used + as the actual data length (without validating against HCF_MAX_MSG and without + validating the total number of bytes put by hcf_put_data). + +.NOTICE + hcf_put_data/send leave the responsibility to only send messages on enabled ports at the MSF level. + This is considered the strategy which is sufficiently adequate for all "robust" MSFs, have the least + processor utilization and being still acceptable robust at the WCI !!!!! +.ENDOC END DOCUMENTATION + +------------------------------------------------------------------------------------------------------------*/ +int hcf_send( IFBP ifbp , hcf_16 port ) { //;?note that port is unused due to ambivalence about what the "right" I/F is + +int rc = HCF_SUCCESS; + + + if ( ifbp->IFB_CardStat & CARD_STAT_PRESENT ) { /* 1 */ + /* H/W Pointer problem detection */ + if ( ifbp->IFB_BAP_0[0] != ifbp->IFB_FSBase ) { //;? should BE HARD CODED, also add to send diag msg /* 30*/ + rc = hcfio_string( ifbp, BAP_0, ifbp->IFB_PIF_FID, ifbp->IFB_PIFLoadIdx, NULL, 0, 0, IO_OUT_CHECK ); + + if ( rc == HCF_FAILURE ) { + ifbp->IFB_PIFRscInd = 1; + } + } + if ( rc == HCF_SUCCESS ) { + if ( /*ifbp->IFB_FrameType == ENC_802_11 || */ ifbp->IFB_TxFrameType == ENC_TX_E_II ) { /* 2 */ + ifbp->IFB_PIFLoadIdx -= HFS_DAT_ABS; //actual length of frame /* 1 */ + CNV_INT_TO_BIG_NP(&ifbp->IFB_PIFLoadIdx); //;?is it worthwhile to have this additional macro + (void)hcfio_string( ifbp, BAP_0, ifbp->IFB_PIF_FID, HFS_LEN_ABS, + (wci_bufp)&ifbp->IFB_PIFLoadIdx, 0, 2, IO_OUT ); /* 7 */ + } +// send( ifbp, ifbp->IFB_PIF_FID, port | ifbp->IFB_FrameType ); /* 4 */ + (void)cmd_wait( ifbp, HCMD_TX + HCMD_RECL, ifbp->IFB_PIF_FID ); //justify "void" + } + /* reset the BAP pointer for the Tx Framestructure, note that we access the BAP not the NIC RAM + * after we relinguished control of the Tx FID to the Hermes + */ + (void)hcfio_string( ifbp, BAP_0, ifbp->IFB_PIF_FID, ifbp->IFB_FSBase, NULL, 0, 0, IO_IN ); + } + return rc; +} /* hcf_send */ + + + +/******************************************************************************************************************* + +.MODULE hcf_send_diag_msg +.LIBRARY HCF +.TYPE function +.SYSTEM msdos +.SYSTEM unix +.SYSTEM NW4 +.APPLICATION Data Transfer Function for WaveLAN based drivers and utilities +.DESCRIPTION Transmit a message on behalf of the Driver-Utility I/F +.ARGUMENTS + void hcf_send_diag_msg( IFBP ifbp, wci_bufp bufp, hcf_16 len ) + Card Interrupts disabled + +.RETURNS + void + + MSF-accessible fields of Result Block: - + +.NARRATIVE + Hcf_send_diag_msg transmits the message +.DIAGRAM + + 2: + + 4: Based on the assumption that hcf_send_diag_msg is called at a low frequency, HFS_TX_CNTL_ABS is written + on each call rather than using an IFB-field to remember the previous value and update only if needed + + +.ENDOC END DOCUMENTATION + +-------------------------------------------------------------------------------------------------------------*/ +int hcf_send_diag_msg( IFBP ifbp, hcf_16 type, wci_bufp bufp, int len ) { + +int rc = HCF_SUCCESS; + + + if ( ifbp->IFB_CardStat & CARD_STAT_PRESENT ) { + rc = HCF_ERR_BUSY; //;?more appropriate value needed + if ( ifbp->IFB_DUIFRscInd ) { /* 2 */ + rc = hcfio_string( ifbp, BAP_0, ifbp->IFB_DUIF_FID, HFS_ADDR_DEST_ABS, bufp, 0, len, IO_OUT_CHECK ); + if ( rc == HCF_SUCCESS ) { + ifbp->IFB_DUIFRscInd = 0; + (void)hcfio_string( ifbp, BAP_0, ifbp->IFB_PIF_FID, HFS_TX_CNTL_ABS, //justify void + (wci_bufp)&type, 1, 2, IO_OUT ); /* 4 */ + (void)cmd_wait( ifbp, HCMD_TX + HCMD_RECL, ifbp->IFB_DUIF_FID ); + } + } + } + return rc; +} /* hcf_send_diag_msg */ + + + + + +/******************************************************************************************************************* + + +.MODULE hcf_service_nic +.LIBRARY HCF +.TYPE function +.SYSTEM msdos +.APPLICATION Data Transfer Function for WaveLAN based drivers and utilities +.DESCRIPTION Provides received message and link status information +.ARGUMENTS + int hcf_service_nic(IFBP ifbp ) + Card Interrupts disabled + +.RETURNS + int + all the bits of the Hermes evitable register, which are encountered during execution of hcf_service_nic + the "pseudo"-events HREG_EV_NO_CARD, HREG_EV_DUIF_RX + MSF-accessible fields of Result Block + IFB_RxLen 0 or Frame size as reported by LAN Controller + IFB_RxStat + IFB_MBInfoLen + IFB_PIFRscInd + IFB_DUIFRscInd + IFB_NotifyRscInd + IFB_HCF_Tallies + + +.NARRATIVE + hcf_service_nic is primarily intended to be part of the Interrupt Service Routine. + hcf_service_nic is presumed to neither interrupt other HCF-tasks nor to be interrupted by other HCF-tasks. + A way to achieve this is to precede hcf_service_nic as well as all other HCF-tasks with a call to + hcf_action to disable the card interrupts and, after all work is completed, with a call to hcf_action to + restore (which is not necessarily the same as enabling) the card interrupts. + In case of a polled environment, it is assumed that the MSF programmer is sufficiently familiar with the + specific requirements of that environment to translate the interrupt strategy to a polled strategy. + + hcf_service_nic services the following Hermes events: + HREG_EV_INFO Asynchronous Information Frame + HREG_EV_INFO_DROP WMAC did not have sufficient RAM to build Unsolicited Information Frame + HREG_EV_ALLOC Asynchronous part of Allocation/Reclaim completed + HREG_EV_RX the detection of the availability of received messages + + If a message is available, its length is reflected by the IFB_RxLen field of the IFB. This length + reflects the 802.3 message length (i.e. the data itself but not the Destination Address, Source Address, + DataLength field nor the SAP-header in case of decapsulation by the HCF). + If no message is available, IFB_RxLen is zero. + + **Buffer free strategy + When hcf_service_nic reports the availability of a message, the MSF can access that message or parts + thereof, by means of hcf_get_data calls till the next call of hcf_service_nic. Therefore it must be + prevented that the LAN Controller writes new data in the buffer associated with the last hcf_service_nic + report. + As a consequence hcf_service_nic is the only procedure which can free receive buffers for re-use by the + LAN Controller. Freeing a buffer is done implicitly by acknowledging the Rx event to the Hermes. The + strategy of hcf_service_nic is to free the buffer it has reported as containing an available message in + the preceeding call (assuming there was an available message). + A consequence of this strategy is that the Interrupt Service Routine of the MSF must repeatedly call + hcf_service_nic till hcf_service_nic returns "no message available". It can be reasoned that + hcf_action( INT_ON ) should not be given before the MSF has completely processed a reported Rx-frame. The + reason is that the INT_ON action is guaranteed to cause a (Rx-)interrupt (the MSF is processing a + Rx-frame, hence the Rx-event bit in the Hermes register must be active). This interrupt will cause + hcf_service_nic to be called, which will cause the ack-ing of the "last" Rx-event to the Hermes, + causing the Hermes to discard the associated NIC RAM buffer. + + +.DIAGRAM + 2: IFB_RxLen and IFB_RxStat must be cleared before the NIC presence check otherwise these values may stay + non-zero if the NIC is pulled out at an inconvenient moment + 4: If the card is not present, prevent all I/O because "our" I/O base may have been given away to someone + else in a CS/SS environment. + The MSF may have considerable latency in informing the HCF of the card removal by means of an hcf_disable. + To prevent that hcf_service_nic reports bogus information to the MSF with all - possibly difficult to + debug - undesirable side effects, hcf_service_nic pays performance wise the prize to use the momentanuous + NIC presence test by checking the contents of the Hermes register HREG_SW_0 against the value HCF_MAGIC. + 6: The return status of hcf_service_nic is defined as reflecting all interrupt causes this call has run into, + hence an accumulator is needed. This return status services ONLY to help the MSF programmer to debug the + total system. + When the card is removed, the pseudo event HREG_EV_NO_CARD is reported. + NOTE, the HREG_EV_NO_CARD bit is explicitly not intended for the MSF to detect NIC removal. The MSF must + use its own - environment specific - means for that. +10: ack the "old" Rx-event. See "Buffer free strategy" above for more explanation. + IFB_RxFID, IFB_RxLen and IFB_RxStat must be cleared to bring both the internal HCF house keeping as the + information supplied to the MSF in the state "no frame received" +12: The evitable register of the Hermes is sampled and all non-Rx activities are handled. + The non-Rx activities are: + - Alloc. The corresponding FID register is sampled, and based on this FID, either the IFB_PIFRscInd, + the IFB_DUIFRscInd or the IFB_NotifyRscInd is raised. + Note that no ASSERT is performed to check whether the RscInd corresponding with the sampled + HREG_ALLOC_FID has a zero value. It is felt that this obscures the code to the reader while adding + little practical value + - LinkEvent (including solicited and unsolicited tallies) are handled by procedure isr_info. + - Info drop events are handled by incrementing a tally +14: All the non-Rx/non-Cmd activities are acknowledged. Combining all these acknowledgements to a single + place, is considered an optimization. + Note that the Rx-acknowledgement is explicitly not included, as justified in "Buffer free strategy" above. + Note that the Cmd-acknowledgement is explicitly not included, because all command handling is handled + in line. +16: The handling of the non-Rx activities, may have bought the Hermes sufficient time to raise an Rx event + in the evitable register (assuming an other Rx event was pending and this loop through hcf_service_nic + acknowledged an Rx event). Therefore the evitable register is sampled again. If a frame is available, + the FID of that frame and the characteristics (status and length) are read from the NIC. These values are, + after Endianess conversion if needed, stored in IFB_RxStat and IFB_RxLen. IFB_RxLen is also adjusted for + the size of the 802.3 MAC header. Note: Whether this adjustment is the correct/most optimal for 802.11 + is debatable, however it is paramount that IFB_RxFID and IFB_RxLEN must either be both zero or both + non-zero to get a coherent behavior of the MSF+HCF. +18: If the Hermes frame status reflects an error - which can only occure in promiscuous mode - the frame + is not further processed and control is passed back to the MSF +20: WMP messages are processed by copying them to the MailBox. Accu is updated to reflect the reception + of the WMP frame to the debugger and sample is modified to go once more through the loop in the hope + to process the next pending Rx frame. +22: Both in 802.11 mode and 802.3_pure mode, the frame is not further processed (no decapsulation) and + control is passed back to the MSF. + In 802.3 mode the HCF checks whether decaposulation is needed (i.e. the Hermes reported Tunnel + encapsulation or the Hermes reported 1042 Encapsulation and the frame type does not match one of the + values in enc_trans_tbl. + The actual decapsulation takes place on the fly in hcf_get_data, based on the value of IFB_RxFence. + Note that in case of decapsulation the SNAP header is not passed to the MSF, hence IFB_RxLen must be + compensated for the SNAP header length + +.NOTICES + To make it possible to discriminate between a message without payload (only MAC addresses and implicit + the length) it is a convenient I/F to add 14 ( space occupied by MAC addresses and Length) to the + Hermes reported payload. So the maintenance programmer should be forwarned when considering changing + this strategy. Also the impact on 802.11 should be considered ;? +.ENDOC END DOCUMENTATION + +-------------------------------------------------------------------------------------------------------------*/ +int hcf_service_nic(IFBP ifbp ) { + +int accu = HREG_EV_NO_CARD; +hcf_16 sample, tmp; + + + ifbp->IFB_RxLen = ifbp->IFB_RxStat = 0; /* 2 */ + if ( ifbp->IFB_CardStat & CARD_STAT_PRESENT && IN_PORT_WORD( ifbp->IFB_IOBase + HREG_SW_0) == HCF_MAGIC ) { /* 4 */ + accu = 0; /* 6 */ + if ( ifbp->IFB_RxFID ) { /*10 */ + OUT_PORT_WORD( ifbp->IFB_IOBase + HREG_EV_ACK, HREG_EV_RX ); + ifbp->IFB_RxFID = ifbp->IFB_RxLen = ifbp->IFB_RxStat = 0; + } + sample = IN_PORT_WORD( ifbp->IFB_IOBase + HREG_EV_STAT ); /*12*/ + accu |= sample; + + if ( sample & HREG_EV_INFO ) isr_info( ifbp ); + if ( sample & HREG_EV_ALLOC ) { + tmp = IN_PORT_WORD(ifbp->IFB_IOBase + HREG_ALLOC_FID ); + if ( tmp == ifbp->IFB_PIF_FID ) ifbp->IFB_PIFRscInd = 1; + else if ( tmp == ifbp->IFB_DUIF_FID ) ifbp->IFB_DUIFRscInd = 1; + else { + ifbp->IFB_NotifyRscInd = 1; + } + } + tmp = sample & (hcf_16)~(HREG_EV_RX | HREG_EV_CMD ); /*14 */ + if ( tmp ) OUT_PORT_WORD( ifbp->IFB_IOBase + HREG_EV_ACK, tmp ); + + sample = IN_PORT_WORD( ifbp->IFB_IOBase + HREG_EV_STAT ); /*16 */ + if ( sample & HREG_EV_RX ) { + ifbp->IFB_RxFID = IN_PORT_WORD( ifbp->IFB_IOBase + HREG_RX_FID); + (void)hcfio_string(ifbp, BAP_1, ifbp->IFB_RxFID, HFS_STAT_ABS, (wci_bufp)&ifbp->IFB_RxStat, 1, 2, IO_IN ); + (void)hcfio_string(ifbp, BAP_1, ifbp->IFB_RxFID, HFS_DAT_LEN_ABS, (wci_bufp)&ifbp->IFB_RxLen, 1,2,IO_IN ); + ifbp->IFB_RxLen += HFS_DAT; + } + } + return accu; +}/* hcf_service_nic */ + + + + + +/************************************************************************************************************** +************************** H C F S U P P O R T R O U T I N E S ******************************************** +**************************************************************************************************************/ + + + +/****************************************************************************************************************** + + +.MODULE alloc +.LIBRARY HCF_SUP +.TYPE function +.SYSTEM msdos +.SYSTEM unix +.SYSTEM NW4 +.APPLICATION Support for HCFR routines +.DESCRIPTION allocates a (TX or Notify) FID in NIC RAM and clears it + +.ARGUMENTS + +.RETURNS + 0: failure + <>0: PIF value + +.NARRATIVE + + +.DIAGRAM + 1: execute the allocate command by calling cmd_wait + 2: wait till either the alloc event or a time-out occures + 3: if the alloc event occures, + - read the FID to return it to the caller of alloc + - acknowledge the alloc event + - clear the storage allocated in NIC RAM (see notice below) + 4: since alloc is only called after an Hermes initialize command but before the Hermes enable, a failing + allocation is considered a H/W failure, hence the Miscellaneous Error tally is incremented + +.NOTICE + o Clearing the FID is not only an aesthetical matter, it is also the cheapest (code-size) way to enforce + - correlation between IFB_TxCntl (which is cleared by hcf_disable) and the field HFS_TX_CNTL_ABS of a + IFB_PIF_FID + - zero value of the field HFS_TX_CNTL_ABS of a IFB_DUIF_FID (hcf_send_diag_msg only supports port 0) + + Note that Card Interrupts are disabled as a side effect of hcf_disable when alloc is called. This is a + necessary condition, otherwise the ISR can get control, causing hcf_service_nic to run. This would + constitute an error because hcf_service_nic needs a defined IFB_PIF_FID and IFB_DUIF_FID to manipulate + IFB_PIFRscInd and IFB_DUIFRscInd + + The put_info functions must be called before the alloc calls because of cnfMaxDataLength ;?Really, what is the catch + + +.DIAGRAM +.ENDOC END DOCUMENTATION +*/ +/*-----------------------------------------------------------------------------------------------------------*/ +hcf_16 alloc( IFBP ifbp, int len ) { + +hcf_32 prot_cnt = ifbp->IFB_TickIni; +hcf_16 pif = 0; +hcf_16 zero = 0; + + if ( cmd_wait( ifbp, HCMD_ALLOC, len ) == HCF_SUCCESS ) { /* 1 */ + while ( prot_cnt ) { + prot_cnt--; + if ( IN_PORT_WORD(ifbp->IFB_IOBase + HREG_EV_STAT ) & HREG_EV_ALLOC ) { /* 2 */ + pif = IN_PORT_WORD(ifbp->IFB_IOBase + HREG_ALLOC_FID ); /* 3 */ + OUT_PORT_WORD(ifbp->IFB_IOBase + HREG_EV_ACK, HREG_EV_ALLOC ); + (void)hcfio_string( ifbp, BAP_0, pif, 0, (wci_bufp)&zero, 0, 2, IO_OUT ); //justify void + len = DIV_BY_2( len ); + while ( --len ) OUT_PORT_WORD( ifbp->IFB_IOBase + BAP_0, 0 ); + break; + } + } + } + return pif; +}/* alloc */ + + + + + + + + + +/****************************************************************************************************************** + +.MODULE calibrate +.LIBRARY HCF_SUP +.TYPE function +.SYSTEM msdos +.SYSTEM unix +.SYSTEM NW4 +.APPLICATION Support for HCFR routines +.DESCRIPTION + +.ARGUMENTS + int calibrate( IFBP ifbp ) + +.RETURNS + HCF_SUCCESS + HCF_ERR_TIME_OUT + HCF_..... (via hcf_put_info) + +.NARRATIVE + o + o + + +.DIAGRAM + 1: + 2: + +.NOTICE + o + +.DIAGRAM +.ENDOC END DOCUMENTATION +*/ +/*-----------------------------------------------------------------------------------------------------------*/ +int calibrate( IFBP ifbp ) { + +LTV_STRCT x; // initialization with "= { 2, CFG_TICK_TIME};" causes memset + // to be used under some compilers +int cnt = 10; +int rc = HCF_SUCCESS; +hcf_32 prot_cnt; + +// if ( ifbp->IFB_TickIni == 0 ) { /* 22*/ + x.len = 2; + x.typ = CFG_TICK_TIME; + x.val[0] = CNV_LITTLE_TO_INT( 8 ); //no compile time conversion available + rc = hcf_put_info( ifbp, &x ); + ifbp->IFB_TickIni = 0; /* 22*/ + while ( rc == HCF_SUCCESS && --cnt ) { + prot_cnt = 0; + OUT_PORT_WORD( ifbp->IFB_IOBase + HREG_EV_ACK, HREG_EV_TICK ); + while ( (IN_PORT_WORD( ifbp->IFB_IOBase + HREG_EV_STAT ) & HREG_EV_TICK) == 0 && + ++prot_cnt <= INI_TICK_INI ) /*NOP*/; + ifbp->IFB_TickIni = max( ifbp->IFB_TickIni, prot_cnt); + } + if ( ifbp->IFB_TickIni == INI_TICK_INI ) rc = HCF_ERR_TIME_OUT; + ifbp->IFB_TickIni *= 128; //time out value of 8*128 = 1024 k microseconds +// } + x.val[0] = CNV_LITTLE_TO_INT( ONE_SECOND ); + rc = hcf_put_info( ifbp, &x ); + return rc; +} /* calibrate */ + + + + + + +/************************************************************************************************************** + + +.MODULE cmd_wait +.LIBRARY HCF_SUP +.TYPE function +.SYSTEM msdos +.SYSTEM unix +.SYSTEM NW4 +.APPLICATION Support for HCFR routines +.DESCRIPTION + +.ARGUMENTS + +.RETURNS + hcf_16 + HCF_SUCCESS + HCF_ERR_TIME_OUT + HCF_FAILURE + HCF_ERR_BUSY + +.NARRATIVE +.DIAGRAM + + 1: the test on rc checks whether a BAP initialization or a call to cmd_wait did ever fail. If so, the Hermes + is assumed inoperable/defect, and all subsequent bap_ini/cmd_wait calls are nullified till hcf_disable + clears the IFB_TimStat field. + + 2: Based on the Hermes design, the read of the busy bit is superfluous because we wait for the Cmd bit in + the Event Status register. + + 3: When the Hermes reports on another command than the Host just issued, the two are apparently out of + sync and all bets are off about the consequences. Therefore this situation is treated the same as an + Hermes failure as indicated by time-out (blocking all further bap_ini/cmd_wait calls till hcf_disable. + + 5: If HREG_STAT reflects an error it is either an HCF bug or a H/W problem. Since + no distinction can be made at forehand, the "vague" HCF_FAILURE code is used + +.NOTICE + Due to the general HCF strategy to wait for command completion, a 2nd command can never be excuted + overlapping a previous command. As a consequence the Hermes requirement that no Inquiry command may be + executed if there is still an unacknowledged Inquiry command outstanding, is automatically met. + However, there are two pseudo-asynchronous commands (Diagnose and Download) which do not adhere to this + general HCF strategy. In that case we rely on the MSF to do not overlap these commands, but no protection + is offered by the HCF +.ENDOC END DOCUMENTATION +*/ +/* -------------------------------------------------------------------------------------------------------------------*/ +int cmd_wait( IFBP ifbp, int cmd_code, int par_0 ) { + +int rc = ifbp->IFB_TimStat; +hcf_32 prot_cnt = ifbp->IFB_TickIni; + + + if ( rc == HCF_SUCCESS ) { /* 1 */ + OUT_PORT_WORD( ifbp->IFB_IOBase + HREG_PARAM_0, par_0 ); + OUT_PORT_WORD( ifbp->IFB_IOBase + HREG_CMD, cmd_code ); + while (prot_cnt && (IN_PORT_WORD(ifbp->IFB_IOBase + HREG_EV_STAT) & HREG_EV_CMD) == 0 ) prot_cnt--;/*2 */ + if ( prot_cnt == 0 ) { + rc = ifbp->IFB_TimStat = HCF_ERR_TIME_OUT; + } else { + rc = IN_PORT_WORD( ifbp->IFB_IOBase + HREG_STAT ); + OUT_PORT_WORD( ifbp->IFB_IOBase + HREG_EV_ACK, HREG_EV_CMD ); + if ( (rc ^ cmd_code) & HREG_STAT_CMD_CODE ) { /* 3 */ + rc = ifbp->IFB_TimStat = HCF_FAILURE; + } else { + rc &= HREG_STAT_CMD_RESULT; //Hermes defined Result Code + } + if ( rc ) rc = HCF_FAILURE; /* 5 */ + } + } + return rc; +}/* cmd_wait */ + + + +/*********************************************************************************************************************** + + + Name: enable_int + + Summary: Enables a specific Hermes interrupt + + Parameters: + ifbp address of the Interface Block + event Hermes event to be enabled as interrupt source + + Remarks: To get the contents of the IntEn register changed is a two step process: + + o change the "shadow" in IFB_IntEnMask + + o call hcf_action to actually copy the shadow to the IntEn register. + + To prevent a change in the "Card Interrupt En/Disabled state, a balancing + pair of HCF_ACT_INT_OFF and HCF_ACT_INT_ON must be used. To prevent + a temporary enabling as undesirable side effect, the first call must be + HCF_ACT_INT_OFF. + Note that at the very first interrupt, hcf_service_nic causes the removal of + the Tick and Cmd bit in the IntEn register. + + +.DIAGRAM +***********************************************************************************************************************/ +//#pragma Reminder2( "enable_int: shouldn't this be used in more places" ) +void enable_int(IFBP ifbp, int event ) { + + ifbp->IFB_IntEnMask |= event; + (void)hcf_action( ifbp, HCF_ACT_INT_OFF ); + (void)hcf_action( ifbp, HCF_ACT_INT_ON ); + return; + +}/* enable_int */ + + + + + +/**************************************************************************************************************************** + + +.MODULE ini_hermes +.LIBRARY HCF_SUP +.TYPE function +.SYSTEM msdos +.SYSTEM unix +.SYSTEM NW4 +.APPLICATION Support for HCF routines +.DESCRIPTION + +.ARGUMENTS + +.RETURNS + void + + + As side effect of the Hermes Initialize command, the interrupts are disabled +.NARRATIVE + 1: + 2: +.DIAGRAM + +.ENDOC END DOCUMENTATION +-------------------------------------------------------------------------------------------------------------*/ +int ini_hermes( IFBP ifbp ) { + +int rc = HCF_ERR_NO_NIC; +//hcf_32 prot_cnt = ifbp->IFB_TickIni = INI_TICK_INI; //initialize at best guess before calibration +hcf_32 prot_cnt; + + if ( ifbp->IFB_CardStat & CARD_STAT_PRESENT ) {//present /* 7 */ + if ( ifbp->IFB_TickIni == 0) ifbp->IFB_TickIni = INI_TICK_INI; //initialize at best guess before calibration + prot_cnt = ifbp->IFB_TickIni; + while (prot_cnt && IN_PORT_WORD(ifbp->IFB_IOBase + HREG_CMD ) & HCMD_BUSY ) prot_cnt--; /* 16*/ + + rc = HCF_ERR_TIME_OUT; + if ( prot_cnt != 0 ) { + rc = cmd_wait( ifbp, HCMD_INI, 0 ); /* 18*/ + OUT_PORT_WORD( ifbp->IFB_IOBase + HREG_EV_ACK, 0xFFFF ); + } + + } + return rc; +}/* ini_hermes */ + + +/**************************************************************************************************************************** + + +.MODULE isr_info +.LIBRARY HCF_SUP +.TYPE function +.SYSTEM msdos +.SYSTEM unix +.SYSTEM NW4 +.APPLICATION Support for HCF routines +.DESCRIPTION + +.ARGUMENTS + +.RETURNS + void + +.NARRATIVE + 1: info[0] becomes the length of the T-field + the length of the Value-field in words. Note that it is + dangerous to determine the length of the Value field by decrementing info[0], because if -e.g. as a + result of a bug in the Hermes as has happened in real life- info[0] becomes 0, a decrement results in + a very large number. Therefore all code is crafted around an unchanged info[0], with the intention to + make the HCF more robust against I/F violations. + 2: This is an example of the strategy described in #1 above. Info[0] is expected to be HCF_NIC_TAL_CNT + 1. + By using a pre-decrement, this value results in HCF_NIC_TAL_CNT movements of a single tally value into + the IFB_NIC_Tallies area of the IFB. + 3: Although put_info_mb is robust against a len-parameter with value zero, it accepts any bogus value + for the type-parameter. +.DIAGRAM + +.ENDOC END DOCUMENTATION +-------------------------------------------------------------------------------------------------------------*/ +void isr_info( IFBP ifbp ) { + +hcf_16 info[2], tmp; +hcf_32 *p; + + tmp = IN_PORT_WORD( ifbp->IFB_IOBase + HREG_INFO_FID ); + (void)hcfio_string(ifbp, BAP_1, tmp, 0, (wci_bufp)info, 2, sizeof(info), IO_IN ); /* 1 */ + + if ( info[1] == CFG_TALLIES ) { + if ( info[0] > HCF_NIC_TAL_CNT ) info[0] = HCF_NIC_TAL_CNT + 1; /* 2 */ + p = (hcf_32*)&ifbp->IFB_NIC_Tallies;//.TxUnicastFrames; + while ( --info[0] ) *p++ += IN_PORT_WORD( ifbp->IFB_IOBase + BAP_1 ); + } + return; +}/* isr_info */ + + + + + + +#if defined _M_I86TM +#endif //_M_I86TM + +/*********************************************************************************************************************** + + + Name: put_info + + Summary: stores Hermes configuration information in the ConfigTable of the IFB + + Parameters: + ifbp address of the Interface Block + ltvp address in NIC RAM where LVT-records are located + + +.NARRATIVE + +**************************************************************************************************************/ +int put_info( IFBP ifbp, LTVP ltvp ) { + +int cnt = 3; +//hcf_16 i = ltvp->len - 1; +int rc = HCF_SUCCESS; + + + if ( ifbp->IFB_CardStat & CARD_STAT_PRESENT ) { + + + do { + rc = hcfio_string( ifbp, BAP_1, + ltvp->typ, 0, (wci_bufp)ltvp, 2, MUL_BY_2(ltvp->len + 1), IO_OUT_CHECK ); + } while ( cnt-- && rc != HCF_SUCCESS ); + if ( rc == HCF_SUCCESS ) rc = cmd_wait( ifbp, HCMD_ACCESS + HCMD_ACCESS_WRITE, ltvp->typ ); + } + + return rc; +}/* put_info */ + + + + + + + diff -u --recursive --new-file linux/drivers/net/pcmcia/wvlan_hcf.h linux-2.4.1-wavelan/drivers/net/pcmcia/wvlan_hcf.h --- linux/drivers/net/pcmcia/wvlan_hcf.h Wed Dec 31 18:00:00 1969 +++ linux-2.4.1-wavelan/drivers/net/pcmcia/wvlan_hcf.h Tue Jan 30 18:02:36 2001 @@ -0,0 +1,287 @@ +/* This file is part of the Hardware Control Functions Light (HCF-light) library + to control the Lucent Technologies WaveLAN/IEEE Network I/F Card. + The HCF is the implementation of the Wireless Connection I/F (WCI). + + The HCF-light files are a subset of the HCF files. The complete set offers a + number of additional facilities, e.g. firmware download, Etherner-II encapsulation, + additional diagnostic facilities, ASSERT logic to support debugging, 802.11 support, + Configuration Management. + This complete set is explicitely not in the Public Domain but can be made + available under certain restriction. (see the pointer below for support) + + The HCF-light files are free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + At the time of this writing, you can request for support at: + betasupport@wavelan.com + + Documentation is expected to be available in the week of 8 Februari 1999 + +*/ + + +#ifndef HCF_H +#define HCF_H 1 + +/************************************************************************************************************* +* +* FILE : hcf.h *************** 2.0 ************************************************************************* +* +* DATE : 2000/01/06 23:30:52 1.2 +* +* AUTHOR : Nico Valster +* +* DESC : Definitions and Prototypes for MSF as well as HCF sources +* +* Customizable via HCFCFG.H +* +* +************************************************************************************************************** +Instructions to convert HCF.H to HCF.INC by means of H2INC + +Use a command line which defines the specific macros and command line options +needed to build the C-part, e.g. for the DOS ODI driver + `h2inc /C /Ni /Zp /Zn hcf hcf.h` + + +************************************************************************************************************** +* COPYRIGHT (c) 1996, 1997, 1998 by Lucent Technologies. All Rights Reserved. +**************************************************************************************************************/ + +/**************************************************************************** +wvlan_hcf.h,v +Revision 1.2 2000/01/06 23:30:52 root +*** empty log message *** + + * + * Rev 1.0 02 Feb 1999 14:32:30 NVALST + * Initial revision. +Revision 1.2 1999/02/01 22:58:35 nico +*** empty log message *** + +Revision 1.1 1999/01/30 19:24:39 nico +Initial revision + +Revision 1.1 1999/01/30 19:07:57 nico +Initial revision + + * + * Rev 1.110 29 Jan 1999 15:52:42 NVALST + * intermediate, maybe working but seems to need two times to load in + * light-version + * + * Rev 2.12 29 Jan 1999 10:48:44 NVALST + * + * Rev 1.108 28 Jan 1999 14:43:22 NVALST + * +****************************************************************************/ + +/************************************************************************************************************** +* +* CHANGE HISTORY +* + 961018 - NV + Original Entry + +*************************************************************************************************************/ + + + +#include "wvlan_hcfcfg.h" // System Constants to be defined by the MSF-programmer to tailor the HCF +#include //do not move to hcf.cpp to keep Chris (Borland) and Marc (MSVC 4)happy (defines NULL) + +#include "wvlan_mdd.h" // Include file common for HCF, MSF, UIL, USF + +/************************************************************************************************************/ +/****************** H C F F U N C T I O N P A R A M E T E R ****************************************/ +/************************************************************************************************************/ + +//offsets for hcf_put_data and hcf_get_data + + +// 802.3/E-II/802.11 offsets to access Hermes control fields +#define HFS_STAT -0x2E //0x0000 +#define HFS_STAT_ERR RX_STAT_ERR //link "natural" HCF name to "natural" MSF name + +#define HFS_Q_INFO -0x28 //0x0006 +#define HFS_TX_CNTL -0x22 //0x000C +#define HFS_FRAME_CNTL -0x20 //0x000E +#define HFS_ID -0x1E //0x0010 + +// 802.11 relative offsets to access 802.11 header fields +#define HFS_ADDR_1 0x00 //0x0012 +#define HFS_ADDR_2 0x06 //0x0018 +#define HFS_ADDR_3 0x0C //0x001E +#define HFS_SEQ_CNTL 0x12 //0x0024 +#define HFS_ADDR_4 0x14 //0x0026 +#define HFS_DAT_LEN 0x1A //0x002C + +// 802.3 / E-II relative offsets to access 802.3 header fields +#define HFS_ADDR_DEST 0x00 //0x002E +#define HFS_ADDR_SRC 0x06 //0x0034 +#define HFS_LEN 0x0C //0x003A +#define HFS_DAT 0x0E //0x003C + +// E-II relative offsets to access SNAP header fields +#define HFS_TYPE 0x14 //0x0042 //Eternet-II type in 1042/Bridge-Tunnel encapsulated frame + + +//#define HCF_ACT_INT_PENDING 0x0001 //interrupt pending, return status HCF_ACT_INT_OFF + + + +/*************************************************************************************************************/ +/**************** H C F F U N C T I O N R E T U R N C O D E S ***************************************/ +/*************************************************************************************************************/ + +//Debug Purposes only !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +#define HREG_EV_TICK 0x8000 //WMAC Controller Auxiliary Timer Tick +#define HREG_EV_RES 0x4000 //WMAC Controller H/W error (Wait Time-out) +#define HREG_EV_INFO_DROP 0x2000 //WMAC did not have sufficient RAM to build Unsollicited Frame +#define HREG_EV_NO_CARD 0x0800 /* PSEUDO event: card removed */ +#define HREG_EV_DUIF_RX 0x0400 /* PSEUDO event: WMP frame received */ +#define HREG_EV_INFO 0x0080 //WMAC Controller Asynchronous Information Frame +#define HREG_EV_CMD 0x0010 //WMAC Controller Command completed, Status and Response avaialble +#define HREG_EV_ALLOC 0x0008 //WMAC Controller Asynchronous part of Allocation/Reclaim completed +#define HREG_EV_TX_EXC 0x0004 //WMAC Controller Asynchronous Transmission unsuccessful completed +#define HREG_EV_TX 0x0002 //WMAC Controller Asynchronous Transmission successful completed +#define HREG_EV_RX 0x0001 //WMAC Controller Asynchronous Receive Frame + + + +//========================================= T A L L I E S =================================================== + +typedef struct CFG_HERMES_TALLIES_STRCT { //Hermes Tallies (IFB substructure) + hcf_32 TxUnicastFrames; + hcf_32 TxMulticastFrames; + hcf_32 TxFragments; + hcf_32 TxUnicastOctets; + hcf_32 TxMulticastOctets; + hcf_32 TxDeferredTransmissions; + hcf_32 TxSingleRetryFrames; + hcf_32 TxMultipleRetryFrames; + hcf_32 TxRetryLimitExceeded; + hcf_32 TxDiscards; + hcf_32 RxUnicastFrames; + hcf_32 RxMulticastFrames; + hcf_32 RxFragments; + hcf_32 RxUnicastOctets; + hcf_32 RxMulticastOctets; + hcf_32 RxFCSErrors; + hcf_32 RxDiscards_NoBuffer; + hcf_32 TxDiscardsWrongSA; + hcf_32 RxWEPUndecryptable; + hcf_32 RxMsgInMsgFragments; + hcf_32 RxMsgInBadMsgFragments; +}CFG_HERMES_TALLIES_STRCT; + + +//Note this way to define CFG_TALLIES_STRCT_SIZE implies that all tallies must keep the same (hcf_32) size +#define HCF_NIC_TAL_CNT (sizeof(CFG_HERMES_TALLIES_STRCT)/ sizeof(hcf_32)) +#define HCF_TOT_TAL_CNT (HCF_NIC_TAL_CNT) + +/************************************************************************************************************/ +/*********** W C I F U N C T I O N S P R O T O T Y P E S ******************************************/ +/************************************************************************************************************/ + +#define IFB_VERSION 0x82 /* initially 80, to be incremented by every IFB layout change */ + + + +/* identifier IFB_STRCT on typedef line needed to get the individual fields in the MS Browser DataBase */ +typedef struct IFB_STRCT{ //I/F Block +/* MSF readable part of Result block structure *************************************/ + hcf_io IFB_IOBase; /* I/O address of Hermes chip as passed by MSF at hcf_connect call */ +#if defined HCF_PORT_IO + hcf_16 IFB_IOBase_pad; // Optional field, makes IFB-layout independent of IFB_IOBase size +#endif //HCF_PORT_IO + hcf_16 IFB_IORange; // I/O Range used by Hermes chip + hcf_8 IFB_Version; /* initially 0, to be incremented by every IFB layout change */ + hcf_8 IFB_Slack_2; /* align/slack space */ + hcf_8 IFB_HCFVersionMajor; // Major version of the HCF.0x01 for this release + hcf_8 IFB_HCFVersionMinor; /* Minor version of the HCF. Incremented for each coding maintenance + * cycle. 0x01 for the Initial release */ + CFG_HERMES_TALLIES_STRCT IFB_NIC_Tallies; //Hermes tallies + +/* part I (survives hcf_disable) ************************************************************************/ + hcf_16 IFB_CardStat; /* see Design spec */ + hcf_16 IFB_FSBase; // frame type dependent offset (HFS_ADDR_1_ABS or HFS_ADDR_DEST_ABS) + hcf_16 IFB_RxFence; // frame type dependent gap fence (HFS_ADDR_DEST_ABS or HFS_LEN_ABS) + hcf_16 IFB_IntOffCnt; /* see Design spec */ + hcf_32 IFB_TickIni; /* initialization of counter for 1 ms processor loop */ + /* keep this unsigned otherwise the "clever" ASSERT in hcf_disable + * has a higher risk to get into trouble on slow machines + * keep this hcf_16 to prevent a "close to infinity" time out if + * calibration fails on 32-bits machine */ + hcf_16 IFB_Magic; /* see Design spec */ + hcf_16 IFB_Slack_4[2]; /* align/slack space */ + +/* part II (cleared or re-initialized at hcf_disable/hcf_enable) *****************************************/ + hcf_8 IFB_PIFRscInd; /* see Design spec //;?Q:int better than hcf_8 A: No! */ + hcf_8 IFB_DUIFRscInd; /* Value indicating the command resource availability for the + * Driver-Utility I/F (i.e. hcf_send_diag_msg). */ + /* Values: */ + /* * No command resource 0 */ + /* * Command resource available 01h-FFh */ + hcf_8 IFB_NotifyRscInd; /* see Design spec //;?Q:int better than hcf_8 A: No! */ + hcf_8 IFB_Slack_6; /* align/slack space */ + hcf_16 IFB_PIF_FID; /* see Design spec */ + hcf_16 IFB_DUIF_FID; /* field which contains FID value identifying the Tx Frame Structure, + * to be used by hcf_send_diag_msg */ + hcf_16 IFB_Notify_FID; /* field which contains FID value identifying the Notify Frame Struct + * to be used by hcf_put_info in case of Notify type codes */ + hcf_16 IFB_RxFID; /* see Design spec */ + hcf_16 IFB_MB_FID; /* pass appropriate FID to hcf_put_mb_info */ + hcf_16 IFB_TxFrameType; /* see Design spec */ + hcf_16 IFB_RxLen; /* see Design spec */ + hcf_16 IFB_RxStat; /* see Design spec */ + hcf_16 IFB_UnloadIdx; /* see Design spec */ + hcf_16 IFB_PIFLoadIdx; /* see Design spec */ + hcf_8 IFB_TxCntl[2]; /* contents of HFS_TX_CNTL field of TFS + * 0: MACPort, 1: StrucType,TxEx,TxOK */ + hcf_16 IFB_BAP_0[2]; /* offset + * RID/FID */ + hcf_16 IFB_BAP_1[2]; /* offset + * RID/FID */ + hcf_16 IFB_IntEnMask; /* see Design spec */ + hcf_16 IFB_TimStat; /* BAP initialization or Cmd Completion failed once */ + +}IFB_STRCT; + + + +typedef IFB_STRCT* IFBP; + + +EXTERN_C int hcf_action (IFBP ifbp, hcf_action_cmd cmd ); +EXTERN_C void hcf_assert (IFBP ifbp, wci_bufp file_name, unsigned int line_number, int q ); +EXTERN_C void hcf_connect (IFBP ifbp, hcf_io io_base ); +EXTERN_C int hcf_disable (IFBP ifbp, hcf_16 port ); +EXTERN_C void hcf_disconnect (IFBP ifbp ); +EXTERN_C int hcf_enable (IFBP ifbp, hcf_16 port ); +EXTERN_C int hcf_get_info (IFBP ifbp, LTVP ltvp ); +EXTERN_C int hcf_get_data (IFBP ifbp, int offset, wci_bufp bufp, int len ); +EXTERN_C int hcf_service_nic (IFBP ifbp ); +//EXTERN_C void hcf_put_data (IFBP ifbp, wci_bufp bufp, int len ); +EXTERN_C void hcf_put_data (IFBP ifbp, wci_bufp bufp, int len, hcf_16 port ); +EXTERN_C int hcf_put_info (IFBP ifbp, LTVP ltvp ); +EXTERN_C int hcf_put_header (IFBP ifbp, int offset, wci_bufp bufp, int len, hcf_8 check ); +EXTERN_C int hcf_send (IFBP ifbp, hcf_16 type ); +EXTERN_C int hcf_send_diag_msg (IFBP ifbp, hcf_16 type, wci_bufp bufp, int len ); + + + + +#endif /* HCF_H */ + diff -u --recursive --new-file linux/drivers/net/pcmcia/wvlan_hcfcfg.h linux-2.4.1-wavelan/drivers/net/pcmcia/wvlan_hcfcfg.h --- linux/drivers/net/pcmcia/wvlan_hcfcfg.h Wed Dec 31 18:00:00 1969 +++ linux-2.4.1-wavelan/drivers/net/pcmcia/wvlan_hcfcfg.h Tue Jan 30 18:02:36 2001 @@ -0,0 +1,1084 @@ +/* This file is part of the Hardware Control Functions Light (HCF-light) library + to control the Lucent Technologies WaveLAN/IEEE Network I/F Card. + The HCF is the implementation of the Wireless Connection I/F (WCI). + + The HCF-light files are a subset of the HCF files. The complete set offers a + number of additional facilities, e.g. firmware download, Etherner-II encapsulation, + additional diagnostic facilities, ASSERT logic to support debugging, 802.11 support, + Configuration Management. + This complete set is explicitely not in the Public Domain but can be made + available under certain restriction. (see the pointer below for support) + + The HCF-light files are free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + At the time of this writing, you can request for support at: + betasupport@wavelan.com + + Documentation is expected to be available in the week of 8 Februari 1999 + +*/ +#include + +#ifndef HCFCFG_H +#define HCFCFG_H 1 + +/************************************************************************************************************** +* +* FILE : hcfcfg.tpl // hcfcfg.h **************************** 2.0 ******************************************** +* +* DATE : 2000/12/13 22:58:23 1.3 +* +* AUTHOR : Nico Valster +* +* DESC : HCF Customization Macros +* +*************************************************************************************************************** +* COPYRIGHT (c) 1994, 1995 by AT&T. All Rights Reserved. +* COPYRIGHT (c) 1996, 1997, 1998 by Lucent Technologies. All Rights Reserved. +* +*************************************************************************************************************** +* +* hcfcfg.tpl list all #defines which must be specified to: +* I: adjust the HCF functions defined in HCF.CPP to the characteristics of a specific environment +* o maximum sizes for messages and notification frames, persistent configuration storage +* o Endianess +* +* II: Compiler specific macros +* o port I/O macros +* o type definitions +* +* III: Environment specific ASSERT macro +* +* IV: Compiler specific +* +* V: ;? specific +* +* +* By copying HCFCFG.TPL to HCFCFG.H and -if needed- modifying the #defines the WCI functionality can be +* tailored +* T O D O : A D D A R E C I P E T O D O T H I S +* +**************************************************************************************************************/ + +/**************************************************************************** +wvlan_hcfcfg.h,v +Revision 1.3 2000/12/13 22:58:23 root +*** empty log message *** + +Revision 1.2 2000/01/06 23:30:52 root +*** empty log message *** + + * + * Rev 1.0 02 Feb 1999 14:32:32 NVALST + * Initial revision. +Revision 1.2 1999/02/01 21:01:41 nico +*** empty log message *** + +Revision 1.1 1999/01/30 19:24:39 nico +Initial revision + +Revision 1.1 1999/01/30 19:07:57 nico +Initial revision + + * + * Rev 1.110 29 Jan 1999 15:52:44 NVALST + * intermediate, maybe working but seems to need two times to load in + * light-version + * + * Rev 1.109 29 Jan 1999 12:50:26 NVALST + * intermediate + * + * Rev 1.108 28 Jan 1999 14:43:24 NVALST + * intermediate, once more correction of loop in hcf_service_nic + download + * passed to Marc + * + * Rev 1.107 27 Jan 1999 13:53:24 NVALST + * intermediate, once more correction of loop in hcf_service_nic + * + * Rev 1.106 26 Jan 1999 16:42:46 NVALST + * intermediate, corrected loop in hcf_service_nic (which was as result of a + * walkthrough, changed from a bug without consequences into one with consequences + * + * Rev 1.105 25 Jan 1999 14:24:48 NVALST + * intermediate, hopefully suitable for release + * + * Rev 1.104 22 Jan 1999 16:59:34 NVALST + * intermediate, minor corrections + some HCF-L stuff + * + * Rev 1.103 15 Jan 1999 15:14:46 NVALST + * intermediate, deposited as HCF2.10 + * +*************************************************************************************************/ + + +/**************************************************************************** +* +* CHANGE HISTORY +* + + 960702 - NV + Original Entry - derived from HCF 2.12 +*************************************************************************************************/ + + +/* * * * * * * * * * * * * * * * * * * * * * * I * * * * * * * * * * * * * * * * * * * * * * */ + +/* Endianess + * Default: HCF_LITTLE_ENDIAN + * Little Endian (a.k.a. Intel), least significant byte first + * Big Endian (a.k.a. Motorola), most significant byte first + * + * If neither HCF_LITTLE_ENDIAN nor HCF_BIG_ENDIAN, the defintion of the following macros must be supplied + * by the MSF programmer: + * o CNV_LITTLE_TO_INT(w) interprets the 16-bits input value as Little Endian, returns an hcf_16 + * o CNV_BIG_TO_INT(w) interprets the 16-bits input value as Big Endian, returns an hcf_16 + * o CNV_INT_TO_BIG_NP(addr) converts in place the 16-bit value addressed by a near pointer from hcf_16 + * to Big Endian + * o CNV_LITTLE_TO_INT_NP(addr) converts in place the 16-bit value addressed by a near pointer from + * Little endian to hcf_16 + * + * At a number of places in the HCF code, the CNV_INT_TO_BIG_NP macro is used. While it does have the desired + * effect on all platforms, it's naming is misleading, so revisit all places where these CNV macros are used + * to assure the right name is used at the right place. + * Hint: introduce CNV_HOST_TO_NETWORK names if appropriate + * + */ + +#ifdef __BIG_ENDIAN +#define HCF_BIG_ENDIAN // selects Big Endian (a.k.a. Motorola), most significant byte first +#else +#define HCF_LITTLE_ENDIAN // selects Little Endian (a.k.a. Intel), least significant byte first +#endif + +/* I/O Address size + * Platforms which use port mapped I/O will (in general) have a 64k I/O space, conveniently expressed in + * a 16-bits quantity + * Platforms which use memory mapped I/O will (in general) have an I/O space much larger than 64k, + * and need a 32-bits quantity to express the I/O base + * To accomodate this the macros HCF_PORT_IO and HCF_MEM_IO are available. Exactly 1 of these must be + * defined. If HCF_PORT_IO is defined, the HCF will use an hcf_16 to express I/O base and store in the + * IFB. If HCF_MEM_IO, an hcf_32 is used for this purpose. The default is HCF_PORT_IO + */ +#define HCF_PORT_IO +//#define HCF_MEM_IO + +/* Alignment + * Some platforms can access words on odd boundaries (with possibly an performance impact), at other + * platforms such an access may result in a memory access violation. + * It is assumed that everywhere where the HCF casts a char pointer into a word pointer, the + * alignment criteria are met. This put some restrictions on the MSF, which are assumed to be + * "automatically" fullfilled at the applicable platforms + * To assert this assumption, the macro HCF_ALIGN can be defined. The default vaslue is 0, meaning no + * alignment, a value of 2 means word alignment, other values are invalid + */ + +/* * * * * * * * * * * * * * * * * * * * * * * II * * * * * * * * * * * * * * * * * * * * * * */ + + + +/************************************************************************************************/ +/****************** C O M P I L E R S P E C I F I C M A C R O S ***************************/ +/************************************************************************************************/ +/************************************************************************************************* +* +* The platforms supported by this version are: +* - Microsoft Visual C 1.5 (16 bits platform) +* - Microsoft Visual C 2.0 (32 bits platform) +* - Watcom C/C++ 9.5 +* - SCO UNIX +* +* In this version of hcfiocfg.tpl all macros except the MSVC 1.5 versions are either dependent on +* compiler/environment supplied macros (e.g. _MSC_VER or "def-ed out" +* +* By selecting the appropriate Macro definitions by means of modifying the +* "#ifdef 0/1" lines, the HCF can be adjusted for the I/O chararcteristics of +* a specific compiler +* +* If needed the macros can be modified or replaced with definitions appropriate +* for your personal platform +* If you need to make such changes it is appreciated if you inform Lucent Technologies WCND Utrecht +* That way the changes can become part of the next release of the WCI +* +* +* The prototypes and functional description of the macros are: +* +* hcf_8 IN_PORT_BYTE( hcf_16 port) +* Reads a byte (8 bits) from the specified port +* +* hcf_16 IN_PORT_WORD( hcf_16 port) +* Reads a word (16 bits) from the specified port +* +* void OUT_PORT_BYTE( hcf_16 port, hcf_8 value) +* Writes a byte (8 bits) to the specified port +* +* void OUT_PORT_WORD( hcf_16 port, hcf_16 value) +* Writes a word (16 bits) to the specified port +* +* void IN_PORT_STRING( port, dest, len) +* Reads len number of words from the specified port to the (FAR) address dest in PC-RAM +* Note that len specifies the number of words, NOT the number of bytes +* !!!NOTE, although len specifies the number of words, dest MUST be a char pointer NOTE!!! +* See also the common notes for IN_PORT_STRING and OUT_PORT_STRING +* +* void OUT_PORT_STRING( port, src, len) +* Writes len number of words from the (FAR) address src in PC-RAM to the specified port +* Note that len specifies the number of words, NOT the number of bytes. +* !!!NOTE, although len specifies the number of words, src MUST be a char pointer NOTE!!! +* +* The peculiar combination of word-length and char pointers for IN_PORT_STRING as well as +* OUT_PORT_STRING is justified by the assumption that it offers a more optimal algorithm +* +* Note to the HCF-implementor: +* Due to the passing of the parameters to compiler specific blabla......... +* do not use "expressions" as parameters, e.g. don't use "ifbp->IFB_IOBase + HREG_AUX_DATA" but +* assign this to a temporary variable. +* +* +* NOTE!! For convenience of the MSF-programmer, all {IN|OUT}_PORT_{BYTE|WORD|STRING} macros are allowed to +* modify their parameters (although some might argue that this would constitute bad coding +* practice). This has its implications on the HCF, e.g. as a consequence these macros should not +* be called with parameters which have side effects, e.g auto-increment. +* +* NOTE!! in the Micosoft implementation of inline assembly it is O.K. to corrupt all flags except +* the direction flag and to corrupt all registers except the segment registers and EDI, ESI, +* ESP and EBP (or their 16 bits equivalents). +* Other environments may have other constraints +* +* NOTE!! in the Intel environment it is O.K to have a word (as a 16 bits quantity) at a byte boundary, +* hence IN_/OUT_PORT_STRING can move words between PC-memory and NIC-memory with as only +* constraint that the the words are on a word boundary in NIC-memory. This does not hold true +* for all conceivalble environments, e.g. an Motorola 68xxx does not allow this, in other +* words whenever there is a move from address in 2*n in one memory type to address 2*m+1 in the +* other type, the current templates for IN_/OUT_PORT_STRING are unsuitable. Probably the +* boundary conditions imposed by these type of platforms prevent this case from materializing +* +*************************************************************************************************/ + +/************************************************************************************************/ +/**************************** N E T W A R E 3 8 6 *******************************************/ +/************************************************************************************************/ + +#if defined __NETWARE_386__ /* WATCOM */ + +#define MSF_COMPONENT_ID COMP_ID_ODI_32 +#define HCF_STA //station characteristics + +#include + +//#define CNV_LITTLE_TO_INT(x) (x) // No endianess conversion needed + +typedef unsigned char hcf_8; +typedef unsigned short hcf_16; +typedef unsigned long hcf_32; + +#define FAR // flat 32-bits code +#define BASED + +#define IN_PORT_BYTE(port) ((hcf_8)inp( (hcf_io)(port) )) //;?leave out cast to hcf_8;? +#define IN_PORT_WORD(port) (inpw( (hcf_io)(port) )) +#define OUT_PORT_BYTE(port, value) (outp( (hcf_io)(port), value )) +#define OUT_PORT_WORD(port, value) (outpw( (hcf_io)(port), value )) + +#define IN_PORT_STRING( prt, dst, n) while ( n-- ) { *(hcf_16 FAR*)dst = IN_PORT_WORD( prt ); dst += 2; } +#define OUT_PORT_STRING( prt, src, n) while ( n-- ) { OUT_PORT_WORD( prt, *(hcf_16 FAR*)src ) ; src += 2; } + +#endif // __NETWARE_386__ + + +// Note: +// Visual C++ 1.5 : _MSC_VER == 800 +// Visual C++ 4.0 : _MSC_VER == 1000 +// Visual C++ 4.2 : _MSC_VER == 1020 + + +/************************************************************************************************/ +/**************************** P A C K E T D R I V E R ***************************************/ +/********************************** D O S O D I *********************************************/ +/************************************************************************************************/ + +#if defined WVLAN_42 || defined WVLAN_43|| defined WVLAN43L + +#pragma warning ( disable: 4001 ) + +#define HCF_STA //station characteristics + +#if defined WVLAN_43 +#define MSF_COMPONENT_ID COMP_ID_ODI_16 +#define MSF_COMPONENT_VAR 1 +#define MSF_COMPONENT_MAJOR_VER 1 +#define MSF_COMPONENT_MINOR_VER 4 + +#elif defined WVLAN_42 +#define MSF_COMPONENT_ID COMP_ID_PACKET +#define MSF_COMPONENT_VAR 1 +#define MSF_COMPONENT_MAJOR_VER 1 +#define MSF_COMPONENT_MINOR_VER 24 + +#elif defined WVLAN43L +#define HCF_MAX_CONFIG 0 + +#define MSF_COMPONENT_MAJOR_VER 0 +#define MSF_COMPONENT_MINOR_VER 1 + +#endif //WVLAN_xx + +#define FAR __far // segmented 16 bits mode +#if defined _M_I86TM +#define BASED __based(__segname("_CODE")) +#else +#define BASED +#endif // _M_I86TM + +typedef unsigned char hcf_8; +typedef unsigned short hcf_16; +typedef unsigned long hcf_32; + +#include +#include +//#ifndef _DEBUG +#pragma intrinsic( _inp, _inpw, _outp, _outpw ) +//#endif // _DEBUG + +#define IN_PORT_BYTE(port) ((hcf_8)_inp( (hcf_io)(port) )) +#define IN_PORT_WORD(port) ((hcf_16)_inpw( (hcf_io)(port) )) +#define OUT_PORT_BYTE(port, value) ((void)_outp( (hcf_io)(port), value )) +#define OUT_PORT_WORD(port, value) ((void)_outpw( (hcf_io)(port), value )) + +#if defined HCF_STRICT +#define IN_PORT_STRING( prt, dst, n) { ips( prt, dst, n); } +#define OUT_PORT_STRING( prt, dst, n) { ops( prt, dst, n); } +#elif 0 // C implementation +#define IN_PORT_STRING( prt, dst, n) while ( n-- ) { *(hcf_16 FAR*)dst = IN_PORT_WORD( prt ); dst += 2; } +#define OUT_PORT_STRING( prt, src, n) while ( n-- ) { OUT_PORT_WORD( prt, *(hcf_16 FAR*)src ) ; src += 2; } +//;? WHY hcf_16 FAR*)src and not unsigned char FAR*)src +#else // Assembler implementation +#define IN_PORT_STRING( port, dest, len) __asm \ +{ \ + __asm push di \ + __asm push es \ + __asm mov cx,len \ + __asm les di,dest \ + __asm mov dx,port \ + __asm rep insw \ + __asm pop es \ + __asm pop di \ +} + +#define OUT_PORT_STRING( port, src, len) __asm \ +{ \ + __asm push si \ + __asm push ds \ + __asm mov cx,len \ + __asm lds si,src \ + __asm mov dx,port \ + __asm rep outsw \ + __asm pop ds \ + __asm pop si \ +} + +#endif // Asm or C implementation + +#endif /* WVLAN_43, WVLAN_42 (DOS ODI, Packet Driver) */ + + +/************************************************************************************************/ +/************************************* W C I T S T *********************************************/ +/************************************************************************************************/ + +#if defined WCITST + +#pragma warning ( disable: 4001 ) + +#define HCF_STA //station characteristics +#define HCF_AP //AccesPoint characteristics + +#if _CONSOLE +#define FAR // flat 32 bits mode (also defined in WINDEF.H) +#define BASED +#else +#define FAR __far // segmented 16 bits mode +#if defined _M_I86TM +#define BASED __based(__segname("_CODE")) +#else +#define BASED +#endif // _M_I86TM +#endif //_CONSOLE + +typedef unsigned char hcf_8; +typedef unsigned short hcf_16; +typedef unsigned long hcf_32; + +#include +#include +#ifndef _DEBUG +#pragma intrinsic( _inp, _inpw, _outp, _outpw ) +#endif // _DEBUG + +#ifdef LOG +extern FILE* utm_logfile; +hcf_16 ipw( hcf_16 port ); +hcf_8 ipb( hcf_16 port ); +void opw( hcf_16 port, hcf_16 value ); +void opb( hcf_16 port, hcf_8 value ); + +#define IN_PORT_BYTE(port) ipb( (hcf_io)(port) ) +#define IN_PORT_WORD(port) ipw( (hcf_io)(port) ) +#define OUT_PORT_BYTE(port, value) opb( (hcf_io)(port), (hcf_8)(value) ) +#define OUT_PORT_WORD(port, value) opw( (hcf_io)(port), (hcf_16)(value) ) +#else //LOG +#define IN_PORT_BYTE(port) ((hcf_8)_inp( (hcf_io)(port) )) +#define IN_PORT_WORD(port) ((hcf_16)_inpw( (hcf_io)(port) )) +#define OUT_PORT_BYTE(port, value) ((void)_outp( (hcf_io)(port), value )) +#define OUT_PORT_WORD(port, value) ((void)_outpw( (hcf_io)(port), value )) +#endif //LOG + +#define toch_maar_geen_asm +#if defined(toch_maar_asm) && !defined(__DA_C__) //;? temporary solution to satisfy DA-C +#define IN_PORT_STRING( port, dest, len) __asm \ +{ \ + __asm push di \ + __asm push es \ + __asm mov cx,len \ + __asm les di,dest \ + __asm mov dx,port \ + __asm rep insw \ + __asm pop es \ + __asm pop di \ +} + +#define OUT_PORT_STRING( port, src, len) __asm \ +{ \ + __asm push si \ + __asm push ds \ + __asm mov cx,len \ + __asm lds si,src \ + __asm mov dx,port \ + __asm rep outsw \ + __asm pop ds \ + __asm pop si \ +} + +#else //toch_maar_asm && !__DA_C__ +#define IN_PORT_STRING( prt, dst, n) while ( n-- ) { *(hcf_16 FAR*)dst = IN_PORT_WORD( prt ); dst += 2; } +#define OUT_PORT_STRING( prt, src, n) while ( n-- ) { OUT_PORT_WORD( prt, *(hcf_16 FAR*)src ) ; src += 2; } +//;? WHY hcf_16 FAR*)src and not unsigned char FAR*)src +#endif //toch_maar_asm && !__DA_C__ + +#endif /* WCITST */ + +/************************************************************************************************/ +/******************************************** W S U *******************************************/ +/************************************************************************************************/ + +#if 0 //;? conflicts with WIN_CE _MSC_VER >= 1000 /* Microsoft Visual C ++ 4.x, 5.x */ + +// Note: +// Visual C++ 4.0 : _MSC_VER == 1000 +// Visual C++ 4.2 : _MSC_VER == 1020 + + +#pragma warning ( disable: 4001 ) + +#define HCF_STA //station characteristics + +//#if defined WVLAN_43 +//#define MSF_COMPONENT_ID COMP_ID_ODI_16 +//#else if defined WVLAN_42 +//#define MSF_COMPONENT_ID COMP_ID_PACKET +//#endif //WVLAN_xx + +#if !defined FAR +//#if _CONSOLE +//#define FAR // flat 32 bits mode (also defined in WINDEF.H) +//#define BASED +//#else +#define FAR // far is an obsolete key in Visual C++ 4.x +//#if defined _M_I86TM +//#define BASED __based(__segname("_CODE")) +//#else +#define BASED +//#endif // _M_I86TM +//#endif //_CONSOLE +#endif //!defined FAR + +typedef unsigned char hcf_8; +typedef unsigned short hcf_16; +typedef unsigned long hcf_32; + +#include +#include + +#define IN_PORT_BYTE(port) ((hcf_8)_inp( (hcf_io)(port) )) +#define IN_PORT_WORD(port) ((hcf_16)_inpw( (hcf_io)(port) )) +#define OUT_PORT_BYTE(port, value) ((void)_outp( (hcf_io)(port), value )) +#define OUT_PORT_WORD(port, value) ((void)_outpw( (hcf_io)(port), value )) + +#define toch_maar_geen_asm +#if defined(toch_maar_asm) +#define IN_PORT_STRING( port, dest, len) __asm \ +{ \ + __asm push di \ + __asm push es \ + __asm mov cx,len \ + __asm les di,dest \ + __asm mov dx,port \ + __asm rep insw \ + __asm pop es \ + __asm pop di \ +} + +#define OUT_PORT_STRING( port, src, len) __asm \ +{ \ + __asm push si \ + __asm push ds \ + __asm mov cx,len \ + __asm lds si,src \ + __asm mov dx,port \ + __asm rep outsw \ + __asm pop ds \ + __asm pop si \ +} + +#else //toch_maar_asm +#define IN_PORT_STRING( prt, dst, n) while ( n-- ) { *(hcf_16 FAR*)dst = IN_PORT_WORD( prt ); dst += 2; } +#define OUT_PORT_STRING( prt, src, n) while ( n-- ) { OUT_PORT_WORD( prt, *(hcf_16 FAR*)src ) ; src += 2; } +//;? WHY hcf_16 FAR*)src and not unsigned char FAR*)src +#endif //toch_maar_asm + +#endif /* _MSC_VER >= 1000 (Microsoft Visual C++ 4.0 ) */ + + + + +/************************************************************************************************/ +/****************************************** L I N U X *****************************************/ +/************************************************************************************************/ + +#if defined __linux__ + +#define HCF_STA //station characteristics +#define MSF_COMPONENT_ID COMP_ID_LINUX +#define MSF_COMPONENT_VAR 1 +#define MSF_COMPONENT_MAJOR_VER 0 +#define MSF_COMPONENT_MINOR_VER 4 + +#include + +#define FAR // flat 32-bits code +#define BASED + +typedef unsigned char hcf_8; +typedef unsigned short hcf_16; +typedef unsigned long hcf_32; + +#define IN_PORT_BYTE(port) ((hcf_8)inb((hcf_io)(port))) +#define IN_PORT_WORD(port) ((hcf_16)inw((hcf_io)(port))) +#define OUT_PORT_BYTE(port, value) outb((hcf_8)(value), (hcf_io)(port)) +#define OUT_PORT_WORD(port, value) outw((hcf_16)(value), (hcf_io)(port)) + +#define IN_PORT_STRING insw +#define OUT_PORT_STRING outsw + +#endif /* LINUX */ + + + +/************************************************************************************************/ +/********************************** S C O U N I X ********************************************/ +/************************************************************************************************/ + +#if 0 + +#define HCF_STA //station characteristics +#define MSF_COMPONENT_ID + +//#define CNV_LITTLE_TO_INT(x) // No endianess conversion needed + +#define FAR // flat 32-bits code +#define BASED + +typedef unsigned char hcf_8; +typedef unsigned short hcf_16; +typedef unsigned long hcf_32; + +#define IN_PORT_BYTE(port) ((hcf_8)inb( (hcf_io)(port) )) +#define IN_PORT_WORD(port) ((hcf_16)inw( (hcf_io)(port) )) +#define OUT_PORT_BYTE(port, value) (outb( (hcf_io)(port), (hcf_8) (value) )) +#define OUT_PORT_WORD(port, value) (outw( (hcf_io)(port), (hcf_16) (value) )) + +#define FAR // flat 32-bits code +#define BASED + + +#endif /* SCO UNIX */ + + +/************************************************************************************************/ +/********************************* M I N I P O R T ********************************************/ +/************************************************************************************************/ + +#if 0 + +#define MSF_COMPONENT_ID COMP_ID_MINIPORT +#define HCF_STA //station characteristics + +#include +#include + +#define MSF_COMPONENT_VAR 1 +#define MSF_COMPONENT_MAJOR_VER TPI_MAJOR_VERSION +#define MSF_COMPONENT_MINOR_VER TPI_MINOR_VERSION + + +//#define CNV_LITTLE_TO_INT(x) // No endianess conversion needed + +#if !defined FAR +#define FAR // flat 32-bits code +#endif //!defined FAR + +#define BASED + +__inline UCHAR NDIS_IN_BYTE( ULONG port ) +{ + UCHAR value; + NdisRawReadPortUchar(port , &value); + return (value); +} + +__inline USHORT NDIS_IN_WORD( ULONG port ) +{ + USHORT value; + NdisRawReadPortUshort(port , &value); + return (value); +} + +#define IN_PORT_BYTE(port) NDIS_IN_BYTE( (ULONG) (port) ) +#define IN_PORT_WORD(port) NDIS_IN_WORD( (ULONG) (port) ) +#define OUT_PORT_BYTE(port, value) NdisRawWritePortUchar( (ULONG) (port) , (UCHAR) (value)) +#define OUT_PORT_WORD(port, value) NdisRawWritePortUshort((ULONG) (port) , (USHORT) (value)) + +#define IN_PORT_STRING(port, addr, len) NdisRawReadPortBufferUshort(port, addr, (len)); +#define OUT_PORT_STRING(port, addr, len) NdisRawWritePortBufferUshort(port, addr, (len)); + +typedef UCHAR hcf_8; +typedef USHORT hcf_16; +typedef ULONG hcf_32; + +#endif /* MINIPORT */ + +/************************************************************************************************/ +/********************************* W A V E P O I N T ******************************************/ +/************************************************************************************************/ + +#if defined WVLAN_81 /* BORLANDC */ + +#define HCF_AP //access point characteristics +#define MSF_COMPONENT_ID COMP_ID_AP1 +#define MSF_COMPONENT_VAR 1 +#define MSF_COMPONENT_MAJOR_VER 3 +#define MSF_COMPONENT_MINOR_VER 34 + +#include + +//#define CNV_LITTLE_TO_INT(x) // No endianess conversion needed + +typedef unsigned char hcf_8; +typedef unsigned short hcf_16; +typedef unsigned long hcf_32; + +//#define HCF_ASSERT 0 /* debug build only */ + +#if !defined FAR +#define FAR far // segmented 16 bits mode +#endif //!defined FAR +#define BASED + + +#define IN_PORT_BYTE(port) (inportb( (hcf_io)(port) )) +#define IN_PORT_WORD(port) (inport( (hcf_io)(port) )) +#define OUT_PORT_BYTE(port, value) (outportb( (hcf_io)(port), value )) +#define OUT_PORT_WORD(port, value) (outport( (hcf_io)(port), value )) + +#define IN_PORT_STRING(port, addr, len) \ + asm { push di; push es; mov cx,len; les di,addr; mov dx,port; rep insw; pop es; pop di } + +#define OUT_PORT_STRING(port, addr, len) \ + asm { push si; push ds; mov cx,len; lds si,addr; mov dx,port; rep outsw; pop ds; pop si } + +#endif /* WavePoint */ + +/************************************************************************************************/ +/************************** MPC860 - Diab or High C 29K **************************************/ +/************************************************************************************************/ + +#if defined(__ppc) || defined(_AM29K) //|| (CPU == PPC860) + +#define HCF_AP //AccesPoint characteristics +#define MSF_COMPONENT_VAR 0 +#define MSF_COMPONENT_ID 0 +#define MSF_COMPONENT_MAJOR_VER 1 +#define MSF_COMPONENT_MINOR_VER 0 + +#define FAR // flat 32-bits code +#define BASED + +typedef unsigned char hcf_8; +typedef unsigned short hcf_16; +typedef unsigned long hcf_32; + +#define SwapBytes(t) /*lint -e572*/(((t) >> 8) + (((t) & 0xff) << 8))/*lint +e572*/ + +#if defined(__ppc) || (CPU == PPC860) + #ifndef __GNUC__ + #define __asm__ asm + #endif + + #if !defined(_lint) + #define EIEIO() __asm__(" eieio") + #else + #define EIEIO() + #endif + + hcf_8 IN_PORT_BYTE(int port) { + hcf_8 value = *(volatile hcf_8 *)(port); EIEIO(); + return value; + } + + hcf_16 IN_PORT_WORD(int port) { + hcf_16 value = *(volatile hcf_16 *)(port); EIEIO(); + value = SwapBytes(value); + return value; + } + + #define OUT_PORT_BYTE(port, value) { *(volatile hcf_8 *)(port) = (value); EIEIO(); } + #define OUT_PORT_WORD(port, value) \ + { *(volatile hcf_16 *)(port) = SwapBytes(value); EIEIO(); } +#else + #define IN_PORT_BYTE(port) (*(volatile hcf_8 *)(port)) + #define IN_PORT_WORD(port) (*(volatile hcf_16 *)(port)) + #define OUT_PORT_BYTE(port, value) (*(volatile hcf_8 *)(port) = (value)) + #define OUT_PORT_WORD(port, value) (*(volatile hcf_16 *)(port) = (value)) +#endif + +/***************************************************************************/ + +#define IN_PORT_STRING( port, dest, len) { \ + unsigned l = (len); \ + hcf_16 t, *d = (volatile hcf_16 *)(dest); \ + while (l--) { \ + t = IN_PORT_WORD(port); \ + *d++ = SwapBytes(t); \ + } \ + } + +#define OUT_PORT_STRING( port, src, len) { \ + unsigned l = (len); \ + hcf_16 t, *s = (volatile hcf_16 *)(src); \ + while (l--) { \ + t = *s++; \ + OUT_PORT_WORD(port, SwapBytes(t)); \ + } \ + } + +#if PRODUCT == 9150 + #define HCF_AP + #define HCF_ASSERT + #undef MSF_COMPONENT_ID +#endif + +#endif /* MPC860 - Diab or High C 29K */ + +/************************************************************************************************/ +/*********************************** M A C O S **********************************************/ +/************************************************************************************************/ + + /**********/ +#if 0 /* MAC_OS */ + /**********/ + +#define HCF_STA //station characteristics +#define MSF_COMPONENT_ID COMP_ID_MAC_OS +#define MSF_COMPONENT_VAR 0 +#define MSF_COMPONENT_MAJOR_VER 3 +#define MSF_COMPONENT_MINOR_VER 0 + +#define MAC_OS 1 +#define FAR // flat 32-bits code +#define BASED + +#undef HCF_LITTLE_ENDIAN // selects Little Endian (a.k.a. Intel), least significant byte first +#define HCF_BIG_ENDIAN // selects Big Endian (a.k.a. Motorola), most significant byte first + +#if defined(DEBUG) +#define HCF_ASSERT 1 +#endif // DEBUG + +typedef unsigned char hcf_8; +typedef unsigned short hcf_16; +typedef unsigned long hcf_32; + +#ifdef __cplusplus +extern "C" { +#endif +extern volatile unsigned char *MacIOaddr; +extern hcf_8 IN_PORT_BYTE(hcf_16 port); +extern void OUT_PORT_BYTE(hcf_16 port, hcf_8 value); +extern hcf_16 IN_PORT_WORD(hcf_16 port); +extern void OUT_PORT_WORD(hcf_16 port, hcf_16 value); +extern void IN_PORT_STRING(hcf_16 port, void *dest, hcf_16 len); +extern void OUT_PORT_STRING(hcf_16 port, void *src, hcf_16 len); + +#define SwapBytes(t) (((t) >> 8) + (((t) & 0xff) << 8)) + +#ifdef __cplusplus +} +#endif + +#endif /* MAC_OS */ + +/************************************************************************************************/ +/*********************************** W I N C E *************************************************/ +/************************************************************************************************/ + + /*********/ +#ifdef _WIN32_WCE /* WINCE */ + /*********/ + +#define MSF_COMPONENT_ID COMP_ID_WIN_CE +#define HCF_STA //station characteristics + +#include +#include +#include + +#define MSF_COMPONENT_VAR 1 +#define MSF_COMPONENT_MAJOR_VER TPI_MAJOR_VERSION +#define MSF_COMPONENT_MINOR_VER TPI_MINOR_VERSION + +#define BASED + +#undef HCF_LITTLE_ENDIAN // selects Little Endian (a.k.a. Intel), least significant byte first +#undef HCF_BIG_ENDIAN // selects Big Endian (a.k.a. Motorola), most significant byte first + +#if defined(_SH3_) || defined (_SHx_) || defined(_MIPS_) || defined(_X86_) +#define HCF_LITTLE_ENDIAN +#endif + +#if defined(DEBUG) || defined(_WIN32_WCE_DEBUG) +#define HCF_ASSERT 1 +#endif // DEBUG + +typedef UCHAR hcf_8; +typedef USHORT hcf_16; +typedef ULONG hcf_32; + +#ifdef __cplusplus +extern "C" { +#endif + +#define WCE_IO_OFFSET 0x40 +extern ULONG WceIoAddr; + +extern hcf_8 IN_PORT_BYTE(hcf_16 port); +extern void OUT_PORT_BYTE(hcf_16 port, hcf_8 value); +extern hcf_16 IN_PORT_WORD(hcf_16 port); +extern void OUT_PORT_WORD(hcf_16 port, hcf_16 value); +extern void IN_PORT_STRING(hcf_16 port, void *dest, hcf_16 len); +extern void OUT_PORT_STRING(hcf_16 port, void *src, hcf_16 len); + +#ifdef __cplusplus +} +#endif + +#endif /* _WIN32_WCE */ + + +/* * * * * * * * * * * * * * * * * * * * * * * IV * * * * * * * * * * * * * * * * * * * * * * */ + +/***************************************Compiler specific ****************************************/ + +#ifdef __cplusplus +#define EXTERN_C extern "C" +#else +#define EXTERN_C +#endif //__cplusplus + + +/************************************************************************************************/ +/********** M A C R O S derived of C O M P I L E R S P E C I F I C M A C R O S *************/ +/************************************************************************************************/ + +typedef hcf_8 FAR *wci_bufp; // segmented 16-bits or flat 32-bits pointer to 8 bits unit +typedef hcf_16 FAR *wci_recordp; // segmented 16-bits or flat 32-bits pointer to 16 bits unit + +typedef hcf_8 FAR *hcf_8fp; // segmented 16-bits or flat 32-bits pointer to 8 bits unit +typedef hcf_16 FAR *hcf_16fp; // segmented 16-bits or flat 32-bits pointer to 16 bits unit +typedef hcf_32 FAR *hcf_32fp; // segmented 16-bits or flat 32-bits pointer to 8 bits unit + + +#if defined HCF_STA && defined HCF_AP +#if defined WCITST +#pragma message( "you should also test both in isolation" ) +#else +error; define exactly one of these terms; +#endif +#endif +#if ! defined HCF_STA && ! defined HCF_AP +error; define exactly one of these terms; +#endif + +/* * * * * * * * * * * * * * * * * * * * * * * V * * * * * * * * * * * * * * * * * * * * * * */ + +#if defined HCF_PORT_IO +#if defined HCF_MEM_IO +error; +#else +typedef hcf_16 hcf_io; +#endif //HCF_MEM_IO +#endif //HCF_PORT_IO +#if defined HCF_MEM_IO +#if defined HCF_PORT_IO +error; +#else +typedef hcf_32 hcf_io; +#endif //HCF_PORT_IO +#endif //HCF_MEM_IO + + + +/* MSF_COMPONENT_ID is used to define the CFG_IDENTITY_STRCT in HCF.C + * CFG_IDENTITY_STRCT is defined in HCF.C purely based on convenience arguments + * The HCF can not have the knowledge to determine the ComponentId field of the + * Identity record (aka as Version Record), therefore the MSF part of the Drivers + * must supply this value via the System Constant MSF_COMPONENT_ID + * There is a set of values predefined in MDD.H (format COMP_ID_.....) + */ + +#if defined MSF_COMPONENT_ID +#define DUI_COMPAT_VAR MSF_COMPONENT_ID +#define DUI_COMPAT_BOT 4 +#define DUI_COMPAT_TOP 4 +#endif // MSF_COMPONENT_ID + +/************************************************************************************************/ +/*************** E N V I R O N M E N T S P E C I F I C M A C R O S ************************/ +/************************************************************************************************/ + + +#if defined HCF_ASSERT //the next line may need modification for a specific environment +extern int BASED HCF_VAR_0; //Revision 2.0 gives an explanation of the need for HCF_VAR_0 +#endif + +#if defined HCF_PROFILING +#endif + +/************************************************************************************************/ +/****** M S F S U P P O R T F U N C T I O N S P R O T O T Y P E S *******************/ +/************************************************************************************************/ + +EXTERN_C void msf_assert ( wci_bufp file_namep, unsigned int line_number, hcf_16 trace, int qual ); + +/* To increase portability, use unsigned char and unsigned char * when accessing parts of larger + * types to convert their Endianess + */ + +#if defined HCF_BIG_ENDIAN +#if defined HCF_LITTLE_ENDIAN + error +#else //************************************* B I G E N D I A N ******************************************* +#define CNV_LITTLE_TO_INT(w) ( ((hcf_16)(w) & 0x00ff) << 8 | ((hcf_16)(w) & 0xff00) >> 8 ) +#define CNV_BIG_TO_INT(w) (w) // No endianess conversion needed + +#define CNV_INT_TO_BIG_NP(addr) +#define CNV_LITTLE_TO_INT_NP(addr) { \ + hcf_8 temp; \ + temp = ((hcf_8 FAR *)(addr))[0]; \ + ((hcf_8 FAR *)(addr))[0] = ((hcf_8 FAR *)(addr))[1]; \ + ((hcf_8 FAR *)(addr))[1] = temp; \ +} + +#endif // HCF_LITTLE_ENDIAN +#endif // HCF_BIG_ENDIAN + +#if defined HCF_LITTLE_ENDIAN +#if defined HCF_BIG_ENDIAN + error; +#else //************************************* L I T T L E E N D I A N ************************************* + +#define CNV_LITTLE_TO_INT(w) (w) // No endianess conversion needed +#define CNV_BIG_TO_INT(w) ( ((hcf_16)(w) & 0x00ff) << 8 | ((hcf_16)(w) & 0xff00) >> 8 ) + +#define CNV_INT_TO_BIG_NP(addr) { \ + hcf_8 temp; \ + temp = ((hcf_8 FAR *)(addr))[0]; \ + ((hcf_8 FAR *)(addr))[0] = ((hcf_8 FAR *)(addr))[1]; \ + ((hcf_8 FAR *)(addr))[1] = temp; \ +} +#define CNV_LITTLE_TO_INT_NP(addr) + +#endif // HCF_BIG_ENDIAN +#endif // HCF_LITTLE_ENDIAN + +// conversion macros which can be expressed in other macros +#define CNV_INT_TO_LITTLE(w) CNV_LITTLE_TO_INT(w) +#define CNV_INT_TO_BIG(w) CNV_BIG_TO_INT(w) + +#endif //HCFCFG_H + +//******************************************* A L I G N M E N T ********************************************** +#if defined HCF_ALIGN +#if HCF_ALIGN != 0 && HCF_ALIGN != 2 + error; +#endif // HCF_ALIGN != 0 && HCF_ALIGN != 2 +#else +#define HCF_ALIGN 0 //default to no alignment +#endif // HCF_ALIGN + + + + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * The routines ips and ops (short for InPutString and OutPutString) are created to use the + * compiler to do the type checking. It turned out that it is too easy to accidentally pass + * a word pointer to the the macros IN_PORT_STRING and OUT_PORT_STRING rather than a byte pointer. + * The "+2" as some macro implementations use, does not have the intended effect in those cases. + * The HCF_STRICT business can be ignored by MSF programmers. + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + +#if defined HCF_STRICT +void ips( hcf_io prt, wci_bufp dst, int n); +void ops( hcf_io prt, wci_bufp src, int n); +#endif //HCF_STRICT + + + + + + + +#if !defined HCF_MAX_CONFIG +#define HCF_MAX_CONFIG 256 // maximum accumulated size in hcf_16 of LTV records used in hcf_put_config +#endif + +#if !defined HCF_MAX_MSG +#define HCF_MAX_MSG 2304 /* WaveLAN Pakket Size */ +#endif + +#if !defined HCF_MAX_NOTIFY +#define HCF_MAX_NOTIFY 6 // maximum size in bytes of "real" data in Notify command +#endif diff -u --recursive --new-file linux/drivers/net/pcmcia/wvlan_hcfdef.h linux-2.4.1-wavelan/drivers/net/pcmcia/wvlan_hcfdef.h --- linux/drivers/net/pcmcia/wvlan_hcfdef.h Wed Dec 31 18:00:00 1969 +++ linux-2.4.1-wavelan/drivers/net/pcmcia/wvlan_hcfdef.h Tue Jan 30 17:50:35 2001 @@ -0,0 +1,375 @@ +/* This file is part of the Hardware Control Functions Light (HCF-light) library + to control the Lucent Technologies WaveLAN/IEEE Network I/F Card. + The HCF is the implementation of the Wireless Connection I/F (WCI). + + The HCF-light files are a subset of the HCF files. The complete set offers a + number of additional facilities, e.g. firmware download, Etherner-II encapsulation, + additional diagnostic facilities, ASSERT logic to support debugging, 802.11 support, + Configuration Management. + This complete set is explicitely not in the Public Domain but can be made + available under certain restriction. (see the pointer below for support) + + The HCF-light files are free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + At the time of this writing, you can request for support at: + betasupport@wavelan.com + + Documentation is expected to be available in the week of 8 Februari 1999 + +*/ + + +#ifndef HCFDEFC_H +#define HCFDEFC_H 1 + + +/************************************************************************************************* +* +* FILE : HCFDEFC.H *************** 2.0 ********************* +* +* DATE : 2000/01/06 23:30:53 1.2 +* +* AUTHOR : Nico Valster +* +* DESC : Definitions and Prototypes for HCF only +* +************************************************************************************************** +* COPYRIGHT (c) 1996, 1997, 1998 by Lucent Technologies. All Rights Reserved. +*************************************************************************************************/ + + +/**************************************************************************** +wvlan_hcfdef.h,v +Revision 1.2 2000/01/06 23:30:53 root +*** empty log message *** + + * + * Rev 1.0 02 Feb 1999 14:32:34 NVALST + * Initial revision. +Revision 1.1 1999/01/30 19:24:39 nico +Initial revision + +Revision 1.1 1999/01/30 19:07:57 nico +Initial revision + + * + * Rev 1.110 29 Jan 1999 15:52:44 NVALST + * intermediate, maybe working but seems to need two times to load in + * light-version + * + * Rev 2.12 29 Jan 1999 10:48:44 NVALST + * + * Rev 1.108 28 Jan 1999 14:43:24 NVALST + * intermediate, once more correction of loop in hcf_service_nic + download + * passed to Marc + * + * Rev 2.11 27 Jan 1999 16:57:42 NVALST + * + * Rev 1.107 27 Jan 1999 13:53:24 NVALST + * intermediate, once more correction of loop in hcf_service_nic + * + * Rev 1.106 26 Jan 1999 16:42:46 NVALST + * intermediate, corrected loop in hcf_service_nic (which was as result of a + * walkthrough, changed from a bug without consequences into one with consequences + * + * Rev 1.105 25 Jan 1999 14:24:46 NVALST + * intermediate, hopefully suitable for release + * + * Rev 1.104 22 Jan 1999 16:59:34 NVALST + * intermediate, minor corrections + some HCF-L stuff + * + * Rev 1.103 15 Jan 1999 15:14:46 NVALST + * intermediate, deposited as HCF2.10 + * + * Rev 2.10 15 Jan 1999 14:54:34 NVALST + * +****************************************************************************/ + + +/**************************************************************************** +* +* CHANGE HISTORY +* + 961018 - NV + Original Entry + +**************************************************************************************************/ + +/************************************************************************************************/ +/********************************* P R E F I X E S ********************************************/ +/************************************************************************************************/ +//IFB_ Interface Block +//HCMD_ Hermes Command +//HFS_ Hermes (Transmit/Receive) Frame Structure +//HREG_ Hermes Register + +/*************************************************************************************************/ + + +/************************************************************************************************/ +/********************************* GENERAL EQUATES **********************************************/ +/************************************************************************************************/ +//#define STATIC //;?cheap way out to get things compiled while intransition for ObjectOutline +//#if ! defined STATIC //;? change to HCF_STATIC some day +//#if defined _DEBUG || defined OOL +#define STATIC EXTERN_C +//#else +//#define STATIC static +//#endif //_DEBUG +//#endif // STATIC + + +#define AUX_MAGIC_0 0xFE01 +#define AUX_MAGIC_1 0xDC23 +#define AUX_MAGIC_2 0xBA45 +#define HCF_MAGIC 0x7D37 // "}7" Handle validation +#define DIAG_MAGIC 0x5A5A + +#define PLUG_DATA_OFFSET 0x3F0000L + + +#define ONE_SECOND 977 // 977 times a Hermes Timer Tick of 1K microseconds ~ 1 second +#define INI_TICK_INI 0x20000L + +#define IO_IN 0 //hcfio_in_string +#define IO_OUT 1 //hcfio_out_string +#define IO_OUT_CHECK 2 //enable Data Corruption Detect on hcfio_out_string + +#define CARD_STAT_ENA_PRES (CARD_STAT_ENABLED|CARD_STAT_PRESENT) +#define CARD_STAT_PRI_PRES (CARD_STAT_PRESENT|CARD_STAT_INCOMP_PRI) +#define CARD_STAT_PRI_STA_PRES (CARD_STAT_PRI_PRES|CARD_STAT_INCOMP_STA) + +#define DO_ASSERT ( ifbp->IFB_Magic != HCF_MAGIC && ifbp->IFB_Magic == HCF_MAGIC ) //FALSE without the nasty compiler warning + +#define HCF_ASSERT_ACTION 0x0001 +//#define HCF_ASSERT_CONNECT no use to trace this +#define HCF_ASSERT_DISABLE 0x0002 +#define HCF_ASSERT_DISCONNECT 0x0004 +#define HCF_ASSERT_ENABLE 0x0008 +#define HCF_ASSERT_GET_DATA 0x0010 +#define HCF_ASSERT_GET_INFO 0x0020 +#define HCF_ASSERT_INITIALIZE 0x0040 +#define HCF_ASSERT_RESEND 0x0080 +#define HCF_ASSERT_SERVICE_NIC 0x0100 +#define HCF_ASSERT_PUT_DATA 0x0200 +#define HCF_ASSERT_PUT_INFO 0x0400 +#define HCF_ASSERT_PUT_HDR 0x0800 +#define HCF_ASSERT_SEND 0x1000 +#define HCF_ASSERT_SEND_DIAG_MSG 0x2000 +#define HCF_ASSERT_INT_OFF 0x4000 +#define HCF_ASSERT_MISC 0x8000 + + +#define CFG_CONFIG_RID_MASK 0xFC00 //CONFIGURATION RECORDS + +#define BAP_0 HREG_DATA_0 //Tx-related register set for WMAC buffer access +#define BAP_1 HREG_DATA_1 //non Tx-related register set for WMAC buffer access +/************************************************************************************************/ +/***************************** STRUCTURES *******************************************************/ +/************************************************************************************************/ + + +//************************* Hermes Receive/Transmit Frame Structures +//HFS_STAT +//see MMD.H for HFS_STAT_ERR +#define HFS_STAT_MSG_TYPE 0xE000 //Hermes reported Message Type +#define HFS_STAT_1042 0x2000 //RFC1042 Encoded +#define HFS_STAT_TUNNEL 0x4000 //Bridge-Tunnel Encoded +#define HFS_STAT_WMP_MSG 0x6000 //WaveLAN-II Management Protocol Frame + +//HFS_TX_CNTL +//see ENC_802_3/ENC_802_11 definition + + +//************************* Hermes Register Offsets and Command bits +#define HREG_IO_RANGE 0x40 //I/O Range used by Hermes + + +//************************* Command/Status +#define HREG_CMD 0x00 // +#define HCMD_CMD_CODE 0x3F +#define HREG_PARAM_0 0x02 // +#define HREG_PARAM_1 0x04 // +#define HREG_PARAM_2 0x06 // +#define HREG_STAT 0x08 // +#define HREG_STAT_CMD_CODE 0x003F // +#define HREG_STAT_DIAG_ERR 0x0100 +#define HREG_STAT_INQUIRE_ERR 0x0500 +#define HREG_STAT_CMD_RESULT 0x7F00 // +#define HREG_RESP_0 0x0A // +#define HREG_RESP_1 0x0C // +#define HREG_RESP_2 0x0E // + + +//************************* FID Management +#define HREG_INFO_FID 0x10 // +#define HREG_RX_FID 0x20 // +#define HREG_ALLOC_FID 0x22 // +//rsrvd #define HREG_TX_COMPL_FID 0x24 // + + +//************************* BAP +#define HREG_SELECT_0 0x18 // +#define HREG_OFFSET_0 0x1C // +//#define HREG_OFFSET_BUSY 0x8000 // use HCMD_BUSY +#define HREG_OFFSET_ERR 0x4000 // +//rsrvd #define HREG_OFFSET_DATA_OFFSET 0x0FFF // + +#define HREG_DATA_0 0x36 // +//rsrvd #define HREG_SELECT_1 0x1A // +//rsrvd #define HREG_OFFSET_1 0x1E // + +#define HREG_DATA_1 0x38 // + + +//************************* Event +#define HREG_EV_STAT 0x30 // +#define HREG_INT_EN 0x32 // +#define HREG_EV_ACK 0x34 // + + +//************************* Host Software +#define HREG_SW_0 0x28 // +#define HREG_SW_1 0x2A // +#define HREG_SW_2 0x2C // +//rsrvd #define HREG_SW_3 0x2E // +//************************* Control and Auxiliary Port + +#define HREG_CNTL 0x14 // +#define HREG_CNTL_AUX_ENA 0xC000 +#define HREG_CNTL_AUX_ENA_STAT 0xC000 +#define HREG_CNTL_AUX_DIS_STAT 0x0000 +#define HREG_CNTL_AUX_ENA_CNTL 0x8000 +#define HREG_CNTL_AUX_DIS_CNTL 0x4000 +#define HREG_AUX_PAGE 0x3A // +#define HREG_AUX_OFFSET 0x3C // +#define HREG_AUX_DATA 0x3E // + + +/************************************************************************************************/ +/***************************** END OF STRUCTURES ***********************************************/ +/************************************************************************************************/ + + +/************************************************************************************************/ +/********************************** EQUATES ***************************************************/ +/************************************************************************************************/ + +// Tx/Rx frame Structure +// +#define HFS_STAT_ABS (0x2E + HFS_STAT) //0x0000 +#define HFS_Q_INFO_ABS (0x2E + HFS_Q_INFO) //0x0006 +#define HFS_TX_CNTL_ABS (0x2E + HFS_TX_CNTL) //0x000C +#define HFS_FRAME_CNTL_ABS (0x2E + HFS_FRAME_CNTL) //0X000E +#define HFS_ID_ABS (0x2E + HFS_ID) //0X0010 + +#define HFS_ADDR_1_ABS (0x12 + HFS_ADDR_1) //0x0012 +#define HFS_ADDR_2_ABS (0x12 + HFS_ADDR_2) //0x0018 +#define HFS_ADDR_3_ABS (0x12 + HFS_ADDR_3) //0x001E +#define HFS_SEQ_CNTL_ABS (0x12 + HFS_SEQ_CNTL) //0x0024 +#define HFS_ADDR_4_ABS (0x12 + HFS_ADDR_4) //0x0026 +#define HFS_DAT_LEN_ABS (0x12 + HFS_DAT_LEN) //0x002C + +#define HFS_ADDR_DEST_ABS (0x2E + HFS_ADDR_DEST) //0x002E +#define HFS_ADDR_SRC_ABS (0x2E + HFS_ADDR_SRC) //0x0034 +#define HFS_LEN_ABS (0x2E + HFS_LEN) //0x003A +#define HFS_DAT_ABS (0x2E + HFS_DAT) //0x003C +#define HFS_TYPE_ABS (0x2E + HFS_TYPE) //0x0042 Eternet-II type in 1042/Bridge-Tunnel encapsulated frame + +#define HFS_802_11_GAP (HFS_DAT_ABS - HFS_ADDR_DEST_ABS) +#define HFS_E_II_GAP (HFS_TYPE_ABS - HFS_LEN_ABS) + +#define KLUDGE_MARGIN 8 //safety margin for Tx Data Corruption workaround + +#define HFS_TX_ALLOC_SIZE HCF_MAX_MSG + HFS_DAT_ABS + KLUDGE_MARGIN + +// IFB field related +// IFB_TxFrameType +//#define ENC_TX_802_3 0x00 +//#define ENC_TX_802_11 0x11 +#define ENC_TX_E_II 0x0E //encapsulation flag + +// SNAP header for E-II Encapsulation +#define ENC_TX_1042 0x00 +#define ENC_TX_TUNNEL 0xF8 + +// Hermes Command Codes and Qualifier bits +#define HCMD_BUSY 0x8000 // Busy bit, applicable for all commands +#define HCMD_RECL 0x0100 // Reclaim bit, applicable for Tx and Inquire + +#define HCMD_INI 0x0000 // +#define HCMD_ENABLE 0x0001 // +#define HCMD_DISABLE 0x0002 // +#define HCMD_DIAG 0x0003 // +#define HCMD_ALLOC 0x000A // +#define HCMD_TX 0x000B // +#define HCMD_NOTIFY 0x0010 // +#define HCMD_INQUIRE 0x0011 // +#define HCMD_ACCESS 0x0021 // +#define HCMD_ACCESS_WRITE 0x0100 // +#define HCMD_PROGRAM 0x0022 // +#define HCMD_PROGRAM_DISABLE 0x0000 // +#define HCMD_PROGRAM_ENABLE_VOLATILE 0x0100 // +#define HCMD_PROGRAM_ENABLE_NON_VOLATILE 0x0200 // +#define HCMD_PROGRAM_NON_VOLATILE 0x0300 // + +// Miscellanuos +// +#define REV_OFFSET 16 // offset of Major version within the PVCS generated Version String + + +/************************************************************************************************/ +/********************************** END OF EQUATES ********************************************/ +/************************************************************************************************/ + + +/************************************************************************************************/ +/************************************** MACROS ************************************************/ +/************************************************************************************************/ + +/************************************************************************************************ + DEBUG_INT is an undocumented feature to assist the HCF debugger + By expanding INT_3 to either an "int 3" or a NOP, it is very easy to check + by means of a binary file compare whether a "debug" version really corresponds + with a "non-debug" version. + ;? is is currently unknown whether there is a real reason to restrict this + implemenation to the MSVC environment +*/ +#if defined (_MSC_VER) +#ifdef DEBUG_INT +//#pragma message( Reminder "int 3, should be removed before releasing" ) +#define INT_3 __asm int 3 +#else +#define INT_3 __asm nop +#endif /*DEBUG_INT*/ +#else +#define INT_3 +#endif /*_MSC_VER*/ + +#define MUL_BY_2( x ) ( (x) << 1 ) //used to multiply by 2 +#define DIV_BY_2( x ) ( (x) >> 1 ) //used to divide by 2 + +/************************************************************************************************/ +/************************************** END OF MACROS *****************************************/ +/************************************************************************************************/ + +/************************************************************************************************/ +/*************************************** PROTOTYPES *******************************************/ +/************************************************************************************************/ + +int hcfio_string( IFBP ifbp, int bap, int fid, int offset, wci_bufp pc_addr, int wlen, int blen, int type ); + + +#endif //HCFDEFC_H diff -u --recursive --new-file linux/drivers/net/pcmcia/wvlan_hcfio.c linux-2.4.1-wavelan/drivers/net/pcmcia/wvlan_hcfio.c --- linux/drivers/net/pcmcia/wvlan_hcfio.c Wed Dec 31 18:00:00 1969 +++ linux-2.4.1-wavelan/drivers/net/pcmcia/wvlan_hcfio.c Tue Jan 30 17:50:35 2001 @@ -0,0 +1,432 @@ +/* This file is part of the Hardware Control Functions Light (HCF-light) library + to control the Lucent Technologies WaveLAN/IEEE Network I/F Card. + The HCF is the implementation of the Wireless Connection I/F (WCI). + + The HCF-light files are a subset of the HCF files. The complete set offers a + number of additional facilities, e.g. firmware download, Etherner-II encapsulation, + additional diagnostic facilities, ASSERT logic to support debugging, 802.11 support, + Configuration Management. + This complete set is explicitely not in the Public Domain but can be made + available under certain restriction. (see the pointer below for support) + + The HCF-light files are free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + At the time of this writing, you can request for support at: + betasupport@wavelan.com + + Documentation is expected to be available in the week of 8 Februari 1999 + +*/ + + + +/************************************************************************************************************** +* +* FILE : hcfio.cpp +* +* DATE : 2000/01/06 23:30:53 1.2 +* +* AUTHOR : Nico Valster +* +* DESC : WCI-II HCF I/O Support Routines +* These routines are isolated in their own *.CPP file to facilitate porting +* +* Customizable via HCFCFG.H which is included by HCF.H +* +*************************************************************************************************************** +* COPYRIGHT (c) 1994, 1995 by AT&T. All Rights Reserved. +* COPYRIGHT (c) 1996, 1997, 1998 by Lucent Technologies. All Rights Reserved. +**************************************************************************************************************/ + +/**************************************************************************** +wvlan_hcfio.c,v +Revision 1.2 2000/01/06 23:30:53 root +*** empty log message *** + + * + * Rev 1.0 02 Feb 1999 14:32:30 NVALST + * Initial revision. +Revision 1.1 1999/01/30 19:34:40 nico +Initial revision + +Revision 1.1 1999/01/30 19:24:39 nico +Initial revision + +Revision 1.1 1999/01/30 19:07:33 nico +Initial revision + + * + * Rev 1.110 29 Jan 1999 15:52:40 NVALST + * intermediate, maybe working but seems to need two times to load in + * light-version + * + * Rev 2.12 29 Jan 1999 10:48:46 NVALST + * + * Rev 1.108 28 Jan 1999 14:43:18 NVALST + * intermediate, once more correction of loop in hcf_service_nic + download + * passed to Marc + * + * Rev 2.11 27 Jan 1999 16:57:42 NVALST + * + * Rev 1.107 27 Jan 1999 13:53:22 NVALST + * intermediate, once more correction of loop in hcf_service_nic + * + * Rev 1.106 26 Jan 1999 16:42:44 NVALST + * intermediate, corrected loop in hcf_service_nic (which was as result of a + * walkthrough, changed from a bug without consequences into one with consequences + * + * Rev 1.105 25 Jan 1999 14:24:46 NVALST + * intermediate, hopefully suitable for release + * + * Rev 1.104 22 Jan 1999 16:59:30 NVALST + * intermediate, minor corrections + some HCF-L stuff + * + * Rev 1.103 15 Jan 1999 15:14:40 NVALST + * intermediate, deposited as HCF2.10 + * +****************************************************************************/ + + +/**************************************************************************** +* +* CHANGE HISTORY +* + 961121 - NV + Original Entry + +**************************************************************************************************************/ + +/* ToDo + * the CNV_LITTLE_TO_INT does have the desired effect on all platforms, but it's naming is + * misleading, so revisit all these CNV macros to assure the right name is used at the right + * place. Hint: introduce CNV_HOST_TO_NETWORK names if appropriate + */ + + +#include "wvlan_hcf.h" +#include "wvlan_hcfdef.h" + +#ifdef HCF_ASSERT +static char BASED HCF__FILE__[] = { " " __FILE__}; /* 6 spaces to supply room to build an LTV record for + * runtime HCF_ASSERTs. This record is constructed as: + * - L: self explanatory + * - T: CFG_MB_ASSERT + * - V[0]: line_number + * - V[1..]: (unchanged) file name */ +#endif + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * + * Refer to HCFCFG.H for more information on the routines ips and ops (short for InPutString + * and OutPutString) + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#if defined HCF_STRICT +void ips( hcf_io prt, wci_bufp dst, int n) { + + while ( n-- ) { + *(hcf_16 FAR*)dst = IN_PORT_WORD( prt ); + dst += 2; + } +} // ips + +void ops( hcf_io prt, wci_bufp src, int n) { + + while ( n-- ) { + OUT_PORT_WORD( prt, *(hcf_16 FAR*)src ); + src += 2; + } +} // ops +#endif // HCF_STRICT + +/***************************************** DOCZ Header ******************************************************** + + +.MODULE hcfio_string +.LIBRARY HCF_SUP +.TYPE function +.SYSTEM msdos +.SYSTEM unix +.SYSTEM NW4 +.APPLICATION I/O Support for HCF routines +.DESCRIPTION read/write string with specified length from/to WaveLAN NIC RAM to/from PC RAM + + +int hcfio_string( IFBP ifbp, int bap, int fid, + int offset, wci_bufp pc_addr, int word_len, int tot_len, int type ) { +.ARGUMENTS + IFBP ifbp I/F Block + int bap BAP0/1 + int fid FID/RID + int offset offset in FID/RID + wci_bufp pc_addr begin address in PC RAM to write to or read from + int word_len number of leading words of which the Endianess must be converted + int tot_len number of bytes to write or read + int type action code + - IO_IN read from NIC RAM + - IO_OUT write to NIC RAM + - IO_OUT_CHECK Data Corruption Detect + +.RETURNS + int + HCF_SUCCESS O.K + HCF_ERR_TIME_OUT BAP can not be initialized + HCF_ERR_NO_NIC card is removed + HCF_FAILURE Data Corruption Detection catched + +.NARRATIVE + + hcfio_string has the following tasks: + - copy data from NIC RAM to Host RAM or vice versa + - optionally convert the data or part of the data from/to Little Endian format (as used by the NIC) + to/from the Native Endian format (as used by the Host) + - check for Data Corruption in the data written to the NIC + + Data is a string with specified length copied from/to a specified offset in a specified Receive Frame + Structure (FID), Transmit Frame Structure (FID) or Record (RID) to/from a Host RAM buffer with a specified + begin address. + A length of 0 can be specified, resulting in no data transfer. This feature accomodates MSFs in certain + Host environments (i.e. ODI) and it is used in the Data Corruption detection. + Which Buffer Acces Path (BAP0 or BAP1) is used, is defined by a parameter. + A non-zero return status indicates: + - the selected BAP could not properly be initialized + - the card is removed before completion of the data transfer + - the Data Corruption Detection triggered + - the NIC is considered inoperational due to a time-out of some Hermes activity in the past + In all other cases, a zero is returned. + If a card removal is returned, the MSF has the option to drop the message or recover in any other way it + sees fit. + BAP Initialization failure indicates an H/W error which is very likely to signal complete H/W failure. Once + a BAP Initialization failure has occured all subsequent interactions with the Hermes will return a time out + status till the Hermes is re-initialized by means of an hcf_disable (at all ports in case of a multi-port + environment) + +.DIAGRAM + + 1: the test on rc checks whether a BAP initialization or a call to cmd_wait did ever fail. If so, the Hermes + is assumed inoperable/defect, and all subsequent bap_ini/cmd_wait calls are nullified till hcf_disable + clears the IFB_TimStat field. + 2: The PCMCIA card can be removed in the middle of the transfer. By depositing a "magic number" in the + HREG_SW_0 register of the Hermes at initialization time and by verifying this location after + reading the string, it can be determined whether the card is still present and the return status is + set accordingly. + 3: The test on offset and fid in the IFB_BAP_ structure corresponding with the BAP entry parameter, + assures that the BAP is only initialized if the current set of parameters specifies a location wich is + not consecutive with the last read/write access. If initialization is needed, then: + - the select register is set + - the offset register is set + - the IFB_BAP_ structure is initialized + - the offset register is monitored till a successful condition (no busy bit and no error bit) is + detected or till the protection counter (calibrated at approx 1 second) expires + If the counter expires, this is reflected in IFB_TimStat, so all subsequent calls to hcfio_string + fail immediately ( see step 1) + 4: the offset register in the IFB_BAP_ structure is updated to be used as described in item 3 above + on the next call +10: The NIC I/F is optimized for word transfer but it can only handle word transfer at a word boundary. + Therefore an additional test must be done to handle the read preparation in case the begin address in + NIC RAM is odd. + This situation is handled by first reading a single byte and secondly reading a string of WORDS with a + BYTE length of the requested length minus 1. + NOTE: MACRO IN_PORT_STRING possibly modifies p (depending on how the MSF-programmer chooses to construct + this macro, so pc_addr can not be used as parameter +11: At completion of the word based transfer, a test is made to determine whether 1 additional byte must be + read (odd length starting at even address or even length starting at odd boundary) +12: finally the optionally conversion of the first words from Little Endian to Native Endian format is done. +20: first the optionally conversion of the first words from Native Endian to Little Endian format is done. + This implies that Endian conversion can ONLY take place at word boundaries. + Note that the difference with the IO_IN part of the logic is based on optimization considerations (both + speed and size) and the boundary condition to return the output buffer unchanged to the caller + Note also that the check on zero-length for output can not be the simple "skip all" as used for input, + because the Data Corruption Detection needs some of the side effects of this code, specifically the + BAP initialization +21: As for the IO_IN part, the logic must first cope with odd begin addresses in NIC RAM and the bulk of the + transfer is done via OUT_PORT_STRING. Due to a flaw in the Hermes, writing the high byte corrupts the + low byte. As a work around, the HCF reads the low byte deposited in NIC RAM by the previous + hcfio_string, merges that byte with the first byte of the current Host RAM buffer into a word and + writes that word to NIC RAM via OUT_PORT_WORD. Since OUT_PORT_WORD converts from Native Endian to + Little Endian, while at this point of the procedure the Host buffer must have the correct Endianess, + the macro CNV_LITTLE_TO_INT counteracts this unwanted adjustment of OUT_PORT_WORD. +22: At completion of the word based transfer, a test is made to determine whether 1 additional byte must be + written +30: The case of Data Corruption Detection: + First the NIC RAM pointer is aligned on a word boundary to cope with the problem of an odd number of + bytes written before. This is done by skipping one additional byte before the Data Corruption + Detection Pattern is appended to the data already written to the NIC RAM. + Then 8 bytes fixed pattern is written. The justification of this is given in the NOTICE section below +31: In order to read the pattern back, the BAP must be initialized to address the begin of the pattern. + The select register does not change, so only the offset register needs to be written, followed by + a wait for successful completion. +40: To recognize the case that the NIC is removed during execution of hcfio_string, the same check as in + step 2 is done again. +99: In the past, one of the asserts in bap_ini (which no longer exists now it is assimilated in hcfio_string) + catched if "offset" was invalid. By calling bap_ini with the original (offset + length), bap_ini would + catch when the MSF passes the RID/FID boundary during the read process. It turned out that this feature + did obscure the tracing during debugging so much that its total effect on the debugging process was + considered detrimental, however re-institution can be considered depending on the bug you are chasing + + +.NOTICE +The problem is that without known cause, the Hermes internal NIC RAM pointer misses its auto-increment causing +two successive writes to NIC RAM to address the same location. As a consequence word is overwritten and +a word is written at position . Since the Hermes is unaware of this, nothing in the system is +going to catch this, e.g. the frame is received on the other side with correct FCS. As a workaround, the HCF +keeps track of where the NIC RAM pointer SHOULD be. After all hcf_put_data calls are done, in other words, +when hcf_send is called, the HCF writes a number of words - the kludge pattern - after the MSF-data. Then it +sets the NIC RAM pointer by means of a re-initialization of the BAP to where this kludge pattern SHOULD be and +reads the first word. This first word must match the kludge pattern, otherwise, apparently, the auto-increment +failed. We need to write more than 1 word otherwise if the previous use of that piece of NIC RAM would have +left by chance the right "kludge" value just after the newly but incorrectly put data, the test would not +trigger. By overwriting the next 3 words as well, we assume the likelihood of this to be sufficiently small. +The frequency observed of this problem varies from 1 out of 1000 frames till to low to be noticeable. Just to +be on the safe side we assume that the chance of an error is 10E-3. By writing 4 words we reduce the +likelihood of an unnoticed problem to 10E-12, but of course this becomes tricky because we don't know whether +the chances are independent. Note that the HCF notion of the NIC RAM pointer is a "logical" view in the +RID/FID address space, while the Hermes has a completely different physical address value for this pointer, +however that difference does not influence above reasoning. + +.NOTE + Depending on the selected optimization options, using "register int reg" causes some obscure + optimization with si. As a result the code is longer. Therefore, do not invest time to optimize this code + that way during a "maintenance cycle". + +.NOTE + The IN_/OUT_PORT_WORD_/STRING macros are MSF-programmer defined and may or may not have side effects + on their parameters, therefore they can not handle expressions like "len/2". As a solution all these macros + must be called via "simple" variables, with no side effects like ++ and their contents is unpredictable + at completion of the macro + +.NOTE + The implementation is choosen to have input, output and BAP setup all rolled into one monolithic + function rather than a more ameniable hcfio_in_string, hcfio_out_string and bap_ini to minimize the + stack usage during Interrupt Service (especially relevant for DOS drivers) + +.NOTE + The local variable reg corresponds with a register of the appropriate BAP. This is possible by the + intentional choice of the addresses of the individual registers of the two BAPs and the macro used to + specify whether BAP_0 or BAP_1 should be used. The value of reg is changed in the flow of hcfio_string + because, depending on the context, reg is most optimal addressing the offset register or the data register. + + + + .ENDOC END DOCUMENTATION + +-------------------------------------------------------------------------------------------------------------*/ + + +int hcfio_string( IFBP ifbp, int bap, int fid, + int offset, wci_bufp pc_addr, int word_len, int tot_len, int type ) { + +hcf_io reg = ifbp->IFB_IOBase + bap - HREG_DATA_0 + HREG_OFFSET_0; //reg = offset register +hcf_32 prot_cnt = ifbp->IFB_TickIni; +hcf_16 *p1 = bap == BAP_0 ? ifbp->IFB_BAP_0 : ifbp->IFB_BAP_1; +wci_bufp cp; +wci_recordp wp = (wci_recordp)pc_addr; +int rc; +int tlen; + +#if HCF_ALIGN != 0 +#endif // HCF_ALIGN + /* assumption, writing words takes place only initial, never at odd NIC RAM addresses nor odd PC + * addresses */ + + if ( ( rc = ifbp->IFB_TimStat ) == HCF_SUCCESS ) { /* 1 */ + if ( IN_PORT_WORD( ifbp->IFB_IOBase + HREG_SW_0 ) != HCF_MAGIC ) rc = HCF_ERR_NO_NIC; /* 2 */ + } + if ( rc == HCF_SUCCESS ) { + + /* make sure all preceeding BAP manipulation is settled */ + while ( prot_cnt && IN_PORT_WORD( reg ) & (HCMD_BUSY|HREG_OFFSET_ERR) ) prot_cnt--; + + if ( offset != (int)*p1 || fid != (int)*(p1+1) ) { /* 3 */ + OUT_PORT_WORD( reg - HREG_OFFSET_0 + HREG_SELECT_0, fid ); + OUT_PORT_WORD( reg, offset & 0xFFFE ); + *p1 = (hcf_16)offset; + *(p1+1) = (hcf_16)fid; + /* use type == IO_IN and len == 0 as a way to set the BAP for the futute, e.g. at the end of hcf_send */ +// while ( prot_cnt-- && IN_PORT_WORD( reg ) & (HCMD_BUSY|HREG_OFFSET_ERR) ) /*NOP*/; + while ( tot_len && prot_cnt && IN_PORT_WORD( reg ) & (HCMD_BUSY|HREG_OFFSET_ERR) ) prot_cnt--; + if ( prot_cnt == 0 ) { + /* ;? It could be discussed whether the HREG_OFFSET_ERR bit should result in blocking NIC access + * till next initialize */ + rc = ifbp->IFB_TimStat = HCF_ERR_TIME_OUT; + } + } + *p1 += (hcf_16)tot_len; /* 4 */ + } + reg += HREG_DATA_0 - HREG_OFFSET_0; // reg = data register + if ( rc == HCF_SUCCESS && type == IO_IN ) { //input + if ( tot_len ) { + if ( offset & 0x01 ) { /*odd */ /* 10*/ + *pc_addr++ = IN_PORT_BYTE( reg+1 ); + tot_len--; + } + cp = pc_addr; + tlen = DIV_BY_2( tot_len ); + IN_PORT_STRING( reg, cp, tlen ); + if ( tot_len & 1 ) *(pc_addr + tot_len - 1) = IN_PORT_BYTE( reg ); /* 11*/ + while ( word_len-- ) { + CNV_LITTLE_TO_INT_NP( wp ); /* 12*/ + wp++; + } + } + } + if ( rc == HCF_SUCCESS && type != IO_IN ) { //output and/or check + tlen = word_len; /* 20*/ + while ( tlen-- ) { /* 20*/ + OUT_PORT_WORD( reg, *(wci_recordp)pc_addr ); + pc_addr += 2; + } +// tlen = offset + tot_len; + if ( tot_len && offset & 0x01 ) { /* 21*/ + OUT_PORT_WORD( reg, CNV_LITTLE_TO_INT( (*pc_addr <<8) + IN_PORT_BYTE( reg ) ) ); + pc_addr++; + tot_len--; + } + word_len = DIV_BY_2( tot_len ) - word_len; //misuse no longer needed parameter as temporary variable + cp = pc_addr; + OUT_PORT_STRING( reg, cp, word_len ); + if ( tot_len & 1 ) OUT_PORT_BYTE( reg, *(pc_addr + tot_len - 1) ); /* 22*/ + + + if ( type == IO_OUT_CHECK /*&& *p1 != ifbp->IFB_FSBase */) { //;? should BE HARD CODED /* 30*/ + if ( *p1 & 0X01 ) (void)IN_PORT_WORD( reg ); //align on word boundary + OUT_PORT_WORD( reg, 0xCAFE ); + OUT_PORT_WORD( reg, 0xABBA ); + OUT_PORT_WORD( reg, 0xDEAD ); + OUT_PORT_WORD( reg, 0xD00F ); +//!! OUT_PORT_WORD( bap - HREG_OFFSET_0 + HREG_SELECT_0, fid ); /* 31*/ + OUT_PORT_WORD( reg - HREG_DATA_0 + HREG_OFFSET_0, (*p1 + 1)&0xFFFE ); + prot_cnt = ifbp->IFB_TickIni; + while ( prot_cnt && IN_PORT_WORD(reg - HREG_DATA_0 + HREG_OFFSET_0) & (HCMD_BUSY|HREG_OFFSET_ERR) ) prot_cnt--; + if ( prot_cnt == 0 ) { + rc = ifbp->IFB_TimStat = HCF_ERR_TIME_OUT; + } + if ( IN_PORT_WORD( reg ) != 0xCAFE ) { + rc = HCF_FAILURE; + ifbp->IFB_PIFRscInd = 1; +//! } else { +//! rc = HCF_SUCCESS; + } + } + } + if ( rc == HCF_SUCCESS ) { /* 40*/ + if ( IN_PORT_WORD( ifbp->IFB_IOBase + HREG_SW_0 ) != HCF_MAGIC ) rc = HCF_ERR_NO_NIC; + } + +//! ASSERT( bap_ini( ifbp, bap, fid, (offset + len) & 0xFFFE) == HCF_SUCCESS ) /*99 */ + return rc; +}/* hcfio_string */ + diff -u --recursive --new-file linux/drivers/net/pcmcia/wvlan_mdd.h linux-2.4.1-wavelan/drivers/net/pcmcia/wvlan_mdd.h --- linux/drivers/net/pcmcia/wvlan_mdd.h Wed Dec 31 18:00:00 1969 +++ linux-2.4.1-wavelan/drivers/net/pcmcia/wvlan_mdd.h Tue Jan 30 17:50:35 2001 @@ -0,0 +1,472 @@ +/* This file is part of the Hardware Control Functions Light (HCF-light) library + to control the Lucent Technologies WaveLAN/IEEE Network I/F Card. + The HCF is the implementation of the Wireless Connection I/F (WCI). + + The HCF-light files are a subset of the HCF files. The complete set offers a + number of additional facilities, e.g. firmware download, Etherner-II encapsulation, + additional diagnostic facilities, ASSERT logic to support debugging, 802.11 support, + Configuration Management. + This complete set is explicitely not in the Public Domain but can be made + available under certain restriction. (see the pointer below for support) + + The HCF-light files are free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + At the time of this writing, you can request for support at: + betasupport@wavelan.com + + Documentation is expected to be available in the week of 8 Februari 1999 + +*/ + + +#ifndef MDD_H +#define MDD_H 1 + +/************************************************************************************************************* +* +* FILE : mdd.h +* +* DATE : 2000/07/14 23:27:51 1.4 +* +* AUTHOR : Nico Valster +* +* DESC : Definitions and Prototypes for HCF, MSF, UIL as well as USF sources +* +* +* +* Implementation Notes +* + - Typ rather than type is used as field names in structures like CFG_CIS_STRCT because type leads to + conflicts with MASM when the H-file is converted to an INC-file +* +************************************************************************************************************** +Instructions to convert MDD.H to MDD.INC by means of H2INC + +Use a command line which defines the specific macros and command line options +needed to build the C-part, e.g. for the DOS ODI driver + `h2inc /C /Ni /Zp /Zn mdd mdd.h` + + +************************************************************************************************************** +* COPYRIGHT (c) 1998 by Lucent Technologies. All Rights Reserved. +*************************************************************************************************************/ + +/**************************************************************************** +wvlan_mdd.h,v +Revision 1.4 2000/07/14 23:27:51 root +*** empty log message *** + +Revision 1.3 2000/02/28 23:09:38 root +*** empty log message *** + +Revision 1.2 2000/01/06 23:30:53 root +*** empty log message *** + + * + * Rev 1.0 02 Feb 1999 14:32:36 NVALST + * Initial revision. +Revision 1.3 1999/02/01 22:58:35 nico +*** empty log message *** + +Revision 1.2 1999/02/01 21:01:41 nico +*** empty log message *** + +Revision 1.1 1999/01/30 19:24:39 nico +Initial revision + +Revision 1.1 1999/01/30 19:07:57 nico +Initial revision + + * + * Rev 1.110 29 Jan 1999 15:52:44 NVALST + * intermediate, maybe working but seems to need two times to load in + * light-version + * + * Rev 2.12 29 Jan 1999 10:48:46 NVALST + * + * Rev 1.108 28 Jan 1999 14:43:24 NVALST + * intermediate, once more correction of loop in hcf_service_nic + download + * passed to Marc + * + * Rev 2.11 27 Jan 1999 16:57:42 NVALST + * + * Rev 1.107 27 Jan 1999 13:53:24 NVALST + * intermediate, once more correction of loop in hcf_service_nic + * + * Rev 1.106 26 Jan 1999 16:42:46 NVALST + * intermediate, corrected loop in hcf_service_nic (which was as result of a + * walkthrough, changed from a bug without consequences into one with consequences + * + * Rev 1.105 25 Jan 1999 14:24:48 NVALST + * intermediate, hopefully suitable for release + * + * Rev 1.104 22 Jan 1999 16:59:34 NVALST + * intermediate, minor corrections + some HCF-L stuff + * + * Rev 1.103 15 Jan 1999 15:14:46 NVALST + * intermediate, deposited as HCF2.10 + * + * Rev 2.10 15 Jan 1999 14:54:36 NVALST + * + * +****************************************************************************/ + + +/**************************************************************************** +* +* CHANGE HISTORY +* + 961018 - NV + Original Entry, split of from HCF.H + +*************************************************************************************************************/ + +/****************************** M A C R O S ********************************************************/ + +/* min and max macros */ +#if !defined(max) +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif +#if !defined(min) +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + + +/*************************************************************************************************************/ + +/****************************** General define ***************************************************************/ + +#define MAC_ADDR_SIZE 6 +#define GROUP_ADDR_SIZE (32 * MAC_ADDR_SIZE) +#define STAT_NAME_SIZE 32 + + + +//IFB field related +// IFB_CardStat +#define CARD_STAT_PRESENT 0x8000U /* MSF defines card as being present + * controls whether hcf-function is allowed to do I/O */ +#define CARD_STAT_ENABLED 0x4000U // one or more MAC Ports enabled +#define CARD_STAT_INI 0x0800U // Hermes Initiliazed + +// IFB_RxStat +#define RX_STAT_ERR 0x0003U //Error mask +#define RX_STAT_UNDECR 0x0002U //Non-decryptable encrypted message +#define RX_STAT_FCS_ERR 0x0001U //FCS error + +/****************************** Xxxxxxxx *********************************************************************/ + +enum /*hcf_stat*/ { + HCF_FAILURE = 0xFF, /* An (unspecified) failure, 0xFF is choosen to have a non-ubiquitous value + * Note that HCF_xxxx errors which can end up in the CFG_DIAG LTV should + * never exceed 0xFF, because the high order byte of VAL[0] is reserved + * for Hermes errors + */ + HCF_SUCCESS = 0x00, // 0x00: OK + //gap for ODI related status + HCF_ERR_DIAG_0 = 0x02, // 0x02: HCF noticed an error after hcf_disable, before diagnose command + HCF_ERR_DIAG_1, // 0x03: HCF noticed an error after succesful diagnose command + HCF_ERR_TIME_OUT, // 0x04: Expected Hermes event did not occure in expected time + HCF_ERR_NO_NIC, // 0x05: card not found (usually yanked away during hcfio_in_string + HCF_ERR_BUSY, // 0x06: ;?Inquire cmd while another Inquire in progress + HCF_ERR_SEQ_BUG, // 0x07: other cmd than the expected completed, probably HCF-bug + HCF_ERR_LEN, // 0x08: buffer size insufficient + // - hcf_get_info buffer has a size of 0 or 1 or less than needed + // to accomodate all data +}; + +#define HCF_INT_PENDING 1 // (ODI initiated) return status of hcf_act( HCF_ACT_INT_OFF ) + + + +/* hard coded values (e.g. for HCF_ACT_TALLIES and HCF_ACT_INT_OFF) are needed for HCFL */ +typedef enum { /*hcf_action_cmd*/ + /* gap left over by swapping 3 frame mode action with 4 INT_OFF/_ON + * CARD_IN/_OUT. This was done to have HCFL default automagically + * to HCF_ACT_802_3_PURE + * This gap available for future features */ + HCF_ACT_SPARE_03, //03 gap available for future features + /* DUI code 0x04 -> DON'T EVER MOVE */ + /* DUI code 0x05 -> DON'T EVER MOVE */ + HCF_ACT_TALLIES = 0x05, //05 Hermes Inquire Tallies (F100) command +#if defined HCF_ASSERT + HCF_ACT_ASSERT_OFF, //09 de-activate Assert reporting + HCF_ACT_ASSERT_ON, //0A activate Assert reporting +#else +#endif // HCF_ASSERT + /* DUI code 0x0B -> DON'T EVER MOVE */ + /* DUI code 0x0C -> DON'T EVER MOVE */ + HCF_ACT_INT_OFF = 0x0D, //0D Disable Interrupt generation + HCF_ACT_INT_ON, //0E Enable Interrupt generation + HCF_ACT_CARD_IN, //0F MSF reported Card insertion + HCF_ACT_CARD_OUT, //10 MSF reported Card removal +/* HCF_ACT_MAX // xxxx: start value for UIL-range, NOT to be passed to HCF + * Too bad, there was originally no spare room created to use + * HCF_ACT_MAX as an equivalent of HCF_ERR_MAX. Since creating + * this room in retrospect would create a backward incompatibilty + * we will just have to live with the haphazard sequence of + * UIL- and HCF specific codes. Theoretically this could be + * corrected when and if there will ever be an overall + * incompatibilty introduced for another reason + */ +} hcf_action_cmd; + + + + + + + + +/*============================================================= HCF Defined RECORDS =========================*/ +/*============================================================= INFORMATION FRRAMES =====================*/ +#define CFG_INFO_FRAME_MIN 0xF000 //lowest value representing an Informatio Frame + +#define CFG_TALLIES 0xF100 //Communications Tallies +#define CFG_SCAN 0xF101 //Scan results + +#define CFG_LINK_STAT 0xF200 //Link Status + +/*============================================================= CONFIGURATION RECORDS =====================*/ +/*============================================================= mask 0xFCxx =====================*/ +// NETWORK PARAMETERS, STATIC CONFIGURATION ENTITIES +//FC05, FC0A, FC0B, FC0C, FC0D: SEE W2DN149 + +#define CFG_RID_CFG_MIN 0xFC00 //lowest value representing a Configuration RID +#define CFG_CNF_PORT_TYPE 0xFC00 //[STA] Connection control characteristics +#define CFG_CNF_OWN_MAC_ADDR 0xFC01 //[STA] MAC Address of this node +#define CFG_CNF_DESIRED_SSID 0xFC02 //[STA] Service Set identification for connection +#define CFG_CNF_OWN_CHANNEL 0xFC03 //Communication channel for BSS creation +#define CFG_CNF_OWN_SSID 0xFC04 //IBSS creation (STA) or ESS (AP) Service Set Ident +#define CFG_CNF_OWN_ATIM_WINDOW 0xFC05 //[STA] ATIM Window time for IBSS creation +#define CFG_CNF_SYSTEM_SCALE 0xFC06 //System Scale that specifies the AP density +#define CFG_CNF_MAX_DATA_LEN 0xFC07 //Maximum length of MAC Frame Body data +#define CFG_CNF_WDS_ADDR 0xFC08 //[STA] MAC Address of corresponding WDS Link node +#define CFG_CNF_PM_ENABLED 0xFC09 //[STA] Switch for ESS Power Management (PM) On/Off +#define CFG_CNF_PM_EPS 0xFC0A //[STA] Switch for ESS PM EPS/PS Mode +#define CFG_CNF_MCAST_RX 0xFC0B //[STA] Switch for ESS PM Multicast reception On/Off +#define CFG_CNF_MAX_SLEEP_DURATION 0xFC0C //[STA] Maximum sleep time for ESS PM +#define CFG_CNF_HOLDOVER_DURATION 0xFC0D //[STA] Holdover time for ESS PM +#define CFG_CNF_OWN_NAME 0xFC0E //Identification text for diagnostic purposes + +#define CFG_CNF_ENCRYPTION 0xFC20 //select en/de-cryption of Tx/Rx messages +#define CFG_CNF_MICRO_WAVE 0xFC25 //MicroWave (Robustness) + + +// NETWORK PARAMETERS, DYNAMIC CONFIGURATION ENTITIES +#define CFG_GROUP_ADDR 0xFC80 //[STA] Multicast MAC Addresses for Rx-message +#define CFG_CREATE_IBSS 0xFC81 //[STA] Switch for IBSS creation On/Off +#define CFG_FRAGMENTATION_THRH 0xFC82 //[STA] Fragment length for unicast Tx-message +#define CFG_RTS_THRH 0xFC83 //[STA] Frame length used for RTS/CTS handshake +#define CFG_TX_RATE_CONTROL 0xFC84 //[STA] Data rate control for message transmission +#define CFG_PROMISCUOUS_MODE 0xFC85 //[STA] Switch for Promiscuous mode reception On/Off + +#define CFG_CNF_DEFAULT_KEYS 0xFCB0 //defines set of encryption keys +#define CFG_CNF_TX_KEY_ID 0xFCB1 //select key for encryption of Tx messages + + +// BEHAVIOR PARAMETERS +#define CFG_TICK_TIME 0xFCE0 //[PRI] Auxiliary Timer tick interval +#define CFG_RID_CFG_MAX 0xFCFF //highest value representing an Configuration RID + + +/*============================================================= INFORMATION RECORDS =====================*/ +/*============================================================= mask 0xFDxx =====================*/ +// NIC INFORMATION +#define CFG_RID_INF_MIN 0xFD00 //lowest value representing an Information RID +#define CFG_PRI_IDENTITY 0xFD02 +#define CFG_PRI_SUP_RANGE 0xFD03 //Primary supplier range +#define CFG_CFI_ACT_RANGES_PRI 0xFD04 + +#define CFG_HSI_SUP_RANGE 0xFD09 //H/W - S/W I/F supplier range +#define CFG_NIC_SERIAL_NUMBER 0xFD0A +#define CFG_NIC_IDENTITY 0xFD0B +#define CFG_MFI_SUP_RANGE 0xFD0C +#define CFG_CFI_SUP_RANGE 0xFD0D + +#define CFG_CHANNEL_LIST 0xFD10 //Allowed communication channels +#define CFG_REG_DOMAINS 0xFD11 //List of intended regulatory domains +#define CFG_TEMP_TYPE 0xFD12 //Hardware temperature range code +#define CFG_CIS 0xFD13 //PC Card Standard Card Information Structure + +#define CFG_STA_IDENTITY 0xFD20 +#define CFG_STA_SUP_RANGE 0xFD21 //Station supplier range +#define CFG_MFI_ACT_RANGES_STA 0xFD22 +#define CFG_CFI_ACT_RANGES_STA 0xFD23 + +// MAC INFORMATION +#define CFG_PORT_STAT 0xFD40 //[STA] Actual MAC Port connection control status +#define CFG_CURRENT_SSID 0xFD41 //[STA] Identification of the actually connected SS +#define CFG_CURRENT_BSSID 0xFD42 //[STA] Identification of the actually connected BSS +#define CFG_COMMS_QUALITY 0xFD43 //[STA] Quality of the Basic Service Set connection +#define CFG_CURRENT_TX_RATE 0xFD44 //[STA] Actual transmit data rate +#define CFG_OWN_BEACON_INTERVAL 0xFD45 //Beacon transmit interval time for BSS creation +#define CFG_CUR_SCALE_THRH 0xFD46 //Actual System Scale thresholds settings +#define CFG_PROTOCOL_RSP_TIME 0xFD47 //Max time to await a response to a request message +#define CFG_SHORT_RETRY_LIMIT 0xFD48 //Max number of transmit attempts for short frames +#define CFG_LONG_RETRY_LIMIT 0xFD49 //Max number of transmit attempts for long frames +#define CFG_MAX_TX_LIFETIME 0xFD4A //Max transmit frame handling duration +#define CFG_MAX_RX_LIFETIME 0xFD4B //Max received frame handling duration +#define CFG_CF_POLLABLE 0xFD4C //[STA] Contention Free pollable capability indication +#define CFG_AUTHENTICATION_ALGORITHMS 0xFD4D //Available Authentication Algorithms indication +#define CFG_AUTHENTICATION_TYPE 0xFD4E //Available Authentication Types indication +#define CFG_PRIVACY_OPTION_IMPLEMENTED 0xFD4F //WEP Option availability indication + + +// MODEM INFORMATION +#define CFG_PHY_TYPE 0xFDC0 // // Physical layer type indication +#define CFG_CURRENT_CHANNEL 0xFDC1 //Actual frequency channel used for transmission +#define CFG_CURRENT_POWER_STATE 0xFDC2 //Actual power consumption status +#define CFG_CCAMODE 0xFDC3 //Clear channel assessment mode indication +#define CFG_CCATIME 0xFDC4 //Clear channel assessment time +#define CFG_MAC_PROCESSING_DELAY 0xFDC5 //MAC processing delay time +#define CFG_SUPPORTED_DATA_RATES 0xFDC6 //Data rates capability information + +#define CFG_RID_INF_MAX 0xFDFF //highest value representing an Information RID + +//} hcf_info_type; + + + + +/*************************************************************************************************************/ + +/****************************** S T R U C T U R E D E F I N I T I O N S ************************************/ + +typedef struct LTV_STRCT { //used for all "minimal" LTV records + hcf_16 len; //default length of RID + hcf_16 typ; //RID identification as defined by Hermes + hcf_16 val[1]; //do not change this, some dynamic structures are defined based on this !! +}LTV_STRCT; + +typedef LTV_STRCT FAR * LTVP; + + + + + +#define COMP_ID_MINIPORT 41 //Windows 9x/NT Miniport +#define COMP_ID_PACKET 42 //Packet +#define COMP_ID_ODI_16 43 //DOS ODI +#define COMP_ID_ODI_32 44 //32-bits ODI +#define COMP_ID_MAC_OS 45 //Macintosh OS +#define COMP_ID_WIN_CE 46 //Windows CE Miniport +#define COMP_ID_LINUX 47 //You never guessed, Linux +#define COMP_ID_AP1 81 //WaveLAN/IEEE AP + + + +#define COMP_ROLE_SUPL 00 //supplier +#define COMP_ROLE_ACT 01 //actor + +#define COMP_ID_MFI 01 //Modem - Firmware I/F +#define COMP_ID_CFI 02 //Controller - Firmware I/F +#define COMP_ID_PRI 03 //Primary Firmware - Driver I/F +#define COMP_ID_STA 04 //Station Firmware - Driver I/F +#define COMP_ID_DUI 05 //Driver - Utility I/F +#define COMP_ID_HSI 06 //H/W - Driver I/F + +typedef struct KEY_STRCT { + hcf_16 len; //length of key + hcf_8 key[14]; //encryption key +} KEY_STRCT; + +typedef struct CFG_CNF_DEFAULT_KEYS_STRCT { //CFG_CNF_DEFAULT_KEYS (0xFCB0) defines set of encrypti + hcf_16 len; //default length of RID + hcf_16 typ; //RID identification as defined by Hermes + KEY_STRCT key[4]; //encryption keys +} CFG_CNF_DEFAULT_KEYS_STRCT; + + +typedef struct CFG_REG_DOMAINS_STRCT { //CFG_REG_DOMAINS (0xFD11) List of intended regulatory domains. + hcf_16 len; //length of RID + hcf_16 typ; //RID identification as defined by Hermes + hcf_16 domains[6]; +}CFG_REG_DOMAINS_STRCT; + +typedef struct CFG_CIS_STRCT { //CFG_CIS (0xFD13) PC Card Standard Card Information Structure + hcf_16 len; //length of RID + hcf_16 typ; //RID identification as defined by Hermes + hcf_16 cis[240]; //Compact CIS Area, a linked list of tuples +}CFG_CIS_STRCT; + + +typedef struct CFG_COMMS_QUALITY_STRCT {//CFG_COMMS_QUALITY (0xFD43) Quality of the Basic Service Set connection [STA] + hcf_16 len; //length of RID + hcf_16 typ; //RID identification as defined by Hermes + hcf_16 coms_qual; //Communication Quality of the BSS the station is connected to + hcf_16 signal_lvl; //Average Signal Level of the BSS the station is connected to + hcf_16 noise_lvl; //Average Noise Level of the currently used Frequency Channel +}CFG_COMMS_QUALITY_STRCT; + + + +typedef struct CFG_CUR_SCALE_THRH_STRCT {//CFG_CUR_SCALE_THRH (0xFD46) Actual System Scale thresholds + hcf_16 len; //default length of RID [STA: 6 AP: 4] + hcf_16 typ; //RID identification as defined by Hermes + hcf_16 energy_detect_thrh; //Receiver H/W Energy Detect Threshold + hcf_16 carrier_detect_thrh; //Receiver H/W Carrier Detect Threshold + hcf_16 defer_thrh; //Receiver H/W Defer Threshold + hcf_16 cell_search_thrh; //Firmware Roaming Cell Search Threshold [STA] + hcf_16 out_of_range_thrh; //Firmware Roaming Out of Range Threshold [STA] + hcf_16 delta_snr; //Firmware Roaming Delta SNR value [STA] +}CFG_CUR_SCALE_THRH_STRCT; + + +typedef struct CFG_PCF_INFO_STRCT { //CFG_PCF_INFO (0xFD87) Point Coordination Function capability info [AP] + hcf_16 len; //default length of RID + hcf_16 typ; //RID identification as defined by Hermes + hcf_16 energy_detect_thrh; + hcf_16 carrier_detect_thrh; + hcf_16 defer_thrh; + hcf_16 cell_search_thrh; + hcf_16 range_thrh; +}CFG_PCF_INFO_STRCT; + + +typedef struct CFG_MAC_ADDR_STRCT{ //0xFC01 [STA] MAC Address of this node. + //0xFC08 STA] MAC Address of corresponding WDS Link node. + //0xFC11 [AP] Port 1 MAC Adrs of corresponding WDS Link node + //0xFC12 [AP] Port 2 MAC Adrs of corresponding WDS Link node + //0xFC13 [AP] Port 3 MAC Adrs of corresponding WDS Link node + //0xFC14 [AP] Port 4 MAC Adrs of corresponding WDS Link node + //0xFC15 [AP] Port 5 MAC Adrs of corresponding WDS Link node + //0xFC16 [AP] Port 6 MAC Adrs of corresponding WDS Link node + hcf_16 len; //default length of RID + hcf_16 typ; //RID identification as defined by Hermes + hcf_16 mac_addr[3]; +}CFG_MAC_ADDR_STRCT; + +typedef struct CFG_GROUP_ADDR_STRCT{ //0xFC80 //[STA] Multicast MAC Addresses for + hcf_16 len; //default length of RID + hcf_16 typ; //RID identification as defined by Hermes + hcf_16 mac_addr[GROUP_ADDR_SIZE/6][3]; +}CFG_GROUP_ADDR_STRCT; + + +typedef struct CFG_ID_STRCT { //0xFC02 [STA] Service Set identification for connection. + //0xFC04 IBSS creation (STA) or ESS (AP) Service Set Ident + //0xFC0E Identification text for diagnostic purposes. + hcf_16 len; //default length of RID + hcf_16 typ; //RID identification as defined by Hermes + hcf_16 id[17]; +}CFG_ID_STRCT; + + +typedef void * DUIP; + +#endif // MDD_H + +