avm_cs.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 535 行 · 第 1/2 页
C
535 行
static int next_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse){ int i = pcmcia_get_next_tuple(handle, tuple); if (i != CS_SUCCESS) return i; return get_tuple(handle, tuple, parse);}static void avmcs_config(dev_link_t *link){ client_handle_t handle; tuple_t tuple; cisparse_t parse; cistpl_cftable_entry_t *cf = &parse.cftable_entry; local_info_t *dev; int i; u_char buf[64]; char devname[128]; int cardtype; int (*addcard)(unsigned int port, unsigned irq); handle = link->handle; dev = link->priv; /* This reads the card's CONFIG tuple to find its configuration registers. */ do { tuple.DesiredTuple = CISTPL_CONFIG; i = pcmcia_get_first_tuple(handle, &tuple); if (i != CS_SUCCESS) break; tuple.TupleData = buf; tuple.TupleDataMax = 64; tuple.TupleOffset = 0; i = pcmcia_get_tuple_data(handle, &tuple); if (i != CS_SUCCESS) break; i = pcmcia_parse_tuple(handle, &tuple, &parse); if (i != CS_SUCCESS) break; link->conf.ConfigBase = parse.config.base; } while (0); if (i != CS_SUCCESS) { cs_error(link->handle, ParseTuple, i); link->state &= ~DEV_CONFIG_PENDING; return; } /* Configure card */ link->state |= DEV_CONFIG; do { tuple.Attributes = 0; tuple.TupleData = buf; tuple.TupleDataMax = 254; tuple.TupleOffset = 0; tuple.DesiredTuple = CISTPL_VERS_1; devname[0] = 0; if( !first_tuple(handle, &tuple, &parse) && parse.version_1.ns > 1 ) { strlcpy(devname,parse.version_1.str + parse.version_1.ofs[1], sizeof(devname)); } /* * find IO port */ 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) { link->conf.ConfigIndex = cf->index; link->io.BasePort1 = cf->io.win[0].base; link->io.NumPorts1 = cf->io.win[0].len; link->io.NumPorts2 = 0; printk(KERN_INFO "avm_cs: testing i/o %#x-%#x\n", link->io.BasePort1, link->io.BasePort1+link->io.NumPorts1-1); i = pcmcia_request_io(link->handle, &link->io); if (i == CS_SUCCESS) goto found_port; } i = next_tuple(handle, &tuple, &parse); }found_port: if (i != CS_SUCCESS) { cs_error(link->handle, RequestIO, i); break; } /* * allocate an interrupt line */ i = pcmcia_request_irq(link->handle, &link->irq); if (i != CS_SUCCESS) { cs_error(link->handle, RequestIRQ, i); pcmcia_release_io(link->handle, &link->io); break; } /* * configure the PCMCIA socket */ i = pcmcia_request_configuration(link->handle, &link->conf); if (i != CS_SUCCESS) { cs_error(link->handle, RequestConfiguration, i); pcmcia_release_io(link->handle, &link->io); pcmcia_release_irq(link->handle, &link->irq); break; } } while (0); /* At this point, the dev_node_t structure(s) should be initialized and arranged in a linked list at link->dev. */ if (devname[0]) { char *s = strrchr(devname, ' '); if (!s) s = devname; else s++; strcpy(dev->node.dev_name, s); if (strcmp("M1", s) == 0) { cardtype = AVM_CARDTYPE_M1; } else if (strcmp("M2", s) == 0) { cardtype = AVM_CARDTYPE_M2; } else { cardtype = AVM_CARDTYPE_B1; } } else { strcpy(dev->node.dev_name, "b1"); cardtype = AVM_CARDTYPE_B1; } dev->node.major = 64; dev->node.minor = 0; link->dev = &dev->node; link->state &= ~DEV_CONFIG_PENDING; /* If any step failed, release any partially configured state */ if (i != 0) { avmcs_release(link); return; } switch (cardtype) { case AVM_CARDTYPE_M1: addcard = b1pcmcia_addcard_m1; break; case AVM_CARDTYPE_M2: addcard = b1pcmcia_addcard_m2; break; default: case AVM_CARDTYPE_B1: addcard = b1pcmcia_addcard_b1; break; } if ((i = (*addcard)(link->io.BasePort1, link->irq.AssignedIRQ)) < 0) { printk(KERN_ERR "avm_cs: failed to add AVM-%s-Controller at i/o %#x, irq %d\n", dev->node.dev_name, link->io.BasePort1, link->irq.AssignedIRQ); avmcs_release(link); return; } dev->node.minor = i;} /* avmcs_config *//*====================================================================== After a card is removed, avmcs_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 avmcs_release(dev_link_t *link){ b1pcmcia_delcard(link->io.BasePort1, link->irq.AssignedIRQ); /* Unlink the device chain */ link->dev = NULL; /* Don't bother checking to see if these succeed or not */ pcmcia_release_configuration(link->handle); pcmcia_release_io(link->handle, &link->io); pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG; if (link->state & DEV_STALE_LINK) avmcs_detach(link); } /* avmcs_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 avmcs_event(event_t event, int priority, event_callback_args_t *args){ dev_link_t *link = args->client_data; switch (event) { case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) avmcs_release(link); break; case CS_EVENT_CARD_INSERTION: link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; avmcs_config(link); break; case CS_EVENT_PM_SUSPEND: link->state |= DEV_SUSPEND; /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) pcmcia_release_configuration(link->handle); break; case CS_EVENT_PM_RESUME: link->state &= ~DEV_SUSPEND; /* Fall through... */ case CS_EVENT_CARD_RESET: if (link->state & DEV_CONFIG) pcmcia_request_configuration(link->handle, &link->conf); break; } return 0;} /* avmcs_event */static struct pcmcia_driver avmcs_driver = { .owner = THIS_MODULE, .drv = { .name = "avm_cs", }, .attach = avmcs_attach, .detach = avmcs_detach,};static int __init avmcs_init(void){ return pcmcia_register_driver(&avmcs_driver);}static void __exit avmcs_exit(void){ pcmcia_unregister_driver(&avmcs_driver); /* XXX: this really needs to move into generic code.. */ while (dev_list != NULL) { if (dev_list->state & DEV_CONFIG) avmcs_release(dev_list); avmcs_detach(dev_list); }}module_init(avmcs_init);module_exit(avmcs_exit);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?