cs.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,183 行 · 第 1/4 页

C
2,183
字号
/* * Handle card insertion.  Setup the socket, reset the card, * and then tell the rest of PCMCIA that a card is present. */static int socket_insert(struct pcmcia_socket *skt){	int ret;	cs_dbg(skt, 4, "insert\n");	if (!cs_socket_get(skt))		return CS_NO_CARD;	ret = socket_setup(skt, setup_delay);	if (ret == CS_SUCCESS) {		skt->state |= SOCKET_PRESENT;#ifdef CONFIG_CARDBUS		if (skt->state & SOCKET_CARDBUS) {			cb_alloc(skt);			skt->state |= SOCKET_CARDBUS_CONFIG;		}#endif		cs_dbg(skt, 4, "insert done\n");		send_event(skt, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW);	} else {		socket_shutdown(skt);		cs_socket_put(skt);	}	return ret;}static int socket_suspend(struct pcmcia_socket *skt){	if (skt->state & SOCKET_SUSPEND)		return CS_IN_USE;	send_event(skt, CS_EVENT_PM_SUSPEND, CS_EVENT_PRI_LOW);	skt->socket = dead_socket;	skt->ops->suspend(skt);	skt->state |= SOCKET_SUSPEND;	return CS_SUCCESS;}/* * Resume a socket.  If a card is present, verify its CIS against * our cached copy.  If they are different, the card has been * replaced, and we need to tell the drivers. */static int socket_resume(struct pcmcia_socket *skt){	int ret;	if (!(skt->state & SOCKET_SUSPEND))		return CS_IN_USE;	skt->socket = dead_socket;	skt->ops->init(skt);	skt->ops->set_socket(skt, &skt->socket);	ret = socket_setup(skt, resume_delay);	if (ret == CS_SUCCESS) {		/*		 * FIXME: need a better check here for cardbus cards.		 */		if (verify_cis_cache(skt) != 0) {			socket_remove_drivers(skt);			destroy_cis_cache(skt);			send_event(skt, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW);		} else {			send_event(skt, CS_EVENT_PM_RESUME, CS_EVENT_PRI_LOW);		}	} else {		socket_shutdown(skt);		cs_socket_put(skt);	}	skt->state &= ~SOCKET_SUSPEND;	return CS_SUCCESS;}static void socket_remove(struct pcmcia_socket *skt){	socket_shutdown(skt);	cs_socket_put(skt);}/* * Process a socket card detect status change. * * If we don't have a card already present, delay the detect event for * about 20ms (to be on the safe side) before reading the socket status. * * Some i82365-based systems send multiple SS_DETECT events during card * insertion, and the "card present" status bit seems to bounce.  This * will probably be true with GPIO-based card detection systems after * the product has aged. */static void socket_detect_change(struct pcmcia_socket *skt){	if (!(skt->state & SOCKET_SUSPEND)) {		int status;		if (!(skt->state & SOCKET_PRESENT))			msleep(20);		skt->ops->get_status(skt, &status);		if ((skt->state & SOCKET_PRESENT) &&		     !(status & SS_DETECT))			socket_remove(skt);		if (!(skt->state & SOCKET_PRESENT) &&		    (status & SS_DETECT))			socket_insert(skt);	}}static int pccardd(void *__skt){	struct pcmcia_socket *skt = __skt;	DECLARE_WAITQUEUE(wait, current);	int ret;	daemonize("pccardd");	skt->thread = current;	skt->socket = dead_socket;	skt->ops->init(skt);	skt->ops->set_socket(skt, &skt->socket);	/* register with the device core */	ret = class_device_register(&skt->dev);	if (ret) {		printk(KERN_WARNING "PCMCIA: unable to register socket 0x%p\n",			skt);		skt->thread = NULL;		complete_and_exit(&skt->thread_done, 0);	}	complete(&skt->thread_done);	add_wait_queue(&skt->thread_wait, &wait);	for (;;) {		unsigned long flags;		unsigned int events;		set_current_state(TASK_INTERRUPTIBLE);		spin_lock_irqsave(&skt->thread_lock, flags);		events = skt->thread_events;		skt->thread_events = 0;		spin_unlock_irqrestore(&skt->thread_lock, flags);		if (events) {			down(&skt->skt_sem);			if (events & SS_DETECT)				socket_detect_change(skt);			if (events & SS_BATDEAD)				send_event(skt, CS_EVENT_BATTERY_DEAD, CS_EVENT_PRI_LOW);			if (events & SS_BATWARN)				send_event(skt, CS_EVENT_BATTERY_LOW, CS_EVENT_PRI_LOW);			if (events & SS_READY)				send_event(skt, CS_EVENT_READY_CHANGE, CS_EVENT_PRI_LOW);			up(&skt->skt_sem);			continue;		}		schedule();		if (current->flags & PF_FREEZE)			refrigerator(PF_FREEZE);		if (!skt->thread)			break;	}	remove_wait_queue(&skt->thread_wait, &wait);	/* remove from the device core */	class_device_unregister(&skt->dev);	complete_and_exit(&skt->thread_done, 0);}/* * Yenta (at least) probes interrupts before registering the socket and * starting the handler thread. */void pcmcia_parse_events(struct pcmcia_socket *s, u_int events){	cs_dbg(s, 4, "parse_events: events %08x\n", events);	if (s->thread) {		spin_lock(&s->thread_lock);		s->thread_events |= events;		spin_unlock(&s->thread_lock);		wake_up(&s->thread_wait);	}} /* pcmcia_parse_events *//*======================================================================    Special stuff for managing IO windows, because they are scarce.    ======================================================================*/static int alloc_io_space(struct pcmcia_socket *s, u_int attr, ioaddr_t *base,			  ioaddr_t num, u_int lines, char *name){    int i;    ioaddr_t try, align;    align = (*base) ? (lines ? 1<<lines : 0) : 1;    if (align && (align < num)) {	if (*base) {	    cs_dbg(s, 0, "odd IO request: num %04x align %04x\n",		   num, align);	    align = 0;	} else	    while (align && (align < num)) align <<= 1;    }    if (*base & ~(align-1)) {	cs_dbg(s, 0, "odd IO request: base %04x align %04x\n",	       *base, align);	align = 0;    }    if ((s->features & SS_CAP_STATIC_MAP) && s->io_offset) {	*base = s->io_offset | (*base & 0x0fff);	return 0;    }    /* Check for an already-allocated window that must conflict with       what was asked for.  It is a hack because it does not catch all       potential conflicts, just the most obvious ones. */    for (i = 0; i < MAX_IO_WIN; i++)	if ((s->io[i].NumPorts != 0) &&	    ((s->io[i].BasePort & (align-1)) == *base))	    return 1;    for (i = 0; i < MAX_IO_WIN; i++) {	if (s->io[i].NumPorts == 0) {	    s->io[i].res = find_io_region(*base, num, align, name, s);	    if (s->io[i].res) {		s->io[i].Attributes = attr;		s->io[i].BasePort = *base = s->io[i].res->start;		s->io[i].NumPorts = s->io[i].InUse = num;		break;	    } else		return 1;	} else if (s->io[i].Attributes != attr)	    continue;	/* Try to extend top of window */	try = s->io[i].BasePort + s->io[i].NumPorts;	if ((*base == 0) || (*base == try))	    if (adjust_io_region(s->io[i].res, s->io[i].res->start,				 s->io[i].res->end + num, s) == 0) {		*base = try;		s->io[i].NumPorts += num;		s->io[i].InUse += num;		break;	    }	/* Try to extend bottom of window */	try = s->io[i].BasePort - num;	if ((*base == 0) || (*base == try))	    if (adjust_io_region(s->io[i].res, s->io[i].res->start - num,				 s->io[i].res->end, s) == 0) {		s->io[i].BasePort = *base = try;		s->io[i].NumPorts += num;		s->io[i].InUse += num;		break;	    }    }    return (i == MAX_IO_WIN);} /* alloc_io_space */static void release_io_space(struct pcmcia_socket *s, ioaddr_t base,			     ioaddr_t num){    int i;    for (i = 0; i < MAX_IO_WIN; i++) {	if ((s->io[i].BasePort <= base) &&	    (s->io[i].BasePort+s->io[i].NumPorts >= base+num)) {	    s->io[i].InUse -= num;	    /* Free the window if no one else is using it */	    if (s->io[i].InUse == 0) {		s->io[i].NumPorts = 0;		release_resource(s->io[i].res);		kfree(s->io[i].res);		s->io[i].res = NULL;	    }	}    }}/*======================================================================    Access_configuration_register() reads and writes configuration    registers in attribute memory.  Memory window 0 is reserved for    this and the tuple reading services.    ======================================================================*/int pcmcia_access_configuration_register(client_handle_t handle,					 conf_reg_t *reg){    struct pcmcia_socket *s;    config_t *c;    int addr;    u_char val;        if (CHECK_HANDLE(handle))	return CS_BAD_HANDLE;    s = SOCKET(handle);    if (handle->Function == BIND_FN_ALL) {	if (reg->Function >= s->functions)	    return CS_BAD_ARGS;	c = &s->config[reg->Function];    } else	c = CONFIG(handle);    if (c == NULL)	return CS_NO_CARD;    if (!(c->state & CONFIG_LOCKED))	return CS_CONFIGURATION_LOCKED;    addr = (c->ConfigBase + reg->Offset) >> 1;        switch (reg->Action) {    case CS_READ:	read_cis_mem(s, 1, addr, 1, &val);	reg->Value = val;	break;    case CS_WRITE:	val = reg->Value;	write_cis_mem(s, 1, addr, 1, &val);	break;    default:	return CS_BAD_ARGS;	break;    }    return CS_SUCCESS;} /* access_configuration_register *//*====================================================================*/int pcmcia_deregister_client(client_handle_t handle){    client_t **client;    struct pcmcia_socket *s;    memory_handle_t region;    u_long flags;    int i;        if (CHECK_HANDLE(handle))	return CS_BAD_HANDLE;    s = SOCKET(handle);    cs_dbg(s, 1, "deregister_client(%p)\n", handle);    if (handle->state &	(CLIENT_IRQ_REQ|CLIENT_IO_REQ|CLIENT_CONFIG_LOCKED))	return CS_IN_USE;    for (i = 0; i < MAX_WIN; i++)	if (handle->state & CLIENT_WIN_REQ(i))	    return CS_IN_USE;    /* Disconnect all MTD links */    if (handle->mtd_count) {	for (region = s->a_region; region; region = region->info.next)	    if (region->mtd == handle) region->mtd = NULL;	for (region = s->c_region; region; region = region->info.next)	    if (region->mtd == handle) region->mtd = NULL;    }        if ((handle->state & CLIENT_STALE) ||	(handle->Attributes & INFO_MASTER_CLIENT)) {	spin_lock_irqsave(&s->lock, flags);	client = &s->clients;	while ((*client) && ((*client) != handle))	    client = &(*client)->next;	if (*client == NULL) {	    spin_unlock_irqrestore(&s->lock, flags);	    return CS_BAD_HANDLE;	}	*client = handle->next;	handle->client_magic = 0;	kfree(handle);	spin_unlock_irqrestore(&s->lock, flags);    } else {	handle->state = CLIENT_UNBOUND;	handle->mtd_count = 0;	handle->event_handler = NULL;    }    return CS_SUCCESS;} /* deregister_client *//*====================================================================*/int pcmcia_get_configuration_info(client_handle_t handle,				  config_info_t *config){    struct pcmcia_socket *s;    config_t *c;        if (CHECK_HANDLE(handle))	return CS_BAD_HANDLE;    s = SOCKET(handle);    if (!(s->state & SOCKET_PRESENT))	return CS_NO_CARD;    if (handle->Function == BIND_FN_ALL) {	if (config->Function && (config->Function >= s->functions))	    return CS_BAD_ARGS;    } else	config->Function = handle->Function;    #ifdef CONFIG_CARDBUS    if (s->state & SOCKET_CARDBUS) {	u_char fn = config->Function;	memset(config, 0, sizeof(config_info_t));	config->Function = fn;	config->Vcc = s->socket.Vcc;	config->Vpp1 = config->Vpp2 = s->socket.Vpp;	config->Option = s->cb_dev->subordinate->number;	if (s->state & SOCKET_CARDBUS_CONFIG) {	    config->Attributes = CONF_VALID_CLIENT;	    config->IntType = INT_CARDBUS;	    config->AssignedIRQ = s->irq.AssignedIRQ;	    if (config->AssignedIRQ)		config->Attributes |= CONF_ENABLE_IRQ;	    config->BasePort1 = s->io[0].BasePort;	    config->NumPorts1 = s->io[0].NumPorts;	}	return CS_SUCCESS;    }#endif        c = (s->config != NULL) ? &s->config[config->Function] : NULL;        if ((c == NULL) || !(c->state & CONFIG_LOCKED)) {	config->Attributes = 0;	config->Vcc = s->socket.Vcc;	config->Vpp1 = config->Vpp2 = s->socket.Vpp;	return CS_SUCCESS;    }        /* !!! This is a hack !!! */    memcpy(&config->Attributes, &c->Attributes, sizeof(config_t));    config->Attributes |= CONF_VALID_CLIENT;    config->CardValues = c->CardValues;    config->IRQAttributes = c->irq.Attributes;    config->AssignedIRQ = s->irq.AssignedIRQ;    config->BasePort1 = c->io.BasePort1;    config->NumPorts1 = c->io.NumPorts1;    config->Attributes1 = c->io.Attributes1;    config->BasePort2 = c->io.BasePort2;    config->NumPorts2 = c->io.NumPorts2;    config->Attributes2 = c->io.Attributes2;    config->IOAddrLines = c->io.IOAddrLines;        return CS_SUCCESS;} /* get_configuration_info *//*======================================================================    Return information about this version of Card Services.    ======================================================================*/int pcmcia_get_card_services_info(servinfo_t *info){    unsigned int socket_count = 0;    struct list_head *tmp;    info->Signature[0] = 'C';    info->Signature[1] = 'S';    down_read(&pcmcia_socket_list_rwsem);    list_for_each(tmp, &pcmcia_socket_list)	    socket_count++;    up_read(&pcmcia_socket_list_rwsem);    info->Count = socket_count;    info->Revision = CS_RELEASE_CODE;    info->CSLevel = 0x0210;    info->VendorString = (char *)release;    return CS_SUCCESS;} /* get_card_services_info *//*======================================================================    Note that get_first_client() *does* recognize the Socket field    in the request structure.    ======================================================================*/int pcmcia_get_first_client(client_handle_t *handle, client_req_t *req){    socket_t s;    struct pcmcia_socket *socket;    if (req->Attributes & CLIENT_THIS_SOCKET)	s = req->Socket;    else	s = 0;    socket = pcmcia_get_socket_by_nr(s);    if (!socket)	return CS_BAD_SOCKET;    if (socket->clients == NULL)	return CS_NO_MORE_ITEMS;    *handle = socket->clients;    return CS_SUCCESS;} /* get_first_client *//*====================================================================*/int pcmcia_get_next_client(client_handle_t *handle, client_req_t *req){    struct pcmcia_socket *s;    if ((handle == NULL) || CHECK_HANDLE(*handle))	return CS_BAD_HANDLE;    if ((*handle)->next == NULL) {	if (req->Attributes & CLIENT_THIS_SOCKET)	    return CS_NO_MORE_ITEMS;	s = (*handle)->Socket;	if (s->clients == NULL)	    return CS_NO_MORE_ITEMS;	*handle = s->clients;    } else	*handle = (*handle)->next;    return CS_SUCCESS;} /* get_next_client *//*====================================================================*/int pcmcia_get_window(window_handle_t *handle, int idx, win_req_t *req){    struct pcmcia_socket *s;    window_t *win;    int w;    if (idx == 0)	s = ((client_handle_t)*handle)->Socket;    else	s = (*handle)->sock;    if (!(s->state & SOCKET_PRESENT))	return CS_NO_CARD;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?