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