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); |