PCMCIA netdriver crap extractor

From: Elmer Joandi (elmer@ylenurme.ee)
Date: Wed Aug 09 2000 - 20:18:19 EST


okey, on David's request to contribute I took my driver and split it
into two pieces, attached to this email:
driver specific: 2675 bytes
pcmcia specific:35685 bytes.

I did it by #defines and did not try to compile, some syntax might be
wrong as I made
macroplay last time a year ago.

Bottom line:
    most of driver<-> manager code _is_ just unnecessary duplication in
every driver.
 general ratio is about 1/5 - 1/10, for other BUS types too.

It would be very nice, if someone knowing pcmcia code fully, would now
turn those ugly macros into functions by some search and replace and
would check
and make it complete...
and make an api out of it :)
so the drivers-writers would kiss him.

elmer


/*
 * Generic 4500 Pcmcia network driver
 * Started by Elmer Joandi, crap extraction
 *
 */

#define PCMCIA_NETWORK_DRIVER_VERSION(ver) \
static const char *version = ver ;

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/ptrace.h>
#include <linux/malloc.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/in.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/bitops.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/if_arp.h>
#include <linux/ioport.h>
#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
#include <pcmcia/ciscode.h>
#include <pcmcia/ds.h>

#define PCMCIA_MODULE_PARAMETERS(irq_mask,startDebug)
static u_int irq_mask = 0x5eF8;
static int pcmcia_debug = 0;
MODULE_PARM(irq_mask, "i");
MODULE_PARM(pcmcia_debug, "i");

#define PCMCIA_DRIVER_PORTS(...)\
        DRIVER_NAME##_ports[] = { ... };

#ifdef PCMCIA_DEBUG
#define PC_DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
#else
#define PC_DEBUG(n, args...)
#endif

/* Index of functions. */

#define PCMCIA_NETDRIVER_GLOBALS(DRIVER_NAME)\
static dev_link_t *dev_list = NULL; \
static dev_info_t dev_info = "##DRIVERNAME##_cs";\
static dev_link_t * DRIVER_NAME##_attach(void); \

#define DECLARE_PCMCIA_NETDRIVER_FUNCTIONS(DRIVER_NAME)\
static dev_link_t * DRIVER_NAME##_attach(void) \
static void DRIVER_NAME##_detach(dev_link_t *); \
static void DRIVER_NAME##_pcmcia_config(dev_link_t *link); \
static void DRIVER_NAME##_release(u_long arg); \
static int DRIVER_NAME##_event(event_t event, int priority, \
                                           event_callback_args_t *args); \
static int DRIVER_NAME##_pcmcia_init(struct net_device *dev); \
static int DRIVER_NAME##_pcmcia_open(struct net_device *dev); \
static int DRIVER_NAME##_pcmcia_close(struct net_device *dev ); \
static void DRIVER_NAME##_pcmcia_config(dev_link_t *link);

#define PCMCIA_DEFINE_BOGUS_FUNCTIONS\
static void cs_error(client_handle_t handle, int func, int ret) \
{ \
        error_info_t err = { func, ret }; \
        CardServices(ReportError, handle, &err); \
} \
static void flush_stale_links(void) \
{ \
    dev_link_t *link, *next; \
    for (link = dev_list; link; link = next) { \
        next = link->next; \
        if (link->state & DEV_STALE_LINK) \
            DRIVER_NAME##_detach(link); \
    } \
}

#define CFG_CHECK(fn, args...) if (CardServices(fn, args) != 0) goto next_entry
#define CS_CHECK(fn, args...) \
while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed

#define PCMCIA_DEFINE_NETDRIVER_FUNCTIONS(DRIVER_NAME) \
static int DRIVER_NAME##_pcmcia_init(struct net_device *dev) \
{ \
        return DRIVER_NAME##_init(dev); \
} \
\
static int DRIVER_NAME##_pcmcia_open(struct net_device *dev) \
{ \
        dev_link_t *link; \
        int status; \
        for (link = dev_list; link; link = link->next) \
                if (link->priv == dev) break; \
        if (!DEV_OK(link)) \
                return -ENODEV; \
        status = DRIVER_NAME##_open(dev); \
        if (!status ) \
                link->open++; \
        return status; \
} \
                                                             \
static int DRIVER_NAME##_pcmcia_close(struct net_device *dev)\
{ \
        dev_link_t *link; \
        int ret; \
                                                             \
        for (link = dev_list; link; link = link->next) \
                if (link->priv == dev) break; \
        if (link == NULL) \
                return -ENODEV; \
                                                             \
        PC_DEBUG(2, "%s: closing device.\n", dev->name); \
                                                             \
        link->open--; \
        ret = DRIVER_NAME##_close(dev); \
                                                             \
        if (link->state & DEV_STALE_CONFIG) { \
                link->release.expires = RUN_AT( HZ/20 ); \
                link->state |= DEV_RELEASE_PENDING; \
                add_timer(&link->release); \
        } \
        return ret; \
} \
                                                             \
static dev_link_t *DRIVER_NAME##_attach(void) \
{ \
        client_reg_t client_reg; \
        dev_link_t *link = NULL; \
        struct net_device *dev = NULL; \
        int ret; \
                                                             \
        PC_DEBUG(0, "DRIVER_NAME##_attach()\n"); \
        flush_stale_links(); \
                                                             \
                                                             \
        link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); \
        memset(link, 0, sizeof(struct dev_link_t)); \
        link->dev = kmalloc(sizeof(struct dev_node_t), GFP_KERNEL); \
        memset(link->dev, 0, sizeof(struct dev_node_t)); \
                                                                        \
        link->release.function = &DRIVER_NAME##_release; \
        link->release.data = (u_long)link; \
        link->irq.IRQInfo2 = irq_mask; \
        link->conf.Attributes = CONF_ENABLE_IRQ; \
        link->conf.Vcc = 50; \
        link->conf.IntType = INT_MEMORY_AND_IO; \
        link->conf.ConfigIndex = 1; \
        link->conf.Present = PRESENT_OPTION; \
                                                                        \
        PCMCIA_NETDRIVER_LINK_INIT \
                                                                        \
        dev = kmalloc(sizeof(struct net_device ), GFP_KERNEL); \
        memset(dev,0,sizeof(struct net_device)); \
                                                                        \
        if (!dev ) { \
                printk(KERN_CRIT "out of mem on dev alloc \n"); \
                kfree(link->dev); \
                kfree(link); \
                return NULL; \
        }; \
        dev->priv = kmalloc(sizeof(struct DRIVER_NAME##_private), GFP_KERNEL); \
        if (!dev->priv ) {printk(KERN_CRIT "out of mem on dev priv alloc \n"); return NULL;};\
        memset(dev->priv,0,sizeof(struct DRIVER_NAME##_private)); \
                                                                        \
        PCMCIA_NETDRIVER_NET_DEVICE_INIT \
                                                                        \
        dev->init = &DRIVER_NAME##_pcmcia_init; \
        dev->open = &DRIVER_NAME##_pcmcia_open; \
        dev->stop = &DRIVER_NAME##_pcmcia_close; \
                                                                        \
        link->priv = dev; \
#if CS_RELEASE_CODE > 0x2911 \
        link->irq.Instance = dev; \
#endif \
                                                                        \
        /* Register with Card Services */ \
        link->next = dev_list; \
        dev_list = link; \
                                                                        \
                                                                        \
        client_reg.dev_info = &dev_info; \
        client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; \
        client_reg.EventMask = \
                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 = &DRIVER_NAME##_event; \
        client_reg.Version = 0x0210; \
        client_reg.event_callback_args.client_data = link; \
        ret = CardServices(RegisterClient, &link->handle, &client_reg); \
        if (ret != 0) { \
                cs_error(link->handle, RegisterClient, ret); \
                DRIVER_NAME##_detach(link); \
                return NULL; \
        } \
        DRIVER_NAME##_detach(link->priv); \ \
        return link; \
} \
                                                                        \
                                                                        \
static void DRIVER_NAME##_detach(dev_link_t *link) \
{ \
        dev_link_t **linkp; \
        long flags; \
        int i=0; \
                                                                        \
        DEBUG(0, "DRIVER_NAME##_detach(0x%p)\n", link); \
                                                                        \
        /* Locate device structure */ \
        for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) \
                if (*linkp == link) break; \
        if (*linkp == NULL) \
        return; \
                                                                        \
        save_flags(flags); \
        cli(); \
        if (link->state & DEV_RELEASE_PENDING) { \
                del_timer(&link->release); \
                link->state &= ~DEV_RELEASE_PENDING; \
        } \
        restore_flags(flags); \
                                                                        \
        if (link->state & DEV_CONFIG) { \
                DRIVER_NAME##_release((u_long)link); \
                if (link->state & DEV_STALE_CONFIG) { \
                        link->state |= DEV_STALE_LINK; \
                        return; \
                } \
        } \
                                                                        \
        if (link->handle) \
                CardServices(DeregisterClient, link->handle); \
                                                                        \
        /* Unlink device structure, free bits */ \
        *linkp = link->next; \
                                                                        \
        DRIVER_NAME##_detach(link->priv) \
        if (link->priv) { \
                kfree(link->priv); \
        } \
        kfree(link->dev); \
        kfree(link); \
} \
                                                                        \
                                                                        \
static void DRIVER_NAME##_pcmcia_config(dev_link_t *link) \
{ \
        client_handle_t handle; \
        struct net_device *dev; \
        struct DRIVER_NAME##_private *lp; \
        tuple_t tuple; \
        int ii; \
        cisparse_t parse; \
        u_short buf[64]; \
        int last_fn, last_ret, i = 0; \
        u16 *phys_addr; \
        int retval; \
                                                                        \
        handle = link->handle; \
        dev = link->priv; \
        phys_addr = (u16 *)dev->dev_addr; \
                                                                        \
        PC_DEBUG(0, "DRIVER_NAME##_pcmcia_config(0x%p)\n", link); \
                                                                        \
        tuple.Attributes = 0; \
        tuple.DesiredTuple = CISTPL_CONFIG; \
        CS_CHECK(GetFirstTuple, handle, &tuple); \
        tuple.TupleData = (cisdata_t *)buf; \
        tuple.TupleDataMax = 64; \
        tuple.TupleOffset = 0; \
        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; \
                                                                        \
             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->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg; \
                if (cfg->index == 0) goto next_entry; \
                link->conf.ConfigIndex = cfg->index; \
                                                                        \
                /* Use power settings for Vcc and Vpp if present */ \
                /* Note that the CIS values need to be rescaled */ \
                if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) \
                    link->conf.Vcc = cfg->vcc.param[CISTPL_POWER_VNOM]/10000; \
                else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) \
                    link->conf.Vcc = dflt.vcc.param[CISTPL_POWER_VNOM]/10000; \
                                                                                \
                if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM)) \
                    link->conf.Vpp1 = link->conf.Vpp2 = \
                        cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; \
                else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM)) \
                    link->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; \
                            } \
                } \
                ii = 0; \
                last_fn = RequestIO; \
                while ((last_ret = CardServices(RequestIO, link->handle, &link->io)) ){ \
                                                                                        \
                        if (ii > 4) \
                                goto cs_failed; \
                        link->io.BasePort1 = DRIVER_NAME##_ports[ii]; \
                        ii++; \
                }; \
                                                                                        \
                                                                                        \
                break; \
                                                                                        \
            next_entry: \
                if (CardServices(GetNextTuple, handle, &tuple)) \
                        break; \
            } \
                                                                                        \
            if (link->conf.Attributes & CONF_ENABLE_IRQ){ \
                                                                                        \
                ii = 0; last_fn = RequestIRQ; \
                while ((last_ret = CardServices(RequestIRQ, link->handle, &link->irq)) ){ \
                                                                                           \
                        ii++; \
                        while (!(irq_mask & (1 << ii) ) && ii < 15) \
                                 ii++; \
                        link->irq.IRQInfo2 = 1 << ii; \
                                                                                           \
                        if(ii > 15) \
                                goto cs_failed; \
                        printk("trying irq %d , mask %x \n",ii, link->irq.IRQInfo2); \
                                                                                           \
                }; \
        } \
                                                                                           \
            CS_CHECK(RequestConfiguration, link->handle, &link->conf); \
                                                                                           \
                                                                                           \
            dev->irq = link->irq.AssignedIRQ; \
            dev->base_addr = link->io.BasePort1; \
                                                                                           \
                                                                                           \
        DRIVER_NAME##_private_init( dev); \
                                                                                           \
                                                                                           \
                                                                                           \
        retval = register_netdev(dev); \
        if (retval != 0) { \
                printk(KERN_NOTICE "DRIVER_NAME##_cs: register_netdev() failed for dev %x retval %x\n",(unsigned int)dev,retval); \
                goto failed; \
        } \
                                                                                           \
            if(DRIVER_NAME##_pcmcia_init(dev)) goto failed; \
                                                                                           \
        i=0; \
        while (aironet4500_devices[i] && i < MAX_AWCS-1) i++; \
        if (!aironet4500_devices[i]){ \
                aironet4500_devices[i]=dev; \
                if (DRIVER_NAME##_proc_set_fun) \
                        DRIVER_NAME##_proc_set_fun(i); \
        } \
                                                                                           \
                                                                                           \
        link->state &= ~DEV_CONFIG_PENDING; \
                                                                                           \
        lp = (struct DRIVER_NAME##_private *)dev->priv; \
                                                                                           \
        DEBUG(1,"pcmcia config complete on port %x \n",(unsigned int)dev->base_addr); \
                                                                                           \
        return; \
                                                                                           \
cs_failed: \
        cs_error(link->handle, last_fn, last_ret); \
        link->dev=NULL; \
failed: \
                                                                                           \
        DRIVER_NAME##_release((u_long)link); \
        return; \
                                                                                           \
} \
                                                                                           \
static void DRIVER_NAME##_release(u_long arg) \
{ \
        dev_link_t *link = (dev_link_t *)arg; \
        struct net_device *dev = link->priv; \
                                                                                           \
        DEBUG(0, "DRIVER_NAME##_release(0x%p)\n", link); \
                                                                                           \
        if (link->open) { \
                DEBUG(1, "DRIVER_NAME##_cs: release postponed, '%s' still open\n", \
                          link->dev->dev_name); \
                link->state |= DEV_STALE_CONFIG; \
                return; \
        } \
                                                                                           \
        CardServices(ReleaseConfiguration, link->handle); \
        CardServices(ReleaseIO, link->handle, &link->io); \
        CardServices(ReleaseIRQ, link->handle, &link->irq); \
                                                                                           \
        CardServices(ReleaseWindow, link->win); \
        if (link->dev) \
                unregister_p80211_netdev(dev); \
                                                                                           \
        link->state &= ~DEV_CONFIG; \
        if (link->state & DEV_STALE_LINK) \
                DRIVER_NAME##_detach(link); \
                                                                                           \
} /* DRIVER_NAME##_release */ \
                                                                                           \
static int DRIVER_NAME##_event(event_t event, int priority, \
                                           event_callback_args_t *args) \
{ \
        dev_link_t *link = args->client_data; \
        struct net_device *dev = link->priv; \
                                                                                           \
        PC_DEBUG(1, "DRIVER_NAME##_event(0x%06x)\n", event); \
                                                                                           \
        switch (event) { \
        case CS_EVENT_CARD_REMOVAL: \
                link->state &= ~DEV_PRESENT; \
                if (link->state & DEV_CONFIG) { \
                        netif_device_detach(dev); \
                        link->release.expires = RUN_AT( HZ/20 ); \
                        add_timer(&link->release); \
                } \
                break; \
        case CS_EVENT_CARD_INSERTION: \
                link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; \
                DRIVER_NAME##_pcmcia_config(link); \
                break; \
        case CS_EVENT_PM_SUSPEND: \
                link->state |= DEV_SUSPEND; \
                 DRIVER_NAME##_suspend(dev); \
        case CS_EVENT_RESET_PHYSICAL: \
                if (link->state & DEV_CONFIG) { \
                        if (link->open) \
                                netif_device_detach(dev); \
                                DRIVER_NAME##_reset_physical(dev); \
                        CardServices(ReleaseConfiguration, link->handle); \
                } \
                break; \
        case CS_EVENT_PM_RESUME: \
                DRIVER_NAME##_resume(dev); \
                link->state &= ~DEV_SUSPEND; \
        case CS_EVENT_CARD_RESET: \
                if (link->state & DEV_CONFIG) { \
                        CardServices(RequestConfiguration, link->handle, &link->conf); \
                        if (link->open) { \
                                netif_device_attach(dev); \
                                DRIVER_NAME##_reset(dev); \
                        } \
                } \
                break; \
        } \
        return 0; \
} \
                                                                                           \
                                                                                           \
                                                                                           \
static int __init DRIVER_NAME##_cs_init(void) \
{ \
        servinfo_t serv; \
                                                                                           \
        /* Always emit the version, before any failure. */ \
        printk(KERN_INFO"%s", DRIVER_NAME##_version); \
        PC_DEBUG(0, "%s\n", version); \
        CardServices(GetCardServicesInfo, &serv); \
        if (serv.Revision != CS_RELEASE_CODE) { \
                printk(KERN_NOTICE "DRIVER_NAME##_cs: Card Services release " \
                           "does not match!\n"); \
                return -1; \
        } \
        register_pcmcia_driver(&dev_info, &DRIVER_NAME##_attach, &DRIVER_NAME##_detach); \
        return 0; \
} \
                                                                                           \
static void __exit DRIVER_NAME##_cs_exit(void) \
{ \
        DEBUG(0, "DRIVER_NAME##_cs: unloading %c ",'\n'); \
        unregister_pcmcia_driver(&dev_info); \
                                                                                           \
        while (dev_list != NULL) { \
                if (dev_list->state & DEV_CONFIG) \
                        DRIVER_NAME##_release((u_long)dev_list); \
                DRIVER_NAME##_detach(dev_list); \
        } \
} \
                                                                                           \
module_init(DRIVER_NAME##_cs_init); \
module_exit(DRIVER_NAME##_cs_exit); \


/*
 * Aironet 4500 Pcmcia driver
 *
 * Elmer Joandi, Januar 1999
 * Copyright Elmer Joandi, all rights restricted
 *
 *
 * Revision 0.1 ,started 30.12.1998
 *
 *
 */
#include <linux/pcmcia_net_api.h>
#include "../aironet4500.h"

#define PCMCIA_DEBUG
PCMCIA_NETWORK_DRIVER_VERSION("aironet4500_cs.c v0.1 1/1/99 Elmer Joandi, elmer@ylenurme.ee.\n");
PCMCIA_MODULE_PARAMETERS(0x5eF8,0);
PCMCIA_DRIVER_PORTS(0x140,0x100,0xc0, 0x80);
PCMCIA_NETDRIVER_GLOBALS(aironet4500)
PCMCIA_DECLARE_NETDRIVER_FUNCTIONS(aironet4500)
PCMCIA_DEFINE_BOGUS_FUNCTIONS

/* this is the very specifc stuff */
#define PCMCIA_NETDRIVER_LINK_INIT \
        link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; \
        link->irq.Attributes = IRQ_HANDLE_PRESENT |IRQ_TYPE_EXCLUSIVE ;\
        link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; \
        link->irq.IRQInfo2 = irq_mask; \
        link->irq.Handler = &awc_interrupt; \
        link->conf.Attributes = CONF_ENABLE_IRQ; \
        link->conf.Vcc = 50; \
        link->conf.IntType = INT_MEMORY_AND_IO; \
        link->conf.ConfigIndex = 1; \
        link->conf.Present = PRESENT_OPTION;

 /* please note, that dev->open, close and init are set in macro afterwards
  */
#define PCMCIA_NETDRIVER_NET_DEVICE_INIT \
        dev->hard_start_xmit = &awc_start_xmit;
        dev->get_stats = &awc_get_stats;
        strcpy(dev->name, ((struct awc_private *)dev->priv)->node.dev_name);

static int aironet4500_init(struct net_device * dev){ return awc_init(dev); };
static int aironet4500_open(struct net_device * dev){ return awc_open(dev); };
static int aironet4500_close(struct net_device * dev){ return awc_close(dev); };
static int aironet4500_private_init(struct net_device * dev){ return awc_private_init(dev); };
static int aironet4500_suspend(struct net_device * dev){ return 0 ; };
static int aironet4500_resume(struct net_device * dev){ return 0; };
static int aironet4500_reset(struct net_device * dev){ return awc_reset(dev); };
static int aironet4500_reset_physical(struct net_device * dev){ return awc_reset(dev); };
static void aironet4500_attach( dev_link_t *link) { };
static void aironet4500_detach( dev_link_t *link) {
        int i=0;
        i=0;
        while ( i < MAX_AWCS) {
                if (!aironet4500_devices[i])
                        {i++; continue;}
                if (aironet4500_devices[i] == link->priv){
                        if (awc_proc_unset_fun)
                                awc_proc_unset_fun(i);

                        aironet4500_devices[i]=0;
                }
                i++;
        }

};

/* this does most of it */
PCMCIA_DEFINE_NETDRIVER_FUNCTIONS(aironet4500)

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Tue Aug 15 2000 - 21:00:19 EST