blob: 758ece8dc362f5862d0d4c83280212f0fd8e905c [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
Dominik Brodowskic5023802008-06-19 19:02:52 +0200141
142#ifdef CONFIG_PCMCIA_PROBE
143
144static int adjust_irq(struct pcmcia_socket *s, adjust_t *adj)
145{
146 int irq;
147 u32 mask;
148
149 irq = adj->resource.irq.IRQ;
150 if ((irq < 0) || (irq > 15))
151 return CS_BAD_IRQ;
152
153 if (adj->Action != REMOVE_MANAGED_RESOURCE)
154 return 0;
155
156 mask = 1 << irq;
157
158 if (!(s->irq_mask & mask))
159 return 0;
160
161 s->irq_mask &= ~mask;
162
163 return 0;
164}
165
166#else
167
168static inline int adjust_irq(struct pcmcia_socket *s, adjust_t *adj) {
169 return CS_SUCCESS;
170}
171
172#endif
173
174static int pcmcia_adjust_resource_info(adjust_t *adj)
175{
176 struct pcmcia_socket *s;
177 int ret = CS_UNSUPPORTED_FUNCTION;
178 unsigned long flags;
179
180 down_read(&pcmcia_socket_list_rwsem);
181 list_for_each_entry(s, &pcmcia_socket_list, socket_list) {
182
183 if (adj->Resource == RES_IRQ)
184 ret = adjust_irq(s, adj);
185
186 else if (s->resource_ops->add_io) {
187 unsigned long begin, end;
188
189 /* you can't use the old interface if the new
190 * one was used before */
191 spin_lock_irqsave(&s->lock, flags);
192 if ((s->resource_setup_new) &&
193 !(s->resource_setup_old)) {
194 spin_unlock_irqrestore(&s->lock, flags);
195 continue;
196 } else if (!(s->resource_setup_old))
197 s->resource_setup_old = 1;
198 spin_unlock_irqrestore(&s->lock, flags);
199
200 switch (adj->Resource) {
201 case RES_MEMORY_RANGE:
202 begin = adj->resource.memory.Base;
203 end = adj->resource.memory.Base + adj->resource.memory.Size - 1;
204 if (s->resource_ops->add_mem)
205 ret =s->resource_ops->add_mem(s, adj->Action, begin, end);
206 case RES_IO_RANGE:
207 begin = adj->resource.io.BasePort;
208 end = adj->resource.io.BasePort + adj->resource.io.NumPorts - 1;
209 if (s->resource_ops->add_io)
210 ret = s->resource_ops->add_io(s, adj->Action, begin, end);
211 }
212 if (!ret) {
213 /* as there's no way we know this is the
214 * last call to adjust_resource_info, we
215 * always need to assume this is the latest
216 * one... */
217 spin_lock_irqsave(&s->lock, flags);
218 s->resource_setup_done = 1;
219 spin_unlock_irqrestore(&s->lock, flags);
220 }
221 }
222 }
223 up_read(&pcmcia_socket_list_rwsem);
224
225 return (ret);
226}
227
228
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700229/*======================================================================
230
231 These manage a ring buffer of events pending for one user process
232
233======================================================================*/
234
235
236static int queue_empty(user_info_t *user)
237{
238 return (user->event_head == user->event_tail);
239}
240
241static event_t get_queued_event(user_info_t *user)
242{
243 user->event_tail = (user->event_tail+1) % MAX_EVENTS;
244 return user->event[user->event_tail];
245}
246
247static void queue_event(user_info_t *user, event_t event)
248{
249 user->event_head = (user->event_head+1) % MAX_EVENTS;
250 if (user->event_head == user->event_tail)
251 user->event_tail = (user->event_tail+1) % MAX_EVENTS;
252 user->event[user->event_head] = event;
253}
254
Dominik Brodowskidc109492005-06-27 16:28:50 -0700255void handle_event(struct pcmcia_socket *s, event_t event)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700256{
257 user_info_t *user;
258 for (user = s->user; user; user = user->next)
259 queue_event(user, event);
260 wake_up_interruptible(&s->queue);
261}
262
263
264/*======================================================================
265
266 bind_request() and bind_device() are merged by now. Register_client()
267 is called right at the end of bind_request(), during the driver's
268 ->attach() call. Individual descriptions:
269
270 bind_request() connects a socket to a particular client driver.
271 It looks up the specified device ID in the list of registered
272 drivers, binds it to the socket, and tries to create an instance
273 of the device. unbind_request() deletes a driver instance.
274
275 Bind_device() associates a device driver with a particular socket.
276 It is normally called by Driver Services after it has identified
277 a newly inserted card. An instance of that driver will then be
278 eligible to register as a client of this socket.
279
280 Register_client() uses the dev_info_t handle to match the
281 caller with a socket. The driver must have already been bound
282 to a socket with bind_device() -- in fact, bind_device()
283 allocates the client structure that will be used.
284
285======================================================================*/
286
Dominik Brodowskidc109492005-06-27 16:28:50 -0700287static int bind_request(struct pcmcia_socket *s, bind_info_t *bind_info)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700288{
289 struct pcmcia_driver *p_drv;
290 struct pcmcia_device *p_dev;
291 int ret = 0;
292 unsigned long flags;
293
Dominik Brodowskidc109492005-06-27 16:28:50 -0700294 s = pcmcia_get_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700295 if (!s)
296 return -EINVAL;
297
Dominik Brodowskidc109492005-06-27 16:28:50 -0700298 ds_dbg(2, "bind_request(%d, '%s')\n", s->sock,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700299 (char *)bind_info->dev_info);
300
301 p_drv = get_pcmcia_driver(&bind_info->dev_info);
302 if (!p_drv) {
303 ret = -EINVAL;
304 goto err_put;
305 }
306
307 if (!try_module_get(p_drv->owner)) {
308 ret = -EINVAL;
309 goto err_put_driver;
310 }
311
312 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
313 list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
314 if (p_dev->func == bind_info->function) {
315 if ((p_dev->dev.driver == &p_drv->drv)) {
316 if (p_dev->cardmgr) {
317 /* if there's already a device
318 * registered, and it was registered
319 * by userspace before, we need to
320 * return the "instance". */
321 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
Dominik Brodowskifd238232006-03-05 10:45:09 +0100322 bind_info->instance = p_dev;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700323 ret = -EBUSY;
324 goto err_put_module;
325 } else {
326 /* the correct driver managed to bind
327 * itself magically to the correct
328 * device. */
329 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
330 p_dev->cardmgr = p_drv;
331 ret = 0;
332 goto err_put_module;
333 }
334 } else if (!p_dev->dev.driver) {
335 /* there's already a device available where
336 * no device has been bound to yet. So we don't
337 * need to register a device! */
338 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
339 goto rescan;
340 }
341 }
342 }
343 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
344
345 p_dev = pcmcia_device_add(s, bind_info->function);
346 if (!p_dev) {
347 ret = -EIO;
348 goto err_put_module;
349 }
350
351rescan:
352 p_dev->cardmgr = p_drv;
353
354 /* if a driver is already running, we can abort */
355 if (p_dev->dev.driver)
356 goto err_put_module;
357
358 /*
359 * Prevent this racing with a card insertion.
360 */
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100361 mutex_lock(&s->skt_mutex);
Jeff Garzik4deb7c12006-10-20 14:44:23 -0700362 ret = bus_rescan_devices(&pcmcia_bus_type);
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100363 mutex_unlock(&s->skt_mutex);
Jeff Garzik4deb7c12006-10-20 14:44:23 -0700364 if (ret)
365 goto err_put_module;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700366
367 /* check whether the driver indeed matched. I don't care if this
368 * is racy or not, because it can only happen on cardmgr access
369 * paths...
370 */
371 if (!(p_dev->dev.driver == &p_drv->drv))
372 p_dev->cardmgr = NULL;
373
374 err_put_module:
375 module_put(p_drv->owner);
376 err_put_driver:
377 put_driver(&p_drv->drv);
378 err_put:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700379 pcmcia_put_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700380
381 return (ret);
382} /* bind_request */
383
Dominik Brodowski33519dd2005-06-27 16:28:53 -0700384#ifdef CONFIG_CARDBUS
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700385
Dominik Brodowski33519dd2005-06-27 16:28:53 -0700386static struct pci_bus *pcmcia_lookup_bus(struct pcmcia_socket *s)
387{
388 if (!s || !(s->state & SOCKET_CARDBUS))
389 return NULL;
390
391 return s->cb_dev->subordinate;
392}
393#endif
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700394
Dominik Brodowskidc109492005-06-27 16:28:50 -0700395static int get_device_info(struct pcmcia_socket *s, bind_info_t *bind_info, int first)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700396{
397 dev_node_t *node;
398 struct pcmcia_device *p_dev;
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100399 struct pcmcia_driver *p_drv;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700400 unsigned long flags;
401 int ret = 0;
402
403#ifdef CONFIG_CARDBUS
404 /*
405 * Some unbelievably ugly code to associate the PCI cardbus
406 * device and its driver with the PCMCIA "bind" information.
407 */
408 {
409 struct pci_bus *bus;
410
Dominik Brodowskidc109492005-06-27 16:28:50 -0700411 bus = pcmcia_lookup_bus(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700412 if (bus) {
413 struct list_head *list;
414 struct pci_dev *dev = NULL;
415
416 list = bus->devices.next;
417 while (list != &bus->devices) {
418 struct pci_dev *pdev = pci_dev_b(list);
419 list = list->next;
420
421 if (first) {
422 dev = pdev;
423 break;
424 }
425
426 /* Try to handle "next" here some way? */
427 }
428 if (dev && dev->driver) {
429 strlcpy(bind_info->name, dev->driver->name, DEV_NAME_LEN);
430 bind_info->major = 0;
431 bind_info->minor = 0;
432 bind_info->next = NULL;
433 return 0;
434 }
435 }
436 }
437#endif
438
439 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
440 list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
441 if (p_dev->func == bind_info->function) {
442 p_dev = pcmcia_get_dev(p_dev);
443 if (!p_dev)
444 continue;
445 goto found;
446 }
447 }
448 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
449 return -ENODEV;
450
451 found:
452 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
453
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100454 p_drv = to_pcmcia_drv(p_dev->dev.driver);
455 if (p_drv && !p_dev->_locked) {
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700456 ret = -EAGAIN;
457 goto err_put;
458 }
459
460 if (first)
Dominik Brodowskifd238232006-03-05 10:45:09 +0100461 node = p_dev->dev_node;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700462 else
Dominik Brodowskifd238232006-03-05 10:45:09 +0100463 for (node = p_dev->dev_node; node; node = node->next)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700464 if (node == bind_info->next)
465 break;
466 if (!node) {
467 ret = -ENODEV;
468 goto err_put;
469 }
470
471 strlcpy(bind_info->name, node->dev_name, DEV_NAME_LEN);
472 bind_info->major = node->major;
473 bind_info->minor = node->minor;
474 bind_info->next = node->next;
475
476 err_put:
477 pcmcia_put_dev(p_dev);
478 return (ret);
479} /* get_device_info */
480
481
482static int ds_open(struct inode *inode, struct file *file)
483{
484 socket_t i = iminor(inode);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700485 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700486 user_info_t *user;
Dominik Brodowskic352ec82005-09-13 01:25:03 -0700487 static int warning_printed = 0;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700488
489 ds_dbg(0, "ds_open(socket %d)\n", i);
490
Dominik Brodowskidc109492005-06-27 16:28:50 -0700491 s = pcmcia_get_socket_by_nr(i);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700492 if (!s)
493 return -ENODEV;
Dominik Brodowskidc109492005-06-27 16:28:50 -0700494 s = pcmcia_get_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700495 if (!s)
496 return -ENODEV;
497
498 if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700499 if (s->pcmcia_state.busy) {
Dominik Brodowskidc109492005-06-27 16:28:50 -0700500 pcmcia_put_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700501 return -EBUSY;
502 }
503 else
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700504 s->pcmcia_state.busy = 1;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700505 }
506
507 user = kmalloc(sizeof(user_info_t), GFP_KERNEL);
508 if (!user) {
Dominik Brodowskidc109492005-06-27 16:28:50 -0700509 pcmcia_put_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700510 return -ENOMEM;
511 }
512 user->event_tail = user->event_head = 0;
513 user->next = s->user;
514 user->user_magic = USER_MAGIC;
515 user->socket = s;
516 s->user = user;
517 file->private_data = user;
518
Dominik Brodowskic352ec82005-09-13 01:25:03 -0700519 if (!warning_printed) {
520 printk(KERN_INFO "pcmcia: Detected deprecated PCMCIA ioctl "
Benjamin Herrenschmidt73d58582006-05-15 09:43:53 -0700521 "usage from process: %s.\n", current->comm);
Dominik Brodowskic352ec82005-09-13 01:25:03 -0700522 printk(KERN_INFO "pcmcia: This interface will soon be removed from "
523 "the kernel; please expect breakage unless you upgrade "
524 "to new tools.\n");
525 printk(KERN_INFO "pcmcia: see http://www.kernel.org/pub/linux/"
526 "utils/kernel/pcmcia/pcmcia.html for details.\n");
527 warning_printed = 1;
528 }
529
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700530 if (s->pcmcia_state.present)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700531 queue_event(user, CS_EVENT_CARD_INSERTION);
532 return 0;
533} /* ds_open */
534
535/*====================================================================*/
536
537static int ds_release(struct inode *inode, struct file *file)
538{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700539 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700540 user_info_t *user, **link;
541
542 ds_dbg(0, "ds_release(socket %d)\n", iminor(inode));
543
544 user = file->private_data;
545 if (CHECK_USER(user))
546 goto out;
547
548 s = user->socket;
549
550 /* Unlink user data structure */
551 if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700552 s->pcmcia_state.busy = 0;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700553 }
554 file->private_data = NULL;
555 for (link = &s->user; *link; link = &(*link)->next)
556 if (*link == user) break;
557 if (link == NULL)
558 goto out;
559 *link = user->next;
560 user->user_magic = 0;
561 kfree(user);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700562 pcmcia_put_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700563out:
564 return 0;
565} /* ds_release */
566
567/*====================================================================*/
568
569static ssize_t ds_read(struct file *file, char __user *buf,
570 size_t count, loff_t *ppos)
571{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700572 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700573 user_info_t *user;
574 int ret;
575
Josef Sipek40fad042006-12-08 02:37:29 -0800576 ds_dbg(2, "ds_read(socket %d)\n", iminor(file->f_path.dentry->d_inode));
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700577
578 if (count < 4)
579 return -EINVAL;
580
581 user = file->private_data;
582 if (CHECK_USER(user))
583 return -EIO;
584
585 s = user->socket;
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700586 if (s->pcmcia_state.dead)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700587 return -EIO;
588
589 ret = wait_event_interruptible(s->queue, !queue_empty(user));
590 if (ret == 0)
591 ret = put_user(get_queued_event(user), (int __user *)buf) ? -EFAULT : 4;
592
593 return ret;
594} /* ds_read */
595
596/*====================================================================*/
597
598static ssize_t ds_write(struct file *file, const char __user *buf,
599 size_t count, loff_t *ppos)
600{
Josef Sipek40fad042006-12-08 02:37:29 -0800601 ds_dbg(2, "ds_write(socket %d)\n", iminor(file->f_path.dentry->d_inode));
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700602
603 if (count != 4)
604 return -EINVAL;
605 if ((file->f_flags & O_ACCMODE) == O_RDONLY)
606 return -EBADF;
607
608 return -EIO;
609} /* ds_write */
610
611/*====================================================================*/
612
613/* No kernel lock - fine */
614static u_int ds_poll(struct file *file, poll_table *wait)
615{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700616 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700617 user_info_t *user;
618
Josef Sipek40fad042006-12-08 02:37:29 -0800619 ds_dbg(2, "ds_poll(socket %d)\n", iminor(file->f_path.dentry->d_inode));
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700620
621 user = file->private_data;
622 if (CHECK_USER(user))
623 return POLLERR;
624 s = user->socket;
625 /*
626 * We don't check for a dead socket here since that
627 * will send cardmgr into an endless spin.
628 */
629 poll_wait(file, &s->queue, wait);
630 if (!queue_empty(user))
631 return POLLIN | POLLRDNORM;
632 return 0;
633} /* ds_poll */
634
635/*====================================================================*/
636
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700637static int ds_ioctl(struct inode * inode, struct file * file,
638 u_int cmd, u_long arg)
639{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700640 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700641 void __user *uarg = (char __user *)arg;
642 u_int size;
643 int ret, err;
644 ds_ioctl_arg_t *buf;
645 user_info_t *user;
646
647 ds_dbg(2, "ds_ioctl(socket %d, %#x, %#lx)\n", iminor(inode), cmd, arg);
648
649 user = file->private_data;
650 if (CHECK_USER(user))
651 return -EIO;
652
653 s = user->socket;
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700654 if (s->pcmcia_state.dead)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700655 return -EIO;
656
657 size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
658 if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL;
659
660 /* Permission check */
661 if (!(cmd & IOC_OUT) && !capable(CAP_SYS_ADMIN))
662 return -EPERM;
663
664 if (cmd & IOC_IN) {
665 if (!access_ok(VERIFY_READ, uarg, size)) {
666 ds_dbg(3, "ds_ioctl(): verify_read = %d\n", -EFAULT);
667 return -EFAULT;
668 }
669 }
670 if (cmd & IOC_OUT) {
671 if (!access_ok(VERIFY_WRITE, uarg, size)) {
672 ds_dbg(3, "ds_ioctl(): verify_write = %d\n", -EFAULT);
673 return -EFAULT;
674 }
675 }
676 buf = kmalloc(sizeof(ds_ioctl_arg_t), GFP_KERNEL);
677 if (!buf)
678 return -ENOMEM;
679
680 err = ret = 0;
681
Dominik Brodowski93740742006-11-19 11:21:27 -0500682 if (cmd & IOC_IN) {
683 if (__copy_from_user((char *)buf, uarg, size)) {
684 err = -EFAULT;
685 goto free_out;
686 }
687 }
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700688
689 switch (cmd) {
690 case DS_ADJUST_RESOURCE_INFO:
691 ret = pcmcia_adjust_resource_info(&buf->adjust);
692 break;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700693 case DS_GET_CONFIGURATION_INFO:
694 if (buf->config.Function &&
Dominik Brodowskidc109492005-06-27 16:28:50 -0700695 (buf->config.Function >= s->functions))
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700696 ret = CS_BAD_ARGS;
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100697 else {
698 struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->config.Function);
Daniel Ritzf47ad212006-07-30 03:03:47 -0700699 ret = pccard_get_configuration_info(s, p_dev, &buf->config);
700 pcmcia_put_dev(p_dev);
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100701 }
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700702 break;
703 case DS_GET_FIRST_TUPLE:
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100704 mutex_lock(&s->skt_mutex);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700705 pcmcia_validate_mem(s);
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100706 mutex_unlock(&s->skt_mutex);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700707 ret = pccard_get_first_tuple(s, BIND_FN_ALL, &buf->tuple);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700708 break;
709 case DS_GET_NEXT_TUPLE:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700710 ret = pccard_get_next_tuple(s, BIND_FN_ALL, &buf->tuple);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700711 break;
712 case DS_GET_TUPLE_DATA:
713 buf->tuple.TupleData = buf->tuple_parse.data;
714 buf->tuple.TupleDataMax = sizeof(buf->tuple_parse.data);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700715 ret = pccard_get_tuple_data(s, &buf->tuple);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700716 break;
717 case DS_PARSE_TUPLE:
718 buf->tuple.TupleData = buf->tuple_parse.data;
719 ret = pccard_parse_tuple(&buf->tuple, &buf->tuple_parse.parse);
720 break;
721 case DS_RESET_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700722 ret = pccard_reset_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700723 break;
724 case DS_GET_STATUS:
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100725 if (buf->status.Function &&
726 (buf->status.Function >= s->functions))
727 ret = CS_BAD_ARGS;
728 else {
729 struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->status.Function);
Daniel Ritzf47ad212006-07-30 03:03:47 -0700730 ret = pccard_get_status(s, p_dev, &buf->status);
731 pcmcia_put_dev(p_dev);
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100732 }
733 break;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700734 case DS_VALIDATE_CIS:
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100735 mutex_lock(&s->skt_mutex);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700736 pcmcia_validate_mem(s);
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100737 mutex_unlock(&s->skt_mutex);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700738 ret = pccard_validate_cis(s, BIND_FN_ALL, &buf->cisinfo);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700739 break;
740 case DS_SUSPEND_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700741 ret = pcmcia_suspend_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700742 break;
743 case DS_RESUME_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700744 ret = pcmcia_resume_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700745 break;
746 case DS_EJECT_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700747 err = pcmcia_eject_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700748 break;
749 case DS_INSERT_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700750 err = pcmcia_insert_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700751 break;
752 case DS_ACCESS_CONFIGURATION_REGISTER:
753 if ((buf->conf_reg.Action == CS_WRITE) && !capable(CAP_SYS_ADMIN)) {
754 err = -EPERM;
755 goto free_out;
756 }
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100757
758 ret = CS_BAD_ARGS;
759
760 if (!(buf->conf_reg.Function &&
761 (buf->conf_reg.Function >= s->functions))) {
762 struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->conf_reg.Function);
Benjamin Herrenschmidt73d58582006-05-15 09:43:53 -0700763 if (p_dev) {
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100764 ret = pcmcia_access_configuration_register(p_dev, &buf->conf_reg);
Benjamin Herrenschmidt73d58582006-05-15 09:43:53 -0700765 pcmcia_put_dev(p_dev);
766 }
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100767 }
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700768 break;
769 case DS_GET_FIRST_REGION:
770 case DS_GET_NEXT_REGION:
771 case DS_BIND_MTD:
772 if (!capable(CAP_SYS_ADMIN)) {
773 err = -EPERM;
774 goto free_out;
775 } else {
776 static int printed = 0;
777 if (!printed) {
778 printk(KERN_WARNING "2.6. kernels use pcmciamtd instead of memory_cs.c and do not require special\n");
779 printk(KERN_WARNING "MTD handling any more.\n");
780 printed++;
781 }
782 }
783 err = -EINVAL;
784 goto free_out;
785 break;
786 case DS_GET_FIRST_WINDOW:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700787 ret = pcmcia_get_window(s, &buf->win_info.handle, 0,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700788 &buf->win_info.window);
789 break;
790 case DS_GET_NEXT_WINDOW:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700791 ret = pcmcia_get_window(s, &buf->win_info.handle,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700792 buf->win_info.handle->index + 1, &buf->win_info.window);
793 break;
794 case DS_GET_MEM_PAGE:
795 ret = pcmcia_get_mem_page(buf->win_info.handle,
796 &buf->win_info.map);
797 break;
798 case DS_REPLACE_CIS:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700799 ret = pcmcia_replace_cis(s, &buf->cisdump);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700800 break;
801 case DS_BIND_REQUEST:
802 if (!capable(CAP_SYS_ADMIN)) {
803 err = -EPERM;
804 goto free_out;
805 }
806 err = bind_request(s, &buf->bind_info);
807 break;
808 case DS_GET_DEVICE_INFO:
809 err = get_device_info(s, &buf->bind_info, 1);
810 break;
811 case DS_GET_NEXT_DEVICE:
812 err = get_device_info(s, &buf->bind_info, 0);
813 break;
814 case DS_UNBIND_REQUEST:
815 err = 0;
816 break;
817 default:
818 err = -EINVAL;
819 }
820
821 if ((err == 0) && (ret != CS_SUCCESS)) {
822 ds_dbg(2, "ds_ioctl: ret = %d\n", ret);
823 switch (ret) {
824 case CS_BAD_SOCKET: case CS_NO_CARD:
825 err = -ENODEV; break;
826 case CS_BAD_ARGS: case CS_BAD_ATTRIBUTE: case CS_BAD_IRQ:
827 case CS_BAD_TUPLE:
828 err = -EINVAL; break;
829 case CS_IN_USE:
830 err = -EBUSY; break;
831 case CS_OUT_OF_RESOURCE:
832 err = -ENOSPC; break;
833 case CS_NO_MORE_ITEMS:
834 err = -ENODATA; break;
835 case CS_UNSUPPORTED_FUNCTION:
836 err = -ENOSYS; break;
837 default:
838 err = -EIO; break;
839 }
840 }
841
842 if (cmd & IOC_OUT) {
843 if (__copy_to_user(uarg, (char *)buf, size))
844 err = -EFAULT;
845 }
846
847free_out:
848 kfree(buf);
849 return err;
850} /* ds_ioctl */
851
852/*====================================================================*/
853
Arjan van de Vend54b1fd2007-02-12 00:55:34 -0800854static const struct file_operations ds_fops = {
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700855 .owner = THIS_MODULE,
856 .open = ds_open,
857 .release = ds_release,
858 .ioctl = ds_ioctl,
859 .read = ds_read,
860 .write = ds_write,
861 .poll = ds_poll,
862};
863
864void __init pcmcia_setup_ioctl(void) {
865 int i;
866
867 /* Set up character device for user mode clients */
868 i = register_chrdev(0, "pcmcia", &ds_fops);
Dominik Brodowski1a8ceaf2005-06-27 16:29:00 -0700869 if (i < 0)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700870 printk(KERN_NOTICE "unable to find a free device # for "
Dominik Brodowski1a8ceaf2005-06-27 16:29:00 -0700871 "Driver Services (error=%d)\n", i);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700872 else
873 major_dev = i;
874
875#ifdef CONFIG_PROC_FS
akpm@linux-foundation.org97094dc2008-04-29 10:47:54 -0700876 proc_pccard = proc_mkdir("bus/pccard", NULL);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700877 if (proc_pccard)
878 create_proc_read_entry("drivers",0,proc_pccard,proc_read_drivers,NULL);
879#endif
880}
881
882
883void __exit pcmcia_cleanup_ioctl(void) {
884#ifdef CONFIG_PROC_FS
885 if (proc_pccard) {
886 remove_proc_entry("drivers", proc_pccard);
akpm@linux-foundation.org97094dc2008-04-29 10:47:54 -0700887 remove_proc_entry("bus/pccard", NULL);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700888 }
889#endif
890 if (major_dev != -1)
891 unregister_chrdev(major_dev, "pcmcia");
892}