Merge master.kernel.org:/home/rmk/linux-2.6-i2c manually
[sfrench/cifs-2.6.git] / drivers / pcmcia / pcmcia_ioctl.c
1 /*
2  * pcmcia_ioctl.c -- ioctl interface for cardmgr and cardctl
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  *
8  * The initial developer of the original code is David A. Hinds
9  * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
10  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
11  *
12  * (C) 1999             David A. Hinds
13  * (C) 2003 - 2004      Dominik Brodowski
14  */
15
16 /*
17  * This file will go away soon.
18  */
19
20
21 #include <linux/config.h>
22 #include <linux/kernel.h>
23 #include <linux/module.h>
24 #include <linux/init.h>
25 #include <linux/major.h>
26 #include <linux/errno.h>
27 #include <linux/ioctl.h>
28 #include <linux/proc_fs.h>
29 #include <linux/poll.h>
30 #include <linux/pci.h>
31 #include <linux/workqueue.h>
32
33 #define IN_CARD_SERVICES
34 #include <pcmcia/cs_types.h>
35 #include <pcmcia/cs.h>
36 #include <pcmcia/cistpl.h>
37 #include <pcmcia/ds.h>
38 #include <pcmcia/ss.h>
39
40 #include "cs_internal.h"
41 #include "ds_internal.h"
42
43 static int major_dev = -1;
44
45
46 /* Device user information */
47 #define MAX_EVENTS      32
48 #define USER_MAGIC      0x7ea4
49 #define CHECK_USER(u) \
50     (((u) == NULL) || ((u)->user_magic != USER_MAGIC))
51
52 typedef struct user_info_t {
53         u_int                   user_magic;
54         int                     event_head, event_tail;
55         event_t                 event[MAX_EVENTS];
56         struct user_info_t      *next;
57         struct pcmcia_socket    *socket;
58 } user_info_t;
59
60
61 #ifdef DEBUG
62 extern int ds_pc_debug;
63 #define cs_socket_name(skt)    ((skt)->dev.class_id)
64
65 #define ds_dbg(lvl, fmt, arg...) do {           \
66         if (ds_pc_debug >= lvl)                         \
67                 printk(KERN_DEBUG "ds: " fmt , ## arg);         \
68 } while (0)
69 #else
70 #define ds_dbg(lvl, fmt, arg...) do { } while (0)
71 #endif
72
73
74 /* backwards-compatible accessing of driver --- by name! */
75
76 static struct pcmcia_driver * get_pcmcia_driver (dev_info_t *dev_info)
77 {
78         struct device_driver *drv;
79         struct pcmcia_driver *p_drv;
80
81         drv = driver_find((char *) dev_info, &pcmcia_bus_type);
82         if (!drv)
83                 return NULL;
84
85         p_drv = container_of(drv, struct pcmcia_driver, drv);
86
87         return (p_drv);
88 }
89
90
91 #ifdef CONFIG_PROC_FS
92 static struct proc_dir_entry *proc_pccard = NULL;
93
94 static int proc_read_drivers_callback(struct device_driver *driver, void *d)
95 {
96         char **p = d;
97         struct pcmcia_driver *p_drv = container_of(driver,
98                                                    struct pcmcia_driver, drv);
99
100         *p += sprintf(*p, "%-24.24s 1 %d\n", p_drv->drv.name,
101 #ifdef CONFIG_MODULE_UNLOAD
102                       (p_drv->owner) ? module_refcount(p_drv->owner) : 1
103 #else
104                       1
105 #endif
106         );
107         d = (void *) p;
108
109         return 0;
110 }
111
112 static int proc_read_drivers(char *buf, char **start, off_t pos,
113                              int count, int *eof, void *data)
114 {
115         char *p = buf;
116
117         bus_for_each_drv(&pcmcia_bus_type, NULL,
118                          (void *) &p, proc_read_drivers_callback);
119
120         return (p - buf);
121 }
122 #endif
123
124 /*======================================================================
125
126     These manage a ring buffer of events pending for one user process
127
128 ======================================================================*/
129
130
131 static int queue_empty(user_info_t *user)
132 {
133     return (user->event_head == user->event_tail);
134 }
135
136 static event_t get_queued_event(user_info_t *user)
137 {
138     user->event_tail = (user->event_tail+1) % MAX_EVENTS;
139     return user->event[user->event_tail];
140 }
141
142 static void queue_event(user_info_t *user, event_t event)
143 {
144     user->event_head = (user->event_head+1) % MAX_EVENTS;
145     if (user->event_head == user->event_tail)
146         user->event_tail = (user->event_tail+1) % MAX_EVENTS;
147     user->event[user->event_head] = event;
148 }
149
150 void handle_event(struct pcmcia_socket *s, event_t event)
151 {
152     user_info_t *user;
153     for (user = s->user; user; user = user->next)
154         queue_event(user, event);
155     wake_up_interruptible(&s->queue);
156 }
157
158
159 /*======================================================================
160
161     bind_request() and bind_device() are merged by now. Register_client()
162     is called right at the end of bind_request(), during the driver's
163     ->attach() call. Individual descriptions:
164
165     bind_request() connects a socket to a particular client driver.
166     It looks up the specified device ID in the list of registered
167     drivers, binds it to the socket, and tries to create an instance
168     of the device.  unbind_request() deletes a driver instance.
169
170     Bind_device() associates a device driver with a particular socket.
171     It is normally called by Driver Services after it has identified
172     a newly inserted card.  An instance of that driver will then be
173     eligible to register as a client of this socket.
174
175     Register_client() uses the dev_info_t handle to match the
176     caller with a socket.  The driver must have already been bound
177     to a socket with bind_device() -- in fact, bind_device()
178     allocates the client structure that will be used.
179
180 ======================================================================*/
181
182 static int bind_request(struct pcmcia_socket *s, bind_info_t *bind_info)
183 {
184         struct pcmcia_driver *p_drv;
185         struct pcmcia_device *p_dev;
186         int ret = 0;
187         unsigned long flags;
188
189         s = pcmcia_get_socket(s);
190         if (!s)
191                 return -EINVAL;
192
193         ds_dbg(2, "bind_request(%d, '%s')\n", s->sock,
194                (char *)bind_info->dev_info);
195
196         p_drv = get_pcmcia_driver(&bind_info->dev_info);
197         if (!p_drv) {
198                 ret = -EINVAL;
199                 goto err_put;
200         }
201
202         if (!try_module_get(p_drv->owner)) {
203                 ret = -EINVAL;
204                 goto err_put_driver;
205         }
206
207         spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
208         list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
209                 if (p_dev->func == bind_info->function) {
210                         if ((p_dev->dev.driver == &p_drv->drv)) {
211                                 if (p_dev->cardmgr) {
212                                         /* if there's already a device
213                                          * registered, and it was registered
214                                          * by userspace before, we need to
215                                          * return the "instance". */
216                                         spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
217                                         bind_info->instance = p_dev->instance;
218                                         ret = -EBUSY;
219                                         goto err_put_module;
220                                 } else {
221                                         /* the correct driver managed to bind
222                                          * itself magically to the correct
223                                          * device. */
224                                         spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
225                                         p_dev->cardmgr = p_drv;
226                                         ret = 0;
227                                         goto err_put_module;
228                                 }
229                         } else if (!p_dev->dev.driver) {
230                                 /* there's already a device available where
231                                  * no device has been bound to yet. So we don't
232                                  * need to register a device! */
233                                 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
234                                 goto rescan;
235                         }
236                 }
237         }
238         spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
239
240         p_dev = pcmcia_device_add(s, bind_info->function);
241         if (!p_dev) {
242                 ret = -EIO;
243                 goto err_put_module;
244         }
245
246 rescan:
247         p_dev->cardmgr = p_drv;
248
249         /* if a driver is already running, we can abort */
250         if (p_dev->dev.driver)
251                 goto err_put_module;
252
253         /*
254          * Prevent this racing with a card insertion.
255          */
256         down(&s->skt_sem);
257         bus_rescan_devices(&pcmcia_bus_type);
258         up(&s->skt_sem);
259
260         /* check whether the driver indeed matched. I don't care if this
261          * is racy or not, because it can only happen on cardmgr access
262          * paths...
263          */
264         if (!(p_dev->dev.driver == &p_drv->drv))
265                 p_dev->cardmgr = NULL;
266
267  err_put_module:
268         module_put(p_drv->owner);
269  err_put_driver:
270         put_driver(&p_drv->drv);
271  err_put:
272         pcmcia_put_socket(s);
273
274         return (ret);
275 } /* bind_request */
276
277 #ifdef CONFIG_CARDBUS
278
279 static struct pci_bus *pcmcia_lookup_bus(struct pcmcia_socket *s)
280 {
281         if (!s || !(s->state & SOCKET_CARDBUS))
282                 return NULL;
283
284         return s->cb_dev->subordinate;
285 }
286 #endif
287
288 static int get_device_info(struct pcmcia_socket *s, bind_info_t *bind_info, int first)
289 {
290         dev_node_t *node;
291         struct pcmcia_device *p_dev;
292         unsigned long flags;
293         int ret = 0;
294
295 #ifdef CONFIG_CARDBUS
296         /*
297          * Some unbelievably ugly code to associate the PCI cardbus
298          * device and its driver with the PCMCIA "bind" information.
299          */
300         {
301                 struct pci_bus *bus;
302
303                 bus = pcmcia_lookup_bus(s);
304                 if (bus) {
305                         struct list_head *list;
306                         struct pci_dev *dev = NULL;
307
308                         list = bus->devices.next;
309                         while (list != &bus->devices) {
310                                 struct pci_dev *pdev = pci_dev_b(list);
311                                 list = list->next;
312
313                                 if (first) {
314                                         dev = pdev;
315                                         break;
316                                 }
317
318                                 /* Try to handle "next" here some way? */
319                         }
320                         if (dev && dev->driver) {
321                                 strlcpy(bind_info->name, dev->driver->name, DEV_NAME_LEN);
322                                 bind_info->major = 0;
323                                 bind_info->minor = 0;
324                                 bind_info->next = NULL;
325                                 return 0;
326                         }
327                 }
328         }
329 #endif
330
331         spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
332         list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
333                 if (p_dev->func == bind_info->function) {
334                         p_dev = pcmcia_get_dev(p_dev);
335                         if (!p_dev)
336                                 continue;
337                         goto found;
338                 }
339         }
340         spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
341         return -ENODEV;
342
343  found:
344         spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
345
346         if ((!p_dev->instance) ||
347             (p_dev->instance->state & DEV_CONFIG_PENDING)) {
348                 ret = -EAGAIN;
349                 goto err_put;
350         }
351
352         if (first)
353                 node = p_dev->instance->dev;
354         else
355                 for (node = p_dev->instance->dev; node; node = node->next)
356                         if (node == bind_info->next)
357                                 break;
358         if (!node) {
359                 ret = -ENODEV;
360                 goto err_put;
361         }
362
363         strlcpy(bind_info->name, node->dev_name, DEV_NAME_LEN);
364         bind_info->major = node->major;
365         bind_info->minor = node->minor;
366         bind_info->next = node->next;
367
368  err_put:
369         pcmcia_put_dev(p_dev);
370         return (ret);
371 } /* get_device_info */
372
373
374 static int ds_open(struct inode *inode, struct file *file)
375 {
376     socket_t i = iminor(inode);
377     struct pcmcia_socket *s;
378     user_info_t *user;
379
380     ds_dbg(0, "ds_open(socket %d)\n", i);
381
382     s = pcmcia_get_socket_by_nr(i);
383     if (!s)
384             return -ENODEV;
385     s = pcmcia_get_socket(s);
386     if (!s)
387             return -ENODEV;
388
389     if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
390             if (s->pcmcia_state.busy) {
391                     pcmcia_put_socket(s);
392                     return -EBUSY;
393             }
394         else
395             s->pcmcia_state.busy = 1;
396     }
397
398     user = kmalloc(sizeof(user_info_t), GFP_KERNEL);
399     if (!user) {
400             pcmcia_put_socket(s);
401             return -ENOMEM;
402     }
403     user->event_tail = user->event_head = 0;
404     user->next = s->user;
405     user->user_magic = USER_MAGIC;
406     user->socket = s;
407     s->user = user;
408     file->private_data = user;
409
410     if (s->pcmcia_state.present)
411         queue_event(user, CS_EVENT_CARD_INSERTION);
412     return 0;
413 } /* ds_open */
414
415 /*====================================================================*/
416
417 static int ds_release(struct inode *inode, struct file *file)
418 {
419     struct pcmcia_socket *s;
420     user_info_t *user, **link;
421
422     ds_dbg(0, "ds_release(socket %d)\n", iminor(inode));
423
424     user = file->private_data;
425     if (CHECK_USER(user))
426         goto out;
427
428     s = user->socket;
429
430     /* Unlink user data structure */
431     if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
432         s->pcmcia_state.busy = 0;
433     }
434     file->private_data = NULL;
435     for (link = &s->user; *link; link = &(*link)->next)
436         if (*link == user) break;
437     if (link == NULL)
438         goto out;
439     *link = user->next;
440     user->user_magic = 0;
441     kfree(user);
442     pcmcia_put_socket(s);
443 out:
444     return 0;
445 } /* ds_release */
446
447 /*====================================================================*/
448
449 static ssize_t ds_read(struct file *file, char __user *buf,
450                        size_t count, loff_t *ppos)
451 {
452     struct pcmcia_socket *s;
453     user_info_t *user;
454     int ret;
455
456     ds_dbg(2, "ds_read(socket %d)\n", iminor(file->f_dentry->d_inode));
457
458     if (count < 4)
459         return -EINVAL;
460
461     user = file->private_data;
462     if (CHECK_USER(user))
463         return -EIO;
464
465     s = user->socket;
466     if (s->pcmcia_state.dead)
467         return -EIO;
468
469     ret = wait_event_interruptible(s->queue, !queue_empty(user));
470     if (ret == 0)
471         ret = put_user(get_queued_event(user), (int __user *)buf) ? -EFAULT : 4;
472
473     return ret;
474 } /* ds_read */
475
476 /*====================================================================*/
477
478 static ssize_t ds_write(struct file *file, const char __user *buf,
479                         size_t count, loff_t *ppos)
480 {
481     ds_dbg(2, "ds_write(socket %d)\n", iminor(file->f_dentry->d_inode));
482
483     if (count != 4)
484         return -EINVAL;
485     if ((file->f_flags & O_ACCMODE) == O_RDONLY)
486         return -EBADF;
487
488     return -EIO;
489 } /* ds_write */
490
491 /*====================================================================*/
492
493 /* No kernel lock - fine */
494 static u_int ds_poll(struct file *file, poll_table *wait)
495 {
496     struct pcmcia_socket *s;
497     user_info_t *user;
498
499     ds_dbg(2, "ds_poll(socket %d)\n", iminor(file->f_dentry->d_inode));
500
501     user = file->private_data;
502     if (CHECK_USER(user))
503         return POLLERR;
504     s = user->socket;
505     /*
506      * We don't check for a dead socket here since that
507      * will send cardmgr into an endless spin.
508      */
509     poll_wait(file, &s->queue, wait);
510     if (!queue_empty(user))
511         return POLLIN | POLLRDNORM;
512     return 0;
513 } /* ds_poll */
514
515 /*====================================================================*/
516
517 extern int pcmcia_adjust_resource_info(adjust_t *adj);
518
519 static int ds_ioctl(struct inode * inode, struct file * file,
520                     u_int cmd, u_long arg)
521 {
522     struct pcmcia_socket *s;
523     void __user *uarg = (char __user *)arg;
524     u_int size;
525     int ret, err;
526     ds_ioctl_arg_t *buf;
527     user_info_t *user;
528
529     ds_dbg(2, "ds_ioctl(socket %d, %#x, %#lx)\n", iminor(inode), cmd, arg);
530
531     user = file->private_data;
532     if (CHECK_USER(user))
533         return -EIO;
534
535     s = user->socket;
536     if (s->pcmcia_state.dead)
537         return -EIO;
538
539     size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
540     if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL;
541
542     /* Permission check */
543     if (!(cmd & IOC_OUT) && !capable(CAP_SYS_ADMIN))
544         return -EPERM;
545
546     if (cmd & IOC_IN) {
547         if (!access_ok(VERIFY_READ, uarg, size)) {
548             ds_dbg(3, "ds_ioctl(): verify_read = %d\n", -EFAULT);
549             return -EFAULT;
550         }
551     }
552     if (cmd & IOC_OUT) {
553         if (!access_ok(VERIFY_WRITE, uarg, size)) {
554             ds_dbg(3, "ds_ioctl(): verify_write = %d\n", -EFAULT);
555             return -EFAULT;
556         }
557     }
558     buf = kmalloc(sizeof(ds_ioctl_arg_t), GFP_KERNEL);
559     if (!buf)
560         return -ENOMEM;
561
562     err = ret = 0;
563
564     if (cmd & IOC_IN) __copy_from_user((char *)buf, uarg, size);
565
566     switch (cmd) {
567     case DS_ADJUST_RESOURCE_INFO:
568         ret = pcmcia_adjust_resource_info(&buf->adjust);
569         break;
570     case DS_GET_CONFIGURATION_INFO:
571         if (buf->config.Function &&
572            (buf->config.Function >= s->functions))
573             ret = CS_BAD_ARGS;
574         else
575             ret = pccard_get_configuration_info(s,
576                         buf->config.Function, &buf->config);
577         break;
578     case DS_GET_FIRST_TUPLE:
579         down(&s->skt_sem);
580         pcmcia_validate_mem(s);
581         up(&s->skt_sem);
582         ret = pccard_get_first_tuple(s, BIND_FN_ALL, &buf->tuple);
583         break;
584     case DS_GET_NEXT_TUPLE:
585         ret = pccard_get_next_tuple(s, BIND_FN_ALL, &buf->tuple);
586         break;
587     case DS_GET_TUPLE_DATA:
588         buf->tuple.TupleData = buf->tuple_parse.data;
589         buf->tuple.TupleDataMax = sizeof(buf->tuple_parse.data);
590         ret = pccard_get_tuple_data(s, &buf->tuple);
591         break;
592     case DS_PARSE_TUPLE:
593         buf->tuple.TupleData = buf->tuple_parse.data;
594         ret = pccard_parse_tuple(&buf->tuple, &buf->tuple_parse.parse);
595         break;
596     case DS_RESET_CARD:
597         ret = pccard_reset_card(s);
598         break;
599     case DS_GET_STATUS:
600         if (buf->status.Function &&
601            (buf->status.Function >= s->functions))
602             ret = CS_BAD_ARGS;
603         else
604         ret = pccard_get_status(s, buf->status.Function, &buf->status);
605         break;
606     case DS_VALIDATE_CIS:
607         down(&s->skt_sem);
608         pcmcia_validate_mem(s);
609         up(&s->skt_sem);
610         ret = pccard_validate_cis(s, BIND_FN_ALL, &buf->cisinfo);
611         break;
612     case DS_SUSPEND_CARD:
613         ret = pcmcia_suspend_card(s);
614         break;
615     case DS_RESUME_CARD:
616         ret = pcmcia_resume_card(s);
617         break;
618     case DS_EJECT_CARD:
619         err = pcmcia_eject_card(s);
620         break;
621     case DS_INSERT_CARD:
622         err = pcmcia_insert_card(s);
623         break;
624     case DS_ACCESS_CONFIGURATION_REGISTER:
625         if ((buf->conf_reg.Action == CS_WRITE) && !capable(CAP_SYS_ADMIN)) {
626             err = -EPERM;
627             goto free_out;
628         }
629         if (buf->conf_reg.Function &&
630            (buf->conf_reg.Function >= s->functions))
631             ret = CS_BAD_ARGS;
632         else
633             ret = pccard_access_configuration_register(s,
634                         buf->conf_reg.Function, &buf->conf_reg);
635         break;
636     case DS_GET_FIRST_REGION:
637     case DS_GET_NEXT_REGION:
638     case DS_BIND_MTD:
639         if (!capable(CAP_SYS_ADMIN)) {
640                 err = -EPERM;
641                 goto free_out;
642         } else {
643                 static int printed = 0;
644                 if (!printed) {
645                         printk(KERN_WARNING "2.6. kernels use pcmciamtd instead of memory_cs.c and do not require special\n");
646                         printk(KERN_WARNING "MTD handling any more.\n");
647                         printed++;
648                 }
649         }
650         err = -EINVAL;
651         goto free_out;
652         break;
653     case DS_GET_FIRST_WINDOW:
654         ret = pcmcia_get_window(s, &buf->win_info.handle, 0,
655                         &buf->win_info.window);
656         break;
657     case DS_GET_NEXT_WINDOW:
658         ret = pcmcia_get_window(s, &buf->win_info.handle,
659                         buf->win_info.handle->index + 1, &buf->win_info.window);
660         break;
661     case DS_GET_MEM_PAGE:
662         ret = pcmcia_get_mem_page(buf->win_info.handle,
663                            &buf->win_info.map);
664         break;
665     case DS_REPLACE_CIS:
666         ret = pcmcia_replace_cis(s, &buf->cisdump);
667         break;
668     case DS_BIND_REQUEST:
669         if (!capable(CAP_SYS_ADMIN)) {
670                 err = -EPERM;
671                 goto free_out;
672         }
673         err = bind_request(s, &buf->bind_info);
674         break;
675     case DS_GET_DEVICE_INFO:
676         err = get_device_info(s, &buf->bind_info, 1);
677         break;
678     case DS_GET_NEXT_DEVICE:
679         err = get_device_info(s, &buf->bind_info, 0);
680         break;
681     case DS_UNBIND_REQUEST:
682         err = 0;
683         break;
684     default:
685         err = -EINVAL;
686     }
687
688     if ((err == 0) && (ret != CS_SUCCESS)) {
689         ds_dbg(2, "ds_ioctl: ret = %d\n", ret);
690         switch (ret) {
691         case CS_BAD_SOCKET: case CS_NO_CARD:
692             err = -ENODEV; break;
693         case CS_BAD_ARGS: case CS_BAD_ATTRIBUTE: case CS_BAD_IRQ:
694         case CS_BAD_TUPLE:
695             err = -EINVAL; break;
696         case CS_IN_USE:
697             err = -EBUSY; break;
698         case CS_OUT_OF_RESOURCE:
699             err = -ENOSPC; break;
700         case CS_NO_MORE_ITEMS:
701             err = -ENODATA; break;
702         case CS_UNSUPPORTED_FUNCTION:
703             err = -ENOSYS; break;
704         default:
705             err = -EIO; break;
706         }
707     }
708
709     if (cmd & IOC_OUT) {
710         if (__copy_to_user(uarg, (char *)buf, size))
711             err = -EFAULT;
712     }
713
714 free_out:
715     kfree(buf);
716     return err;
717 } /* ds_ioctl */
718
719 /*====================================================================*/
720
721 static struct file_operations ds_fops = {
722         .owner          = THIS_MODULE,
723         .open           = ds_open,
724         .release        = ds_release,
725         .ioctl          = ds_ioctl,
726         .read           = ds_read,
727         .write          = ds_write,
728         .poll           = ds_poll,
729 };
730
731 void __init pcmcia_setup_ioctl(void) {
732         int i;
733
734         /* Set up character device for user mode clients */
735         i = register_chrdev(0, "pcmcia", &ds_fops);
736         if (i < 0)
737                 printk(KERN_NOTICE "unable to find a free device # for "
738                        "Driver Services (error=%d)\n", i);
739         else
740                 major_dev = i;
741
742 #ifdef CONFIG_PROC_FS
743         proc_pccard = proc_mkdir("pccard", proc_bus);
744         if (proc_pccard)
745                 create_proc_read_entry("drivers",0,proc_pccard,proc_read_drivers,NULL);
746 #endif
747 }
748
749
750 void __exit pcmcia_cleanup_ioctl(void) {
751 #ifdef CONFIG_PROC_FS
752         if (proc_pccard) {
753                 remove_proc_entry("drivers", proc_pccard);
754                 remove_proc_entry("pccard", proc_bus);
755         }
756 #endif
757         if (major_dev != -1)
758                 unregister_chrdev(major_dev, "pcmcia");
759 }