blob: 0bebfdbdc27b5180ef9b0dfd80b82e3ef2b6698f [file] [log] [blame]
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001/*
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/module.h>
23#include <linux/moduleparam.h>
24#include <linux/init.h>
25#include <linux/kernel.h>
26#include <linux/major.h>
27#include <linux/string.h>
28#include <linux/errno.h>
29#include <linux/slab.h>
30#include <linux/mm.h>
31#include <linux/fcntl.h>
32#include <linux/sched.h>
33#include <linux/smp_lock.h>
34#include <linux/timer.h>
35#include <linux/ioctl.h>
36#include <linux/proc_fs.h>
37#include <linux/poll.h>
38#include <linux/pci.h>
39#include <linux/list.h>
40#include <linux/delay.h>
41#include <linux/kref.h>
42#include <linux/workqueue.h>
43#include <linux/crc32.h>
44
45#include <asm/atomic.h>
46
47#define IN_CARD_SERVICES
48#include <pcmcia/version.h>
49#include <pcmcia/cs_types.h>
50#include <pcmcia/cs.h>
51#include <pcmcia/bulkmem.h>
52#include <pcmcia/cistpl.h>
53#include <pcmcia/ds.h>
54#include <pcmcia/ss.h>
55
56#include "cs_internal.h"
57#include "ds_internal.h"
58
59static int major_dev = -1;
60
61
62/* Device user information */
63#define MAX_EVENTS 32
64#define USER_MAGIC 0x7ea4
65#define CHECK_USER(u) \
66 (((u) == NULL) || ((u)->user_magic != USER_MAGIC))
67
68typedef struct user_info_t {
69 u_int user_magic;
70 int event_head, event_tail;
71 event_t event[MAX_EVENTS];
72 struct user_info_t *next;
Dominik Brodowskidc109492005-06-27 16:28:50 -070073 struct pcmcia_socket *socket;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070074} user_info_t;
75
76
77#ifdef DEBUG
78extern int ds_pc_debug;
79#define cs_socket_name(skt) ((skt)->dev.class_id)
80
81#define ds_dbg(lvl, fmt, arg...) do { \
82 if (ds_pc_debug >= lvl) \
83 printk(KERN_DEBUG "ds: " fmt , ## arg); \
84} while (0)
85#else
86#define ds_dbg(lvl, fmt, arg...) do { } while (0)
87#endif
88
89
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070090/* backwards-compatible accessing of driver --- by name! */
91
92static struct pcmcia_driver * get_pcmcia_driver (dev_info_t *dev_info)
93{
94 struct device_driver *drv;
95 struct pcmcia_driver *p_drv;
96
97 drv = driver_find((char *) dev_info, &pcmcia_bus_type);
98 if (!drv)
99 return NULL;
100
101 p_drv = container_of(drv, struct pcmcia_driver, drv);
102
103 return (p_drv);
104}
105
106
107#ifdef CONFIG_PROC_FS
108static struct proc_dir_entry *proc_pccard = NULL;
109
110static int proc_read_drivers_callback(struct device_driver *driver, void *d)
111{
112 char **p = d;
113 struct pcmcia_driver *p_drv = container_of(driver,
114 struct pcmcia_driver, drv);
115
116 *p += sprintf(*p, "%-24.24s 1 %d\n", p_drv->drv.name,
117#ifdef CONFIG_MODULE_UNLOAD
118 (p_drv->owner) ? module_refcount(p_drv->owner) : 1
119#else
120 1
121#endif
122 );
123 d = (void *) p;
124
125 return 0;
126}
127
128static int proc_read_drivers(char *buf, char **start, off_t pos,
129 int count, int *eof, void *data)
130{
131 char *p = buf;
132
133 bus_for_each_drv(&pcmcia_bus_type, NULL,
134 (void *) &p, proc_read_drivers_callback);
135
136 return (p - buf);
137}
138#endif
139
140/*======================================================================
141
142 These manage a ring buffer of events pending for one user process
143
144======================================================================*/
145
146
147static int queue_empty(user_info_t *user)
148{
149 return (user->event_head == user->event_tail);
150}
151
152static event_t get_queued_event(user_info_t *user)
153{
154 user->event_tail = (user->event_tail+1) % MAX_EVENTS;
155 return user->event[user->event_tail];
156}
157
158static void queue_event(user_info_t *user, event_t event)
159{
160 user->event_head = (user->event_head+1) % MAX_EVENTS;
161 if (user->event_head == user->event_tail)
162 user->event_tail = (user->event_tail+1) % MAX_EVENTS;
163 user->event[user->event_head] = event;
164}
165
Dominik Brodowskidc109492005-06-27 16:28:50 -0700166void handle_event(struct pcmcia_socket *s, event_t event)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700167{
168 user_info_t *user;
169 for (user = s->user; user; user = user->next)
170 queue_event(user, event);
171 wake_up_interruptible(&s->queue);
172}
173
174
175/*======================================================================
176
177 bind_request() and bind_device() are merged by now. Register_client()
178 is called right at the end of bind_request(), during the driver's
179 ->attach() call. Individual descriptions:
180
181 bind_request() connects a socket to a particular client driver.
182 It looks up the specified device ID in the list of registered
183 drivers, binds it to the socket, and tries to create an instance
184 of the device. unbind_request() deletes a driver instance.
185
186 Bind_device() associates a device driver with a particular socket.
187 It is normally called by Driver Services after it has identified
188 a newly inserted card. An instance of that driver will then be
189 eligible to register as a client of this socket.
190
191 Register_client() uses the dev_info_t handle to match the
192 caller with a socket. The driver must have already been bound
193 to a socket with bind_device() -- in fact, bind_device()
194 allocates the client structure that will be used.
195
196======================================================================*/
197
Dominik Brodowskidc109492005-06-27 16:28:50 -0700198static int bind_request(struct pcmcia_socket *s, bind_info_t *bind_info)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700199{
200 struct pcmcia_driver *p_drv;
201 struct pcmcia_device *p_dev;
202 int ret = 0;
203 unsigned long flags;
204
Dominik Brodowskidc109492005-06-27 16:28:50 -0700205 s = pcmcia_get_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700206 if (!s)
207 return -EINVAL;
208
Dominik Brodowskidc109492005-06-27 16:28:50 -0700209 ds_dbg(2, "bind_request(%d, '%s')\n", s->sock,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700210 (char *)bind_info->dev_info);
211
212 p_drv = get_pcmcia_driver(&bind_info->dev_info);
213 if (!p_drv) {
214 ret = -EINVAL;
215 goto err_put;
216 }
217
218 if (!try_module_get(p_drv->owner)) {
219 ret = -EINVAL;
220 goto err_put_driver;
221 }
222
223 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
224 list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
225 if (p_dev->func == bind_info->function) {
226 if ((p_dev->dev.driver == &p_drv->drv)) {
227 if (p_dev->cardmgr) {
228 /* if there's already a device
229 * registered, and it was registered
230 * by userspace before, we need to
231 * return the "instance". */
232 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
233 bind_info->instance = p_dev->instance;
234 ret = -EBUSY;
235 goto err_put_module;
236 } else {
237 /* the correct driver managed to bind
238 * itself magically to the correct
239 * device. */
240 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
241 p_dev->cardmgr = p_drv;
242 ret = 0;
243 goto err_put_module;
244 }
245 } else if (!p_dev->dev.driver) {
246 /* there's already a device available where
247 * no device has been bound to yet. So we don't
248 * need to register a device! */
249 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
250 goto rescan;
251 }
252 }
253 }
254 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
255
256 p_dev = pcmcia_device_add(s, bind_info->function);
257 if (!p_dev) {
258 ret = -EIO;
259 goto err_put_module;
260 }
261
262rescan:
263 p_dev->cardmgr = p_drv;
264
265 /* if a driver is already running, we can abort */
266 if (p_dev->dev.driver)
267 goto err_put_module;
268
269 /*
270 * Prevent this racing with a card insertion.
271 */
Dominik Brodowskidc109492005-06-27 16:28:50 -0700272 down(&s->skt_sem);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700273 bus_rescan_devices(&pcmcia_bus_type);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700274 up(&s->skt_sem);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700275
276 /* check whether the driver indeed matched. I don't care if this
277 * is racy or not, because it can only happen on cardmgr access
278 * paths...
279 */
280 if (!(p_dev->dev.driver == &p_drv->drv))
281 p_dev->cardmgr = NULL;
282
283 err_put_module:
284 module_put(p_drv->owner);
285 err_put_driver:
286 put_driver(&p_drv->drv);
287 err_put:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700288 pcmcia_put_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700289
290 return (ret);
291} /* bind_request */
292
293
294extern struct pci_bus *pcmcia_lookup_bus(struct pcmcia_socket *s);
295
Dominik Brodowskidc109492005-06-27 16:28:50 -0700296static int get_device_info(struct pcmcia_socket *s, bind_info_t *bind_info, int first)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700297{
298 dev_node_t *node;
299 struct pcmcia_device *p_dev;
300 unsigned long flags;
301 int ret = 0;
302
303#ifdef CONFIG_CARDBUS
304 /*
305 * Some unbelievably ugly code to associate the PCI cardbus
306 * device and its driver with the PCMCIA "bind" information.
307 */
308 {
309 struct pci_bus *bus;
310
Dominik Brodowskidc109492005-06-27 16:28:50 -0700311 bus = pcmcia_lookup_bus(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700312 if (bus) {
313 struct list_head *list;
314 struct pci_dev *dev = NULL;
315
316 list = bus->devices.next;
317 while (list != &bus->devices) {
318 struct pci_dev *pdev = pci_dev_b(list);
319 list = list->next;
320
321 if (first) {
322 dev = pdev;
323 break;
324 }
325
326 /* Try to handle "next" here some way? */
327 }
328 if (dev && dev->driver) {
329 strlcpy(bind_info->name, dev->driver->name, DEV_NAME_LEN);
330 bind_info->major = 0;
331 bind_info->minor = 0;
332 bind_info->next = NULL;
333 return 0;
334 }
335 }
336 }
337#endif
338
339 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
340 list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
341 if (p_dev->func == bind_info->function) {
342 p_dev = pcmcia_get_dev(p_dev);
343 if (!p_dev)
344 continue;
345 goto found;
346 }
347 }
348 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
349 return -ENODEV;
350
351 found:
352 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
353
354 if ((!p_dev->instance) ||
355 (p_dev->instance->state & DEV_CONFIG_PENDING)) {
356 ret = -EAGAIN;
357 goto err_put;
358 }
359
360 if (first)
361 node = p_dev->instance->dev;
362 else
363 for (node = p_dev->instance->dev; node; node = node->next)
364 if (node == bind_info->next)
365 break;
366 if (!node) {
367 ret = -ENODEV;
368 goto err_put;
369 }
370
371 strlcpy(bind_info->name, node->dev_name, DEV_NAME_LEN);
372 bind_info->major = node->major;
373 bind_info->minor = node->minor;
374 bind_info->next = node->next;
375
376 err_put:
377 pcmcia_put_dev(p_dev);
378 return (ret);
379} /* get_device_info */
380
381
382static int ds_open(struct inode *inode, struct file *file)
383{
384 socket_t i = iminor(inode);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700385 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700386 user_info_t *user;
387
388 ds_dbg(0, "ds_open(socket %d)\n", i);
389
Dominik Brodowskidc109492005-06-27 16:28:50 -0700390 s = pcmcia_get_socket_by_nr(i);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700391 if (!s)
392 return -ENODEV;
Dominik Brodowskidc109492005-06-27 16:28:50 -0700393 s = pcmcia_get_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700394 if (!s)
395 return -ENODEV;
396
397 if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700398 if (s->pcmcia_state.busy) {
Dominik Brodowskidc109492005-06-27 16:28:50 -0700399 pcmcia_put_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700400 return -EBUSY;
401 }
402 else
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700403 s->pcmcia_state.busy = 1;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700404 }
405
406 user = kmalloc(sizeof(user_info_t), GFP_KERNEL);
407 if (!user) {
Dominik Brodowskidc109492005-06-27 16:28:50 -0700408 pcmcia_put_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700409 return -ENOMEM;
410 }
411 user->event_tail = user->event_head = 0;
412 user->next = s->user;
413 user->user_magic = USER_MAGIC;
414 user->socket = s;
415 s->user = user;
416 file->private_data = user;
417
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700418 if (s->pcmcia_state.present)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700419 queue_event(user, CS_EVENT_CARD_INSERTION);
420 return 0;
421} /* ds_open */
422
423/*====================================================================*/
424
425static int ds_release(struct inode *inode, struct file *file)
426{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700427 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700428 user_info_t *user, **link;
429
430 ds_dbg(0, "ds_release(socket %d)\n", iminor(inode));
431
432 user = file->private_data;
433 if (CHECK_USER(user))
434 goto out;
435
436 s = user->socket;
437
438 /* Unlink user data structure */
439 if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700440 s->pcmcia_state.busy = 0;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700441 }
442 file->private_data = NULL;
443 for (link = &s->user; *link; link = &(*link)->next)
444 if (*link == user) break;
445 if (link == NULL)
446 goto out;
447 *link = user->next;
448 user->user_magic = 0;
449 kfree(user);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700450 pcmcia_put_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700451out:
452 return 0;
453} /* ds_release */
454
455/*====================================================================*/
456
457static ssize_t ds_read(struct file *file, char __user *buf,
458 size_t count, loff_t *ppos)
459{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700460 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700461 user_info_t *user;
462 int ret;
463
464 ds_dbg(2, "ds_read(socket %d)\n", iminor(file->f_dentry->d_inode));
465
466 if (count < 4)
467 return -EINVAL;
468
469 user = file->private_data;
470 if (CHECK_USER(user))
471 return -EIO;
472
473 s = user->socket;
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700474 if (s->pcmcia_state.dead)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700475 return -EIO;
476
477 ret = wait_event_interruptible(s->queue, !queue_empty(user));
478 if (ret == 0)
479 ret = put_user(get_queued_event(user), (int __user *)buf) ? -EFAULT : 4;
480
481 return ret;
482} /* ds_read */
483
484/*====================================================================*/
485
486static ssize_t ds_write(struct file *file, const char __user *buf,
487 size_t count, loff_t *ppos)
488{
489 ds_dbg(2, "ds_write(socket %d)\n", iminor(file->f_dentry->d_inode));
490
491 if (count != 4)
492 return -EINVAL;
493 if ((file->f_flags & O_ACCMODE) == O_RDONLY)
494 return -EBADF;
495
496 return -EIO;
497} /* ds_write */
498
499/*====================================================================*/
500
501/* No kernel lock - fine */
502static u_int ds_poll(struct file *file, poll_table *wait)
503{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700504 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700505 user_info_t *user;
506
507 ds_dbg(2, "ds_poll(socket %d)\n", iminor(file->f_dentry->d_inode));
508
509 user = file->private_data;
510 if (CHECK_USER(user))
511 return POLLERR;
512 s = user->socket;
513 /*
514 * We don't check for a dead socket here since that
515 * will send cardmgr into an endless spin.
516 */
517 poll_wait(file, &s->queue, wait);
518 if (!queue_empty(user))
519 return POLLIN | POLLRDNORM;
520 return 0;
521} /* ds_poll */
522
523/*====================================================================*/
524
525extern int pcmcia_adjust_resource_info(adjust_t *adj);
526
527static int ds_ioctl(struct inode * inode, struct file * file,
528 u_int cmd, u_long arg)
529{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700530 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700531 void __user *uarg = (char __user *)arg;
532 u_int size;
533 int ret, err;
534 ds_ioctl_arg_t *buf;
535 user_info_t *user;
536
537 ds_dbg(2, "ds_ioctl(socket %d, %#x, %#lx)\n", iminor(inode), cmd, arg);
538
539 user = file->private_data;
540 if (CHECK_USER(user))
541 return -EIO;
542
543 s = user->socket;
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700544 if (s->pcmcia_state.dead)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700545 return -EIO;
546
547 size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
548 if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL;
549
550 /* Permission check */
551 if (!(cmd & IOC_OUT) && !capable(CAP_SYS_ADMIN))
552 return -EPERM;
553
554 if (cmd & IOC_IN) {
555 if (!access_ok(VERIFY_READ, uarg, size)) {
556 ds_dbg(3, "ds_ioctl(): verify_read = %d\n", -EFAULT);
557 return -EFAULT;
558 }
559 }
560 if (cmd & IOC_OUT) {
561 if (!access_ok(VERIFY_WRITE, uarg, size)) {
562 ds_dbg(3, "ds_ioctl(): verify_write = %d\n", -EFAULT);
563 return -EFAULT;
564 }
565 }
566 buf = kmalloc(sizeof(ds_ioctl_arg_t), GFP_KERNEL);
567 if (!buf)
568 return -ENOMEM;
569
570 err = ret = 0;
571
572 if (cmd & IOC_IN) __copy_from_user((char *)buf, uarg, size);
573
574 switch (cmd) {
575 case DS_ADJUST_RESOURCE_INFO:
576 ret = pcmcia_adjust_resource_info(&buf->adjust);
577 break;
578 case DS_GET_CARD_SERVICES_INFO:
579 ret = pcmcia_get_card_services_info(&buf->servinfo);
580 break;
581 case DS_GET_CONFIGURATION_INFO:
582 if (buf->config.Function &&
Dominik Brodowskidc109492005-06-27 16:28:50 -0700583 (buf->config.Function >= s->functions))
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700584 ret = CS_BAD_ARGS;
585 else
Dominik Brodowskidc109492005-06-27 16:28:50 -0700586 ret = pccard_get_configuration_info(s,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700587 buf->config.Function, &buf->config);
588 break;
589 case DS_GET_FIRST_TUPLE:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700590 down(&s->skt_sem);
591 pcmcia_validate_mem(s);
592 up(&s->skt_sem);
593 ret = pccard_get_first_tuple(s, BIND_FN_ALL, &buf->tuple);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700594 break;
595 case DS_GET_NEXT_TUPLE:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700596 ret = pccard_get_next_tuple(s, BIND_FN_ALL, &buf->tuple);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700597 break;
598 case DS_GET_TUPLE_DATA:
599 buf->tuple.TupleData = buf->tuple_parse.data;
600 buf->tuple.TupleDataMax = sizeof(buf->tuple_parse.data);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700601 ret = pccard_get_tuple_data(s, &buf->tuple);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700602 break;
603 case DS_PARSE_TUPLE:
604 buf->tuple.TupleData = buf->tuple_parse.data;
605 ret = pccard_parse_tuple(&buf->tuple, &buf->tuple_parse.parse);
606 break;
607 case DS_RESET_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700608 ret = pccard_reset_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700609 break;
610 case DS_GET_STATUS:
611 if (buf->status.Function &&
Dominik Brodowskidc109492005-06-27 16:28:50 -0700612 (buf->status.Function >= s->functions))
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700613 ret = CS_BAD_ARGS;
614 else
Dominik Brodowskidc109492005-06-27 16:28:50 -0700615 ret = pccard_get_status(s, buf->status.Function, &buf->status);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700616 break;
617 case DS_VALIDATE_CIS:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700618 down(&s->skt_sem);
619 pcmcia_validate_mem(s);
620 up(&s->skt_sem);
621 ret = pccard_validate_cis(s, BIND_FN_ALL, &buf->cisinfo);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700622 break;
623 case DS_SUSPEND_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700624 ret = pcmcia_suspend_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700625 break;
626 case DS_RESUME_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700627 ret = pcmcia_resume_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700628 break;
629 case DS_EJECT_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700630 err = pcmcia_eject_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700631 break;
632 case DS_INSERT_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700633 err = pcmcia_insert_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700634 break;
635 case DS_ACCESS_CONFIGURATION_REGISTER:
636 if ((buf->conf_reg.Action == CS_WRITE) && !capable(CAP_SYS_ADMIN)) {
637 err = -EPERM;
638 goto free_out;
639 }
640 if (buf->conf_reg.Function &&
Dominik Brodowskidc109492005-06-27 16:28:50 -0700641 (buf->conf_reg.Function >= s->functions))
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700642 ret = CS_BAD_ARGS;
643 else
Dominik Brodowskidc109492005-06-27 16:28:50 -0700644 ret = pccard_access_configuration_register(s,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700645 buf->conf_reg.Function, &buf->conf_reg);
646 break;
647 case DS_GET_FIRST_REGION:
648 case DS_GET_NEXT_REGION:
649 case DS_BIND_MTD:
650 if (!capable(CAP_SYS_ADMIN)) {
651 err = -EPERM;
652 goto free_out;
653 } else {
654 static int printed = 0;
655 if (!printed) {
656 printk(KERN_WARNING "2.6. kernels use pcmciamtd instead of memory_cs.c and do not require special\n");
657 printk(KERN_WARNING "MTD handling any more.\n");
658 printed++;
659 }
660 }
661 err = -EINVAL;
662 goto free_out;
663 break;
664 case DS_GET_FIRST_WINDOW:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700665 ret = pcmcia_get_window(s, &buf->win_info.handle, 0,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700666 &buf->win_info.window);
667 break;
668 case DS_GET_NEXT_WINDOW:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700669 ret = pcmcia_get_window(s, &buf->win_info.handle,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700670 buf->win_info.handle->index + 1, &buf->win_info.window);
671 break;
672 case DS_GET_MEM_PAGE:
673 ret = pcmcia_get_mem_page(buf->win_info.handle,
674 &buf->win_info.map);
675 break;
676 case DS_REPLACE_CIS:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700677 ret = pcmcia_replace_cis(s, &buf->cisdump);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700678 break;
679 case DS_BIND_REQUEST:
680 if (!capable(CAP_SYS_ADMIN)) {
681 err = -EPERM;
682 goto free_out;
683 }
684 err = bind_request(s, &buf->bind_info);
685 break;
686 case DS_GET_DEVICE_INFO:
687 err = get_device_info(s, &buf->bind_info, 1);
688 break;
689 case DS_GET_NEXT_DEVICE:
690 err = get_device_info(s, &buf->bind_info, 0);
691 break;
692 case DS_UNBIND_REQUEST:
693 err = 0;
694 break;
695 default:
696 err = -EINVAL;
697 }
698
699 if ((err == 0) && (ret != CS_SUCCESS)) {
700 ds_dbg(2, "ds_ioctl: ret = %d\n", ret);
701 switch (ret) {
702 case CS_BAD_SOCKET: case CS_NO_CARD:
703 err = -ENODEV; break;
704 case CS_BAD_ARGS: case CS_BAD_ATTRIBUTE: case CS_BAD_IRQ:
705 case CS_BAD_TUPLE:
706 err = -EINVAL; break;
707 case CS_IN_USE:
708 err = -EBUSY; break;
709 case CS_OUT_OF_RESOURCE:
710 err = -ENOSPC; break;
711 case CS_NO_MORE_ITEMS:
712 err = -ENODATA; break;
713 case CS_UNSUPPORTED_FUNCTION:
714 err = -ENOSYS; break;
715 default:
716 err = -EIO; break;
717 }
718 }
719
720 if (cmd & IOC_OUT) {
721 if (__copy_to_user(uarg, (char *)buf, size))
722 err = -EFAULT;
723 }
724
725free_out:
726 kfree(buf);
727 return err;
728} /* ds_ioctl */
729
730/*====================================================================*/
731
732static struct file_operations ds_fops = {
733 .owner = THIS_MODULE,
734 .open = ds_open,
735 .release = ds_release,
736 .ioctl = ds_ioctl,
737 .read = ds_read,
738 .write = ds_write,
739 .poll = ds_poll,
740};
741
742void __init pcmcia_setup_ioctl(void) {
743 int i;
744
745 /* Set up character device for user mode clients */
746 i = register_chrdev(0, "pcmcia", &ds_fops);
747 if (i == -EBUSY)
748 printk(KERN_NOTICE "unable to find a free device # for "
749 "Driver Services\n");
750 else
751 major_dev = i;
752
753#ifdef CONFIG_PROC_FS
754 proc_pccard = proc_mkdir("pccard", proc_bus);
755 if (proc_pccard)
756 create_proc_read_entry("drivers",0,proc_pccard,proc_read_drivers,NULL);
757#endif
758}
759
760
761void __exit pcmcia_cleanup_ioctl(void) {
762#ifdef CONFIG_PROC_FS
763 if (proc_pccard) {
764 remove_proc_entry("drivers", proc_pccard);
765 remove_proc_entry("pccard", proc_bus);
766 }
767#endif
768 if (major_dev != -1)
769 unregister_chrdev(major_dev, "pcmcia");
770}