blob: fa2a79d29e165b90193cb04da73d1dedeb061f5f [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
34#include <pcmcia/version.h>
35#include <pcmcia/cs_types.h>
36#include <pcmcia/cs.h>
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070037#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;
Dominik Brodowskidc109492005-06-27 16:28:50 -070058 struct pcmcia_socket *socket;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070059} 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
74
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070075/* backwards-compatible accessing of driver --- by name! */
76
77static struct pcmcia_driver * get_pcmcia_driver (dev_info_t *dev_info)
78{
79 struct device_driver *drv;
80 struct pcmcia_driver *p_drv;
81
82 drv = driver_find((char *) dev_info, &pcmcia_bus_type);
83 if (!drv)
84 return NULL;
85
86 p_drv = container_of(drv, struct pcmcia_driver, drv);
87
88 return (p_drv);
89}
90
91
92#ifdef CONFIG_PROC_FS
93static struct proc_dir_entry *proc_pccard = NULL;
94
95static int proc_read_drivers_callback(struct device_driver *driver, void *d)
96{
97 char **p = d;
98 struct pcmcia_driver *p_drv = container_of(driver,
99 struct pcmcia_driver, drv);
100
101 *p += sprintf(*p, "%-24.24s 1 %d\n", p_drv->drv.name,
102#ifdef CONFIG_MODULE_UNLOAD
103 (p_drv->owner) ? module_refcount(p_drv->owner) : 1
104#else
105 1
106#endif
107 );
108 d = (void *) p;
109
110 return 0;
111}
112
113static int proc_read_drivers(char *buf, char **start, off_t pos,
114 int count, int *eof, void *data)
115{
116 char *p = buf;
117
118 bus_for_each_drv(&pcmcia_bus_type, NULL,
119 (void *) &p, proc_read_drivers_callback);
120
121 return (p - buf);
122}
123#endif
124
125/*======================================================================
126
127 These manage a ring buffer of events pending for one user process
128
129======================================================================*/
130
131
132static int queue_empty(user_info_t *user)
133{
134 return (user->event_head == user->event_tail);
135}
136
137static event_t get_queued_event(user_info_t *user)
138{
139 user->event_tail = (user->event_tail+1) % MAX_EVENTS;
140 return user->event[user->event_tail];
141}
142
143static void queue_event(user_info_t *user, event_t event)
144{
145 user->event_head = (user->event_head+1) % MAX_EVENTS;
146 if (user->event_head == user->event_tail)
147 user->event_tail = (user->event_tail+1) % MAX_EVENTS;
148 user->event[user->event_head] = event;
149}
150
Dominik Brodowskidc109492005-06-27 16:28:50 -0700151void handle_event(struct pcmcia_socket *s, event_t event)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700152{
153 user_info_t *user;
154 for (user = s->user; user; user = user->next)
155 queue_event(user, event);
156 wake_up_interruptible(&s->queue);
157}
158
159
160/*======================================================================
161
162 bind_request() and bind_device() are merged by now. Register_client()
163 is called right at the end of bind_request(), during the driver's
164 ->attach() call. Individual descriptions:
165
166 bind_request() connects a socket to a particular client driver.
167 It looks up the specified device ID in the list of registered
168 drivers, binds it to the socket, and tries to create an instance
169 of the device. unbind_request() deletes a driver instance.
170
171 Bind_device() associates a device driver with a particular socket.
172 It is normally called by Driver Services after it has identified
173 a newly inserted card. An instance of that driver will then be
174 eligible to register as a client of this socket.
175
176 Register_client() uses the dev_info_t handle to match the
177 caller with a socket. The driver must have already been bound
178 to a socket with bind_device() -- in fact, bind_device()
179 allocates the client structure that will be used.
180
181======================================================================*/
182
Dominik Brodowskidc109492005-06-27 16:28:50 -0700183static int bind_request(struct pcmcia_socket *s, bind_info_t *bind_info)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700184{
185 struct pcmcia_driver *p_drv;
186 struct pcmcia_device *p_dev;
187 int ret = 0;
188 unsigned long flags;
189
Dominik Brodowskidc109492005-06-27 16:28:50 -0700190 s = pcmcia_get_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700191 if (!s)
192 return -EINVAL;
193
Dominik Brodowskidc109492005-06-27 16:28:50 -0700194 ds_dbg(2, "bind_request(%d, '%s')\n", s->sock,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700195 (char *)bind_info->dev_info);
196
197 p_drv = get_pcmcia_driver(&bind_info->dev_info);
198 if (!p_drv) {
199 ret = -EINVAL;
200 goto err_put;
201 }
202
203 if (!try_module_get(p_drv->owner)) {
204 ret = -EINVAL;
205 goto err_put_driver;
206 }
207
208 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
209 list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
210 if (p_dev->func == bind_info->function) {
211 if ((p_dev->dev.driver == &p_drv->drv)) {
212 if (p_dev->cardmgr) {
213 /* if there's already a device
214 * registered, and it was registered
215 * by userspace before, we need to
216 * return the "instance". */
217 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
218 bind_info->instance = p_dev->instance;
219 ret = -EBUSY;
220 goto err_put_module;
221 } else {
222 /* the correct driver managed to bind
223 * itself magically to the correct
224 * device. */
225 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
226 p_dev->cardmgr = p_drv;
227 ret = 0;
228 goto err_put_module;
229 }
230 } else if (!p_dev->dev.driver) {
231 /* there's already a device available where
232 * no device has been bound to yet. So we don't
233 * need to register a device! */
234 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
235 goto rescan;
236 }
237 }
238 }
239 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
240
241 p_dev = pcmcia_device_add(s, bind_info->function);
242 if (!p_dev) {
243 ret = -EIO;
244 goto err_put_module;
245 }
246
247rescan:
248 p_dev->cardmgr = p_drv;
249
250 /* if a driver is already running, we can abort */
251 if (p_dev->dev.driver)
252 goto err_put_module;
253
254 /*
255 * Prevent this racing with a card insertion.
256 */
Dominik Brodowskidc109492005-06-27 16:28:50 -0700257 down(&s->skt_sem);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700258 bus_rescan_devices(&pcmcia_bus_type);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700259 up(&s->skt_sem);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700260
261 /* check whether the driver indeed matched. I don't care if this
262 * is racy or not, because it can only happen on cardmgr access
263 * paths...
264 */
265 if (!(p_dev->dev.driver == &p_drv->drv))
266 p_dev->cardmgr = NULL;
267
268 err_put_module:
269 module_put(p_drv->owner);
270 err_put_driver:
271 put_driver(&p_drv->drv);
272 err_put:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700273 pcmcia_put_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700274
275 return (ret);
276} /* bind_request */
277
Dominik Brodowski33519dd2005-06-27 16:28:53 -0700278#ifdef CONFIG_CARDBUS
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700279
Dominik Brodowski33519dd2005-06-27 16:28:53 -0700280static struct pci_bus *pcmcia_lookup_bus(struct pcmcia_socket *s)
281{
282 if (!s || !(s->state & SOCKET_CARDBUS))
283 return NULL;
284
285 return s->cb_dev->subordinate;
286}
287#endif
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700288
Dominik Brodowskidc109492005-06-27 16:28:50 -0700289static int get_device_info(struct pcmcia_socket *s, bind_info_t *bind_info, int first)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700290{
291 dev_node_t *node;
292 struct pcmcia_device *p_dev;
293 unsigned long flags;
294 int ret = 0;
295
296#ifdef CONFIG_CARDBUS
297 /*
298 * Some unbelievably ugly code to associate the PCI cardbus
299 * device and its driver with the PCMCIA "bind" information.
300 */
301 {
302 struct pci_bus *bus;
303
Dominik Brodowskidc109492005-06-27 16:28:50 -0700304 bus = pcmcia_lookup_bus(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700305 if (bus) {
306 struct list_head *list;
307 struct pci_dev *dev = NULL;
308
309 list = bus->devices.next;
310 while (list != &bus->devices) {
311 struct pci_dev *pdev = pci_dev_b(list);
312 list = list->next;
313
314 if (first) {
315 dev = pdev;
316 break;
317 }
318
319 /* Try to handle "next" here some way? */
320 }
321 if (dev && dev->driver) {
322 strlcpy(bind_info->name, dev->driver->name, DEV_NAME_LEN);
323 bind_info->major = 0;
324 bind_info->minor = 0;
325 bind_info->next = NULL;
326 return 0;
327 }
328 }
329 }
330#endif
331
332 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
333 list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
334 if (p_dev->func == bind_info->function) {
335 p_dev = pcmcia_get_dev(p_dev);
336 if (!p_dev)
337 continue;
338 goto found;
339 }
340 }
341 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
342 return -ENODEV;
343
344 found:
345 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
346
347 if ((!p_dev->instance) ||
348 (p_dev->instance->state & DEV_CONFIG_PENDING)) {
349 ret = -EAGAIN;
350 goto err_put;
351 }
352
353 if (first)
354 node = p_dev->instance->dev;
355 else
356 for (node = p_dev->instance->dev; node; node = node->next)
357 if (node == bind_info->next)
358 break;
359 if (!node) {
360 ret = -ENODEV;
361 goto err_put;
362 }
363
364 strlcpy(bind_info->name, node->dev_name, DEV_NAME_LEN);
365 bind_info->major = node->major;
366 bind_info->minor = node->minor;
367 bind_info->next = node->next;
368
369 err_put:
370 pcmcia_put_dev(p_dev);
371 return (ret);
372} /* get_device_info */
373
374
375static int ds_open(struct inode *inode, struct file *file)
376{
377 socket_t i = iminor(inode);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700378 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700379 user_info_t *user;
380
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 Brodowskib5e43912005-06-27 16:28:50 -0700411 if (s->pcmcia_state.present)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700412 queue_event(user, CS_EVENT_CARD_INSERTION);
413 return 0;
414} /* ds_open */
415
416/*====================================================================*/
417
418static int ds_release(struct inode *inode, struct file *file)
419{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700420 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700421 user_info_t *user, **link;
422
423 ds_dbg(0, "ds_release(socket %d)\n", iminor(inode));
424
425 user = file->private_data;
426 if (CHECK_USER(user))
427 goto out;
428
429 s = user->socket;
430
431 /* Unlink user data structure */
432 if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700433 s->pcmcia_state.busy = 0;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700434 }
435 file->private_data = NULL;
436 for (link = &s->user; *link; link = &(*link)->next)
437 if (*link == user) break;
438 if (link == NULL)
439 goto out;
440 *link = user->next;
441 user->user_magic = 0;
442 kfree(user);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700443 pcmcia_put_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700444out:
445 return 0;
446} /* ds_release */
447
448/*====================================================================*/
449
450static ssize_t ds_read(struct file *file, char __user *buf,
451 size_t count, loff_t *ppos)
452{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700453 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700454 user_info_t *user;
455 int ret;
456
457 ds_dbg(2, "ds_read(socket %d)\n", iminor(file->f_dentry->d_inode));
458
459 if (count < 4)
460 return -EINVAL;
461
462 user = file->private_data;
463 if (CHECK_USER(user))
464 return -EIO;
465
466 s = user->socket;
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700467 if (s->pcmcia_state.dead)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700468 return -EIO;
469
470 ret = wait_event_interruptible(s->queue, !queue_empty(user));
471 if (ret == 0)
472 ret = put_user(get_queued_event(user), (int __user *)buf) ? -EFAULT : 4;
473
474 return ret;
475} /* ds_read */
476
477/*====================================================================*/
478
479static ssize_t ds_write(struct file *file, const char __user *buf,
480 size_t count, loff_t *ppos)
481{
482 ds_dbg(2, "ds_write(socket %d)\n", iminor(file->f_dentry->d_inode));
483
484 if (count != 4)
485 return -EINVAL;
486 if ((file->f_flags & O_ACCMODE) == O_RDONLY)
487 return -EBADF;
488
489 return -EIO;
490} /* ds_write */
491
492/*====================================================================*/
493
494/* No kernel lock - fine */
495static u_int ds_poll(struct file *file, poll_table *wait)
496{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700497 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700498 user_info_t *user;
499
500 ds_dbg(2, "ds_poll(socket %d)\n", iminor(file->f_dentry->d_inode));
501
502 user = file->private_data;
503 if (CHECK_USER(user))
504 return POLLERR;
505 s = user->socket;
506 /*
507 * We don't check for a dead socket here since that
508 * will send cardmgr into an endless spin.
509 */
510 poll_wait(file, &s->queue, wait);
511 if (!queue_empty(user))
512 return POLLIN | POLLRDNORM;
513 return 0;
514} /* ds_poll */
515
516/*====================================================================*/
517
518extern int pcmcia_adjust_resource_info(adjust_t *adj);
519
520static int ds_ioctl(struct inode * inode, struct file * file,
521 u_int cmd, u_long arg)
522{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700523 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700524 void __user *uarg = (char __user *)arg;
525 u_int size;
526 int ret, err;
527 ds_ioctl_arg_t *buf;
528 user_info_t *user;
529
530 ds_dbg(2, "ds_ioctl(socket %d, %#x, %#lx)\n", iminor(inode), cmd, arg);
531
532 user = file->private_data;
533 if (CHECK_USER(user))
534 return -EIO;
535
536 s = user->socket;
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700537 if (s->pcmcia_state.dead)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700538 return -EIO;
539
540 size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
541 if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL;
542
543 /* Permission check */
544 if (!(cmd & IOC_OUT) && !capable(CAP_SYS_ADMIN))
545 return -EPERM;
546
547 if (cmd & IOC_IN) {
548 if (!access_ok(VERIFY_READ, uarg, size)) {
549 ds_dbg(3, "ds_ioctl(): verify_read = %d\n", -EFAULT);
550 return -EFAULT;
551 }
552 }
553 if (cmd & IOC_OUT) {
554 if (!access_ok(VERIFY_WRITE, uarg, size)) {
555 ds_dbg(3, "ds_ioctl(): verify_write = %d\n", -EFAULT);
556 return -EFAULT;
557 }
558 }
559 buf = kmalloc(sizeof(ds_ioctl_arg_t), GFP_KERNEL);
560 if (!buf)
561 return -ENOMEM;
562
563 err = ret = 0;
564
565 if (cmd & IOC_IN) __copy_from_user((char *)buf, uarg, size);
566
567 switch (cmd) {
568 case DS_ADJUST_RESOURCE_INFO:
569 ret = pcmcia_adjust_resource_info(&buf->adjust);
570 break;
571 case DS_GET_CARD_SERVICES_INFO:
572 ret = pcmcia_get_card_services_info(&buf->servinfo);
573 break;
574 case DS_GET_CONFIGURATION_INFO:
575 if (buf->config.Function &&
Dominik Brodowskidc109492005-06-27 16:28:50 -0700576 (buf->config.Function >= s->functions))
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700577 ret = CS_BAD_ARGS;
578 else
Dominik Brodowskidc109492005-06-27 16:28:50 -0700579 ret = pccard_get_configuration_info(s,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700580 buf->config.Function, &buf->config);
581 break;
582 case DS_GET_FIRST_TUPLE:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700583 down(&s->skt_sem);
584 pcmcia_validate_mem(s);
585 up(&s->skt_sem);
586 ret = pccard_get_first_tuple(s, BIND_FN_ALL, &buf->tuple);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700587 break;
588 case DS_GET_NEXT_TUPLE:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700589 ret = pccard_get_next_tuple(s, BIND_FN_ALL, &buf->tuple);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700590 break;
591 case DS_GET_TUPLE_DATA:
592 buf->tuple.TupleData = buf->tuple_parse.data;
593 buf->tuple.TupleDataMax = sizeof(buf->tuple_parse.data);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700594 ret = pccard_get_tuple_data(s, &buf->tuple);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700595 break;
596 case DS_PARSE_TUPLE:
597 buf->tuple.TupleData = buf->tuple_parse.data;
598 ret = pccard_parse_tuple(&buf->tuple, &buf->tuple_parse.parse);
599 break;
600 case DS_RESET_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700601 ret = pccard_reset_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700602 break;
603 case DS_GET_STATUS:
604 if (buf->status.Function &&
Dominik Brodowskidc109492005-06-27 16:28:50 -0700605 (buf->status.Function >= s->functions))
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700606 ret = CS_BAD_ARGS;
607 else
Dominik Brodowskidc109492005-06-27 16:28:50 -0700608 ret = pccard_get_status(s, buf->status.Function, &buf->status);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700609 break;
610 case DS_VALIDATE_CIS:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700611 down(&s->skt_sem);
612 pcmcia_validate_mem(s);
613 up(&s->skt_sem);
614 ret = pccard_validate_cis(s, BIND_FN_ALL, &buf->cisinfo);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700615 break;
616 case DS_SUSPEND_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700617 ret = pcmcia_suspend_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700618 break;
619 case DS_RESUME_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700620 ret = pcmcia_resume_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700621 break;
622 case DS_EJECT_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700623 err = pcmcia_eject_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700624 break;
625 case DS_INSERT_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700626 err = pcmcia_insert_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700627 break;
628 case DS_ACCESS_CONFIGURATION_REGISTER:
629 if ((buf->conf_reg.Action == CS_WRITE) && !capable(CAP_SYS_ADMIN)) {
630 err = -EPERM;
631 goto free_out;
632 }
633 if (buf->conf_reg.Function &&
Dominik Brodowskidc109492005-06-27 16:28:50 -0700634 (buf->conf_reg.Function >= s->functions))
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700635 ret = CS_BAD_ARGS;
636 else
Dominik Brodowskidc109492005-06-27 16:28:50 -0700637 ret = pccard_access_configuration_register(s,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700638 buf->conf_reg.Function, &buf->conf_reg);
639 break;
640 case DS_GET_FIRST_REGION:
641 case DS_GET_NEXT_REGION:
642 case DS_BIND_MTD:
643 if (!capable(CAP_SYS_ADMIN)) {
644 err = -EPERM;
645 goto free_out;
646 } else {
647 static int printed = 0;
648 if (!printed) {
649 printk(KERN_WARNING "2.6. kernels use pcmciamtd instead of memory_cs.c and do not require special\n");
650 printk(KERN_WARNING "MTD handling any more.\n");
651 printed++;
652 }
653 }
654 err = -EINVAL;
655 goto free_out;
656 break;
657 case DS_GET_FIRST_WINDOW:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700658 ret = pcmcia_get_window(s, &buf->win_info.handle, 0,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700659 &buf->win_info.window);
660 break;
661 case DS_GET_NEXT_WINDOW:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700662 ret = pcmcia_get_window(s, &buf->win_info.handle,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700663 buf->win_info.handle->index + 1, &buf->win_info.window);
664 break;
665 case DS_GET_MEM_PAGE:
666 ret = pcmcia_get_mem_page(buf->win_info.handle,
667 &buf->win_info.map);
668 break;
669 case DS_REPLACE_CIS:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700670 ret = pcmcia_replace_cis(s, &buf->cisdump);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700671 break;
672 case DS_BIND_REQUEST:
673 if (!capable(CAP_SYS_ADMIN)) {
674 err = -EPERM;
675 goto free_out;
676 }
677 err = bind_request(s, &buf->bind_info);
678 break;
679 case DS_GET_DEVICE_INFO:
680 err = get_device_info(s, &buf->bind_info, 1);
681 break;
682 case DS_GET_NEXT_DEVICE:
683 err = get_device_info(s, &buf->bind_info, 0);
684 break;
685 case DS_UNBIND_REQUEST:
686 err = 0;
687 break;
688 default:
689 err = -EINVAL;
690 }
691
692 if ((err == 0) && (ret != CS_SUCCESS)) {
693 ds_dbg(2, "ds_ioctl: ret = %d\n", ret);
694 switch (ret) {
695 case CS_BAD_SOCKET: case CS_NO_CARD:
696 err = -ENODEV; break;
697 case CS_BAD_ARGS: case CS_BAD_ATTRIBUTE: case CS_BAD_IRQ:
698 case CS_BAD_TUPLE:
699 err = -EINVAL; break;
700 case CS_IN_USE:
701 err = -EBUSY; break;
702 case CS_OUT_OF_RESOURCE:
703 err = -ENOSPC; break;
704 case CS_NO_MORE_ITEMS:
705 err = -ENODATA; break;
706 case CS_UNSUPPORTED_FUNCTION:
707 err = -ENOSYS; break;
708 default:
709 err = -EIO; break;
710 }
711 }
712
713 if (cmd & IOC_OUT) {
714 if (__copy_to_user(uarg, (char *)buf, size))
715 err = -EFAULT;
716 }
717
718free_out:
719 kfree(buf);
720 return err;
721} /* ds_ioctl */
722
723/*====================================================================*/
724
725static struct file_operations ds_fops = {
726 .owner = THIS_MODULE,
727 .open = ds_open,
728 .release = ds_release,
729 .ioctl = ds_ioctl,
730 .read = ds_read,
731 .write = ds_write,
732 .poll = ds_poll,
733};
734
735void __init pcmcia_setup_ioctl(void) {
736 int i;
737
738 /* Set up character device for user mode clients */
739 i = register_chrdev(0, "pcmcia", &ds_fops);
740 if (i == -EBUSY)
741 printk(KERN_NOTICE "unable to find a free device # for "
742 "Driver Services\n");
743 else
744 major_dev = i;
745
746#ifdef CONFIG_PROC_FS
747 proc_pccard = proc_mkdir("pccard", proc_bus);
748 if (proc_pccard)
749 create_proc_read_entry("drivers",0,proc_pccard,proc_read_drivers,NULL);
750#endif
751}
752
753
754void __exit pcmcia_cleanup_ioctl(void) {
755#ifdef CONFIG_PROC_FS
756 if (proc_pccard) {
757 remove_proc_entry("drivers", proc_pccard);
758 remove_proc_entry("pccard", proc_bus);
759 }
760#endif
761 if (major_dev != -1)
762 unregister_chrdev(major_dev, "pcmcia");
763}