blob: 5f186abca1082843a7b12e30865b3bb7c8b83f34 [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;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070062
63#define ds_dbg(lvl, fmt, arg...) do { \
64 if (ds_pc_debug >= lvl) \
65 printk(KERN_DEBUG "ds: " fmt , ## arg); \
66} while (0)
67#else
68#define ds_dbg(lvl, fmt, arg...) do { } while (0)
69#endif
70
Dominik Brodowski855cdf12006-01-10 20:48:59 +010071static struct pcmcia_device *get_pcmcia_device(struct pcmcia_socket *s,
72 unsigned int function)
73{
74 struct pcmcia_device *p_dev = NULL;
75 unsigned long flags;
76
77 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
78 list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
79 if (p_dev->func == function) {
80 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
81 return pcmcia_get_dev(p_dev);
82 }
83 }
84 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
85 return NULL;
86}
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070087
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070088/* backwards-compatible accessing of driver --- by name! */
89
Dominik Brodowski855cdf12006-01-10 20:48:59 +010090static struct pcmcia_driver *get_pcmcia_driver(dev_info_t *dev_info)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070091{
92 struct device_driver *drv;
93 struct pcmcia_driver *p_drv;
94
95 drv = driver_find((char *) dev_info, &pcmcia_bus_type);
96 if (!drv)
97 return NULL;
98
99 p_drv = container_of(drv, struct pcmcia_driver, drv);
100
101 return (p_drv);
102}
103
104
105#ifdef CONFIG_PROC_FS
106static struct proc_dir_entry *proc_pccard = NULL;
107
108static int proc_read_drivers_callback(struct device_driver *driver, void *d)
109{
110 char **p = d;
111 struct pcmcia_driver *p_drv = container_of(driver,
112 struct pcmcia_driver, drv);
113
114 *p += sprintf(*p, "%-24.24s 1 %d\n", p_drv->drv.name,
115#ifdef CONFIG_MODULE_UNLOAD
116 (p_drv->owner) ? module_refcount(p_drv->owner) : 1
117#else
118 1
119#endif
120 );
121 d = (void *) p;
122
123 return 0;
124}
125
126static int proc_read_drivers(char *buf, char **start, off_t pos,
127 int count, int *eof, void *data)
128{
129 char *p = buf;
Jeff Garzik4deb7c12006-10-20 14:44:23 -0700130 int rc;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700131
Jeff Garzik4deb7c12006-10-20 14:44:23 -0700132 rc = bus_for_each_drv(&pcmcia_bus_type, NULL,
133 (void *) &p, proc_read_drivers_callback);
134 if (rc < 0)
135 return rc;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700136
137 return (p - buf);
138}
139#endif
140
141/*======================================================================
142
143 These manage a ring buffer of events pending for one user process
144
145======================================================================*/
146
147
148static int queue_empty(user_info_t *user)
149{
150 return (user->event_head == user->event_tail);
151}
152
153static event_t get_queued_event(user_info_t *user)
154{
155 user->event_tail = (user->event_tail+1) % MAX_EVENTS;
156 return user->event[user->event_tail];
157}
158
159static void queue_event(user_info_t *user, event_t event)
160{
161 user->event_head = (user->event_head+1) % MAX_EVENTS;
162 if (user->event_head == user->event_tail)
163 user->event_tail = (user->event_tail+1) % MAX_EVENTS;
164 user->event[user->event_head] = event;
165}
166
Dominik Brodowskidc109492005-06-27 16:28:50 -0700167void handle_event(struct pcmcia_socket *s, event_t event)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700168{
169 user_info_t *user;
170 for (user = s->user; user; user = user->next)
171 queue_event(user, event);
172 wake_up_interruptible(&s->queue);
173}
174
175
176/*======================================================================
177
178 bind_request() and bind_device() are merged by now. Register_client()
179 is called right at the end of bind_request(), during the driver's
180 ->attach() call. Individual descriptions:
181
182 bind_request() connects a socket to a particular client driver.
183 It looks up the specified device ID in the list of registered
184 drivers, binds it to the socket, and tries to create an instance
185 of the device. unbind_request() deletes a driver instance.
186
187 Bind_device() associates a device driver with a particular socket.
188 It is normally called by Driver Services after it has identified
189 a newly inserted card. An instance of that driver will then be
190 eligible to register as a client of this socket.
191
192 Register_client() uses the dev_info_t handle to match the
193 caller with a socket. The driver must have already been bound
194 to a socket with bind_device() -- in fact, bind_device()
195 allocates the client structure that will be used.
196
197======================================================================*/
198
Dominik Brodowskidc109492005-06-27 16:28:50 -0700199static int bind_request(struct pcmcia_socket *s, bind_info_t *bind_info)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700200{
201 struct pcmcia_driver *p_drv;
202 struct pcmcia_device *p_dev;
203 int ret = 0;
204 unsigned long flags;
205
Dominik Brodowskidc109492005-06-27 16:28:50 -0700206 s = pcmcia_get_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700207 if (!s)
208 return -EINVAL;
209
Dominik Brodowskidc109492005-06-27 16:28:50 -0700210 ds_dbg(2, "bind_request(%d, '%s')\n", s->sock,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700211 (char *)bind_info->dev_info);
212
213 p_drv = get_pcmcia_driver(&bind_info->dev_info);
214 if (!p_drv) {
215 ret = -EINVAL;
216 goto err_put;
217 }
218
219 if (!try_module_get(p_drv->owner)) {
220 ret = -EINVAL;
221 goto err_put_driver;
222 }
223
224 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
225 list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
226 if (p_dev->func == bind_info->function) {
227 if ((p_dev->dev.driver == &p_drv->drv)) {
228 if (p_dev->cardmgr) {
229 /* if there's already a device
230 * registered, and it was registered
231 * by userspace before, we need to
232 * return the "instance". */
233 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
Dominik Brodowskifd238232006-03-05 10:45:09 +0100234 bind_info->instance = p_dev;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700235 ret = -EBUSY;
236 goto err_put_module;
237 } else {
238 /* the correct driver managed to bind
239 * itself magically to the correct
240 * device. */
241 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
242 p_dev->cardmgr = p_drv;
243 ret = 0;
244 goto err_put_module;
245 }
246 } else if (!p_dev->dev.driver) {
247 /* there's already a device available where
248 * no device has been bound to yet. So we don't
249 * need to register a device! */
250 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
251 goto rescan;
252 }
253 }
254 }
255 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
256
257 p_dev = pcmcia_device_add(s, bind_info->function);
258 if (!p_dev) {
259 ret = -EIO;
260 goto err_put_module;
261 }
262
263rescan:
264 p_dev->cardmgr = p_drv;
265
266 /* if a driver is already running, we can abort */
267 if (p_dev->dev.driver)
268 goto err_put_module;
269
270 /*
271 * Prevent this racing with a card insertion.
272 */
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100273 mutex_lock(&s->skt_mutex);
Jeff Garzik4deb7c12006-10-20 14:44:23 -0700274 ret = bus_rescan_devices(&pcmcia_bus_type);
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100275 mutex_unlock(&s->skt_mutex);
Jeff Garzik4deb7c12006-10-20 14:44:23 -0700276 if (ret)
277 goto err_put_module;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700278
279 /* check whether the driver indeed matched. I don't care if this
280 * is racy or not, because it can only happen on cardmgr access
281 * paths...
282 */
283 if (!(p_dev->dev.driver == &p_drv->drv))
284 p_dev->cardmgr = NULL;
285
286 err_put_module:
287 module_put(p_drv->owner);
288 err_put_driver:
289 put_driver(&p_drv->drv);
290 err_put:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700291 pcmcia_put_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700292
293 return (ret);
294} /* bind_request */
295
Dominik Brodowski33519dd2005-06-27 16:28:53 -0700296#ifdef CONFIG_CARDBUS
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700297
Dominik Brodowski33519dd2005-06-27 16:28:53 -0700298static struct pci_bus *pcmcia_lookup_bus(struct pcmcia_socket *s)
299{
300 if (!s || !(s->state & SOCKET_CARDBUS))
301 return NULL;
302
303 return s->cb_dev->subordinate;
304}
305#endif
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700306
Dominik Brodowskidc109492005-06-27 16:28:50 -0700307static int get_device_info(struct pcmcia_socket *s, bind_info_t *bind_info, int first)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700308{
309 dev_node_t *node;
310 struct pcmcia_device *p_dev;
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100311 struct pcmcia_driver *p_drv;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700312 unsigned long flags;
313 int ret = 0;
314
315#ifdef CONFIG_CARDBUS
316 /*
317 * Some unbelievably ugly code to associate the PCI cardbus
318 * device and its driver with the PCMCIA "bind" information.
319 */
320 {
321 struct pci_bus *bus;
322
Dominik Brodowskidc109492005-06-27 16:28:50 -0700323 bus = pcmcia_lookup_bus(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700324 if (bus) {
325 struct list_head *list;
326 struct pci_dev *dev = NULL;
327
328 list = bus->devices.next;
329 while (list != &bus->devices) {
330 struct pci_dev *pdev = pci_dev_b(list);
331 list = list->next;
332
333 if (first) {
334 dev = pdev;
335 break;
336 }
337
338 /* Try to handle "next" here some way? */
339 }
340 if (dev && dev->driver) {
341 strlcpy(bind_info->name, dev->driver->name, DEV_NAME_LEN);
342 bind_info->major = 0;
343 bind_info->minor = 0;
344 bind_info->next = NULL;
345 return 0;
346 }
347 }
348 }
349#endif
350
351 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
352 list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
353 if (p_dev->func == bind_info->function) {
354 p_dev = pcmcia_get_dev(p_dev);
355 if (!p_dev)
356 continue;
357 goto found;
358 }
359 }
360 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
361 return -ENODEV;
362
363 found:
364 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
365
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100366 p_drv = to_pcmcia_drv(p_dev->dev.driver);
367 if (p_drv && !p_dev->_locked) {
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700368 ret = -EAGAIN;
369 goto err_put;
370 }
371
372 if (first)
Dominik Brodowskifd238232006-03-05 10:45:09 +0100373 node = p_dev->dev_node;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700374 else
Dominik Brodowskifd238232006-03-05 10:45:09 +0100375 for (node = p_dev->dev_node; node; node = node->next)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700376 if (node == bind_info->next)
377 break;
378 if (!node) {
379 ret = -ENODEV;
380 goto err_put;
381 }
382
383 strlcpy(bind_info->name, node->dev_name, DEV_NAME_LEN);
384 bind_info->major = node->major;
385 bind_info->minor = node->minor;
386 bind_info->next = node->next;
387
388 err_put:
389 pcmcia_put_dev(p_dev);
390 return (ret);
391} /* get_device_info */
392
393
394static int ds_open(struct inode *inode, struct file *file)
395{
396 socket_t i = iminor(inode);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700397 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700398 user_info_t *user;
Dominik Brodowskic352ec82005-09-13 01:25:03 -0700399 static int warning_printed = 0;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700400
401 ds_dbg(0, "ds_open(socket %d)\n", i);
402
Dominik Brodowskidc109492005-06-27 16:28:50 -0700403 s = pcmcia_get_socket_by_nr(i);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700404 if (!s)
405 return -ENODEV;
Dominik Brodowskidc109492005-06-27 16:28:50 -0700406 s = pcmcia_get_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700407 if (!s)
408 return -ENODEV;
409
410 if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700411 if (s->pcmcia_state.busy) {
Dominik Brodowskidc109492005-06-27 16:28:50 -0700412 pcmcia_put_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700413 return -EBUSY;
414 }
415 else
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700416 s->pcmcia_state.busy = 1;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700417 }
418
419 user = kmalloc(sizeof(user_info_t), GFP_KERNEL);
420 if (!user) {
Dominik Brodowskidc109492005-06-27 16:28:50 -0700421 pcmcia_put_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700422 return -ENOMEM;
423 }
424 user->event_tail = user->event_head = 0;
425 user->next = s->user;
426 user->user_magic = USER_MAGIC;
427 user->socket = s;
428 s->user = user;
429 file->private_data = user;
430
Dominik Brodowskic352ec82005-09-13 01:25:03 -0700431 if (!warning_printed) {
432 printk(KERN_INFO "pcmcia: Detected deprecated PCMCIA ioctl "
Benjamin Herrenschmidt73d58582006-05-15 09:43:53 -0700433 "usage from process: %s.\n", current->comm);
Dominik Brodowskic352ec82005-09-13 01:25:03 -0700434 printk(KERN_INFO "pcmcia: This interface will soon be removed from "
435 "the kernel; please expect breakage unless you upgrade "
436 "to new tools.\n");
437 printk(KERN_INFO "pcmcia: see http://www.kernel.org/pub/linux/"
438 "utils/kernel/pcmcia/pcmcia.html for details.\n");
439 warning_printed = 1;
440 }
441
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700442 if (s->pcmcia_state.present)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700443 queue_event(user, CS_EVENT_CARD_INSERTION);
444 return 0;
445} /* ds_open */
446
447/*====================================================================*/
448
449static int ds_release(struct inode *inode, struct file *file)
450{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700451 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700452 user_info_t *user, **link;
453
454 ds_dbg(0, "ds_release(socket %d)\n", iminor(inode));
455
456 user = file->private_data;
457 if (CHECK_USER(user))
458 goto out;
459
460 s = user->socket;
461
462 /* Unlink user data structure */
463 if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700464 s->pcmcia_state.busy = 0;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700465 }
466 file->private_data = NULL;
467 for (link = &s->user; *link; link = &(*link)->next)
468 if (*link == user) break;
469 if (link == NULL)
470 goto out;
471 *link = user->next;
472 user->user_magic = 0;
473 kfree(user);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700474 pcmcia_put_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700475out:
476 return 0;
477} /* ds_release */
478
479/*====================================================================*/
480
481static ssize_t ds_read(struct file *file, char __user *buf,
482 size_t count, loff_t *ppos)
483{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700484 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700485 user_info_t *user;
486 int ret;
487
Josef Sipek40fad042006-12-08 02:37:29 -0800488 ds_dbg(2, "ds_read(socket %d)\n", iminor(file->f_path.dentry->d_inode));
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700489
490 if (count < 4)
491 return -EINVAL;
492
493 user = file->private_data;
494 if (CHECK_USER(user))
495 return -EIO;
496
497 s = user->socket;
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700498 if (s->pcmcia_state.dead)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700499 return -EIO;
500
501 ret = wait_event_interruptible(s->queue, !queue_empty(user));
502 if (ret == 0)
503 ret = put_user(get_queued_event(user), (int __user *)buf) ? -EFAULT : 4;
504
505 return ret;
506} /* ds_read */
507
508/*====================================================================*/
509
510static ssize_t ds_write(struct file *file, const char __user *buf,
511 size_t count, loff_t *ppos)
512{
Josef Sipek40fad042006-12-08 02:37:29 -0800513 ds_dbg(2, "ds_write(socket %d)\n", iminor(file->f_path.dentry->d_inode));
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700514
515 if (count != 4)
516 return -EINVAL;
517 if ((file->f_flags & O_ACCMODE) == O_RDONLY)
518 return -EBADF;
519
520 return -EIO;
521} /* ds_write */
522
523/*====================================================================*/
524
525/* No kernel lock - fine */
526static u_int ds_poll(struct file *file, poll_table *wait)
527{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700528 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700529 user_info_t *user;
530
Josef Sipek40fad042006-12-08 02:37:29 -0800531 ds_dbg(2, "ds_poll(socket %d)\n", iminor(file->f_path.dentry->d_inode));
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700532
533 user = file->private_data;
534 if (CHECK_USER(user))
535 return POLLERR;
536 s = user->socket;
537 /*
538 * We don't check for a dead socket here since that
539 * will send cardmgr into an endless spin.
540 */
541 poll_wait(file, &s->queue, wait);
542 if (!queue_empty(user))
543 return POLLIN | POLLRDNORM;
544 return 0;
545} /* ds_poll */
546
547/*====================================================================*/
548
549extern int pcmcia_adjust_resource_info(adjust_t *adj);
550
551static int ds_ioctl(struct inode * inode, struct file * file,
552 u_int cmd, u_long arg)
553{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700554 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700555 void __user *uarg = (char __user *)arg;
556 u_int size;
557 int ret, err;
558 ds_ioctl_arg_t *buf;
559 user_info_t *user;
560
561 ds_dbg(2, "ds_ioctl(socket %d, %#x, %#lx)\n", iminor(inode), cmd, arg);
562
563 user = file->private_data;
564 if (CHECK_USER(user))
565 return -EIO;
566
567 s = user->socket;
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700568 if (s->pcmcia_state.dead)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700569 return -EIO;
570
571 size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
572 if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL;
573
574 /* Permission check */
575 if (!(cmd & IOC_OUT) && !capable(CAP_SYS_ADMIN))
576 return -EPERM;
577
578 if (cmd & IOC_IN) {
579 if (!access_ok(VERIFY_READ, uarg, size)) {
580 ds_dbg(3, "ds_ioctl(): verify_read = %d\n", -EFAULT);
581 return -EFAULT;
582 }
583 }
584 if (cmd & IOC_OUT) {
585 if (!access_ok(VERIFY_WRITE, uarg, size)) {
586 ds_dbg(3, "ds_ioctl(): verify_write = %d\n", -EFAULT);
587 return -EFAULT;
588 }
589 }
590 buf = kmalloc(sizeof(ds_ioctl_arg_t), GFP_KERNEL);
591 if (!buf)
592 return -ENOMEM;
593
594 err = ret = 0;
595
Dominik Brodowski93740742006-11-19 11:21:27 -0500596 if (cmd & IOC_IN) {
597 if (__copy_from_user((char *)buf, uarg, size)) {
598 err = -EFAULT;
599 goto free_out;
600 }
601 }
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700602
603 switch (cmd) {
604 case DS_ADJUST_RESOURCE_INFO:
605 ret = pcmcia_adjust_resource_info(&buf->adjust);
606 break;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700607 case DS_GET_CONFIGURATION_INFO:
608 if (buf->config.Function &&
Dominik Brodowskidc109492005-06-27 16:28:50 -0700609 (buf->config.Function >= s->functions))
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700610 ret = CS_BAD_ARGS;
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100611 else {
612 struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->config.Function);
Daniel Ritzf47ad212006-07-30 03:03:47 -0700613 ret = pccard_get_configuration_info(s, p_dev, &buf->config);
614 pcmcia_put_dev(p_dev);
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100615 }
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700616 break;
617 case DS_GET_FIRST_TUPLE:
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100618 mutex_lock(&s->skt_mutex);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700619 pcmcia_validate_mem(s);
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100620 mutex_unlock(&s->skt_mutex);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700621 ret = pccard_get_first_tuple(s, BIND_FN_ALL, &buf->tuple);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700622 break;
623 case DS_GET_NEXT_TUPLE:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700624 ret = pccard_get_next_tuple(s, BIND_FN_ALL, &buf->tuple);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700625 break;
626 case DS_GET_TUPLE_DATA:
627 buf->tuple.TupleData = buf->tuple_parse.data;
628 buf->tuple.TupleDataMax = sizeof(buf->tuple_parse.data);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700629 ret = pccard_get_tuple_data(s, &buf->tuple);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700630 break;
631 case DS_PARSE_TUPLE:
632 buf->tuple.TupleData = buf->tuple_parse.data;
633 ret = pccard_parse_tuple(&buf->tuple, &buf->tuple_parse.parse);
634 break;
635 case DS_RESET_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700636 ret = pccard_reset_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700637 break;
638 case DS_GET_STATUS:
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100639 if (buf->status.Function &&
640 (buf->status.Function >= s->functions))
641 ret = CS_BAD_ARGS;
642 else {
643 struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->status.Function);
Daniel Ritzf47ad212006-07-30 03:03:47 -0700644 ret = pccard_get_status(s, p_dev, &buf->status);
645 pcmcia_put_dev(p_dev);
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100646 }
647 break;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700648 case DS_VALIDATE_CIS:
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100649 mutex_lock(&s->skt_mutex);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700650 pcmcia_validate_mem(s);
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100651 mutex_unlock(&s->skt_mutex);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700652 ret = pccard_validate_cis(s, BIND_FN_ALL, &buf->cisinfo);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700653 break;
654 case DS_SUSPEND_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700655 ret = pcmcia_suspend_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700656 break;
657 case DS_RESUME_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700658 ret = pcmcia_resume_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700659 break;
660 case DS_EJECT_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700661 err = pcmcia_eject_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700662 break;
663 case DS_INSERT_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700664 err = pcmcia_insert_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700665 break;
666 case DS_ACCESS_CONFIGURATION_REGISTER:
667 if ((buf->conf_reg.Action == CS_WRITE) && !capable(CAP_SYS_ADMIN)) {
668 err = -EPERM;
669 goto free_out;
670 }
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100671
672 ret = CS_BAD_ARGS;
673
674 if (!(buf->conf_reg.Function &&
675 (buf->conf_reg.Function >= s->functions))) {
676 struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->conf_reg.Function);
Benjamin Herrenschmidt73d58582006-05-15 09:43:53 -0700677 if (p_dev) {
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100678 ret = pcmcia_access_configuration_register(p_dev, &buf->conf_reg);
Benjamin Herrenschmidt73d58582006-05-15 09:43:53 -0700679 pcmcia_put_dev(p_dev);
680 }
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100681 }
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700682 break;
683 case DS_GET_FIRST_REGION:
684 case DS_GET_NEXT_REGION:
685 case DS_BIND_MTD:
686 if (!capable(CAP_SYS_ADMIN)) {
687 err = -EPERM;
688 goto free_out;
689 } else {
690 static int printed = 0;
691 if (!printed) {
692 printk(KERN_WARNING "2.6. kernels use pcmciamtd instead of memory_cs.c and do not require special\n");
693 printk(KERN_WARNING "MTD handling any more.\n");
694 printed++;
695 }
696 }
697 err = -EINVAL;
698 goto free_out;
699 break;
700 case DS_GET_FIRST_WINDOW:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700701 ret = pcmcia_get_window(s, &buf->win_info.handle, 0,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700702 &buf->win_info.window);
703 break;
704 case DS_GET_NEXT_WINDOW:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700705 ret = pcmcia_get_window(s, &buf->win_info.handle,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700706 buf->win_info.handle->index + 1, &buf->win_info.window);
707 break;
708 case DS_GET_MEM_PAGE:
709 ret = pcmcia_get_mem_page(buf->win_info.handle,
710 &buf->win_info.map);
711 break;
712 case DS_REPLACE_CIS:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700713 ret = pcmcia_replace_cis(s, &buf->cisdump);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700714 break;
715 case DS_BIND_REQUEST:
716 if (!capable(CAP_SYS_ADMIN)) {
717 err = -EPERM;
718 goto free_out;
719 }
720 err = bind_request(s, &buf->bind_info);
721 break;
722 case DS_GET_DEVICE_INFO:
723 err = get_device_info(s, &buf->bind_info, 1);
724 break;
725 case DS_GET_NEXT_DEVICE:
726 err = get_device_info(s, &buf->bind_info, 0);
727 break;
728 case DS_UNBIND_REQUEST:
729 err = 0;
730 break;
731 default:
732 err = -EINVAL;
733 }
734
735 if ((err == 0) && (ret != CS_SUCCESS)) {
736 ds_dbg(2, "ds_ioctl: ret = %d\n", ret);
737 switch (ret) {
738 case CS_BAD_SOCKET: case CS_NO_CARD:
739 err = -ENODEV; break;
740 case CS_BAD_ARGS: case CS_BAD_ATTRIBUTE: case CS_BAD_IRQ:
741 case CS_BAD_TUPLE:
742 err = -EINVAL; break;
743 case CS_IN_USE:
744 err = -EBUSY; break;
745 case CS_OUT_OF_RESOURCE:
746 err = -ENOSPC; break;
747 case CS_NO_MORE_ITEMS:
748 err = -ENODATA; break;
749 case CS_UNSUPPORTED_FUNCTION:
750 err = -ENOSYS; break;
751 default:
752 err = -EIO; break;
753 }
754 }
755
756 if (cmd & IOC_OUT) {
757 if (__copy_to_user(uarg, (char *)buf, size))
758 err = -EFAULT;
759 }
760
761free_out:
762 kfree(buf);
763 return err;
764} /* ds_ioctl */
765
766/*====================================================================*/
767
Arjan van de Vend54b1fd2007-02-12 00:55:34 -0800768static const struct file_operations ds_fops = {
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700769 .owner = THIS_MODULE,
770 .open = ds_open,
771 .release = ds_release,
772 .ioctl = ds_ioctl,
773 .read = ds_read,
774 .write = ds_write,
775 .poll = ds_poll,
776};
777
778void __init pcmcia_setup_ioctl(void) {
779 int i;
780
781 /* Set up character device for user mode clients */
782 i = register_chrdev(0, "pcmcia", &ds_fops);
Dominik Brodowski1a8ceaf2005-06-27 16:29:00 -0700783 if (i < 0)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700784 printk(KERN_NOTICE "unable to find a free device # for "
Dominik Brodowski1a8ceaf2005-06-27 16:29:00 -0700785 "Driver Services (error=%d)\n", i);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700786 else
787 major_dev = i;
788
789#ifdef CONFIG_PROC_FS
akpm@linux-foundation.org97094dc2008-04-29 10:47:54 -0700790 proc_pccard = proc_mkdir("bus/pccard", NULL);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700791 if (proc_pccard)
792 create_proc_read_entry("drivers",0,proc_pccard,proc_read_drivers,NULL);
793#endif
794}
795
796
797void __exit pcmcia_cleanup_ioctl(void) {
798#ifdef CONFIG_PROC_FS
799 if (proc_pccard) {
800 remove_proc_entry("drivers", proc_pccard);
akpm@linux-foundation.org97094dc2008-04-29 10:47:54 -0700801 remove_proc_entry("bus/pccard", NULL);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700802 }
803#endif
804 if (major_dev != -1)
805 unregister_chrdev(major_dev, "pcmcia");
806}