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