blob: 579ec9455706c10a19e1308422f87ea8dde0ad66 [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>
Jonathan Corbet0bec0bb2008-05-15 09:25:03 -060030#include <linux/smp_lock.h>
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070031#include <linux/workqueue.h>
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070032
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>
Dominik Brodowski4aeba012008-06-20 13:24:31 +020036#include <pcmcia/cisreg.h>
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070037#include <pcmcia/ds.h>
38#include <pcmcia/ss.h>
39
40#include "cs_internal.h"
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070041
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
Dominik Brodowski7d16b652008-08-02 21:02:01 +020060#ifdef CONFIG_PCMCIA_DEBUG
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070061extern 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))
Dominik Brodowski69ba4432008-08-03 12:10:53 +0200151 return -EINVAL;
Dominik Brodowskic5023802008-06-19 19:02:52 +0200152
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) {
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200169 return 0;
Dominik Brodowskic5023802008-06-19 19:02:52 +0200170}
171
172#endif
173
174static int pcmcia_adjust_resource_info(adjust_t *adj)
175{
176 struct pcmcia_socket *s;
Dominik Brodowskide6405e2008-08-03 10:47:59 +0200177 int ret = -ENOSYS;
Dominik Brodowskic5023802008-06-19 19:02:52 +0200178 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))
Dominik Brodowski3939c1ef2008-08-03 11:10:56 +0200250 return -ENODEV;
Dominik Brodowski4aeba012008-06-20 13:24:31 +0200251
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 }
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200276 return 0;
Dominik Brodowski4aeba012008-06-20 13:24:31 +0200277 }
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;
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200286 return 0;
Dominik Brodowski4aeba012008-06-20 13:24:31 +0200287} /* pccard_get_status */
Dominik Brodowskic5023802008-06-19 19:02:52 +0200288
Dominik Brodowski64f34642008-08-02 17:00:46 +0200289int pccard_get_configuration_info(struct pcmcia_socket *s,
290 struct pcmcia_device *p_dev,
291 config_info_t *config)
292{
293 config_t *c;
294
295 if (!(s->state & SOCKET_PRESENT))
Dominik Brodowski3939c1ef2008-08-03 11:10:56 +0200296 return -ENODEV;
Dominik Brodowski64f34642008-08-02 17:00:46 +0200297
298
299#ifdef CONFIG_CARDBUS
300 if (s->state & SOCKET_CARDBUS) {
301 memset(config, 0, sizeof(config_info_t));
302 config->Vcc = s->socket.Vcc;
303 config->Vpp1 = config->Vpp2 = s->socket.Vpp;
304 config->Option = s->cb_dev->subordinate->number;
305 if (s->state & SOCKET_CARDBUS_CONFIG) {
306 config->Attributes = CONF_VALID_CLIENT;
307 config->IntType = INT_CARDBUS;
308 config->AssignedIRQ = s->irq.AssignedIRQ;
309 if (config->AssignedIRQ)
310 config->Attributes |= CONF_ENABLE_IRQ;
311 if (s->io[0].res) {
312 config->BasePort1 = s->io[0].res->start;
313 config->NumPorts1 = s->io[0].res->end -
314 config->BasePort1 + 1;
315 }
316 }
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200317 return 0;
Dominik Brodowski64f34642008-08-02 17:00:46 +0200318 }
319#endif
320
321 if (p_dev) {
322 c = p_dev->function_config;
323 config->Function = p_dev->func;
324 } else {
325 c = NULL;
326 config->Function = 0;
327 }
328
329 if ((c == NULL) || !(c->state & CONFIG_LOCKED)) {
330 config->Attributes = 0;
331 config->Vcc = s->socket.Vcc;
332 config->Vpp1 = config->Vpp2 = s->socket.Vpp;
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200333 return 0;
Dominik Brodowski64f34642008-08-02 17:00:46 +0200334 }
335
336 config->Attributes = c->Attributes | CONF_VALID_CLIENT;
337 config->Vcc = s->socket.Vcc;
338 config->Vpp1 = config->Vpp2 = s->socket.Vpp;
339 config->IntType = c->IntType;
340 config->ConfigBase = c->ConfigBase;
341 config->Status = c->Status;
342 config->Pin = c->Pin;
343 config->Copy = c->Copy;
344 config->Option = c->Option;
345 config->ExtStatus = c->ExtStatus;
346 config->Present = config->CardValues = c->CardValues;
347 config->IRQAttributes = c->irq.Attributes;
348 config->AssignedIRQ = s->irq.AssignedIRQ;
349 config->BasePort1 = c->io.BasePort1;
350 config->NumPorts1 = c->io.NumPorts1;
351 config->Attributes1 = c->io.Attributes1;
352 config->BasePort2 = c->io.BasePort2;
353 config->NumPorts2 = c->io.NumPorts2;
354 config->Attributes2 = c->io.Attributes2;
355 config->IOAddrLines = c->io.IOAddrLines;
356
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200357 return 0;
Dominik Brodowski64f34642008-08-02 17:00:46 +0200358} /* pccard_get_configuration_info */
359
360
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700361/*======================================================================
362
363 These manage a ring buffer of events pending for one user process
364
365======================================================================*/
366
367
368static int queue_empty(user_info_t *user)
369{
370 return (user->event_head == user->event_tail);
371}
372
373static event_t get_queued_event(user_info_t *user)
374{
375 user->event_tail = (user->event_tail+1) % MAX_EVENTS;
376 return user->event[user->event_tail];
377}
378
379static void queue_event(user_info_t *user, event_t event)
380{
381 user->event_head = (user->event_head+1) % MAX_EVENTS;
382 if (user->event_head == user->event_tail)
383 user->event_tail = (user->event_tail+1) % MAX_EVENTS;
384 user->event[user->event_head] = event;
385}
386
Dominik Brodowskidc109492005-06-27 16:28:50 -0700387void handle_event(struct pcmcia_socket *s, event_t event)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700388{
389 user_info_t *user;
390 for (user = s->user; user; user = user->next)
391 queue_event(user, event);
392 wake_up_interruptible(&s->queue);
393}
394
395
396/*======================================================================
397
398 bind_request() and bind_device() are merged by now. Register_client()
399 is called right at the end of bind_request(), during the driver's
400 ->attach() call. Individual descriptions:
401
402 bind_request() connects a socket to a particular client driver.
403 It looks up the specified device ID in the list of registered
404 drivers, binds it to the socket, and tries to create an instance
405 of the device. unbind_request() deletes a driver instance.
406
407 Bind_device() associates a device driver with a particular socket.
408 It is normally called by Driver Services after it has identified
409 a newly inserted card. An instance of that driver will then be
410 eligible to register as a client of this socket.
411
412 Register_client() uses the dev_info_t handle to match the
413 caller with a socket. The driver must have already been bound
414 to a socket with bind_device() -- in fact, bind_device()
415 allocates the client structure that will be used.
416
417======================================================================*/
418
Dominik Brodowskidc109492005-06-27 16:28:50 -0700419static int bind_request(struct pcmcia_socket *s, bind_info_t *bind_info)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700420{
421 struct pcmcia_driver *p_drv;
422 struct pcmcia_device *p_dev;
423 int ret = 0;
424 unsigned long flags;
425
Dominik Brodowskidc109492005-06-27 16:28:50 -0700426 s = pcmcia_get_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700427 if (!s)
428 return -EINVAL;
429
Dominik Brodowskidc109492005-06-27 16:28:50 -0700430 ds_dbg(2, "bind_request(%d, '%s')\n", s->sock,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700431 (char *)bind_info->dev_info);
432
433 p_drv = get_pcmcia_driver(&bind_info->dev_info);
434 if (!p_drv) {
435 ret = -EINVAL;
436 goto err_put;
437 }
438
439 if (!try_module_get(p_drv->owner)) {
440 ret = -EINVAL;
441 goto err_put_driver;
442 }
443
444 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
445 list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
446 if (p_dev->func == bind_info->function) {
447 if ((p_dev->dev.driver == &p_drv->drv)) {
448 if (p_dev->cardmgr) {
449 /* if there's already a device
450 * registered, and it was registered
451 * by userspace before, we need to
452 * return the "instance". */
453 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
Dominik Brodowskifd238232006-03-05 10:45:09 +0100454 bind_info->instance = p_dev;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700455 ret = -EBUSY;
456 goto err_put_module;
457 } else {
458 /* the correct driver managed to bind
459 * itself magically to the correct
460 * device. */
461 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
462 p_dev->cardmgr = p_drv;
463 ret = 0;
464 goto err_put_module;
465 }
466 } else if (!p_dev->dev.driver) {
467 /* there's already a device available where
468 * no device has been bound to yet. So we don't
469 * need to register a device! */
470 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
471 goto rescan;
472 }
473 }
474 }
475 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
476
477 p_dev = pcmcia_device_add(s, bind_info->function);
478 if (!p_dev) {
479 ret = -EIO;
480 goto err_put_module;
481 }
482
483rescan:
484 p_dev->cardmgr = p_drv;
485
486 /* if a driver is already running, we can abort */
487 if (p_dev->dev.driver)
488 goto err_put_module;
489
490 /*
491 * Prevent this racing with a card insertion.
492 */
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100493 mutex_lock(&s->skt_mutex);
Jeff Garzik4deb7c12006-10-20 14:44:23 -0700494 ret = bus_rescan_devices(&pcmcia_bus_type);
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100495 mutex_unlock(&s->skt_mutex);
Jeff Garzik4deb7c12006-10-20 14:44:23 -0700496 if (ret)
497 goto err_put_module;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700498
499 /* check whether the driver indeed matched. I don't care if this
500 * is racy or not, because it can only happen on cardmgr access
501 * paths...
502 */
503 if (!(p_dev->dev.driver == &p_drv->drv))
504 p_dev->cardmgr = NULL;
505
506 err_put_module:
507 module_put(p_drv->owner);
508 err_put_driver:
509 put_driver(&p_drv->drv);
510 err_put:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700511 pcmcia_put_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700512
513 return (ret);
514} /* bind_request */
515
Dominik Brodowski33519dd2005-06-27 16:28:53 -0700516#ifdef CONFIG_CARDBUS
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700517
Dominik Brodowski33519dd2005-06-27 16:28:53 -0700518static struct pci_bus *pcmcia_lookup_bus(struct pcmcia_socket *s)
519{
520 if (!s || !(s->state & SOCKET_CARDBUS))
521 return NULL;
522
523 return s->cb_dev->subordinate;
524}
525#endif
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700526
Dominik Brodowskidc109492005-06-27 16:28:50 -0700527static int get_device_info(struct pcmcia_socket *s, bind_info_t *bind_info, int first)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700528{
529 dev_node_t *node;
530 struct pcmcia_device *p_dev;
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100531 struct pcmcia_driver *p_drv;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700532 unsigned long flags;
533 int ret = 0;
534
535#ifdef CONFIG_CARDBUS
536 /*
537 * Some unbelievably ugly code to associate the PCI cardbus
538 * device and its driver with the PCMCIA "bind" information.
539 */
540 {
541 struct pci_bus *bus;
542
Dominik Brodowskidc109492005-06-27 16:28:50 -0700543 bus = pcmcia_lookup_bus(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700544 if (bus) {
545 struct list_head *list;
546 struct pci_dev *dev = NULL;
547
548 list = bus->devices.next;
549 while (list != &bus->devices) {
550 struct pci_dev *pdev = pci_dev_b(list);
551 list = list->next;
552
553 if (first) {
554 dev = pdev;
555 break;
556 }
557
558 /* Try to handle "next" here some way? */
559 }
560 if (dev && dev->driver) {
561 strlcpy(bind_info->name, dev->driver->name, DEV_NAME_LEN);
562 bind_info->major = 0;
563 bind_info->minor = 0;
564 bind_info->next = NULL;
565 return 0;
566 }
567 }
568 }
569#endif
570
571 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
572 list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
573 if (p_dev->func == bind_info->function) {
574 p_dev = pcmcia_get_dev(p_dev);
575 if (!p_dev)
576 continue;
577 goto found;
578 }
579 }
580 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
581 return -ENODEV;
582
583 found:
584 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
585
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100586 p_drv = to_pcmcia_drv(p_dev->dev.driver);
587 if (p_drv && !p_dev->_locked) {
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700588 ret = -EAGAIN;
589 goto err_put;
590 }
591
592 if (first)
Dominik Brodowskifd238232006-03-05 10:45:09 +0100593 node = p_dev->dev_node;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700594 else
Dominik Brodowskifd238232006-03-05 10:45:09 +0100595 for (node = p_dev->dev_node; node; node = node->next)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700596 if (node == bind_info->next)
597 break;
598 if (!node) {
599 ret = -ENODEV;
600 goto err_put;
601 }
602
603 strlcpy(bind_info->name, node->dev_name, DEV_NAME_LEN);
604 bind_info->major = node->major;
605 bind_info->minor = node->minor;
606 bind_info->next = node->next;
607
608 err_put:
609 pcmcia_put_dev(p_dev);
610 return (ret);
611} /* get_device_info */
612
613
614static int ds_open(struct inode *inode, struct file *file)
615{
616 socket_t i = iminor(inode);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700617 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700618 user_info_t *user;
Dominik Brodowskic352ec82005-09-13 01:25:03 -0700619 static int warning_printed = 0;
Jonathan Corbet0bec0bb2008-05-15 09:25:03 -0600620 int ret = 0;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700621
622 ds_dbg(0, "ds_open(socket %d)\n", i);
623
Jonathan Corbet0bec0bb2008-05-15 09:25:03 -0600624 lock_kernel();
Dominik Brodowskidc109492005-06-27 16:28:50 -0700625 s = pcmcia_get_socket_by_nr(i);
Jonathan Corbet0bec0bb2008-05-15 09:25:03 -0600626 if (!s) {
627 ret = -ENODEV;
628 goto out;
629 }
Dominik Brodowskidc109492005-06-27 16:28:50 -0700630 s = pcmcia_get_socket(s);
Jonathan Corbet0bec0bb2008-05-15 09:25:03 -0600631 if (!s) {
632 ret = -ENODEV;
633 goto out;
634 }
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700635
636 if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700637 if (s->pcmcia_state.busy) {
Dominik Brodowskidc109492005-06-27 16:28:50 -0700638 pcmcia_put_socket(s);
Jonathan Corbet0bec0bb2008-05-15 09:25:03 -0600639 ret = -EBUSY;
640 goto out;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700641 }
642 else
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700643 s->pcmcia_state.busy = 1;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700644 }
645
646 user = kmalloc(sizeof(user_info_t), GFP_KERNEL);
647 if (!user) {
Dominik Brodowskidc109492005-06-27 16:28:50 -0700648 pcmcia_put_socket(s);
Jonathan Corbet0bec0bb2008-05-15 09:25:03 -0600649 ret = -ENOMEM;
650 goto out;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700651 }
652 user->event_tail = user->event_head = 0;
653 user->next = s->user;
654 user->user_magic = USER_MAGIC;
655 user->socket = s;
656 s->user = user;
657 file->private_data = user;
658
Dominik Brodowskic352ec82005-09-13 01:25:03 -0700659 if (!warning_printed) {
660 printk(KERN_INFO "pcmcia: Detected deprecated PCMCIA ioctl "
Benjamin Herrenschmidt73d58582006-05-15 09:43:53 -0700661 "usage from process: %s.\n", current->comm);
Dominik Brodowskic352ec82005-09-13 01:25:03 -0700662 printk(KERN_INFO "pcmcia: This interface will soon be removed from "
663 "the kernel; please expect breakage unless you upgrade "
664 "to new tools.\n");
665 printk(KERN_INFO "pcmcia: see http://www.kernel.org/pub/linux/"
666 "utils/kernel/pcmcia/pcmcia.html for details.\n");
667 warning_printed = 1;
668 }
669
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700670 if (s->pcmcia_state.present)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700671 queue_event(user, CS_EVENT_CARD_INSERTION);
Jonathan Corbet0bec0bb2008-05-15 09:25:03 -0600672out:
673 unlock_kernel();
674 return ret;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700675} /* ds_open */
676
677/*====================================================================*/
678
679static int ds_release(struct inode *inode, struct file *file)
680{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700681 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700682 user_info_t *user, **link;
683
684 ds_dbg(0, "ds_release(socket %d)\n", iminor(inode));
685
686 user = file->private_data;
687 if (CHECK_USER(user))
688 goto out;
689
690 s = user->socket;
691
692 /* Unlink user data structure */
693 if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700694 s->pcmcia_state.busy = 0;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700695 }
696 file->private_data = NULL;
697 for (link = &s->user; *link; link = &(*link)->next)
698 if (*link == user) break;
699 if (link == NULL)
700 goto out;
701 *link = user->next;
702 user->user_magic = 0;
703 kfree(user);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700704 pcmcia_put_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700705out:
706 return 0;
707} /* ds_release */
708
709/*====================================================================*/
710
711static ssize_t ds_read(struct file *file, char __user *buf,
712 size_t count, loff_t *ppos)
713{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700714 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700715 user_info_t *user;
716 int ret;
717
Josef Sipek40fad042006-12-08 02:37:29 -0800718 ds_dbg(2, "ds_read(socket %d)\n", iminor(file->f_path.dentry->d_inode));
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700719
720 if (count < 4)
721 return -EINVAL;
722
723 user = file->private_data;
724 if (CHECK_USER(user))
725 return -EIO;
726
727 s = user->socket;
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700728 if (s->pcmcia_state.dead)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700729 return -EIO;
730
731 ret = wait_event_interruptible(s->queue, !queue_empty(user));
732 if (ret == 0)
733 ret = put_user(get_queued_event(user), (int __user *)buf) ? -EFAULT : 4;
734
735 return ret;
736} /* ds_read */
737
738/*====================================================================*/
739
740static ssize_t ds_write(struct file *file, const char __user *buf,
741 size_t count, loff_t *ppos)
742{
Josef Sipek40fad042006-12-08 02:37:29 -0800743 ds_dbg(2, "ds_write(socket %d)\n", iminor(file->f_path.dentry->d_inode));
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700744
745 if (count != 4)
746 return -EINVAL;
747 if ((file->f_flags & O_ACCMODE) == O_RDONLY)
748 return -EBADF;
749
750 return -EIO;
751} /* ds_write */
752
753/*====================================================================*/
754
755/* No kernel lock - fine */
756static u_int ds_poll(struct file *file, poll_table *wait)
757{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700758 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700759 user_info_t *user;
760
Josef Sipek40fad042006-12-08 02:37:29 -0800761 ds_dbg(2, "ds_poll(socket %d)\n", iminor(file->f_path.dentry->d_inode));
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700762
763 user = file->private_data;
764 if (CHECK_USER(user))
765 return POLLERR;
766 s = user->socket;
767 /*
768 * We don't check for a dead socket here since that
769 * will send cardmgr into an endless spin.
770 */
771 poll_wait(file, &s->queue, wait);
772 if (!queue_empty(user))
773 return POLLIN | POLLRDNORM;
774 return 0;
775} /* ds_poll */
776
777/*====================================================================*/
778
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700779static int ds_ioctl(struct inode * inode, struct file * file,
780 u_int cmd, u_long arg)
781{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700782 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700783 void __user *uarg = (char __user *)arg;
784 u_int size;
785 int ret, err;
786 ds_ioctl_arg_t *buf;
787 user_info_t *user;
788
789 ds_dbg(2, "ds_ioctl(socket %d, %#x, %#lx)\n", iminor(inode), cmd, arg);
790
791 user = file->private_data;
792 if (CHECK_USER(user))
793 return -EIO;
794
795 s = user->socket;
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700796 if (s->pcmcia_state.dead)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700797 return -EIO;
798
799 size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
800 if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL;
801
802 /* Permission check */
803 if (!(cmd & IOC_OUT) && !capable(CAP_SYS_ADMIN))
804 return -EPERM;
805
806 if (cmd & IOC_IN) {
807 if (!access_ok(VERIFY_READ, uarg, size)) {
808 ds_dbg(3, "ds_ioctl(): verify_read = %d\n", -EFAULT);
809 return -EFAULT;
810 }
811 }
812 if (cmd & IOC_OUT) {
813 if (!access_ok(VERIFY_WRITE, uarg, size)) {
814 ds_dbg(3, "ds_ioctl(): verify_write = %d\n", -EFAULT);
815 return -EFAULT;
816 }
817 }
818 buf = kmalloc(sizeof(ds_ioctl_arg_t), GFP_KERNEL);
819 if (!buf)
820 return -ENOMEM;
821
822 err = ret = 0;
823
Dominik Brodowski93740742006-11-19 11:21:27 -0500824 if (cmd & IOC_IN) {
825 if (__copy_from_user((char *)buf, uarg, size)) {
826 err = -EFAULT;
827 goto free_out;
828 }
829 }
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700830
831 switch (cmd) {
832 case DS_ADJUST_RESOURCE_INFO:
833 ret = pcmcia_adjust_resource_info(&buf->adjust);
834 break;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700835 case DS_GET_CONFIGURATION_INFO:
836 if (buf->config.Function &&
Dominik Brodowskidc109492005-06-27 16:28:50 -0700837 (buf->config.Function >= s->functions))
Dominik Brodowski926c5402008-08-03 12:15:11 +0200838 ret = -EINVAL;
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100839 else {
840 struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->config.Function);
Daniel Ritzf47ad212006-07-30 03:03:47 -0700841 ret = pccard_get_configuration_info(s, p_dev, &buf->config);
842 pcmcia_put_dev(p_dev);
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100843 }
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700844 break;
845 case DS_GET_FIRST_TUPLE:
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100846 mutex_lock(&s->skt_mutex);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700847 pcmcia_validate_mem(s);
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100848 mutex_unlock(&s->skt_mutex);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700849 ret = pccard_get_first_tuple(s, BIND_FN_ALL, &buf->tuple);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700850 break;
851 case DS_GET_NEXT_TUPLE:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700852 ret = pccard_get_next_tuple(s, BIND_FN_ALL, &buf->tuple);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700853 break;
854 case DS_GET_TUPLE_DATA:
855 buf->tuple.TupleData = buf->tuple_parse.data;
856 buf->tuple.TupleDataMax = sizeof(buf->tuple_parse.data);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700857 ret = pccard_get_tuple_data(s, &buf->tuple);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700858 break;
859 case DS_PARSE_TUPLE:
860 buf->tuple.TupleData = buf->tuple_parse.data;
861 ret = pccard_parse_tuple(&buf->tuple, &buf->tuple_parse.parse);
862 break;
863 case DS_RESET_CARD:
Dominik Brodowski994917f2008-08-31 15:20:26 +0200864 ret = pcmcia_reset_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700865 break;
866 case DS_GET_STATUS:
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100867 if (buf->status.Function &&
868 (buf->status.Function >= s->functions))
Dominik Brodowski926c5402008-08-03 12:15:11 +0200869 ret = -EINVAL;
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100870 else {
871 struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->status.Function);
Daniel Ritzf47ad212006-07-30 03:03:47 -0700872 ret = pccard_get_status(s, p_dev, &buf->status);
873 pcmcia_put_dev(p_dev);
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100874 }
875 break;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700876 case DS_VALIDATE_CIS:
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100877 mutex_lock(&s->skt_mutex);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700878 pcmcia_validate_mem(s);
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100879 mutex_unlock(&s->skt_mutex);
Dominik Brodowskic5081d52008-06-19 20:12:34 +0200880 ret = pccard_validate_cis(s, BIND_FN_ALL, &buf->cisinfo.Chains);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700881 break;
882 case DS_SUSPEND_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700883 ret = pcmcia_suspend_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700884 break;
885 case DS_RESUME_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700886 ret = pcmcia_resume_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700887 break;
888 case DS_EJECT_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700889 err = pcmcia_eject_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700890 break;
891 case DS_INSERT_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700892 err = pcmcia_insert_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700893 break;
894 case DS_ACCESS_CONFIGURATION_REGISTER:
895 if ((buf->conf_reg.Action == CS_WRITE) && !capable(CAP_SYS_ADMIN)) {
896 err = -EPERM;
897 goto free_out;
898 }
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100899
Dominik Brodowski926c5402008-08-03 12:15:11 +0200900 ret = -EINVAL;
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100901
902 if (!(buf->conf_reg.Function &&
903 (buf->conf_reg.Function >= s->functions))) {
904 struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->conf_reg.Function);
Benjamin Herrenschmidt73d58582006-05-15 09:43:53 -0700905 if (p_dev) {
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100906 ret = pcmcia_access_configuration_register(p_dev, &buf->conf_reg);
Benjamin Herrenschmidt73d58582006-05-15 09:43:53 -0700907 pcmcia_put_dev(p_dev);
908 }
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100909 }
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700910 break;
911 case DS_GET_FIRST_REGION:
912 case DS_GET_NEXT_REGION:
913 case DS_BIND_MTD:
914 if (!capable(CAP_SYS_ADMIN)) {
915 err = -EPERM;
916 goto free_out;
917 } else {
918 static int printed = 0;
919 if (!printed) {
920 printk(KERN_WARNING "2.6. kernels use pcmciamtd instead of memory_cs.c and do not require special\n");
921 printk(KERN_WARNING "MTD handling any more.\n");
922 printed++;
923 }
924 }
925 err = -EINVAL;
926 goto free_out;
927 break;
928 case DS_GET_FIRST_WINDOW:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700929 ret = pcmcia_get_window(s, &buf->win_info.handle, 0,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700930 &buf->win_info.window);
931 break;
932 case DS_GET_NEXT_WINDOW:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700933 ret = pcmcia_get_window(s, &buf->win_info.handle,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700934 buf->win_info.handle->index + 1, &buf->win_info.window);
935 break;
936 case DS_GET_MEM_PAGE:
937 ret = pcmcia_get_mem_page(buf->win_info.handle,
938 &buf->win_info.map);
939 break;
940 case DS_REPLACE_CIS:
Dominik Brodowski53efec92008-07-28 19:44:05 +0200941 ret = pcmcia_replace_cis(s, buf->cisdump.Data, buf->cisdump.Length);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700942 break;
943 case DS_BIND_REQUEST:
944 if (!capable(CAP_SYS_ADMIN)) {
945 err = -EPERM;
946 goto free_out;
947 }
948 err = bind_request(s, &buf->bind_info);
949 break;
950 case DS_GET_DEVICE_INFO:
951 err = get_device_info(s, &buf->bind_info, 1);
952 break;
953 case DS_GET_NEXT_DEVICE:
954 err = get_device_info(s, &buf->bind_info, 0);
955 break;
956 case DS_UNBIND_REQUEST:
957 err = 0;
958 break;
959 default:
960 err = -EINVAL;
961 }
962
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200963 if ((err == 0) && (ret != 0)) {
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700964 ds_dbg(2, "ds_ioctl: ret = %d\n", ret);
965 switch (ret) {
Dominik Brodowski610e2372008-08-03 11:58:53 +0200966 case -ENODEV:
967 case -EINVAL:
968 case -EBUSY:
969 case -ENOSYS:
970 err = ret;
971 break;
Dominik Brodowski610e2372008-08-03 11:58:53 +0200972 case -ENOMEM:
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700973 err = -ENOSPC; break;
Dominik Brodowski635d19b2008-08-03 11:47:29 +0200974 case -ENOSPC:
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700975 err = -ENODATA; break;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700976 default:
977 err = -EIO; break;
978 }
979 }
980
981 if (cmd & IOC_OUT) {
982 if (__copy_to_user(uarg, (char *)buf, size))
983 err = -EFAULT;
984 }
985
986free_out:
987 kfree(buf);
988 return err;
989} /* ds_ioctl */
990
991/*====================================================================*/
992
Arjan van de Vend54b1fd2007-02-12 00:55:34 -0800993static const struct file_operations ds_fops = {
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700994 .owner = THIS_MODULE,
995 .open = ds_open,
996 .release = ds_release,
997 .ioctl = ds_ioctl,
998 .read = ds_read,
999 .write = ds_write,
1000 .poll = ds_poll,
1001};
1002
1003void __init pcmcia_setup_ioctl(void) {
1004 int i;
1005
1006 /* Set up character device for user mode clients */
1007 i = register_chrdev(0, "pcmcia", &ds_fops);
Dominik Brodowski1a8ceaf2005-06-27 16:29:00 -07001008 if (i < 0)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001009 printk(KERN_NOTICE "unable to find a free device # for "
Dominik Brodowski1a8ceaf2005-06-27 16:29:00 -07001010 "Driver Services (error=%d)\n", i);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001011 else
1012 major_dev = i;
1013
1014#ifdef CONFIG_PROC_FS
akpm@linux-foundation.org97094dc2008-04-29 10:47:54 -07001015 proc_pccard = proc_mkdir("bus/pccard", NULL);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001016 if (proc_pccard)
1017 create_proc_read_entry("drivers",0,proc_pccard,proc_read_drivers,NULL);
1018#endif
1019}
1020
1021
1022void __exit pcmcia_cleanup_ioctl(void) {
1023#ifdef CONFIG_PROC_FS
1024 if (proc_pccard) {
1025 remove_proc_entry("drivers", proc_pccard);
akpm@linux-foundation.org97094dc2008-04-29 10:47:54 -07001026 remove_proc_entry("bus/pccard", NULL);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001027 }
1028#endif
1029 if (major_dev != -1)
1030 unregister_chrdev(major_dev, "pcmcia");
1031}