File: | obj-scan-build/../linux/pcmcia-cs/modules/ds.c |
Location: | line 317, column 5 |
Description: | Value stored to 'i' is never read |
1 | /*====================================================================== |
2 | |
3 | PC Card Driver Services |
4 | |
5 | ds.c 1.115 2002/10/12 19:03:44 |
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/major.h> |
38 | #include <linux/string.h> |
39 | #include <linux/errno.h> |
40 | #include <linux/slab.h> |
41 | #include <linux/mm.h> |
42 | #include <linux/fcntl.h> |
43 | #include <linux/sched.h> |
44 | #include <linux/timer.h> |
45 | #include <linux/ioctl.h> |
46 | #include <linux/proc_fs.h> |
47 | #if (LINUX_VERSION_CODE131108 >= KERNEL_VERSION(2,1,23)(((2)<<16)+(1<<8)+23)) |
48 | #include <linux/poll.h> |
49 | #endif |
50 | |
51 | /* |
52 | * <pcmcia/cs.h> defines io_req_t which is not used in this file, but |
53 | * which clashes with the io_req_t needed for the Mach devices. Rename |
54 | * it to cardservice_io_req_t to avoid this clash. |
55 | */ |
56 | #define io_req_t cardservice_io_req_t |
57 | #include <pcmcia/version.h> |
58 | #include <pcmcia/cs_types.h> |
59 | #include <pcmcia/cs.h> |
60 | #include <pcmcia/bulkmem.h> |
61 | #include <pcmcia/cistpl.h> |
62 | #include <pcmcia/ds.h> |
63 | #undef io_req_t |
64 | |
65 | /*====================================================================*/ |
66 | |
67 | /* Module parameters */ |
68 | |
69 | MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>"); |
70 | MODULE_DESCRIPTION("PCMCIA Driver Services " CS_RELEASE); |
71 | MODULE_LICENSE("Dual MPL/GPL"); |
72 | |
73 | #define INT_MODULE_PARM(n, v)static int n = v; static int n = v; MODULE_PARM(n, "i") |
74 | |
75 | #ifdef PCMCIA_DEBUG4 |
76 | INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG)static int pc_debug = 4;; |
77 | #define DEBUG(n, args...)if (pc_debug>(n)) printk("<7>" args...) if (pc_debug>(n)) printk(KERN_DEBUG"<7>" args) |
78 | static const char *version = |
79 | "ds.c 1.115 2002/10/12 19:03:44 (David Hinds)"; |
80 | #else |
81 | #define DEBUG(n, args...)if (pc_debug>(n)) printk("<7>" args...) |
82 | #endif |
83 | |
84 | /*====================================================================*/ |
85 | |
86 | typedef struct driver_info_t { |
87 | dev_info_t dev_info; |
88 | int use_count, status; |
89 | dev_link_t *(*attach)(void); |
90 | void (*detach)(dev_link_t *); |
91 | struct driver_info_t *next; |
92 | } driver_info_t; |
93 | |
94 | typedef struct socket_bind_t { |
95 | driver_info_t *driver; |
96 | u_char function; |
97 | dev_link_t *instance; |
98 | struct socket_bind_t *next; |
99 | } socket_bind_t; |
100 | |
101 | /* Device user information */ |
102 | #define MAX_EVENTS32 32 |
103 | #define USER_MAGIC0x7ea4 0x7ea4 |
104 | #define CHECK_USER(u)(((u) == ((void *) 0)) || ((u)->user_magic != 0x7ea4)) \ |
105 | (((u) == NULL((void *) 0)) || ((u)->user_magic != USER_MAGIC0x7ea4)) |
106 | typedef struct user_info_t { |
107 | u_int user_magic; |
108 | int event_head, event_tail; |
109 | event_t event[MAX_EVENTS32]; |
110 | struct user_info_t *next; |
111 | } user_info_t; |
112 | |
113 | /* Socket state information */ |
114 | typedef struct socket_info_t { |
115 | client_handle_t handle; |
116 | int state; |
117 | user_info_t *user; |
118 | int req_pending, req_result; |
119 | wait_queue_head_t queue, request; |
120 | struct timer_list removal; |
121 | socket_bind_t *bind; |
122 | } socket_info_t; |
123 | |
124 | #define SOCKET_PRESENT0x01 0x01 |
125 | #define SOCKET_BUSY0x02 0x02 |
126 | #define SOCKET_REMOVAL_PENDING0x10 0x10 |
127 | |
128 | /*====================================================================*/ |
129 | |
130 | /* Device driver ID passed to Card Services */ |
131 | static dev_info_t dev_info = "Driver Services"; |
132 | |
133 | /* Linked list of all registered device drivers */ |
134 | static driver_info_t *root_driver = NULL((void *) 0); |
135 | |
136 | static int sockets = 0, major_dev = -1; |
137 | static socket_info_t *socket_table = NULL((void *) 0); |
138 | |
139 | extern struct proc_dir_entry *proc_pccard; |
140 | |
141 | /* We use this to distinguish in-kernel from modular drivers */ |
142 | static int init_status = 1; |
143 | |
144 | /*====================================================================*/ |
145 | |
146 | static void cs_error(client_handle_t handle, int func, int ret) |
147 | { |
148 | error_info_t err = { func, ret }; |
149 | CardServices(ReportError, handle, &err); |
150 | } |
151 | |
152 | /*====================================================================== |
153 | |
154 | Register_pccard_driver() and unregister_pccard_driver() are used |
155 | tell Driver Services that a PC Card client driver is available to |
156 | be bound to sockets. |
157 | |
158 | ======================================================================*/ |
159 | |
160 | int register_pccard_driver(dev_info_t *dev_info, |
161 | dev_link_t *(*attach)(void), |
162 | void (*detach)(dev_link_t *)) |
163 | { |
164 | driver_info_t *driver; |
165 | socket_bind_t *b; |
166 | int i; |
167 | |
168 | DEBUG(0, "ds: register_pccard_driver('%s')\n", (char *)dev_info)if (pc_debug>(0)) printk("<7>" "ds: register_pccard_driver('%s')\n" , (char *)dev_info); |
169 | for (driver = root_driver; driver; driver = driver->next) |
170 | if (strncmp((char *)dev_info, (char *)driver->dev_info, |
171 | DEV_NAME_LEN32) == 0) |
172 | break; |
173 | if (!driver) { |
174 | driver = kmalloclinux_kmalloc(sizeof(driver_info_t), GFP_KERNEL0x03); |
175 | if (!driver) return -ENOMEM12; |
176 | strncpy(driver->dev_info, (char *)dev_info, DEV_NAME_LEN32); |
177 | driver->use_count = 0; |
178 | driver->status = init_status; |
179 | driver->next = root_driver; |
180 | root_driver = driver; |
181 | } |
182 | |
183 | driver->attach = attach; |
184 | driver->detach = detach; |
185 | if (driver->use_count == 0) return 0; |
186 | |
187 | /* Instantiate any already-bound devices */ |
188 | for (i = 0; i < sockets; i++) |
189 | for (b = socket_table[i].bind; b; b = b->next) { |
190 | if (b->driver != driver) continue; |
191 | b->instance = driver->attach(); |
192 | if (b->instance == NULL((void *) 0)) |
193 | printk(KERN_NOTICE"<5>" "ds: unable to create instance " |
194 | "of '%s'!\n", driver->dev_info); |
195 | } |
196 | |
197 | return 0; |
198 | } /* register_pccard_driver */ |
199 | |
200 | /*====================================================================*/ |
201 | |
202 | int unregister_pccard_driver(dev_info_t *dev_info) |
203 | { |
204 | driver_info_t *target, **d = &root_driver; |
205 | socket_bind_t *b; |
206 | int i; |
207 | |
208 | DEBUG(0, "ds: unregister_pccard_driver('%s')\n",if (pc_debug>(0)) printk("<7>" "ds: unregister_pccard_driver('%s')\n" , (char *)dev_info) |
209 | (char *)dev_info)if (pc_debug>(0)) printk("<7>" "ds: unregister_pccard_driver('%s')\n" , (char *)dev_info); |
210 | while ((*d) && (strncmp((*d)->dev_info, (char *)dev_info, |
211 | DEV_NAME_LEN32) != 0)) |
212 | d = &(*d)->next; |
213 | if (*d == NULL((void *) 0)) |
214 | return -ENODEV19; |
215 | |
216 | target = *d; |
217 | if (target->use_count == 0) { |
218 | *d = target->next; |
219 | kfree(target); |
220 | } else { |
221 | /* Blank out any left-over device instances */ |
222 | target->attach = NULL((void *) 0); target->detach = NULL((void *) 0); |
223 | for (i = 0; i < sockets; i++) |
224 | for (b = socket_table[i].bind; b; b = b->next) |
225 | if (b->driver == target) b->instance = NULL((void *) 0); |
226 | } |
227 | return 0; |
228 | } /* unregister_pccard_driver */ |
229 | |
230 | /*====================================================================*/ |
231 | |
232 | #ifdef HAS_PROC_BUS |
233 | static int proc_read_drivers(char *buf, char **start, off_t pos, |
234 | int count, int *eof, void *data) |
235 | { |
236 | driver_info_t *d; |
237 | char *p = buf; |
238 | for (d = root_driver; d; d = d->next) |
239 | p += sprintflinux_sprintf(p, "%-24.24s %d %d\n", d->dev_info, |
240 | d->status, d->use_count); |
241 | return (p - buf); |
242 | } |
243 | #endif |
244 | |
245 | /*====================================================================== |
246 | |
247 | These manage a ring buffer of events pending for one user process |
248 | |
249 | ======================================================================*/ |
250 | |
251 | static int queue_empty(user_info_t *user) |
252 | { |
253 | return (user->event_head == user->event_tail); |
254 | } |
255 | |
256 | static event_t get_queued_event(user_info_t *user) |
257 | { |
258 | user->event_tail = (user->event_tail+1) % MAX_EVENTS32; |
259 | return user->event[user->event_tail]; |
260 | } |
261 | |
262 | static void queue_event(user_info_t *user, event_t event) |
263 | { |
264 | user->event_head = (user->event_head+1) % MAX_EVENTS32; |
265 | if (user->event_head == user->event_tail) |
266 | user->event_tail = (user->event_tail+1) % MAX_EVENTS32; |
267 | user->event[user->event_head] = event; |
268 | } |
269 | |
270 | static void handle_event(socket_info_t *s, event_t event) |
271 | { |
272 | user_info_t *user; |
273 | for (user = s->user; user; user = user->next) |
274 | queue_event(user, event); |
275 | wake_up_interruptiblewake_up(&s->queue); |
276 | } |
277 | |
278 | static int handle_request(socket_info_t *s, event_t event) |
279 | { |
280 | if (s->req_pending != 0) |
281 | return CS_IN_USE0x1e; |
282 | if (s->state & SOCKET_BUSY0x02) |
283 | s->req_pending = 1; |
284 | handle_event(s, event); |
285 | if (s->req_pending > 0) { |
286 | interruptible_sleep_on(&s->request); |
287 | if (signal_pending(current)0) |
288 | return CS_IN_USE0x1e; |
289 | else |
290 | return s->req_result; |
291 | } |
292 | return CS_SUCCESS0x00; |
293 | } |
294 | |
295 | static void handle_removal(u_long sn) |
296 | { |
297 | socket_info_t *s = &socket_table[sn]; |
298 | handle_event(s, CS_EVENT_CARD_REMOVAL0x000008); |
299 | s->state &= ~SOCKET_REMOVAL_PENDING0x10; |
300 | } |
301 | |
302 | /*====================================================================== |
303 | |
304 | The card status event handler. |
305 | |
306 | ======================================================================*/ |
307 | |
308 | static int ds_event(event_t event, int priority, |
309 | event_callback_args_t *args) |
310 | { |
311 | socket_info_t *s; |
312 | int i; |
313 | |
314 | DEBUG(1, "ds: ds_event(0x%06x, %d, 0x%p)\n",if (pc_debug>(1)) printk("<7>" "ds: ds_event(0x%06x, %d, 0x%p)\n" , event, priority, args->client_handle) |
315 | event, priority, args->client_handle)if (pc_debug>(1)) printk("<7>" "ds: ds_event(0x%06x, %d, 0x%p)\n" , event, priority, args->client_handle); |
316 | s = args->client_data; |
317 | i = s - socket_table; |
Value stored to 'i' is never read | |
318 | |
319 | switch (event) { |
320 | |
321 | case CS_EVENT_CARD_REMOVAL0x000008: |
322 | s->state &= ~SOCKET_PRESENT0x01; |
323 | if (!(s->state & SOCKET_REMOVAL_PENDING0x10)) { |
324 | s->state |= SOCKET_REMOVAL_PENDING0x10; |
325 | s->removal.expires = jiffies + HZ100/10; |
326 | add_timer(&s->removal); |
327 | } |
328 | break; |
329 | |
330 | case CS_EVENT_CARD_INSERTION0x000004: |
331 | s->state |= SOCKET_PRESENT0x01; |
332 | handle_event(s, event); |
333 | break; |
334 | |
335 | case CS_EVENT_EJECTION_REQUEST0x010000: |
336 | return handle_request(s, event); |
337 | break; |
338 | |
339 | default: |
340 | handle_event(s, event); |
341 | break; |
342 | } |
343 | |
344 | return 0; |
345 | } /* ds_event */ |
346 | |
347 | /*====================================================================== |
348 | |
349 | bind_mtd() connects a memory region with an MTD client. |
350 | |
351 | ======================================================================*/ |
352 | |
353 | static int bind_mtd(int i, mtd_info_t *mtd_info) |
354 | { |
355 | mtd_bind_t bind_req; |
356 | int ret; |
357 | |
358 | bind_req.dev_info = &mtd_info->dev_info; |
359 | bind_req.Attributes = mtd_info->Attributes; |
360 | bind_req.Socket = i; |
361 | bind_req.CardOffset = mtd_info->CardOffset; |
362 | ret = CardServices(BindMTD, &bind_req); |
363 | if (ret != CS_SUCCESS0x00) { |
364 | cs_error(NULL((void *) 0), BindMTD, ret); |
365 | printk(KERN_NOTICE"<5>" "ds: unable to bind MTD '%s' to socket %d" |
366 | " offset 0x%x\n", |
367 | (char *)bind_req.dev_info, i, bind_req.CardOffset); |
368 | return -ENODEV19; |
369 | } |
370 | return 0; |
371 | } /* bind_mtd */ |
372 | |
373 | /*====================================================================== |
374 | |
375 | bind_request() connects a socket to a particular client driver. |
376 | It looks up the specified device ID in the list of registered |
377 | drivers, binds it to the socket, and tries to create an instance |
378 | of the device. unbind_request() deletes a driver instance. |
379 | |
380 | ======================================================================*/ |
381 | |
382 | static int bind_request(int i, bind_info_t *bind_info) |
383 | { |
384 | struct driver_info_t *driver; |
385 | socket_bind_t *b; |
386 | bind_req_t bind_req; |
387 | socket_info_t *s = &socket_table[i]; |
388 | int ret; |
389 | |
390 | DEBUG(2, "bind_request(%d, '%s')\n", i,if (pc_debug>(2)) printk("<7>" "bind_request(%d, '%s')\n" , i, (char *)bind_info->dev_info) |
391 | (char *)bind_info->dev_info)if (pc_debug>(2)) printk("<7>" "bind_request(%d, '%s')\n" , i, (char *)bind_info->dev_info); |
392 | for (driver = root_driver; driver; driver = driver->next) |
393 | if (strcmp((char *)driver->dev_info, |
394 | (char *)bind_info->dev_info) == 0) |
395 | break; |
396 | if (driver == NULL((void *) 0)) { |
397 | driver = kmalloclinux_kmalloc(sizeof(driver_info_t), GFP_KERNEL0x03); |
398 | if (!driver) return -ENOMEM12; |
399 | strncpy(driver->dev_info, bind_info->dev_info, DEV_NAME_LEN32); |
400 | driver->use_count = 0; |
401 | driver->next = root_driver; |
402 | driver->attach = NULL((void *) 0); driver->detach = NULL((void *) 0); |
403 | root_driver = driver; |
404 | } |
405 | |
406 | for (b = s->bind; b; b = b->next) |
407 | if ((driver == b->driver) && |
408 | (bind_info->function == b->function)) |
409 | break; |
410 | if (b != NULL((void *) 0)) { |
411 | bind_info->instance = b->instance; |
412 | return -EBUSY16; |
413 | } |
414 | b = kmalloclinux_kmalloc(sizeof(socket_bind_t), GFP_KERNEL0x03); |
415 | if (!b) |
416 | return -ENOMEM12; |
417 | |
418 | bind_req.Socket = i; |
419 | bind_req.Function = bind_info->function; |
420 | bind_req.dev_info = &driver->dev_info; |
421 | ret = CardServices(BindDevice, &bind_req); |
422 | if (ret != CS_SUCCESS0x00) { |
423 | cs_error(NULL((void *) 0), BindDevice, ret); |
424 | printk(KERN_NOTICE"<5>" "ds: unable to bind '%s' to socket %d\n", |
425 | (char *)dev_info, i); |
426 | kfree(b); |
427 | return -ENODEV19; |
428 | } |
429 | |
430 | /* Add binding to list for this socket */ |
431 | driver->use_count++; |
432 | b->driver = driver; |
433 | b->function = bind_info->function; |
434 | b->instance = NULL((void *) 0); |
435 | b->next = s->bind; |
436 | s->bind = b; |
437 | |
438 | if (driver->attach) { |
439 | b->instance = driver->attach(); |
440 | if (b->instance == NULL((void *) 0)) { |
441 | printk(KERN_NOTICE"<5>" "ds: unable to create instance " |
442 | "of '%s'!\n", (char *)bind_info->dev_info); |
443 | return -ENODEV19; |
444 | } |
445 | } |
446 | |
447 | return 0; |
448 | } /* bind_request */ |
449 | |
450 | /*====================================================================*/ |
451 | |
452 | static int get_device_info(int i, bind_info_t *bind_info, int first) |
453 | { |
454 | socket_info_t *s = &socket_table[i]; |
455 | socket_bind_t *b; |
456 | dev_node_t *node; |
457 | |
458 | for (b = s->bind; b; b = b->next) |
459 | if ((strcmp((char *)b->driver->dev_info, |
460 | (char *)bind_info->dev_info) == 0) && |
461 | (b->function == bind_info->function)) |
462 | break; |
463 | if (b == NULL((void *) 0)) return -ENODEV19; |
464 | if ((b->instance == NULL((void *) 0)) || |
465 | (b->instance->state & DEV_CONFIG_PENDING0x10)) |
466 | return -EAGAIN11; |
467 | if (first) |
468 | node = b->instance->dev; |
469 | else |
470 | for (node = b->instance->dev; node; node = node->next) |
471 | if (node == bind_info->next) break; |
472 | if (node == NULL((void *) 0)) return -ENODEV19; |
473 | |
474 | strncpy(bind_info->name, node->dev_name, DEV_NAME_LEN32); |
475 | bind_info->name[DEV_NAME_LEN32-1] = '\0'; |
476 | bind_info->major = node->major; |
477 | bind_info->minor = node->minor; |
478 | bind_info->next = node->next; |
479 | |
480 | return 0; |
481 | } /* get_device_info */ |
482 | |
483 | /*====================================================================*/ |
484 | |
485 | static int unbind_request(int i, bind_info_t *bind_info) |
486 | { |
487 | socket_info_t *s = &socket_table[i]; |
488 | socket_bind_t **b, *c; |
489 | |
490 | DEBUG(2, "unbind_request(%d, '%s')\n", i,if (pc_debug>(2)) printk("<7>" "unbind_request(%d, '%s')\n" , i, (char *)bind_info->dev_info) |
491 | (char *)bind_info->dev_info)if (pc_debug>(2)) printk("<7>" "unbind_request(%d, '%s')\n" , i, (char *)bind_info->dev_info); |
492 | for (b = &s->bind; *b; b = &(*b)->next) |
493 | if ((strcmp((char *)(*b)->driver->dev_info, |
494 | (char *)bind_info->dev_info) == 0) && |
495 | ((*b)->function == bind_info->function)) |
496 | break; |
497 | if (*b == NULL((void *) 0)) |
498 | return -ENODEV19; |
499 | |
500 | c = *b; |
501 | c->driver->use_count--; |
502 | if (c->driver->detach) { |
503 | if (c->instance) |
504 | c->driver->detach(c->instance); |
505 | } else { |
506 | if (c->driver->use_count == 0) { |
507 | driver_info_t **d; |
508 | for (d = &root_driver; *d; d = &((*d)->next)) |
509 | if (c->driver == *d) break; |
510 | *d = (*d)->next; |
511 | kfree(c->driver); |
512 | } |
513 | } |
514 | *b = c->next; |
515 | kfree(c); |
516 | |
517 | return 0; |
518 | } /* unbind_request */ |
519 | |
520 | /*====================================================================== |
521 | |
522 | The user-mode PC Card device interface |
523 | |
524 | ======================================================================*/ |
525 | |
526 | /* Disable all the ds filesystem operations. */ |
527 | #ifndef MACH1 |
528 | |
529 | static int ds_open(struct inode *inode, struct file *file) |
530 | { |
531 | socket_t i = MINOR(inode->i_rdev)((inode->i_rdev) & ((1<<8) - 1)); |
532 | socket_info_t *s; |
533 | user_info_t *user; |
534 | |
535 | DEBUG(0, "ds_open(socket %d)\n", i)if (pc_debug>(0)) printk("<7>" "ds_open(socket %d)\n" , i); |
536 | if ((i >= sockets) || (sockets == 0)) |
537 | return -ENODEV19; |
538 | s = &socket_table[i]; |
539 | if ((file->f_flags & O_ACCMODE0003) != O_RDONLY00) { |
540 | if (s->state & SOCKET_BUSY0x02) |
541 | return -EBUSY16; |
542 | else |
543 | s->state |= SOCKET_BUSY0x02; |
544 | } |
545 | |
546 | MOD_INC_USE_COUNTdo { } while (0); |
547 | user = kmalloclinux_kmalloc(sizeof(user_info_t), GFP_KERNEL0x03); |
548 | if (!user) { |
549 | MOD_DEC_USE_COUNTdo { } while (0); |
550 | return -ENOMEM12; |
551 | } |
552 | user->event_tail = user->event_head = 0; |
553 | user->next = s->user; |
554 | user->user_magic = USER_MAGIC0x7ea4; |
555 | s->user = user; |
556 | file->private_data = user; |
557 | |
558 | if (s->state & SOCKET_PRESENT0x01) |
559 | queue_event(user, CS_EVENT_CARD_INSERTION0x000004); |
560 | return 0; |
561 | } /* ds_open */ |
562 | |
563 | /*====================================================================*/ |
564 | |
565 | static FS_RELEASE_T ds_release(struct inode *inode, struct file *file) |
566 | { |
567 | socket_t i = MINOR(inode->i_rdev)((inode->i_rdev) & ((1<<8) - 1)); |
568 | socket_info_t *s; |
569 | user_info_t *user, **link; |
570 | |
571 | DEBUG(0, "ds_release(socket %d)\n", i)if (pc_debug>(0)) printk("<7>" "ds_release(socket %d)\n" , i); |
572 | if ((i >= sockets) || (sockets == 0)) |
573 | return (FS_RELEASE_T)0; |
574 | s = &socket_table[i]; |
575 | user = file->private_data; |
576 | if (CHECK_USER(user)(((user) == ((void *) 0)) || ((user)->user_magic != 0x7ea4 ))) |
577 | return (FS_RELEASE_T)0; |
578 | |
579 | /* Unlink user data structure */ |
580 | if ((file->f_flags & O_ACCMODE0003) != O_RDONLY00) |
581 | s->state &= ~SOCKET_BUSY0x02; |
582 | file->private_data = NULL((void *) 0); |
583 | for (link = &s->user; *link; link = &(*link)->next) |
584 | if (*link == user) break; |
585 | if (link == NULL((void *) 0)) |
586 | return (FS_RELEASE_T)0; |
587 | *link = user->next; |
588 | user->user_magic = 0; |
589 | kfree(user); |
590 | |
591 | MOD_DEC_USE_COUNTdo { } while (0); |
592 | return (FS_RELEASE_T)0; |
593 | } /* ds_release */ |
594 | |
595 | /*====================================================================*/ |
596 | |
597 | static ssize_t ds_read FOPS(struct inode *inode, |
598 | struct file *file, char *buf, |
599 | size_t count, loff_t *ppos) |
600 | { |
601 | socket_t i = MINOR(F_INODE(file)->i_rdev)((F_INODE(file)->i_rdev) & ((1<<8) - 1)); |
602 | socket_info_t *s; |
603 | user_info_t *user; |
604 | |
605 | DEBUG(2, "ds_read(socket %d)\n", i)if (pc_debug>(2)) printk("<7>" "ds_read(socket %d)\n" , i); |
606 | |
607 | if ((i >= sockets) || (sockets == 0)) |
608 | return -ENODEV19; |
609 | if (count < 4) |
610 | return -EINVAL22; |
611 | s = &socket_table[i]; |
612 | user = file->private_data; |
613 | if (CHECK_USER(user)(((user) == ((void *) 0)) || ((user)->user_magic != 0x7ea4 ))) |
614 | return -EIO5; |
615 | |
616 | if (queue_empty(user)) { |
617 | interruptible_sleep_on(&s->queue); |
618 | if (signal_pending(current)0) |
619 | return -EINTR4; |
620 | } |
621 | put_user(get_queued_event(user), (int *)buf)__put_user((unsigned long)(get_queued_event(user)),((int *)buf ),sizeof(*((int *)buf))); |
622 | return 4; |
623 | } /* ds_read */ |
624 | |
625 | /*====================================================================*/ |
626 | |
627 | static ssize_t ds_write FOPS(struct inode *inode, |
628 | struct file *file, const char *buf, |
629 | size_t count, loff_t *ppos) |
630 | { |
631 | socket_t i = MINOR(F_INODE(file)->i_rdev)((F_INODE(file)->i_rdev) & ((1<<8) - 1)); |
632 | socket_info_t *s; |
633 | user_info_t *user; |
634 | |
635 | DEBUG(2, "ds_write(socket %d)\n", i)if (pc_debug>(2)) printk("<7>" "ds_write(socket %d)\n" , i); |
636 | |
637 | if ((i >= sockets) || (sockets == 0)) |
638 | return -ENODEV19; |
639 | if (count != 4) |
640 | return -EINVAL22; |
641 | if ((file->f_flags & O_ACCMODE0003) == O_RDONLY00) |
642 | return -EBADF9; |
643 | s = &socket_table[i]; |
644 | user = file->private_data; |
645 | if (CHECK_USER(user)(((user) == ((void *) 0)) || ((user)->user_magic != 0x7ea4 ))) |
646 | return -EIO5; |
647 | |
648 | if (s->req_pending) { |
649 | s->req_pending--; |
650 | get_user(s->req_result, (int *)buf); |
651 | if ((s->req_result != 0) || (s->req_pending == 0)) |
652 | wake_up_interruptiblewake_up(&s->request); |
653 | } else |
654 | return -EIO5; |
655 | |
656 | return 4; |
657 | } /* ds_write */ |
658 | |
659 | /*====================================================================*/ |
660 | |
661 | #if (LINUX_VERSION_CODE131108 < VERSION(2,1,23)(((2)<<16)+(1<<8)+23)) |
662 | |
663 | static int ds_select(struct inode *inode, struct file *file, |
664 | int sel_type, select_table *wait) |
665 | { |
666 | socket_t i = MINOR(inode->i_rdev)((inode->i_rdev) & ((1<<8) - 1)); |
667 | socket_info_t *s; |
668 | user_info_t *user; |
669 | |
670 | DEBUG(2, "ds_select(socket %d)\n", i)if (pc_debug>(2)) printk("<7>" "ds_select(socket %d)\n" , i); |
671 | |
672 | if ((i >= sockets) || (sockets == 0)) |
673 | return -ENODEV19; |
674 | s = &socket_table[i]; |
675 | user = file->private_data; |
676 | if (CHECK_USER(user)(((user) == ((void *) 0)) || ((user)->user_magic != 0x7ea4 ))) |
677 | return -EIO5; |
678 | if (sel_type != SEL_IN1) |
679 | return 0; |
680 | if (!queue_empty(user)) |
681 | return 1; |
682 | select_wait(&s->queue, wait); |
683 | return 0; |
684 | } /* ds_select */ |
685 | |
686 | #else |
687 | |
688 | static u_int ds_poll(struct file *file, poll_table *wait) |
689 | { |
690 | socket_t i = MINOR(F_INODE(file)->i_rdev)((F_INODE(file)->i_rdev) & ((1<<8) - 1)); |
691 | socket_info_t *s; |
692 | user_info_t *user; |
693 | |
694 | DEBUG(2, "ds_poll(socket %d)\n", i)if (pc_debug>(2)) printk("<7>" "ds_poll(socket %d)\n" , i); |
695 | |
696 | if ((i >= sockets) || (sockets == 0)) |
697 | return POLLERR; |
698 | s = &socket_table[i]; |
699 | user = file->private_data; |
700 | if (CHECK_USER(user)(((user) == ((void *) 0)) || ((user)->user_magic != 0x7ea4 ))) |
701 | return POLLERR; |
702 | POLL_WAIT(file, &s->queue, wait); |
703 | if (!queue_empty(user)) |
704 | return POLLIN | POLLRDNORM; |
705 | return 0; |
706 | } /* ds_poll */ |
707 | |
708 | #endif |
709 | |
710 | /*====================================================================*/ |
711 | |
712 | #endif /* !defined(MACH) */ |
713 | |
714 | static int ds_ioctl(struct inode * inode, struct file * file, |
715 | u_int cmd, u_long arg) |
716 | { |
717 | socket_t i = MINOR(inode->i_rdev)((inode->i_rdev) & ((1<<8) - 1)); |
718 | socket_info_t *s; |
719 | u_int size; |
720 | int ret, err; |
721 | ds_ioctl_arg_t buf; |
722 | |
723 | DEBUG(2, "ds_ioctl(socket %d, %#x, %#lx)\n", i, cmd, arg)if (pc_debug>(2)) printk("<7>" "ds_ioctl(socket %d, %#x, %#lx)\n" , i, cmd, arg); |
724 | |
725 | if ((i >= sockets) || (sockets == 0)) |
726 | return -ENODEV19; |
727 | s = &socket_table[i]; |
728 | |
729 | size = (cmd & IOCSIZE_MASK(((1 << 14)-1) << ((0 +8)+8))) >> IOCSIZE_SHIFT(((0 +8)+8)); |
730 | if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL22; |
731 | |
732 | /* Permission check */ |
733 | if (!(cmd & IOC_OUT(2U << (((0 +8)+8)+14))) && !capable(CAP_SYS_ADMIN)suser()) |
734 | return -EPERM1; |
735 | |
736 | #ifndef MACH1 |
737 | if (cmd & IOC_IN(1U << (((0 +8)+8)+14))) { |
738 | err = verify_area(VERIFY_READ0, (char *)arg, size); |
739 | if (err) { |
740 | DEBUG(3, "ds_ioctl(): verify_read = %d\n", err)if (pc_debug>(3)) printk("<7>" "ds_ioctl(): verify_read = %d\n" , err); |
741 | return err; |
742 | } |
743 | } |
744 | if (cmd & IOC_OUT(2U << (((0 +8)+8)+14))) { |
745 | err = verify_area(VERIFY_WRITE1, (char *)arg, size); |
746 | if (err) { |
747 | DEBUG(3, "ds_ioctl(): verify_write = %d\n", err)if (pc_debug>(3)) printk("<7>" "ds_ioctl(): verify_write = %d\n" , err); |
748 | return err; |
749 | } |
750 | } |
751 | #endif |
752 | |
753 | err = ret = 0; |
754 | |
755 | #ifndef MACH1 |
756 | if (cmd & IOC_IN(1U << (((0 +8)+8)+14))) copy_from_user((char *)&buf, (char *)arg, size); |
757 | #else |
758 | if (cmd & IOC_IN(1U << (((0 +8)+8)+14))) memcpy((char *) &buf, (char *) arg, size)(__builtin_constant_p(size) ? __constant_memcpy(((char *) & buf),((char *) arg),(size)) : __memcpy(((char *) &buf),(( char *) arg),(size))); |
759 | #endif |
760 | |
761 | switch (cmd) { |
762 | case DS_ADJUST_RESOURCE_INFO(((2U|1U) << (((0 +8)+8)+14)) | ((('d')) << (0 +8 )) | (((2)) << 0) | ((sizeof(adjust_t)) << ((0 +8 )+8))): |
763 | ret = CardServices(AdjustResourceInfo, s->handle, &buf.adjust); |
764 | break; |
765 | case DS_GET_CARD_SERVICES_INFO(((2U) << (((0 +8)+8)+14)) | ((('d')) << (0 +8)) | (((1)) << 0) | ((sizeof(servinfo_t)) << ((0 +8)+ 8))): |
766 | ret = CardServices(GetCardServicesInfo, &buf.servinfo); |
767 | break; |
768 | case DS_GET_CONFIGURATION_INFO(((2U|1U) << (((0 +8)+8)+14)) | ((('d')) << (0 +8 )) | (((3)) << 0) | ((sizeof(config_info_t)) << ( (0 +8)+8))): |
769 | ret = CardServices(GetConfigurationInfo, s->handle, &buf.config); |
770 | break; |
771 | case DS_GET_FIRST_TUPLE(((2U|1U) << (((0 +8)+8)+14)) | ((('d')) << (0 +8 )) | (((4)) << 0) | ((sizeof(tuple_t)) << ((0 +8) +8))): |
772 | ret = CardServices(GetFirstTuple, s->handle, &buf.tuple); |
773 | break; |
774 | case DS_GET_NEXT_TUPLE(((2U|1U) << (((0 +8)+8)+14)) | ((('d')) << (0 +8 )) | (((5)) << 0) | ((sizeof(tuple_t)) << ((0 +8) +8))): |
775 | ret = CardServices(GetNextTuple, s->handle, &buf.tuple); |
776 | break; |
777 | case DS_GET_TUPLE_DATA(((2U|1U) << (((0 +8)+8)+14)) | ((('d')) << (0 +8 )) | (((6)) << 0) | ((sizeof(tuple_parse_t)) << ( (0 +8)+8))): |
778 | buf.tuple.TupleData = buf.tuple_parse.data; |
779 | buf.tuple.TupleDataMax = sizeof(buf.tuple_parse.data); |
780 | ret = CardServices(GetTupleData, s->handle, &buf.tuple); |
781 | break; |
782 | case DS_PARSE_TUPLE(((2U|1U) << (((0 +8)+8)+14)) | ((('d')) << (0 +8 )) | (((7)) << 0) | ((sizeof(tuple_parse_t)) << ( (0 +8)+8))): |
783 | buf.tuple.TupleData = buf.tuple_parse.data; |
784 | ret = CardServices(ParseTuple, s->handle, &buf.tuple, |
785 | &buf.tuple_parse.parse); |
786 | break; |
787 | case DS_RESET_CARD(((0U) << (((0 +8)+8)+14)) | ((('d')) << (0 +8)) | (((8)) << 0) | ((0) << ((0 +8)+8))): |
788 | ret = CardServices(ResetCard, s->handle, NULL((void *) 0)); |
789 | break; |
790 | case DS_GET_STATUS(((2U|1U) << (((0 +8)+8)+14)) | ((('d')) << (0 +8 )) | (((9)) << 0) | ((sizeof(cs_status_t)) << ((0 +8)+8))): |
791 | ret = CardServices(GetStatus, s->handle, &buf.status); |
792 | break; |
793 | case DS_VALIDATE_CIS(((2U) << (((0 +8)+8)+14)) | ((('d')) << (0 +8)) | (((11)) << 0) | ((sizeof(cisinfo_t)) << ((0 +8)+ 8))): |
794 | ret = CardServices(ValidateCIS, s->handle, &buf.cisinfo); |
795 | break; |
796 | case DS_SUSPEND_CARD(((0U) << (((0 +8)+8)+14)) | ((('d')) << (0 +8)) | (((12)) << 0) | ((0) << ((0 +8)+8))): |
797 | ret = CardServices(SuspendCard, s->handle, NULL((void *) 0)); |
798 | break; |
799 | case DS_RESUME_CARD(((0U) << (((0 +8)+8)+14)) | ((('d')) << (0 +8)) | (((13)) << 0) | ((0) << ((0 +8)+8))): |
800 | ret = CardServices(ResumeCard, s->handle, NULL((void *) 0)); |
801 | break; |
802 | case DS_EJECT_CARD(((0U) << (((0 +8)+8)+14)) | ((('d')) << (0 +8)) | (((14)) << 0) | ((0) << ((0 +8)+8))): |
803 | ret = CardServices(EjectCard, s->handle, NULL((void *) 0)); |
804 | break; |
805 | case DS_INSERT_CARD(((0U) << (((0 +8)+8)+14)) | ((('d')) << (0 +8)) | (((15)) << 0) | ((0) << ((0 +8)+8))): |
806 | ret = CardServices(InsertCard, s->handle, NULL((void *) 0)); |
807 | break; |
808 | case DS_ACCESS_CONFIGURATION_REGISTER(((2U|1U) << (((0 +8)+8)+14)) | ((('d')) << (0 +8 )) | (((10)) << 0) | ((sizeof(conf_reg_t)) << ((0 +8)+8))): |
809 | if ((buf.conf_reg.Action == CS_WRITE2) && !capable(CAP_SYS_ADMIN)suser()) |
810 | return -EPERM1; |
811 | ret = CardServices(AccessConfigurationRegister, s->handle, |
812 | &buf.conf_reg); |
813 | break; |
814 | case DS_GET_FIRST_REGION(((2U|1U) << (((0 +8)+8)+14)) | ((('d')) << (0 +8 )) | (((16)) << 0) | ((sizeof(region_info_t)) << ( (0 +8)+8))): |
815 | ret = CardServices(GetFirstRegion, s->handle, &buf.region); |
816 | break; |
817 | case DS_GET_NEXT_REGION(((2U|1U) << (((0 +8)+8)+14)) | ((('d')) << (0 +8 )) | (((17)) << 0) | ((sizeof(region_info_t)) << ( (0 +8)+8))): |
818 | ret = CardServices(GetNextRegion, s->handle, &buf.region); |
819 | break; |
820 | case DS_GET_FIRST_WINDOW(((2U) << (((0 +8)+8)+14)) | ((('d')) << (0 +8)) | (((19)) << 0) | ((sizeof(win_info_t)) << ((0 +8) +8))): |
821 | buf.win_info.handle = (window_handle_t)s->handle; |
822 | ret = CardServices(GetFirstWindow, &buf.win_info.handle, |
823 | &buf.win_info.window); |
824 | break; |
825 | case DS_GET_NEXT_WINDOW(((2U|1U) << (((0 +8)+8)+14)) | ((('d')) << (0 +8 )) | (((20)) << 0) | ((sizeof(win_info_t)) << ((0 +8)+8))): |
826 | ret = CardServices(GetNextWindow, &buf.win_info.handle, |
827 | &buf.win_info.window); |
828 | break; |
829 | case DS_GET_MEM_PAGE(((2U|1U) << (((0 +8)+8)+14)) | ((('d')) << (0 +8 )) | (((21)) << 0) | ((sizeof(win_info_t)) << ((0 +8)+8))): |
830 | ret = CardServices(GetMemPage, buf.win_info.handle, |
831 | &buf.win_info.map); |
832 | break; |
833 | case DS_REPLACE_CIS(((2U|1U) << (((0 +8)+8)+14)) | ((('d')) << (0 +8 )) | (((18)) << 0) | ((sizeof(cisdump_t)) << ((0 + 8)+8))): |
834 | ret = CardServices(ReplaceCIS, s->handle, &buf.cisdump); |
835 | break; |
836 | case DS_BIND_REQUEST(((2U|1U) << (((0 +8)+8)+14)) | ((('d')) << (0 +8 )) | (((60)) << 0) | ((sizeof(bind_info_t)) << (( 0 +8)+8))): |
837 | if (!capable(CAP_SYS_ADMIN)suser()) return -EPERM1; |
838 | err = bind_request(i, &buf.bind_info); |
839 | break; |
840 | case DS_GET_DEVICE_INFO(((2U|1U) << (((0 +8)+8)+14)) | ((('d')) << (0 +8 )) | (((61)) << 0) | ((sizeof(bind_info_t)) << (( 0 +8)+8))): |
841 | err = get_device_info(i, &buf.bind_info, 1); |
842 | break; |
843 | case DS_GET_NEXT_DEVICE(((2U|1U) << (((0 +8)+8)+14)) | ((('d')) << (0 +8 )) | (((62)) << 0) | ((sizeof(bind_info_t)) << (( 0 +8)+8))): |
844 | err = get_device_info(i, &buf.bind_info, 0); |
845 | break; |
846 | case DS_UNBIND_REQUEST(((1U) << (((0 +8)+8)+14)) | ((('d')) << (0 +8)) | (((63)) << 0) | ((sizeof(bind_info_t)) << ((0 +8 )+8))): |
847 | err = unbind_request(i, &buf.bind_info); |
848 | break; |
849 | case DS_BIND_MTD(((2U|1U) << (((0 +8)+8)+14)) | ((('d')) << (0 +8 )) | (((64)) << 0) | ((sizeof(mtd_info_t)) << ((0 +8)+8))): |
850 | if (!capable(CAP_SYS_ADMIN)suser()) return -EPERM1; |
851 | err = bind_mtd(i, &buf.mtd_info); |
852 | break; |
853 | default: |
854 | err = -EINVAL22; |
855 | } |
856 | |
857 | if ((err == 0) && (ret != CS_SUCCESS0x00)) { |
858 | DEBUG(2, "ds_ioctl: ret = %d\n", ret)if (pc_debug>(2)) printk("<7>" "ds_ioctl: ret = %d\n" , ret); |
859 | switch (ret) { |
860 | case CS_BAD_SOCKET0x0b: case CS_NO_CARD0x14: |
861 | err = -ENODEV19; break; |
862 | case CS_BAD_ARGS0x1c: case CS_BAD_ATTRIBUTE0x02: case CS_BAD_IRQ0x06: |
863 | case CS_BAD_TUPLE0x40: |
864 | err = -EINVAL22; break; |
865 | case CS_IN_USE0x1e: |
866 | err = -EBUSY16; break; |
867 | case CS_OUT_OF_RESOURCE0x20: |
868 | err = -ENOSPC28; break; |
869 | case CS_NO_MORE_ITEMS0x1f: |
870 | err = -ENODATA61; break; |
871 | case CS_UNSUPPORTED_FUNCTION0x15: |
872 | err = -ENOSYS38; break; |
873 | default: |
874 | err = -EIO5; break; |
875 | } |
876 | } |
877 | |
878 | #ifndef MACH1 |
879 | if (cmd & IOC_OUT(2U << (((0 +8)+8)+14))) copy_to_user((char *)arg, (char *)&buf, size)memcpy_tofs((char *)arg,(char *)&buf,size); |
880 | #else |
881 | if (cmd & IOC_OUT(2U << (((0 +8)+8)+14))) memcpy((char *) arg, (char *) &buf, size)(__builtin_constant_p(size) ? __constant_memcpy(((char *) arg ),((char *) &buf),(size)) : __memcpy(((char *) arg),((char *) &buf),(size))); |
882 | #endif |
883 | |
884 | return err; |
885 | } /* ds_ioctl */ |
886 | |
887 | /*====================================================================*/ |
888 | |
889 | #ifndef MACH1 |
890 | |
891 | static struct file_operations ds_fops = { |
892 | open: ds_open, |
893 | release: ds_release, |
894 | ioctl: ds_ioctl, |
895 | read: ds_read, |
896 | write: ds_write, |
897 | #if (LINUX_VERSION_CODE131108 < VERSION(2,1,23)(((2)<<16)+(1<<8)+23)) |
898 | select: ds_select |
899 | #else |
900 | poll: ds_poll |
901 | #endif |
902 | }; |
903 | |
904 | #if (LINUX_VERSION_CODE131108 <= VERSION(2,1,17)(((2)<<16)+(1<<8)+17)) |
905 | |
906 | #undef CONFIG_MODVERSIONS |
907 | static struct symbol_table ds_symtab = { |
908 | #include <linux/symtab_begin.h> |
909 | #undef X |
910 | #define X(sym) { (void *)&sym, SYMBOL_NAME_STR(sym)"sym" } |
911 | X(register_pccard_driver), |
912 | X(unregister_pccard_driver), |
913 | #include <linux/symtab_end.h> |
914 | }; |
915 | |
916 | #else |
917 | |
918 | EXPORT_SYMBOL(register_pccard_driver); |
919 | EXPORT_SYMBOL(unregister_pccard_driver); |
920 | |
921 | #endif |
922 | |
923 | #endif /* !defined(MACH) */ |
924 | |
925 | /*====================================================================*/ |
926 | |
927 | int __init init_pcmcia_ds(void) |
928 | { |
929 | client_reg_t client_reg; |
930 | servinfo_t serv; |
931 | bind_req_t bind; |
932 | socket_info_t *s; |
933 | int i, ret; |
934 | |
935 | DEBUG(0, "%s\n", version)if (pc_debug>(0)) printk("<7>" "%s\n", version); |
936 | |
937 | CardServices(GetCardServicesInfo, &serv); |
938 | if (serv.Revision != CS_RELEASE_CODE0x3208) { |
939 | printk(KERN_NOTICE"<5>" "ds: Card Services release does not match!\n"); |
940 | return -EINVAL22; |
941 | } |
942 | if (serv.Count == 0) { |
943 | printk(KERN_NOTICE"<5>" "ds: no socket drivers loaded!\n"); |
944 | return -1; |
945 | } |
946 | |
947 | sockets = serv.Count; |
948 | socket_table = kmalloclinux_kmalloc(sockets*sizeof(socket_info_t), GFP_KERNEL0x03); |
949 | if (!socket_table) return -1; |
950 | for (i = 0, s = socket_table; i < sockets; i++, s++) { |
951 | s->state = 0; |
952 | s->user = NULL((void *) 0); |
953 | s->req_pending = 0; |
954 | init_waitqueue_head(&s->queue)*(&s->queue)=((void *) 0); |
955 | init_waitqueue_head(&s->request)*(&s->request)=((void *) 0); |
956 | s->handle = NULL((void *) 0); |
957 | init_timer(&s->removal); |
958 | s->removal.data = i; |
959 | s->removal.function = &handle_removal; |
960 | s->bind = NULL((void *) 0); |
961 | } |
962 | |
963 | /* Set up hotline to Card Services */ |
964 | client_reg.dev_info = bind.dev_info = &dev_info; |
965 | client_reg.Attributes = INFO_MASTER_CLIENT0x01; |
966 | client_reg.EventMask = |
967 | CS_EVENT_CARD_INSERTION0x000004 | CS_EVENT_CARD_REMOVAL0x000008 | |
968 | CS_EVENT_RESET_PHYSICAL0x000200 | CS_EVENT_CARD_RESET0x000400 | |
969 | CS_EVENT_EJECTION_REQUEST0x010000 | CS_EVENT_INSERTION_REQUEST0x008000 | |
970 | CS_EVENT_PM_SUSPEND0x002000 | CS_EVENT_PM_RESUME0x004000; |
971 | client_reg.event_handler = &ds_event; |
972 | client_reg.Version = 0x0210; |
973 | for (i = 0; i < sockets; i++) { |
974 | bind.Socket = i; |
975 | bind.Function = BIND_FN_ALL0xff; |
976 | ret = CardServices(BindDevice, &bind); |
977 | if (ret != CS_SUCCESS0x00) { |
978 | cs_error(NULL((void *) 0), BindDevice, ret); |
979 | break; |
980 | } |
981 | client_reg.event_callback_args.client_data = &socket_table[i]; |
982 | ret = CardServices(RegisterClient, &socket_table[i].handle, |
983 | &client_reg); |
984 | if (ret != CS_SUCCESS0x00) { |
985 | cs_error(NULL((void *) 0), RegisterClient, ret); |
986 | break; |
987 | } |
988 | } |
989 | |
990 | #ifndef MACH1 |
991 | /* Set up character device for user mode clients */ |
992 | i = register_chrdev(0, "pcmcia", &ds_fops); |
993 | if (i == -EBUSY16) |
994 | printk(KERN_NOTICE"<5>" "unable to find a free device # for " |
995 | "Driver Services\n"); |
996 | else |
997 | major_dev = i; |
998 | register_symtab(&ds_symtab); |
999 | #endif |
1000 | |
1001 | #ifdef HAS_PROC_BUS |
1002 | if (proc_pccard) |
1003 | create_proc_read_entry("drivers", 0, proc_pccard, |
1004 | proc_read_drivers, NULL((void *) 0)); |
1005 | init_status = 0; |
1006 | #endif |
1007 | return 0; |
1008 | } |
1009 | |
1010 | #ifdef MODULE |
1011 | |
1012 | int __init init_module(void) |
1013 | { |
1014 | return init_pcmcia_ds(); |
1015 | } |
1016 | |
1017 | void __exit__attribute__((__used__)) __attribute__((no_instrument_function )) cleanup_module(void) |
1018 | { |
1019 | int i; |
1020 | #ifdef HAS_PROC_BUS |
1021 | if (proc_pccard) |
1022 | remove_proc_entry("drivers", proc_pccard); |
1023 | #endif |
1024 | if (major_dev != -1) |
1025 | unregister_chrdev(major_dev, "pcmcia"); |
1026 | for (i = 0; i < sockets; i++) |
1027 | CardServices(DeregisterClient, socket_table[i].handle); |
1028 | sockets = 0; |
1029 | kfree(socket_table); |
1030 | } |
1031 | |
1032 | #endif |
1033 | |
1034 | /*====================================================================*/ |
1035 | |
1036 | /* Include the interface glue code to GNU Mach. */ |
1037 | #include "../glue/ds.c" |
1038 | |
1039 | /*====================================================================*/ |