[DCCP] ccid3: Fixup some type conversions related to rtts
[linux-2.6/kvm.git] / drivers / pcmcia / pcmcia_ioctl.c
blob327372b7a54e61deb9b22193eff13c99ed065264
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;
131 int rc;
133 rc = bus_for_each_drv(&pcmcia_bus_type, NULL,
134 (void *) &p, proc_read_drivers_callback);
135 if (rc < 0)
136 return rc;
138 return (p - buf);
140 #endif
142 /*======================================================================
144 These manage a ring buffer of events pending for one user process
146 ======================================================================*/
149 static int queue_empty(user_info_t *user)
151 return (user->event_head == user->event_tail);
154 static event_t get_queued_event(user_info_t *user)
156 user->event_tail = (user->event_tail+1) % MAX_EVENTS;
157 return user->event[user->event_tail];
160 static void queue_event(user_info_t *user, event_t event)
162 user->event_head = (user->event_head+1) % MAX_EVENTS;
163 if (user->event_head == user->event_tail)
164 user->event_tail = (user->event_tail+1) % MAX_EVENTS;
165 user->event[user->event_head] = event;
168 void handle_event(struct pcmcia_socket *s, event_t event)
170 user_info_t *user;
171 for (user = s->user; user; user = user->next)
172 queue_event(user, event);
173 wake_up_interruptible(&s->queue);
177 /*======================================================================
179 bind_request() and bind_device() are merged by now. Register_client()
180 is called right at the end of bind_request(), during the driver's
181 ->attach() call. Individual descriptions:
183 bind_request() connects a socket to a particular client driver.
184 It looks up the specified device ID in the list of registered
185 drivers, binds it to the socket, and tries to create an instance
186 of the device. unbind_request() deletes a driver instance.
188 Bind_device() associates a device driver with a particular socket.
189 It is normally called by Driver Services after it has identified
190 a newly inserted card. An instance of that driver will then be
191 eligible to register as a client of this socket.
193 Register_client() uses the dev_info_t handle to match the
194 caller with a socket. The driver must have already been bound
195 to a socket with bind_device() -- in fact, bind_device()
196 allocates the client structure that will be used.
198 ======================================================================*/
200 static int bind_request(struct pcmcia_socket *s, bind_info_t *bind_info)
202 struct pcmcia_driver *p_drv;
203 struct pcmcia_device *p_dev;
204 int ret = 0;
205 unsigned long flags;
207 s = pcmcia_get_socket(s);
208 if (!s)
209 return -EINVAL;
211 ds_dbg(2, "bind_request(%d, '%s')\n", s->sock,
212 (char *)bind_info->dev_info);
214 p_drv = get_pcmcia_driver(&bind_info->dev_info);
215 if (!p_drv) {
216 ret = -EINVAL;
217 goto err_put;
220 if (!try_module_get(p_drv->owner)) {
221 ret = -EINVAL;
222 goto err_put_driver;
225 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
226 list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
227 if (p_dev->func == bind_info->function) {
228 if ((p_dev->dev.driver == &p_drv->drv)) {
229 if (p_dev->cardmgr) {
230 /* if there's already a device
231 * registered, and it was registered
232 * by userspace before, we need to
233 * return the "instance". */
234 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
235 bind_info->instance = p_dev;
236 ret = -EBUSY;
237 goto err_put_module;
238 } else {
239 /* the correct driver managed to bind
240 * itself magically to the correct
241 * device. */
242 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
243 p_dev->cardmgr = p_drv;
244 ret = 0;
245 goto err_put_module;
247 } else if (!p_dev->dev.driver) {
248 /* there's already a device available where
249 * no device has been bound to yet. So we don't
250 * need to register a device! */
251 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
252 goto rescan;
256 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
258 p_dev = pcmcia_device_add(s, bind_info->function);
259 if (!p_dev) {
260 ret = -EIO;
261 goto err_put_module;
264 rescan:
265 p_dev->cardmgr = p_drv;
267 /* if a driver is already running, we can abort */
268 if (p_dev->dev.driver)
269 goto err_put_module;
272 * Prevent this racing with a card insertion.
274 mutex_lock(&s->skt_mutex);
275 ret = bus_rescan_devices(&pcmcia_bus_type);
276 mutex_unlock(&s->skt_mutex);
277 if (ret)
278 goto err_put_module;
280 /* check whether the driver indeed matched. I don't care if this
281 * is racy or not, because it can only happen on cardmgr access
282 * paths...
284 if (!(p_dev->dev.driver == &p_drv->drv))
285 p_dev->cardmgr = NULL;
287 err_put_module:
288 module_put(p_drv->owner);
289 err_put_driver:
290 put_driver(&p_drv->drv);
291 err_put:
292 pcmcia_put_socket(s);
294 return (ret);
295 } /* bind_request */
297 #ifdef CONFIG_CARDBUS
299 static struct pci_bus *pcmcia_lookup_bus(struct pcmcia_socket *s)
301 if (!s || !(s->state & SOCKET_CARDBUS))
302 return NULL;
304 return s->cb_dev->subordinate;
306 #endif
308 static int get_device_info(struct pcmcia_socket *s, bind_info_t *bind_info, int first)
310 dev_node_t *node;
311 struct pcmcia_device *p_dev;
312 struct pcmcia_driver *p_drv;
313 unsigned long flags;
314 int ret = 0;
316 #ifdef CONFIG_CARDBUS
318 * Some unbelievably ugly code to associate the PCI cardbus
319 * device and its driver with the PCMCIA "bind" information.
322 struct pci_bus *bus;
324 bus = pcmcia_lookup_bus(s);
325 if (bus) {
326 struct list_head *list;
327 struct pci_dev *dev = NULL;
329 list = bus->devices.next;
330 while (list != &bus->devices) {
331 struct pci_dev *pdev = pci_dev_b(list);
332 list = list->next;
334 if (first) {
335 dev = pdev;
336 break;
339 /* Try to handle "next" here some way? */
341 if (dev && dev->driver) {
342 strlcpy(bind_info->name, dev->driver->name, DEV_NAME_LEN);
343 bind_info->major = 0;
344 bind_info->minor = 0;
345 bind_info->next = NULL;
346 return 0;
350 #endif
352 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
353 list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
354 if (p_dev->func == bind_info->function) {
355 p_dev = pcmcia_get_dev(p_dev);
356 if (!p_dev)
357 continue;
358 goto found;
361 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
362 return -ENODEV;
364 found:
365 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
367 p_drv = to_pcmcia_drv(p_dev->dev.driver);
368 if (p_drv && !p_dev->_locked) {
369 ret = -EAGAIN;
370 goto err_put;
373 if (first)
374 node = p_dev->dev_node;
375 else
376 for (node = p_dev->dev_node; node; node = node->next)
377 if (node == bind_info->next)
378 break;
379 if (!node) {
380 ret = -ENODEV;
381 goto err_put;
384 strlcpy(bind_info->name, node->dev_name, DEV_NAME_LEN);
385 bind_info->major = node->major;
386 bind_info->minor = node->minor;
387 bind_info->next = node->next;
389 err_put:
390 pcmcia_put_dev(p_dev);
391 return (ret);
392 } /* get_device_info */
395 static int ds_open(struct inode *inode, struct file *file)
397 socket_t i = iminor(inode);
398 struct pcmcia_socket *s;
399 user_info_t *user;
400 static int warning_printed = 0;
402 ds_dbg(0, "ds_open(socket %d)\n", i);
404 s = pcmcia_get_socket_by_nr(i);
405 if (!s)
406 return -ENODEV;
407 s = pcmcia_get_socket(s);
408 if (!s)
409 return -ENODEV;
411 if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
412 if (s->pcmcia_state.busy) {
413 pcmcia_put_socket(s);
414 return -EBUSY;
416 else
417 s->pcmcia_state.busy = 1;
420 user = kmalloc(sizeof(user_info_t), GFP_KERNEL);
421 if (!user) {
422 pcmcia_put_socket(s);
423 return -ENOMEM;
425 user->event_tail = user->event_head = 0;
426 user->next = s->user;
427 user->user_magic = USER_MAGIC;
428 user->socket = s;
429 s->user = user;
430 file->private_data = user;
432 if (!warning_printed) {
433 printk(KERN_INFO "pcmcia: Detected deprecated PCMCIA ioctl "
434 "usage from process: %s.\n", current->comm);
435 printk(KERN_INFO "pcmcia: This interface will soon be removed from "
436 "the kernel; please expect breakage unless you upgrade "
437 "to new tools.\n");
438 printk(KERN_INFO "pcmcia: see http://www.kernel.org/pub/linux/"
439 "utils/kernel/pcmcia/pcmcia.html for details.\n");
440 warning_printed = 1;
443 if (s->pcmcia_state.present)
444 queue_event(user, CS_EVENT_CARD_INSERTION);
445 return 0;
446 } /* ds_open */
448 /*====================================================================*/
450 static int ds_release(struct inode *inode, struct file *file)
452 struct pcmcia_socket *s;
453 user_info_t *user, **link;
455 ds_dbg(0, "ds_release(socket %d)\n", iminor(inode));
457 user = file->private_data;
458 if (CHECK_USER(user))
459 goto out;
461 s = user->socket;
463 /* Unlink user data structure */
464 if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
465 s->pcmcia_state.busy = 0;
467 file->private_data = NULL;
468 for (link = &s->user; *link; link = &(*link)->next)
469 if (*link == user) break;
470 if (link == NULL)
471 goto out;
472 *link = user->next;
473 user->user_magic = 0;
474 kfree(user);
475 pcmcia_put_socket(s);
476 out:
477 return 0;
478 } /* ds_release */
480 /*====================================================================*/
482 static ssize_t ds_read(struct file *file, char __user *buf,
483 size_t count, loff_t *ppos)
485 struct pcmcia_socket *s;
486 user_info_t *user;
487 int ret;
489 ds_dbg(2, "ds_read(socket %d)\n", iminor(file->f_path.dentry->d_inode));
491 if (count < 4)
492 return -EINVAL;
494 user = file->private_data;
495 if (CHECK_USER(user))
496 return -EIO;
498 s = user->socket;
499 if (s->pcmcia_state.dead)
500 return -EIO;
502 ret = wait_event_interruptible(s->queue, !queue_empty(user));
503 if (ret == 0)
504 ret = put_user(get_queued_event(user), (int __user *)buf) ? -EFAULT : 4;
506 return ret;
507 } /* ds_read */
509 /*====================================================================*/
511 static ssize_t ds_write(struct file *file, const char __user *buf,
512 size_t count, loff_t *ppos)
514 ds_dbg(2, "ds_write(socket %d)\n", iminor(file->f_path.dentry->d_inode));
516 if (count != 4)
517 return -EINVAL;
518 if ((file->f_flags & O_ACCMODE) == O_RDONLY)
519 return -EBADF;
521 return -EIO;
522 } /* ds_write */
524 /*====================================================================*/
526 /* No kernel lock - fine */
527 static u_int ds_poll(struct file *file, poll_table *wait)
529 struct pcmcia_socket *s;
530 user_info_t *user;
532 ds_dbg(2, "ds_poll(socket %d)\n", iminor(file->f_path.dentry->d_inode));
534 user = file->private_data;
535 if (CHECK_USER(user))
536 return POLLERR;
537 s = user->socket;
539 * We don't check for a dead socket here since that
540 * will send cardmgr into an endless spin.
542 poll_wait(file, &s->queue, wait);
543 if (!queue_empty(user))
544 return POLLIN | POLLRDNORM;
545 return 0;
546 } /* ds_poll */
548 /*====================================================================*/
550 extern int pcmcia_adjust_resource_info(adjust_t *adj);
552 static int ds_ioctl(struct inode * inode, struct file * file,
553 u_int cmd, u_long arg)
555 struct pcmcia_socket *s;
556 void __user *uarg = (char __user *)arg;
557 u_int size;
558 int ret, err;
559 ds_ioctl_arg_t *buf;
560 user_info_t *user;
562 ds_dbg(2, "ds_ioctl(socket %d, %#x, %#lx)\n", iminor(inode), cmd, arg);
564 user = file->private_data;
565 if (CHECK_USER(user))
566 return -EIO;
568 s = user->socket;
569 if (s->pcmcia_state.dead)
570 return -EIO;
572 size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
573 if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL;
575 /* Permission check */
576 if (!(cmd & IOC_OUT) && !capable(CAP_SYS_ADMIN))
577 return -EPERM;
579 if (cmd & IOC_IN) {
580 if (!access_ok(VERIFY_READ, uarg, size)) {
581 ds_dbg(3, "ds_ioctl(): verify_read = %d\n", -EFAULT);
582 return -EFAULT;
585 if (cmd & IOC_OUT) {
586 if (!access_ok(VERIFY_WRITE, uarg, size)) {
587 ds_dbg(3, "ds_ioctl(): verify_write = %d\n", -EFAULT);
588 return -EFAULT;
591 buf = kmalloc(sizeof(ds_ioctl_arg_t), GFP_KERNEL);
592 if (!buf)
593 return -ENOMEM;
595 err = ret = 0;
597 if (cmd & IOC_IN) {
598 if (__copy_from_user((char *)buf, uarg, size)) {
599 err = -EFAULT;
600 goto free_out;
604 switch (cmd) {
605 case DS_ADJUST_RESOURCE_INFO:
606 ret = pcmcia_adjust_resource_info(&buf->adjust);
607 break;
608 case DS_GET_CONFIGURATION_INFO:
609 if (buf->config.Function &&
610 (buf->config.Function >= s->functions))
611 ret = CS_BAD_ARGS;
612 else {
613 struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->config.Function);
614 ret = pccard_get_configuration_info(s, p_dev, &buf->config);
615 pcmcia_put_dev(p_dev);
617 break;
618 case DS_GET_FIRST_TUPLE:
619 mutex_lock(&s->skt_mutex);
620 pcmcia_validate_mem(s);
621 mutex_unlock(&s->skt_mutex);
622 ret = pccard_get_first_tuple(s, BIND_FN_ALL, &buf->tuple);
623 break;
624 case DS_GET_NEXT_TUPLE:
625 ret = pccard_get_next_tuple(s, BIND_FN_ALL, &buf->tuple);
626 break;
627 case DS_GET_TUPLE_DATA:
628 buf->tuple.TupleData = buf->tuple_parse.data;
629 buf->tuple.TupleDataMax = sizeof(buf->tuple_parse.data);
630 ret = pccard_get_tuple_data(s, &buf->tuple);
631 break;
632 case DS_PARSE_TUPLE:
633 buf->tuple.TupleData = buf->tuple_parse.data;
634 ret = pccard_parse_tuple(&buf->tuple, &buf->tuple_parse.parse);
635 break;
636 case DS_RESET_CARD:
637 ret = pccard_reset_card(s);
638 break;
639 case DS_GET_STATUS:
640 if (buf->status.Function &&
641 (buf->status.Function >= s->functions))
642 ret = CS_BAD_ARGS;
643 else {
644 struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->status.Function);
645 ret = pccard_get_status(s, p_dev, &buf->status);
646 pcmcia_put_dev(p_dev);
648 break;
649 case DS_VALIDATE_CIS:
650 mutex_lock(&s->skt_mutex);
651 pcmcia_validate_mem(s);
652 mutex_unlock(&s->skt_mutex);
653 ret = pccard_validate_cis(s, BIND_FN_ALL, &buf->cisinfo);
654 break;
655 case DS_SUSPEND_CARD:
656 ret = pcmcia_suspend_card(s);
657 break;
658 case DS_RESUME_CARD:
659 ret = pcmcia_resume_card(s);
660 break;
661 case DS_EJECT_CARD:
662 err = pcmcia_eject_card(s);
663 break;
664 case DS_INSERT_CARD:
665 err = pcmcia_insert_card(s);
666 break;
667 case DS_ACCESS_CONFIGURATION_REGISTER:
668 if ((buf->conf_reg.Action == CS_WRITE) && !capable(CAP_SYS_ADMIN)) {
669 err = -EPERM;
670 goto free_out;
673 ret = CS_BAD_ARGS;
675 if (!(buf->conf_reg.Function &&
676 (buf->conf_reg.Function >= s->functions))) {
677 struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->conf_reg.Function);
678 if (p_dev) {
679 ret = pcmcia_access_configuration_register(p_dev, &buf->conf_reg);
680 pcmcia_put_dev(p_dev);
683 break;
684 case DS_GET_FIRST_REGION:
685 case DS_GET_NEXT_REGION:
686 case DS_BIND_MTD:
687 if (!capable(CAP_SYS_ADMIN)) {
688 err = -EPERM;
689 goto free_out;
690 } else {
691 static int printed = 0;
692 if (!printed) {
693 printk(KERN_WARNING "2.6. kernels use pcmciamtd instead of memory_cs.c and do not require special\n");
694 printk(KERN_WARNING "MTD handling any more.\n");
695 printed++;
698 err = -EINVAL;
699 goto free_out;
700 break;
701 case DS_GET_FIRST_WINDOW:
702 ret = pcmcia_get_window(s, &buf->win_info.handle, 0,
703 &buf->win_info.window);
704 break;
705 case DS_GET_NEXT_WINDOW:
706 ret = pcmcia_get_window(s, &buf->win_info.handle,
707 buf->win_info.handle->index + 1, &buf->win_info.window);
708 break;
709 case DS_GET_MEM_PAGE:
710 ret = pcmcia_get_mem_page(buf->win_info.handle,
711 &buf->win_info.map);
712 break;
713 case DS_REPLACE_CIS:
714 ret = pcmcia_replace_cis(s, &buf->cisdump);
715 break;
716 case DS_BIND_REQUEST:
717 if (!capable(CAP_SYS_ADMIN)) {
718 err = -EPERM;
719 goto free_out;
721 err = bind_request(s, &buf->bind_info);
722 break;
723 case DS_GET_DEVICE_INFO:
724 err = get_device_info(s, &buf->bind_info, 1);
725 break;
726 case DS_GET_NEXT_DEVICE:
727 err = get_device_info(s, &buf->bind_info, 0);
728 break;
729 case DS_UNBIND_REQUEST:
730 err = 0;
731 break;
732 default:
733 err = -EINVAL;
736 if ((err == 0) && (ret != CS_SUCCESS)) {
737 ds_dbg(2, "ds_ioctl: ret = %d\n", ret);
738 switch (ret) {
739 case CS_BAD_SOCKET: case CS_NO_CARD:
740 err = -ENODEV; break;
741 case CS_BAD_ARGS: case CS_BAD_ATTRIBUTE: case CS_BAD_IRQ:
742 case CS_BAD_TUPLE:
743 err = -EINVAL; break;
744 case CS_IN_USE:
745 err = -EBUSY; break;
746 case CS_OUT_OF_RESOURCE:
747 err = -ENOSPC; break;
748 case CS_NO_MORE_ITEMS:
749 err = -ENODATA; break;
750 case CS_UNSUPPORTED_FUNCTION:
751 err = -ENOSYS; break;
752 default:
753 err = -EIO; break;
757 if (cmd & IOC_OUT) {
758 if (__copy_to_user(uarg, (char *)buf, size))
759 err = -EFAULT;
762 free_out:
763 kfree(buf);
764 return err;
765 } /* ds_ioctl */
767 /*====================================================================*/
769 static struct file_operations ds_fops = {
770 .owner = THIS_MODULE,
771 .open = ds_open,
772 .release = ds_release,
773 .ioctl = ds_ioctl,
774 .read = ds_read,
775 .write = ds_write,
776 .poll = ds_poll,
779 void __init pcmcia_setup_ioctl(void) {
780 int i;
782 /* Set up character device for user mode clients */
783 i = register_chrdev(0, "pcmcia", &ds_fops);
784 if (i < 0)
785 printk(KERN_NOTICE "unable to find a free device # for "
786 "Driver Services (error=%d)\n", i);
787 else
788 major_dev = i;
790 #ifdef CONFIG_PROC_FS
791 proc_pccard = proc_mkdir("pccard", proc_bus);
792 if (proc_pccard)
793 create_proc_read_entry("drivers",0,proc_pccard,proc_read_drivers,NULL);
794 #endif
798 void __exit pcmcia_cleanup_ioctl(void) {
799 #ifdef CONFIG_PROC_FS
800 if (proc_pccard) {
801 remove_proc_entry("drivers", proc_pccard);
802 remove_proc_entry("pccard", proc_bus);
804 #endif
805 if (major_dev != -1)
806 unregister_chrdev(major_dev, "pcmcia");