blob: 7aa2e7f20d5059199563339e03ac2f54c3444d31 [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
278
279extern struct pci_bus *pcmcia_lookup_bus(struct pcmcia_socket *s);
280
Dominik Brodowskidc109492005-06-27 16:28:50 -0700281static int get_device_info(struct pcmcia_socket *s, bind_info_t *bind_info, int first)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700282{
283 dev_node_t *node;
284 struct pcmcia_device *p_dev;
285 unsigned long flags;
286 int ret = 0;
287
288#ifdef CONFIG_CARDBUS
289 /*
290 * Some unbelievably ugly code to associate the PCI cardbus
291 * device and its driver with the PCMCIA "bind" information.
292 */
293 {
294 struct pci_bus *bus;
295
Dominik Brodowskidc109492005-06-27 16:28:50 -0700296 bus = pcmcia_lookup_bus(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700297 if (bus) {
298 struct list_head *list;
299 struct pci_dev *dev = NULL;
300
301 list = bus->devices.next;
302 while (list != &bus->devices) {
303 struct pci_dev *pdev = pci_dev_b(list);
304 list = list->next;
305
306 if (first) {
307 dev = pdev;
308 break;
309 }
310
311 /* Try to handle "next" here some way? */
312 }
313 if (dev && dev->driver) {
314 strlcpy(bind_info->name, dev->driver->name, DEV_NAME_LEN);
315 bind_info->major = 0;
316 bind_info->minor = 0;
317 bind_info->next = NULL;
318 return 0;
319 }
320 }
321 }
322#endif
323
324 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
325 list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
326 if (p_dev->func == bind_info->function) {
327 p_dev = pcmcia_get_dev(p_dev);
328 if (!p_dev)
329 continue;
330 goto found;
331 }
332 }
333 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
334 return -ENODEV;
335
336 found:
337 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
338
339 if ((!p_dev->instance) ||
340 (p_dev->instance->state & DEV_CONFIG_PENDING)) {
341 ret = -EAGAIN;
342 goto err_put;
343 }
344
345 if (first)
346 node = p_dev->instance->dev;
347 else
348 for (node = p_dev->instance->dev; node; node = node->next)
349 if (node == bind_info->next)
350 break;
351 if (!node) {
352 ret = -ENODEV;
353 goto err_put;
354 }
355
356 strlcpy(bind_info->name, node->dev_name, DEV_NAME_LEN);
357 bind_info->major = node->major;
358 bind_info->minor = node->minor;
359 bind_info->next = node->next;
360
361 err_put:
362 pcmcia_put_dev(p_dev);
363 return (ret);
364} /* get_device_info */
365
366
367static int ds_open(struct inode *inode, struct file *file)
368{
369 socket_t i = iminor(inode);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700370 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700371 user_info_t *user;
372
373 ds_dbg(0, "ds_open(socket %d)\n", i);
374
Dominik Brodowskidc109492005-06-27 16:28:50 -0700375 s = pcmcia_get_socket_by_nr(i);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700376 if (!s)
377 return -ENODEV;
Dominik Brodowskidc109492005-06-27 16:28:50 -0700378 s = pcmcia_get_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700379 if (!s)
380 return -ENODEV;
381
382 if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700383 if (s->pcmcia_state.busy) {
Dominik Brodowskidc109492005-06-27 16:28:50 -0700384 pcmcia_put_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700385 return -EBUSY;
386 }
387 else
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700388 s->pcmcia_state.busy = 1;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700389 }
390
391 user = kmalloc(sizeof(user_info_t), GFP_KERNEL);
392 if (!user) {
Dominik Brodowskidc109492005-06-27 16:28:50 -0700393 pcmcia_put_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700394 return -ENOMEM;
395 }
396 user->event_tail = user->event_head = 0;
397 user->next = s->user;
398 user->user_magic = USER_MAGIC;
399 user->socket = s;
400 s->user = user;
401 file->private_data = user;
402
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700403 if (s->pcmcia_state.present)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700404 queue_event(user, CS_EVENT_CARD_INSERTION);
405 return 0;
406} /* ds_open */
407
408/*====================================================================*/
409
410static int ds_release(struct inode *inode, struct file *file)
411{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700412 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700413 user_info_t *user, **link;
414
415 ds_dbg(0, "ds_release(socket %d)\n", iminor(inode));
416
417 user = file->private_data;
418 if (CHECK_USER(user))
419 goto out;
420
421 s = user->socket;
422
423 /* Unlink user data structure */
424 if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700425 s->pcmcia_state.busy = 0;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700426 }
427 file->private_data = NULL;
428 for (link = &s->user; *link; link = &(*link)->next)
429 if (*link == user) break;
430 if (link == NULL)
431 goto out;
432 *link = user->next;
433 user->user_magic = 0;
434 kfree(user);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700435 pcmcia_put_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700436out:
437 return 0;
438} /* ds_release */
439
440/*====================================================================*/
441
442static ssize_t ds_read(struct file *file, char __user *buf,
443 size_t count, loff_t *ppos)
444{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700445 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700446 user_info_t *user;
447 int ret;
448
449 ds_dbg(2, "ds_read(socket %d)\n", iminor(file->f_dentry->d_inode));
450
451 if (count < 4)
452 return -EINVAL;
453
454 user = file->private_data;
455 if (CHECK_USER(user))
456 return -EIO;
457
458 s = user->socket;
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700459 if (s->pcmcia_state.dead)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700460 return -EIO;
461
462 ret = wait_event_interruptible(s->queue, !queue_empty(user));
463 if (ret == 0)
464 ret = put_user(get_queued_event(user), (int __user *)buf) ? -EFAULT : 4;
465
466 return ret;
467} /* ds_read */
468
469/*====================================================================*/
470
471static ssize_t ds_write(struct file *file, const char __user *buf,
472 size_t count, loff_t *ppos)
473{
474 ds_dbg(2, "ds_write(socket %d)\n", iminor(file->f_dentry->d_inode));
475
476 if (count != 4)
477 return -EINVAL;
478 if ((file->f_flags & O_ACCMODE) == O_RDONLY)
479 return -EBADF;
480
481 return -EIO;
482} /* ds_write */
483
484/*====================================================================*/
485
486/* No kernel lock - fine */
487static u_int ds_poll(struct file *file, poll_table *wait)
488{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700489 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700490 user_info_t *user;
491
492 ds_dbg(2, "ds_poll(socket %d)\n", iminor(file->f_dentry->d_inode));
493
494 user = file->private_data;
495 if (CHECK_USER(user))
496 return POLLERR;
497 s = user->socket;
498 /*
499 * We don't check for a dead socket here since that
500 * will send cardmgr into an endless spin.
501 */
502 poll_wait(file, &s->queue, wait);
503 if (!queue_empty(user))
504 return POLLIN | POLLRDNORM;
505 return 0;
506} /* ds_poll */
507
508/*====================================================================*/
509
510extern int pcmcia_adjust_resource_info(adjust_t *adj);
511
512static int ds_ioctl(struct inode * inode, struct file * file,
513 u_int cmd, u_long arg)
514{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700515 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700516 void __user *uarg = (char __user *)arg;
517 u_int size;
518 int ret, err;
519 ds_ioctl_arg_t *buf;
520 user_info_t *user;
521
522 ds_dbg(2, "ds_ioctl(socket %d, %#x, %#lx)\n", iminor(inode), cmd, arg);
523
524 user = file->private_data;
525 if (CHECK_USER(user))
526 return -EIO;
527
528 s = user->socket;
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700529 if (s->pcmcia_state.dead)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700530 return -EIO;
531
532 size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
533 if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL;
534
535 /* Permission check */
536 if (!(cmd & IOC_OUT) && !capable(CAP_SYS_ADMIN))
537 return -EPERM;
538
539 if (cmd & IOC_IN) {
540 if (!access_ok(VERIFY_READ, uarg, size)) {
541 ds_dbg(3, "ds_ioctl(): verify_read = %d\n", -EFAULT);
542 return -EFAULT;
543 }
544 }
545 if (cmd & IOC_OUT) {
546 if (!access_ok(VERIFY_WRITE, uarg, size)) {
547 ds_dbg(3, "ds_ioctl(): verify_write = %d\n", -EFAULT);
548 return -EFAULT;
549 }
550 }
551 buf = kmalloc(sizeof(ds_ioctl_arg_t), GFP_KERNEL);
552 if (!buf)
553 return -ENOMEM;
554
555 err = ret = 0;
556
557 if (cmd & IOC_IN) __copy_from_user((char *)buf, uarg, size);
558
559 switch (cmd) {
560 case DS_ADJUST_RESOURCE_INFO:
561 ret = pcmcia_adjust_resource_info(&buf->adjust);
562 break;
563 case DS_GET_CARD_SERVICES_INFO:
564 ret = pcmcia_get_card_services_info(&buf->servinfo);
565 break;
566 case DS_GET_CONFIGURATION_INFO:
567 if (buf->config.Function &&
Dominik Brodowskidc109492005-06-27 16:28:50 -0700568 (buf->config.Function >= s->functions))
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700569 ret = CS_BAD_ARGS;
570 else
Dominik Brodowskidc109492005-06-27 16:28:50 -0700571 ret = pccard_get_configuration_info(s,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700572 buf->config.Function, &buf->config);
573 break;
574 case DS_GET_FIRST_TUPLE:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700575 down(&s->skt_sem);
576 pcmcia_validate_mem(s);
577 up(&s->skt_sem);
578 ret = pccard_get_first_tuple(s, BIND_FN_ALL, &buf->tuple);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700579 break;
580 case DS_GET_NEXT_TUPLE:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700581 ret = pccard_get_next_tuple(s, BIND_FN_ALL, &buf->tuple);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700582 break;
583 case DS_GET_TUPLE_DATA:
584 buf->tuple.TupleData = buf->tuple_parse.data;
585 buf->tuple.TupleDataMax = sizeof(buf->tuple_parse.data);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700586 ret = pccard_get_tuple_data(s, &buf->tuple);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700587 break;
588 case DS_PARSE_TUPLE:
589 buf->tuple.TupleData = buf->tuple_parse.data;
590 ret = pccard_parse_tuple(&buf->tuple, &buf->tuple_parse.parse);
591 break;
592 case DS_RESET_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700593 ret = pccard_reset_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700594 break;
595 case DS_GET_STATUS:
596 if (buf->status.Function &&
Dominik Brodowskidc109492005-06-27 16:28:50 -0700597 (buf->status.Function >= s->functions))
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700598 ret = CS_BAD_ARGS;
599 else
Dominik Brodowskidc109492005-06-27 16:28:50 -0700600 ret = pccard_get_status(s, buf->status.Function, &buf->status);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700601 break;
602 case DS_VALIDATE_CIS:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700603 down(&s->skt_sem);
604 pcmcia_validate_mem(s);
605 up(&s->skt_sem);
606 ret = pccard_validate_cis(s, BIND_FN_ALL, &buf->cisinfo);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700607 break;
608 case DS_SUSPEND_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700609 ret = pcmcia_suspend_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700610 break;
611 case DS_RESUME_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700612 ret = pcmcia_resume_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700613 break;
614 case DS_EJECT_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700615 err = pcmcia_eject_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700616 break;
617 case DS_INSERT_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700618 err = pcmcia_insert_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700619 break;
620 case DS_ACCESS_CONFIGURATION_REGISTER:
621 if ((buf->conf_reg.Action == CS_WRITE) && !capable(CAP_SYS_ADMIN)) {
622 err = -EPERM;
623 goto free_out;
624 }
625 if (buf->conf_reg.Function &&
Dominik Brodowskidc109492005-06-27 16:28:50 -0700626 (buf->conf_reg.Function >= s->functions))
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700627 ret = CS_BAD_ARGS;
628 else
Dominik Brodowskidc109492005-06-27 16:28:50 -0700629 ret = pccard_access_configuration_register(s,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700630 buf->conf_reg.Function, &buf->conf_reg);
631 break;
632 case DS_GET_FIRST_REGION:
633 case DS_GET_NEXT_REGION:
634 case DS_BIND_MTD:
635 if (!capable(CAP_SYS_ADMIN)) {
636 err = -EPERM;
637 goto free_out;
638 } else {
639 static int printed = 0;
640 if (!printed) {
641 printk(KERN_WARNING "2.6. kernels use pcmciamtd instead of memory_cs.c and do not require special\n");
642 printk(KERN_WARNING "MTD handling any more.\n");
643 printed++;
644 }
645 }
646 err = -EINVAL;
647 goto free_out;
648 break;
649 case DS_GET_FIRST_WINDOW:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700650 ret = pcmcia_get_window(s, &buf->win_info.handle, 0,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700651 &buf->win_info.window);
652 break;
653 case DS_GET_NEXT_WINDOW:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700654 ret = pcmcia_get_window(s, &buf->win_info.handle,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700655 buf->win_info.handle->index + 1, &buf->win_info.window);
656 break;
657 case DS_GET_MEM_PAGE:
658 ret = pcmcia_get_mem_page(buf->win_info.handle,
659 &buf->win_info.map);
660 break;
661 case DS_REPLACE_CIS:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700662 ret = pcmcia_replace_cis(s, &buf->cisdump);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700663 break;
664 case DS_BIND_REQUEST:
665 if (!capable(CAP_SYS_ADMIN)) {
666 err = -EPERM;
667 goto free_out;
668 }
669 err = bind_request(s, &buf->bind_info);
670 break;
671 case DS_GET_DEVICE_INFO:
672 err = get_device_info(s, &buf->bind_info, 1);
673 break;
674 case DS_GET_NEXT_DEVICE:
675 err = get_device_info(s, &buf->bind_info, 0);
676 break;
677 case DS_UNBIND_REQUEST:
678 err = 0;
679 break;
680 default:
681 err = -EINVAL;
682 }
683
684 if ((err == 0) && (ret != CS_SUCCESS)) {
685 ds_dbg(2, "ds_ioctl: ret = %d\n", ret);
686 switch (ret) {
687 case CS_BAD_SOCKET: case CS_NO_CARD:
688 err = -ENODEV; break;
689 case CS_BAD_ARGS: case CS_BAD_ATTRIBUTE: case CS_BAD_IRQ:
690 case CS_BAD_TUPLE:
691 err = -EINVAL; break;
692 case CS_IN_USE:
693 err = -EBUSY; break;
694 case CS_OUT_OF_RESOURCE:
695 err = -ENOSPC; break;
696 case CS_NO_MORE_ITEMS:
697 err = -ENODATA; break;
698 case CS_UNSUPPORTED_FUNCTION:
699 err = -ENOSYS; break;
700 default:
701 err = -EIO; break;
702 }
703 }
704
705 if (cmd & IOC_OUT) {
706 if (__copy_to_user(uarg, (char *)buf, size))
707 err = -EFAULT;
708 }
709
710free_out:
711 kfree(buf);
712 return err;
713} /* ds_ioctl */
714
715/*====================================================================*/
716
717static struct file_operations ds_fops = {
718 .owner = THIS_MODULE,
719 .open = ds_open,
720 .release = ds_release,
721 .ioctl = ds_ioctl,
722 .read = ds_read,
723 .write = ds_write,
724 .poll = ds_poll,
725};
726
727void __init pcmcia_setup_ioctl(void) {
728 int i;
729
730 /* Set up character device for user mode clients */
731 i = register_chrdev(0, "pcmcia", &ds_fops);
732 if (i == -EBUSY)
733 printk(KERN_NOTICE "unable to find a free device # for "
734 "Driver Services\n");
735 else
736 major_dev = i;
737
738#ifdef CONFIG_PROC_FS
739 proc_pccard = proc_mkdir("pccard", proc_bus);
740 if (proc_pccard)
741 create_proc_read_entry("drivers",0,proc_pccard,proc_read_drivers,NULL);
742#endif
743}
744
745
746void __exit pcmcia_cleanup_ioctl(void) {
747#ifdef CONFIG_PROC_FS
748 if (proc_pccard) {
749 remove_proc_entry("drivers", proc_pccard);
750 remove_proc_entry("pccard", proc_bus);
751 }
752#endif
753 if (major_dev != -1)
754 unregister_chrdev(major_dev, "pcmcia");
755}