Linux 2.6.17.7
[linux/fpc-iii.git] / drivers / pcmcia / pcmcia_ioctl.c
blob738b1ef595a3506fd595f9f742da4c6f966b7e47
1 /*
2 * pcmcia_ioctl.c -- ioctl interface for cardmgr and cardctl
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.
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.
12 * (C) 1999 David A. Hinds
13 * (C) 2003 - 2004 Dominik Brodowski
17 * This file will go away soon.
21 #include <linux/kernel.h>
22 #include <linux/module.h>
23 #include <linux/init.h>
24 #include <linux/major.h>
25 #include <linux/errno.h>
26 #include <linux/ioctl.h>
27 #include <linux/proc_fs.h>
28 #include <linux/poll.h>
29 #include <linux/pci.h>
30 #include <linux/workqueue.h>
32 #define IN_CARD_SERVICES
33 #include <pcmcia/cs_types.h>
34 #include <pcmcia/cs.h>
35 #include <pcmcia/cistpl.h>
36 #include <pcmcia/ds.h>
37 #include <pcmcia/ss.h>
39 #include "cs_internal.h"
40 #include "ds_internal.h"
42 static int major_dev = -1;
45 /* Device user information */
46 #define MAX_EVENTS 32
47 #define USER_MAGIC 0x7ea4
48 #define CHECK_USER(u) \
49 (((u) == NULL) || ((u)->user_magic != USER_MAGIC))
51 typedef struct user_info_t {
52 u_int user_magic;
53 int event_head, event_tail;
54 event_t event[MAX_EVENTS];
55 struct user_info_t *next;
56 struct pcmcia_socket *socket;
57 } user_info_t;
60 #ifdef DEBUG
61 extern int ds_pc_debug;
62 #define cs_socket_name(skt) ((skt)->dev.class_id)
64 #define ds_dbg(lvl, fmt, arg...) do { \
65 if (ds_pc_debug >= lvl) \
66 printk(KERN_DEBUG "ds: " fmt , ## arg); \
67 } while (0)
68 #else
69 #define ds_dbg(lvl, fmt, arg...) do { } while (0)
70 #endif
72 static struct pcmcia_device *get_pcmcia_device(struct pcmcia_socket *s,
73 unsigned int function)
75 struct pcmcia_device *p_dev = NULL;
76 unsigned long flags;
78 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
79 list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
80 if (p_dev->func == function) {
81 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
82 return pcmcia_get_dev(p_dev);
85 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
86 return NULL;
89 /* backwards-compatible accessing of driver --- by name! */
91 static struct pcmcia_driver *get_pcmcia_driver(dev_info_t *dev_info)
93 struct device_driver *drv;
94 struct pcmcia_driver *p_drv;
96 drv = driver_find((char *) dev_info, &pcmcia_bus_type);
97 if (!drv)
98 return NULL;
100 p_drv = container_of(drv, struct pcmcia_driver, drv);
102 return (p_drv);
106 #ifdef CONFIG_PROC_FS
107 static struct proc_dir_entry *proc_pccard = NULL;
109 static int proc_read_drivers_callback(struct device_driver *driver, void *d)
111 char **p = d;
112 struct pcmcia_driver *p_drv = container_of(driver,
113 struct pcmcia_driver, drv);
115 *p += sprintf(*p, "%-24.24s 1 %d\n", p_drv->drv.name,
116 #ifdef CONFIG_MODULE_UNLOAD
117 (p_drv->owner) ? module_refcount(p_drv->owner) : 1
118 #else
120 #endif
122 d = (void *) p;
124 return 0;
127 static int proc_read_drivers(char *buf, char **start, off_t pos,
128 int count, int *eof, void *data)
130 char *p = buf;
132 bus_for_each_drv(&pcmcia_bus_type, NULL,
133 (void *) &p, proc_read_drivers_callback);
135 return (p - buf);
137 #endif
139 /*======================================================================
141 These manage a ring buffer of events pending for one user process
143 ======================================================================*/
146 static int queue_empty(user_info_t *user)
148 return (user->event_head == user->event_tail);
151 static event_t get_queued_event(user_info_t *user)
153 user->event_tail = (user->event_tail+1) % MAX_EVENTS;
154 return user->event[user->event_tail];
157 static void queue_event(user_info_t *user, event_t event)
159 user->event_head = (user->event_head+1) % MAX_EVENTS;
160 if (user->event_head == user->event_tail)
161 user->event_tail = (user->event_tail+1) % MAX_EVENTS;
162 user->event[user->event_head] = event;
165 void handle_event(struct pcmcia_socket *s, event_t event)
167 user_info_t *user;
168 for (user = s->user; user; user = user->next)
169 queue_event(user, event);
170 wake_up_interruptible(&s->queue);
174 /*======================================================================
176 bind_request() and bind_device() are merged by now. Register_client()
177 is called right at the end of bind_request(), during the driver's
178 ->attach() call. Individual descriptions:
180 bind_request() connects a socket to a particular client driver.
181 It looks up the specified device ID in the list of registered
182 drivers, binds it to the socket, and tries to create an instance
183 of the device. unbind_request() deletes a driver instance.
185 Bind_device() associates a device driver with a particular socket.
186 It is normally called by Driver Services after it has identified
187 a newly inserted card. An instance of that driver will then be
188 eligible to register as a client of this socket.
190 Register_client() uses the dev_info_t handle to match the
191 caller with a socket. The driver must have already been bound
192 to a socket with bind_device() -- in fact, bind_device()
193 allocates the client structure that will be used.
195 ======================================================================*/
197 static int bind_request(struct pcmcia_socket *s, bind_info_t *bind_info)
199 struct pcmcia_driver *p_drv;
200 struct pcmcia_device *p_dev;
201 int ret = 0;
202 unsigned long flags;
204 s = pcmcia_get_socket(s);
205 if (!s)
206 return -EINVAL;
208 ds_dbg(2, "bind_request(%d, '%s')\n", s->sock,
209 (char *)bind_info->dev_info);
211 p_drv = get_pcmcia_driver(&bind_info->dev_info);
212 if (!p_drv) {
213 ret = -EINVAL;
214 goto err_put;
217 if (!try_module_get(p_drv->owner)) {
218 ret = -EINVAL;
219 goto err_put_driver;
222 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
223 list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
224 if (p_dev->func == bind_info->function) {
225 if ((p_dev->dev.driver == &p_drv->drv)) {
226 if (p_dev->cardmgr) {
227 /* if there's already a device
228 * registered, and it was registered
229 * by userspace before, we need to
230 * return the "instance". */
231 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
232 bind_info->instance = p_dev;
233 ret = -EBUSY;
234 goto err_put_module;
235 } else {
236 /* the correct driver managed to bind
237 * itself magically to the correct
238 * device. */
239 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
240 p_dev->cardmgr = p_drv;
241 ret = 0;
242 goto err_put_module;
244 } else if (!p_dev->dev.driver) {
245 /* there's already a device available where
246 * no device has been bound to yet. So we don't
247 * need to register a device! */
248 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
249 goto rescan;
253 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
255 p_dev = pcmcia_device_add(s, bind_info->function);
256 if (!p_dev) {
257 ret = -EIO;
258 goto err_put_module;
261 rescan:
262 p_dev->cardmgr = p_drv;
264 /* if a driver is already running, we can abort */
265 if (p_dev->dev.driver)
266 goto err_put_module;
269 * Prevent this racing with a card insertion.
271 mutex_lock(&s->skt_mutex);
272 bus_rescan_devices(&pcmcia_bus_type);
273 mutex_unlock(&s->skt_mutex);
275 /* check whether the driver indeed matched. I don't care if this
276 * is racy or not, because it can only happen on cardmgr access
277 * paths...
279 if (!(p_dev->dev.driver == &p_drv->drv))
280 p_dev->cardmgr = NULL;
282 err_put_module:
283 module_put(p_drv->owner);
284 err_put_driver:
285 put_driver(&p_drv->drv);
286 err_put:
287 pcmcia_put_socket(s);
289 return (ret);
290 } /* bind_request */
292 #ifdef CONFIG_CARDBUS
294 static struct pci_bus *pcmcia_lookup_bus(struct pcmcia_socket *s)
296 if (!s || !(s->state & SOCKET_CARDBUS))
297 return NULL;
299 return s->cb_dev->subordinate;
301 #endif
303 static int get_device_info(struct pcmcia_socket *s, bind_info_t *bind_info, int first)
305 dev_node_t *node;
306 struct pcmcia_device *p_dev;
307 struct pcmcia_driver *p_drv;
308 unsigned long flags;
309 int ret = 0;
311 #ifdef CONFIG_CARDBUS
313 * Some unbelievably ugly code to associate the PCI cardbus
314 * device and its driver with the PCMCIA "bind" information.
317 struct pci_bus *bus;
319 bus = pcmcia_lookup_bus(s);
320 if (bus) {
321 struct list_head *list;
322 struct pci_dev *dev = NULL;
324 list = bus->devices.next;
325 while (list != &bus->devices) {
326 struct pci_dev *pdev = pci_dev_b(list);
327 list = list->next;
329 if (first) {
330 dev = pdev;
331 break;
334 /* Try to handle "next" here some way? */
336 if (dev && dev->driver) {
337 strlcpy(bind_info->name, dev->driver->name, DEV_NAME_LEN);
338 bind_info->major = 0;
339 bind_info->minor = 0;
340 bind_info->next = NULL;
341 return 0;
345 #endif
347 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
348 list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
349 if (p_dev->func == bind_info->function) {
350 p_dev = pcmcia_get_dev(p_dev);
351 if (!p_dev)
352 continue;
353 goto found;
356 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
357 return -ENODEV;
359 found:
360 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
362 p_drv = to_pcmcia_drv(p_dev->dev.driver);
363 if (p_drv && !p_dev->_locked) {
364 ret = -EAGAIN;
365 goto err_put;
368 if (first)
369 node = p_dev->dev_node;
370 else
371 for (node = p_dev->dev_node; node; node = node->next)
372 if (node == bind_info->next)
373 break;
374 if (!node) {
375 ret = -ENODEV;
376 goto err_put;
379 strlcpy(bind_info->name, node->dev_name, DEV_NAME_LEN);
380 bind_info->major = node->major;
381 bind_info->minor = node->minor;
382 bind_info->next = node->next;
384 err_put:
385 pcmcia_put_dev(p_dev);
386 return (ret);
387 } /* get_device_info */
390 static int ds_open(struct inode *inode, struct file *file)
392 socket_t i = iminor(inode);
393 struct pcmcia_socket *s;
394 user_info_t *user;
395 static int warning_printed = 0;
397 ds_dbg(0, "ds_open(socket %d)\n", i);
399 s = pcmcia_get_socket_by_nr(i);
400 if (!s)
401 return -ENODEV;
402 s = pcmcia_get_socket(s);
403 if (!s)
404 return -ENODEV;
406 if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
407 if (s->pcmcia_state.busy) {
408 pcmcia_put_socket(s);
409 return -EBUSY;
411 else
412 s->pcmcia_state.busy = 1;
415 user = kmalloc(sizeof(user_info_t), GFP_KERNEL);
416 if (!user) {
417 pcmcia_put_socket(s);
418 return -ENOMEM;
420 user->event_tail = user->event_head = 0;
421 user->next = s->user;
422 user->user_magic = USER_MAGIC;
423 user->socket = s;
424 s->user = user;
425 file->private_data = user;
427 if (!warning_printed) {
428 printk(KERN_INFO "pcmcia: Detected deprecated PCMCIA ioctl "
429 "usage from process: %s.\n", current->comm);
430 printk(KERN_INFO "pcmcia: This interface will soon be removed from "
431 "the kernel; please expect breakage unless you upgrade "
432 "to new tools.\n");
433 printk(KERN_INFO "pcmcia: see http://www.kernel.org/pub/linux/"
434 "utils/kernel/pcmcia/pcmcia.html for details.\n");
435 warning_printed = 1;
438 if (s->pcmcia_state.present)
439 queue_event(user, CS_EVENT_CARD_INSERTION);
440 return 0;
441 } /* ds_open */
443 /*====================================================================*/
445 static int ds_release(struct inode *inode, struct file *file)
447 struct pcmcia_socket *s;
448 user_info_t *user, **link;
450 ds_dbg(0, "ds_release(socket %d)\n", iminor(inode));
452 user = file->private_data;
453 if (CHECK_USER(user))
454 goto out;
456 s = user->socket;
458 /* Unlink user data structure */
459 if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
460 s->pcmcia_state.busy = 0;
462 file->private_data = NULL;
463 for (link = &s->user; *link; link = &(*link)->next)
464 if (*link == user) break;
465 if (link == NULL)
466 goto out;
467 *link = user->next;
468 user->user_magic = 0;
469 kfree(user);
470 pcmcia_put_socket(s);
471 out:
472 return 0;
473 } /* ds_release */
475 /*====================================================================*/
477 static ssize_t ds_read(struct file *file, char __user *buf,
478 size_t count, loff_t *ppos)
480 struct pcmcia_socket *s;
481 user_info_t *user;
482 int ret;
484 ds_dbg(2, "ds_read(socket %d)\n", iminor(file->f_dentry->d_inode));
486 if (count < 4)
487 return -EINVAL;
489 user = file->private_data;
490 if (CHECK_USER(user))
491 return -EIO;
493 s = user->socket;
494 if (s->pcmcia_state.dead)
495 return -EIO;
497 ret = wait_event_interruptible(s->queue, !queue_empty(user));
498 if (ret == 0)
499 ret = put_user(get_queued_event(user), (int __user *)buf) ? -EFAULT : 4;
501 return ret;
502 } /* ds_read */
504 /*====================================================================*/
506 static ssize_t ds_write(struct file *file, const char __user *buf,
507 size_t count, loff_t *ppos)
509 ds_dbg(2, "ds_write(socket %d)\n", iminor(file->f_dentry->d_inode));
511 if (count != 4)
512 return -EINVAL;
513 if ((file->f_flags & O_ACCMODE) == O_RDONLY)
514 return -EBADF;
516 return -EIO;
517 } /* ds_write */
519 /*====================================================================*/
521 /* No kernel lock - fine */
522 static u_int ds_poll(struct file *file, poll_table *wait)
524 struct pcmcia_socket *s;
525 user_info_t *user;
527 ds_dbg(2, "ds_poll(socket %d)\n", iminor(file->f_dentry->d_inode));
529 user = file->private_data;
530 if (CHECK_USER(user))
531 return POLLERR;
532 s = user->socket;
534 * We don't check for a dead socket here since that
535 * will send cardmgr into an endless spin.
537 poll_wait(file, &s->queue, wait);
538 if (!queue_empty(user))
539 return POLLIN | POLLRDNORM;
540 return 0;
541 } /* ds_poll */
543 /*====================================================================*/
545 extern int pcmcia_adjust_resource_info(adjust_t *adj);
547 static int ds_ioctl(struct inode * inode, struct file * file,
548 u_int cmd, u_long arg)
550 struct pcmcia_socket *s;
551 void __user *uarg = (char __user *)arg;
552 u_int size;
553 int ret, err;
554 ds_ioctl_arg_t *buf;
555 user_info_t *user;
557 ds_dbg(2, "ds_ioctl(socket %d, %#x, %#lx)\n", iminor(inode), cmd, arg);
559 user = file->private_data;
560 if (CHECK_USER(user))
561 return -EIO;
563 s = user->socket;
564 if (s->pcmcia_state.dead)
565 return -EIO;
567 size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
568 if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL;
570 /* Permission check */
571 if (!(cmd & IOC_OUT) && !capable(CAP_SYS_ADMIN))
572 return -EPERM;
574 if (cmd & IOC_IN) {
575 if (!access_ok(VERIFY_READ, uarg, size)) {
576 ds_dbg(3, "ds_ioctl(): verify_read = %d\n", -EFAULT);
577 return -EFAULT;
580 if (cmd & IOC_OUT) {
581 if (!access_ok(VERIFY_WRITE, uarg, size)) {
582 ds_dbg(3, "ds_ioctl(): verify_write = %d\n", -EFAULT);
583 return -EFAULT;
586 buf = kmalloc(sizeof(ds_ioctl_arg_t), GFP_KERNEL);
587 if (!buf)
588 return -ENOMEM;
590 err = ret = 0;
592 if (cmd & IOC_IN) __copy_from_user((char *)buf, uarg, size);
594 switch (cmd) {
595 case DS_ADJUST_RESOURCE_INFO:
596 ret = pcmcia_adjust_resource_info(&buf->adjust);
597 break;
598 case DS_GET_CONFIGURATION_INFO:
599 if (buf->config.Function &&
600 (buf->config.Function >= s->functions))
601 ret = CS_BAD_ARGS;
602 else {
603 struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->config.Function);
604 if (p_dev == NULL)
605 ret = CS_BAD_ARGS;
606 else {
607 ret = pccard_get_configuration_info(s, p_dev, &buf->config);
608 pcmcia_put_dev(p_dev);
611 break;
612 case DS_GET_FIRST_TUPLE:
613 mutex_lock(&s->skt_mutex);
614 pcmcia_validate_mem(s);
615 mutex_unlock(&s->skt_mutex);
616 ret = pccard_get_first_tuple(s, BIND_FN_ALL, &buf->tuple);
617 break;
618 case DS_GET_NEXT_TUPLE:
619 ret = pccard_get_next_tuple(s, BIND_FN_ALL, &buf->tuple);
620 break;
621 case DS_GET_TUPLE_DATA:
622 buf->tuple.TupleData = buf->tuple_parse.data;
623 buf->tuple.TupleDataMax = sizeof(buf->tuple_parse.data);
624 ret = pccard_get_tuple_data(s, &buf->tuple);
625 break;
626 case DS_PARSE_TUPLE:
627 buf->tuple.TupleData = buf->tuple_parse.data;
628 ret = pccard_parse_tuple(&buf->tuple, &buf->tuple_parse.parse);
629 break;
630 case DS_RESET_CARD:
631 ret = pccard_reset_card(s);
632 break;
633 case DS_GET_STATUS:
634 if (buf->status.Function &&
635 (buf->status.Function >= s->functions))
636 ret = CS_BAD_ARGS;
637 else {
638 struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->status.Function);
639 if (p_dev == NULL)
640 ret = CS_BAD_ARGS;
641 else {
642 ret = pccard_get_status(s, p_dev, &buf->status);
643 pcmcia_put_dev(p_dev);
646 break;
647 case DS_VALIDATE_CIS:
648 mutex_lock(&s->skt_mutex);
649 pcmcia_validate_mem(s);
650 mutex_unlock(&s->skt_mutex);
651 ret = pccard_validate_cis(s, BIND_FN_ALL, &buf->cisinfo);
652 break;
653 case DS_SUSPEND_CARD:
654 ret = pcmcia_suspend_card(s);
655 break;
656 case DS_RESUME_CARD:
657 ret = pcmcia_resume_card(s);
658 break;
659 case DS_EJECT_CARD:
660 err = pcmcia_eject_card(s);
661 break;
662 case DS_INSERT_CARD:
663 err = pcmcia_insert_card(s);
664 break;
665 case DS_ACCESS_CONFIGURATION_REGISTER:
666 if ((buf->conf_reg.Action == CS_WRITE) && !capable(CAP_SYS_ADMIN)) {
667 err = -EPERM;
668 goto free_out;
671 ret = CS_BAD_ARGS;
673 if (!(buf->conf_reg.Function &&
674 (buf->conf_reg.Function >= s->functions))) {
675 struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->conf_reg.Function);
676 if (p_dev) {
677 ret = pcmcia_access_configuration_register(p_dev, &buf->conf_reg);
678 pcmcia_put_dev(p_dev);
681 break;
682 case DS_GET_FIRST_REGION:
683 case DS_GET_NEXT_REGION:
684 case DS_BIND_MTD:
685 if (!capable(CAP_SYS_ADMIN)) {
686 err = -EPERM;
687 goto free_out;
688 } else {
689 static int printed = 0;
690 if (!printed) {
691 printk(KERN_WARNING "2.6. kernels use pcmciamtd instead of memory_cs.c and do not require special\n");
692 printk(KERN_WARNING "MTD handling any more.\n");
693 printed++;
696 err = -EINVAL;
697 goto free_out;
698 break;
699 case DS_GET_FIRST_WINDOW:
700 ret = pcmcia_get_window(s, &buf->win_info.handle, 0,
701 &buf->win_info.window);
702 break;
703 case DS_GET_NEXT_WINDOW:
704 ret = pcmcia_get_window(s, &buf->win_info.handle,
705 buf->win_info.handle->index + 1, &buf->win_info.window);
706 break;
707 case DS_GET_MEM_PAGE:
708 ret = pcmcia_get_mem_page(buf->win_info.handle,
709 &buf->win_info.map);
710 break;
711 case DS_REPLACE_CIS:
712 ret = pcmcia_replace_cis(s, &buf->cisdump);
713 break;
714 case DS_BIND_REQUEST:
715 if (!capable(CAP_SYS_ADMIN)) {
716 err = -EPERM;
717 goto free_out;
719 err = bind_request(s, &buf->bind_info);
720 break;
721 case DS_GET_DEVICE_INFO:
722 err = get_device_info(s, &buf->bind_info, 1);
723 break;
724 case DS_GET_NEXT_DEVICE:
725 err = get_device_info(s, &buf->bind_info, 0);
726 break;
727 case DS_UNBIND_REQUEST:
728 err = 0;
729 break;
730 default:
731 err = -EINVAL;
734 if ((err == 0) && (ret != CS_SUCCESS)) {
735 ds_dbg(2, "ds_ioctl: ret = %d\n", ret);
736 switch (ret) {
737 case CS_BAD_SOCKET: case CS_NO_CARD:
738 err = -ENODEV; break;
739 case CS_BAD_ARGS: case CS_BAD_ATTRIBUTE: case CS_BAD_IRQ:
740 case CS_BAD_TUPLE:
741 err = -EINVAL; break;
742 case CS_IN_USE:
743 err = -EBUSY; break;
744 case CS_OUT_OF_RESOURCE:
745 err = -ENOSPC; break;
746 case CS_NO_MORE_ITEMS:
747 err = -ENODATA; break;
748 case CS_UNSUPPORTED_FUNCTION:
749 err = -ENOSYS; break;
750 default:
751 err = -EIO; break;
755 if (cmd & IOC_OUT) {
756 if (__copy_to_user(uarg, (char *)buf, size))
757 err = -EFAULT;
760 free_out:
761 kfree(buf);
762 return err;
763 } /* ds_ioctl */
765 /*====================================================================*/
767 static struct file_operations ds_fops = {
768 .owner = THIS_MODULE,
769 .open = ds_open,
770 .release = ds_release,
771 .ioctl = ds_ioctl,
772 .read = ds_read,
773 .write = ds_write,
774 .poll = ds_poll,
777 void __init pcmcia_setup_ioctl(void) {
778 int i;
780 /* Set up character device for user mode clients */
781 i = register_chrdev(0, "pcmcia", &ds_fops);
782 if (i < 0)
783 printk(KERN_NOTICE "unable to find a free device # for "
784 "Driver Services (error=%d)\n", i);
785 else
786 major_dev = i;
788 #ifdef CONFIG_PROC_FS
789 proc_pccard = proc_mkdir("pccard", proc_bus);
790 if (proc_pccard)
791 create_proc_read_entry("drivers",0,proc_pccard,proc_read_drivers,NULL);
792 #endif
796 void __exit pcmcia_cleanup_ioctl(void) {
797 #ifdef CONFIG_PROC_FS
798 if (proc_pccard) {
799 remove_proc_entry("drivers", proc_pccard);
800 remove_proc_entry("pccard", proc_bus);
802 #endif
803 if (major_dev != -1)
804 unregister_chrdev(major_dev, "pcmcia");