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