cs.c
来自「pcmcia source code」· C语言 代码 · 共 2,204 行 · 第 1/5 页
C
2,204 行
/*====================================================================== PCMCIA Card Services -- core services cs.c 1.283 2002/06/29 06:23:09 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. The initial developer of the original code is David A. Hinds <dahinds@users.sourceforge.net>. Portions created by David A. Hinds are Copyright (C) 1999 David A. Hinds. All Rights Reserved. Alternatively, the contents of this file may be used under the terms of the GNU General Public License version 2 (the "GPL"), in which case the provisions of the GPL are applicable instead of the above. If you wish to allow the use of your version of this file only under the terms of the GPL and not to allow others to use your version of this file under the MPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the GPL. If you do not delete the provisions above, a recipient may use your version of this file under either the MPL or the GPL. ======================================================================*/#include <linux/module.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/config.h>#include <linux/string.h>#include <linux/major.h>#include <linux/errno.h>#include <linux/slab.h>#include <linux/mm.h>#include <linux/sched.h>#include <linux/timer.h>#include <linux/ioport.h>#include <linux/delay.h>#include <linux/proc_fs.h>#include <linux/pm.h>#include <linux/pci.h>#include <linux/spinlock.h>#include <asm/system.h>#include <asm/irq.h>#define IN_CARD_SERVICES#include <pcmcia/version.h>#include <pcmcia/cs_types.h>#include <pcmcia/ss.h>#include <pcmcia/cs.h>#include <pcmcia/bulkmem.h>#include <pcmcia/cistpl.h>#include <pcmcia/cisreg.h>#include <pcmcia/bus_ops.h>#include "cs_internal.h"#ifdef CONFIG_PCI#define PCI_OPT " [pci]"#else#define PCI_OPT ""#endif#ifdef CONFIG_CARDBUS#define CB_OPT " [cardbus]"#else#define CB_OPT ""#endif#ifdef CONFIG_PM#define PM_OPT " [apm]"#else#define PM_OPT ""#endif#ifdef CONFIG_PNP_BIOS#define PNP_OPT " [pnp]"#else#define PNP_OPT ""#endif#if !defined(CONFIG_CARDBUS) && !defined(CONFIG_PCI) && \ !defined(CONFIG_PM) && !defined(CONFIG_PNP_BIOS)#define OPTIONS " none"#else#define OPTIONS PCI_OPT CB_OPT PM_OPT PNP_OPT#endifstatic const char *release = "Linux PCMCIA Card Services " CS_RELEASE;#ifdef UTS_RELEASEstatic const char *kernel = "kernel build: " UTS_RELEASE " " UTS_VERSION;#endifstatic const char *options = "options: " OPTIONS;/*====================================================================*//* Module parameters */MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");MODULE_DESCRIPTION("Linux PCMCIA Card Services " CS_RELEASE "\n options:" OPTIONS);MODULE_LICENSE("Dual MPL/GPL");#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")INT_MODULE_PARM(setup_delay, HZ/20); /* ticks */INT_MODULE_PARM(resume_delay, HZ/5); /* ticks */INT_MODULE_PARM(shutdown_delay, HZ/40); /* ticks */INT_MODULE_PARM(vcc_settle, HZ*4/10); /* ticks */INT_MODULE_PARM(reset_time, 10); /* usecs */INT_MODULE_PARM(unreset_delay, HZ/10); /* ticks */INT_MODULE_PARM(unreset_check, HZ/10); /* ticks */INT_MODULE_PARM(unreset_limit, 50); /* unreset_check's *//* Access speed for attribute memory windows */INT_MODULE_PARM(cis_speed, 300); /* ns *//* Access speed for IO windows */INT_MODULE_PARM(io_speed, 0); /* ns *//* Optional features */#ifdef CONFIG_PMINT_MODULE_PARM(do_apm, 1);#endif#ifdef CONFIG_PNP_BIOSINT_MODULE_PARM(do_pnp, 1);#endif#ifdef PCMCIA_DEBUGINT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);static const char *version ="cs.c 1.283 2002/06/29 06:23:09 (David Hinds)";#endif/*====================================================================*/static socket_state_t dead_socket = { 0, SS_DETECT, 0, 0, 0};/* Table of sockets */socket_t sockets = 0;socket_info_t *socket_table[MAX_SOCK];#ifdef HAS_PROC_BUSstruct proc_dir_entry *proc_pccard = NULL;#endif/*====================================================================*//* String tables for error messages */typedef struct lookup_t { int key; char *msg;} lookup_t;static const lookup_t error_table[] = { { CS_SUCCESS, "Operation succeeded" }, { CS_BAD_ADAPTER, "Bad adapter" }, { CS_BAD_ATTRIBUTE, "Bad attribute", }, { CS_BAD_BASE, "Bad base address" }, { CS_BAD_EDC, "Bad EDC" }, { CS_BAD_IRQ, "Bad IRQ" }, { CS_BAD_OFFSET, "Bad offset" }, { CS_BAD_PAGE, "Bad page number" }, { CS_READ_FAILURE, "Read failure" }, { CS_BAD_SIZE, "Bad size" }, { CS_BAD_SOCKET, "Bad socket" }, { CS_BAD_TYPE, "Bad type" }, { CS_BAD_VCC, "Bad Vcc" }, { CS_BAD_VPP, "Bad Vpp" }, { CS_BAD_WINDOW, "Bad window" }, { CS_WRITE_FAILURE, "Write failure" }, { CS_NO_CARD, "No card present" }, { CS_UNSUPPORTED_FUNCTION, "Usupported function" }, { CS_UNSUPPORTED_MODE, "Unsupported mode" }, { CS_BAD_SPEED, "Bad speed" }, { CS_BUSY, "Resource busy" }, { CS_GENERAL_FAILURE, "General failure" }, { CS_WRITE_PROTECTED, "Write protected" }, { CS_BAD_ARG_LENGTH, "Bad argument length" }, { CS_BAD_ARGS, "Bad arguments" }, { CS_CONFIGURATION_LOCKED, "Configuration locked" }, { CS_IN_USE, "Resource in use" }, { CS_NO_MORE_ITEMS, "No more items" }, { CS_OUT_OF_RESOURCE, "Out of resource" }, { CS_BAD_HANDLE, "Bad handle" }, { CS_BAD_TUPLE, "Bad CIS tuple" }};#define ERROR_COUNT (sizeof(error_table)/sizeof(lookup_t))static const lookup_t service_table[] = { { AccessConfigurationRegister, "AccessConfigurationRegister" }, { AddSocketServices, "AddSocketServices" }, { AdjustResourceInfo, "AdjustResourceInfo" }, { CheckEraseQueue, "CheckEraseQueue" }, { CloseMemory, "CloseMemory" }, { DeregisterClient, "DeregisterClient" }, { DeregisterEraseQueue, "DeregisterEraseQueue" }, { GetCardServicesInfo, "GetCardServicesInfo" }, { GetClientInfo, "GetClientInfo" }, { GetConfigurationInfo, "GetConfigurationInfo" }, { GetEventMask, "GetEventMask" }, { GetFirstClient, "GetFirstClient" }, { GetFirstRegion, "GetFirstRegion" }, { GetFirstTuple, "GetFirstTuple" }, { GetNextClient, "GetNextClient" }, { GetNextRegion, "GetNextRegion" }, { GetNextTuple, "GetNextTuple" }, { GetStatus, "GetStatus" }, { GetTupleData, "GetTupleData" }, { MapMemPage, "MapMemPage" }, { ModifyConfiguration, "ModifyConfiguration" }, { ModifyWindow, "ModifyWindow" }, { OpenMemory, "OpenMemory" }, { ParseTuple, "ParseTuple" }, { ReadMemory, "ReadMemory" }, { RegisterClient, "RegisterClient" }, { RegisterEraseQueue, "RegisterEraseQueue" }, { RegisterMTD, "RegisterMTD" }, { ReleaseConfiguration, "ReleaseConfiguration" }, { ReleaseIO, "ReleaseIO" }, { ReleaseIRQ, "ReleaseIRQ" }, { ReleaseWindow, "ReleaseWindow" }, { RequestConfiguration, "RequestConfiguration" }, { RequestIO, "RequestIO" }, { RequestIRQ, "RequestIRQ" }, { RequestSocketMask, "RequestSocketMask" }, { RequestWindow, "RequestWindow" }, { ResetCard, "ResetCard" }, { SetEventMask, "SetEventMask" }, { ValidateCIS, "ValidateCIS" }, { WriteMemory, "WriteMemory" }, { BindDevice, "BindDevice" }, { BindMTD, "BindMTD" }, { ReportError, "ReportError" }, { SuspendCard, "SuspendCard" }, { ResumeCard, "ResumeCard" }, { EjectCard, "EjectCard" }, { InsertCard, "InsertCard" }, { ReplaceCIS, "ReplaceCIS" }};#define SERVICE_COUNT (sizeof(service_table)/sizeof(lookup_t))/*====================================================================== Reset a socket to the default state ======================================================================*/static void init_socket(socket_info_t *s){ int i; pccard_io_map io = { 0, 0, 0, 0, 1 }; pccard_mem_map mem = { 0, 0, 0, 0, 0, 0 }; mem.sys_stop = s->cap.map_size; s->socket = dead_socket; s->ss_entry(s->sock, SS_SetSocket, &s->socket); for (i = 0; i < 2; i++) { io.map = i; s->ss_entry(s->sock, SS_SetIOMap, &io); } for (i = 0; i < 5; i++) { mem.map = i; s->ss_entry(s->sock, SS_SetMemMap, &mem); }}/*====================================================================*/#if defined(HAS_PROC_BUS) && defined(PCMCIA_DEBUG)static int proc_read_clients(char *buf, char **start, off_t pos, int count, int *eof, void *data){ socket_info_t *s = data; client_handle_t c; char *p = buf; for (c = s->clients; c; c = c->next) p += sprintf(p, "fn %x: '%s' [attr 0x%04x] [state 0x%04x]\n", c->Function, c->dev_info, c->Attributes, c->state); return (p - buf);}#endif/*====================================================================== Low-level PC Card interface drivers need to register with Card Services using these calls. ======================================================================*/static void setup_socket(u_long i);static void shutdown_socket(u_long i);static void reset_socket(u_long i);static void unreset_socket(u_long i);static void parse_events(void *info, u_int events);int register_ss_entry(int nsock, ss_entry_t ss_entry){ int i, ns; socket_info_t *s; DEBUG(0, "cs: register_ss_entry(%d, 0x%p)\n", nsock, ss_entry); for (ns = 0; ns < nsock; ns++) { s = kmalloc(sizeof(struct socket_info_t), GFP_KERNEL); if (!s) { printk(KERN_NOTICE "cs: memory allocation failure!\n"); return (!ns); } memset(s, 0, sizeof(socket_info_t)); s->ss_entry = ss_entry; s->sock = ns; s->setup.data = sockets; s->setup.function = &setup_socket; s->shutdown.data = sockets; s->shutdown.function = &shutdown_socket; /* base address = 0, map = 0 */ s->cis_mem.flags = 0; s->cis_mem.speed = cis_speed; s->erase_busy.next = s->erase_busy.prev = &s->erase_busy; spin_lock_init(&s->lock); for (i = 0; i < sockets; i++) if (socket_table[i] == NULL) break; socket_table[i] = s; if (i == sockets) sockets++; init_socket(s); ss_entry(ns, SS_InquireSocket, &s->cap);#ifdef HAS_PROC_BUS if (proc_pccard) { char name[3]; sprintf(name, "%02d", i); s->proc = proc_mkdir(name, proc_pccard); if (s->proc) ss_entry(ns, SS_ProcSetup, s->proc);#ifdef PCMCIA_DEBUG if (s->proc) create_proc_read_entry("clients", 0, s->proc, proc_read_clients, s);#endif }#endif } return 0;} /* register_ss_entry *//*====================================================================*/void unregister_ss_entry(ss_entry_t ss_entry){ int i, j; socket_info_t *s = NULL; client_t *client;#ifdef HAS_PROC_BUS for (i = 0; i < sockets; i++) { s = socket_table[i]; if (s->ss_entry != ss_entry) continue; if (proc_pccard) { char name[3]; sprintf(name, "%02d", i);#ifdef PCMCIA_DEBUG remove_proc_entry("clients", s->proc);#endif remove_proc_entry(name, proc_pccard); } }#endif for (;;) { for (i = 0; i < sockets; i++) { s = socket_table[i]; if (s->ss_entry == ss_entry) break; } if (i == sockets) break; shutdown_socket(i); release_cis_mem(s); while (s->clients) { client = s->clients; s->clients = s->clients->next; kfree(client); } s->ss_entry = NULL; kfree(s); socket_table[i] = NULL; for (j = i; j < sockets-1; j++) socket_table[j] = socket_table[j+1]; sockets--; } } /* unregister_ss_entry *//*====================================================================== Shutdown_Socket() and setup_socket() are scheduled using add_timer calls by the main event handler when card insertion and removal events are received. Shutdown_Socket() unconfigures a socket and turns off socket power. Setup_socket() turns on socket power and resets the socket, in two stages.======================================================================*/static void free_regions(memory_handle_t *list){ memory_handle_t tmp; while (*list != NULL) { tmp = *list; *list = tmp->info.next; tmp->region_magic = 0; kfree(tmp); }}static int send_event(socket_info_t *s, event_t event, int priority);static void shutdown_socket(u_long i){ socket_info_t *s = socket_table[i]; client_t **c; DEBUG(1, "cs: shutdown_socket(%ld)\n", i); /* Blank out the socket state */ s->state &= SOCKET_PRESENT|SOCKET_SETUP_PENDING; init_socket(s); s->irq.AssignedIRQ = s->irq.Config = 0; s->lock_count = 0; s->cis_used = 0; if (s->fake_cis) { kfree(s->fake_cis);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?