blob: 80969f7e7a0be4eddc31e675ab404e6f144593f3 [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>
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070022#include <linux/kernel.h>
Dominik Brodowski3b659fb2005-06-27 16:28:51 -070023#include <linux/module.h>
24#include <linux/init.h>
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070025#include <linux/major.h>
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070026#include <linux/errno.h>
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070027#include <linux/ioctl.h>
28#include <linux/proc_fs.h>
29#include <linux/poll.h>
30#include <linux/pci.h>
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070031#include <linux/workqueue.h>
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070032
33#define IN_CARD_SERVICES
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070034#include <pcmcia/cs_types.h>
35#include <pcmcia/cs.h>
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070036#include <pcmcia/cistpl.h>
37#include <pcmcia/ds.h>
38#include <pcmcia/ss.h>
39
40#include "cs_internal.h"
41#include "ds_internal.h"
42
43static int major_dev = -1;
44
45
46/* Device user information */
47#define MAX_EVENTS 32
48#define USER_MAGIC 0x7ea4
49#define CHECK_USER(u) \
50 (((u) == NULL) || ((u)->user_magic != USER_MAGIC))
51
52typedef struct user_info_t {
53 u_int user_magic;
54 int event_head, event_tail;
55 event_t event[MAX_EVENTS];
56 struct user_info_t *next;
Dominik Brodowskidc109492005-06-27 16:28:50 -070057 struct pcmcia_socket *socket;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070058} user_info_t;
59
60
61#ifdef DEBUG
62extern int ds_pc_debug;
63#define cs_socket_name(skt) ((skt)->dev.class_id)
64
65#define ds_dbg(lvl, fmt, arg...) do { \
66 if (ds_pc_debug >= lvl) \
67 printk(KERN_DEBUG "ds: " fmt , ## arg); \
68} while (0)
69#else
70#define ds_dbg(lvl, fmt, arg...) do { } while (0)
71#endif
72
73
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070074/* backwards-compatible accessing of driver --- by name! */
75
76static struct pcmcia_driver * get_pcmcia_driver (dev_info_t *dev_info)
77{
78 struct device_driver *drv;
79 struct pcmcia_driver *p_drv;
80
81 drv = driver_find((char *) dev_info, &pcmcia_bus_type);
82 if (!drv)
83 return NULL;
84
85 p_drv = container_of(drv, struct pcmcia_driver, drv);
86
87 return (p_drv);
88}
89
90
91#ifdef CONFIG_PROC_FS
92static struct proc_dir_entry *proc_pccard = NULL;
93
94static int proc_read_drivers_callback(struct device_driver *driver, void *d)
95{
96 char **p = d;
97 struct pcmcia_driver *p_drv = container_of(driver,
98 struct pcmcia_driver, drv);
99
100 *p += sprintf(*p, "%-24.24s 1 %d\n", p_drv->drv.name,
101#ifdef CONFIG_MODULE_UNLOAD
102 (p_drv->owner) ? module_refcount(p_drv->owner) : 1
103#else
104 1
105#endif
106 );
107 d = (void *) p;
108
109 return 0;
110}
111
112static int proc_read_drivers(char *buf, char **start, off_t pos,
113 int count, int *eof, void *data)
114{
115 char *p = buf;
116
117 bus_for_each_drv(&pcmcia_bus_type, NULL,
118 (void *) &p, proc_read_drivers_callback);
119
120 return (p - buf);
121}
122#endif
123
124/*======================================================================
125
126 These manage a ring buffer of events pending for one user process
127
128======================================================================*/
129
130
131static int queue_empty(user_info_t *user)
132{
133 return (user->event_head == user->event_tail);
134}
135
136static event_t get_queued_event(user_info_t *user)
137{
138 user->event_tail = (user->event_tail+1) % MAX_EVENTS;
139 return user->event[user->event_tail];
140}
141
142static void queue_event(user_info_t *user, event_t event)
143{
144 user->event_head = (user->event_head+1) % MAX_EVENTS;
145 if (user->event_head == user->event_tail)
146 user->event_tail = (user->event_tail+1) % MAX_EVENTS;
147 user->event[user->event_head] = event;
148}
149
Dominik Brodowskidc109492005-06-27 16:28:50 -0700150void handle_event(struct pcmcia_socket *s, event_t event)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700151{
152 user_info_t *user;
153 for (user = s->user; user; user = user->next)
154 queue_event(user, event);
155 wake_up_interruptible(&s->queue);
156}
157
158
159/*======================================================================
160
161 bind_request() and bind_device() are merged by now. Register_client()
162 is called right at the end of bind_request(), during the driver's
163 ->attach() call. Individual descriptions:
164
165 bind_request() connects a socket to a particular client driver.
166 It looks up the specified device ID in the list of registered
167 drivers, binds it to the socket, and tries to create an instance
168 of the device. unbind_request() deletes a driver instance.
169
170 Bind_device() associates a device driver with a particular socket.
171 It is normally called by Driver Services after it has identified
172 a newly inserted card. An instance of that driver will then be
173 eligible to register as a client of this socket.
174
175 Register_client() uses the dev_info_t handle to match the
176 caller with a socket. The driver must have already been bound
177 to a socket with bind_device() -- in fact, bind_device()
178 allocates the client structure that will be used.
179
180======================================================================*/
181
Dominik Brodowskidc109492005-06-27 16:28:50 -0700182static int bind_request(struct pcmcia_socket *s, bind_info_t *bind_info)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700183{
184 struct pcmcia_driver *p_drv;
185 struct pcmcia_device *p_dev;
186 int ret = 0;
187 unsigned long flags;
188
Dominik Brodowskidc109492005-06-27 16:28:50 -0700189 s = pcmcia_get_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700190 if (!s)
191 return -EINVAL;
192
Dominik Brodowskidc109492005-06-27 16:28:50 -0700193 ds_dbg(2, "bind_request(%d, '%s')\n", s->sock,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700194 (char *)bind_info->dev_info);
195
196 p_drv = get_pcmcia_driver(&bind_info->dev_info);
197 if (!p_drv) {
198 ret = -EINVAL;
199 goto err_put;
200 }
201
202 if (!try_module_get(p_drv->owner)) {
203 ret = -EINVAL;
204 goto err_put_driver;
205 }
206
207 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
208 list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
209 if (p_dev->func == bind_info->function) {
210 if ((p_dev->dev.driver == &p_drv->drv)) {
211 if (p_dev->cardmgr) {
212 /* if there's already a device
213 * registered, and it was registered
214 * by userspace before, we need to
215 * return the "instance". */
216 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
217 bind_info->instance = p_dev->instance;
218 ret = -EBUSY;
219 goto err_put_module;
220 } else {
221 /* the correct driver managed to bind
222 * itself magically to the correct
223 * device. */
224 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
225 p_dev->cardmgr = p_drv;
226 ret = 0;
227 goto err_put_module;
228 }
229 } else if (!p_dev->dev.driver) {
230 /* there's already a device available where
231 * no device has been bound to yet. So we don't
232 * need to register a device! */
233 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
234 goto rescan;
235 }
236 }
237 }
238 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
239
240 p_dev = pcmcia_device_add(s, bind_info->function);
241 if (!p_dev) {
242 ret = -EIO;
243 goto err_put_module;
244 }
245
246rescan:
247 p_dev->cardmgr = p_drv;
248
249 /* if a driver is already running, we can abort */
250 if (p_dev->dev.driver)
251 goto err_put_module;
252
253 /*
254 * Prevent this racing with a card insertion.
255 */
Dominik Brodowskidc109492005-06-27 16:28:50 -0700256 down(&s->skt_sem);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700257 bus_rescan_devices(&pcmcia_bus_type);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700258 up(&s->skt_sem);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700259
260 /* check whether the driver indeed matched. I don't care if this
261 * is racy or not, because it can only happen on cardmgr access
262 * paths...
263 */
264 if (!(p_dev->dev.driver == &p_drv->drv))
265 p_dev->cardmgr = NULL;
266
267 err_put_module:
268 module_put(p_drv->owner);
269 err_put_driver:
270 put_driver(&p_drv->drv);
271 err_put:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700272 pcmcia_put_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700273
274 return (ret);
275} /* bind_request */
276
Dominik Brodowski33519dd2005-06-27 16:28:53 -0700277#ifdef CONFIG_CARDBUS
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700278
Dominik Brodowski33519dd2005-06-27 16:28:53 -0700279static struct pci_bus *pcmcia_lookup_bus(struct pcmcia_socket *s)
280{
281 if (!s || !(s->state & SOCKET_CARDBUS))
282 return NULL;
283
284 return s->cb_dev->subordinate;
285}
286#endif
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700287
Dominik Brodowskidc109492005-06-27 16:28:50 -0700288static int get_device_info(struct pcmcia_socket *s, bind_info_t *bind_info, int first)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700289{
290 dev_node_t *node;
291 struct pcmcia_device *p_dev;
292 unsigned long flags;
293 int ret = 0;
294
295#ifdef CONFIG_CARDBUS
296 /*
297 * Some unbelievably ugly code to associate the PCI cardbus
298 * device and its driver with the PCMCIA "bind" information.
299 */
300 {
301 struct pci_bus *bus;
302
Dominik Brodowskidc109492005-06-27 16:28:50 -0700303 bus = pcmcia_lookup_bus(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700304 if (bus) {
305 struct list_head *list;
306 struct pci_dev *dev = NULL;
307
308 list = bus->devices.next;
309 while (list != &bus->devices) {
310 struct pci_dev *pdev = pci_dev_b(list);
311 list = list->next;
312
313 if (first) {
314 dev = pdev;
315 break;
316 }
317
318 /* Try to handle "next" here some way? */
319 }
320 if (dev && dev->driver) {
321 strlcpy(bind_info->name, dev->driver->name, DEV_NAME_LEN);
322 bind_info->major = 0;
323 bind_info->minor = 0;
324 bind_info->next = NULL;
325 return 0;
326 }
327 }
328 }
329#endif
330
331 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
332 list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
333 if (p_dev->func == bind_info->function) {
334 p_dev = pcmcia_get_dev(p_dev);
335 if (!p_dev)
336 continue;
337 goto found;
338 }
339 }
340 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
341 return -ENODEV;
342
343 found:
344 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
345
346 if ((!p_dev->instance) ||
347 (p_dev->instance->state & DEV_CONFIG_PENDING)) {
348 ret = -EAGAIN;
349 goto err_put;
350 }
351
352 if (first)
353 node = p_dev->instance->dev;
354 else
355 for (node = p_dev->instance->dev; node; node = node->next)
356 if (node == bind_info->next)
357 break;
358 if (!node) {
359 ret = -ENODEV;
360 goto err_put;
361 }
362
363 strlcpy(bind_info->name, node->dev_name, DEV_NAME_LEN);
364 bind_info->major = node->major;
365 bind_info->minor = node->minor;
366 bind_info->next = node->next;
367
368 err_put:
369 pcmcia_put_dev(p_dev);
370 return (ret);
371} /* get_device_info */
372
373
374static int ds_open(struct inode *inode, struct file *file)
375{
376 socket_t i = iminor(inode);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700377 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700378 user_info_t *user;
Dominik Brodowskic352ec82005-09-13 01:25:03 -0700379 static int warning_printed = 0;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700380
381 ds_dbg(0, "ds_open(socket %d)\n", i);
382
Dominik Brodowskidc109492005-06-27 16:28:50 -0700383 s = pcmcia_get_socket_by_nr(i);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700384 if (!s)
385 return -ENODEV;
Dominik Brodowskidc109492005-06-27 16:28:50 -0700386 s = pcmcia_get_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700387 if (!s)
388 return -ENODEV;
389
390 if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700391 if (s->pcmcia_state.busy) {
Dominik Brodowskidc109492005-06-27 16:28:50 -0700392 pcmcia_put_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700393 return -EBUSY;
394 }
395 else
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700396 s->pcmcia_state.busy = 1;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700397 }
398
399 user = kmalloc(sizeof(user_info_t), GFP_KERNEL);
400 if (!user) {
Dominik Brodowskidc109492005-06-27 16:28:50 -0700401 pcmcia_put_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700402 return -ENOMEM;
403 }
404 user->event_tail = user->event_head = 0;
405 user->next = s->user;
406 user->user_magic = USER_MAGIC;
407 user->socket = s;
408 s->user = user;
409 file->private_data = user;
410
Dominik Brodowskic352ec82005-09-13 01:25:03 -0700411 if (!warning_printed) {
412 printk(KERN_INFO "pcmcia: Detected deprecated PCMCIA ioctl "
413 "usage.\n");
414 printk(KERN_INFO "pcmcia: This interface will soon be removed from "
415 "the kernel; please expect breakage unless you upgrade "
416 "to new tools.\n");
417 printk(KERN_INFO "pcmcia: see http://www.kernel.org/pub/linux/"
418 "utils/kernel/pcmcia/pcmcia.html for details.\n");
419 warning_printed = 1;
420 }
421
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700422 if (s->pcmcia_state.present)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700423 queue_event(user, CS_EVENT_CARD_INSERTION);
424 return 0;
425} /* ds_open */
426
427/*====================================================================*/
428
429static int ds_release(struct inode *inode, struct file *file)
430{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700431 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700432 user_info_t *user, **link;
433
434 ds_dbg(0, "ds_release(socket %d)\n", iminor(inode));
435
436 user = file->private_data;
437 if (CHECK_USER(user))
438 goto out;
439
440 s = user->socket;
441
442 /* Unlink user data structure */
443 if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700444 s->pcmcia_state.busy = 0;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700445 }
446 file->private_data = NULL;
447 for (link = &s->user; *link; link = &(*link)->next)
448 if (*link == user) break;
449 if (link == NULL)
450 goto out;
451 *link = user->next;
452 user->user_magic = 0;
453 kfree(user);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700454 pcmcia_put_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700455out:
456 return 0;
457} /* ds_release */
458
459/*====================================================================*/
460
461static ssize_t ds_read(struct file *file, char __user *buf,
462 size_t count, loff_t *ppos)
463{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700464 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700465 user_info_t *user;
466 int ret;
467
468 ds_dbg(2, "ds_read(socket %d)\n", iminor(file->f_dentry->d_inode));
469
470 if (count < 4)
471 return -EINVAL;
472
473 user = file->private_data;
474 if (CHECK_USER(user))
475 return -EIO;
476
477 s = user->socket;
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700478 if (s->pcmcia_state.dead)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700479 return -EIO;
480
481 ret = wait_event_interruptible(s->queue, !queue_empty(user));
482 if (ret == 0)
483 ret = put_user(get_queued_event(user), (int __user *)buf) ? -EFAULT : 4;
484
485 return ret;
486} /* ds_read */
487
488/*====================================================================*/
489
490static ssize_t ds_write(struct file *file, const char __user *buf,
491 size_t count, loff_t *ppos)
492{
493 ds_dbg(2, "ds_write(socket %d)\n", iminor(file->f_dentry->d_inode));
494
495 if (count != 4)
496 return -EINVAL;
497 if ((file->f_flags & O_ACCMODE) == O_RDONLY)
498 return -EBADF;
499
500 return -EIO;
501} /* ds_write */
502
503/*====================================================================*/
504
505/* No kernel lock - fine */
506static u_int ds_poll(struct file *file, poll_table *wait)
507{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700508 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700509 user_info_t *user;
510
511 ds_dbg(2, "ds_poll(socket %d)\n", iminor(file->f_dentry->d_inode));
512
513 user = file->private_data;
514 if (CHECK_USER(user))
515 return POLLERR;
516 s = user->socket;
517 /*
518 * We don't check for a dead socket here since that
519 * will send cardmgr into an endless spin.
520 */
521 poll_wait(file, &s->queue, wait);
522 if (!queue_empty(user))
523 return POLLIN | POLLRDNORM;
524 return 0;
525} /* ds_poll */
526
527/*====================================================================*/
528
529extern int pcmcia_adjust_resource_info(adjust_t *adj);
530
531static int ds_ioctl(struct inode * inode, struct file * file,
532 u_int cmd, u_long arg)
533{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700534 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700535 void __user *uarg = (char __user *)arg;
536 u_int size;
537 int ret, err;
538 ds_ioctl_arg_t *buf;
539 user_info_t *user;
540
541 ds_dbg(2, "ds_ioctl(socket %d, %#x, %#lx)\n", iminor(inode), cmd, arg);
542
543 user = file->private_data;
544 if (CHECK_USER(user))
545 return -EIO;
546
547 s = user->socket;
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700548 if (s->pcmcia_state.dead)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700549 return -EIO;
550
551 size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
552 if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL;
553
554 /* Permission check */
555 if (!(cmd & IOC_OUT) && !capable(CAP_SYS_ADMIN))
556 return -EPERM;
557
558 if (cmd & IOC_IN) {
559 if (!access_ok(VERIFY_READ, uarg, size)) {
560 ds_dbg(3, "ds_ioctl(): verify_read = %d\n", -EFAULT);
561 return -EFAULT;
562 }
563 }
564 if (cmd & IOC_OUT) {
565 if (!access_ok(VERIFY_WRITE, uarg, size)) {
566 ds_dbg(3, "ds_ioctl(): verify_write = %d\n", -EFAULT);
567 return -EFAULT;
568 }
569 }
570 buf = kmalloc(sizeof(ds_ioctl_arg_t), GFP_KERNEL);
571 if (!buf)
572 return -ENOMEM;
573
574 err = ret = 0;
575
576 if (cmd & IOC_IN) __copy_from_user((char *)buf, uarg, size);
577
578 switch (cmd) {
579 case DS_ADJUST_RESOURCE_INFO:
580 ret = pcmcia_adjust_resource_info(&buf->adjust);
581 break;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700582 case DS_GET_CONFIGURATION_INFO:
583 if (buf->config.Function &&
Dominik Brodowskidc109492005-06-27 16:28:50 -0700584 (buf->config.Function >= s->functions))
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700585 ret = CS_BAD_ARGS;
586 else
Dominik Brodowskidc109492005-06-27 16:28:50 -0700587 ret = pccard_get_configuration_info(s,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700588 buf->config.Function, &buf->config);
589 break;
590 case DS_GET_FIRST_TUPLE:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700591 down(&s->skt_sem);
592 pcmcia_validate_mem(s);
593 up(&s->skt_sem);
594 ret = pccard_get_first_tuple(s, BIND_FN_ALL, &buf->tuple);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700595 break;
596 case DS_GET_NEXT_TUPLE:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700597 ret = pccard_get_next_tuple(s, BIND_FN_ALL, &buf->tuple);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700598 break;
599 case DS_GET_TUPLE_DATA:
600 buf->tuple.TupleData = buf->tuple_parse.data;
601 buf->tuple.TupleDataMax = sizeof(buf->tuple_parse.data);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700602 ret = pccard_get_tuple_data(s, &buf->tuple);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700603 break;
604 case DS_PARSE_TUPLE:
605 buf->tuple.TupleData = buf->tuple_parse.data;
606 ret = pccard_parse_tuple(&buf->tuple, &buf->tuple_parse.parse);
607 break;
608 case DS_RESET_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700609 ret = pccard_reset_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700610 break;
611 case DS_GET_STATUS:
612 if (buf->status.Function &&
Dominik Brodowskidc109492005-06-27 16:28:50 -0700613 (buf->status.Function >= s->functions))
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700614 ret = CS_BAD_ARGS;
615 else
Dominik Brodowskidc109492005-06-27 16:28:50 -0700616 ret = pccard_get_status(s, buf->status.Function, &buf->status);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700617 break;
618 case DS_VALIDATE_CIS:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700619 down(&s->skt_sem);
620 pcmcia_validate_mem(s);
621 up(&s->skt_sem);
622 ret = pccard_validate_cis(s, BIND_FN_ALL, &buf->cisinfo);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700623 break;
624 case DS_SUSPEND_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700625 ret = pcmcia_suspend_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700626 break;
627 case DS_RESUME_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700628 ret = pcmcia_resume_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700629 break;
630 case DS_EJECT_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700631 err = pcmcia_eject_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700632 break;
633 case DS_INSERT_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700634 err = pcmcia_insert_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700635 break;
636 case DS_ACCESS_CONFIGURATION_REGISTER:
637 if ((buf->conf_reg.Action == CS_WRITE) && !capable(CAP_SYS_ADMIN)) {
638 err = -EPERM;
639 goto free_out;
640 }
641 if (buf->conf_reg.Function &&
Dominik Brodowskidc109492005-06-27 16:28:50 -0700642 (buf->conf_reg.Function >= s->functions))
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700643 ret = CS_BAD_ARGS;
644 else
Dominik Brodowskidc109492005-06-27 16:28:50 -0700645 ret = pccard_access_configuration_register(s,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700646 buf->conf_reg.Function, &buf->conf_reg);
647 break;
648 case DS_GET_FIRST_REGION:
649 case DS_GET_NEXT_REGION:
650 case DS_BIND_MTD:
651 if (!capable(CAP_SYS_ADMIN)) {
652 err = -EPERM;
653 goto free_out;
654 } else {
655 static int printed = 0;
656 if (!printed) {
657 printk(KERN_WARNING "2.6. kernels use pcmciamtd instead of memory_cs.c and do not require special\n");
658 printk(KERN_WARNING "MTD handling any more.\n");
659 printed++;
660 }
661 }
662 err = -EINVAL;
663 goto free_out;
664 break;
665 case DS_GET_FIRST_WINDOW:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700666 ret = pcmcia_get_window(s, &buf->win_info.handle, 0,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700667 &buf->win_info.window);
668 break;
669 case DS_GET_NEXT_WINDOW:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700670 ret = pcmcia_get_window(s, &buf->win_info.handle,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700671 buf->win_info.handle->index + 1, &buf->win_info.window);
672 break;
673 case DS_GET_MEM_PAGE:
674 ret = pcmcia_get_mem_page(buf->win_info.handle,
675 &buf->win_info.map);
676 break;
677 case DS_REPLACE_CIS:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700678 ret = pcmcia_replace_cis(s, &buf->cisdump);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700679 break;
680 case DS_BIND_REQUEST:
681 if (!capable(CAP_SYS_ADMIN)) {
682 err = -EPERM;
683 goto free_out;
684 }
685 err = bind_request(s, &buf->bind_info);
686 break;
687 case DS_GET_DEVICE_INFO:
688 err = get_device_info(s, &buf->bind_info, 1);
689 break;
690 case DS_GET_NEXT_DEVICE:
691 err = get_device_info(s, &buf->bind_info, 0);
692 break;
693 case DS_UNBIND_REQUEST:
694 err = 0;
695 break;
696 default:
697 err = -EINVAL;
698 }
699
700 if ((err == 0) && (ret != CS_SUCCESS)) {
701 ds_dbg(2, "ds_ioctl: ret = %d\n", ret);
702 switch (ret) {
703 case CS_BAD_SOCKET: case CS_NO_CARD:
704 err = -ENODEV; break;
705 case CS_BAD_ARGS: case CS_BAD_ATTRIBUTE: case CS_BAD_IRQ:
706 case CS_BAD_TUPLE:
707 err = -EINVAL; break;
708 case CS_IN_USE:
709 err = -EBUSY; break;
710 case CS_OUT_OF_RESOURCE:
711 err = -ENOSPC; break;
712 case CS_NO_MORE_ITEMS:
713 err = -ENODATA; break;
714 case CS_UNSUPPORTED_FUNCTION:
715 err = -ENOSYS; break;
716 default:
717 err = -EIO; break;
718 }
719 }
720
721 if (cmd & IOC_OUT) {
722 if (__copy_to_user(uarg, (char *)buf, size))
723 err = -EFAULT;
724 }
725
726free_out:
727 kfree(buf);
728 return err;
729} /* ds_ioctl */
730
731/*====================================================================*/
732
733static struct file_operations ds_fops = {
734 .owner = THIS_MODULE,
735 .open = ds_open,
736 .release = ds_release,
737 .ioctl = ds_ioctl,
738 .read = ds_read,
739 .write = ds_write,
740 .poll = ds_poll,
741};
742
743void __init pcmcia_setup_ioctl(void) {
744 int i;
745
746 /* Set up character device for user mode clients */
747 i = register_chrdev(0, "pcmcia", &ds_fops);
Dominik Brodowski1a8ceaf2005-06-27 16:29:00 -0700748 if (i < 0)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700749 printk(KERN_NOTICE "unable to find a free device # for "
Dominik Brodowski1a8ceaf2005-06-27 16:29:00 -0700750 "Driver Services (error=%d)\n", i);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700751 else
752 major_dev = i;
753
754#ifdef CONFIG_PROC_FS
755 proc_pccard = proc_mkdir("pccard", proc_bus);
756 if (proc_pccard)
757 create_proc_read_entry("drivers",0,proc_pccard,proc_read_drivers,NULL);
758#endif
759}
760
761
762void __exit pcmcia_cleanup_ioctl(void) {
763#ifdef CONFIG_PROC_FS
764 if (proc_pccard) {
765 remove_proc_entry("drivers", proc_pccard);
766 remove_proc_entry("pccard", proc_bus);
767 }
768#endif
769 if (major_dev != -1)
770 unregister_chrdev(major_dev, "pcmcia");
771}