]> pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/pcmcia/pcmcia_ioctl.c
fa2a79d29e165b90193cb04da73d1dedeb061f5f
[linux-2.6-omap-h63xx.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/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_CARD_SERVICES_INFO:
572         ret = pcmcia_get_card_services_info(&buf->servinfo);
573         break;
574     case DS_GET_CONFIGURATION_INFO:
575         if (buf->config.Function &&
576            (buf->config.Function >= s->functions))
577             ret = CS_BAD_ARGS;
578         else
579             ret = pccard_get_configuration_info(s,
580                         buf->config.Function, &buf->config);
581         break;
582     case DS_GET_FIRST_TUPLE:
583         down(&s->skt_sem);
584         pcmcia_validate_mem(s);
585         up(&s->skt_sem);
586         ret = pccard_get_first_tuple(s, BIND_FN_ALL, &buf->tuple);
587         break;
588     case DS_GET_NEXT_TUPLE:
589         ret = pccard_get_next_tuple(s, BIND_FN_ALL, &buf->tuple);
590         break;
591     case DS_GET_TUPLE_DATA:
592         buf->tuple.TupleData = buf->tuple_parse.data;
593         buf->tuple.TupleDataMax = sizeof(buf->tuple_parse.data);
594         ret = pccard_get_tuple_data(s, &buf->tuple);
595         break;
596     case DS_PARSE_TUPLE:
597         buf->tuple.TupleData = buf->tuple_parse.data;
598         ret = pccard_parse_tuple(&buf->tuple, &buf->tuple_parse.parse);
599         break;
600     case DS_RESET_CARD:
601         ret = pccard_reset_card(s);
602         break;
603     case DS_GET_STATUS:
604         if (buf->status.Function &&
605            (buf->status.Function >= s->functions))
606             ret = CS_BAD_ARGS;
607         else
608         ret = pccard_get_status(s, buf->status.Function, &buf->status);
609         break;
610     case DS_VALIDATE_CIS:
611         down(&s->skt_sem);
612         pcmcia_validate_mem(s);
613         up(&s->skt_sem);
614         ret = pccard_validate_cis(s, BIND_FN_ALL, &buf->cisinfo);
615         break;
616     case DS_SUSPEND_CARD:
617         ret = pcmcia_suspend_card(s);
618         break;
619     case DS_RESUME_CARD:
620         ret = pcmcia_resume_card(s);
621         break;
622     case DS_EJECT_CARD:
623         err = pcmcia_eject_card(s);
624         break;
625     case DS_INSERT_CARD:
626         err = pcmcia_insert_card(s);
627         break;
628     case DS_ACCESS_CONFIGURATION_REGISTER:
629         if ((buf->conf_reg.Action == CS_WRITE) && !capable(CAP_SYS_ADMIN)) {
630             err = -EPERM;
631             goto free_out;
632         }
633         if (buf->conf_reg.Function &&
634            (buf->conf_reg.Function >= s->functions))
635             ret = CS_BAD_ARGS;
636         else
637             ret = pccard_access_configuration_register(s,
638                         buf->conf_reg.Function, &buf->conf_reg);
639         break;
640     case DS_GET_FIRST_REGION:
641     case DS_GET_NEXT_REGION:
642     case DS_BIND_MTD:
643         if (!capable(CAP_SYS_ADMIN)) {
644                 err = -EPERM;
645                 goto free_out;
646         } else {
647                 static int printed = 0;
648                 if (!printed) {
649                         printk(KERN_WARNING "2.6. kernels use pcmciamtd instead of memory_cs.c and do not require special\n");
650                         printk(KERN_WARNING "MTD handling any more.\n");
651                         printed++;
652                 }
653         }
654         err = -EINVAL;
655         goto free_out;
656         break;
657     case DS_GET_FIRST_WINDOW:
658         ret = pcmcia_get_window(s, &buf->win_info.handle, 0,
659                         &buf->win_info.window);
660         break;
661     case DS_GET_NEXT_WINDOW:
662         ret = pcmcia_get_window(s, &buf->win_info.handle,
663                         buf->win_info.handle->index + 1, &buf->win_info.window);
664         break;
665     case DS_GET_MEM_PAGE:
666         ret = pcmcia_get_mem_page(buf->win_info.handle,
667                            &buf->win_info.map);
668         break;
669     case DS_REPLACE_CIS:
670         ret = pcmcia_replace_cis(s, &buf->cisdump);
671         break;
672     case DS_BIND_REQUEST:
673         if (!capable(CAP_SYS_ADMIN)) {
674                 err = -EPERM;
675                 goto free_out;
676         }
677         err = bind_request(s, &buf->bind_info);
678         break;
679     case DS_GET_DEVICE_INFO:
680         err = get_device_info(s, &buf->bind_info, 1);
681         break;
682     case DS_GET_NEXT_DEVICE:
683         err = get_device_info(s, &buf->bind_info, 0);
684         break;
685     case DS_UNBIND_REQUEST:
686         err = 0;
687         break;
688     default:
689         err = -EINVAL;
690     }
691
692     if ((err == 0) && (ret != CS_SUCCESS)) {
693         ds_dbg(2, "ds_ioctl: ret = %d\n", ret);
694         switch (ret) {
695         case CS_BAD_SOCKET: case CS_NO_CARD:
696             err = -ENODEV; break;
697         case CS_BAD_ARGS: case CS_BAD_ATTRIBUTE: case CS_BAD_IRQ:
698         case CS_BAD_TUPLE:
699             err = -EINVAL; break;
700         case CS_IN_USE:
701             err = -EBUSY; break;
702         case CS_OUT_OF_RESOURCE:
703             err = -ENOSPC; break;
704         case CS_NO_MORE_ITEMS:
705             err = -ENODATA; break;
706         case CS_UNSUPPORTED_FUNCTION:
707             err = -ENOSYS; break;
708         default:
709             err = -EIO; break;
710         }
711     }
712
713     if (cmd & IOC_OUT) {
714         if (__copy_to_user(uarg, (char *)buf, size))
715             err = -EFAULT;
716     }
717
718 free_out:
719     kfree(buf);
720     return err;
721 } /* ds_ioctl */
722
723 /*====================================================================*/
724
725 static struct file_operations ds_fops = {
726         .owner          = THIS_MODULE,
727         .open           = ds_open,
728         .release        = ds_release,
729         .ioctl          = ds_ioctl,
730         .read           = ds_read,
731         .write          = ds_write,
732         .poll           = ds_poll,
733 };
734
735 void __init pcmcia_setup_ioctl(void) {
736         int i;
737
738         /* Set up character device for user mode clients */
739         i = register_chrdev(0, "pcmcia", &ds_fops);
740         if (i == -EBUSY)
741                 printk(KERN_NOTICE "unable to find a free device # for "
742                        "Driver Services\n");
743         else
744                 major_dev = i;
745
746 #ifdef CONFIG_PROC_FS
747         proc_pccard = proc_mkdir("pccard", proc_bus);
748         if (proc_pccard)
749                 create_proc_read_entry("drivers",0,proc_pccard,proc_read_drivers,NULL);
750 #endif
751 }
752
753
754 void __exit pcmcia_cleanup_ioctl(void) {
755 #ifdef CONFIG_PROC_FS
756         if (proc_pccard) {
757                 remove_proc_entry("drivers", proc_pccard);
758                 remove_proc_entry("pccard", proc_bus);
759         }
760 #endif
761         if (major_dev != -1)
762                 unregister_chrdev(major_dev, "pcmcia");
763 }