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 + -
显示快捷键?