cs.c

来自「pcmcia source code」· C语言 代码 · 共 2,204 行 · 第 1/5 页

C
2,204
字号
	s->fake_cis = NULL;    }#ifdef CONFIG_CARDBUS    cb_release_cis_mem(s);    cb_free(s);#endif    s->functions = 0;    if (s->config) {	kfree(s->config);	s->config = NULL;    }    for (c = &s->clients; *c; ) {	if ((*c)->state & CLIENT_UNBOUND) {	    client_t *d = *c;	    *c = (*c)->next;	    kfree(d);	} else {	    c = &((*c)->next);	}    }    free_regions(&s->a_region);    free_regions(&s->c_region);} /* shutdown_socket */static void setup_socket(u_long i){    int val;    socket_info_t *s = socket_table[i];    s->ss_entry(s->sock, SS_GetStatus, &val);    if (val & SS_PENDING) {	/* Does the socket need more time? */	DEBUG(2, "cs: setup_socket(%ld): status pending\n", i);	if (++s->setup_timeout > 100) {	    printk(KERN_NOTICE "cs: socket %ld voltage interrogation"		   " timed out\n", i);	} else {	    mod_timer(&s->setup, jiffies + HZ/10);	}    } else if (val & SS_DETECT) {	DEBUG(1, "cs: setup_socket(%ld): applying power\n", i);	s->state |= SOCKET_PRESENT;	s->socket.flags = 0;	if (val & SS_3VCARD)	    s->socket.Vcc = s->socket.Vpp = 33;	else if (!(val & SS_XVCARD))	    s->socket.Vcc = s->socket.Vpp = 50;	else {	    printk(KERN_NOTICE "cs: socket %ld: unsupported "		   "voltage key\n", i);	    s->socket.Vcc = 0;	}	if (val & SS_CARDBUS) {	    s->state |= SOCKET_CARDBUS;#ifndef CONFIG_CARDBUS	    printk(KERN_NOTICE "cs: unsupported card type detected!\n");#endif	}	s->ss_entry(s->sock, SS_SetSocket, &s->socket);	s->setup.function = &reset_socket;	mod_timer(&s->setup, jiffies + vcc_settle);    } else	DEBUG(0, "cs: setup_socket(%ld): no card!\n", i);} /* setup_socket *//*======================================================================    Reset_socket() and unreset_socket() handle hard resets.  Resets    have several causes: card insertion, a call to reset_socket, or    recovery from a suspend/resume cycle.  Unreset_socket() sends    a CS event that matches the cause of the reset.    ======================================================================*/static void reset_socket(u_long i){    socket_info_t *s = socket_table[i];    DEBUG(1, "cs: resetting socket %ld\n", i);    s->socket.flags |= SS_OUTPUT_ENA | SS_RESET;    s->ss_entry(s->sock, SS_SetSocket, &s->socket);    udelay((long)reset_time);    s->socket.flags &= ~SS_RESET;    s->ss_entry(s->sock, SS_SetSocket, &s->socket);    s->setup_timeout = 0;    s->setup.function = &unreset_socket;    mod_timer(&s->setup, jiffies + unreset_delay);} /* reset_socket */#define EVENT_MASK \(SOCKET_SETUP_PENDING|SOCKET_SUSPEND|SOCKET_RESET_PENDING)static void unreset_socket(u_long i){    socket_info_t *s = socket_table[i];    int val;    s->ss_entry(s->sock, SS_GetStatus, &val);    if (val & SS_READY) {	DEBUG(1, "cs: reset done on socket %ld\n", i);	if (s->state & SOCKET_SUSPEND) {	    s->state &= ~EVENT_MASK;	    if (verify_cis_cache(s) != 0)		parse_events(s, SS_DETECT);	    else		send_event(s, CS_EVENT_PM_RESUME, CS_EVENT_PRI_LOW);	} else if (s->state & SOCKET_SETUP_PENDING) {#ifdef CONFIG_CARDBUS	    if (s->state & SOCKET_CARDBUS)		cb_alloc(s);#endif	    send_event(s, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW);	    s->state &= ~SOCKET_SETUP_PENDING;	} else {	    send_event(s, CS_EVENT_CARD_RESET, CS_EVENT_PRI_LOW);	    if (s->reset_handle) {		s->reset_handle->event_callback_args.info = NULL;		EVENT(s->reset_handle, CS_EVENT_RESET_COMPLETE,		      CS_EVENT_PRI_LOW);		s->state &= ~EVENT_MASK;	    }	}    } else {	DEBUG(2, "cs: socket %ld not ready yet\n", i);	if (++s->setup_timeout > unreset_limit) {	    printk(KERN_NOTICE "cs: socket %ld timed out during"		   " reset\n", i);	    s->state &= ~EVENT_MASK;	} else {	    mod_timer(&s->setup, jiffies + unreset_check);	}    }} /* unreset_socket *//*======================================================================    The central event handler.  Send_event() sends an event to all    valid clients.  Parse_events() interprets the event bits from    a card status change report.  Do_shotdown() handles the high    priority stuff associated with a card removal.    ======================================================================*/static int send_event(socket_info_t *s, event_t event, int priority){    client_t *client = s->clients;    int ret;    DEBUG(1, "cs: send_event(sock %d, event %d, pri %d)\n",	  s->sock, event, priority);    ret = 0;    for (; client; client = client->next) { 	if (client->state & (CLIENT_UNBOUND|CLIENT_STALE))	    continue;	if (client->EventMask & event) {	    ret = EVENT(client, event, priority);	    if (ret != 0)		return ret;	}    }    return ret;} /* send_event */static void do_shutdown(socket_info_t *s){    client_t *client;    if (s->state & SOCKET_SHUTDOWN_PENDING)	return;    s->state |= SOCKET_SHUTDOWN_PENDING;    send_event(s, CS_EVENT_CARD_REMOVAL, CS_EVENT_PRI_HIGH);    for (client = s->clients; client; client = client->next)	if (!(client->Attributes & INFO_MASTER_CLIENT))	    client->state |= CLIENT_STALE;    if (s->state & (SOCKET_SETUP_PENDING|SOCKET_RESET_PENDING)) {	DEBUG(0, "cs: flushing pending setup\n");	del_timer(&s->setup);	s->state &= ~EVENT_MASK;    }    mod_timer(&s->shutdown, jiffies + shutdown_delay);    s->state &= ~SOCKET_PRESENT;}static void parse_events(void *info, u_int events){    socket_info_t *s = info;    if (events & SS_DETECT) {	int status;	u_long flags;	spin_lock_irqsave(&s->lock, flags);	s->ss_entry(s->sock, SS_GetStatus, &status);	if ((s->state & SOCKET_PRESENT) &&	    (!(s->state & SOCKET_SUSPEND) ||	     !(status & SS_DETECT)))	    do_shutdown(s);	if (status & SS_DETECT) {	    if (s->state & SOCKET_SETUP_PENDING) {		del_timer(&s->setup);		DEBUG(1, "cs: delaying pending setup\n");	    }	    s->state |= SOCKET_SETUP_PENDING;	    s->setup.function = &setup_socket;	    s->setup_timeout = 0;	    if (s->state & SOCKET_SUSPEND)		s->setup.expires = jiffies + resume_delay;	    else		s->setup.expires = jiffies + setup_delay;	    add_timer(&s->setup);	}	spin_unlock_irqrestore(&s->lock, flags);    }    if (events & SS_BATDEAD)	send_event(s, CS_EVENT_BATTERY_DEAD, CS_EVENT_PRI_LOW);    if (events & SS_BATWARN)	send_event(s, CS_EVENT_BATTERY_LOW, CS_EVENT_PRI_LOW);    if (events & SS_READY) {	if (!(s->state & SOCKET_RESET_PENDING))	    send_event(s, CS_EVENT_READY_CHANGE, CS_EVENT_PRI_LOW);	else DEBUG(1, "cs: ready change during reset\n");    }} /* parse_events *//*======================================================================    Another event handler, for power management events.    This does not comply with the latest PC Card spec for handling    power management events.    ======================================================================*/#ifdef CONFIG_PM#if (LINUX_VERSION_CODE < VERSION(2,3,43))static int handle_pm_event(apm_event_t rqst)#elsestatic int handle_pm_event(struct pm_dev *dev, pm_request_t rqst,			   void *data)#endif{    int i, stat;    socket_info_t *s;    static int down = 0;    /* <linux/pm.h> hides a hack so this works with old APM support */    switch (rqst) {    case PM_SUSPEND:	DEBUG(1, "cs: received suspend notification\n");	if (down) {	    printk(KERN_DEBUG "cs: received extra suspend event\n");	    break;	}	down = 1;	for (i = 0; i < sockets; i++) {	    s = socket_table[i];	    if ((s->state & SOCKET_PRESENT) &&		!(s->state & SOCKET_SUSPEND)){		send_event(s, CS_EVENT_PM_SUSPEND, CS_EVENT_PRI_LOW);		s->ss_entry(s->sock, SS_SetSocket, &dead_socket);		s->state |= SOCKET_SUSPEND;	    }	}	break;    case PM_RESUME:	DEBUG(1, "cs: received resume notification\n");	if (!down) {	    printk(KERN_DEBUG "cs: received bogus resume event\n");	    break;	}	down = 0;	for (i = 0; i < sockets; i++) {	    s = socket_table[i];	    /* Do this just to reinitialize the socket */	    init_socket(s);	    s->ss_entry(s->sock, SS_GetStatus, &stat);	    /* If there was or is a card here, we need to do something	       about it... but parse_events will sort it all out. */       	    if ((s->state & SOCKET_PRESENT) || (stat & SS_DETECT))		parse_events(s, SS_DETECT);	}	break;    }    return 0;} /* handle_pm_event */#endif/*======================================================================    Special stuff for managing IO windows, because they are scarce.    ======================================================================*/static int alloc_io_space(socket_info_t *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) {	    DEBUG(0, "odd IO request: num %04x align %04x\n",		  num, align);	    align = 0;	} else	    while (align && (align < num)) align <<= 1;    }    if (*base & ~(align-1)) {	DEBUG(0, "odd IO request: base %04x align %04x\n",	      *base, align);	align = 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) {	    if (find_io_region(base, num, align, name) == 0) {		s->io[i].Attributes = attr;		s->io[i].BasePort = *base;		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 (find_io_region(&try, num, 0, name) == 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 (find_io_region(&try, num, 0, name) == 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(socket_info_t *s, ioaddr_t base,			     ioaddr_t num){    int i;    release_region(base, num);    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;	}    }}/*======================================================================    Access_configuration_register() reads and writes configuration    registers in attribute memory.  Memory window 0 is reserved for    this and the tuple reading services.    ======================================================================*/static int access_configuration_register(client_handle_t handle,					 conf_reg_t *reg){    socket_info_t *s;    config_t *c;    int addr;    u_char val;        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 (reg->Function >= s->functions)	    return CS_BAD_ARGS;	c = &s->config[reg->Function];    } else	c = CONFIG(handle);    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 *//*======================================================================    Bind_device() associates a device driver with a particular socket.    It is normally called by Driver Services after it has identified    a newly inserted card.  An instance of that driver will then be    eligible to register as a client of this socket.    ======================================================================*/static int bind_device(bind_req_t *req){    client_t *client;    socket_info_t *s;    if (CHECK_SOCKET(req->Socket))	return CS_BAD_SOCKET;    s = SOCKET(req);    client = (client_t *)kmalloc(sizeof(client_t), GFP_KERNEL);    if (!client) return CS_OUT_OF_RESOURCE;    memset(client, '\0', sizeof(client_t));    client->client_magic = CLIENT_MAGIC;    strncpy(client->dev_info, (char *)req->dev_info, DEV_NAME_LEN);    client->Socket = req->Socket;    client->Function = req->Function;    client->state = CLIENT_UNBOUND;    client->erase_busy.next = &client->erase_busy;    client->erase_busy.prev = &client->erase_busy;

⌨️ 快捷键说明

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