pcmcia: CompactFlash driver for PA Semi Electra boards
[pv_ops_mirror.git] / drivers / pcmcia / pcmcia_ioctl.c
blob27523c5f4dad50a9fd9de15ff768257945716d99
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;
63 #define ds_dbg(lvl, fmt, arg...) do { \
64 if (ds_pc_debug >= lvl) \
65 printk(KERN_DEBUG "ds: " fmt , ## arg); \
66 } while (0)
67 #else
68 #define ds_dbg(lvl, fmt, arg...) do { } while (0)
69 #endif
71 static struct pcmcia_device *get_pcmcia_device(struct pcmcia_socket *s,
72 unsigned int function)
74 struct pcmcia_device *p_dev = NULL;
75 unsigned long flags;
77 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
78 list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
79 if (p_dev->func == function) {
80 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
81 return pcmcia_get_dev(p_dev);
84 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
85 return NULL;
88 /* backwards-compatible accessing of driver --- by name! */
90 static struct pcmcia_driver *get_pcmcia_driver(dev_info_t *dev_info)
92 struct device_driver *drv;
93 struct pcmcia_driver *p_drv;
95 drv = driver_find((char *) dev_info, &pcmcia_bus_type);
96 if (!drv)
97 return NULL;
99 p_drv = container_of(drv, struct pcmcia_driver, drv);
101 return (p_drv);
105 #ifdef CONFIG_PROC_FS
106 static struct proc_dir_entry *proc_pccard = NULL;
108 static int proc_read_drivers_callback(struct device_driver *driver, void *d)
110 char **p = d;
111 struct pcmcia_driver *p_drv = container_of(driver,
112 struct pcmcia_driver, drv);
114 *p += sprintf(*p, "%-24.24s 1 %d\n", p_drv->drv.name,
115 #ifdef CONFIG_MODULE_UNLOAD
116 (p_drv->owner) ? module_refcount(p_drv->owner) : 1
117 #else
119 #endif
121 d = (void *) p;
123 return 0;
126 static int proc_read_drivers(char *buf, char **start, off_t pos,
127 int count, int *eof, void *data)
129 char *p = buf;
130 int rc;
132 rc = bus_for_each_drv(&pcmcia_bus_type, NULL,
133 (void *) &p, proc_read_drivers_callback);
134 if (rc < 0)
135 return rc;
137 return (p - buf);
139 #endif
141 /*======================================================================
143 These manage a ring buffer of events pending for one user process
145 ======================================================================*/
148 static int queue_empty(user_info_t *user)
150 return (user->event_head == user->event_tail);
153 static event_t get_queued_event(user_info_t *user)
155 user->event_tail = (user->event_tail+1) % MAX_EVENTS;
156 return user->event[user->event_tail];
159 static void queue_event(user_info_t *user, event_t event)
161 user->event_head = (user->event_head+1) % MAX_EVENTS;
162 if (user->event_head == user->event_tail)
163 user->event_tail = (user->event_tail+1) % MAX_EVENTS;
164 user->event[user->event_head] = event;
167 void handle_event(struct pcmcia_socket *s, event_t event)
169 user_info_t *user;
170 for (user = s->user; user; user = user->next)
171 queue_event(user, event);
172 wake_up_interruptible(&s->queue);
176 /*======================================================================
178 bind_request() and bind_device() are merged by now. Register_client()
179 is called right at the end of bind_request(), during the driver's
180 ->attach() call. Individual descriptions:
182 bind_request() connects a socket to a particular client driver.
183 It looks up the specified device ID in the list of registered
184 drivers, binds it to the socket, and tries to create an instance
185 of the device. unbind_request() deletes a driver instance.
187 Bind_device() associates a device driver with a particular socket.
188 It is normally called by Driver Services after it has identified
189 a newly inserted card. An instance of that driver will then be
190 eligible to register as a client of this socket.
192 Register_client() uses the dev_info_t handle to match the
193 caller with a socket. The driver must have already been bound
194 to a socket with bind_device() -- in fact, bind_device()
195 allocates the client structure that will be used.
197 ======================================================================*/
199 static int bind_request(struct pcmcia_socket *s, bind_info_t *bind_info)
201 struct pcmcia_driver *p_drv;
202 struct pcmcia_device *p_dev;
203 int ret = 0;
204 unsigned long flags;
206 s = pcmcia_get_socket(s);
207 if (!s)
208 return -EINVAL;
210 ds_dbg(2, "bind_request(%d, '%s')\n", s->sock,
211 (char *)bind_info->dev_info);
213 p_drv = get_pcmcia_driver(&bind_info->dev_info);
214 if (!p_drv) {
215 ret = -EINVAL;
216 goto err_put;
219 if (!try_module_get(p_drv->owner)) {
220 ret = -EINVAL;
221 goto err_put_driver;
224 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
225 list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
226 if (p_dev->func == bind_info->function) {
227 if ((p_dev->dev.driver == &p_drv->drv)) {
228 if (p_dev->cardmgr) {
229 /* if there's already a device
230 * registered, and it was registered
231 * by userspace before, we need to
232 * return the "instance". */
233 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
234 bind_info->instance = p_dev;
235 ret = -EBUSY;
236 goto err_put_module;
237 } else {
238 /* the correct driver managed to bind
239 * itself magically to the correct
240 * device. */
241 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
242 p_dev->cardmgr = p_drv;
243 ret = 0;
244 goto err_put_module;
246 } else if (!p_dev->dev.driver) {
247 /* there's already a device available where
248 * no device has been bound to yet. So we don't
249 * need to register a device! */
250 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
251 goto rescan;
255 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
257 p_dev = pcmcia_device_add(s, bind_info->function);
258 if (!p_dev) {
259 ret = -EIO;
260 goto err_put_module;
263 rescan:
264 p_dev->cardmgr = p_drv;
266 /* if a driver is already running, we can abort */
267 if (p_dev->dev.driver)
268 goto err_put_module;
271 * Prevent this racing with a card insertion.
273 mutex_lock(&s->skt_mutex);
274 ret = bus_rescan_devices(&pcmcia_bus_type);
275 mutex_unlock(&s->skt_mutex);
276 if (ret)
277 goto err_put_module;
279 /* check whether the driver indeed matched. I don't care if this
280 * is racy or not, because it can only happen on cardmgr access
281 * paths...
283 if (!(p_dev->dev.driver == &p_drv->drv))
284 p_dev->cardmgr = NULL;
286 err_put_module:
287 module_put(p_drv->owner);
288 err_put_driver:
289 put_driver(&p_drv->drv);
290 err_put:
291 pcmcia_put_socket(s);
293 return (ret);
294 } /* bind_request */
296 #ifdef CONFIG_CARDBUS
298 static struct pci_bus *pcmcia_lookup_bus(struct pcmcia_socket *s)
300 if (!s || !(s->state & SOCKET_CARDBUS))
301 return NULL;
303 return s->cb_dev->subordinate;
305 #endif
307 static int get_device_info(struct pcmcia_socket *s, bind_info_t *bind_info, int first)
309 dev_node_t *node;
310 struct pcmcia_device *p_dev;
311 struct pcmcia_driver *p_drv;
312 unsigned long flags;
313 int ret = 0;
315 #ifdef CONFIG_CARDBUS
317 * Some unbelievably ugly code to associate the PCI cardbus
318 * device and its driver with the PCMCIA "bind" information.
321 struct pci_bus *bus;
323 bus = pcmcia_lookup_bus(s);
324 if (bus) {
325 struct list_head *list;
326 struct pci_dev *dev = NULL;
328 list = bus->devices.next;
329 while (list != &bus->devices) {
330 struct pci_dev *pdev = pci_dev_b(list);
331 list = list->next;
333 if (first) {
334 dev = pdev;
335 break;
338 /* Try to handle "next" here some way? */
340 if (dev && dev->driver) {
341 strlcpy(bind_info->name, dev->driver->name, DEV_NAME_LEN);
342 bind_info->major = 0;
343 bind_info->minor = 0;
344 bind_info->next = NULL;
345 return 0;
349 #endif
351 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
352 list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
353 if (p_dev->func == bind_info->function) {
354 p_dev = pcmcia_get_dev(p_dev);
355 if (!p_dev)
356 continue;
357 goto found;
360 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
361 return -ENODEV;
363 found:
364 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
366 p_drv = to_pcmcia_drv(p_dev->dev.driver);
367 if (p_drv && !p_dev->_locked) {
368 ret = -EAGAIN;
369 goto err_put;
372 if (first)
373 node = p_dev->dev_node;
374 else
375 for (node = p_dev->dev_node; node; node = node->next)
376 if (node == bind_info->next)
377 break;
378 if (!node) {
379 ret = -ENODEV;
380 goto err_put;
383 strlcpy(bind_info->name, node->dev_name, DEV_NAME_LEN);
384 bind_info->major = node->major;
385 bind_info->minor = node->minor;
386 bind_info->next = node->next;
388 err_put:
389 pcmcia_put_dev(p_dev);
390 return (ret);
391 } /* get_device_info */
394 static int ds_open(struct inode *inode, struct file *file)
396 socket_t i = iminor(inode);
397 struct pcmcia_socket *s;
398 user_info_t *user;
399 static int warning_printed = 0;
401 ds_dbg(0, "ds_open(socket %d)\n", i);
403 s = pcmcia_get_socket_by_nr(i);
404 if (!s)
405 return -ENODEV;
406 s = pcmcia_get_socket(s);
407 if (!s)
408 return -ENODEV;
410 if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
411 if (s->pcmcia_state.busy) {
412 pcmcia_put_socket(s);
413 return -EBUSY;
415 else
416 s->pcmcia_state.busy = 1;
419 user = kmalloc(sizeof(user_info_t), GFP_KERNEL);
420 if (!user) {
421 pcmcia_put_socket(s);
422 return -ENOMEM;
424 user->event_tail = user->event_head = 0;
425 user->next = s->user;
426 user->user_magic = USER_MAGIC;
427 user->socket = s;
428 s->user = user;
429 file->private_data = user;
431 if (!warning_printed) {
432 printk(KERN_INFO "pcmcia: Detected deprecated PCMCIA ioctl "
433 "usage from process: %s.\n", current->comm);
434 printk(KERN_INFO "pcmcia: This interface will soon be removed from "
435 "the kernel; please expect breakage unless you upgrade "
436 "to new tools.\n");
437 printk(KERN_INFO "pcmcia: see http://www.kernel.org/pub/linux/"
438 "utils/kernel/pcmcia/pcmcia.html for details.\n");
439 warning_printed = 1;
442 if (s->pcmcia_state.present)
443 queue_event(user, CS_EVENT_CARD_INSERTION);
444 return 0;
445 } /* ds_open */
447 /*====================================================================*/
449 static int ds_release(struct inode *inode, struct file *file)
451 struct pcmcia_socket *s;
452 user_info_t *user, **link;
454 ds_dbg(0, "ds_release(socket %d)\n", iminor(inode));
456 user = file->private_data;
457 if (CHECK_USER(user))
458 goto out;
460 s = user->socket;
462 /* Unlink user data structure */
463 if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
464 s->pcmcia_state.busy = 0;
466 file->private_data = NULL;
467 for (link = &s->user; *link; link = &(*link)->next)
468 if (*link == user) break;
469 if (link == NULL)
470 goto out;
471 *link = user->next;
472 user->user_magic = 0;
473 kfree(user);
474 pcmcia_put_socket(s);
475 out:
476 return 0;
477 } /* ds_release */
479 /*====================================================================*/
481 static ssize_t ds_read(struct file *file, char __user *buf,
482 size_t count, loff_t *ppos)
484 struct pcmcia_socket *s;
485 user_info_t *user;
486 int ret;
488 ds_dbg(2, "ds_read(socket %d)\n", iminor(file->f_path.dentry->d_inode));
490 if (count < 4)
491 return -EINVAL;
493 user = file->private_data;
494 if (CHECK_USER(user))
495 return -EIO;
497 s = user->socket;
498 if (s->pcmcia_state.dead)
499 return -EIO;
501 ret = wait_event_interruptible(s->queue, !queue_empty(user));
502 if (ret == 0)
503 ret = put_user(get_queued_event(user), (int __user *)buf) ? -EFAULT : 4;
505 return ret;
506 } /* ds_read */
508 /*====================================================================*/
510 static ssize_t ds_write(struct file *file, const char __user *buf,
511 size_t count, loff_t *ppos)
513 ds_dbg(2, "ds_write(socket %d)\n", iminor(file->f_path.dentry->d_inode));
515 if (count != 4)
516 return -EINVAL;
517 if ((file->f_flags & O_ACCMODE) == O_RDONLY)
518 return -EBADF;
520 return -EIO;
521 } /* ds_write */
523 /*====================================================================*/
525 /* No kernel lock - fine */
526 static u_int ds_poll(struct file *file, poll_table *wait)
528 struct pcmcia_socket *s;
529 user_info_t *user;
531 ds_dbg(2, "ds_poll(socket %d)\n", iminor(file->f_path.dentry->d_inode));
533 user = file->private_data;
534 if (CHECK_USER(user))
535 return POLLERR;
536 s = user->socket;
538 * We don't check for a dead socket here since that
539 * will send cardmgr into an endless spin.
541 poll_wait(file, &s->queue, wait);
542 if (!queue_empty(user))
543 return POLLIN | POLLRDNORM;
544 return 0;
545 } /* ds_poll */
547 /*====================================================================*/
549 extern int pcmcia_adjust_resource_info(adjust_t *adj);
551 static int ds_ioctl(struct inode * inode, struct file * file,
552 u_int cmd, u_long arg)
554 struct pcmcia_socket *s;
555 void __user *uarg = (char __user *)arg;
556 u_int size;
557 int ret, err;
558 ds_ioctl_arg_t *buf;
559 user_info_t *user;
561 ds_dbg(2, "ds_ioctl(socket %d, %#x, %#lx)\n", iminor(inode), cmd, arg);
563 user = file->private_data;
564 if (CHECK_USER(user))
565 return -EIO;
567 s = user->socket;
568 if (s->pcmcia_state.dead)
569 return -EIO;
571 size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
572 if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL;
574 /* Permission check */
575 if (!(cmd & IOC_OUT) && !capable(CAP_SYS_ADMIN))
576 return -EPERM;
578 if (cmd & IOC_IN) {
579 if (!access_ok(VERIFY_READ, uarg, size)) {
580 ds_dbg(3, "ds_ioctl(): verify_read = %d\n", -EFAULT);
581 return -EFAULT;
584 if (cmd & IOC_OUT) {
585 if (!access_ok(VERIFY_WRITE, uarg, size)) {
586 ds_dbg(3, "ds_ioctl(): verify_write = %d\n", -EFAULT);
587 return -EFAULT;
590 buf = kmalloc(sizeof(ds_ioctl_arg_t), GFP_KERNEL);
591 if (!buf)
592 return -ENOMEM;
594 err = ret = 0;
596 if (cmd & IOC_IN) {
597 if (__copy_from_user((char *)buf, uarg, size)) {
598 err = -EFAULT;
599 goto free_out;
603 switch (cmd) {
604 case DS_ADJUST_RESOURCE_INFO:
605 ret = pcmcia_adjust_resource_info(&buf->adjust);
606 break;
607 case DS_GET_CONFIGURATION_INFO:
608 if (buf->config.Function &&
609 (buf->config.Function >= s->functions))
610 ret = CS_BAD_ARGS;
611 else {
612 struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->config.Function);
613 ret = pccard_get_configuration_info(s, p_dev, &buf->config);
614 pcmcia_put_dev(p_dev);
616 break;
617 case DS_GET_FIRST_TUPLE:
618 mutex_lock(&s->skt_mutex);
619 pcmcia_validate_mem(s);
620 mutex_unlock(&s->skt_mutex);
621 ret = pccard_get_first_tuple(s, BIND_FN_ALL, &buf->tuple);
622 break;
623 case DS_GET_NEXT_TUPLE:
624 ret = pccard_get_next_tuple(s, BIND_FN_ALL, &buf->tuple);
625 break;
626 case DS_GET_TUPLE_DATA:
627 buf->tuple.TupleData = buf->tuple_parse.data;
628 buf->tuple.TupleDataMax = sizeof(buf->tuple_parse.data);
629 ret = pccard_get_tuple_data(s, &buf->tuple);
630 break;
631 case DS_PARSE_TUPLE:
632 buf->tuple.TupleData = buf->tuple_parse.data;
633 ret = pccard_parse_tuple(&buf->tuple, &buf->tuple_parse.parse);
634 break;
635 case DS_RESET_CARD:
636 ret = pccard_reset_card(s);
637 break;
638 case DS_GET_STATUS:
639 if (buf->status.Function &&
640 (buf->status.Function >= s->functions))
641 ret = CS_BAD_ARGS;
642 else {
643 struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->status.Function);
644 ret = pccard_get_status(s, p_dev, &buf->status);
645 pcmcia_put_dev(p_dev);
647 break;
648 case DS_VALIDATE_CIS:
649 mutex_lock(&s->skt_mutex);
650 pcmcia_validate_mem(s);
651 mutex_unlock(&s->skt_mutex);
652 ret = pccard_validate_cis(s, BIND_FN_ALL, &buf->cisinfo);
653 break;
654 case DS_SUSPEND_CARD:
655 ret = pcmcia_suspend_card(s);
656 break;
657 case DS_RESUME_CARD:
658 ret = pcmcia_resume_card(s);
659 break;
660 case DS_EJECT_CARD:
661 err = pcmcia_eject_card(s);
662 break;
663 case DS_INSERT_CARD:
664 err = pcmcia_insert_card(s);
665 break;
666 case DS_ACCESS_CONFIGURATION_REGISTER:
667 if ((buf->conf_reg.Action == CS_WRITE) && !capable(CAP_SYS_ADMIN)) {
668 err = -EPERM;
669 goto free_out;
672 ret = CS_BAD_ARGS;
674 if (!(buf->conf_reg.Function &&
675 (buf->conf_reg.Function >= s->functions))) {
676 struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->conf_reg.Function);
677 if (p_dev) {
678 ret = pcmcia_access_configuration_register(p_dev, &buf->conf_reg);
679 pcmcia_put_dev(p_dev);
682 break;
683 case DS_GET_FIRST_REGION:
684 case DS_GET_NEXT_REGION:
685 case DS_BIND_MTD:
686 if (!capable(CAP_SYS_ADMIN)) {
687 err = -EPERM;
688 goto free_out;
689 } else {
690 static int printed = 0;
691 if (!printed) {
692 printk(KERN_WARNING "2.6. kernels use pcmciamtd instead of memory_cs.c and do not require special\n");
693 printk(KERN_WARNING "MTD handling any more.\n");
694 printed++;
697 err = -EINVAL;
698 goto free_out;
699 break;
700 case DS_GET_FIRST_WINDOW:
701 ret = pcmcia_get_window(s, &buf->win_info.handle, 0,
702 &buf->win_info.window);
703 break;
704 case DS_GET_NEXT_WINDOW:
705 ret = pcmcia_get_window(s, &buf->win_info.handle,
706 buf->win_info.handle->index + 1, &buf->win_info.window);
707 break;
708 case DS_GET_MEM_PAGE:
709 ret = pcmcia_get_mem_page(buf->win_info.handle,
710 &buf->win_info.map);
711 break;
712 case DS_REPLACE_CIS:
713 ret = pcmcia_replace_cis(s, &buf->cisdump);
714 break;
715 case DS_BIND_REQUEST:
716 if (!capable(CAP_SYS_ADMIN)) {
717 err = -EPERM;
718 goto free_out;
720 err = bind_request(s, &buf->bind_info);
721 break;
722 case DS_GET_DEVICE_INFO:
723 err = get_device_info(s, &buf->bind_info, 1);
724 break;
725 case DS_GET_NEXT_DEVICE:
726 err = get_device_info(s, &buf->bind_info, 0);
727 break;
728 case DS_UNBIND_REQUEST:
729 err = 0;
730 break;
731 default:
732 err = -EINVAL;
735 if ((err == 0) && (ret != CS_SUCCESS)) {
736 ds_dbg(2, "ds_ioctl: ret = %d\n", ret);
737 switch (ret) {
738 case CS_BAD_SOCKET: case CS_NO_CARD:
739 err = -ENODEV; break;
740 case CS_BAD_ARGS: case CS_BAD_ATTRIBUTE: case CS_BAD_IRQ:
741 case CS_BAD_TUPLE:
742 err = -EINVAL; break;
743 case CS_IN_USE:
744 err = -EBUSY; break;
745 case CS_OUT_OF_RESOURCE:
746 err = -ENOSPC; break;
747 case CS_NO_MORE_ITEMS:
748 err = -ENODATA; break;
749 case CS_UNSUPPORTED_FUNCTION:
750 err = -ENOSYS; break;
751 default:
752 err = -EIO; break;
756 if (cmd & IOC_OUT) {
757 if (__copy_to_user(uarg, (char *)buf, size))
758 err = -EFAULT;
761 free_out:
762 kfree(buf);
763 return err;
764 } /* ds_ioctl */
766 /*====================================================================*/
768 static const struct file_operations ds_fops = {
769 .owner = THIS_MODULE,
770 .open = ds_open,
771 .release = ds_release,
772 .ioctl = ds_ioctl,
773 .read = ds_read,
774 .write = ds_write,
775 .poll = ds_poll,
778 void __init pcmcia_setup_ioctl(void) {
779 int i;
781 /* Set up character device for user mode clients */
782 i = register_chrdev(0, "pcmcia", &ds_fops);
783 if (i < 0)
784 printk(KERN_NOTICE "unable to find a free device # for "
785 "Driver Services (error=%d)\n", i);
786 else
787 major_dev = i;
789 #ifdef CONFIG_PROC_FS
790 proc_pccard = proc_mkdir("pccard", proc_bus);
791 if (proc_pccard)
792 create_proc_read_entry("drivers",0,proc_pccard,proc_read_drivers,NULL);
793 #endif
797 void __exit pcmcia_cleanup_ioctl(void) {
798 #ifdef CONFIG_PROC_FS
799 if (proc_pccard) {
800 remove_proc_entry("drivers", proc_pccard);
801 remove_proc_entry("pccard", proc_bus);
803 #endif
804 if (major_dev != -1)
805 unregister_chrdev(major_dev, "pcmcia");