blob: afd00e7bbbefe92f53cbfd82cc52ea8f323357e8 [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
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070032#include <pcmcia/cs_types.h>
33#include <pcmcia/cs.h>
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070034#include <pcmcia/cistpl.h>
Dominik Brodowski4aeba012008-06-20 13:24:31 +020035#include <pcmcia/cisreg.h>
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070036#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
Dominik Brodowski4aeba012008-06-20 13:24:31 +0200228/** pccard_get_status
229 *
230 * Get the current socket state bits. We don't support the latched
231 * SocketState yet: I haven't seen any point for it.
232 */
233
234static int pccard_get_status(struct pcmcia_socket *s,
235 struct pcmcia_device *p_dev,
236 cs_status_t *status)
237{
238 config_t *c;
239 int val;
240
241 s->ops->get_status(s, &val);
242 status->CardState = status->SocketState = 0;
243 status->CardState |= (val & SS_DETECT) ? CS_EVENT_CARD_DETECT : 0;
244 status->CardState |= (val & SS_CARDBUS) ? CS_EVENT_CB_DETECT : 0;
245 status->CardState |= (val & SS_3VCARD) ? CS_EVENT_3VCARD : 0;
246 status->CardState |= (val & SS_XVCARD) ? CS_EVENT_XVCARD : 0;
247 if (s->state & SOCKET_SUSPEND)
248 status->CardState |= CS_EVENT_PM_SUSPEND;
249 if (!(s->state & SOCKET_PRESENT))
250 return CS_NO_CARD;
251
252 c = (p_dev) ? p_dev->function_config : NULL;
253
254 if ((c != NULL) && (c->state & CONFIG_LOCKED) &&
255 (c->IntType & (INT_MEMORY_AND_IO | INT_ZOOMED_VIDEO))) {
256 u_char reg;
257 if (c->CardValues & PRESENT_PIN_REPLACE) {
258 pcmcia_read_cis_mem(s, 1, (c->ConfigBase+CISREG_PRR)>>1, 1, &reg);
259 status->CardState |=
260 (reg & PRR_WP_STATUS) ? CS_EVENT_WRITE_PROTECT : 0;
261 status->CardState |=
262 (reg & PRR_READY_STATUS) ? CS_EVENT_READY_CHANGE : 0;
263 status->CardState |=
264 (reg & PRR_BVD2_STATUS) ? CS_EVENT_BATTERY_LOW : 0;
265 status->CardState |=
266 (reg & PRR_BVD1_STATUS) ? CS_EVENT_BATTERY_DEAD : 0;
267 } else {
268 /* No PRR? Then assume we're always ready */
269 status->CardState |= CS_EVENT_READY_CHANGE;
270 }
271 if (c->CardValues & PRESENT_EXT_STATUS) {
272 pcmcia_read_cis_mem(s, 1, (c->ConfigBase+CISREG_ESR)>>1, 1, &reg);
273 status->CardState |=
274 (reg & ESR_REQ_ATTN) ? CS_EVENT_REQUEST_ATTENTION : 0;
275 }
276 return CS_SUCCESS;
277 }
278 status->CardState |=
279 (val & SS_WRPROT) ? CS_EVENT_WRITE_PROTECT : 0;
280 status->CardState |=
281 (val & SS_BATDEAD) ? CS_EVENT_BATTERY_DEAD : 0;
282 status->CardState |=
283 (val & SS_BATWARN) ? CS_EVENT_BATTERY_LOW : 0;
284 status->CardState |=
285 (val & SS_READY) ? CS_EVENT_READY_CHANGE : 0;
286 return CS_SUCCESS;
287} /* pccard_get_status */
Dominik Brodowskic5023802008-06-19 19:02:52 +0200288
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700289/*======================================================================
290
291 These manage a ring buffer of events pending for one user process
292
293======================================================================*/
294
295
296static int queue_empty(user_info_t *user)
297{
298 return (user->event_head == user->event_tail);
299}
300
301static event_t get_queued_event(user_info_t *user)
302{
303 user->event_tail = (user->event_tail+1) % MAX_EVENTS;
304 return user->event[user->event_tail];
305}
306
307static void queue_event(user_info_t *user, event_t event)
308{
309 user->event_head = (user->event_head+1) % MAX_EVENTS;
310 if (user->event_head == user->event_tail)
311 user->event_tail = (user->event_tail+1) % MAX_EVENTS;
312 user->event[user->event_head] = event;
313}
314
Dominik Brodowskidc109492005-06-27 16:28:50 -0700315void handle_event(struct pcmcia_socket *s, event_t event)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700316{
317 user_info_t *user;
318 for (user = s->user; user; user = user->next)
319 queue_event(user, event);
320 wake_up_interruptible(&s->queue);
321}
322
323
324/*======================================================================
325
326 bind_request() and bind_device() are merged by now. Register_client()
327 is called right at the end of bind_request(), during the driver's
328 ->attach() call. Individual descriptions:
329
330 bind_request() connects a socket to a particular client driver.
331 It looks up the specified device ID in the list of registered
332 drivers, binds it to the socket, and tries to create an instance
333 of the device. unbind_request() deletes a driver instance.
334
335 Bind_device() associates a device driver with a particular socket.
336 It is normally called by Driver Services after it has identified
337 a newly inserted card. An instance of that driver will then be
338 eligible to register as a client of this socket.
339
340 Register_client() uses the dev_info_t handle to match the
341 caller with a socket. The driver must have already been bound
342 to a socket with bind_device() -- in fact, bind_device()
343 allocates the client structure that will be used.
344
345======================================================================*/
346
Dominik Brodowskidc109492005-06-27 16:28:50 -0700347static int bind_request(struct pcmcia_socket *s, bind_info_t *bind_info)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700348{
349 struct pcmcia_driver *p_drv;
350 struct pcmcia_device *p_dev;
351 int ret = 0;
352 unsigned long flags;
353
Dominik Brodowskidc109492005-06-27 16:28:50 -0700354 s = pcmcia_get_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700355 if (!s)
356 return -EINVAL;
357
Dominik Brodowskidc109492005-06-27 16:28:50 -0700358 ds_dbg(2, "bind_request(%d, '%s')\n", s->sock,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700359 (char *)bind_info->dev_info);
360
361 p_drv = get_pcmcia_driver(&bind_info->dev_info);
362 if (!p_drv) {
363 ret = -EINVAL;
364 goto err_put;
365 }
366
367 if (!try_module_get(p_drv->owner)) {
368 ret = -EINVAL;
369 goto err_put_driver;
370 }
371
372 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
373 list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
374 if (p_dev->func == bind_info->function) {
375 if ((p_dev->dev.driver == &p_drv->drv)) {
376 if (p_dev->cardmgr) {
377 /* if there's already a device
378 * registered, and it was registered
379 * by userspace before, we need to
380 * return the "instance". */
381 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
Dominik Brodowskifd238232006-03-05 10:45:09 +0100382 bind_info->instance = p_dev;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700383 ret = -EBUSY;
384 goto err_put_module;
385 } else {
386 /* the correct driver managed to bind
387 * itself magically to the correct
388 * device. */
389 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
390 p_dev->cardmgr = p_drv;
391 ret = 0;
392 goto err_put_module;
393 }
394 } else if (!p_dev->dev.driver) {
395 /* there's already a device available where
396 * no device has been bound to yet. So we don't
397 * need to register a device! */
398 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
399 goto rescan;
400 }
401 }
402 }
403 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
404
405 p_dev = pcmcia_device_add(s, bind_info->function);
406 if (!p_dev) {
407 ret = -EIO;
408 goto err_put_module;
409 }
410
411rescan:
412 p_dev->cardmgr = p_drv;
413
414 /* if a driver is already running, we can abort */
415 if (p_dev->dev.driver)
416 goto err_put_module;
417
418 /*
419 * Prevent this racing with a card insertion.
420 */
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100421 mutex_lock(&s->skt_mutex);
Jeff Garzik4deb7c12006-10-20 14:44:23 -0700422 ret = bus_rescan_devices(&pcmcia_bus_type);
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100423 mutex_unlock(&s->skt_mutex);
Jeff Garzik4deb7c12006-10-20 14:44:23 -0700424 if (ret)
425 goto err_put_module;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700426
427 /* check whether the driver indeed matched. I don't care if this
428 * is racy or not, because it can only happen on cardmgr access
429 * paths...
430 */
431 if (!(p_dev->dev.driver == &p_drv->drv))
432 p_dev->cardmgr = NULL;
433
434 err_put_module:
435 module_put(p_drv->owner);
436 err_put_driver:
437 put_driver(&p_drv->drv);
438 err_put:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700439 pcmcia_put_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700440
441 return (ret);
442} /* bind_request */
443
Dominik Brodowski33519dd2005-06-27 16:28:53 -0700444#ifdef CONFIG_CARDBUS
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700445
Dominik Brodowski33519dd2005-06-27 16:28:53 -0700446static struct pci_bus *pcmcia_lookup_bus(struct pcmcia_socket *s)
447{
448 if (!s || !(s->state & SOCKET_CARDBUS))
449 return NULL;
450
451 return s->cb_dev->subordinate;
452}
453#endif
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700454
Dominik Brodowskidc109492005-06-27 16:28:50 -0700455static int get_device_info(struct pcmcia_socket *s, bind_info_t *bind_info, int first)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700456{
457 dev_node_t *node;
458 struct pcmcia_device *p_dev;
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100459 struct pcmcia_driver *p_drv;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700460 unsigned long flags;
461 int ret = 0;
462
463#ifdef CONFIG_CARDBUS
464 /*
465 * Some unbelievably ugly code to associate the PCI cardbus
466 * device and its driver with the PCMCIA "bind" information.
467 */
468 {
469 struct pci_bus *bus;
470
Dominik Brodowskidc109492005-06-27 16:28:50 -0700471 bus = pcmcia_lookup_bus(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700472 if (bus) {
473 struct list_head *list;
474 struct pci_dev *dev = NULL;
475
476 list = bus->devices.next;
477 while (list != &bus->devices) {
478 struct pci_dev *pdev = pci_dev_b(list);
479 list = list->next;
480
481 if (first) {
482 dev = pdev;
483 break;
484 }
485
486 /* Try to handle "next" here some way? */
487 }
488 if (dev && dev->driver) {
489 strlcpy(bind_info->name, dev->driver->name, DEV_NAME_LEN);
490 bind_info->major = 0;
491 bind_info->minor = 0;
492 bind_info->next = NULL;
493 return 0;
494 }
495 }
496 }
497#endif
498
499 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
500 list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
501 if (p_dev->func == bind_info->function) {
502 p_dev = pcmcia_get_dev(p_dev);
503 if (!p_dev)
504 continue;
505 goto found;
506 }
507 }
508 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
509 return -ENODEV;
510
511 found:
512 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
513
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100514 p_drv = to_pcmcia_drv(p_dev->dev.driver);
515 if (p_drv && !p_dev->_locked) {
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700516 ret = -EAGAIN;
517 goto err_put;
518 }
519
520 if (first)
Dominik Brodowskifd238232006-03-05 10:45:09 +0100521 node = p_dev->dev_node;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700522 else
Dominik Brodowskifd238232006-03-05 10:45:09 +0100523 for (node = p_dev->dev_node; node; node = node->next)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700524 if (node == bind_info->next)
525 break;
526 if (!node) {
527 ret = -ENODEV;
528 goto err_put;
529 }
530
531 strlcpy(bind_info->name, node->dev_name, DEV_NAME_LEN);
532 bind_info->major = node->major;
533 bind_info->minor = node->minor;
534 bind_info->next = node->next;
535
536 err_put:
537 pcmcia_put_dev(p_dev);
538 return (ret);
539} /* get_device_info */
540
541
542static int ds_open(struct inode *inode, struct file *file)
543{
544 socket_t i = iminor(inode);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700545 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700546 user_info_t *user;
Dominik Brodowskic352ec82005-09-13 01:25:03 -0700547 static int warning_printed = 0;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700548
549 ds_dbg(0, "ds_open(socket %d)\n", i);
550
Dominik Brodowskidc109492005-06-27 16:28:50 -0700551 s = pcmcia_get_socket_by_nr(i);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700552 if (!s)
553 return -ENODEV;
Dominik Brodowskidc109492005-06-27 16:28:50 -0700554 s = pcmcia_get_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700555 if (!s)
556 return -ENODEV;
557
558 if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700559 if (s->pcmcia_state.busy) {
Dominik Brodowskidc109492005-06-27 16:28:50 -0700560 pcmcia_put_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700561 return -EBUSY;
562 }
563 else
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700564 s->pcmcia_state.busy = 1;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700565 }
566
567 user = kmalloc(sizeof(user_info_t), GFP_KERNEL);
568 if (!user) {
Dominik Brodowskidc109492005-06-27 16:28:50 -0700569 pcmcia_put_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700570 return -ENOMEM;
571 }
572 user->event_tail = user->event_head = 0;
573 user->next = s->user;
574 user->user_magic = USER_MAGIC;
575 user->socket = s;
576 s->user = user;
577 file->private_data = user;
578
Dominik Brodowskic352ec82005-09-13 01:25:03 -0700579 if (!warning_printed) {
580 printk(KERN_INFO "pcmcia: Detected deprecated PCMCIA ioctl "
Benjamin Herrenschmidt73d58582006-05-15 09:43:53 -0700581 "usage from process: %s.\n", current->comm);
Dominik Brodowskic352ec82005-09-13 01:25:03 -0700582 printk(KERN_INFO "pcmcia: This interface will soon be removed from "
583 "the kernel; please expect breakage unless you upgrade "
584 "to new tools.\n");
585 printk(KERN_INFO "pcmcia: see http://www.kernel.org/pub/linux/"
586 "utils/kernel/pcmcia/pcmcia.html for details.\n");
587 warning_printed = 1;
588 }
589
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700590 if (s->pcmcia_state.present)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700591 queue_event(user, CS_EVENT_CARD_INSERTION);
592 return 0;
593} /* ds_open */
594
595/*====================================================================*/
596
597static int ds_release(struct inode *inode, struct file *file)
598{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700599 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700600 user_info_t *user, **link;
601
602 ds_dbg(0, "ds_release(socket %d)\n", iminor(inode));
603
604 user = file->private_data;
605 if (CHECK_USER(user))
606 goto out;
607
608 s = user->socket;
609
610 /* Unlink user data structure */
611 if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700612 s->pcmcia_state.busy = 0;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700613 }
614 file->private_data = NULL;
615 for (link = &s->user; *link; link = &(*link)->next)
616 if (*link == user) break;
617 if (link == NULL)
618 goto out;
619 *link = user->next;
620 user->user_magic = 0;
621 kfree(user);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700622 pcmcia_put_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700623out:
624 return 0;
625} /* ds_release */
626
627/*====================================================================*/
628
629static ssize_t ds_read(struct file *file, char __user *buf,
630 size_t count, loff_t *ppos)
631{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700632 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700633 user_info_t *user;
634 int ret;
635
Josef Sipek40fad042006-12-08 02:37:29 -0800636 ds_dbg(2, "ds_read(socket %d)\n", iminor(file->f_path.dentry->d_inode));
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700637
638 if (count < 4)
639 return -EINVAL;
640
641 user = file->private_data;
642 if (CHECK_USER(user))
643 return -EIO;
644
645 s = user->socket;
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700646 if (s->pcmcia_state.dead)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700647 return -EIO;
648
649 ret = wait_event_interruptible(s->queue, !queue_empty(user));
650 if (ret == 0)
651 ret = put_user(get_queued_event(user), (int __user *)buf) ? -EFAULT : 4;
652
653 return ret;
654} /* ds_read */
655
656/*====================================================================*/
657
658static ssize_t ds_write(struct file *file, const char __user *buf,
659 size_t count, loff_t *ppos)
660{
Josef Sipek40fad042006-12-08 02:37:29 -0800661 ds_dbg(2, "ds_write(socket %d)\n", iminor(file->f_path.dentry->d_inode));
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700662
663 if (count != 4)
664 return -EINVAL;
665 if ((file->f_flags & O_ACCMODE) == O_RDONLY)
666 return -EBADF;
667
668 return -EIO;
669} /* ds_write */
670
671/*====================================================================*/
672
673/* No kernel lock - fine */
674static u_int ds_poll(struct file *file, poll_table *wait)
675{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700676 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700677 user_info_t *user;
678
Josef Sipek40fad042006-12-08 02:37:29 -0800679 ds_dbg(2, "ds_poll(socket %d)\n", iminor(file->f_path.dentry->d_inode));
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700680
681 user = file->private_data;
682 if (CHECK_USER(user))
683 return POLLERR;
684 s = user->socket;
685 /*
686 * We don't check for a dead socket here since that
687 * will send cardmgr into an endless spin.
688 */
689 poll_wait(file, &s->queue, wait);
690 if (!queue_empty(user))
691 return POLLIN | POLLRDNORM;
692 return 0;
693} /* ds_poll */
694
695/*====================================================================*/
696
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700697static int ds_ioctl(struct inode * inode, struct file * file,
698 u_int cmd, u_long arg)
699{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700700 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700701 void __user *uarg = (char __user *)arg;
702 u_int size;
703 int ret, err;
704 ds_ioctl_arg_t *buf;
705 user_info_t *user;
706
707 ds_dbg(2, "ds_ioctl(socket %d, %#x, %#lx)\n", iminor(inode), cmd, arg);
708
709 user = file->private_data;
710 if (CHECK_USER(user))
711 return -EIO;
712
713 s = user->socket;
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700714 if (s->pcmcia_state.dead)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700715 return -EIO;
716
717 size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
718 if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL;
719
720 /* Permission check */
721 if (!(cmd & IOC_OUT) && !capable(CAP_SYS_ADMIN))
722 return -EPERM;
723
724 if (cmd & IOC_IN) {
725 if (!access_ok(VERIFY_READ, uarg, size)) {
726 ds_dbg(3, "ds_ioctl(): verify_read = %d\n", -EFAULT);
727 return -EFAULT;
728 }
729 }
730 if (cmd & IOC_OUT) {
731 if (!access_ok(VERIFY_WRITE, uarg, size)) {
732 ds_dbg(3, "ds_ioctl(): verify_write = %d\n", -EFAULT);
733 return -EFAULT;
734 }
735 }
736 buf = kmalloc(sizeof(ds_ioctl_arg_t), GFP_KERNEL);
737 if (!buf)
738 return -ENOMEM;
739
740 err = ret = 0;
741
Dominik Brodowski93740742006-11-19 11:21:27 -0500742 if (cmd & IOC_IN) {
743 if (__copy_from_user((char *)buf, uarg, size)) {
744 err = -EFAULT;
745 goto free_out;
746 }
747 }
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700748
749 switch (cmd) {
750 case DS_ADJUST_RESOURCE_INFO:
751 ret = pcmcia_adjust_resource_info(&buf->adjust);
752 break;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700753 case DS_GET_CONFIGURATION_INFO:
754 if (buf->config.Function &&
Dominik Brodowskidc109492005-06-27 16:28:50 -0700755 (buf->config.Function >= s->functions))
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700756 ret = CS_BAD_ARGS;
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100757 else {
758 struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->config.Function);
Daniel Ritzf47ad212006-07-30 03:03:47 -0700759 ret = pccard_get_configuration_info(s, p_dev, &buf->config);
760 pcmcia_put_dev(p_dev);
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100761 }
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700762 break;
763 case DS_GET_FIRST_TUPLE:
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100764 mutex_lock(&s->skt_mutex);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700765 pcmcia_validate_mem(s);
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100766 mutex_unlock(&s->skt_mutex);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700767 ret = pccard_get_first_tuple(s, BIND_FN_ALL, &buf->tuple);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700768 break;
769 case DS_GET_NEXT_TUPLE:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700770 ret = pccard_get_next_tuple(s, BIND_FN_ALL, &buf->tuple);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700771 break;
772 case DS_GET_TUPLE_DATA:
773 buf->tuple.TupleData = buf->tuple_parse.data;
774 buf->tuple.TupleDataMax = sizeof(buf->tuple_parse.data);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700775 ret = pccard_get_tuple_data(s, &buf->tuple);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700776 break;
777 case DS_PARSE_TUPLE:
778 buf->tuple.TupleData = buf->tuple_parse.data;
779 ret = pccard_parse_tuple(&buf->tuple, &buf->tuple_parse.parse);
780 break;
781 case DS_RESET_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700782 ret = pccard_reset_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700783 break;
784 case DS_GET_STATUS:
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100785 if (buf->status.Function &&
786 (buf->status.Function >= s->functions))
787 ret = CS_BAD_ARGS;
788 else {
789 struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->status.Function);
Daniel Ritzf47ad212006-07-30 03:03:47 -0700790 ret = pccard_get_status(s, p_dev, &buf->status);
791 pcmcia_put_dev(p_dev);
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100792 }
793 break;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700794 case DS_VALIDATE_CIS:
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100795 mutex_lock(&s->skt_mutex);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700796 pcmcia_validate_mem(s);
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100797 mutex_unlock(&s->skt_mutex);
Dominik Brodowskic5081d52008-06-19 20:12:34 +0200798 ret = pccard_validate_cis(s, BIND_FN_ALL, &buf->cisinfo.Chains);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700799 break;
800 case DS_SUSPEND_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700801 ret = pcmcia_suspend_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700802 break;
803 case DS_RESUME_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700804 ret = pcmcia_resume_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700805 break;
806 case DS_EJECT_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700807 err = pcmcia_eject_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700808 break;
809 case DS_INSERT_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700810 err = pcmcia_insert_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700811 break;
812 case DS_ACCESS_CONFIGURATION_REGISTER:
813 if ((buf->conf_reg.Action == CS_WRITE) && !capable(CAP_SYS_ADMIN)) {
814 err = -EPERM;
815 goto free_out;
816 }
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100817
818 ret = CS_BAD_ARGS;
819
820 if (!(buf->conf_reg.Function &&
821 (buf->conf_reg.Function >= s->functions))) {
822 struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->conf_reg.Function);
Benjamin Herrenschmidt73d58582006-05-15 09:43:53 -0700823 if (p_dev) {
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100824 ret = pcmcia_access_configuration_register(p_dev, &buf->conf_reg);
Benjamin Herrenschmidt73d58582006-05-15 09:43:53 -0700825 pcmcia_put_dev(p_dev);
826 }
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100827 }
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700828 break;
829 case DS_GET_FIRST_REGION:
830 case DS_GET_NEXT_REGION:
831 case DS_BIND_MTD:
832 if (!capable(CAP_SYS_ADMIN)) {
833 err = -EPERM;
834 goto free_out;
835 } else {
836 static int printed = 0;
837 if (!printed) {
838 printk(KERN_WARNING "2.6. kernels use pcmciamtd instead of memory_cs.c and do not require special\n");
839 printk(KERN_WARNING "MTD handling any more.\n");
840 printed++;
841 }
842 }
843 err = -EINVAL;
844 goto free_out;
845 break;
846 case DS_GET_FIRST_WINDOW:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700847 ret = pcmcia_get_window(s, &buf->win_info.handle, 0,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700848 &buf->win_info.window);
849 break;
850 case DS_GET_NEXT_WINDOW:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700851 ret = pcmcia_get_window(s, &buf->win_info.handle,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700852 buf->win_info.handle->index + 1, &buf->win_info.window);
853 break;
854 case DS_GET_MEM_PAGE:
855 ret = pcmcia_get_mem_page(buf->win_info.handle,
856 &buf->win_info.map);
857 break;
858 case DS_REPLACE_CIS:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700859 ret = pcmcia_replace_cis(s, &buf->cisdump);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700860 break;
861 case DS_BIND_REQUEST:
862 if (!capable(CAP_SYS_ADMIN)) {
863 err = -EPERM;
864 goto free_out;
865 }
866 err = bind_request(s, &buf->bind_info);
867 break;
868 case DS_GET_DEVICE_INFO:
869 err = get_device_info(s, &buf->bind_info, 1);
870 break;
871 case DS_GET_NEXT_DEVICE:
872 err = get_device_info(s, &buf->bind_info, 0);
873 break;
874 case DS_UNBIND_REQUEST:
875 err = 0;
876 break;
877 default:
878 err = -EINVAL;
879 }
880
881 if ((err == 0) && (ret != CS_SUCCESS)) {
882 ds_dbg(2, "ds_ioctl: ret = %d\n", ret);
883 switch (ret) {
884 case CS_BAD_SOCKET: case CS_NO_CARD:
885 err = -ENODEV; break;
886 case CS_BAD_ARGS: case CS_BAD_ATTRIBUTE: case CS_BAD_IRQ:
887 case CS_BAD_TUPLE:
888 err = -EINVAL; break;
889 case CS_IN_USE:
890 err = -EBUSY; break;
891 case CS_OUT_OF_RESOURCE:
892 err = -ENOSPC; break;
893 case CS_NO_MORE_ITEMS:
894 err = -ENODATA; break;
895 case CS_UNSUPPORTED_FUNCTION:
896 err = -ENOSYS; break;
897 default:
898 err = -EIO; break;
899 }
900 }
901
902 if (cmd & IOC_OUT) {
903 if (__copy_to_user(uarg, (char *)buf, size))
904 err = -EFAULT;
905 }
906
907free_out:
908 kfree(buf);
909 return err;
910} /* ds_ioctl */
911
912/*====================================================================*/
913
Arjan van de Vend54b1fd2007-02-12 00:55:34 -0800914static const struct file_operations ds_fops = {
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700915 .owner = THIS_MODULE,
916 .open = ds_open,
917 .release = ds_release,
918 .ioctl = ds_ioctl,
919 .read = ds_read,
920 .write = ds_write,
921 .poll = ds_poll,
922};
923
924void __init pcmcia_setup_ioctl(void) {
925 int i;
926
927 /* Set up character device for user mode clients */
928 i = register_chrdev(0, "pcmcia", &ds_fops);
Dominik Brodowski1a8ceaf2005-06-27 16:29:00 -0700929 if (i < 0)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700930 printk(KERN_NOTICE "unable to find a free device # for "
Dominik Brodowski1a8ceaf2005-06-27 16:29:00 -0700931 "Driver Services (error=%d)\n", i);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700932 else
933 major_dev = i;
934
935#ifdef CONFIG_PROC_FS
akpm@linux-foundation.org97094dc2008-04-29 10:47:54 -0700936 proc_pccard = proc_mkdir("bus/pccard", NULL);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700937 if (proc_pccard)
938 create_proc_read_entry("drivers",0,proc_pccard,proc_read_drivers,NULL);
939#endif
940}
941
942
943void __exit pcmcia_cleanup_ioctl(void) {
944#ifdef CONFIG_PROC_FS
945 if (proc_pccard) {
946 remove_proc_entry("drivers", proc_pccard);
akpm@linux-foundation.org97094dc2008-04-29 10:47:54 -0700947 remove_proc_entry("bus/pccard", NULL);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700948 }
949#endif
950 if (major_dev != -1)
951 unregister_chrdev(major_dev, "pcmcia");
952}