blob: 2b11a332175e339fe2b9f6e8c8e8cc7623a24e1d [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
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070021#include <linux/kernel.h>
Dominik Brodowski3b659fb2005-06-27 16:28:51 -070022#include <linux/module.h>
23#include <linux/init.h>
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070024#include <linux/major.h>
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070025#include <linux/errno.h>
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070026#include <linux/ioctl.h>
27#include <linux/proc_fs.h>
28#include <linux/poll.h>
29#include <linux/pci.h>
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070030#include <linux/workqueue.h>
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070031
32#define IN_CARD_SERVICES
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070033#include <pcmcia/cs_types.h>
34#include <pcmcia/cs.h>
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070035#include <pcmcia/cistpl.h>
36#include <pcmcia/ds.h>
37#include <pcmcia/ss.h>
38
39#include "cs_internal.h"
40#include "ds_internal.h"
41
42static int major_dev = -1;
43
44
45/* Device user information */
46#define MAX_EVENTS 32
47#define USER_MAGIC 0x7ea4
48#define CHECK_USER(u) \
49 (((u) == NULL) || ((u)->user_magic != USER_MAGIC))
50
51typedef struct user_info_t {
52 u_int user_magic;
53 int event_head, event_tail;
54 event_t event[MAX_EVENTS];
55 struct user_info_t *next;
Dominik Brodowskidc109492005-06-27 16:28:50 -070056 struct pcmcia_socket *socket;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070057} user_info_t;
58
59
60#ifdef DEBUG
61extern int ds_pc_debug;
62#define cs_socket_name(skt) ((skt)->dev.class_id)
63
64#define ds_dbg(lvl, fmt, arg...) do { \
65 if (ds_pc_debug >= lvl) \
66 printk(KERN_DEBUG "ds: " fmt , ## arg); \
67} while (0)
68#else
69#define ds_dbg(lvl, fmt, arg...) do { } while (0)
70#endif
71
Dominik Brodowski855cdf12006-01-10 20:48:59 +010072static struct pcmcia_device *get_pcmcia_device(struct pcmcia_socket *s,
73 unsigned int function)
74{
75 struct pcmcia_device *p_dev = NULL;
76 unsigned long flags;
77
78 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
79 list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
80 if (p_dev->func == function) {
81 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
82 return pcmcia_get_dev(p_dev);
83 }
84 }
85 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
86 return NULL;
87}
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070088
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070089/* backwards-compatible accessing of driver --- by name! */
90
Dominik Brodowski855cdf12006-01-10 20:48:59 +010091static struct pcmcia_driver *get_pcmcia_driver(dev_info_t *dev_info)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070092{
93 struct device_driver *drv;
94 struct pcmcia_driver *p_drv;
95
96 drv = driver_find((char *) dev_info, &pcmcia_bus_type);
97 if (!drv)
98 return NULL;
99
100 p_drv = container_of(drv, struct pcmcia_driver, drv);
101
102 return (p_drv);
103}
104
105
106#ifdef CONFIG_PROC_FS
107static struct proc_dir_entry *proc_pccard = NULL;
108
109static int proc_read_drivers_callback(struct device_driver *driver, void *d)
110{
111 char **p = d;
112 struct pcmcia_driver *p_drv = container_of(driver,
113 struct pcmcia_driver, drv);
114
115 *p += sprintf(*p, "%-24.24s 1 %d\n", p_drv->drv.name,
116#ifdef CONFIG_MODULE_UNLOAD
117 (p_drv->owner) ? module_refcount(p_drv->owner) : 1
118#else
119 1
120#endif
121 );
122 d = (void *) p;
123
124 return 0;
125}
126
127static int proc_read_drivers(char *buf, char **start, off_t pos,
128 int count, int *eof, void *data)
129{
130 char *p = buf;
131
132 bus_for_each_drv(&pcmcia_bus_type, NULL,
133 (void *) &p, proc_read_drivers_callback);
134
135 return (p - buf);
136}
137#endif
138
139/*======================================================================
140
141 These manage a ring buffer of events pending for one user process
142
143======================================================================*/
144
145
146static int queue_empty(user_info_t *user)
147{
148 return (user->event_head == user->event_tail);
149}
150
151static event_t get_queued_event(user_info_t *user)
152{
153 user->event_tail = (user->event_tail+1) % MAX_EVENTS;
154 return user->event[user->event_tail];
155}
156
157static void queue_event(user_info_t *user, event_t event)
158{
159 user->event_head = (user->event_head+1) % MAX_EVENTS;
160 if (user->event_head == user->event_tail)
161 user->event_tail = (user->event_tail+1) % MAX_EVENTS;
162 user->event[user->event_head] = event;
163}
164
Dominik Brodowskidc109492005-06-27 16:28:50 -0700165void handle_event(struct pcmcia_socket *s, event_t event)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700166{
167 user_info_t *user;
168 for (user = s->user; user; user = user->next)
169 queue_event(user, event);
170 wake_up_interruptible(&s->queue);
171}
172
173
174/*======================================================================
175
176 bind_request() and bind_device() are merged by now. Register_client()
177 is called right at the end of bind_request(), during the driver's
178 ->attach() call. Individual descriptions:
179
180 bind_request() connects a socket to a particular client driver.
181 It looks up the specified device ID in the list of registered
182 drivers, binds it to the socket, and tries to create an instance
183 of the device. unbind_request() deletes a driver instance.
184
185 Bind_device() associates a device driver with a particular socket.
186 It is normally called by Driver Services after it has identified
187 a newly inserted card. An instance of that driver will then be
188 eligible to register as a client of this socket.
189
190 Register_client() uses the dev_info_t handle to match the
191 caller with a socket. The driver must have already been bound
192 to a socket with bind_device() -- in fact, bind_device()
193 allocates the client structure that will be used.
194
195======================================================================*/
196
Dominik Brodowskidc109492005-06-27 16:28:50 -0700197static int bind_request(struct pcmcia_socket *s, bind_info_t *bind_info)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700198{
199 struct pcmcia_driver *p_drv;
200 struct pcmcia_device *p_dev;
201 int ret = 0;
202 unsigned long flags;
203
Dominik Brodowskidc109492005-06-27 16:28:50 -0700204 s = pcmcia_get_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700205 if (!s)
206 return -EINVAL;
207
Dominik Brodowskidc109492005-06-27 16:28:50 -0700208 ds_dbg(2, "bind_request(%d, '%s')\n", s->sock,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700209 (char *)bind_info->dev_info);
210
211 p_drv = get_pcmcia_driver(&bind_info->dev_info);
212 if (!p_drv) {
213 ret = -EINVAL;
214 goto err_put;
215 }
216
217 if (!try_module_get(p_drv->owner)) {
218 ret = -EINVAL;
219 goto err_put_driver;
220 }
221
222 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
223 list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
224 if (p_dev->func == bind_info->function) {
225 if ((p_dev->dev.driver == &p_drv->drv)) {
226 if (p_dev->cardmgr) {
227 /* if there's already a device
228 * registered, and it was registered
229 * by userspace before, we need to
230 * return the "instance". */
231 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
Dominik Brodowskifd238232006-03-05 10:45:09 +0100232 bind_info->instance = p_dev;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700233 ret = -EBUSY;
234 goto err_put_module;
235 } else {
236 /* the correct driver managed to bind
237 * itself magically to the correct
238 * device. */
239 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
240 p_dev->cardmgr = p_drv;
241 ret = 0;
242 goto err_put_module;
243 }
244 } else if (!p_dev->dev.driver) {
245 /* there's already a device available where
246 * no device has been bound to yet. So we don't
247 * need to register a device! */
248 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
249 goto rescan;
250 }
251 }
252 }
253 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
254
255 p_dev = pcmcia_device_add(s, bind_info->function);
256 if (!p_dev) {
257 ret = -EIO;
258 goto err_put_module;
259 }
260
261rescan:
262 p_dev->cardmgr = p_drv;
263
264 /* if a driver is already running, we can abort */
265 if (p_dev->dev.driver)
266 goto err_put_module;
267
268 /*
269 * Prevent this racing with a card insertion.
270 */
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100271 mutex_lock(&s->skt_mutex);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700272 bus_rescan_devices(&pcmcia_bus_type);
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100273 mutex_unlock(&s->skt_mutex);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700274
275 /* check whether the driver indeed matched. I don't care if this
276 * is racy or not, because it can only happen on cardmgr access
277 * paths...
278 */
279 if (!(p_dev->dev.driver == &p_drv->drv))
280 p_dev->cardmgr = NULL;
281
282 err_put_module:
283 module_put(p_drv->owner);
284 err_put_driver:
285 put_driver(&p_drv->drv);
286 err_put:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700287 pcmcia_put_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700288
289 return (ret);
290} /* bind_request */
291
Dominik Brodowski33519dd2005-06-27 16:28:53 -0700292#ifdef CONFIG_CARDBUS
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700293
Dominik Brodowski33519dd2005-06-27 16:28:53 -0700294static struct pci_bus *pcmcia_lookup_bus(struct pcmcia_socket *s)
295{
296 if (!s || !(s->state & SOCKET_CARDBUS))
297 return NULL;
298
299 return s->cb_dev->subordinate;
300}
301#endif
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700302
Dominik Brodowskidc109492005-06-27 16:28:50 -0700303static int get_device_info(struct pcmcia_socket *s, bind_info_t *bind_info, int first)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700304{
305 dev_node_t *node;
306 struct pcmcia_device *p_dev;
307 unsigned long flags;
308 int ret = 0;
309
310#ifdef CONFIG_CARDBUS
311 /*
312 * Some unbelievably ugly code to associate the PCI cardbus
313 * device and its driver with the PCMCIA "bind" information.
314 */
315 {
316 struct pci_bus *bus;
317
Dominik Brodowskidc109492005-06-27 16:28:50 -0700318 bus = pcmcia_lookup_bus(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700319 if (bus) {
320 struct list_head *list;
321 struct pci_dev *dev = NULL;
322
323 list = bus->devices.next;
324 while (list != &bus->devices) {
325 struct pci_dev *pdev = pci_dev_b(list);
326 list = list->next;
327
328 if (first) {
329 dev = pdev;
330 break;
331 }
332
333 /* Try to handle "next" here some way? */
334 }
335 if (dev && dev->driver) {
336 strlcpy(bind_info->name, dev->driver->name, DEV_NAME_LEN);
337 bind_info->major = 0;
338 bind_info->minor = 0;
339 bind_info->next = NULL;
340 return 0;
341 }
342 }
343 }
344#endif
345
346 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
347 list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
348 if (p_dev->func == bind_info->function) {
349 p_dev = pcmcia_get_dev(p_dev);
350 if (!p_dev)
351 continue;
352 goto found;
353 }
354 }
355 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
356 return -ENODEV;
357
358 found:
359 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
360
Dominik Brodowskifd238232006-03-05 10:45:09 +0100361 if (p_dev->state & DEV_CONFIG_PENDING) {
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700362 ret = -EAGAIN;
363 goto err_put;
364 }
365
366 if (first)
Dominik Brodowskifd238232006-03-05 10:45:09 +0100367 node = p_dev->dev_node;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700368 else
Dominik Brodowskifd238232006-03-05 10:45:09 +0100369 for (node = p_dev->dev_node; node; node = node->next)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700370 if (node == bind_info->next)
371 break;
372 if (!node) {
373 ret = -ENODEV;
374 goto err_put;
375 }
376
377 strlcpy(bind_info->name, node->dev_name, DEV_NAME_LEN);
378 bind_info->major = node->major;
379 bind_info->minor = node->minor;
380 bind_info->next = node->next;
381
382 err_put:
383 pcmcia_put_dev(p_dev);
384 return (ret);
385} /* get_device_info */
386
387
388static int ds_open(struct inode *inode, struct file *file)
389{
390 socket_t i = iminor(inode);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700391 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700392 user_info_t *user;
Dominik Brodowskic352ec82005-09-13 01:25:03 -0700393 static int warning_printed = 0;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700394
395 ds_dbg(0, "ds_open(socket %d)\n", i);
396
Dominik Brodowskidc109492005-06-27 16:28:50 -0700397 s = pcmcia_get_socket_by_nr(i);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700398 if (!s)
399 return -ENODEV;
Dominik Brodowskidc109492005-06-27 16:28:50 -0700400 s = pcmcia_get_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700401 if (!s)
402 return -ENODEV;
403
404 if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700405 if (s->pcmcia_state.busy) {
Dominik Brodowskidc109492005-06-27 16:28:50 -0700406 pcmcia_put_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700407 return -EBUSY;
408 }
409 else
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700410 s->pcmcia_state.busy = 1;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700411 }
412
413 user = kmalloc(sizeof(user_info_t), GFP_KERNEL);
414 if (!user) {
Dominik Brodowskidc109492005-06-27 16:28:50 -0700415 pcmcia_put_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700416 return -ENOMEM;
417 }
418 user->event_tail = user->event_head = 0;
419 user->next = s->user;
420 user->user_magic = USER_MAGIC;
421 user->socket = s;
422 s->user = user;
423 file->private_data = user;
424
Dominik Brodowskic352ec82005-09-13 01:25:03 -0700425 if (!warning_printed) {
426 printk(KERN_INFO "pcmcia: Detected deprecated PCMCIA ioctl "
427 "usage.\n");
428 printk(KERN_INFO "pcmcia: This interface will soon be removed from "
429 "the kernel; please expect breakage unless you upgrade "
430 "to new tools.\n");
431 printk(KERN_INFO "pcmcia: see http://www.kernel.org/pub/linux/"
432 "utils/kernel/pcmcia/pcmcia.html for details.\n");
433 warning_printed = 1;
434 }
435
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700436 if (s->pcmcia_state.present)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700437 queue_event(user, CS_EVENT_CARD_INSERTION);
438 return 0;
439} /* ds_open */
440
441/*====================================================================*/
442
443static int ds_release(struct inode *inode, struct file *file)
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, **link;
447
448 ds_dbg(0, "ds_release(socket %d)\n", iminor(inode));
449
450 user = file->private_data;
451 if (CHECK_USER(user))
452 goto out;
453
454 s = user->socket;
455
456 /* Unlink user data structure */
457 if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700458 s->pcmcia_state.busy = 0;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700459 }
460 file->private_data = NULL;
461 for (link = &s->user; *link; link = &(*link)->next)
462 if (*link == user) break;
463 if (link == NULL)
464 goto out;
465 *link = user->next;
466 user->user_magic = 0;
467 kfree(user);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700468 pcmcia_put_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700469out:
470 return 0;
471} /* ds_release */
472
473/*====================================================================*/
474
475static ssize_t ds_read(struct file *file, char __user *buf,
476 size_t count, loff_t *ppos)
477{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700478 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700479 user_info_t *user;
480 int ret;
481
482 ds_dbg(2, "ds_read(socket %d)\n", iminor(file->f_dentry->d_inode));
483
484 if (count < 4)
485 return -EINVAL;
486
487 user = file->private_data;
488 if (CHECK_USER(user))
489 return -EIO;
490
491 s = user->socket;
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700492 if (s->pcmcia_state.dead)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700493 return -EIO;
494
495 ret = wait_event_interruptible(s->queue, !queue_empty(user));
496 if (ret == 0)
497 ret = put_user(get_queued_event(user), (int __user *)buf) ? -EFAULT : 4;
498
499 return ret;
500} /* ds_read */
501
502/*====================================================================*/
503
504static ssize_t ds_write(struct file *file, const char __user *buf,
505 size_t count, loff_t *ppos)
506{
507 ds_dbg(2, "ds_write(socket %d)\n", iminor(file->f_dentry->d_inode));
508
509 if (count != 4)
510 return -EINVAL;
511 if ((file->f_flags & O_ACCMODE) == O_RDONLY)
512 return -EBADF;
513
514 return -EIO;
515} /* ds_write */
516
517/*====================================================================*/
518
519/* No kernel lock - fine */
520static u_int ds_poll(struct file *file, poll_table *wait)
521{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700522 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700523 user_info_t *user;
524
525 ds_dbg(2, "ds_poll(socket %d)\n", iminor(file->f_dentry->d_inode));
526
527 user = file->private_data;
528 if (CHECK_USER(user))
529 return POLLERR;
530 s = user->socket;
531 /*
532 * We don't check for a dead socket here since that
533 * will send cardmgr into an endless spin.
534 */
535 poll_wait(file, &s->queue, wait);
536 if (!queue_empty(user))
537 return POLLIN | POLLRDNORM;
538 return 0;
539} /* ds_poll */
540
541/*====================================================================*/
542
543extern int pcmcia_adjust_resource_info(adjust_t *adj);
544
545static int ds_ioctl(struct inode * inode, struct file * file,
546 u_int cmd, u_long arg)
547{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700548 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700549 void __user *uarg = (char __user *)arg;
550 u_int size;
551 int ret, err;
552 ds_ioctl_arg_t *buf;
553 user_info_t *user;
554
555 ds_dbg(2, "ds_ioctl(socket %d, %#x, %#lx)\n", iminor(inode), cmd, arg);
556
557 user = file->private_data;
558 if (CHECK_USER(user))
559 return -EIO;
560
561 s = user->socket;
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700562 if (s->pcmcia_state.dead)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700563 return -EIO;
564
565 size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
566 if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL;
567
568 /* Permission check */
569 if (!(cmd & IOC_OUT) && !capable(CAP_SYS_ADMIN))
570 return -EPERM;
571
572 if (cmd & IOC_IN) {
573 if (!access_ok(VERIFY_READ, uarg, size)) {
574 ds_dbg(3, "ds_ioctl(): verify_read = %d\n", -EFAULT);
575 return -EFAULT;
576 }
577 }
578 if (cmd & IOC_OUT) {
579 if (!access_ok(VERIFY_WRITE, uarg, size)) {
580 ds_dbg(3, "ds_ioctl(): verify_write = %d\n", -EFAULT);
581 return -EFAULT;
582 }
583 }
584 buf = kmalloc(sizeof(ds_ioctl_arg_t), GFP_KERNEL);
585 if (!buf)
586 return -ENOMEM;
587
588 err = ret = 0;
589
590 if (cmd & IOC_IN) __copy_from_user((char *)buf, uarg, size);
591
592 switch (cmd) {
593 case DS_ADJUST_RESOURCE_INFO:
594 ret = pcmcia_adjust_resource_info(&buf->adjust);
595 break;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700596 case DS_GET_CONFIGURATION_INFO:
597 if (buf->config.Function &&
Dominik Brodowskidc109492005-06-27 16:28:50 -0700598 (buf->config.Function >= s->functions))
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700599 ret = CS_BAD_ARGS;
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100600 else {
601 struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->config.Function);
602 ret = pccard_get_configuration_info(s, p_dev, &buf->config);
603 pcmcia_put_dev(p_dev);
604 }
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700605 break;
606 case DS_GET_FIRST_TUPLE:
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100607 mutex_lock(&s->skt_mutex);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700608 pcmcia_validate_mem(s);
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100609 mutex_unlock(&s->skt_mutex);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700610 ret = pccard_get_first_tuple(s, BIND_FN_ALL, &buf->tuple);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700611 break;
612 case DS_GET_NEXT_TUPLE:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700613 ret = pccard_get_next_tuple(s, BIND_FN_ALL, &buf->tuple);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700614 break;
615 case DS_GET_TUPLE_DATA:
616 buf->tuple.TupleData = buf->tuple_parse.data;
617 buf->tuple.TupleDataMax = sizeof(buf->tuple_parse.data);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700618 ret = pccard_get_tuple_data(s, &buf->tuple);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700619 break;
620 case DS_PARSE_TUPLE:
621 buf->tuple.TupleData = buf->tuple_parse.data;
622 ret = pccard_parse_tuple(&buf->tuple, &buf->tuple_parse.parse);
623 break;
624 case DS_RESET_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700625 ret = pccard_reset_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700626 break;
627 case DS_GET_STATUS:
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100628 if (buf->status.Function &&
629 (buf->status.Function >= s->functions))
630 ret = CS_BAD_ARGS;
631 else {
632 struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->status.Function);
633 ret = pccard_get_status(s, p_dev, &buf->status);
634 pcmcia_put_dev(p_dev);
635 }
636 break;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700637 case DS_VALIDATE_CIS:
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100638 mutex_lock(&s->skt_mutex);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700639 pcmcia_validate_mem(s);
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100640 mutex_unlock(&s->skt_mutex);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700641 ret = pccard_validate_cis(s, BIND_FN_ALL, &buf->cisinfo);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700642 break;
643 case DS_SUSPEND_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700644 ret = pcmcia_suspend_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700645 break;
646 case DS_RESUME_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700647 ret = pcmcia_resume_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700648 break;
649 case DS_EJECT_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700650 err = pcmcia_eject_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700651 break;
652 case DS_INSERT_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700653 err = pcmcia_insert_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700654 break;
655 case DS_ACCESS_CONFIGURATION_REGISTER:
656 if ((buf->conf_reg.Action == CS_WRITE) && !capable(CAP_SYS_ADMIN)) {
657 err = -EPERM;
658 goto free_out;
659 }
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100660
661 ret = CS_BAD_ARGS;
662
663 if (!(buf->conf_reg.Function &&
664 (buf->conf_reg.Function >= s->functions))) {
665 struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->conf_reg.Function);
666 if (p_dev)
667 ret = pcmcia_access_configuration_register(p_dev, &buf->conf_reg);
668 pcmcia_put_dev(p_dev);
669 }
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700670 break;
671 case DS_GET_FIRST_REGION:
672 case DS_GET_NEXT_REGION:
673 case DS_BIND_MTD:
674 if (!capable(CAP_SYS_ADMIN)) {
675 err = -EPERM;
676 goto free_out;
677 } else {
678 static int printed = 0;
679 if (!printed) {
680 printk(KERN_WARNING "2.6. kernels use pcmciamtd instead of memory_cs.c and do not require special\n");
681 printk(KERN_WARNING "MTD handling any more.\n");
682 printed++;
683 }
684 }
685 err = -EINVAL;
686 goto free_out;
687 break;
688 case DS_GET_FIRST_WINDOW:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700689 ret = pcmcia_get_window(s, &buf->win_info.handle, 0,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700690 &buf->win_info.window);
691 break;
692 case DS_GET_NEXT_WINDOW:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700693 ret = pcmcia_get_window(s, &buf->win_info.handle,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700694 buf->win_info.handle->index + 1, &buf->win_info.window);
695 break;
696 case DS_GET_MEM_PAGE:
697 ret = pcmcia_get_mem_page(buf->win_info.handle,
698 &buf->win_info.map);
699 break;
700 case DS_REPLACE_CIS:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700701 ret = pcmcia_replace_cis(s, &buf->cisdump);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700702 break;
703 case DS_BIND_REQUEST:
704 if (!capable(CAP_SYS_ADMIN)) {
705 err = -EPERM;
706 goto free_out;
707 }
708 err = bind_request(s, &buf->bind_info);
709 break;
710 case DS_GET_DEVICE_INFO:
711 err = get_device_info(s, &buf->bind_info, 1);
712 break;
713 case DS_GET_NEXT_DEVICE:
714 err = get_device_info(s, &buf->bind_info, 0);
715 break;
716 case DS_UNBIND_REQUEST:
717 err = 0;
718 break;
719 default:
720 err = -EINVAL;
721 }
722
723 if ((err == 0) && (ret != CS_SUCCESS)) {
724 ds_dbg(2, "ds_ioctl: ret = %d\n", ret);
725 switch (ret) {
726 case CS_BAD_SOCKET: case CS_NO_CARD:
727 err = -ENODEV; break;
728 case CS_BAD_ARGS: case CS_BAD_ATTRIBUTE: case CS_BAD_IRQ:
729 case CS_BAD_TUPLE:
730 err = -EINVAL; break;
731 case CS_IN_USE:
732 err = -EBUSY; break;
733 case CS_OUT_OF_RESOURCE:
734 err = -ENOSPC; break;
735 case CS_NO_MORE_ITEMS:
736 err = -ENODATA; break;
737 case CS_UNSUPPORTED_FUNCTION:
738 err = -ENOSYS; break;
739 default:
740 err = -EIO; break;
741 }
742 }
743
744 if (cmd & IOC_OUT) {
745 if (__copy_to_user(uarg, (char *)buf, size))
746 err = -EFAULT;
747 }
748
749free_out:
750 kfree(buf);
751 return err;
752} /* ds_ioctl */
753
754/*====================================================================*/
755
756static struct file_operations ds_fops = {
757 .owner = THIS_MODULE,
758 .open = ds_open,
759 .release = ds_release,
760 .ioctl = ds_ioctl,
761 .read = ds_read,
762 .write = ds_write,
763 .poll = ds_poll,
764};
765
766void __init pcmcia_setup_ioctl(void) {
767 int i;
768
769 /* Set up character device for user mode clients */
770 i = register_chrdev(0, "pcmcia", &ds_fops);
Dominik Brodowski1a8ceaf2005-06-27 16:29:00 -0700771 if (i < 0)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700772 printk(KERN_NOTICE "unable to find a free device # for "
Dominik Brodowski1a8ceaf2005-06-27 16:29:00 -0700773 "Driver Services (error=%d)\n", i);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700774 else
775 major_dev = i;
776
777#ifdef CONFIG_PROC_FS
778 proc_pccard = proc_mkdir("pccard", proc_bus);
779 if (proc_pccard)
780 create_proc_read_entry("drivers",0,proc_pccard,proc_read_drivers,NULL);
781#endif
782}
783
784
785void __exit pcmcia_cleanup_ioctl(void) {
786#ifdef CONFIG_PROC_FS
787 if (proc_pccard) {
788 remove_proc_entry("drivers", proc_pccard);
789 remove_proc_entry("pccard", proc_bus);
790 }
791#endif
792 if (major_dev != -1)
793 unregister_chrdev(major_dev, "pcmcia");
794}