| File: | obj-scan-build/../linux/pcmcia-cs/modules/cs.c |
| Location: | line 384, column 10 |
| Description: | Access to field 'ss_entry' results in a dereference of a null pointer (loaded from variable 's') |
| 1 | /*====================================================================== | |||
| 2 | ||||
| 3 | PCMCIA Card Services -- core services | |||
| 4 | ||||
| 5 | cs.c 1.287 2004/04/09 03:54:25 | |||
| 6 | ||||
| 7 | The contents of this file are subject to the Mozilla Public | |||
| 8 | License Version 1.1 (the "License"); you may not use this file | |||
| 9 | except in compliance with the License. You may obtain a copy of | |||
| 10 | the License at http://www.mozilla.org/MPL/ | |||
| 11 | ||||
| 12 | Software distributed under the License is distributed on an "AS | |||
| 13 | IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or | |||
| 14 | implied. See the License for the specific language governing | |||
| 15 | rights and limitations under the License. | |||
| 16 | ||||
| 17 | The initial developer of the original code is David A. Hinds | |||
| 18 | <dahinds@users.sourceforge.net>. Portions created by David A. Hinds | |||
| 19 | are Copyright (C) 1999 David A. Hinds. All Rights Reserved. | |||
| 20 | ||||
| 21 | Alternatively, the contents of this file may be used under the | |||
| 22 | terms of the GNU General Public License version 2 (the "GPL"), in | |||
| 23 | which case the provisions of the GPL are applicable instead of the | |||
| 24 | above. If you wish to allow the use of your version of this file | |||
| 25 | only under the terms of the GPL and not to allow others to use | |||
| 26 | your version of this file under the MPL, indicate your decision | |||
| 27 | by deleting the provisions above and replace them with the notice | |||
| 28 | and other provisions required by the GPL. If you do not delete | |||
| 29 | the provisions above, a recipient may use your version of this | |||
| 30 | file under either the MPL or the GPL. | |||
| 31 | ||||
| 32 | ======================================================================*/ | |||
| 33 | ||||
| 34 | #include <linux/module.h> | |||
| 35 | #include <linux/init.h> | |||
| 36 | #include <linux/kernel.h> | |||
| 37 | #include <linux/config.h> | |||
| 38 | #include <linux/string.h> | |||
| 39 | #include <linux/major.h> | |||
| 40 | #include <linux/errno.h> | |||
| 41 | #include <linux/slab.h> | |||
| 42 | #include <linux/mm.h> | |||
| 43 | #include <linux/sched.h> | |||
| 44 | #include <linux/timer.h> | |||
| 45 | #include <linux/ioport.h> | |||
| 46 | #include <linux/delay.h> | |||
| 47 | #include <linux/proc_fs.h> | |||
| 48 | #include <linux/pm.h> | |||
| 49 | #include <linux/pci.h> | |||
| 50 | #include <linux/spinlock.h> | |||
| 51 | #include <asm/system.h> | |||
| 52 | #include <asm/irq.h> | |||
| 53 | ||||
| 54 | #define IN_CARD_SERVICES | |||
| 55 | #include <pcmcia/version.h> | |||
| 56 | #include <pcmcia/cs_types.h> | |||
| 57 | #include <pcmcia/ss.h> | |||
| 58 | #include <pcmcia/cs.h> | |||
| 59 | #include <pcmcia/bulkmem.h> | |||
| 60 | #include <pcmcia/cistpl.h> | |||
| 61 | #include <pcmcia/cisreg.h> | |||
| 62 | #include <pcmcia/bus_ops.h> | |||
| 63 | #include "cs_internal.h" | |||
| 64 | ||||
| 65 | #ifdef CONFIG_PCI1 | |||
| 66 | #define PCI_OPT" [pci]" " [pci]" | |||
| 67 | #else | |||
| 68 | #define PCI_OPT" [pci]" "" | |||
| 69 | #endif | |||
| 70 | #ifdef CONFIG_CARDBUS | |||
| 71 | #define CB_OPT"" " [cardbus]" | |||
| 72 | #else | |||
| 73 | #define CB_OPT"" "" | |||
| 74 | #endif | |||
| 75 | #ifdef CONFIG_PM | |||
| 76 | #define PM_OPT"" " [apm]" | |||
| 77 | #else | |||
| 78 | #define PM_OPT"" "" | |||
| 79 | #endif | |||
| 80 | #ifdef CONFIG_PNP_BIOS | |||
| 81 | #define PNP_OPT"" " [pnp]" | |||
| 82 | #else | |||
| 83 | #define PNP_OPT"" "" | |||
| 84 | #endif | |||
| 85 | #if !defined(CONFIG_CARDBUS) && !defined(CONFIG_PCI1) && \ | |||
| 86 | !defined(CONFIG_PM) && !defined(CONFIG_PNP_BIOS) | |||
| 87 | #define OPTIONS" [pci]" "" "" "" " none" | |||
| 88 | #else | |||
| 89 | #define OPTIONS" [pci]" "" "" "" PCI_OPT" [pci]" CB_OPT"" PM_OPT"" PNP_OPT"" | |||
| 90 | #endif | |||
| 91 | ||||
| 92 | static const char *release = "Linux PCMCIA Card Services " CS_RELEASE"3.2.8"; | |||
| 93 | #ifdef UTS_RELEASE"2.0.36" | |||
| 94 | static const char *kernel = "kernel build: " UTS_RELEASE"2.0.36" " " UTS_VERSION""; | |||
| 95 | #endif | |||
| 96 | static const char *options = "options: " OPTIONS" [pci]" "" "" ""; | |||
| 97 | ||||
| 98 | /*====================================================================*/ | |||
| 99 | ||||
| 100 | /* Module parameters */ | |||
| 101 | ||||
| 102 | MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>"); | |||
| 103 | MODULE_DESCRIPTION("Linux PCMCIA Card Services " CS_RELEASE | |||
| 104 | "\n options:" OPTIONS); | |||
| 105 | MODULE_LICENSE("Dual MPL/GPL"); | |||
| 106 | ||||
| 107 | #define INT_MODULE_PARM(n, v)static int n = v; static int n = v; MODULE_PARM(n, "i") | |||
| 108 | ||||
| 109 | INT_MODULE_PARM(setup_delay, HZ/20)static int setup_delay = 100/20;; /* ticks */ | |||
| 110 | INT_MODULE_PARM(resume_delay, HZ/5)static int resume_delay = 100/5;; /* ticks */ | |||
| 111 | INT_MODULE_PARM(shutdown_delay, HZ/40)static int shutdown_delay = 100/40;; /* ticks */ | |||
| 112 | INT_MODULE_PARM(vcc_settle, HZ*4/10)static int vcc_settle = 100*4/10;; /* ticks */ | |||
| 113 | INT_MODULE_PARM(reset_time, 10)static int reset_time = 10;; /* usecs */ | |||
| 114 | INT_MODULE_PARM(unreset_delay, HZ/10)static int unreset_delay = 100/10;; /* ticks */ | |||
| 115 | INT_MODULE_PARM(unreset_check, HZ/10)static int unreset_check = 100/10;; /* ticks */ | |||
| 116 | INT_MODULE_PARM(unreset_limit, 50)static int unreset_limit = 50;; /* unreset_check's */ | |||
| 117 | ||||
| 118 | /* Access speed for attribute memory windows */ | |||
| 119 | INT_MODULE_PARM(cis_speed, 300)static int cis_speed = 300;; /* ns */ | |||
| 120 | ||||
| 121 | /* Access speed for IO windows */ | |||
| 122 | INT_MODULE_PARM(io_speed, 0)static int io_speed = 0;; /* ns */ | |||
| 123 | ||||
| 124 | /* Optional features */ | |||
| 125 | #ifdef CONFIG_PM | |||
| 126 | INT_MODULE_PARM(do_apm, 1)static int do_apm = 1;; | |||
| 127 | #endif | |||
| 128 | #ifdef CONFIG_PNP_BIOS | |||
| 129 | INT_MODULE_PARM(do_pnp, 1)static int do_pnp = 1;; | |||
| 130 | #endif | |||
| 131 | ||||
| 132 | #ifdef PCMCIA_DEBUG4 | |||
| 133 | int pc_debug=PCMCIA_DEBUG4; | |||
| 134 | MODULE_PARM(pc_debug, "i"); | |||
| 135 | static const char *version = | |||
| 136 | "cs.c 1.287 2004/04/09 03:54:25 (David Hinds)"; | |||
| 137 | #endif | |||
| 138 | ||||
| 139 | /*====================================================================*/ | |||
| 140 | ||||
| 141 | static socket_state_t dead_socket = { | |||
| 142 | 0, SS_DETECT0x0080, 0, 0, 0 | |||
| 143 | }; | |||
| 144 | ||||
| 145 | /* Table of sockets */ | |||
| 146 | socket_t sockets = 0; | |||
| 147 | socket_info_t *socket_table[MAX_SOCK8]; | |||
| 148 | ||||
| 149 | #ifdef HAS_PROC_BUS | |||
| 150 | struct proc_dir_entry *proc_pccard = NULL((void *) 0); | |||
| 151 | #endif | |||
| 152 | ||||
| 153 | /*====================================================================*/ | |||
| 154 | ||||
| 155 | /* String tables for error messages */ | |||
| 156 | ||||
| 157 | typedef struct lookup_t { | |||
| 158 | int key; | |||
| 159 | char *msg; | |||
| 160 | } lookup_t; | |||
| 161 | ||||
| 162 | static const lookup_t error_table[] = { | |||
| 163 | { CS_SUCCESS0x00, "Operation succeeded" }, | |||
| 164 | { CS_BAD_ADAPTER0x01, "Bad adapter" }, | |||
| 165 | { CS_BAD_ATTRIBUTE0x02, "Bad attribute", }, | |||
| 166 | { CS_BAD_BASE0x03, "Bad base address" }, | |||
| 167 | { CS_BAD_EDC0x04, "Bad EDC" }, | |||
| 168 | { CS_BAD_IRQ0x06, "Bad IRQ" }, | |||
| 169 | { CS_BAD_OFFSET0x07, "Bad offset" }, | |||
| 170 | { CS_BAD_PAGE0x08, "Bad page number" }, | |||
| 171 | { CS_READ_FAILURE0x09, "Read failure" }, | |||
| 172 | { CS_BAD_SIZE0x0a, "Bad size" }, | |||
| 173 | { CS_BAD_SOCKET0x0b, "Bad socket" }, | |||
| 174 | { CS_BAD_TYPE0x0d, "Bad type" }, | |||
| 175 | { CS_BAD_VCC0x0e, "Bad Vcc" }, | |||
| 176 | { CS_BAD_VPP0x0f, "Bad Vpp" }, | |||
| 177 | { CS_BAD_WINDOW0x11, "Bad window" }, | |||
| 178 | { CS_WRITE_FAILURE0x12, "Write failure" }, | |||
| 179 | { CS_NO_CARD0x14, "No card present" }, | |||
| 180 | { CS_UNSUPPORTED_FUNCTION0x15, "Usupported function" }, | |||
| 181 | { CS_UNSUPPORTED_MODE0x16, "Unsupported mode" }, | |||
| 182 | { CS_BAD_SPEED0x17, "Bad speed" }, | |||
| 183 | { CS_BUSY0x18, "Resource busy" }, | |||
| 184 | { CS_GENERAL_FAILURE0x19, "General failure" }, | |||
| 185 | { CS_WRITE_PROTECTED0x1a, "Write protected" }, | |||
| 186 | { CS_BAD_ARG_LENGTH0x1b, "Bad argument length" }, | |||
| 187 | { CS_BAD_ARGS0x1c, "Bad arguments" }, | |||
| 188 | { CS_CONFIGURATION_LOCKED0x1d, "Configuration locked" }, | |||
| 189 | { CS_IN_USE0x1e, "Resource in use" }, | |||
| 190 | { CS_NO_MORE_ITEMS0x1f, "No more items" }, | |||
| 191 | { CS_OUT_OF_RESOURCE0x20, "Out of resource" }, | |||
| 192 | { CS_BAD_HANDLE0x21, "Bad handle" }, | |||
| 193 | { CS_BAD_TUPLE0x40, "Bad CIS tuple" } | |||
| 194 | }; | |||
| 195 | #define ERROR_COUNT(sizeof(error_table)/sizeof(lookup_t)) (sizeof(error_table)/sizeof(lookup_t)) | |||
| 196 | ||||
| 197 | static const lookup_t service_table[] = { | |||
| 198 | { AccessConfigurationRegister, "AccessConfigurationRegister" }, | |||
| 199 | { AddSocketServices, "AddSocketServices" }, | |||
| 200 | { AdjustResourceInfo, "AdjustResourceInfo" }, | |||
| 201 | { CheckEraseQueue, "CheckEraseQueue" }, | |||
| 202 | { CloseMemory, "CloseMemory" }, | |||
| 203 | { DeregisterClient, "DeregisterClient" }, | |||
| 204 | { DeregisterEraseQueue, "DeregisterEraseQueue" }, | |||
| 205 | { GetCardServicesInfo, "GetCardServicesInfo" }, | |||
| 206 | { GetClientInfo, "GetClientInfo" }, | |||
| 207 | { GetConfigurationInfo, "GetConfigurationInfo" }, | |||
| 208 | { GetEventMask, "GetEventMask" }, | |||
| 209 | { GetFirstClient, "GetFirstClient" }, | |||
| 210 | { GetFirstRegion, "GetFirstRegion" }, | |||
| 211 | { GetFirstTuple, "GetFirstTuple" }, | |||
| 212 | { GetNextClient, "GetNextClient" }, | |||
| 213 | { GetNextRegion, "GetNextRegion" }, | |||
| 214 | { GetNextTuple, "GetNextTuple" }, | |||
| 215 | { GetStatus, "GetStatus" }, | |||
| 216 | { GetTupleData, "GetTupleData" }, | |||
| 217 | { MapMemPage, "MapMemPage" }, | |||
| 218 | { ModifyConfiguration, "ModifyConfiguration" }, | |||
| 219 | { ModifyWindow, "ModifyWindow" }, | |||
| 220 | { OpenMemory, "OpenMemory" }, | |||
| 221 | { ParseTuple, "ParseTuple" }, | |||
| 222 | { ReadMemory, "ReadMemory" }, | |||
| 223 | { RegisterClient, "RegisterClient" }, | |||
| 224 | { RegisterEraseQueue, "RegisterEraseQueue" }, | |||
| 225 | { RegisterMTD, "RegisterMTD" }, | |||
| 226 | { ReleaseConfiguration, "ReleaseConfiguration" }, | |||
| 227 | { ReleaseIO, "ReleaseIO" }, | |||
| 228 | { ReleaseIRQ, "ReleaseIRQ" }, | |||
| 229 | { ReleaseWindow, "ReleaseWindow" }, | |||
| 230 | { RequestConfiguration, "RequestConfiguration" }, | |||
| 231 | { RequestIO, "RequestIO" }, | |||
| 232 | { RequestIRQ, "RequestIRQ" }, | |||
| 233 | { RequestSocketMask, "RequestSocketMask" }, | |||
| 234 | { RequestWindow, "RequestWindow" }, | |||
| 235 | { ResetCard, "ResetCard" }, | |||
| 236 | { SetEventMask, "SetEventMask" }, | |||
| 237 | { ValidateCIS, "ValidateCIS" }, | |||
| 238 | { WriteMemory, "WriteMemory" }, | |||
| 239 | { BindDevice, "BindDevice" }, | |||
| 240 | { BindMTD, "BindMTD" }, | |||
| 241 | { ReportError, "ReportError" }, | |||
| 242 | { SuspendCard, "SuspendCard" }, | |||
| 243 | { ResumeCard, "ResumeCard" }, | |||
| 244 | { EjectCard, "EjectCard" }, | |||
| 245 | { InsertCard, "InsertCard" }, | |||
| 246 | { ReplaceCIS, "ReplaceCIS" } | |||
| 247 | }; | |||
| 248 | #define SERVICE_COUNT(sizeof(service_table)/sizeof(lookup_t)) (sizeof(service_table)/sizeof(lookup_t)) | |||
| 249 | ||||
| 250 | /*====================================================================== | |||
| 251 | ||||
| 252 | Reset a socket to the default state | |||
| 253 | ||||
| 254 | ======================================================================*/ | |||
| 255 | ||||
| 256 | static void init_socket(socket_info_t *s) | |||
| 257 | { | |||
| 258 | int i; | |||
| 259 | pccard_io_map io = { 0, 0, 0, 0, 1 }; | |||
| 260 | pccard_mem_map mem = { 0, 0, 0, 0, 0, 0 }; | |||
| 261 | ||||
| 262 | mem.sys_stop = s->cap.map_size; | |||
| 263 | s->socket = dead_socket; | |||
| 264 | s->ss_entry(s->sock, SS_SetSocket, &s->socket); | |||
| 265 | for (i = 0; i < 2; i++) { | |||
| 266 | io.map = i; | |||
| 267 | s->ss_entry(s->sock, SS_SetIOMap, &io); | |||
| 268 | } | |||
| 269 | for (i = 0; i < 5; i++) { | |||
| 270 | mem.map = i; | |||
| 271 | s->ss_entry(s->sock, SS_SetMemMap, &mem); | |||
| 272 | } | |||
| 273 | } | |||
| 274 | ||||
| 275 | /*====================================================================*/ | |||
| 276 | ||||
| 277 | #if defined(HAS_PROC_BUS) && defined(PCMCIA_DEBUG4) | |||
| 278 | static int proc_read_clients(char *buf, char **start, off_t pos, | |||
| 279 | int count, int *eof, void *data) | |||
| 280 | { | |||
| 281 | socket_info_t *s = data; | |||
| 282 | client_handle_t c; | |||
| 283 | char *p = buf; | |||
| 284 | ||||
| 285 | for (c = s->clients; c; c = c->next) | |||
| 286 | p += sprintflinux_sprintf(p, "fn %x: '%s' [attr 0x%04x] [state 0x%04x]\n", | |||
| 287 | c->Function, c->dev_info, c->Attributes, c->state); | |||
| 288 | return (p - buf); | |||
| 289 | } | |||
| 290 | #endif | |||
| 291 | ||||
| 292 | /*====================================================================== | |||
| 293 | ||||
| 294 | Low-level PC Card interface drivers need to register with Card | |||
| 295 | Services using these calls. | |||
| 296 | ||||
| 297 | ======================================================================*/ | |||
| 298 | ||||
| 299 | static void setup_socket(u_long i); | |||
| 300 | static void shutdown_socket(u_long i); | |||
| 301 | static void reset_socket(u_long i); | |||
| 302 | static void unreset_socket(u_long i); | |||
| 303 | static void parse_events(void *info, u_int events); | |||
| 304 | ||||
| 305 | int register_ss_entry(int nsock, ss_entry_t ss_entry) | |||
| 306 | { | |||
| 307 | int i, ns; | |||
| 308 | socket_info_t *s; | |||
| 309 | ||||
| 310 | DEBUG(0, "cs: register_ss_entry(%d, 0x%p)\n", nsock, ss_entry)do { if (pc_debug>(0)) printk("<7>" "cs: register_ss_entry(%d, 0x%p)\n" , nsock, ss_entry); } while (0); | |||
| 311 | ||||
| 312 | for (ns = 0; ns < nsock; ns++) { | |||
| 313 | s = kmalloclinux_kmalloc(sizeof(struct socket_info_t), GFP_KERNEL0x03); | |||
| 314 | if (!s) { | |||
| 315 | printk(KERN_NOTICE"<5>" "cs: memory allocation failure!\n"); | |||
| 316 | return (!ns); | |||
| 317 | } | |||
| 318 | memset(s, 0, sizeof(socket_info_t))(__builtin_constant_p(0) ? (__builtin_constant_p((sizeof(socket_info_t ))) ? __constant_c_and_count_memset(((s)),((0x01010101UL*(unsigned char)(0))),((sizeof(socket_info_t)))) : __constant_c_memset( ((s)),((0x01010101UL*(unsigned char)(0))),((sizeof(socket_info_t ))))) : (__builtin_constant_p((sizeof(socket_info_t))) ? __memset_generic ((((s))),(((0))),(((sizeof(socket_info_t))))) : __memset_generic (((s)),((0)),((sizeof(socket_info_t)))))); | |||
| 319 | ||||
| 320 | s->ss_entry = ss_entry; | |||
| 321 | s->sock = ns; | |||
| 322 | s->setup.data = sockets; | |||
| 323 | s->setup.function = &setup_socket; | |||
| 324 | s->shutdown.data = sockets; | |||
| 325 | s->shutdown.function = &shutdown_socket; | |||
| 326 | /* base address = 0, map = 0 */ | |||
| 327 | s->cis_mem.flags = 0; | |||
| 328 | s->cis_mem.speed = cis_speed; | |||
| 329 | s->erase_busy.next = s->erase_busy.prev = &s->erase_busy; | |||
| 330 | spin_lock_init(&s->lock)do { } while(0); | |||
| 331 | ||||
| 332 | for (i = 0; i < sockets; i++) | |||
| 333 | if (socket_table[i] == NULL((void *) 0)) break; | |||
| 334 | socket_table[i] = s; | |||
| 335 | if (i == sockets) sockets++; | |||
| 336 | ||||
| 337 | init_socket(s); | |||
| 338 | ss_entry(ns, SS_InquireSocket, &s->cap); | |||
| 339 | #ifdef HAS_PROC_BUS | |||
| 340 | if (proc_pccard) { | |||
| 341 | char name[3]; | |||
| 342 | sprintflinux_sprintf(name, "%02d", i); | |||
| 343 | s->proc = proc_mkdir(name, proc_pccard); | |||
| 344 | if (s->proc) | |||
| 345 | ss_entry(ns, SS_ProcSetup, s->proc); | |||
| 346 | #ifdef PCMCIA_DEBUG4 | |||
| 347 | if (s->proc) | |||
| 348 | create_proc_read_entry("clients", 0, s->proc, | |||
| 349 | proc_read_clients, s); | |||
| 350 | #endif | |||
| 351 | } | |||
| 352 | #endif | |||
| 353 | } | |||
| 354 | ||||
| 355 | return 0; | |||
| 356 | } /* register_ss_entry */ | |||
| 357 | ||||
| 358 | /*====================================================================*/ | |||
| 359 | ||||
| 360 | void unregister_ss_entry(ss_entry_t ss_entry) | |||
| 361 | { | |||
| 362 | int i, j; | |||
| 363 | socket_info_t *s = NULL((void *) 0); | |||
| 364 | client_t *client; | |||
| 365 | ||||
| 366 | #ifdef HAS_PROC_BUS | |||
| 367 | for (i = 0; i < sockets; i++) { | |||
| 368 | s = socket_table[i]; | |||
| 369 | if (s->ss_entry != ss_entry) continue; | |||
| 370 | if (proc_pccard) { | |||
| 371 | char name[3]; | |||
| 372 | sprintflinux_sprintf(name, "%02d", i); | |||
| 373 | #ifdef PCMCIA_DEBUG4 | |||
| 374 | remove_proc_entry("clients", s->proc); | |||
| 375 | #endif | |||
| 376 | remove_proc_entry(name, proc_pccard); | |||
| 377 | } | |||
| 378 | } | |||
| 379 | #endif | |||
| 380 | ||||
| 381 | for (;;) { | |||
| ||||
| 382 | for (i = 0; i < sockets; i++) { | |||
| 383 | s = socket_table[i]; | |||
| 384 | if (s->ss_entry == ss_entry) break; | |||
| ||||
| 385 | } | |||
| 386 | if (i == sockets) | |||
| 387 | break; | |||
| 388 | shutdown_socket(i); | |||
| 389 | release_cis_mem(s); | |||
| 390 | while (s->clients) { | |||
| 391 | client = s->clients; | |||
| 392 | s->clients = s->clients->next; | |||
| 393 | kfreelinux_kfree(client); | |||
| 394 | } | |||
| 395 | s->ss_entry = NULL((void *) 0); | |||
| 396 | kfreelinux_kfree(s); | |||
| 397 | socket_table[i] = NULL((void *) 0); | |||
| 398 | for (j = i; j < sockets-1; j++) | |||
| 399 | socket_table[j] = socket_table[j+1]; | |||
| 400 | sockets--; | |||
| 401 | } | |||
| 402 | ||||
| 403 | } /* unregister_ss_entry */ | |||
| 404 | ||||
| 405 | /*====================================================================== | |||
| 406 | ||||
| 407 | Shutdown_Socket() and setup_socket() are scheduled using add_timer | |||
| 408 | calls by the main event handler when card insertion and removal | |||
| 409 | events are received. Shutdown_Socket() unconfigures a socket and | |||
| 410 | turns off socket power. Setup_socket() turns on socket power | |||
| 411 | and resets the socket, in two stages. | |||
| 412 | ||||
| 413 | ======================================================================*/ | |||
| 414 | ||||
| 415 | static void free_regions(memory_handle_t *list) | |||
| 416 | { | |||
| 417 | memory_handle_t tmp; | |||
| 418 | while (*list != NULL((void *) 0)) { | |||
| 419 | tmp = *list; | |||
| 420 | *list = tmp->info.next; | |||
| 421 | tmp->region_magic = 0; | |||
| 422 | kfreelinux_kfree(tmp); | |||
| 423 | } | |||
| 424 | } | |||
| 425 | ||||
| 426 | static int send_event(socket_info_t *s, event_t event, int priority); | |||
| 427 | ||||
| 428 | static void shutdown_socket(u_long i) | |||
| 429 | { | |||
| 430 | socket_info_t *s = socket_table[i]; | |||
| 431 | client_t **c; | |||
| 432 | ||||
| 433 | DEBUG(1, "cs: shutdown_socket(%ld)\n", i)do { if (pc_debug>(1)) printk("<7>" "cs: shutdown_socket(%ld)\n" , i); } while (0); | |||
| 434 | ||||
| 435 | /* Blank out the socket state */ | |||
| 436 | s->state &= SOCKET_PRESENT0x0008|SOCKET_SETUP_PENDING0x0010; | |||
| 437 | init_socket(s); | |||
| 438 | s->irq.AssignedIRQ = s->irq.Config = 0; | |||
| 439 | s->lock_count = 0; | |||
| 440 | s->cis_used = 0; | |||
| 441 | if (s->fake_cis) { | |||
| 442 | kfreelinux_kfree(s->fake_cis); | |||
| 443 | s->fake_cis = NULL((void *) 0); | |||
| 444 | } | |||
| 445 | #ifdef CONFIG_CARDBUS | |||
| 446 | cb_release_cis_mem(s); | |||
| 447 | cb_free(s); | |||
| 448 | #endif | |||
| 449 | s->functions = 0; | |||
| 450 | if (s->config) { | |||
| 451 | kfreelinux_kfree(s->config); | |||
| 452 | s->config = NULL((void *) 0); | |||
| 453 | } | |||
| 454 | for (c = &s->clients; *c; ) { | |||
| 455 | if ((*c)->state & CLIENT_UNBOUND0x0008) { | |||
| 456 | client_t *d = *c; | |||
| 457 | *c = (*c)->next; | |||
| 458 | kfreelinux_kfree(d); | |||
| 459 | } else { | |||
| 460 | c = &((*c)->next); | |||
| 461 | } | |||
| 462 | } | |||
| 463 | free_regions(&s->a_region); | |||
| 464 | free_regions(&s->c_region); | |||
| 465 | } /* shutdown_socket */ | |||
| 466 | ||||
| 467 | static void setup_socket(u_long i) | |||
| 468 | { | |||
| 469 | int val; | |||
| 470 | socket_info_t *s = socket_table[i]; | |||
| 471 | ||||
| 472 | s->ss_entry(s->sock, SS_GetStatus, &val); | |||
| 473 | if (val & SS_PENDING0x4000) { | |||
| 474 | /* Does the socket need more time? */ | |||
| 475 | DEBUG(2, "cs: setup_socket(%ld): status pending\n", i)do { if (pc_debug>(2)) printk("<7>" "cs: setup_socket(%ld): status pending\n" , i); } while (0); | |||
| 476 | if (++s->setup_timeout > 100) { | |||
| 477 | printk(KERN_NOTICE"<5>" "cs: socket %ld voltage interrogation" | |||
| 478 | " timed out\n", i); | |||
| 479 | } else { | |||
| 480 | mod_timer(&s->setup, jiffies + HZ/10)do { del_timer(&s->setup); (&s->setup)->expires = (jiffies + 100/10); add_timer(&s->setup); } while ( 0); | |||
| 481 | } | |||
| 482 | } else if (val & SS_DETECT0x0080) { | |||
| 483 | DEBUG(1, "cs: setup_socket(%ld): applying power\n", i)do { if (pc_debug>(1)) printk("<7>" "cs: setup_socket(%ld): applying power\n" , i); } while (0); | |||
| 484 | s->state |= SOCKET_PRESENT0x0008; | |||
| 485 | s->socket.flags = 0; | |||
| 486 | if (val & SS_3VCARD0x1000) | |||
| 487 | s->socket.Vcc = s->socket.Vpp = 33; | |||
| 488 | else if (!(val & SS_XVCARD0x2000)) | |||
| 489 | s->socket.Vcc = s->socket.Vpp = 50; | |||
| 490 | else { | |||
| 491 | printk(KERN_NOTICE"<5>" "cs: socket %ld: unsupported " | |||
| 492 | "voltage key\n", i); | |||
| 493 | s->socket.Vcc = 0; | |||
| 494 | } | |||
| 495 | if (val & SS_CARDBUS0x0800) { | |||
| 496 | s->state |= SOCKET_CARDBUS0x8000; | |||
| 497 | #ifndef CONFIG_CARDBUS | |||
| 498 | printk(KERN_NOTICE"<5>" "cs: unsupported card type detected!\n"); | |||
| 499 | #endif | |||
| 500 | } | |||
| 501 | s->ss_entry(s->sock, SS_SetSocket, &s->socket); | |||
| 502 | s->setup.function = &reset_socket; | |||
| 503 | mod_timer(&s->setup, jiffies + vcc_settle)do { del_timer(&s->setup); (&s->setup)->expires = (jiffies + vcc_settle); add_timer(&s->setup); } while (0); | |||
| 504 | } else | |||
| 505 | DEBUG(0, "cs: setup_socket(%ld): no card!\n", i)do { if (pc_debug>(0)) printk("<7>" "cs: setup_socket(%ld): no card!\n" , i); } while (0); | |||
| 506 | } /* setup_socket */ | |||
| 507 | ||||
| 508 | /*====================================================================== | |||
| 509 | ||||
| 510 | Reset_socket() and unreset_socket() handle hard resets. Resets | |||
| 511 | have several causes: card insertion, a call to reset_socket, or | |||
| 512 | recovery from a suspend/resume cycle. Unreset_socket() sends | |||
| 513 | a CS event that matches the cause of the reset. | |||
| 514 | ||||
| 515 | ======================================================================*/ | |||
| 516 | ||||
| 517 | static void reset_socket(u_long i) | |||
| 518 | { | |||
| 519 | socket_info_t *s = socket_table[i]; | |||
| 520 | ||||
| 521 | DEBUG(1, "cs: resetting socket %ld\n", i)do { if (pc_debug>(1)) printk("<7>" "cs: resetting socket %ld\n" , i); } while (0); | |||
| 522 | s->socket.flags |= SS_OUTPUT_ENA0x0200 | SS_RESET0x0040; | |||
| 523 | s->ss_entry(s->sock, SS_SetSocket, &s->socket); | |||
| 524 | udelay((long)reset_time)(__builtin_constant_p((long)reset_time) ? __const_udelay(((long )reset_time) * 0x10c6ul) : __udelay((long)reset_time)); | |||
| 525 | s->socket.flags &= ~SS_RESET0x0040; | |||
| 526 | s->ss_entry(s->sock, SS_SetSocket, &s->socket); | |||
| 527 | s->setup_timeout = 0; | |||
| 528 | s->setup.function = &unreset_socket; | |||
| 529 | mod_timer(&s->setup, jiffies + unreset_delay)do { del_timer(&s->setup); (&s->setup)->expires = (jiffies + unreset_delay); add_timer(&s->setup); } while (0); | |||
| 530 | } /* reset_socket */ | |||
| 531 | ||||
| 532 | #define EVENT_MASK(0x0010|0x0080|0x0040) \ | |||
| 533 | (SOCKET_SETUP_PENDING0x0010|SOCKET_SUSPEND0x0080|SOCKET_RESET_PENDING0x0040) | |||
| 534 | ||||
| 535 | static void unreset_socket(u_long i) | |||
| 536 | { | |||
| 537 | socket_info_t *s = socket_table[i]; | |||
| 538 | int val; | |||
| 539 | ||||
| 540 | s->ss_entry(s->sock, SS_GetStatus, &val); | |||
| 541 | if (val & SS_READY0x0040) { | |||
| 542 | DEBUG(1, "cs: reset done on socket %ld\n", i)do { if (pc_debug>(1)) printk("<7>" "cs: reset done on socket %ld\n" , i); } while (0); | |||
| 543 | if (s->state & SOCKET_SUSPEND0x0080) { | |||
| 544 | s->state &= ~EVENT_MASK(0x0010|0x0080|0x0040); | |||
| 545 | if (verify_cis_cache(s) != 0) | |||
| 546 | parse_events(s, SS_DETECT0x0080); | |||
| 547 | else | |||
| 548 | send_event(s, CS_EVENT_PM_RESUME0x004000, CS_EVENT_PRI_LOW0); | |||
| 549 | } else if (s->state & SOCKET_SETUP_PENDING0x0010) { | |||
| 550 | #ifdef CONFIG_CARDBUS | |||
| 551 | if (s->state & SOCKET_CARDBUS0x8000) | |||
| 552 | cb_alloc(s); | |||
| 553 | #endif | |||
| 554 | send_event(s, CS_EVENT_CARD_INSERTION0x000004, CS_EVENT_PRI_LOW0); | |||
| 555 | s->state &= ~SOCKET_SETUP_PENDING0x0010; | |||
| 556 | } else { | |||
| 557 | send_event(s, CS_EVENT_CARD_RESET0x000400, CS_EVENT_PRI_LOW0); | |||
| 558 | if (s->reset_handle) { | |||
| 559 | s->reset_handle->event_callback_args.info = NULL((void *) 0); | |||
| 560 | EVENT(s->reset_handle, CS_EVENT_RESET_COMPLETE,((s->reset_handle)->event_handler((0x001000), (0), & (s->reset_handle)->event_callback_args)) | |||
| 561 | CS_EVENT_PRI_LOW)((s->reset_handle)->event_handler((0x001000), (0), & (s->reset_handle)->event_callback_args)); | |||
| 562 | s->state &= ~EVENT_MASK(0x0010|0x0080|0x0040); | |||
| 563 | } | |||
| 564 | } | |||
| 565 | } else { | |||
| 566 | DEBUG(2, "cs: socket %ld not ready yet\n", i)do { if (pc_debug>(2)) printk("<7>" "cs: socket %ld not ready yet\n" , i); } while (0); | |||
| 567 | if (++s->setup_timeout > unreset_limit) { | |||
| 568 | printk(KERN_NOTICE"<5>" "cs: socket %ld timed out during" | |||
| 569 | " reset\n", i); | |||
| 570 | s->state &= ~EVENT_MASK(0x0010|0x0080|0x0040); | |||
| 571 | } else { | |||
| 572 | mod_timer(&s->setup, jiffies + unreset_check)do { del_timer(&s->setup); (&s->setup)->expires = (jiffies + unreset_check); add_timer(&s->setup); } while (0); | |||
| 573 | } | |||
| 574 | } | |||
| 575 | } /* unreset_socket */ | |||
| 576 | ||||
| 577 | /*====================================================================== | |||
| 578 | ||||
| 579 | The central event handler. Send_event() sends an event to all | |||
| 580 | valid clients. Parse_events() interprets the event bits from | |||
| 581 | a card status change report. Do_shotdown() handles the high | |||
| 582 | priority stuff associated with a card removal. | |||
| 583 | ||||
| 584 | ======================================================================*/ | |||
| 585 | ||||
| 586 | static int send_event(socket_info_t *s, event_t event, int priority) | |||
| 587 | { | |||
| 588 | client_t *client = s->clients; | |||
| 589 | int ret; | |||
| 590 | DEBUG(1, "cs: send_event(sock %d, event %d, pri %d)\n",do { if (pc_debug>(1)) printk("<7>" "cs: send_event(sock %d, event %d, pri %d)\n" , s->sock, event, priority); } while (0) | |||
| 591 | s->sock, event, priority)do { if (pc_debug>(1)) printk("<7>" "cs: send_event(sock %d, event %d, pri %d)\n" , s->sock, event, priority); } while (0); | |||
| 592 | ret = 0; | |||
| 593 | for (; client; client = client->next) { | |||
| 594 | if (client->state & (CLIENT_UNBOUND0x0008|CLIENT_STALE0x0010)) | |||
| 595 | continue; | |||
| 596 | if (client->EventMask & event) { | |||
| 597 | ret = EVENT(client, event, priority)((client)->event_handler((event), (priority), &(client )->event_callback_args)); | |||
| 598 | if (ret != 0) | |||
| 599 | return ret; | |||
| 600 | } | |||
| 601 | } | |||
| 602 | return ret; | |||
| 603 | } /* send_event */ | |||
| 604 | ||||
| 605 | static void do_shutdown(socket_info_t *s) | |||
| 606 | { | |||
| 607 | client_t *client; | |||
| 608 | if (s->state & SOCKET_SHUTDOWN_PENDING0x0020) | |||
| 609 | return; | |||
| 610 | s->state |= SOCKET_SHUTDOWN_PENDING0x0020; | |||
| 611 | send_event(s, CS_EVENT_CARD_REMOVAL0x000008, CS_EVENT_PRI_HIGH1); | |||
| 612 | for (client = s->clients; client; client = client->next) | |||
| 613 | if (!(client->Attributes & INFO_MASTER_CLIENT0x01)) | |||
| 614 | client->state |= CLIENT_STALE0x0010; | |||
| 615 | if (s->state & (SOCKET_SETUP_PENDING0x0010|SOCKET_RESET_PENDING0x0040)) { | |||
| 616 | DEBUG(0, "cs: flushing pending setup\n")do { if (pc_debug>(0)) printk("<7>" "cs: flushing pending setup\n" ); } while (0); | |||
| 617 | del_timer(&s->setup); | |||
| 618 | s->state &= ~EVENT_MASK(0x0010|0x0080|0x0040); | |||
| 619 | } | |||
| 620 | mod_timer(&s->shutdown, jiffies + shutdown_delay)do { del_timer(&s->shutdown); (&s->shutdown)-> expires = (jiffies + shutdown_delay); add_timer(&s->shutdown ); } while (0); | |||
| 621 | s->state &= ~SOCKET_PRESENT0x0008; | |||
| 622 | } | |||
| 623 | ||||
| 624 | static void parse_events(void *info, u_int events) | |||
| 625 | { | |||
| 626 | socket_info_t *s = info; | |||
| 627 | if (events & SS_DETECT0x0080) { | |||
| 628 | int status; | |||
| 629 | u_long flags; | |||
| 630 | spin_lock_irqsave(&s->lock, flags)do { __asm__ __volatile__("pushf ; pop %0" : "=r" (flags): :"memory" ); __asm__ __volatile__ ("cli": : :"memory"); } while (0); | |||
| 631 | s->ss_entry(s->sock, SS_GetStatus, &status); | |||
| 632 | if ((s->state & SOCKET_PRESENT0x0008) && | |||
| 633 | (!(s->state & SOCKET_SUSPEND0x0080) || | |||
| 634 | !(status & SS_DETECT0x0080))) | |||
| 635 | do_shutdown(s); | |||
| 636 | if (status & SS_DETECT0x0080) { | |||
| 637 | if (s->state & SOCKET_SETUP_PENDING0x0010) { | |||
| 638 | del_timer(&s->setup); | |||
| 639 | DEBUG(1, "cs: delaying pending setup\n")do { if (pc_debug>(1)) printk("<7>" "cs: delaying pending setup\n" ); } while (0); | |||
| 640 | } | |||
| 641 | s->state |= SOCKET_SETUP_PENDING0x0010; | |||
| 642 | s->setup.function = &setup_socket; | |||
| 643 | s->setup_timeout = 0; | |||
| 644 | if (s->state & SOCKET_SUSPEND0x0080) | |||
| 645 | s->setup.expires = jiffies + resume_delay; | |||
| 646 | else | |||
| 647 | s->setup.expires = jiffies + setup_delay; | |||
| 648 | add_timer(&s->setup); | |||
| 649 | } | |||
| 650 | spin_unlock_irqrestore(&s->lock, flags)__asm__ __volatile__("push %0 ; popf": :"g" (flags):"memory"); | |||
| 651 | } | |||
| 652 | if (events & SS_BATDEAD0x0010) | |||
| 653 | send_event(s, CS_EVENT_BATTERY_DEAD0x000010, CS_EVENT_PRI_LOW0); | |||
| 654 | if (events & SS_BATWARN0x0020) | |||
| 655 | send_event(s, CS_EVENT_BATTERY_LOW0x000020, CS_EVENT_PRI_LOW0); | |||
| 656 | if (events & SS_READY0x0040) { | |||
| 657 | if (!(s->state & SOCKET_RESET_PENDING0x0040)) | |||
| 658 | send_event(s, CS_EVENT_READY_CHANGE0x000040, CS_EVENT_PRI_LOW0); | |||
| 659 | else DEBUG(1, "cs: ready change during reset\n")do { if (pc_debug>(1)) printk("<7>" "cs: ready change during reset\n" ); } while (0); | |||
| 660 | } | |||
| 661 | } /* parse_events */ | |||
| 662 | ||||
| 663 | /*====================================================================== | |||
| 664 | ||||
| 665 | Another event handler, for power management events. | |||
| 666 | ||||
| 667 | This does not comply with the latest PC Card spec for handling | |||
| 668 | power management events. | |||
| 669 | ||||
| 670 | ======================================================================*/ | |||
| 671 | ||||
| 672 | #ifdef CONFIG_PM | |||
| 673 | #if (LINUX_VERSION_CODE131108 < VERSION(2,3,43)(((2)<<16)+(3<<8)+43)) | |||
| 674 | static int handle_pm_event(apm_event_t rqst) | |||
| 675 | #else | |||
| 676 | static int handle_pm_event(struct pm_dev *dev, pm_request_t rqst, | |||
| 677 | void *data) | |||
| 678 | #endif | |||
| 679 | { | |||
| 680 | int i, stat; | |||
| 681 | socket_info_t *s; | |||
| 682 | static int down = 0; | |||
| 683 | ||||
| 684 | /* <linux/pm.h> hides a hack so this works with old APM support */ | |||
| 685 | switch (rqst) { | |||
| 686 | case PM_SUSPEND: | |||
| 687 | DEBUG(1, "cs: received suspend notification\n")do { if (pc_debug>(1)) printk("<7>" "cs: received suspend notification\n" ); } while (0); | |||
| 688 | if (down) { | |||
| 689 | printk(KERN_DEBUG"<7>" "cs: received extra suspend event\n"); | |||
| 690 | break; | |||
| 691 | } | |||
| 692 | down = 1; | |||
| 693 | for (i = 0; i < sockets; i++) { | |||
| 694 | s = socket_table[i]; | |||
| 695 | if ((s->state & SOCKET_PRESENT0x0008) && | |||
| 696 | !(s->state & SOCKET_SUSPEND0x0080)){ | |||
| 697 | send_event(s, CS_EVENT_PM_SUSPEND0x002000, CS_EVENT_PRI_LOW0); | |||
| 698 | s->ss_entry(s->sock, SS_SetSocket, &dead_socket); | |||
| 699 | s->state |= SOCKET_SUSPEND0x0080; | |||
| 700 | } | |||
| 701 | } | |||
| 702 | break; | |||
| 703 | case PM_RESUME: | |||
| 704 | DEBUG(1, "cs: received resume notification\n")do { if (pc_debug>(1)) printk("<7>" "cs: received resume notification\n" ); } while (0); | |||
| 705 | if (!down) { | |||
| 706 | printk(KERN_DEBUG"<7>" "cs: received bogus resume event\n"); | |||
| 707 | break; | |||
| 708 | } | |||
| 709 | down = 0; | |||
| 710 | for (i = 0; i < sockets; i++) { | |||
| 711 | s = socket_table[i]; | |||
| 712 | /* Do this just to reinitialize the socket */ | |||
| 713 | init_socket(s); | |||
| 714 | s->ss_entry(s->sock, SS_GetStatus, &stat); | |||
| 715 | /* If there was or is a card here, we need to do something | |||
| 716 | about it... but parse_events will sort it all out. */ | |||
| 717 | if ((s->state & SOCKET_PRESENT0x0008) || (stat & SS_DETECT0x0080)) | |||
| 718 | parse_events(s, SS_DETECT0x0080); | |||
| 719 | } | |||
| 720 | break; | |||
| 721 | } | |||
| 722 | return 0; | |||
| 723 | } /* handle_pm_event */ | |||
| 724 | #endif | |||
| 725 | ||||
| 726 | /*====================================================================== | |||
| 727 | ||||
| 728 | Special stuff for managing IO windows, because they are scarce. | |||
| 729 | ||||
| 730 | ======================================================================*/ | |||
| 731 | ||||
| 732 | static int alloc_io_space(socket_info_t *s, u_int attr, ioaddr_t *base, | |||
| 733 | ioaddr_t num, u_int lines, char *name) | |||
| 734 | { | |||
| 735 | int i; | |||
| 736 | ioaddr_t try, align; | |||
| 737 | ||||
| 738 | align = (*base) ? (lines ? 1<<lines : 0) : 1; | |||
| 739 | if (align && (align < num)) { | |||
| 740 | if (*base) { | |||
| 741 | DEBUG(0, "odd IO request: num %04x align %04x\n",do { if (pc_debug>(0)) printk("<7>" "odd IO request: num %04x align %04x\n" , num, align); } while (0) | |||
| 742 | num, align)do { if (pc_debug>(0)) printk("<7>" "odd IO request: num %04x align %04x\n" , num, align); } while (0); | |||
| 743 | align = 0; | |||
| 744 | } else | |||
| 745 | while (align && (align < num)) align <<= 1; | |||
| 746 | } | |||
| 747 | if (*base & ~(align-1)) { | |||
| 748 | DEBUG(0, "odd IO request: base %04x align %04x\n",do { if (pc_debug>(0)) printk("<7>" "odd IO request: base %04x align %04x\n" , *base, align); } while (0) | |||
| 749 | *base, align)do { if (pc_debug>(0)) printk("<7>" "odd IO request: base %04x align %04x\n" , *base, align); } while (0); | |||
| 750 | while (*base & ~(align-1)) align <<= 1; | |||
| 751 | } | |||
| 752 | /* Check for an already-allocated window that must conflict with | |||
| 753 | what was asked for. It is a hack because it does not catch all | |||
| 754 | potential conflicts, just the most obvious ones. */ | |||
| 755 | for (i = 0; i < MAX_IO_WIN2; i++) | |||
| 756 | if ((s->io[i].NumPorts != 0) && | |||
| 757 | ((s->io[i].BasePort & (align-1)) == *base)) | |||
| 758 | return 1; | |||
| 759 | for (i = 0; i < MAX_IO_WIN2; i++) { | |||
| 760 | if (s->io[i].NumPorts == 0) { | |||
| 761 | if (find_io_region(base, num, align, name) == 0) { | |||
| 762 | s->io[i].Attributes = attr; | |||
| 763 | s->io[i].BasePort = *base; | |||
| 764 | s->io[i].NumPorts = s->io[i].InUse = num; | |||
| 765 | break; | |||
| 766 | } else | |||
| 767 | return 1; | |||
| 768 | } else if (s->io[i].Attributes != attr) | |||
| 769 | continue; | |||
| 770 | /* Try to extend top of window */ | |||
| 771 | try = s->io[i].BasePort + s->io[i].NumPorts; | |||
| 772 | if ((*base == 0) || (*base == try)) | |||
| 773 | if (find_io_region(&try, num, 0, name) == 0) { | |||
| 774 | *base = try; | |||
| 775 | s->io[i].NumPorts += num; | |||
| 776 | s->io[i].InUse += num; | |||
| 777 | break; | |||
| 778 | } | |||
| 779 | /* Try to extend bottom of window */ | |||
| 780 | try = s->io[i].BasePort - num; | |||
| 781 | if ((*base == 0) || (*base == try)) | |||
| 782 | if (find_io_region(&try, num, 0, name) == 0) { | |||
| 783 | s->io[i].BasePort = *base = try; | |||
| 784 | s->io[i].NumPorts += num; | |||
| 785 | s->io[i].InUse += num; | |||
| 786 | break; | |||
| 787 | } | |||
| 788 | } | |||
| 789 | return (i == MAX_IO_WIN2); | |||
| 790 | } /* alloc_io_space */ | |||
| 791 | ||||
| 792 | static void release_io_space(socket_info_t *s, ioaddr_t base, | |||
| 793 | ioaddr_t num) | |||
| 794 | { | |||
| 795 | int i; | |||
| 796 | release_region(base, num); | |||
| 797 | for (i = 0; i < MAX_IO_WIN2; i++) { | |||
| 798 | if ((s->io[i].BasePort <= base) && | |||
| 799 | (s->io[i].BasePort+s->io[i].NumPorts >= base+num)) { | |||
| 800 | s->io[i].InUse -= num; | |||
| 801 | /* Free the window if no one else is using it */ | |||
| 802 | if (s->io[i].InUse == 0) | |||
| 803 | s->io[i].NumPorts = 0; | |||
| 804 | } | |||
| 805 | } | |||
| 806 | } | |||
| 807 | ||||
| 808 | /*====================================================================== | |||
| 809 | ||||
| 810 | Access_configuration_register() reads and writes configuration | |||
| 811 | registers in attribute memory. Memory window 0 is reserved for | |||
| 812 | this and the tuple reading services. | |||
| 813 | ||||
| 814 | ======================================================================*/ | |||
| 815 | ||||
| 816 | static int access_configuration_register(client_handle_t handle, | |||
| 817 | conf_reg_t *reg) | |||
| 818 | { | |||
| 819 | socket_info_t *s; | |||
| 820 | config_t *c; | |||
| 821 | int addr; | |||
| 822 | u_char val; | |||
| 823 | ||||
| 824 | if (CHECK_HANDLE(handle)(((handle) == ((void *) 0)) || ((handle)->client_magic != 0x51E6 ))) | |||
| 825 | return CS_BAD_HANDLE0x21; | |||
| 826 | s = SOCKET(handle)(socket_table[(handle)->Socket]); | |||
| 827 | if (!(s->state & SOCKET_PRESENT0x0008)) | |||
| 828 | return CS_NO_CARD0x14; | |||
| 829 | if (handle->Function == BIND_FN_ALL0xff) { | |||
| 830 | if (reg->Function >= s->functions) | |||
| 831 | return CS_BAD_ARGS0x1c; | |||
| 832 | c = &s->config[reg->Function]; | |||
| 833 | } else | |||
| 834 | c = CONFIG(handle)(&(socket_table[(handle)->Socket])->config[(handle) ->Function]); | |||
| 835 | if (!(c->state & CONFIG_LOCKED0x01)) | |||
| 836 | return CS_CONFIGURATION_LOCKED0x1d; | |||
| 837 | ||||
| 838 | addr = (c->ConfigBase + reg->Offset) >> 1; | |||
| 839 | ||||
| 840 | switch (reg->Action) { | |||
| 841 | case CS_READ1: | |||
| 842 | read_cis_mem(s, 1, addr, 1, &val); | |||
| 843 | reg->Value = val; | |||
| 844 | break; | |||
| 845 | case CS_WRITE2: | |||
| 846 | val = reg->Value; | |||
| 847 | write_cis_mem(s, 1, addr, 1, &val); | |||
| 848 | break; | |||
| 849 | default: | |||
| 850 | return CS_BAD_ARGS0x1c; | |||
| 851 | break; | |||
| 852 | } | |||
| 853 | return CS_SUCCESS0x00; | |||
| 854 | } /* access_configuration_register */ | |||
| 855 | ||||
| 856 | /*====================================================================== | |||
| 857 | ||||
| 858 | Bind_device() associates a device driver with a particular socket. | |||
| 859 | It is normally called by Driver Services after it has identified | |||
| 860 | a newly inserted card. An instance of that driver will then be | |||
| 861 | eligible to register as a client of this socket. | |||
| 862 | ||||
| 863 | ======================================================================*/ | |||
| 864 | ||||
| 865 | static int bind_device(bind_req_t *req) | |||
| 866 | { | |||
| 867 | client_t *client; | |||
| 868 | socket_info_t *s; | |||
| 869 | ||||
| 870 | if (CHECK_SOCKET(req->Socket)(((req->Socket) >= sockets) || (socket_table[req->Socket ]->ss_entry == ((void *) 0)))) | |||
| 871 | return CS_BAD_SOCKET0x0b; | |||
| 872 | s = SOCKET(req)(socket_table[(req)->Socket]); | |||
| 873 | ||||
| 874 | client = (client_t *)kmalloclinux_kmalloc(sizeof(client_t), GFP_KERNEL0x03); | |||
| 875 | if (!client) return CS_OUT_OF_RESOURCE0x20; | |||
| 876 | memset(client, '\0', sizeof(client_t))(__builtin_constant_p('\0') ? (__builtin_constant_p((sizeof(client_t ))) ? __constant_c_and_count_memset(((client)),((0x01010101UL *(unsigned char)('\0'))),((sizeof(client_t)))) : __constant_c_memset (((client)),((0x01010101UL*(unsigned char)('\0'))),((sizeof(client_t ))))) : (__builtin_constant_p((sizeof(client_t))) ? __memset_generic ((((client))),((('\0'))),(((sizeof(client_t))))) : __memset_generic (((client)),(('\0')),((sizeof(client_t)))))); | |||
| 877 | client->client_magic = CLIENT_MAGIC0x51E6; | |||
| 878 | strncpy(client->dev_info, (char *)req->dev_info, DEV_NAME_LEN32); | |||
| 879 | client->Socket = req->Socket; | |||
| 880 | client->Function = req->Function; | |||
| 881 | client->state = CLIENT_UNBOUND0x0008; | |||
| 882 | client->erase_busy.next = &client->erase_busy; | |||
| 883 | client->erase_busy.prev = &client->erase_busy; | |||
| 884 | init_waitqueue_head(&client->mtd_req)*(&client->mtd_req)=((void *) 0); | |||
| 885 | client->next = s->clients; | |||
| 886 | s->clients = client; | |||
| 887 | DEBUG(1, "cs: bind_device(): client 0x%p, sock %d, dev %s\n",do { if (pc_debug>(1)) printk("<7>" "cs: bind_device(): client 0x%p, sock %d, dev %s\n" , client, client->Socket, client->dev_info); } while (0 ) | |||
| 888 | client, client->Socket, client->dev_info)do { if (pc_debug>(1)) printk("<7>" "cs: bind_device(): client 0x%p, sock %d, dev %s\n" , client, client->Socket, client->dev_info); } while (0 ); | |||
| 889 | return CS_SUCCESS0x00; | |||
| 890 | } /* bind_device */ | |||
| 891 | ||||
| 892 | /*====================================================================== | |||
| 893 | ||||
| 894 | Bind_mtd() associates a device driver with a particular memory | |||
| 895 | region. It is normally called by Driver Services after it has | |||
| 896 | identified a memory device type. An instance of the corresponding | |||
| 897 | driver will then be able to register to control this region. | |||
| 898 | ||||
| 899 | ======================================================================*/ | |||
| 900 | ||||
| 901 | static int bind_mtd(mtd_bind_t *req) | |||
| 902 | { | |||
| 903 | socket_info_t *s; | |||
| 904 | memory_handle_t region; | |||
| 905 | ||||
| 906 | if (CHECK_SOCKET(req->Socket)(((req->Socket) >= sockets) || (socket_table[req->Socket ]->ss_entry == ((void *) 0)))) | |||
| 907 | return CS_BAD_SOCKET0x0b; | |||
| 908 | s = SOCKET(req)(socket_table[(req)->Socket]); | |||
| 909 | ||||
| 910 | if (req->Attributes & REGION_TYPE_AM0x0001) | |||
| 911 | region = s->a_region; | |||
| 912 | else | |||
| 913 | region = s->c_region; | |||
| 914 | ||||
| 915 | while (region) { | |||
| 916 | if (region->info.CardOffset == req->CardOffset) break; | |||
| 917 | region = region->info.next; | |||
| 918 | } | |||
| 919 | if (!region || (region->mtd != NULL((void *) 0))) | |||
| 920 | return CS_BAD_OFFSET0x07; | |||
| 921 | strncpy(region->dev_info, (char *)req->dev_info, DEV_NAME_LEN32); | |||
| 922 | ||||
| 923 | DEBUG(1, "cs: bind_mtd(): attr 0x%x, offset 0x%x, dev %s\n",do { if (pc_debug>(1)) printk("<7>" "cs: bind_mtd(): attr 0x%x, offset 0x%x, dev %s\n" , req->Attributes, req->CardOffset, (char *)req->dev_info ); } while (0) | |||
| 924 | req->Attributes, req->CardOffset, (char *)req->dev_info)do { if (pc_debug>(1)) printk("<7>" "cs: bind_mtd(): attr 0x%x, offset 0x%x, dev %s\n" , req->Attributes, req->CardOffset, (char *)req->dev_info ); } while (0); | |||
| 925 | return CS_SUCCESS0x00; | |||
| 926 | } /* bind_mtd */ | |||
| 927 | ||||
| 928 | /*====================================================================*/ | |||
| 929 | ||||
| 930 | static int deregister_client(client_handle_t handle) | |||
| 931 | { | |||
| 932 | client_t **client; | |||
| 933 | socket_info_t *s; | |||
| 934 | memory_handle_t region; | |||
| 935 | u_long flags; | |||
| 936 | int i, sn; | |||
| 937 | ||||
| 938 | DEBUG(1, "cs: deregister_client(%p)\n", handle)do { if (pc_debug>(1)) printk("<7>" "cs: deregister_client(%p)\n" , handle); } while (0); | |||
| 939 | if (CHECK_HANDLE(handle)(((handle) == ((void *) 0)) || ((handle)->client_magic != 0x51E6 ))) | |||
| 940 | return CS_BAD_HANDLE0x21; | |||
| 941 | if (handle->state & | |||
| 942 | (CLIENT_IRQ_REQ0x0002|CLIENT_IO_REQ0x0004|CLIENT_CONFIG_LOCKED0x0001)) | |||
| 943 | return CS_IN_USE0x1e; | |||
| 944 | for (i = 0; i < MAX_WIN4; i++) | |||
| 945 | if (handle->state & CLIENT_WIN_REQ(i)(0x20<<(i))) | |||
| 946 | return CS_IN_USE0x1e; | |||
| 947 | ||||
| 948 | /* Disconnect all MTD links */ | |||
| 949 | s = SOCKET(handle)(socket_table[(handle)->Socket]); | |||
| 950 | if (handle->mtd_count) { | |||
| 951 | for (region = s->a_region; region; region = region->info.next) | |||
| 952 | if (region->mtd == handle) region->mtd = NULL((void *) 0); | |||
| 953 | for (region = s->c_region; region; region = region->info.next) | |||
| 954 | if (region->mtd == handle) region->mtd = NULL((void *) 0); | |||
| 955 | } | |||
| 956 | ||||
| 957 | sn = handle->Socket; s = socket_table[sn]; | |||
| 958 | ||||
| 959 | if ((handle->state & CLIENT_STALE0x0010) || | |||
| 960 | (handle->Attributes & INFO_MASTER_CLIENT0x01)) { | |||
| 961 | spin_lock_irqsave(&s->lock, flags)do { __asm__ __volatile__("pushf ; pop %0" : "=r" (flags): :"memory" ); __asm__ __volatile__ ("cli": : :"memory"); } while (0); | |||
| 962 | client = &s->clients; | |||
| 963 | while ((*client) && ((*client) != handle)) | |||
| 964 | client = &(*client)->next; | |||
| 965 | if (*client == NULL((void *) 0)) { | |||
| 966 | spin_unlock_irqrestore(&s->lock, flags)__asm__ __volatile__("push %0 ; popf": :"g" (flags):"memory"); | |||
| 967 | return CS_BAD_HANDLE0x21; | |||
| 968 | } | |||
| 969 | *client = handle->next; | |||
| 970 | handle->client_magic = 0; | |||
| 971 | kfreelinux_kfree(handle); | |||
| 972 | spin_unlock_irqrestore(&s->lock, flags)__asm__ __volatile__("push %0 ; popf": :"g" (flags):"memory"); | |||
| 973 | } else { | |||
| 974 | handle->state = CLIENT_UNBOUND0x0008; | |||
| 975 | handle->mtd_count = 0; | |||
| 976 | handle->event_handler = NULL((void *) 0); | |||
| 977 | } | |||
| 978 | ||||
| 979 | if (--s->real_clients == 0) | |||
| 980 | s->ss_entry(sn, SS_RegisterCallback, NULL((void *) 0)); | |||
| 981 | ||||
| 982 | return CS_SUCCESS0x00; | |||
| 983 | } /* deregister_client */ | |||
| 984 | ||||
| 985 | /*====================================================================*/ | |||
| 986 | ||||
| 987 | static int get_configuration_info(client_handle_t handle, | |||
| 988 | config_info_t *config) | |||
| 989 | { | |||
| 990 | socket_info_t *s; | |||
| 991 | config_t *c; | |||
| 992 | ||||
| 993 | if (CHECK_HANDLE(handle)(((handle) == ((void *) 0)) || ((handle)->client_magic != 0x51E6 ))) | |||
| 994 | return CS_BAD_HANDLE0x21; | |||
| 995 | s = SOCKET(handle)(socket_table[(handle)->Socket]); | |||
| 996 | if (!(s->state & SOCKET_PRESENT0x0008)) | |||
| 997 | return CS_NO_CARD0x14; | |||
| 998 | ||||
| 999 | if (handle->Function == BIND_FN_ALL0xff) { | |||
| 1000 | if (config->Function && (config->Function >= s->functions)) | |||
| 1001 | return CS_BAD_ARGS0x1c; | |||
| 1002 | } else | |||
| 1003 | config->Function = handle->Function; | |||
| 1004 | ||||
| 1005 | #ifdef CONFIG_CARDBUS | |||
| 1006 | if (s->state & SOCKET_CARDBUS0x8000) { | |||
| 1007 | u_char fn = config->Function; | |||
| 1008 | memset(config, 0, sizeof(config_info_t))(__builtin_constant_p(0) ? (__builtin_constant_p((sizeof(config_info_t ))) ? __constant_c_and_count_memset(((config)),((0x01010101UL *(unsigned char)(0))),((sizeof(config_info_t)))) : __constant_c_memset (((config)),((0x01010101UL*(unsigned char)(0))),((sizeof(config_info_t ))))) : (__builtin_constant_p((sizeof(config_info_t))) ? __memset_generic ((((config))),(((0))),(((sizeof(config_info_t))))) : __memset_generic (((config)),((0)),((sizeof(config_info_t)))))); | |||
| 1009 | config->Function = fn; | |||
| 1010 | config->Vcc = s->socket.Vcc; | |||
| 1011 | config->Vpp1 = config->Vpp2 = s->socket.Vpp; | |||
| 1012 | config->Option = s->cap.cardbus; | |||
| 1013 | config->IntType = INT_CARDBUS0x04; | |||
| 1014 | /* This is a nasty hack */ | |||
| 1015 | pcibios_read_config_dword(s->cap.cardbus, 0, 0, &config->ConfigBase); | |||
| 1016 | if (s->cb_config) { | |||
| 1017 | config->Attributes = CONF_VALID_CLIENT0x100; | |||
| 1018 | config->AssignedIRQ = s->irq.AssignedIRQ; | |||
| 1019 | if (config->AssignedIRQ) | |||
| 1020 | config->Attributes |= CONF_ENABLE_IRQ0x01; | |||
| 1021 | config->BasePort1 = s->io[0].BasePort; | |||
| 1022 | config->NumPorts1 = s->io[0].NumPorts; | |||
| 1023 | } | |||
| 1024 | return CS_SUCCESS0x00; | |||
| 1025 | } | |||
| 1026 | #endif | |||
| 1027 | ||||
| 1028 | c = (s->config != NULL((void *) 0)) ? &s->config[config->Function] : NULL((void *) 0); | |||
| 1029 | ||||
| 1030 | if ((c == NULL((void *) 0)) || !(c->state & CONFIG_LOCKED0x01)) { | |||
| 1031 | config->Attributes = 0; | |||
| 1032 | config->Vcc = s->socket.Vcc; | |||
| 1033 | config->Vpp1 = config->Vpp2 = s->socket.Vpp; | |||
| 1034 | return CS_SUCCESS0x00; | |||
| 1035 | } | |||
| 1036 | ||||
| 1037 | /* !!! This is a hack !!! */ | |||
| 1038 | memcpy(&config->Attributes, &c->Attributes, sizeof(config_t))(__builtin_constant_p(sizeof(config_t)) ? __constant_memcpy(( &config->Attributes),(&c->Attributes),(sizeof(config_t ))) : __memcpy((&config->Attributes),(&c->Attributes ),(sizeof(config_t)))); | |||
| 1039 | config->Attributes |= CONF_VALID_CLIENT0x100; | |||
| 1040 | config->CardValues = c->CardValues; | |||
| 1041 | config->IRQAttributes = c->irq.Attributes; | |||
| 1042 | config->AssignedIRQ = s->irq.AssignedIRQ; | |||
| 1043 | config->BasePort1 = c->io.BasePort1; | |||
| 1044 | config->NumPorts1 = c->io.NumPorts1; | |||
| 1045 | config->Attributes1 = c->io.Attributes1; | |||
| 1046 | config->BasePort2 = c->io.BasePort2; | |||
| 1047 | config->NumPorts2 = c->io.NumPorts2; | |||
| 1048 | config->Attributes2 = c->io.Attributes2; | |||
| 1049 | config->IOAddrLines = c->io.IOAddrLines; | |||
| 1050 | ||||
| 1051 | return CS_SUCCESS0x00; | |||
| 1052 | } /* get_configuration_info */ | |||
| 1053 | ||||
| 1054 | /*====================================================================== | |||
| 1055 | ||||
| 1056 | Return information about this version of Card Services. | |||
| 1057 | ||||
| 1058 | ======================================================================*/ | |||
| 1059 | ||||
| 1060 | static int get_card_services_info(servinfo_t *info) | |||
| 1061 | { | |||
| 1062 | info->Signature[0] = 'C'; | |||
| 1063 | info->Signature[1] = 'S'; | |||
| 1064 | info->Count = sockets; | |||
| 1065 | info->Revision = CS_RELEASE_CODE0x3208; | |||
| 1066 | info->CSLevel = 0x0210; | |||
| 1067 | info->VendorString = (char *)release; | |||
| 1068 | return CS_SUCCESS0x00; | |||
| 1069 | } /* get_card_services_info */ | |||
| 1070 | ||||
| 1071 | /*====================================================================== | |||
| 1072 | ||||
| 1073 | Note that get_first_client() *does* recognize the Socket field | |||
| 1074 | in the request structure. | |||
| 1075 | ||||
| 1076 | ======================================================================*/ | |||
| 1077 | ||||
| 1078 | static int get_first_client(client_handle_t *handle, client_req_t *req) | |||
| 1079 | { | |||
| 1080 | socket_t s; | |||
| 1081 | if (req->Attributes & CLIENT_THIS_SOCKET0x01) | |||
| 1082 | s = req->Socket; | |||
| 1083 | else | |||
| 1084 | s = 0; | |||
| 1085 | if (CHECK_SOCKET(req->Socket)(((req->Socket) >= sockets) || (socket_table[req->Socket ]->ss_entry == ((void *) 0)))) | |||
| 1086 | return CS_BAD_SOCKET0x0b; | |||
| 1087 | if (socket_table[s]->clients == NULL((void *) 0)) | |||
| 1088 | return CS_NO_MORE_ITEMS0x1f; | |||
| 1089 | *handle = socket_table[s]->clients; | |||
| 1090 | return CS_SUCCESS0x00; | |||
| 1091 | } /* get_first_client */ | |||
| 1092 | ||||
| 1093 | /*====================================================================*/ | |||
| 1094 | ||||
| 1095 | static int get_next_client(client_handle_t *handle, client_req_t *req) | |||
| 1096 | { | |||
| 1097 | socket_info_t *s; | |||
| 1098 | if ((handle == NULL((void *) 0)) || CHECK_HANDLE(*handle)(((*handle) == ((void *) 0)) || ((*handle)->client_magic != 0x51E6))) | |||
| 1099 | return CS_BAD_HANDLE0x21; | |||
| 1100 | if ((*handle)->next == NULL((void *) 0)) { | |||
| 1101 | if (req->Attributes & CLIENT_THIS_SOCKET0x01) | |||
| 1102 | return CS_NO_MORE_ITEMS0x1f; | |||
| 1103 | s = SOCKET(*handle)(socket_table[(*handle)->Socket]); | |||
| 1104 | if (s->clients == NULL((void *) 0)) | |||
| 1105 | return CS_NO_MORE_ITEMS0x1f; | |||
| 1106 | *handle = s->clients; | |||
| 1107 | } else | |||
| 1108 | *handle = (*handle)->next; | |||
| 1109 | return CS_SUCCESS0x00; | |||
| 1110 | } /* get_next_client */ | |||
| 1111 | ||||
| 1112 | /*====================================================================*/ | |||
| 1113 | ||||
| 1114 | static int get_window(window_handle_t *handle, int idx, win_req_t *req) | |||
| 1115 | { | |||
| 1116 | socket_info_t *s; | |||
| 1117 | window_t *win; | |||
| 1118 | int w; | |||
| 1119 | ||||
| 1120 | if (idx == 0) | |||
| 1121 | s = SOCKET((client_handle_t)*handle)(socket_table[((client_handle_t)*handle)->Socket]); | |||
| 1122 | else | |||
| 1123 | s = (*handle)->sock; | |||
| 1124 | if (!(s->state & SOCKET_PRESENT0x0008)) | |||
| 1125 | return CS_NO_CARD0x14; | |||
| 1126 | for (w = idx; w < MAX_WIN4; w++) | |||
| 1127 | if (s->state & SOCKET_WIN_REQ(w)(0x0100<<(w))) break; | |||
| 1128 | if (w == MAX_WIN4) | |||
| 1129 | return CS_NO_MORE_ITEMS0x1f; | |||
| 1130 | win = &s->win[w]; | |||
| 1131 | req->Base = win->ctl.sys_start; | |||
| 1132 | req->Size = win->ctl.sys_stop - win->ctl.sys_start + 1; | |||
| 1133 | req->AccessSpeed = win->ctl.speed; | |||
| 1134 | req->Attributes = 0; | |||
| 1135 | if (win->ctl.flags & MAP_ATTRIB0x20) | |||
| 1136 | req->Attributes |= WIN_MEMORY_TYPE_AM0x0002; | |||
| 1137 | if (win->ctl.flags & MAP_ACTIVE0x01) | |||
| 1138 | req->Attributes |= WIN_ENABLE0x0004; | |||
| 1139 | if (win->ctl.flags & MAP_16BIT0x02) | |||
| 1140 | req->Attributes |= WIN_DATA_WIDTH_160x0008; | |||
| 1141 | if (win->ctl.flags & MAP_USE_WAIT0x40) | |||
| 1142 | req->Attributes |= WIN_USE_WAIT0x0100; | |||
| 1143 | *handle = win; | |||
| 1144 | return CS_SUCCESS0x00; | |||
| 1145 | } /* get_window */ | |||
| 1146 | ||||
| 1147 | static int get_first_window(client_handle_t *handle, win_req_t *req) | |||
| 1148 | { | |||
| 1149 | if ((handle == NULL((void *) 0)) || CHECK_HANDLE(*handle)(((*handle) == ((void *) 0)) || ((*handle)->client_magic != 0x51E6))) | |||
| 1150 | return CS_BAD_HANDLE0x21; | |||
| 1151 | return get_window((window_handle_t *)handle, 0, req); | |||
| 1152 | } | |||
| 1153 | ||||
| 1154 | static int get_next_window(window_handle_t *win, win_req_t *req) | |||
| 1155 | { | |||
| 1156 | if ((win == NULL((void *) 0)) || ((*win)->magic != WINDOW_MAGIC0xB35C)) | |||
| 1157 | return CS_BAD_HANDLE0x21; | |||
| 1158 | return get_window(win, (*win)->index+1, req); | |||
| 1159 | } | |||
| 1160 | ||||
| 1161 | /*====================================================================== | |||
| 1162 | ||||
| 1163 | Get the current socket state bits. We don't support the latched | |||
| 1164 | SocketState yet: I haven't seen any point for it. | |||
| 1165 | ||||
| 1166 | ======================================================================*/ | |||
| 1167 | ||||
| 1168 | static int cs_get_status(client_handle_t handle, cs_status_t *status) | |||
| 1169 | { | |||
| 1170 | socket_info_t *s; | |||
| 1171 | config_t *c; | |||
| 1172 | int val; | |||
| 1173 | ||||
| 1174 | if (CHECK_HANDLE(handle)(((handle) == ((void *) 0)) || ((handle)->client_magic != 0x51E6 ))) | |||
| 1175 | return CS_BAD_HANDLE0x21; | |||
| 1176 | s = SOCKET(handle)(socket_table[(handle)->Socket]); | |||
| 1177 | s->ss_entry(s->sock, SS_GetStatus, &val); | |||
| 1178 | status->CardState = status->SocketState = 0; | |||
| 1179 | status->CardState |= (val & SS_DETECT0x0080) ? CS_EVENT_CARD_DETECT0x000080 : 0; | |||
| 1180 | status->CardState |= (val & SS_CARDBUS0x0800) ? CS_EVENT_CB_DETECT0x100000 : 0; | |||
| 1181 | status->CardState |= (val & SS_3VCARD0x1000) ? CS_EVENT_3VCARD0x200000 : 0; | |||
| 1182 | status->CardState |= (val & SS_XVCARD0x2000) ? CS_EVENT_XVCARD0x400000 : 0; | |||
| 1183 | if (s->state & SOCKET_SUSPEND0x0080) | |||
| 1184 | status->CardState |= CS_EVENT_PM_SUSPEND0x002000; | |||
| 1185 | if (!(s->state & SOCKET_PRESENT0x0008)) | |||
| 1186 | return CS_NO_CARD0x14; | |||
| 1187 | if (s->state & SOCKET_SETUP_PENDING0x0010) | |||
| 1188 | status->CardState |= CS_EVENT_CARD_INSERTION0x000004; | |||
| 1189 | ||||
| 1190 | /* Get info from the PRR, if necessary */ | |||
| 1191 | if (handle->Function == BIND_FN_ALL0xff) { | |||
| 1192 | if (status->Function && (status->Function >= s->functions)) | |||
| 1193 | return CS_BAD_ARGS0x1c; | |||
| 1194 | c = (s->config != NULL((void *) 0)) ? &s->config[status->Function] : NULL((void *) 0); | |||
| 1195 | } else | |||
| 1196 | c = CONFIG(handle)(&(socket_table[(handle)->Socket])->config[(handle) ->Function]); | |||
| 1197 | if ((c != NULL((void *) 0)) && (c->state & CONFIG_LOCKED0x01) && | |||
| 1198 | (c->IntType & (INT_MEMORY_AND_IO0x02 | INT_ZOOMED_VIDEO0x08))) { | |||
| 1199 | u_char reg; | |||
| 1200 | if (c->Present & PRESENT_PIN_REPLACE0x004) { | |||
| 1201 | read_cis_mem(s, 1, (c->ConfigBase+CISREG_PRR0x04)>>1, 1, ®); | |||
| 1202 | status->CardState |= | |||
| 1203 | (reg & PRR_WP_STATUS0x01) ? CS_EVENT_WRITE_PROTECT0x000001 : 0; | |||
| 1204 | status->CardState |= | |||
| 1205 | (reg & PRR_READY_STATUS0x02) ? CS_EVENT_READY_CHANGE0x000040 : 0; | |||
| 1206 | status->CardState |= | |||
| 1207 | (reg & PRR_BVD2_STATUS0x04) ? CS_EVENT_BATTERY_LOW0x000020 : 0; | |||
| 1208 | status->CardState |= | |||
| 1209 | (reg & PRR_BVD1_STATUS0x08) ? CS_EVENT_BATTERY_DEAD0x000010 : 0; | |||
| 1210 | } else { | |||
| 1211 | /* No PRR? Then assume we're always ready */ | |||
| 1212 | status->CardState |= CS_EVENT_READY_CHANGE0x000040; | |||
| 1213 | } | |||
| 1214 | if (c->Present & PRESENT_EXT_STATUS0x010) { | |||
| 1215 | read_cis_mem(s, 1, (c->ConfigBase+CISREG_ESR0x08)>>1, 1, ®); | |||
| 1216 | status->CardState |= | |||
| 1217 | (reg & ESR_REQ_ATTN0x10) ? CS_EVENT_REQUEST_ATTENTION0x080000 : 0; | |||
| 1218 | } | |||
| 1219 | return CS_SUCCESS0x00; | |||
| 1220 | } | |||
| 1221 | status->CardState |= | |||
| 1222 | (val & SS_WRPROT0x0001) ? CS_EVENT_WRITE_PROTECT0x000001 : 0; | |||
| 1223 | status->CardState |= | |||
| 1224 | (val & SS_BATDEAD0x0010) ? CS_EVENT_BATTERY_DEAD0x000010 : 0; | |||
| 1225 | status->CardState |= | |||
| 1226 | (val & SS_BATWARN0x0020) ? CS_EVENT_BATTERY_LOW0x000020 : 0; | |||
| 1227 | status->CardState |= | |||
| 1228 | (val & SS_READY0x0040) ? CS_EVENT_READY_CHANGE0x000040 : 0; | |||
| 1229 | return CS_SUCCESS0x00; | |||
| 1230 | } /* cs_get_status */ | |||
| 1231 | ||||
| 1232 | /*====================================================================== | |||
| 1233 | ||||
| 1234 | Change the card address of an already open memory window. | |||
| 1235 | ||||
| 1236 | ======================================================================*/ | |||
| 1237 | ||||
| 1238 | static int get_mem_page(window_handle_t win, memreq_t *req) | |||
| 1239 | { | |||
| 1240 | if ((win == NULL((void *) 0)) || (win->magic != WINDOW_MAGIC0xB35C)) | |||
| 1241 | return CS_BAD_HANDLE0x21; | |||
| 1242 | req->Page = 0; | |||
| 1243 | req->CardOffset = win->ctl.card_start; | |||
| 1244 | return CS_SUCCESS0x00; | |||
| 1245 | } /* get_mem_page */ | |||
| 1246 | ||||
| 1247 | static int map_mem_page(window_handle_t win, memreq_t *req) | |||
| 1248 | { | |||
| 1249 | socket_info_t *s; | |||
| 1250 | if ((win == NULL((void *) 0)) || (win->magic != WINDOW_MAGIC0xB35C)) | |||
| 1251 | return CS_BAD_HANDLE0x21; | |||
| 1252 | if (req->Page != 0) | |||
| 1253 | return CS_BAD_PAGE0x08; | |||
| 1254 | s = win->sock; | |||
| 1255 | win->ctl.card_start = req->CardOffset; | |||
| 1256 | if (s->ss_entry(s->sock, SS_SetMemMap, &win->ctl) != 0) | |||
| 1257 | return CS_BAD_OFFSET0x07; | |||
| 1258 | return CS_SUCCESS0x00; | |||
| 1259 | } /* map_mem_page */ | |||
| 1260 | ||||
| 1261 | /*====================================================================== | |||
| 1262 | ||||
| 1263 | Modify a locked socket configuration | |||
| 1264 | ||||
| 1265 | ======================================================================*/ | |||
| 1266 | ||||
| 1267 | static int modify_configuration(client_handle_t handle, | |||
| 1268 | modconf_t *mod) | |||
| 1269 | { | |||
| 1270 | socket_info_t *s; | |||
| 1271 | config_t *c; | |||
| 1272 | ||||
| 1273 | if (CHECK_HANDLE(handle)(((handle) == ((void *) 0)) || ((handle)->client_magic != 0x51E6 ))) | |||
| 1274 | return CS_BAD_HANDLE0x21; | |||
| 1275 | s = SOCKET(handle)(socket_table[(handle)->Socket]); c = CONFIG(handle)(&(socket_table[(handle)->Socket])->config[(handle) ->Function]); | |||
| 1276 | if (!(s->state & SOCKET_PRESENT0x0008)) | |||
| 1277 | return CS_NO_CARD0x14; | |||
| 1278 | if (!(c->state & CONFIG_LOCKED0x01)) | |||
| 1279 | return CS_CONFIGURATION_LOCKED0x1d; | |||
| 1280 | ||||
| 1281 | if (mod->Attributes & CONF_IRQ_CHANGE_VALID0x100) { | |||
| 1282 | if (mod->Attributes & CONF_ENABLE_IRQ0x01) { | |||
| 1283 | c->Attributes |= CONF_ENABLE_IRQ0x01; | |||
| 1284 | s->socket.io_irq = s->irq.AssignedIRQ; | |||
| 1285 | } else { | |||
| 1286 | c->Attributes &= ~CONF_ENABLE_IRQ0x01; | |||
| 1287 | s->socket.io_irq = 0; | |||
| 1288 | } | |||
| 1289 | s->ss_entry(s->sock, SS_SetSocket, &s->socket); | |||
| 1290 | } | |||
| 1291 | ||||
| 1292 | if (mod->Attributes & CONF_VCC_CHANGE_VALID0x200) | |||
| 1293 | return CS_BAD_VCC0x0e; | |||
| 1294 | ||||
| 1295 | /* We only allow changing Vpp1 and Vpp2 to the same value */ | |||
| 1296 | if ((mod->Attributes & CONF_VPP1_CHANGE_VALID0x400) && | |||
| 1297 | (mod->Attributes & CONF_VPP2_CHANGE_VALID0x800)) { | |||
| 1298 | if (mod->Vpp1 != mod->Vpp2) | |||
| 1299 | return CS_BAD_VPP0x0f; | |||
| 1300 | c->Vpp1 = c->Vpp2 = s->socket.Vpp = mod->Vpp1; | |||
| 1301 | if (s->ss_entry(s->sock, SS_SetSocket, &s->socket)) | |||
| 1302 | return CS_BAD_VPP0x0f; | |||
| 1303 | } else if ((mod->Attributes & CONF_VPP1_CHANGE_VALID0x400) || | |||
| 1304 | (mod->Attributes & CONF_VPP2_CHANGE_VALID0x800)) | |||
| 1305 | return CS_BAD_VPP0x0f; | |||
| 1306 | ||||
| 1307 | return CS_SUCCESS0x00; | |||
| 1308 | } /* modify_configuration */ | |||
| 1309 | ||||
| 1310 | /*====================================================================== | |||
| 1311 | ||||
| 1312 | Modify the attributes of a window returned by RequestWindow. | |||
| 1313 | ||||
| 1314 | ======================================================================*/ | |||
| 1315 | ||||
| 1316 | static int modify_window(window_handle_t win, modwin_t *req) | |||
| 1317 | { | |||
| 1318 | if ((win == NULL((void *) 0)) || (win->magic != WINDOW_MAGIC0xB35C)) | |||
| 1319 | return CS_BAD_HANDLE0x21; | |||
| 1320 | ||||
| 1321 | win->ctl.flags &= ~(MAP_ATTRIB0x20|MAP_ACTIVE0x01); | |||
| 1322 | if (req->Attributes & WIN_MEMORY_TYPE0x0002) | |||
| 1323 | win->ctl.flags |= MAP_ATTRIB0x20; | |||
| 1324 | if (req->Attributes & WIN_ENABLE0x0004) | |||
| 1325 | win->ctl.flags |= MAP_ACTIVE0x01; | |||
| 1326 | if (req->Attributes & WIN_DATA_WIDTH_160x0008) | |||
| 1327 | win->ctl.flags |= MAP_16BIT0x02; | |||
| 1328 | if (req->Attributes & WIN_USE_WAIT0x0100) | |||
| 1329 | win->ctl.flags |= MAP_USE_WAIT0x40; | |||
| 1330 | win->ctl.speed = req->AccessSpeed; | |||
| 1331 | win->sock->ss_entry(win->sock->sock, SS_SetMemMap, &win->ctl); | |||
| 1332 | ||||
| 1333 | return CS_SUCCESS0x00; | |||
| 1334 | } /* modify_window */ | |||
| 1335 | ||||
| 1336 | /*====================================================================== | |||
| 1337 | ||||
| 1338 | Register_client() uses the dev_info_t handle to match the | |||
| 1339 | caller with a socket. The driver must have already been bound | |||
| 1340 | to a socket with bind_device() -- in fact, bind_device() | |||
| 1341 | allocates the client structure that will be used. | |||
| 1342 | ||||
| 1343 | ======================================================================*/ | |||
| 1344 | ||||
| 1345 | static int register_client(client_handle_t *handle, client_reg_t *req) | |||
| 1346 | { | |||
| 1347 | client_t *client; | |||
| 1348 | socket_info_t *s; | |||
| 1349 | socket_t ns; | |||
| 1350 | ||||
| 1351 | /* Look for unbound client with matching dev_info */ | |||
| 1352 | client = NULL((void *) 0); | |||
| 1353 | for (ns = 0; ns < sockets; ns++) { | |||
| 1354 | client = socket_table[ns]->clients; | |||
| 1355 | while (client != NULL((void *) 0)) { | |||
| 1356 | if ((strcmp(client->dev_info, (char *)req->dev_info) == 0) | |||
| 1357 | && (client->state & CLIENT_UNBOUND0x0008)) break; | |||
| 1358 | client = client->next; | |||
| 1359 | } | |||
| 1360 | if (client != NULL((void *) 0)) break; | |||
| 1361 | } | |||
| 1362 | if (client == NULL((void *) 0)) | |||
| 1363 | return CS_OUT_OF_RESOURCE0x20; | |||
| 1364 | ||||
| 1365 | s = socket_table[ns]; | |||
| 1366 | if (++s->real_clients == 1) { | |||
| 1367 | ss_callback_t call; | |||
| 1368 | int status; | |||
| 1369 | call.handler = &parse_events; | |||
| 1370 | call.info = s; | |||
| 1371 | s->ss_entry(ns, SS_RegisterCallback, &call); | |||
| 1372 | s->ss_entry(ns, SS_GetStatus, &status); | |||
| 1373 | if ((status & SS_DETECT0x0080) && | |||
| 1374 | !(s->state & SOCKET_SETUP_PENDING0x0010)) { | |||
| 1375 | s->state |= SOCKET_SETUP_PENDING0x0010; | |||
| 1376 | setup_socket(ns); | |||
| 1377 | } | |||
| 1378 | } | |||
| 1379 | ||||
| 1380 | *handle = client; | |||
| 1381 | client->state &= ~CLIENT_UNBOUND0x0008; | |||
| 1382 | client->Socket = ns; | |||
| 1383 | client->Attributes = req->Attributes; | |||
| 1384 | client->EventMask = req->EventMask; | |||
| 1385 | client->event_handler = req->event_handler; | |||
| 1386 | client->event_callback_args = req->event_callback_args; | |||
| 1387 | client->event_callback_args.client_handle = client; | |||
| 1388 | client->event_callback_args.bus = s->cap.bus; | |||
| 1389 | ||||
| 1390 | if (s->state & SOCKET_CARDBUS0x8000) | |||
| 1391 | client->state |= CLIENT_CARDBUS0x8000; | |||
| 1392 | ||||
| 1393 | if ((!(s->state & SOCKET_CARDBUS0x8000)) && (s->functions == 0) && | |||
| 1394 | (client->Function != BIND_FN_ALL0xff)) { | |||
| 1395 | cistpl_longlink_mfc_t mfc; | |||
| 1396 | if (read_tuple(client, CISTPL_LONGLINK_MFC0x06, &mfc) | |||
| 1397 | == CS_SUCCESS0x00) | |||
| 1398 | s->functions = mfc.nfn; | |||
| 1399 | else | |||
| 1400 | s->functions = 1; | |||
| 1401 | s->config = kmalloclinux_kmalloc(sizeof(config_t) * s->functions, | |||
| 1402 | GFP_KERNEL0x03); | |||
| 1403 | memset(s->config, 0, sizeof(config_t) * s->functions)(__builtin_constant_p(0) ? (__builtin_constant_p((sizeof(config_t ) * s->functions)) ? __constant_c_and_count_memset(((s-> config)),((0x01010101UL*(unsigned char)(0))),((sizeof(config_t ) * s->functions))) : __constant_c_memset(((s->config)) ,((0x01010101UL*(unsigned char)(0))),((sizeof(config_t) * s-> functions)))) : (__builtin_constant_p((sizeof(config_t) * s-> functions)) ? __memset_generic((((s->config))),(((0))),((( sizeof(config_t) * s->functions)))) : __memset_generic(((s ->config)),((0)),((sizeof(config_t) * s->functions))))); | |||
| 1404 | } | |||
| 1405 | ||||
| 1406 | DEBUG(1, "cs: register_client(): client 0x%p, sock %d, dev %s\n",do { if (pc_debug>(1)) printk("<7>" "cs: register_client(): client 0x%p, sock %d, dev %s\n" , client, client->Socket, client->dev_info); } while (0 ) | |||
| 1407 | client, client->Socket, client->dev_info)do { if (pc_debug>(1)) printk("<7>" "cs: register_client(): client 0x%p, sock %d, dev %s\n" , client, client->Socket, client->dev_info); } while (0 ); | |||
| 1408 | if (client->EventMask & CS_EVENT_REGISTRATION_COMPLETE0x000800) | |||
| 1409 | EVENT(client, CS_EVENT_REGISTRATION_COMPLETE, CS_EVENT_PRI_LOW)((client)->event_handler((0x000800), (0), &(client)-> event_callback_args)); | |||
| 1410 | if ((socket_table[ns]->state & SOCKET_PRESENT0x0008) && | |||
| 1411 | !(socket_table[ns]->state & SOCKET_SETUP_PENDING0x0010)) { | |||
| 1412 | if (client->EventMask & CS_EVENT_CARD_INSERTION0x000004) | |||
| 1413 | EVENT(client, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW)((client)->event_handler((0x000004), (0), &(client)-> event_callback_args)); | |||
| 1414 | else | |||
| 1415 | client->PendingEvents |= CS_EVENT_CARD_INSERTION0x000004; | |||
| 1416 | } | |||
| 1417 | return CS_SUCCESS0x00; | |||
| 1418 | } /* register_client */ | |||
| 1419 | ||||
| 1420 | /*====================================================================*/ | |||
| 1421 | ||||
| 1422 | static int release_configuration(client_handle_t handle, | |||
| 1423 | config_req_t *req) | |||
| 1424 | { | |||
| 1425 | socket_info_t *s; | |||
| 1426 | pccard_io_map io = { 0, 0, 0, 0, 1 }; | |||
| 1427 | int i; | |||
| 1428 | ||||
| 1429 | if (CHECK_HANDLE(handle)(((handle) == ((void *) 0)) || ((handle)->client_magic != 0x51E6 )) || | |||
| 1430 | !(handle->state & CLIENT_CONFIG_LOCKED0x0001)) | |||
| 1431 | return CS_BAD_HANDLE0x21; | |||
| 1432 | handle->state &= ~CLIENT_CONFIG_LOCKED0x0001; | |||
| 1433 | s = SOCKET(handle)(socket_table[(handle)->Socket]); | |||
| 1434 | ||||
| 1435 | #ifdef CONFIG_CARDBUS | |||
| 1436 | if (handle->state & CLIENT_CARDBUS0x8000) { | |||
| 1437 | cb_disable(s); | |||
| 1438 | s->lock_count = 0; | |||
| 1439 | return CS_SUCCESS0x00; | |||
| 1440 | } | |||
| 1441 | #endif | |||
| 1442 | ||||
| 1443 | if (!(handle->state & CLIENT_STALE0x0010)) { | |||
| 1444 | config_t *c = CONFIG(handle)(&(socket_table[(handle)->Socket])->config[(handle) ->Function]); | |||
| 1445 | if (--(s->lock_count) == 0) { | |||
| 1446 | s->socket.flags = SS_OUTPUT_ENA0x0200; | |||
| 1447 | s->socket.Vpp = 0; | |||
| 1448 | s->socket.io_irq = 0; | |||
| 1449 | s->ss_entry(s->sock, SS_SetSocket, &s->socket); | |||
| 1450 | } | |||
| 1451 | if (c->state & CONFIG_IO_REQ0x04) | |||
| 1452 | for (i = 0; i < MAX_IO_WIN2; i++) { | |||
| 1453 | if (s->io[i].NumPorts == 0) | |||
| 1454 | continue; | |||
| 1455 | s->io[i].Config--; | |||
| 1456 | if (s->io[i].Config != 0) | |||
| 1457 | continue; | |||
| 1458 | io.map = i; | |||
| 1459 | s->ss_entry(s->sock, SS_SetIOMap, &io); | |||
| 1460 | } | |||
| 1461 | c->state &= ~CONFIG_LOCKED0x01; | |||
| 1462 | } | |||
| 1463 | ||||
| 1464 | return CS_SUCCESS0x00; | |||
| 1465 | } /* release_configuration */ | |||
| 1466 | ||||
| 1467 | /*====================================================================== | |||
| 1468 | ||||
| 1469 | Release_io() releases the I/O ranges allocated by a client. This | |||
| 1470 | may be invoked some time after a card ejection has already dumped | |||
| 1471 | the actual socket configuration, so if the client is "stale", we | |||
| 1472 | don't bother checking the port ranges against the current socket | |||
| 1473 | values. | |||
| 1474 | ||||
| 1475 | ======================================================================*/ | |||
| 1476 | ||||
| 1477 | static int release_io(client_handle_t handle, io_req_t *req) | |||
| 1478 | { | |||
| 1479 | socket_info_t *s; | |||
| 1480 | ||||
| 1481 | if (CHECK_HANDLE(handle)(((handle) == ((void *) 0)) || ((handle)->client_magic != 0x51E6 )) || !(handle->state & CLIENT_IO_REQ0x0004)) | |||
| 1482 | return CS_BAD_HANDLE0x21; | |||
| 1483 | handle->state &= ~CLIENT_IO_REQ0x0004; | |||
| 1484 | s = SOCKET(handle)(socket_table[(handle)->Socket]); | |||
| 1485 | ||||
| 1486 | #ifdef CONFIG_CARDBUS | |||
| 1487 | if (handle->state & CLIENT_CARDBUS0x8000) { | |||
| 1488 | cb_release(s); | |||
| 1489 | return CS_SUCCESS0x00; | |||
| 1490 | } | |||
| 1491 | #endif | |||
| 1492 | ||||
| 1493 | if (!(handle->state & CLIENT_STALE0x0010)) { | |||
| 1494 | config_t *c = CONFIG(handle)(&(socket_table[(handle)->Socket])->config[(handle) ->Function]); | |||
| 1495 | if (c->state & CONFIG_LOCKED0x01) | |||
| 1496 | return CS_CONFIGURATION_LOCKED0x1d; | |||
| 1497 | if ((c->io.BasePort1 != req->BasePort1) || | |||
| 1498 | (c->io.NumPorts1 != req->NumPorts1) || | |||
| 1499 | (c->io.BasePort2 != req->BasePort2) || | |||
| 1500 | (c->io.NumPorts2 != req->NumPorts2)) | |||
| 1501 | return CS_BAD_ARGS0x1c; | |||
| 1502 | c->state &= ~CONFIG_IO_REQ0x04; | |||
| 1503 | } | |||
| 1504 | ||||
| 1505 | release_io_space(s, req->BasePort1, req->NumPorts1); | |||
| 1506 | if (req->NumPorts2) | |||
| 1507 | release_io_space(s, req->BasePort2, req->NumPorts2); | |||
| 1508 | ||||
| 1509 | return CS_SUCCESS0x00; | |||
| 1510 | } /* release_io */ | |||
| 1511 | ||||
| 1512 | /*====================================================================*/ | |||
| 1513 | ||||
| 1514 | static int cs_release_irq(client_handle_t handle, irq_req_t *req) | |||
| 1515 | { | |||
| 1516 | socket_info_t *s; | |||
| 1517 | if (CHECK_HANDLE(handle)(((handle) == ((void *) 0)) || ((handle)->client_magic != 0x51E6 )) || !(handle->state & CLIENT_IRQ_REQ0x0002)) | |||
| 1518 | return CS_BAD_HANDLE0x21; | |||
| 1519 | handle->state &= ~CLIENT_IRQ_REQ0x0002; | |||
| 1520 | s = SOCKET(handle)(socket_table[(handle)->Socket]); | |||
| 1521 | ||||
| 1522 | if (!(handle->state & CLIENT_STALE0x0010)) { | |||
| 1523 | config_t *c = CONFIG(handle)(&(socket_table[(handle)->Socket])->config[(handle) ->Function]); | |||
| 1524 | if (c->state & CONFIG_LOCKED0x01) | |||
| 1525 | return CS_CONFIGURATION_LOCKED0x1d; | |||
| 1526 | if (c->irq.Attributes != req->Attributes) | |||
| 1527 | return CS_BAD_ATTRIBUTE0x02; | |||
| 1528 | if (s->irq.AssignedIRQ != req->AssignedIRQ) | |||
| 1529 | return CS_BAD_IRQ0x06; | |||
| 1530 | if (--s->irq.Config == 0) { | |||
| 1531 | c->state &= ~CONFIG_IRQ_REQ0x02; | |||
| 1532 | s->irq.AssignedIRQ = 0; | |||
| 1533 | } | |||
| 1534 | } | |||
| 1535 | ||||
| 1536 | if (req->Attributes & IRQ_HANDLE_PRESENT0x10) { | |||
| 1537 | bus_free_irq(s->cap.bus, req->AssignedIRQ, req->Instance)free_irq((req->AssignedIRQ),(req->Instance)); | |||
| 1538 | } | |||
| 1539 | ||||
| 1540 | #ifdef CONFIG_ISA1 | |||
| 1541 | if (req->AssignedIRQ != s->cap.pci_irq) | |||
| 1542 | undo_irq(req->Attributes, req->AssignedIRQ); | |||
| 1543 | #endif | |||
| 1544 | ||||
| 1545 | return CS_SUCCESS0x00; | |||
| 1546 | } /* cs_release_irq */ | |||
| 1547 | ||||
| 1548 | /*====================================================================*/ | |||
| 1549 | ||||
| 1550 | static int release_window(window_handle_t win) | |||
| 1551 | { | |||
| 1552 | socket_info_t *s; | |||
| 1553 | ||||
| 1554 | if ((win == NULL((void *) 0)) || (win->magic != WINDOW_MAGIC0xB35C)) | |||
| 1555 | return CS_BAD_HANDLE0x21; | |||
| 1556 | s = win->sock; | |||
| 1557 | if (!(win->handle->state & CLIENT_WIN_REQ(win->index)(0x20<<(win->index)))) | |||
| 1558 | return CS_BAD_HANDLE0x21; | |||
| 1559 | ||||
| 1560 | /* Shut down memory window */ | |||
| 1561 | win->ctl.flags &= ~MAP_ACTIVE0x01; | |||
| 1562 | s->ss_entry(s->sock, SS_SetMemMap, &win->ctl); | |||
| 1563 | s->state &= ~SOCKET_WIN_REQ(win->index)(0x0100<<(win->index)); | |||
| 1564 | ||||
| 1565 | /* Release system memory */ | |||
| 1566 | release_mem_region(win->base, win->size); | |||
| 1567 | win->handle->state &= ~CLIENT_WIN_REQ(win->index)(0x20<<(win->index)); | |||
| 1568 | ||||
| 1569 | win->magic = 0; | |||
| 1570 | ||||
| 1571 | return CS_SUCCESS0x00; | |||
| 1572 | } /* release_window */ | |||
| 1573 | ||||
| 1574 | /*====================================================================*/ | |||
| 1575 | ||||
| 1576 | static int request_configuration(client_handle_t handle, | |||
| 1577 | config_req_t *req) | |||
| 1578 | { | |||
| 1579 | int i; | |||
| 1580 | u_int base; | |||
| 1581 | socket_info_t *s; | |||
| 1582 | config_t *c; | |||
| 1583 | pccard_io_map iomap; | |||
| 1584 | ||||
| 1585 | if (CHECK_HANDLE(handle)(((handle) == ((void *) 0)) || ((handle)->client_magic != 0x51E6 ))) | |||
| 1586 | return CS_BAD_HANDLE0x21; | |||
| 1587 | i = handle->Socket; s = socket_table[i]; | |||
| 1588 | if (!(s->state & SOCKET_PRESENT0x0008)) | |||
| 1589 | return CS_NO_CARD0x14; | |||
| 1590 | ||||
| 1591 | #ifdef CONFIG_CARDBUS | |||
| 1592 | if (handle->state & CLIENT_CARDBUS0x8000) { | |||
| 1593 | if (!(req->IntType & INT_CARDBUS0x04)) | |||
| 1594 | return CS_UNSUPPORTED_MODE0x16; | |||
| 1595 | if (s->lock_count != 0) | |||
| 1596 | return CS_CONFIGURATION_LOCKED0x1d; | |||
| 1597 | cb_enable(s); | |||
| 1598 | handle->state |= CLIENT_CONFIG_LOCKED0x0001; | |||
| 1599 | s->lock_count++; | |||
| 1600 | return CS_SUCCESS0x00; | |||
| 1601 | } | |||
| 1602 | #endif | |||
| 1603 | ||||
| 1604 | if (req->IntType & INT_CARDBUS0x04) | |||
| 1605 | return CS_UNSUPPORTED_MODE0x16; | |||
| 1606 | c = CONFIG(handle)(&(socket_table[(handle)->Socket])->config[(handle) ->Function]); | |||
| 1607 | if (c->state & CONFIG_LOCKED0x01) | |||
| 1608 | return CS_CONFIGURATION_LOCKED0x1d; | |||
| 1609 | ||||
| 1610 | /* Do power control. We don't allow changes in Vcc. */ | |||
| 1611 | if (s->socket.Vcc != req->Vcc) | |||
| 1612 | printk(KERN_DEBUG"<7>" "cs: ignoring requested Vcc\n"); | |||
| 1613 | if (req->Vpp1 != req->Vpp2) | |||
| 1614 | return CS_BAD_VPP0x0f; | |||
| 1615 | s->socket.Vpp = req->Vpp1; | |||
| 1616 | if (s->ss_entry(s->sock, SS_SetSocket, &s->socket)) | |||
| 1617 | return CS_BAD_VPP0x0f; | |||
| 1618 | ||||
| 1619 | c->Vcc = req->Vcc; c->Vpp1 = c->Vpp2 = req->Vpp1; | |||
| 1620 | ||||
| 1621 | /* Pick memory or I/O card, DMA mode, interrupt */ | |||
| 1622 | c->IntType = req->IntType; | |||
| 1623 | c->Attributes = req->Attributes; | |||
| 1624 | if (req->IntType & INT_MEMORY_AND_IO0x02) | |||
| 1625 | s->socket.flags |= SS_IOCARD0x0020; | |||
| 1626 | if (req->IntType & INT_ZOOMED_VIDEO0x08) | |||
| 1627 | s->socket.flags |= SS_ZVCARD0x0400; | |||
| 1628 | if (req->Attributes & CONF_ENABLE_DMA0x02) | |||
| 1629 | s->socket.flags |= SS_DMA_MODE0x0080; | |||
| 1630 | if (req->Attributes & CONF_ENABLE_SPKR0x04) | |||
| 1631 | s->socket.flags |= SS_SPKR_ENA0x0100; | |||
| 1632 | if (req->Attributes & CONF_ENABLE_IRQ0x01) | |||
| 1633 | s->socket.io_irq = s->irq.AssignedIRQ; | |||
| 1634 | else | |||
| 1635 | s->socket.io_irq = 0; | |||
| 1636 | s->ss_entry(s->sock, SS_SetSocket, &s->socket); | |||
| 1637 | s->lock_count++; | |||
| 1638 | ||||
| 1639 | /* Set up CIS configuration registers */ | |||
| 1640 | base = c->ConfigBase = req->ConfigBase; | |||
| 1641 | c->Present = c->CardValues = req->Present; | |||
| 1642 | if (req->Present & PRESENT_COPY0x008) { | |||
| 1643 | c->Copy = req->Copy; | |||
| 1644 | write_cis_mem(s, 1, (base + CISREG_SCR0x06)>>1, 1, &c->Copy); | |||
| 1645 | } | |||
| 1646 | if (req->Present & PRESENT_OPTION0x001) { | |||
| 1647 | if (s->functions == 1) { | |||
| 1648 | c->Option = req->ConfigIndex & COR_CONFIG_MASK0x3f; | |||
| 1649 | } else { | |||
| 1650 | c->Option = req->ConfigIndex & COR_MFC_CONFIG_MASK0x38; | |||
| 1651 | c->Option |= COR_FUNC_ENA0x01|COR_IREQ_ENA0x04; | |||
| 1652 | if (req->Present & PRESENT_IOBASE_00x020) | |||
| 1653 | c->Option |= COR_ADDR_DECODE0x02; | |||
| 1654 | } | |||
| 1655 | if (c->state & CONFIG_IRQ_REQ0x02) | |||
| 1656 | if (!(c->irq.Attributes & IRQ_FORCED_PULSE0x04)) | |||
| 1657 | c->Option |= COR_LEVEL_REQ0x40; | |||
| 1658 | write_cis_mem(s, 1, (base + CISREG_COR0x00)>>1, 1, &c->Option); | |||
| 1659 | mdelay(40)do { int i; for (i=0;i<40;i++) __udelay(1000); } while (0); | |||
| 1660 | } | |||
| 1661 | if (req->Present & PRESENT_STATUS0x002) { | |||
| 1662 | c->Status = req->Status; | |||
| 1663 | write_cis_mem(s, 1, (base + CISREG_CCSR0x02)>>1, 1, &c->Status); | |||
| 1664 | } | |||
| 1665 | if (req->Present & PRESENT_PIN_REPLACE0x004) { | |||
| 1666 | c->Pin = req->Pin; | |||
| 1667 | write_cis_mem(s, 1, (base + CISREG_PRR0x04)>>1, 1, &c->Pin); | |||
| 1668 | } | |||
| 1669 | if (req->Present & PRESENT_EXT_STATUS0x010) { | |||
| 1670 | c->ExtStatus = req->ExtStatus; | |||
| 1671 | write_cis_mem(s, 1, (base + CISREG_ESR0x08)>>1, 1, &c->ExtStatus); | |||
| 1672 | } | |||
| 1673 | if (req->Present & PRESENT_IOBASE_00x020) { | |||
| 1674 | u_char b = c->io.BasePort1 & 0xff; | |||
| 1675 | write_cis_mem(s, 1, (base + CISREG_IOBASE_00x0a)>>1, 1, &b); | |||
| 1676 | b = (c->io.BasePort1 >> 8) & 0xff; | |||
| 1677 | write_cis_mem(s, 1, (base + CISREG_IOBASE_10x0c)>>1, 1, &b); | |||
| 1678 | } | |||
| 1679 | if (req->Present & PRESENT_IOSIZE0x200) { | |||
| 1680 | u_char b = c->io.NumPorts1 + c->io.NumPorts2 - 1; | |||
| 1681 | write_cis_mem(s, 1, (base + CISREG_IOSIZE0x12)>>1, 1, &b); | |||
| 1682 | } | |||
| 1683 | ||||
| 1684 | /* Configure I/O windows */ | |||
| 1685 | if (c->state & CONFIG_IO_REQ0x04) { | |||
| 1686 | iomap.speed = io_speed; | |||
| 1687 | for (i = 0; i < MAX_IO_WIN2; i++) | |||
| 1688 | if (s->io[i].NumPorts != 0) { | |||
| 1689 | iomap.map = i; | |||
| 1690 | iomap.flags = MAP_ACTIVE0x01; | |||
| 1691 | switch (s->io[i].Attributes & IO_DATA_PATH_WIDTH0x18) { | |||
| 1692 | case IO_DATA_PATH_WIDTH_160x08: | |||
| 1693 | iomap.flags |= MAP_16BIT0x02; break; | |||
| 1694 | case IO_DATA_PATH_WIDTH_AUTO0x10: | |||
| 1695 | iomap.flags |= MAP_AUTOSZ0x04; break; | |||
| 1696 | default: | |||
| 1697 | break; | |||
| 1698 | } | |||
| 1699 | iomap.start = s->io[i].BasePort; | |||
| 1700 | iomap.stop = iomap.start + s->io[i].NumPorts - 1; | |||
| 1701 | s->ss_entry(s->sock, SS_SetIOMap, &iomap); | |||
| 1702 | s->io[i].Config++; | |||
| 1703 | } | |||
| 1704 | } | |||
| 1705 | ||||
| 1706 | c->state |= CONFIG_LOCKED0x01; | |||
| 1707 | handle->state |= CLIENT_CONFIG_LOCKED0x0001; | |||
| 1708 | return CS_SUCCESS0x00; | |||
| 1709 | } /* request_configuration */ | |||
| 1710 | ||||
| 1711 | /*====================================================================== | |||
| 1712 | ||||
| 1713 | Request_io() reserves ranges of port addresses for a socket. | |||
| 1714 | I have not implemented range sharing or alias addressing. | |||
| 1715 | ||||
| 1716 | ======================================================================*/ | |||
| 1717 | ||||
| 1718 | static int request_io(client_handle_t handle, io_req_t *req) | |||
| 1719 | { | |||
| 1720 | socket_info_t *s; | |||
| 1721 | config_t *c; | |||
| 1722 | ||||
| 1723 | if (CHECK_HANDLE(handle)(((handle) == ((void *) 0)) || ((handle)->client_magic != 0x51E6 ))) | |||
| 1724 | return CS_BAD_HANDLE0x21; | |||
| 1725 | s = SOCKET(handle)(socket_table[(handle)->Socket]); | |||
| 1726 | if (!(s->state & SOCKET_PRESENT0x0008)) | |||
| 1727 | return CS_NO_CARD0x14; | |||
| 1728 | ||||
| 1729 | if (handle->state & CLIENT_CARDBUS0x8000) { | |||
| 1730 | #ifdef CONFIG_CARDBUS | |||
| 1731 | int ret = cb_config(s); | |||
| 1732 | if (ret == CS_SUCCESS0x00) | |||
| 1733 | handle->state |= CLIENT_IO_REQ0x0004; | |||
| 1734 | return ret; | |||
| 1735 | #else | |||
| 1736 | return CS_UNSUPPORTED_FUNCTION0x15; | |||
| 1737 | #endif | |||
| 1738 | } | |||
| 1739 | ||||
| 1740 | if (!req) | |||
| 1741 | return CS_UNSUPPORTED_MODE0x16; | |||
| 1742 | c = CONFIG(handle)(&(socket_table[(handle)->Socket])->config[(handle) ->Function]); | |||
| 1743 | if (c->state & CONFIG_LOCKED0x01) | |||
| 1744 | return CS_CONFIGURATION_LOCKED0x1d; | |||
| 1745 | if (c->state & CONFIG_IO_REQ0x04) | |||
| 1746 | return CS_IN_USE0x1e; | |||
| 1747 | if (req->Attributes1 & (IO_SHARED0x01 | IO_FORCE_ALIAS_ACCESS0x04)) | |||
| 1748 | return CS_BAD_ATTRIBUTE0x02; | |||
| 1749 | if ((req->NumPorts2 > 0) && | |||
| 1750 | (req->Attributes2 & (IO_SHARED0x01 | IO_FORCE_ALIAS_ACCESS0x04))) | |||
| 1751 | return CS_BAD_ATTRIBUTE0x02; | |||
| 1752 | ||||
| 1753 | if (alloc_io_space(s, req->Attributes1, &req->BasePort1, | |||
| 1754 | req->NumPorts1, req->IOAddrLines, | |||
| 1755 | handle->dev_info)) | |||
| 1756 | return CS_IN_USE0x1e; | |||
| 1757 | ||||
| 1758 | if (req->NumPorts2) { | |||
| 1759 | if (alloc_io_space(s, req->Attributes2, &req->BasePort2, | |||
| 1760 | req->NumPorts2, req->IOAddrLines, | |||
| 1761 | handle->dev_info)) { | |||
| 1762 | release_io_space(s, req->BasePort1, req->NumPorts1); | |||
| 1763 | return CS_IN_USE0x1e; | |||
| 1764 | } | |||
| 1765 | } | |||
| 1766 | ||||
| 1767 | c->io = *req; | |||
| 1768 | c->state |= CONFIG_IO_REQ0x04; | |||
| 1769 | handle->state |= CLIENT_IO_REQ0x0004; | |||
| 1770 | return CS_SUCCESS0x00; | |||
| 1771 | } /* request_io */ | |||
| 1772 | ||||
| 1773 | /*====================================================================== | |||
| 1774 | ||||
| 1775 | Request_irq() reserves an irq for this client. | |||
| 1776 | ||||
| 1777 | Also, since Linux only reserves irq's when they are actually | |||
| 1778 | hooked, we don't guarantee that an irq will still be available | |||
| 1779 | when the configuration is locked. Now that I think about it, | |||
| 1780 | there might be a way to fix this using a dummy handler. | |||
| 1781 | ||||
| 1782 | ======================================================================*/ | |||
| 1783 | ||||
| 1784 | static int cs_request_irq(client_handle_t handle, irq_req_t *req) | |||
| 1785 | { | |||
| 1786 | socket_info_t *s; | |||
| 1787 | config_t *c; | |||
| 1788 | int ret = CS_IN_USE0x1e, irq = 0; | |||
| 1789 | ||||
| 1790 | if (CHECK_HANDLE(handle)(((handle) == ((void *) 0)) || ((handle)->client_magic != 0x51E6 ))) | |||
| 1791 | return CS_BAD_HANDLE0x21; | |||
| 1792 | s = SOCKET(handle)(socket_table[(handle)->Socket]); | |||
| 1793 | if (!(s->state & SOCKET_PRESENT0x0008)) | |||
| 1794 | return CS_NO_CARD0x14; | |||
| 1795 | c = CONFIG(handle)(&(socket_table[(handle)->Socket])->config[(handle) ->Function]); | |||
| 1796 | if (c->state & CONFIG_LOCKED0x01) | |||
| 1797 | return CS_CONFIGURATION_LOCKED0x1d; | |||
| 1798 | if (c->state & CONFIG_IRQ_REQ0x02) | |||
| 1799 | return CS_IN_USE0x1e; | |||
| 1800 | ||||
| 1801 | #ifdef CONFIG_ISA1 | |||
| 1802 | if (s->irq.AssignedIRQ != 0) { | |||
| 1803 | /* If the interrupt is already assigned, it must match */ | |||
| 1804 | irq = s->irq.AssignedIRQ; | |||
| 1805 | if (req->IRQInfo1 & IRQ_INFO2_VALID0x10) { | |||
| 1806 | u_int mask = req->IRQInfo2 & s->cap.irq_mask; | |||
| 1807 | ret = ((mask >> irq) & 1) ? 0 : CS_BAD_ARGS0x1c; | |||
| 1808 | } else | |||
| 1809 | ret = ((req->IRQInfo1&IRQ_MASK0x0f) == irq) ? 0 : CS_BAD_ARGS0x1c; | |||
| 1810 | } else { | |||
| 1811 | if (req->IRQInfo1 & IRQ_INFO2_VALID0x10) { | |||
| 1812 | u_int try, mask = req->IRQInfo2 & s->cap.irq_mask; | |||
| 1813 | for (try = 0; try < 2; try++) { | |||
| 1814 | for (irq = 0; irq < 16; irq++) | |||
| 1815 | if ((mask >> irq) & 1) { | |||
| 1816 | ret = try_irq(req->Attributes, irq, try); | |||
| 1817 | if (ret == 0) break; | |||
| 1818 | } | |||
| 1819 | if (ret == 0) break; | |||
| 1820 | } | |||
| 1821 | } else { | |||
| 1822 | irq = req->IRQInfo1 & IRQ_MASK0x0f; | |||
| 1823 | ret = try_irq(req->Attributes, irq, 1); | |||
| 1824 | } | |||
| 1825 | } | |||
| 1826 | #endif | |||
| 1827 | if (ret != 0) { | |||
| 1828 | if (!s->cap.pci_irq) | |||
| 1829 | return ret; | |||
| 1830 | irq = s->cap.pci_irq; | |||
| 1831 | } | |||
| 1832 | ||||
| 1833 | if (req->Attributes & IRQ_HANDLE_PRESENT0x10) { | |||
| 1834 | if (bus_request_irq(s->cap.bus, irq, req->Handler,request_irq((irq),(req->Handler),(((req->Attributes & 0x02) || (s->functions > 1) || (irq == s->cap.pci_irq )) ? 0x04000000 : 0),(handle->dev_info),(req->Instance) ) | |||
| 1835 | ((req->Attributes & IRQ_TYPE_DYNAMIC_SHARING) ||request_irq((irq),(req->Handler),(((req->Attributes & 0x02) || (s->functions > 1) || (irq == s->cap.pci_irq )) ? 0x04000000 : 0),(handle->dev_info),(req->Instance) ) | |||
| 1836 | (s->functions > 1) ||request_irq((irq),(req->Handler),(((req->Attributes & 0x02) || (s->functions > 1) || (irq == s->cap.pci_irq )) ? 0x04000000 : 0),(handle->dev_info),(req->Instance) ) | |||
| 1837 | (irq == s->cap.pci_irq)) ? SA_SHIRQ : 0,request_irq((irq),(req->Handler),(((req->Attributes & 0x02) || (s->functions > 1) || (irq == s->cap.pci_irq )) ? 0x04000000 : 0),(handle->dev_info),(req->Instance) ) | |||
| 1838 | handle->dev_info, req->Instance)request_irq((irq),(req->Handler),(((req->Attributes & 0x02) || (s->functions > 1) || (irq == s->cap.pci_irq )) ? 0x04000000 : 0),(handle->dev_info),(req->Instance) )) | |||
| 1839 | return CS_IN_USE0x1e; | |||
| 1840 | } | |||
| 1841 | ||||
| 1842 | c->irq.Attributes = req->Attributes; | |||
| 1843 | s->irq.AssignedIRQ = req->AssignedIRQ = irq; | |||
| 1844 | s->irq.Config++; | |||
| 1845 | ||||
| 1846 | c->state |= CONFIG_IRQ_REQ0x02; | |||
| 1847 | handle->state |= CLIENT_IRQ_REQ0x0002; | |||
| 1848 | return CS_SUCCESS0x00; | |||
| 1849 | } /* cs_request_irq */ | |||
| 1850 | ||||
| 1851 | /*====================================================================== | |||
| 1852 | ||||
| 1853 | Request_window() establishes a mapping between card memory space | |||
| 1854 | and system memory space. | |||
| 1855 | ||||
| 1856 | ======================================================================*/ | |||
| 1857 | ||||
| 1858 | static int request_window(client_handle_t *handle, win_req_t *req) | |||
| 1859 | { | |||
| 1860 | socket_info_t *s; | |||
| 1861 | window_t *win; | |||
| 1862 | u_long align; | |||
| 1863 | int w; | |||
| 1864 | ||||
| 1865 | if (CHECK_HANDLE(*handle)(((*handle) == ((void *) 0)) || ((*handle)->client_magic != 0x51E6))) | |||
| 1866 | return CS_BAD_HANDLE0x21; | |||
| 1867 | s = SOCKET(*handle)(socket_table[(*handle)->Socket]); | |||
| 1868 | if (!(s->state & SOCKET_PRESENT0x0008)) | |||
| 1869 | return CS_NO_CARD0x14; | |||
| 1870 | if (req->Attributes & (WIN_PAGED0x0020 | WIN_SHARED0x0040)) | |||
| 1871 | return CS_BAD_ATTRIBUTE0x02; | |||
| 1872 | ||||
| 1873 | /* Window size defaults to smallest available */ | |||
| 1874 | if (req->Size == 0) | |||
| 1875 | req->Size = s->cap.map_size; | |||
| 1876 | align = (((s->cap.features & SS_CAP_MEM_ALIGN0x0004) || | |||
| 1877 | (req->Attributes & WIN_STRICT_ALIGN0x0200)) ? | |||
| 1878 | req->Size : s->cap.map_size); | |||
| 1879 | if (req->Size & (s->cap.map_size-1)) | |||
| 1880 | return CS_BAD_SIZE0x0a; | |||
| 1881 | if ((req->Base && (s->cap.features & SS_CAP_STATIC_MAP0x0008)) || | |||
| 1882 | (req->Base & (align-1))) | |||
| 1883 | return CS_BAD_BASE0x03; | |||
| 1884 | if (req->Base) | |||
| 1885 | align = 0; | |||
| 1886 | ||||
| 1887 | /* Allocate system memory window */ | |||
| 1888 | for (w = 0; w < MAX_WIN4; w++) | |||
| 1889 | if (!(s->state & SOCKET_WIN_REQ(w)(0x0100<<(w)))) break; | |||
| 1890 | if (w == MAX_WIN4) | |||
| 1891 | return CS_OUT_OF_RESOURCE0x20; | |||
| 1892 | ||||
| 1893 | win = &s->win[w]; | |||
| 1894 | win->magic = WINDOW_MAGIC0xB35C; | |||
| 1895 | win->index = w; | |||
| 1896 | win->handle = *handle; | |||
| 1897 | win->sock = s; | |||
| 1898 | win->base = req->Base; | |||
| 1899 | win->size = req->Size; | |||
| 1900 | ||||
| 1901 | if (!(s->cap.features & SS_CAP_STATIC_MAP0x0008) && | |||
| 1902 | find_mem_region(&win->base, win->size, align, | |||
| 1903 | (req->Attributes & WIN_MAP_BELOW_1MB0x0400) || | |||
| 1904 | !(s->cap.features & SS_CAP_PAGE_REGS0x0001), | |||
| 1905 | (*handle)->dev_info)) | |||
| 1906 | return CS_IN_USE0x1e; | |||
| 1907 | (*handle)->state |= CLIENT_WIN_REQ(w)(0x20<<(w)); | |||
| 1908 | ||||
| 1909 | /* Configure the socket controller */ | |||
| 1910 | win->ctl.map = w+1; | |||
| 1911 | win->ctl.flags = 0; | |||
| 1912 | win->ctl.speed = req->AccessSpeed; | |||
| 1913 | if (req->Attributes & WIN_MEMORY_TYPE0x0002) | |||
| 1914 | win->ctl.flags |= MAP_ATTRIB0x20; | |||
| 1915 | if (req->Attributes & WIN_ENABLE0x0004) | |||
| 1916 | win->ctl.flags |= MAP_ACTIVE0x01; | |||
| 1917 | if (req->Attributes & WIN_DATA_WIDTH_160x0008) | |||
| 1918 | win->ctl.flags |= MAP_16BIT0x02; | |||
| 1919 | if (req->Attributes & WIN_USE_WAIT0x0100) | |||
| 1920 | win->ctl.flags |= MAP_USE_WAIT0x40; | |||
| 1921 | win->ctl.sys_start = win->base; | |||
| 1922 | win->ctl.sys_stop = win->base + win->size-1; | |||
| 1923 | win->ctl.card_start = 0; | |||
| 1924 | if (s->ss_entry(s->sock, SS_SetMemMap, &win->ctl) != 0) | |||
| 1925 | return CS_BAD_ARGS0x1c; | |||
| 1926 | s->state |= SOCKET_WIN_REQ(w)(0x0100<<(w)); | |||
| 1927 | ||||
| 1928 | /* Return window handle */ | |||
| 1929 | req->Base = win->ctl.sys_start; | |||
| 1930 | *handle = (client_handle_t)win; | |||
| 1931 | ||||
| 1932 | return CS_SUCCESS0x00; | |||
| 1933 | } /* request_window */ | |||
| 1934 | ||||
| 1935 | /*====================================================================== | |||
| 1936 | ||||
| 1937 | I'm not sure which "reset" function this is supposed to use, | |||
| 1938 | but for now, it uses the low-level interface's reset, not the | |||
| 1939 | CIS register. | |||
| 1940 | ||||
| 1941 | ======================================================================*/ | |||
| 1942 | ||||
| 1943 | static int reset_card(client_handle_t handle, client_req_t *req) | |||
| 1944 | { | |||
| 1945 | int i, ret; | |||
| 1946 | socket_info_t *s; | |||
| 1947 | ||||
| 1948 | if (CHECK_HANDLE(handle)(((handle) == ((void *) 0)) || ((handle)->client_magic != 0x51E6 ))) | |||
| 1949 | return CS_BAD_HANDLE0x21; | |||
| 1950 | i = handle->Socket; s = socket_table[i]; | |||
| 1951 | if (!(s->state & SOCKET_PRESENT0x0008)) | |||
| 1952 | return CS_NO_CARD0x14; | |||
| 1953 | if (s->state & SOCKET_RESET_PENDING0x0040) | |||
| 1954 | return CS_IN_USE0x1e; | |||
| 1955 | s->state |= SOCKET_RESET_PENDING0x0040; | |||
| 1956 | ||||
| 1957 | ret = send_event(s, CS_EVENT_RESET_REQUEST0x000100, CS_EVENT_PRI_LOW0); | |||
| 1958 | if (ret != 0) { | |||
| 1959 | s->state &= ~SOCKET_RESET_PENDING0x0040; | |||
| 1960 | handle->event_callback_args.info = (void *)(u_long)ret; | |||
| 1961 | EVENT(handle, CS_EVENT_RESET_COMPLETE, CS_EVENT_PRI_LOW)((handle)->event_handler((0x001000), (0), &(handle)-> event_callback_args)); | |||
| 1962 | } else { | |||
| 1963 | DEBUG(1, "cs: resetting socket %d\n", i)do { if (pc_debug>(1)) printk("<7>" "cs: resetting socket %d\n" , i); } while (0); | |||
| 1964 | send_event(s, CS_EVENT_RESET_PHYSICAL0x000200, CS_EVENT_PRI_LOW0); | |||
| 1965 | s->reset_handle = handle; | |||
| 1966 | reset_socket(i); | |||
| 1967 | } | |||
| 1968 | return CS_SUCCESS0x00; | |||
| 1969 | } /* reset_card */ | |||
| 1970 | ||||
| 1971 | /*====================================================================== | |||
| 1972 | ||||
| 1973 | These shut down or wake up a socket. They are sort of user | |||
| 1974 | initiated versions of the APM suspend and resume actions. | |||
| 1975 | ||||
| 1976 | ======================================================================*/ | |||
| 1977 | ||||
| 1978 | static int suspend_card(client_handle_t handle, client_req_t *req) | |||
| 1979 | { | |||
| 1980 | int i; | |||
| 1981 | socket_info_t *s; | |||
| 1982 | ||||
| 1983 | if (CHECK_HANDLE(handle)(((handle) == ((void *) 0)) || ((handle)->client_magic != 0x51E6 ))) | |||
| 1984 | return CS_BAD_HANDLE0x21; | |||
| 1985 | i = handle->Socket; s = socket_table[i]; | |||
| 1986 | if (!(s->state & SOCKET_PRESENT0x0008)) | |||
| 1987 | return CS_NO_CARD0x14; | |||
| 1988 | if (s->state & SOCKET_SUSPEND0x0080) | |||
| 1989 | return CS_IN_USE0x1e; | |||
| 1990 | ||||
| 1991 | DEBUG(1, "cs: suspending socket %d\n", i)do { if (pc_debug>(1)) printk("<7>" "cs: suspending socket %d\n" , i); } while (0); | |||
| 1992 | send_event(s, CS_EVENT_PM_SUSPEND0x002000, CS_EVENT_PRI_LOW0); | |||
| 1993 | s->ss_entry(s->sock, SS_SetSocket, &dead_socket); | |||
| 1994 | s->state |= SOCKET_SUSPEND0x0080; | |||
| 1995 | ||||
| 1996 | return CS_SUCCESS0x00; | |||
| 1997 | } /* suspend_card */ | |||
| 1998 | ||||
| 1999 | static int resume_card(client_handle_t handle, client_req_t *req) | |||
| 2000 | { | |||
| 2001 | int i; | |||
| 2002 | socket_info_t *s; | |||
| 2003 | ||||
| 2004 | if (CHECK_HANDLE(handle)(((handle) == ((void *) 0)) || ((handle)->client_magic != 0x51E6 ))) | |||
| 2005 | return CS_BAD_HANDLE0x21; | |||
| 2006 | i = handle->Socket; s = socket_table[i]; | |||
| 2007 | if (!(s->state & SOCKET_PRESENT0x0008)) | |||
| 2008 | return CS_NO_CARD0x14; | |||
| 2009 | if (!(s->state & SOCKET_SUSPEND0x0080)) | |||
| 2010 | return CS_IN_USE0x1e; | |||
| 2011 | ||||
| 2012 | DEBUG(1, "cs: waking up socket %d\n", i)do { if (pc_debug>(1)) printk("<7>" "cs: waking up socket %d\n" , i); } while (0); | |||
| 2013 | setup_socket(i); | |||
| 2014 | ||||
| 2015 | return CS_SUCCESS0x00; | |||
| 2016 | } /* resume_card */ | |||
| 2017 | ||||
| 2018 | /*====================================================================== | |||
| 2019 | ||||
| 2020 | These handle user requests to eject or insert a card. | |||
| 2021 | ||||
| 2022 | ======================================================================*/ | |||
| 2023 | ||||
| 2024 | static int eject_card(client_handle_t handle, client_req_t *req) | |||
| 2025 | { | |||
| 2026 | int i, ret; | |||
| 2027 | socket_info_t *s; | |||
| 2028 | u_long flags; | |||
| 2029 | ||||
| 2030 | if (CHECK_HANDLE(handle)(((handle) == ((void *) 0)) || ((handle)->client_magic != 0x51E6 ))) | |||
| 2031 | return CS_BAD_HANDLE0x21; | |||
| 2032 | i = handle->Socket; s = socket_table[i]; | |||
| 2033 | if (!(s->state & SOCKET_PRESENT0x0008)) | |||
| 2034 | return CS_NO_CARD0x14; | |||
| 2035 | ||||
| 2036 | DEBUG(1, "cs: user eject request on socket %d\n", i)do { if (pc_debug>(1)) printk("<7>" "cs: user eject request on socket %d\n" , i); } while (0); | |||
| 2037 | ||||
| 2038 | ret = send_event(s, CS_EVENT_EJECTION_REQUEST0x010000, CS_EVENT_PRI_LOW0); | |||
| 2039 | if (ret != 0) | |||
| 2040 | return ret; | |||
| 2041 | ||||
| 2042 | spin_lock_irqsave(&s->lock, flags)do { __asm__ __volatile__("pushf ; pop %0" : "=r" (flags): :"memory" ); __asm__ __volatile__ ("cli": : :"memory"); } while (0); | |||
| 2043 | do_shutdown(s); | |||
| 2044 | spin_unlock_irqrestore(&s->lock, flags)__asm__ __volatile__("push %0 ; popf": :"g" (flags):"memory"); | |||
| 2045 | ||||
| 2046 | return CS_SUCCESS0x00; | |||
| 2047 | ||||
| 2048 | } /* eject_card */ | |||
| 2049 | ||||
| 2050 | static int insert_card(client_handle_t handle, client_req_t *req) | |||
| 2051 | { | |||
| 2052 | int i, status; | |||
| 2053 | socket_info_t *s; | |||
| 2054 | u_long flags; | |||
| 2055 | ||||
| 2056 | if (CHECK_HANDLE(handle)(((handle) == ((void *) 0)) || ((handle)->client_magic != 0x51E6 ))) | |||
| 2057 | return CS_BAD_HANDLE0x21; | |||
| 2058 | i = handle->Socket; s = socket_table[i]; | |||
| 2059 | if (s->state & SOCKET_PRESENT0x0008) | |||
| 2060 | return CS_IN_USE0x1e; | |||
| 2061 | ||||
| 2062 | DEBUG(1, "cs: user insert request on socket %d\n", i)do { if (pc_debug>(1)) printk("<7>" "cs: user insert request on socket %d\n" , i); } while (0); | |||
| 2063 | ||||
| 2064 | spin_lock_irqsave(&s->lock, flags)do { __asm__ __volatile__("pushf ; pop %0" : "=r" (flags): :"memory" ); __asm__ __volatile__ ("cli": : :"memory"); } while (0); | |||
| 2065 | if (!(s->state & SOCKET_SETUP_PENDING0x0010)) { | |||
| 2066 | s->state |= SOCKET_SETUP_PENDING0x0010; | |||
| 2067 | spin_unlock_irqrestore(&s->lock, flags)__asm__ __volatile__("push %0 ; popf": :"g" (flags):"memory"); | |||
| 2068 | s->ss_entry(i, SS_GetStatus, &status); | |||
| 2069 | if (status & SS_DETECT0x0080) | |||
| 2070 | setup_socket(i); | |||
| 2071 | else { | |||
| 2072 | s->state &= ~SOCKET_SETUP_PENDING0x0010; | |||
| 2073 | return CS_NO_CARD0x14; | |||
| 2074 | } | |||
| 2075 | } else | |||
| 2076 | spin_unlock_irqrestore(&s->lock, flags)__asm__ __volatile__("push %0 ; popf": :"g" (flags):"memory"); | |||
| 2077 | ||||
| 2078 | return CS_SUCCESS0x00; | |||
| 2079 | } /* insert_card */ | |||
| 2080 | ||||
| 2081 | /*====================================================================== | |||
| 2082 | ||||
| 2083 | Maybe this should send a CS_EVENT_CARD_INSERTION event if we | |||
| 2084 | haven't sent one to this client yet? | |||
| 2085 | ||||
| 2086 | ======================================================================*/ | |||
| 2087 | ||||
| 2088 | static int set_event_mask(client_handle_t handle, eventmask_t *mask) | |||
| 2089 | { | |||
| 2090 | u_int events, bit; | |||
| 2091 | if (CHECK_HANDLE(handle)(((handle) == ((void *) 0)) || ((handle)->client_magic != 0x51E6 ))) | |||
| 2092 | return CS_BAD_HANDLE0x21; | |||
| 2093 | if (handle->Attributes & CONF_EVENT_MASK_VALID0x01) | |||
| 2094 | return CS_BAD_SOCKET0x0b; | |||
| 2095 | handle->EventMask = mask->EventMask; | |||
| 2096 | events = handle->PendingEvents & handle->EventMask; | |||
| 2097 | handle->PendingEvents -= events; | |||
| 2098 | while (events != 0) { | |||
| 2099 | bit = ((events ^ (events-1)) + 1) >> 1; | |||
| 2100 | EVENT(handle, bit, CS_EVENT_PRI_LOW)((handle)->event_handler((bit), (0), &(handle)->event_callback_args )); | |||
| 2101 | events -= bit; | |||
| 2102 | } | |||
| 2103 | return CS_SUCCESS0x00; | |||
| 2104 | } /* set_event_mask */ | |||
| 2105 | ||||
| 2106 | /*====================================================================*/ | |||
| 2107 | ||||
| 2108 | static int report_error(client_handle_t handle, error_info_t *err) | |||
| 2109 | { | |||
| 2110 | int i; | |||
| 2111 | char *serv; | |||
| 2112 | ||||
| 2113 | if (CHECK_HANDLE(handle)(((handle) == ((void *) 0)) || ((handle)->client_magic != 0x51E6 ))) | |||
| 2114 | printk(KERN_NOTICE"<5>"); | |||
| 2115 | else | |||
| 2116 | printk(KERN_NOTICE"<5>" "%s: ", handle->dev_info); | |||
| 2117 | ||||
| 2118 | for (i = 0; i < SERVICE_COUNT(sizeof(service_table)/sizeof(lookup_t)); i++) | |||
| 2119 | if (service_table[i].key == err->func) break; | |||
| 2120 | if (i < SERVICE_COUNT(sizeof(service_table)/sizeof(lookup_t))) | |||
| 2121 | serv = service_table[i].msg; | |||
| 2122 | else | |||
| 2123 | serv = "Unknown service number"; | |||
| 2124 | ||||
| 2125 | for (i = 0; i < ERROR_COUNT(sizeof(error_table)/sizeof(lookup_t)); i++) | |||
| 2126 | if (error_table[i].key == err->retcode) break; | |||
| 2127 | if (i < ERROR_COUNT(sizeof(error_table)/sizeof(lookup_t))) | |||
| 2128 | printk("%s: %s\n", serv, error_table[i].msg); | |||
| 2129 | else | |||
| 2130 | printk("%s: Unknown error code %#x\n", serv, err->retcode); | |||
| 2131 | ||||
| 2132 | return CS_SUCCESS0x00; | |||
| 2133 | } /* report_error */ | |||
| 2134 | ||||
| 2135 | /*====================================================================*/ | |||
| 2136 | ||||
| 2137 | int CardServices(int func, void *a1, void *a2, void *a3) | |||
| 2138 | { | |||
| 2139 | ||||
| 2140 | #ifdef PCMCIA_DEBUG4 | |||
| 2141 | if (pc_debug > 2) { | |||
| 2142 | int i; | |||
| 2143 | for (i = 0; i < SERVICE_COUNT(sizeof(service_table)/sizeof(lookup_t)); i++) | |||
| 2144 | if (service_table[i].key == func) break; | |||
| 2145 | if (i < SERVICE_COUNT(sizeof(service_table)/sizeof(lookup_t))) | |||
| 2146 | printk(KERN_DEBUG"<7>" "cs: CardServices(%s, 0x%p, 0x%p)\n", | |||
| 2147 | service_table[i].msg, a1, a2); | |||
| 2148 | else | |||
| 2149 | printk(KERN_DEBUG"<7>" "cs: CardServices(Unknown func %d, " | |||
| 2150 | "0x%p, 0x%p)\n", func, a1, a2); | |||
| 2151 | } | |||
| 2152 | #endif | |||
| 2153 | switch (func) { | |||
| 2154 | case AccessConfigurationRegister: | |||
| 2155 | return access_configuration_register(a1, a2); break; | |||
| 2156 | case AdjustResourceInfo: | |||
| 2157 | return adjust_resource_info(a1, a2); break; | |||
| 2158 | case CheckEraseQueue: | |||
| 2159 | return check_erase_queue(a1); break; | |||
| 2160 | case CloseMemory: | |||
| 2161 | return close_memory(a1); break; | |||
| 2162 | case CopyMemory: | |||
| 2163 | return copy_memory(a1, a2); break; | |||
| 2164 | case DeregisterClient: | |||
| 2165 | return deregister_client(a1); break; | |||
| 2166 | case DeregisterEraseQueue: | |||
| 2167 | return deregister_erase_queue(a1); break; | |||
| 2168 | case GetFirstClient: | |||
| 2169 | return get_first_client(a1, a2); break; | |||
| 2170 | case GetCardServicesInfo: | |||
| 2171 | return get_card_services_info(a1); break; | |||
| 2172 | case GetConfigurationInfo: | |||
| 2173 | return get_configuration_info(a1, a2); break; | |||
| 2174 | case GetNextClient: | |||
| 2175 | return get_next_client(a1, a2); break; | |||
| 2176 | case GetFirstRegion: | |||
| 2177 | return get_first_region(a1, a2); break; | |||
| 2178 | case GetFirstTuple: | |||
| 2179 | return get_first_tuple(a1, a2); break; | |||
| 2180 | case GetNextRegion: | |||
| 2181 | return get_next_region(a1, a2); break; | |||
| 2182 | case GetNextTuple: | |||
| 2183 | return get_next_tuple(a1, a2); break; | |||
| 2184 | case GetStatus: | |||
| 2185 | return cs_get_status(a1, a2); break; | |||
| 2186 | case GetTupleData: | |||
| 2187 | return get_tuple_data(a1, a2); break; | |||
| 2188 | case MapMemPage: | |||
| 2189 | return map_mem_page(a1, a2); break; | |||
| 2190 | case ModifyConfiguration: | |||
| 2191 | return modify_configuration(a1, a2); break; | |||
| 2192 | case ModifyWindow: | |||
| 2193 | return modify_window(a1, a2); break; | |||
| 2194 | case OpenMemory: | |||
| 2195 | return open_memory(a1, a2); | |||
| 2196 | case ParseTuple: | |||
| 2197 | return parse_tuple(a1, a2, a3); break; | |||
| 2198 | case ReadMemory: | |||
| 2199 | return read_memory(a1, a2, a3); break; | |||
| 2200 | case RegisterClient: | |||
| 2201 | return register_client(a1, a2); break; | |||
| 2202 | case RegisterEraseQueue: | |||
| 2203 | return register_erase_queue(a1, a2); break; | |||
| 2204 | case RegisterMTD: | |||
| 2205 | return register_mtd(a1, a2); break; | |||
| 2206 | case ReleaseConfiguration: | |||
| 2207 | return release_configuration(a1, a2); break; | |||
| 2208 | case ReleaseIO: | |||
| 2209 | return release_io(a1, a2); break; | |||
| 2210 | case ReleaseIRQ: | |||
| 2211 | return cs_release_irq(a1, a2); break; | |||
| 2212 | case ReleaseWindow: | |||
| 2213 | return release_window(a1); break; | |||
| 2214 | case RequestConfiguration: | |||
| 2215 | return request_configuration(a1, a2); break; | |||
| 2216 | case RequestIO: | |||
| 2217 | return request_io(a1, a2); break; | |||
| 2218 | case RequestIRQ: | |||
| 2219 | return cs_request_irq(a1, a2); break; | |||
| 2220 | case RequestWindow: | |||
| 2221 | return request_window(a1, a2); break; | |||
| 2222 | case ResetCard: | |||
| 2223 | return reset_card(a1, a2); break; | |||
| 2224 | case SetEventMask: | |||
| 2225 | return set_event_mask(a1, a2); break; | |||
| 2226 | case ValidateCIS: | |||
| 2227 | return validate_cis(a1, a2); break; | |||
| 2228 | case WriteMemory: | |||
| 2229 | return write_memory(a1, a2, a3); break; | |||
| 2230 | case BindDevice: | |||
| 2231 | return bind_device(a1); break; | |||
| 2232 | case BindMTD: | |||
| 2233 | return bind_mtd(a1); break; | |||
| 2234 | case ReportError: | |||
| 2235 | return report_error(a1, a2); break; | |||
| 2236 | case SuspendCard: | |||
| 2237 | return suspend_card(a1, a2); break; | |||
| 2238 | case ResumeCard: | |||
| 2239 | return resume_card(a1, a2); break; | |||
| 2240 | case EjectCard: | |||
| 2241 | return eject_card(a1, a2); break; | |||
| 2242 | case InsertCard: | |||
| 2243 | return insert_card(a1, a2); break; | |||
| 2244 | case ReplaceCIS: | |||
| 2245 | return replace_cis(a1, a2); break; | |||
| 2246 | case GetFirstWindow: | |||
| 2247 | return get_first_window(a1, a2); break; | |||
| 2248 | case GetNextWindow: | |||
| 2249 | return get_next_window(a1, a2); break; | |||
| 2250 | case GetMemPage: | |||
| 2251 | return get_mem_page(a1, a2); break; | |||
| 2252 | default: | |||
| 2253 | return CS_UNSUPPORTED_FUNCTION0x15; break; | |||
| 2254 | } | |||
| 2255 | ||||
| 2256 | } /* CardServices */ | |||
| 2257 | ||||
| 2258 | /*====================================================================== | |||
| 2259 | ||||
| 2260 | OS-specific module glue goes here | |||
| 2261 | ||||
| 2262 | ======================================================================*/ | |||
| 2263 | ||||
| 2264 | #include <linux/pci.h> | |||
| 2265 | ||||
| 2266 | #if (LINUX_VERSION_CODE131108 <= VERSION(2,1,17)(((2)<<16)+(1<<8)+17)) | |||
| 2267 | ||||
| 2268 | #undef CONFIG_MODVERSIONS | |||
| 2269 | static struct symbol_table cs_symtab = { | |||
| 2270 | #include <linux/symtab_begin.h> | |||
| 2271 | #undef X | |||
| 2272 | #define X(sym) { (void *)&sym, SYMBOL_NAME_STR(sym)"sym" } | |||
| 2273 | X(register_ss_entry), | |||
| 2274 | X(unregister_ss_entry), | |||
| 2275 | X(CardServices), | |||
| 2276 | X(MTDHelperEntry), | |||
| 2277 | #ifdef HAS_PROC_BUS | |||
| 2278 | X(proc_pccard), | |||
| 2279 | #endif | |||
| 2280 | #ifndef HAVE_MEMRESERVE | |||
| 2281 | X(request_mem_region), | |||
| 2282 | X(release_mem_region), | |||
| 2283 | #endif | |||
| 2284 | #ifdef CONFIG_PNP_BIOS | |||
| 2285 | X(check_pnp_irq), | |||
| 2286 | #endif | |||
| 2287 | #ifdef CONFIG_PCI1 | |||
| 2288 | X(pci_irq_mask), | |||
| 2289 | X(pci_devices), | |||
| 2290 | X(pci_root), | |||
| 2291 | X(pci_find_slot), | |||
| 2292 | X(pci_find_class), | |||
| 2293 | X(pci_enable_device), | |||
| 2294 | X(pci_set_power_state), | |||
| 2295 | #endif | |||
| 2296 | #include <linux/symtab_end.h> | |||
| 2297 | }; | |||
| 2298 | ||||
| 2299 | #else | |||
| 2300 | ||||
| 2301 | EXPORT_SYMBOL(register_ss_entry); | |||
| 2302 | EXPORT_SYMBOL(unregister_ss_entry); | |||
| 2303 | EXPORT_SYMBOL(CardServices); | |||
| 2304 | EXPORT_SYMBOL(MTDHelperEntry); | |||
| 2305 | #ifdef HAS_PROC_BUS | |||
| 2306 | EXPORT_SYMBOL(proc_pccard); | |||
| 2307 | #endif | |||
| 2308 | #ifndef HAVE_MEMRESERVE | |||
| 2309 | EXPORT_SYMBOL(request_mem_region); | |||
| 2310 | EXPORT_SYMBOL(release_mem_region); | |||
| 2311 | #endif | |||
| 2312 | #ifdef CONFIG_PNP_BIOS | |||
| 2313 | EXPORT_SYMBOL(check_pnp_irq); | |||
| 2314 | #endif | |||
| 2315 | #ifdef CONFIG_PCI1 | |||
| 2316 | EXPORT_SYMBOL(pci_irq_mask); | |||
| 2317 | #if (LINUX_VERSION_CODE131108 < VERSION(2,3,24)(((2)<<16)+(3<<8)+24)) | |||
| 2318 | EXPORT_SYMBOL(pci_enable_device); | |||
| 2319 | EXPORT_SYMBOL(pci_set_power_state); | |||
| 2320 | #endif | |||
| 2321 | #endif | |||
| 2322 | ||||
| 2323 | #endif | |||
| 2324 | ||||
| 2325 | int __init init_pcmcia_cs(void) | |||
| 2326 | { | |||
| 2327 | printk(KERN_INFO"<6>" "%s\n", release); | |||
| 2328 | #ifdef UTS_RELEASE"2.0.36" | |||
| 2329 | printk(KERN_INFO"<6>" " %s\n", kernel); | |||
| 2330 | #endif | |||
| 2331 | printk(KERN_INFO"<6>" " %s\n", options); | |||
| 2332 | DEBUG(0, "%s\n", version)do { if (pc_debug>(0)) printk("<7>" "%s\n", version) ; } while (0); | |||
| 2333 | #ifdef CONFIG_PM | |||
| 2334 | if (do_apm) | |||
| 2335 | pm_register(PM_SYS_DEV, PM_SYS_PCMCIA, handle_pm_event); | |||
| 2336 | #endif | |||
| 2337 | #ifdef CONFIG_PCI1 | |||
| 2338 | pci_fixup_init(); | |||
| 2339 | #endif | |||
| 2340 | #ifdef CONFIG_PNP_BIOS | |||
| 2341 | if (do_pnp) { | |||
| 2342 | pnp_bios_init(); | |||
| 2343 | pnp_proc_init(); | |||
| 2344 | pnp_rsrc_init(); | |||
| 2345 | } | |||
| 2346 | #endif | |||
| 2347 | register_symtab(&cs_symtab); | |||
| 2348 | #ifdef HAS_PROC_BUS | |||
| 2349 | proc_pccard = proc_mkdir("pccard", proc_bus); | |||
| 2350 | #ifdef CONFIG_PNP_BIOS | |||
| 2351 | if (proc_pccard) { | |||
| 2352 | create_proc_read_entry("ioport", 0, proc_pccard, | |||
| 2353 | proc_read_io, NULL((void *) 0)); | |||
| 2354 | create_proc_read_entry("irq", 0, proc_pccard, | |||
| 2355 | proc_read_irq, NULL((void *) 0)); | |||
| 2356 | } | |||
| 2357 | #endif | |||
| 2358 | #ifndef HAVE_MEMRESERVE | |||
| 2359 | if (proc_pccard) | |||
| 2360 | create_proc_read_entry("memory", 0, proc_pccard, | |||
| 2361 | proc_read_mem, NULL((void *) 0)); | |||
| 2362 | #endif | |||
| 2363 | #endif | |||
| 2364 | return 0; | |||
| 2365 | } | |||
| 2366 | ||||
| 2367 | static void __exit__attribute__((__used__)) __attribute__((no_instrument_function )) exit_pcmcia_cs(void) | |||
| 2368 | { | |||
| 2369 | printk(KERN_INFO"<6>" "unloading PCMCIA Card Services\n"); | |||
| 2370 | #ifdef HAS_PROC_BUS | |||
| 2371 | if (proc_pccard) { | |||
| 2372 | #ifdef CONFIG_PNP_BIOS | |||
| 2373 | remove_proc_entry("ioport", proc_pccard); | |||
| 2374 | remove_proc_entry("irq", proc_pccard); | |||
| 2375 | #endif | |||
| 2376 | #ifndef HAVE_MEMRESERVE | |||
| 2377 | remove_proc_entry("memory", proc_pccard); | |||
| 2378 | #endif | |||
| 2379 | remove_proc_entry("pccard", proc_bus); | |||
| 2380 | } | |||
| 2381 | #endif | |||
| 2382 | #ifdef CONFIG_PM | |||
| 2383 | if (do_apm) | |||
| 2384 | pm_unregister_all(handle_pm_event); | |||
| 2385 | #endif | |||
| 2386 | #ifdef CONFIG_PCI1 | |||
| 2387 | pci_fixup_done(); | |||
| 2388 | #endif | |||
| 2389 | #ifdef CONFIG_PNP_BIOS | |||
| 2390 | if (do_pnp) { | |||
| 2391 | pnp_proc_done(); | |||
| 2392 | pnp_rsrc_done(); | |||
| 2393 | } | |||
| 2394 | #endif | |||
| 2395 | release_resource_db(); | |||
| 2396 | } | |||
| 2397 | ||||
| 2398 | module_init(init_pcmcia_cs)void pcmcia_modinit_pcmcia_cs (void) { init_pcmcia_cs(); return ; }; | |||
| 2399 | module_exit(exit_pcmcia_cs); |