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