📄 elsa_cs.c
字号:
del_timer(&link->release); if (link->state & DEV_CONFIG) elsa_cs_release((u_long)link); /* 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(). */ if (link->state & DEV_CONFIG) { DEBUG(0, "elsa_cs: detach postponed, '%s' " "still locked\n", link->dev->dev_name); link->state |= DEV_STALE_LINK; return; } /* Break the link with Card Services */ if (link->handle) { ret = CardServices(DeregisterClient, link->handle); if (ret != CS_SUCCESS) cs_error(link->handle, DeregisterClient, ret); } /* Unlink device structure and free it */ *linkp = link->next; kfree(info);} /* elsa_cs_detach *//*====================================================================== elsa_cs_config() is scheduled to run after a CARD_INSERTION event is received, to configure the PCMCIA socket, and to make the device available to the system.======================================================================*/static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse){ int i; i = CardServices(fn, handle, tuple); if (i != CS_SUCCESS) return i; i = CardServices(GetTupleData, handle, tuple); if (i != CS_SUCCESS) return i; return CardServices(ParseTuple, handle, tuple, parse);}#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c)#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c)static void elsa_cs_config(dev_link_t *link){ client_handle_t handle; tuple_t tuple; cisparse_t parse; local_info_t *dev; int i, j, last_fn; u_short buf[128]; cistpl_cftable_entry_t *cf = &parse.cftable_entry; DEBUG(0, "elsa_config(0x%p)\n", link); handle = link->handle; dev = link->priv; /* This reads the card's CONFIG tuple to find its configuration registers. */ tuple.DesiredTuple = CISTPL_CONFIG; tuple.TupleData = (cisdata_t *)buf; tuple.TupleDataMax = 255; tuple.TupleOffset = 0; tuple.Attributes = 0; i = first_tuple(handle, &tuple, &parse); if (i != CS_SUCCESS) { last_fn = ParseTuple; goto cs_failed; } link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; /* Configure card */ link->state |= DEV_CONFIG; tuple.TupleData = (cisdata_t *)buf; tuple.TupleOffset = 0; tuple.TupleDataMax = 255; tuple.Attributes = 0; tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; i = first_tuple(handle, &tuple, &parse); while (i == CS_SUCCESS) { if ( (cf->io.nwin > 0) && cf->io.win[0].base) { printk(KERN_INFO "(elsa_cs: looks like the 96 model)\n"); link->conf.ConfigIndex = cf->index; link->io.BasePort1 = cf->io.win[0].base; i = CardServices(RequestIO, link->handle, &link->io); if (i == CS_SUCCESS) break; } else { printk(KERN_INFO "(elsa_cs: looks like the 97 model)\n"); link->conf.ConfigIndex = cf->index; for (i = 0, j = 0x2f0; j > 0x100; j -= 0x10) { link->io.BasePort1 = j; i = CardServices(RequestIO, link->handle, &link->io); if (i == CS_SUCCESS) break; } break; } i = next_tuple(handle, &tuple, &parse); } if (i != CS_SUCCESS) { last_fn = RequestIO; goto cs_failed; } i = CardServices(RequestIRQ, link->handle, &link->irq); if (i != CS_SUCCESS) { link->irq.AssignedIRQ = 0; last_fn = RequestIRQ; goto cs_failed; } i = CardServices(RequestConfiguration, link->handle, &link->conf); if (i != CS_SUCCESS) { last_fn = RequestConfiguration; goto cs_failed; } /* At this point, the dev_node_t structure(s) should be initialized and arranged in a linked list at link->dev. *//* */ sprintf(dev->node.dev_name, "elsa"); dev->node.major = dev->node.minor = 0x0; link->dev = &dev->node; /* Finally, report what we've done */ printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d", dev->node.dev_name, 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); printk("\n"); link->state &= ~DEV_CONFIG_PENDING; elsa_init_pcmcia(link->io.BasePort1, link->irq.AssignedIRQ, &(((local_info_t*)link->priv)->busy), protocol); return;cs_failed: cs_error(link->handle, last_fn, i); elsa_cs_release((u_long)link);} /* elsa_cs_config *//*====================================================================== After a card is removed, elsa_cs_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 elsa_cs_release(u_long arg){ dev_link_t *link = (dev_link_t *)arg; DEBUG(0, "elsa_cs_release(0x%p)\n", link); /* If the device is currently in use, we won't release until it is actually closed, because until then, we can't be sure that no one will try to access the device or its data structures. */ if (link->open) { DEBUG(1, "elsa_cs: release postponed, '%s' " "still open\n", link->dev->dev_name); link->state |= DEV_STALE_CONFIG; return; } /* Unlink the device chain */ link->dev = NULL; /* Don't bother checking to see if these succeed or not */ if (link->win) CardServices(ReleaseWindow, link->win); CardServices(ReleaseConfiguration, link->handle); CardServices(ReleaseIO, link->handle, &link->io); CardServices(ReleaseIRQ, link->handle, &link->irq); link->state &= ~DEV_CONFIG; if (link->state & DEV_STALE_LINK) elsa_cs_detach(link);} /* elsa_cs_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. When a CARD_REMOVAL event is received, we immediately set a flag to block future accesses to this device. All the functions that actually access the device should check this flag to make sure the card is still present.======================================================================*/static int elsa_cs_event(event_t event, int priority, event_callback_args_t *args){ dev_link_t *link = args->client_data; local_info_t *dev = link->priv; DEBUG(1, "elsa_cs_event(%d)\n", event); switch (event) { case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { ((local_info_t*)link->priv)->busy = 1; mod_timer(&link->release, jiffies + HZ/20); } break; case CS_EVENT_CARD_INSERTION: link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; dev->bus = args->bus; elsa_cs_config(link); break; case CS_EVENT_PM_SUSPEND: link->state |= DEV_SUSPEND; /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: /* Mark the device as stopped, to block IO until later */ dev->busy = 1; if (link->state & DEV_CONFIG) 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); dev->busy = 0; break; } return 0;} /* elsa_cs_event *//*====================================================================*/static int __init init_elsa_cs(void){ servinfo_t serv; DEBUG(0, "%s\n", version); CardServices(GetCardServicesInfo, &serv); if (serv.Revision != CS_RELEASE_CODE) { printk(KERN_NOTICE "elsa_cs: Card Services release " "does not match!\n"); return -1; } register_pccard_driver(&dev_info, &elsa_cs_attach, &elsa_cs_detach); return 0;}static void __exit exit_elsa_cs(void){ DEBUG(0, "elsa_cs: unloading\n"); unregister_pccard_driver(&dev_info); while (dev_list != NULL) elsa_cs_detach(dev_list);}module_init(init_elsa_cs);module_exit(exit_elsa_cs);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -