Annotation of Gnu-Mach/linux/pcmcia-cs/wireless/orinoco_cs.c, revision 1.1

1.1     ! root        1: /* orinoco_cs.c 0.13e  - (formerly known as dldwd_cs.c)
        !             2:  *
        !             3:  * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such
        !             4:  * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/
        !             5:  * EnteraSys RoamAbout 802.11, ELSA Airlancer, Melco Buffalo and others).
        !             6:  * It should also be usable on various Prism II based cards such as the
        !             7:  * Linksys, D-Link and Farallon Skyline. It should also work on Symbol
        !             8:  * cards such as the 3Com AirConnect and Ericsson WLAN.
        !             9:  * 
        !            10:  * Copyright notice & release notes in file orinoco.c
        !            11:  */
        !            12: 
        !            13: #include <linux/config.h>
        !            14: #include <linux/module.h>
        !            15: #include <linux/kernel.h>
        !            16: #include <linux/init.h>
        !            17: #include <linux/sched.h>
        !            18: #include <linux/ptrace.h>
        !            19: #include <linux/slab.h>
        !            20: #include <linux/string.h>
        !            21: #include <linux/ioport.h>
        !            22: #include <linux/netdevice.h>
        !            23: #include <linux/if_arp.h>
        !            24: #include <linux/etherdevice.h>
        !            25: #include <linux/wireless.h>
        !            26: 
        !            27: #include <pcmcia/version.h>
        !            28: #include <pcmcia/cs_types.h>
        !            29: #include <pcmcia/cs.h>
        !            30: #include <pcmcia/cistpl.h>
        !            31: #include <pcmcia/cisreg.h>
        !            32: #include <pcmcia/ds.h>
        !            33: 
        !            34: #include <asm/uaccess.h>
        !            35: #include <asm/io.h>
        !            36: #include <asm/system.h>
        !            37: 
        !            38: #include "orinoco.h"
        !            39: 
        !            40: /********************************************************************/
        !            41: /* Module stuff                                                            */
        !            42: /********************************************************************/
        !            43: 
        !            44: MODULE_AUTHOR("David Gibson <[email protected]>");
        !            45: MODULE_DESCRIPTION("Driver for PCMCIA Lucent Orinoco, Prism II based and similar wireless cards");
        !            46: #ifdef MODULE_LICENSE
        !            47: MODULE_LICENSE("Dual MPL/GPL");
        !            48: #endif
        !            49: 
        !            50: /* Module parameters */
        !            51: 
        !            52: /* The old way: bit map of interrupts to choose from */
        !            53: /* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */
        !            54: static uint irq_mask = 0xdeb8;
        !            55: /* Newer, simpler way of listing specific interrupts */
        !            56: static int irq_list[4] = { -1 };
        !            57: 
        !            58: /* Some D-Link cards have buggy CIS. They do work at 5v properly, but
        !            59:  * don't have any CIS entry for it. This workaround it... */
        !            60: static int ignore_cis_vcc; /* = 0 */
        !            61: 
        !            62: MODULE_PARM(irq_mask, "i");
        !            63: MODULE_PARM(irq_list, "1-4i");
        !            64: MODULE_PARM(ignore_cis_vcc, "i");
        !            65: 
        !            66: /********************************************************************/
        !            67: /* Magic constants                                                 */
        !            68: /********************************************************************/
        !            69: 
        !            70: /*
        !            71:  * The dev_info variable is the "key" that is used to match up this
        !            72:  * device driver with appropriate cards, through the card
        !            73:  * configuration database.
        !            74:  */
        !            75: static dev_info_t dev_info = "orinoco_cs";
        !            76: 
        !            77: /********************************************************************/
        !            78: /* Data structures                                                 */
        !            79: /********************************************************************/
        !            80: 
        !            81: /* PCMCIA specific device information (goes in the card field of
        !            82:  * struct orinoco_private */
        !            83: struct orinoco_pccard {
        !            84:        dev_link_t link;
        !            85:        dev_node_t node;
        !            86: 
        !            87:        /* Used to handle hard reset */
        !            88:        /* yuck, we need this hack to work around the insanity of the
        !            89:          * PCMCIA layer */
        !            90:        unsigned long hard_reset_in_progress; 
        !            91: };
        !            92: 
        !            93: /*
        !            94:  * A linked list of "instances" of the device.  Each actual PCMCIA
        !            95:  * card corresponds to one device instance, and is described by one
        !            96:  * dev_link_t structure (defined in ds.h).
        !            97:  */
        !            98: static dev_link_t *dev_list; /* = NULL */
        !            99: 
        !           100: /********************************************************************/
        !           101: /* Function prototypes                                             */
        !           102: /********************************************************************/
        !           103: 
        !           104: /* device methods */
        !           105: static int orinoco_cs_hard_reset(struct orinoco_private *priv);
        !           106: 
        !           107: /* PCMCIA gumpf */
        !           108: static void orinoco_cs_config(dev_link_t * link);
        !           109: static void orinoco_cs_release(u_long arg);
        !           110: static int orinoco_cs_event(event_t event, int priority,
        !           111:                            event_callback_args_t * args);
        !           112: 
        !           113: static dev_link_t *orinoco_cs_attach(void);
        !           114: static void orinoco_cs_detach(dev_link_t *);
        !           115: 
        !           116: /********************************************************************/
        !           117: /* Device methods                                                  */
        !           118: /********************************************************************/
        !           119: 
        !           120: static int
        !           121: orinoco_cs_hard_reset(struct orinoco_private *priv)
        !           122: {
        !           123:        struct orinoco_pccard *card = priv->card;
        !           124:        dev_link_t *link = &card->link;
        !           125:        int err;
        !           126: 
        !           127:        /* We need atomic ops here, because we're not holding the lock */
        !           128:        set_bit(0, &card->hard_reset_in_progress);
        !           129: 
        !           130:        err = CardServices(ResetCard, link->handle, NULL);
        !           131:        if (err)
        !           132:                return err;
        !           133: 
        !           134:        clear_bit(0, &card->hard_reset_in_progress);
        !           135: 
        !           136:        return 0;
        !           137: }
        !           138: 
        !           139: /********************************************************************/
        !           140: /* PCMCIA stuff                                                    */
        !           141: /********************************************************************/
        !           142: 
        !           143: /* In 2.5 (as of 2.5.69 at least) there is a cs_error exported which
        !           144:  * does this, but it's not in 2.4 so we do our own for now. */
        !           145: static void
        !           146: orinoco_cs_error(client_handle_t handle, int func, int ret)
        !           147: {
        !           148:        error_info_t err = { func, ret };
        !           149:        CardServices(ReportError, handle, &err);
        !           150: }
        !           151: 
        !           152: 
        !           153: /* Remove zombie instances (card removed, detach pending) */
        !           154: static void
        !           155: flush_stale_links(void)
        !           156: {
        !           157:        dev_link_t *link, *next;
        !           158: 
        !           159:        TRACE_ENTER("");
        !           160: 
        !           161:        for (link = dev_list; link; link = next) {
        !           162:                next = link->next;
        !           163:                if (link->state & DEV_STALE_LINK) {
        !           164:                        orinoco_cs_detach(link);
        !           165:                }
        !           166:        }
        !           167:        TRACE_EXIT("");
        !           168: }
        !           169: 
        !           170: /*
        !           171:  * This creates an "instance" of the driver, allocating local data
        !           172:  * structures for one device.  The device is registered with Card
        !           173:  * Services.
        !           174:  * 
        !           175:  * The dev_link structure is initialized, but we don't actually
        !           176:  * configure the card at this point -- we wait until we receive a card
        !           177:  * insertion event.  */
        !           178: static dev_link_t *
        !           179: orinoco_cs_attach(void)
        !           180: {
        !           181:        struct net_device *dev;
        !           182:        struct orinoco_private *priv;
        !           183:        struct orinoco_pccard *card;
        !           184:        dev_link_t *link;
        !           185:        client_reg_t client_reg;
        !           186:        int ret, i;
        !           187: 
        !           188:        /* A bit of cleanup */
        !           189:        flush_stale_links();
        !           190: 
        !           191:        dev = alloc_orinocodev(sizeof(*card), orinoco_cs_hard_reset);
        !           192:        if (! dev)
        !           193:                return NULL;
        !           194:        priv = dev->priv;
        !           195:        card = priv->card;
        !           196: 
        !           197:        /* Link both structures together */
        !           198:        link = &card->link;
        !           199:        link->priv = dev;
        !           200: 
        !           201:        /* Initialize the dev_link_t structure */
        !           202:        init_timer(&link->release);
        !           203:        link->release.function = &orinoco_cs_release;
        !           204:        link->release.data = (u_long) link;
        !           205: 
        !           206:        /* Interrupt setup */
        !           207:        link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
        !           208:        link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
        !           209:        if (irq_list[0] == -1)
        !           210:                link->irq.IRQInfo2 = irq_mask;
        !           211:        else
        !           212:                for (i = 0; i < 4; i++)
        !           213:                        link->irq.IRQInfo2 |= 1 << irq_list[i];
        !           214:        link->irq.Handler = NULL;
        !           215: 
        !           216:        /* General socket configuration defaults can go here.  In this
        !           217:         * client, we assume very little, and rely on the CIS for
        !           218:         * almost everything.  In most clients, many details (i.e.,
        !           219:         * number, sizes, and attributes of IO windows) are fixed by
        !           220:         * the nature of the device, and can be hard-wired here. */
        !           221:        link->conf.Attributes = 0;
        !           222:        link->conf.IntType = INT_MEMORY_AND_IO;
        !           223: 
        !           224:        /* Register with Card Services */
        !           225:        /* FIXME: need a lock? */
        !           226:        link->next = dev_list;
        !           227:        dev_list = link;
        !           228: 
        !           229:        client_reg.dev_info = &dev_info;
        !           230:        client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
        !           231:        client_reg.EventMask =
        !           232:                CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
        !           233:                CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
        !           234:                CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
        !           235:        client_reg.event_handler = &orinoco_cs_event;
        !           236:        client_reg.Version = 0x0210; /* FIXME: what does this mean? */
        !           237:        client_reg.event_callback_args.client_data = link;
        !           238: 
        !           239:        ret = CardServices(RegisterClient, &link->handle, &client_reg);
        !           240:        if (ret != CS_SUCCESS) {
        !           241:                orinoco_cs_error(link->handle, RegisterClient, ret);
        !           242:                orinoco_cs_detach(link);
        !           243:                return NULL;
        !           244:        }
        !           245: 
        !           246:        return link;
        !           247: }                              /* orinoco_cs_attach */
        !           248: 
        !           249: /*
        !           250:  * This deletes a driver "instance".  The device is de-registered with
        !           251:  * Card Services.  If it has been released, all local data structures
        !           252:  * are freed.  Otherwise, the structures will be freed when the device
        !           253:  * is released.
        !           254:  */
        !           255: static void
        !           256: orinoco_cs_detach(dev_link_t * link)
        !           257: {
        !           258:        dev_link_t **linkp;
        !           259:        struct net_device *dev = link->priv;
        !           260: 
        !           261:        /* Locate device structure */
        !           262:        for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
        !           263:                if (*linkp == link)
        !           264:                        break;
        !           265:        if (*linkp == NULL) {
        !           266:                BUG();
        !           267:                return;
        !           268:        }
        !           269: 
        !           270:        if (link->state & DEV_CONFIG) {
        !           271:                orinoco_cs_release((u_long)link);
        !           272:                if (link->state & DEV_CONFIG) {
        !           273:                        link->state |= DEV_STALE_LINK;
        !           274:                        return;
        !           275:                }
        !           276:        }
        !           277: 
        !           278:        /* Break the link with Card Services */
        !           279:        if (link->handle)
        !           280:                CardServices(DeregisterClient, link->handle);
        !           281: 
        !           282:        /* Unlink device structure, and free it */
        !           283:        *linkp = link->next;
        !           284:        DEBUG(0, "orinoco_cs: detach: link=%p link->dev=%p\n", link, link->dev);
        !           285:        if (link->dev) {
        !           286:                DEBUG(0, "orinoco_cs: About to unregister net device %p\n",
        !           287:                      dev);
        !           288:                unregister_netdev(dev);
        !           289:        }
        !           290:        kfree(dev);
        !           291: }                              /* orinoco_cs_detach */
        !           292: 
        !           293: /*
        !           294:  * orinoco_cs_config() is scheduled to run after a CARD_INSERTION
        !           295:  * event is received, to configure the PCMCIA socket, and to make the
        !           296:  * device available to the system.
        !           297:  */
        !           298: 
        !           299: #define CS_CHECK(fn, args...) \
        !           300:        while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed
        !           301: 
        !           302: #define CFG_CHECK(fn, args...) \
        !           303:        if (CardServices(fn, args) != 0) goto next_entry
        !           304: 
        !           305: static void
        !           306: orinoco_cs_config(dev_link_t *link)
        !           307: {
        !           308:        struct net_device *dev = link->priv;
        !           309:        client_handle_t handle = link->handle;
        !           310:        struct orinoco_private *priv = dev->priv;
        !           311:        struct orinoco_pccard *card = priv->card;
        !           312:        hermes_t *hw = &priv->hw;
        !           313:        int last_fn, last_ret;
        !           314:        u_char buf[64];
        !           315:        config_info_t conf;
        !           316:        cisinfo_t info;
        !           317:        tuple_t tuple;
        !           318:        cisparse_t parse;
        !           319: 
        !           320:        CS_CHECK(ValidateCIS, handle, &info);
        !           321: 
        !           322:        /*
        !           323:         * This reads the card's CONFIG tuple to find its
        !           324:         * configuration registers.
        !           325:         */
        !           326:        tuple.DesiredTuple = CISTPL_CONFIG;
        !           327:        tuple.Attributes = 0;
        !           328:        tuple.TupleData = buf;
        !           329:        tuple.TupleDataMax = sizeof(buf);
        !           330:        tuple.TupleOffset = 0;
        !           331:        CS_CHECK(GetFirstTuple, handle, &tuple);
        !           332:        CS_CHECK(GetTupleData, handle, &tuple);
        !           333:        CS_CHECK(ParseTuple, handle, &tuple, &parse);
        !           334:        link->conf.ConfigBase = parse.config.base;
        !           335:        link->conf.Present = parse.config.rmask[0];
        !           336: 
        !           337:        /* Configure card */
        !           338:        link->state |= DEV_CONFIG;
        !           339: 
        !           340:        /* Look up the current Vcc */
        !           341:        CS_CHECK(GetConfigurationInfo, handle, &conf);
        !           342:        link->conf.Vcc = conf.Vcc;
        !           343: 
        !           344:        /*
        !           345:         * In this loop, we scan the CIS for configuration table
        !           346:         * entries, each of which describes a valid card
        !           347:         * configuration, including voltage, IO window, memory window,
        !           348:         * and interrupt settings.
        !           349:         *
        !           350:         * We make no assumptions about the card to be configured: we
        !           351:         * use just the information available in the CIS.  In an ideal
        !           352:         * world, this would work for any PCMCIA card, but it requires
        !           353:         * a complete and accurate CIS.  In practice, a driver usually
        !           354:         * "knows" most of these things without consulting the CIS,
        !           355:         * and most client drivers will only use the CIS to fill in
        !           356:         * implementation-defined details.
        !           357:         */
        !           358:        tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
        !           359:        CS_CHECK(GetFirstTuple, handle, &tuple);
        !           360:        while (1) {
        !           361:                cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
        !           362:                cistpl_cftable_entry_t dflt = { .index = 0 };
        !           363: 
        !           364:                CFG_CHECK(GetTupleData, handle, &tuple);
        !           365:                CFG_CHECK(ParseTuple, handle, &tuple, &parse);
        !           366: 
        !           367:                if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
        !           368:                        dflt = *cfg;
        !           369:                if (cfg->index == 0)
        !           370:                        goto next_entry;
        !           371:                link->conf.ConfigIndex = cfg->index;
        !           372: 
        !           373:                /* Does this card need audio output? */
        !           374:                if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
        !           375:                        link->conf.Attributes |= CONF_ENABLE_SPKR;
        !           376:                        link->conf.Status = CCSR_AUDIO_ENA;
        !           377:                }
        !           378: 
        !           379:                /* Use power settings for Vcc and Vpp if present */
        !           380:                /* Note that the CIS values need to be rescaled */
        !           381:                if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
        !           382:                        if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) {
        !           383:                                DEBUG(2, "orinoco_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n",  conf.Vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000);
        !           384:                                if (!ignore_cis_vcc)
        !           385:                                        goto next_entry;
        !           386:                        }
        !           387:                } else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) {
        !           388:                        if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) {
        !           389:                                DEBUG(2, "orinoco_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n",  conf.Vcc, dflt.vcc.param[CISTPL_POWER_VNOM] / 10000);
        !           390:                                if(!ignore_cis_vcc)
        !           391:                                        goto next_entry;
        !           392:                        }
        !           393:                }
        !           394: 
        !           395:                if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
        !           396:                        link->conf.Vpp1 = link->conf.Vpp2 =
        !           397:                            cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
        !           398:                else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM))
        !           399:                        link->conf.Vpp1 = link->conf.Vpp2 =
        !           400:                            dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
        !           401:                
        !           402:                /* Do we need to allocate an interrupt? */
        !           403:                if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1)
        !           404:                        link->conf.Attributes |= CONF_ENABLE_IRQ;
        !           405: 
        !           406:                /* IO window settings */
        !           407:                link->io.NumPorts1 = link->io.NumPorts2 = 0;
        !           408:                if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
        !           409:                        cistpl_io_t *io =
        !           410:                            (cfg->io.nwin) ? &cfg->io : &dflt.io;
        !           411:                        link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
        !           412:                        if (!(io->flags & CISTPL_IO_8BIT))
        !           413:                                link->io.Attributes1 =
        !           414:                                    IO_DATA_PATH_WIDTH_16;
        !           415:                        if (!(io->flags & CISTPL_IO_16BIT))
        !           416:                                link->io.Attributes1 =
        !           417:                                    IO_DATA_PATH_WIDTH_8;
        !           418:                        link->io.IOAddrLines =
        !           419:                            io->flags & CISTPL_IO_LINES_MASK;
        !           420:                        link->io.BasePort1 = io->win[0].base;
        !           421:                        link->io.NumPorts1 = io->win[0].len;
        !           422:                        if (io->nwin > 1) {
        !           423:                                link->io.Attributes2 =
        !           424:                                    link->io.Attributes1;
        !           425:                                link->io.BasePort2 = io->win[1].base;
        !           426:                                link->io.NumPorts2 = io->win[1].len;
        !           427:                        }
        !           428: 
        !           429:                        /* This reserves IO space but doesn't actually enable it */
        !           430:                        CFG_CHECK(RequestIO, link->handle, &link->io);
        !           431:                }
        !           432: 
        !           433: 
        !           434:                /* If we got this far, we're cool! */
        !           435: 
        !           436:                break;
        !           437:                
        !           438:        next_entry:
        !           439:                if (link->io.NumPorts1)
        !           440:                        CardServices(ReleaseIO, link->handle, &link->io);
        !           441:                last_ret = CardServices(GetNextTuple, handle, &tuple);
        !           442:                if (last_ret  == CS_NO_MORE_ITEMS) {
        !           443:                        printk(KERN_ERR "GetNextTuple().  No matching CIS configuration, "
        !           444:                               "maybe you need the ignore_cis_vcc=1 parameter.\n");
        !           445:                        goto cs_failed;
        !           446:                }
        !           447:        }
        !           448: 
        !           449:        /*
        !           450:         * Allocate an interrupt line.  Note that this does not assign
        !           451:         * a handler to the interrupt, unless the 'Handler' member of
        !           452:         * the irq structure is initialized.
        !           453:         */
        !           454:        if (link->conf.Attributes & CONF_ENABLE_IRQ) {
        !           455:                int i;
        !           456: 
        !           457:                link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
        !           458:                link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
        !           459:                if (irq_list[0] == -1)
        !           460:                        link->irq.IRQInfo2 = irq_mask;
        !           461:                else
        !           462:                        for (i=0; i<4; i++)
        !           463:                                link->irq.IRQInfo2 |= 1 << irq_list[i];
        !           464:                
        !           465:                link->irq.Handler = orinoco_interrupt; 
        !           466:                link->irq.Instance = dev; 
        !           467:                
        !           468:                CS_CHECK(RequestIRQ, link->handle, &link->irq);
        !           469:        }
        !           470: 
        !           471:        /* We initialize the hermes structure before completing PCMCIA
        !           472:         * configuration just in case the interrupt handler gets
        !           473:         * called. */
        !           474:        hermes_struct_init(hw, link->io.BasePort1,
        !           475:                                HERMES_IO, HERMES_16BIT_REGSPACING);
        !           476: 
        !           477:        /*
        !           478:         * This actually configures the PCMCIA socket -- setting up
        !           479:         * the I/O windows and the interrupt mapping, and putting the
        !           480:         * card and host interface into "Memory and IO" mode.
        !           481:         */
        !           482:        CS_CHECK(RequestConfiguration, link->handle, &link->conf);
        !           483: 
        !           484:        /* Ok, we have the configuration, prepare to register the netdev */
        !           485:        dev->base_addr = link->io.BasePort1;
        !           486:        dev->irq = link->irq.AssignedIRQ;
        !           487:        SET_MODULE_OWNER(dev);
        !           488:        card->node.major = card->node.minor = 0;
        !           489: 
        !           490:        /* register_netdev will give us an ethX name */
        !           491:        dev->name[0] = '\0';
        !           492:        /* Tell the stack we exist */
        !           493:        if (register_netdev(dev) != 0) {
        !           494:                printk(KERN_ERR "orinoco_cs: register_netdev() failed\n");
        !           495:                goto failed;
        !           496:        }
        !           497: 
        !           498:        /* At this point, the dev_node_t structure(s) needs to be
        !           499:         * initialized and arranged in a linked list at link->dev. */
        !           500:        strcpy(card->node.dev_name, dev->name);
        !           501:        link->dev = &card->node; /* link->dev being non-NULL is also
        !           502:                                     used to indicate that the
        !           503:                                     net_device has been registered */
        !           504:        link->state &= ~DEV_CONFIG_PENDING;
        !           505: 
        !           506:        /* Finally, report what we've done */
        !           507:        printk(KERN_DEBUG "%s: index 0x%02x: Vcc %d.%d",
        !           508:               dev->name, link->conf.ConfigIndex,
        !           509:               link->conf.Vcc / 10, link->conf.Vcc % 10);
        !           510:        if (link->conf.Vpp1)
        !           511:                printk(", Vpp %d.%d", link->conf.Vpp1 / 10,
        !           512:                       link->conf.Vpp1 % 10);
        !           513:        if (link->conf.Attributes & CONF_ENABLE_IRQ)
        !           514:                printk(", irq %d", link->irq.AssignedIRQ);
        !           515:        if (link->io.NumPorts1)
        !           516:                printk(", io 0x%04x-0x%04x", link->io.BasePort1,
        !           517:                       link->io.BasePort1 + link->io.NumPorts1 - 1);
        !           518:        if (link->io.NumPorts2)
        !           519:                printk(" & 0x%04x-0x%04x", link->io.BasePort2,
        !           520:                       link->io.BasePort2 + link->io.NumPorts2 - 1);
        !           521:        printk("\n");
        !           522: 
        !           523:        return;
        !           524: 
        !           525:  cs_failed:
        !           526:        orinoco_cs_error(link->handle, last_fn, last_ret);
        !           527: 
        !           528:  failed:
        !           529:        orinoco_cs_release((u_long) link);
        !           530: }                              /* orinoco_cs_config */
        !           531: 
        !           532: /*
        !           533:  * After a card is removed, orinoco_cs_release() will unregister the
        !           534:  * device, and release the PCMCIA configuration.  If the device is
        !           535:  * still open, this will be postponed until it is closed.
        !           536:  */
        !           537: static void
        !           538: orinoco_cs_release(u_long arg)
        !           539: {
        !           540:        dev_link_t *link = (dev_link_t *) arg;
        !           541:        struct net_device *dev = link->priv;
        !           542:        struct orinoco_private *priv = dev->priv;
        !           543:        unsigned long flags;
        !           544: 
        !           545:        /* We're committed to taking the device away now, so mark the
        !           546:         * hardware as unavailable */
        !           547:        spin_lock_irqsave(&priv->lock, flags);
        !           548:        priv->hw_unavailable++;
        !           549:        spin_unlock_irqrestore(&priv->lock, flags);
        !           550: 
        !           551:        /* Don't bother checking to see if these succeed or not */
        !           552:        CardServices(ReleaseConfiguration, link->handle);
        !           553:        if (link->io.NumPorts1)
        !           554:                CardServices(ReleaseIO, link->handle, &link->io);
        !           555:        if (link->irq.AssignedIRQ)
        !           556:                CardServices(ReleaseIRQ, link->handle, &link->irq);
        !           557:        link->state &= ~DEV_CONFIG;
        !           558: }                              /* orinoco_cs_release */
        !           559: 
        !           560: /*
        !           561:  * The card status event handler.  Mostly, this schedules other stuff
        !           562:  * to run after an event is received.
        !           563:  */
        !           564: static int
        !           565: orinoco_cs_event(event_t event, int priority,
        !           566:                       event_callback_args_t * args)
        !           567: {
        !           568:        dev_link_t *link = args->client_data;
        !           569:        struct net_device *dev = link->priv;
        !           570:        struct orinoco_private *priv = dev->priv;
        !           571:        struct orinoco_pccard *card = priv->card;
        !           572:        int err = 0;
        !           573:        unsigned long flags;
        !           574: 
        !           575:        switch (event) {
        !           576:        case CS_EVENT_CARD_REMOVAL:
        !           577:                link->state &= ~DEV_PRESENT;
        !           578:                if (link->state & DEV_CONFIG) {
        !           579:                        orinoco_lock(priv, &flags);
        !           580: 
        !           581:                        netif_device_detach(dev);
        !           582:                        priv->hw_unavailable++;
        !           583: 
        !           584:                        orinoco_unlock(priv, &flags);
        !           585:                }
        !           586:                break;
        !           587: 
        !           588:        case CS_EVENT_CARD_INSERTION:
        !           589:                link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
        !           590:                orinoco_cs_config(link);
        !           591:                break;
        !           592: 
        !           593:        case CS_EVENT_PM_SUSPEND:
        !           594:                link->state |= DEV_SUSPEND;
        !           595:                /* Fall through... */
        !           596:        case CS_EVENT_RESET_PHYSICAL:
        !           597:                /* Mark the device as stopped, to block IO until later */
        !           598:                if (link->state & DEV_CONFIG) {
        !           599:                        /* This is probably racy, but I can't think of
        !           600:                            a better way, short of rewriting the PCMCIA
        !           601:                            layer to not suck :-( */
        !           602:                        if (! test_bit(0, &card->hard_reset_in_progress)) {
        !           603:                                spin_lock_irqsave(&priv->lock, flags);
        !           604: 
        !           605:                                err = __orinoco_down(dev);
        !           606:                                if (err)
        !           607:                                        printk(KERN_WARNING "%s: %s: Error %d downing interface\n",
        !           608:                                               dev->name,
        !           609:                                               event == CS_EVENT_PM_SUSPEND ? "SUSPEND" : "RESET_PHYSICAL",
        !           610:                                               err);
        !           611:                                
        !           612:                                netif_device_detach(dev);
        !           613:                                priv->hw_unavailable++;
        !           614: 
        !           615:                                spin_unlock_irqrestore(&priv->lock, flags);
        !           616:                        }
        !           617: 
        !           618:                        CardServices(ReleaseConfiguration, link->handle);
        !           619:                }
        !           620:                break;
        !           621: 
        !           622:        case CS_EVENT_PM_RESUME:
        !           623:                link->state &= ~DEV_SUSPEND;
        !           624:                /* Fall through... */
        !           625:        case CS_EVENT_CARD_RESET:
        !           626:                if (link->state & DEV_CONFIG) {
        !           627:                        /* FIXME: should we double check that this is
        !           628:                         * the same card as we had before */
        !           629:                        CardServices(RequestConfiguration, link->handle,
        !           630:                                     &link->conf);
        !           631: 
        !           632:                        if (! test_bit(0, &card->hard_reset_in_progress)) {
        !           633:                                err = orinoco_reinit_firmware(dev);
        !           634:                                if (err) {
        !           635:                                        printk(KERN_ERR "%s: Error %d re-initializing firmware\n",
        !           636:                                               dev->name, err);
        !           637:                                        break;
        !           638:                                }
        !           639:                                
        !           640:                                spin_lock_irqsave(&priv->lock, flags);
        !           641:                                
        !           642:                                netif_device_attach(dev);
        !           643:                                priv->hw_unavailable--;
        !           644:                                
        !           645:                                if (priv->open && ! priv->hw_unavailable) {
        !           646:                                        err = __orinoco_up(dev);
        !           647:                                        if (err)
        !           648:                                                printk(KERN_ERR "%s: Error %d restarting card\n",
        !           649:                                                       dev->name, err);
        !           650:                                        
        !           651:                                }
        !           652: 
        !           653:                                spin_unlock_irqrestore(&priv->lock, flags);
        !           654:                        }
        !           655:                }
        !           656:                break;
        !           657:        }
        !           658: 
        !           659:        return err;
        !           660: }                              /* orinoco_cs_event */
        !           661: 
        !           662: /********************************************************************/
        !           663: /* Module initialization                                           */
        !           664: /********************************************************************/
        !           665: 
        !           666: /* Can't be declared "const" or the whole __initdata section will
        !           667:  * become const */
        !           668: static char version[] __initdata = "orinoco_cs.c 0.13e (David Gibson <[email protected]> and others)";
        !           669: 
        !           670: static int __init
        !           671: init_orinoco_cs(void)
        !           672: {
        !           673:        servinfo_t serv;
        !           674: 
        !           675:        printk(KERN_DEBUG "%s\n", version);
        !           676: 
        !           677:        CardServices(GetCardServicesInfo, &serv);
        !           678:        if (serv.Revision != CS_RELEASE_CODE) {
        !           679:                printk(KERN_NOTICE "orinoco_cs: Card Services release "
        !           680:                       "does not match!\n");
        !           681:                return -EINVAL;
        !           682:        }
        !           683: 
        !           684:        register_pccard_driver(&dev_info, &orinoco_cs_attach, &orinoco_cs_detach);
        !           685: 
        !           686:        return 0;
        !           687: }
        !           688: 
        !           689: static void __exit
        !           690: exit_orinoco_cs(void)
        !           691: {
        !           692:        unregister_pccard_driver(&dev_info);
        !           693: 
        !           694:        if (dev_list)
        !           695:                DEBUG(0, "orinoco_cs: Removing leftover devices.\n");
        !           696:        while (dev_list != NULL) {
        !           697:                if (dev_list->state & DEV_CONFIG)
        !           698:                        orinoco_cs_release((u_long) dev_list);
        !           699:                orinoco_cs_detach(dev_list);
        !           700:        }
        !           701: }
        !           702: 
        !           703: module_init(init_orinoco_cs);
        !           704: module_exit(exit_orinoco_cs);
        !           705: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.