📄 cs.c
字号:
/*====================================================================== PCMCIA Card Services -- core services cs.c 1.271 2000/10/02 20:27:49 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 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/malloc.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 <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"#include "rsrc_mgr.h"#ifdef PCMCIA_DEBUGint pc_debug = PCMCIA_DEBUG;MODULE_PARM(pc_debug, "i");static const char *version ="cs.c 1.271 2000/10/02 20:27:49 (David Hinds)";#endif#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 " [pm]"#else#define PM_OPT ""#endif#if !defined(CONFIG_CARDBUS) && !defined(CONFIG_PCI) && !defined(CONFIG_PM)#define OPTIONS " none"#else#define OPTIONS PCI_OPT CB_OPT PM_OPT#endifstatic const char *release = "Linux PCMCIA Card Services " CS_RELEASE;static const char *options = "options: " OPTIONS;MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");MODULE_DESCRIPTION("Linux PCMCIA Card Services " CS_RELEASE "\n options:" OPTIONS);/*====================================================================*//* Parameters that can be set with 'insmod' */#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")INT_MODULE_PARM(setup_delay, 10); /* centiseconds */INT_MODULE_PARM(resume_delay, 20); /* centiseconds */INT_MODULE_PARM(shutdown_delay, 3); /* centiseconds */INT_MODULE_PARM(vcc_settle, 40); /* centiseconds */INT_MODULE_PARM(reset_time, 10); /* usecs */INT_MODULE_PARM(unreset_delay, 10); /* centiseconds */INT_MODULE_PARM(unreset_check, 10); /* centiseconds */INT_MODULE_PARM(unreset_limit, 30); /* 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);#elseINT_MODULE_PARM(do_apm, 0);#endif/*====================================================================*/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 CONFIG_PROC_FSstruct 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))/*====================================================================== These functions are just shorthand for the actual low-level drivers======================================================================*/static int register_callback(socket_info_t *s, void (*handler)(void *, unsigned int), void * info){ return s->ss_entry->register_callback(s->sock, handler, info);}static int get_socket_status(socket_info_t *s, int *val){ return s->ss_entry->get_status(s->sock, val);}static int set_socket(socket_info_t *s, socket_state_t *state){ return s->ss_entry->set_socket(s->sock, state);}static int set_io_map(socket_info_t *s, struct pccard_io_map *io){ return s->ss_entry->set_io_map(s->sock, io);}static int set_mem_map(socket_info_t *s, struct pccard_mem_map *mem){ return s->ss_entry->set_mem_map(s->sock, mem);}static int suspend_socket(socket_info_t *s){ s->socket = dead_socket; return s->ss_entry->suspend(s->sock);}static int init_socket(socket_info_t *s){ s->socket = dead_socket; return s->ss_entry->init(s->sock);}/*====================================================================*/#if defined(CONFIG_PROC_FS) && 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 int setup_socket(socket_info_t *);static void shutdown_socket(socket_info_t *);static void reset_socket(socket_info_t *);static void unreset_socket(socket_info_t *);static void parse_events(void *info, u_int events);socket_info_t *pcmcia_register_socket (int slot, struct pccard_operations * ss_entry, int use_bus_pm){ socket_info_t *s; int i; DEBUG(0, "cs: pcmcia_register_socket(0x%p)\n", ss_entry); s = kmalloc(sizeof(struct socket_info_t), GFP_KERNEL); if (!s) return NULL; memset(s, 0, sizeof(socket_info_t)); s->ss_entry = ss_entry; s->sock = slot; /* base address = 0, map = 0 */ s->cis_mem.flags = 0; s->cis_mem.speed = cis_speed; s->use_bus_pm = use_bus_pm; 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->inquire_socket(slot, &s->cap);#ifdef CONFIG_PROC_FS if (proc_pccard) { char name[3]; sprintf(name, "%02d", i); s->proc = proc_mkdir(name, proc_pccard); if (s->proc) ss_entry->proc_setup(slot, s->proc);#ifdef PCMCIA_DEBUG if (s->proc) create_proc_read_entry("clients", 0, s->proc, proc_read_clients, s);#endif }#endif return s;} /* pcmcia_register_socket */int register_ss_entry(int nsock, struct pccard_operations * ss_entry){ int ns; DEBUG(0, "cs: register_ss_entry(%d, 0x%p)\n", nsock, ss_entry); for (ns = 0; ns < nsock; ns++) { pcmcia_register_socket (ns, ss_entry, 0); } return 0;} /* register_ss_entry *//*====================================================================*/void pcmcia_unregister_socket(socket_info_t *s){ int j, socket = -1; client_t *client; for (j = 0; j < MAX_SOCK; j++) if (socket_table [j] == s) { socket = j; break; } if (socket < 0) return;#ifdef CONFIG_PROC_FS if (proc_pccard) { char name[3]; sprintf(name, "%02d", socket);#ifdef PCMCIA_DEBUG remove_proc_entry("clients", s->proc);#endif remove_proc_entry(name, proc_pccard); }#endif shutdown_socket(s); 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[socket] = NULL; for (j = socket; j < sockets-1; j++) socket_table[j] = socket_table[j+1]; sockets--;} /* pcmcia_unregister_socket */void unregister_ss_entry(struct pccard_operations * ss_entry){ int i; for (i = sockets-1; i >= 0; i-- ) { socket_info_t *socket = socket_table[i]; if (socket->ss_entry == ss_entry) pcmcia_unregister_socket (socket); }} /* 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);/* * Sleep for n_cs centiseconds (1 cs = 1/100th of a second) */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -