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