📄 aironet4500_cs.c
字号:
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) { awc_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; 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++; } if (link->priv) { //struct net_device *dev = link->priv; // dam dam damn mif (dev->priv) // kfree(dev->priv); kfree(link->priv); } kfree(link->dev); kfree(link);} /* awc_detach *//* awc_pcmcia_config() is scheduled to run after a CARD_INSERTION event is received, to configure the PCMCIA socket, and to make the ethernet device available to the system.*/#define CS_CHECK(fn, args...) \while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failedstatic void awc_pcmcia_config(dev_link_t *link){ client_handle_t handle; struct net_device *dev; struct awc_private *lp; tuple_t tuple; int ii; cisparse_t parse; u_short buf[64]; int last_fn, last_ret, i = 0;// int ioaddr; u16 *phys_addr; int retval; handle = link->handle; dev = link->priv; phys_addr = (u16 *)dev->dev_addr; PC_DEBUG(0, "awc_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; printk(KERN_CRIT "8-bit IO not supported on this aironet 4500 driver \n"); } 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 = awc_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; awc_private_init( dev); retval = register_netdev(dev); if (retval != 0) { printk(KERN_NOTICE "awc_cs: register_netdev() failed for dev %x retval %x\n",(unsigned int)dev,retval); goto failed; } if(awc_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 (awc_proc_set_fun) awc_proc_set_fun(i); } link->state &= ~DEV_CONFIG_PENDING; lp = (struct awc_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: awc_release((u_long)link); return;} /* awc_pcmcia_config *//* After a card is removed, awc_release() will unregister the net device, and release the PCMCIA configuration. If the device is still open, this will be postponed until it is closed.*/static void awc_release(u_long arg){ dev_link_t *link = (dev_link_t *)arg; struct net_device *dev = link->priv; DEBUG(0, "awc_release(0x%p)\n", link); if (link->open) { DEBUG(1, "awc_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_netdev(dev); // link->dev = NULL; link->state &= ~DEV_CONFIG; if (link->state & DEV_STALE_LINK) awc_detach(link);} /* awc_release *//* The card status event handler. Mostly, this schedules other stuff to run after an event is received. A CARD_REMOVAL event also sets some flags to discourage the net drivers from trying to talk to the card any more.*/static int awc_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, "awc_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; awc_pcmcia_config(link); break; case CS_EVENT_PM_SUSPEND: link->state |= DEV_SUSPEND; /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) { if (link->open) 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) { // awc_reset(dev); netif_device_attach(dev); } } break; } return 0;} /* awc_event */ static int __init aironet_cs_init(void){ servinfo_t serv; /* Always emit the version, before any failure. */ printk(KERN_INFO"%s", awc_version); PC_DEBUG(0, "%s\n", version); CardServices(GetCardServicesInfo, &serv); if (serv.Revision != CS_RELEASE_CODE) { printk(KERN_NOTICE "awc_cs: Card Services release " "does not match!\n"); return -1; } register_pcmcia_driver(&dev_info, &awc_attach, &awc_detach); return 0;}static void __exit aironet_cs_exit(void){ DEBUG(0, "awc_cs: unloading %c ",'\n'); unregister_pcmcia_driver(&dev_info); while (dev_list != NULL) { if (dev_list->state & DEV_CONFIG) awc_release((u_long)dev_list); awc_detach(dev_list); } // while (dev_list != NULL)// awc_detach(dev_list);}module_init(aironet_cs_init);module_exit(aironet_cs_exit);MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -