blob: f73fd5beaa372f05ddd64a8621b6c1786e64c366 [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>
Alexey Dobriyane6be4a82009-09-21 17:03:55 -070030#include <linux/seq_file.h>
Jonathan Corbet0bec0bb2008-05-15 09:25:03 -060031#include <linux/smp_lock.h>
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070032#include <linux/workqueue.h>
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070033
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070034#include <pcmcia/cs_types.h>
35#include <pcmcia/cs.h>
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070036#include <pcmcia/cistpl.h>
Dominik Brodowski4aeba012008-06-20 13:24:31 +020037#include <pcmcia/cisreg.h>
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070038#include <pcmcia/ds.h>
39#include <pcmcia/ss.h>
40
41#include "cs_internal.h"
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070042
43static int major_dev = -1;
44
45
46/* Device user information */
47#define MAX_EVENTS 32
48#define USER_MAGIC 0x7ea4
49#define CHECK_USER(u) \
50 (((u) == NULL) || ((u)->user_magic != USER_MAGIC))
51
52typedef struct user_info_t {
53 u_int user_magic;
54 int event_head, event_tail;
55 event_t event[MAX_EVENTS];
56 struct user_info_t *next;
Dominik Brodowskidc109492005-06-27 16:28:50 -070057 struct pcmcia_socket *socket;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070058} user_info_t;
59
60
Dominik Brodowski855cdf12006-01-10 20:48:59 +010061static struct pcmcia_device *get_pcmcia_device(struct pcmcia_socket *s,
62 unsigned int function)
63{
64 struct pcmcia_device *p_dev = NULL;
65 unsigned long flags;
66
67 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
68 list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
69 if (p_dev->func == function) {
70 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
71 return pcmcia_get_dev(p_dev);
72 }
73 }
74 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
75 return NULL;
76}
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070077
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070078/* backwards-compatible accessing of driver --- by name! */
79
Dominik Brodowski855cdf12006-01-10 20:48:59 +010080static struct pcmcia_driver *get_pcmcia_driver(dev_info_t *dev_info)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070081{
82 struct device_driver *drv;
83 struct pcmcia_driver *p_drv;
84
85 drv = driver_find((char *) dev_info, &pcmcia_bus_type);
86 if (!drv)
87 return NULL;
88
89 p_drv = container_of(drv, struct pcmcia_driver, drv);
90
Dominik Brodowski9fea84f2009-12-07 22:11:45 +010091 return p_drv;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070092}
93
94
95#ifdef CONFIG_PROC_FS
Dominik Brodowski9fea84f2009-12-07 22:11:45 +010096static struct proc_dir_entry *proc_pccard;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070097
Alexey Dobriyane6be4a82009-09-21 17:03:55 -070098static int proc_read_drivers_callback(struct device_driver *driver, void *_m)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070099{
Alexey Dobriyane6be4a82009-09-21 17:03:55 -0700100 struct seq_file *m = _m;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700101 struct pcmcia_driver *p_drv = container_of(driver,
102 struct pcmcia_driver, drv);
103
Alexey Dobriyane6be4a82009-09-21 17:03:55 -0700104 seq_printf(m, "%-24.24s 1 %d\n", p_drv->drv.name,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700105#ifdef CONFIG_MODULE_UNLOAD
106 (p_drv->owner) ? module_refcount(p_drv->owner) : 1
107#else
108 1
109#endif
110 );
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700111 return 0;
112}
113
Alexey Dobriyane6be4a82009-09-21 17:03:55 -0700114static int pccard_drivers_proc_show(struct seq_file *m, void *v)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700115{
Alexey Dobriyane6be4a82009-09-21 17:03:55 -0700116 return bus_for_each_drv(&pcmcia_bus_type, NULL,
117 m, proc_read_drivers_callback);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700118}
Alexey Dobriyane6be4a82009-09-21 17:03:55 -0700119
120static int pccard_drivers_proc_open(struct inode *inode, struct file *file)
121{
122 return single_open(file, pccard_drivers_proc_show, NULL);
123}
124
125static const struct file_operations pccard_drivers_proc_fops = {
126 .owner = THIS_MODULE,
127 .open = pccard_drivers_proc_open,
128 .read = seq_read,
129 .llseek = seq_lseek,
130 .release = single_release,
131};
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700132#endif
133
Dominik Brodowskic5023802008-06-19 19:02:52 +0200134
135#ifdef CONFIG_PCMCIA_PROBE
136
137static int adjust_irq(struct pcmcia_socket *s, adjust_t *adj)
138{
139 int irq;
140 u32 mask;
141
142 irq = adj->resource.irq.IRQ;
143 if ((irq < 0) || (irq > 15))
Dominik Brodowski69ba4432008-08-03 12:10:53 +0200144 return -EINVAL;
Dominik Brodowskic5023802008-06-19 19:02:52 +0200145
146 if (adj->Action != REMOVE_MANAGED_RESOURCE)
147 return 0;
148
149 mask = 1 << irq;
150
151 if (!(s->irq_mask & mask))
152 return 0;
153
154 s->irq_mask &= ~mask;
155
156 return 0;
157}
158
159#else
160
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100161static inline int adjust_irq(struct pcmcia_socket *s, adjust_t *adj)
162{
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200163 return 0;
Dominik Brodowskic5023802008-06-19 19:02:52 +0200164}
165
166#endif
167
168static int pcmcia_adjust_resource_info(adjust_t *adj)
169{
170 struct pcmcia_socket *s;
Dominik Brodowskide6405e2008-08-03 10:47:59 +0200171 int ret = -ENOSYS;
Dominik Brodowskic5023802008-06-19 19:02:52 +0200172 unsigned long flags;
173
174 down_read(&pcmcia_socket_list_rwsem);
175 list_for_each_entry(s, &pcmcia_socket_list, socket_list) {
176
177 if (adj->Resource == RES_IRQ)
178 ret = adjust_irq(s, adj);
179
180 else if (s->resource_ops->add_io) {
181 unsigned long begin, end;
182
183 /* you can't use the old interface if the new
184 * one was used before */
185 spin_lock_irqsave(&s->lock, flags);
186 if ((s->resource_setup_new) &&
187 !(s->resource_setup_old)) {
188 spin_unlock_irqrestore(&s->lock, flags);
189 continue;
190 } else if (!(s->resource_setup_old))
191 s->resource_setup_old = 1;
192 spin_unlock_irqrestore(&s->lock, flags);
193
194 switch (adj->Resource) {
195 case RES_MEMORY_RANGE:
196 begin = adj->resource.memory.Base;
197 end = adj->resource.memory.Base + adj->resource.memory.Size - 1;
198 if (s->resource_ops->add_mem)
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100199 ret = s->resource_ops->add_mem(s, adj->Action, begin, end);
Dominik Brodowskic5023802008-06-19 19:02:52 +0200200 case RES_IO_RANGE:
201 begin = adj->resource.io.BasePort;
202 end = adj->resource.io.BasePort + adj->resource.io.NumPorts - 1;
203 if (s->resource_ops->add_io)
204 ret = s->resource_ops->add_io(s, adj->Action, begin, end);
205 }
206 if (!ret) {
207 /* as there's no way we know this is the
208 * last call to adjust_resource_info, we
209 * always need to assume this is the latest
210 * one... */
211 spin_lock_irqsave(&s->lock, flags);
212 s->resource_setup_done = 1;
213 spin_unlock_irqrestore(&s->lock, flags);
214 }
215 }
216 }
217 up_read(&pcmcia_socket_list_rwsem);
218
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100219 return ret;
Dominik Brodowskic5023802008-06-19 19:02:52 +0200220}
221
Dominik Brodowskid7b03642009-11-03 01:05:33 +0100222
223/** pcmcia_get_window
224 */
225static int pcmcia_get_window(struct pcmcia_socket *s, window_handle_t *wh_out,
226 window_handle_t wh, win_req_t *req)
227{
Dominik Brodowski82f88e32009-11-03 01:16:12 +0100228 pccard_mem_map *win;
Dominik Brodowskid7b03642009-11-03 01:05:33 +0100229 window_handle_t w;
230
231 wh--;
232 if (!s || !(s->state & SOCKET_PRESENT))
233 return -ENODEV;
234 if (wh >= MAX_WIN)
235 return -EINVAL;
236 for (w = wh; w < MAX_WIN; w++)
237 if (s->state & SOCKET_WIN_REQ(w))
238 break;
239 if (w == MAX_WIN)
240 return -EINVAL;
241 win = &s->win[w];
Dominik Brodowski82f88e32009-11-03 01:16:12 +0100242 req->Base = win->res->start;
243 req->Size = win->res->end - win->res->start + 1;
244 req->AccessSpeed = win->speed;
Dominik Brodowskid7b03642009-11-03 01:05:33 +0100245 req->Attributes = 0;
Dominik Brodowski82f88e32009-11-03 01:16:12 +0100246 if (win->flags & MAP_ATTRIB)
Dominik Brodowskid7b03642009-11-03 01:05:33 +0100247 req->Attributes |= WIN_MEMORY_TYPE_AM;
Dominik Brodowski82f88e32009-11-03 01:16:12 +0100248 if (win->flags & MAP_ACTIVE)
Dominik Brodowskid7b03642009-11-03 01:05:33 +0100249 req->Attributes |= WIN_ENABLE;
Dominik Brodowski82f88e32009-11-03 01:16:12 +0100250 if (win->flags & MAP_16BIT)
Dominik Brodowskid7b03642009-11-03 01:05:33 +0100251 req->Attributes |= WIN_DATA_WIDTH_16;
Dominik Brodowski82f88e32009-11-03 01:16:12 +0100252 if (win->flags & MAP_USE_WAIT)
Dominik Brodowskid7b03642009-11-03 01:05:33 +0100253 req->Attributes |= WIN_USE_WAIT;
254
255 *wh_out = w + 1;
256 return 0;
257} /* pcmcia_get_window */
258
259
260/** pcmcia_get_mem_page
261 *
262 * Change the card address of an already open memory window.
263 */
264static int pcmcia_get_mem_page(struct pcmcia_socket *skt, window_handle_t wh,
265 memreq_t *req)
266{
267 wh--;
268 if (wh >= MAX_WIN)
269 return -EINVAL;
270
271 req->Page = 0;
Dominik Brodowski82f88e32009-11-03 01:16:12 +0100272 req->CardOffset = skt->win[wh].card_start;
Dominik Brodowskid7b03642009-11-03 01:05:33 +0100273 return 0;
274} /* pcmcia_get_mem_page */
275
276
Dominik Brodowski4aeba012008-06-20 13:24:31 +0200277/** pccard_get_status
278 *
279 * Get the current socket state bits. We don't support the latched
280 * SocketState yet: I haven't seen any point for it.
281 */
282
283static int pccard_get_status(struct pcmcia_socket *s,
284 struct pcmcia_device *p_dev,
285 cs_status_t *status)
286{
287 config_t *c;
288 int val;
289
290 s->ops->get_status(s, &val);
291 status->CardState = status->SocketState = 0;
292 status->CardState |= (val & SS_DETECT) ? CS_EVENT_CARD_DETECT : 0;
293 status->CardState |= (val & SS_CARDBUS) ? CS_EVENT_CB_DETECT : 0;
294 status->CardState |= (val & SS_3VCARD) ? CS_EVENT_3VCARD : 0;
295 status->CardState |= (val & SS_XVCARD) ? CS_EVENT_XVCARD : 0;
296 if (s->state & SOCKET_SUSPEND)
297 status->CardState |= CS_EVENT_PM_SUSPEND;
298 if (!(s->state & SOCKET_PRESENT))
Dominik Brodowski3939c1ef2008-08-03 11:10:56 +0200299 return -ENODEV;
Dominik Brodowski4aeba012008-06-20 13:24:31 +0200300
301 c = (p_dev) ? p_dev->function_config : NULL;
302
303 if ((c != NULL) && (c->state & CONFIG_LOCKED) &&
304 (c->IntType & (INT_MEMORY_AND_IO | INT_ZOOMED_VIDEO))) {
305 u_char reg;
306 if (c->CardValues & PRESENT_PIN_REPLACE) {
307 pcmcia_read_cis_mem(s, 1, (c->ConfigBase+CISREG_PRR)>>1, 1, &reg);
308 status->CardState |=
309 (reg & PRR_WP_STATUS) ? CS_EVENT_WRITE_PROTECT : 0;
310 status->CardState |=
311 (reg & PRR_READY_STATUS) ? CS_EVENT_READY_CHANGE : 0;
312 status->CardState |=
313 (reg & PRR_BVD2_STATUS) ? CS_EVENT_BATTERY_LOW : 0;
314 status->CardState |=
315 (reg & PRR_BVD1_STATUS) ? CS_EVENT_BATTERY_DEAD : 0;
316 } else {
317 /* No PRR? Then assume we're always ready */
318 status->CardState |= CS_EVENT_READY_CHANGE;
319 }
320 if (c->CardValues & PRESENT_EXT_STATUS) {
321 pcmcia_read_cis_mem(s, 1, (c->ConfigBase+CISREG_ESR)>>1, 1, &reg);
322 status->CardState |=
323 (reg & ESR_REQ_ATTN) ? CS_EVENT_REQUEST_ATTENTION : 0;
324 }
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200325 return 0;
Dominik Brodowski4aeba012008-06-20 13:24:31 +0200326 }
327 status->CardState |=
328 (val & SS_WRPROT) ? CS_EVENT_WRITE_PROTECT : 0;
329 status->CardState |=
330 (val & SS_BATDEAD) ? CS_EVENT_BATTERY_DEAD : 0;
331 status->CardState |=
332 (val & SS_BATWARN) ? CS_EVENT_BATTERY_LOW : 0;
333 status->CardState |=
334 (val & SS_READY) ? CS_EVENT_READY_CHANGE : 0;
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200335 return 0;
Dominik Brodowski4aeba012008-06-20 13:24:31 +0200336} /* pccard_get_status */
Dominik Brodowskic5023802008-06-19 19:02:52 +0200337
Roel Kluina0779322008-12-09 22:12:50 +0100338static int pccard_get_configuration_info(struct pcmcia_socket *s,
Dominik Brodowski64f34642008-08-02 17:00:46 +0200339 struct pcmcia_device *p_dev,
340 config_info_t *config)
341{
342 config_t *c;
343
344 if (!(s->state & SOCKET_PRESENT))
Dominik Brodowski3939c1ef2008-08-03 11:10:56 +0200345 return -ENODEV;
Dominik Brodowski64f34642008-08-02 17:00:46 +0200346
347
348#ifdef CONFIG_CARDBUS
349 if (s->state & SOCKET_CARDBUS) {
350 memset(config, 0, sizeof(config_info_t));
351 config->Vcc = s->socket.Vcc;
352 config->Vpp1 = config->Vpp2 = s->socket.Vpp;
353 config->Option = s->cb_dev->subordinate->number;
354 if (s->state & SOCKET_CARDBUS_CONFIG) {
355 config->Attributes = CONF_VALID_CLIENT;
356 config->IntType = INT_CARDBUS;
357 config->AssignedIRQ = s->irq.AssignedIRQ;
358 if (config->AssignedIRQ)
359 config->Attributes |= CONF_ENABLE_IRQ;
360 if (s->io[0].res) {
361 config->BasePort1 = s->io[0].res->start;
362 config->NumPorts1 = s->io[0].res->end -
363 config->BasePort1 + 1;
364 }
365 }
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200366 return 0;
Dominik Brodowski64f34642008-08-02 17:00:46 +0200367 }
368#endif
369
370 if (p_dev) {
371 c = p_dev->function_config;
372 config->Function = p_dev->func;
373 } else {
374 c = NULL;
375 config->Function = 0;
376 }
377
378 if ((c == NULL) || !(c->state & CONFIG_LOCKED)) {
379 config->Attributes = 0;
380 config->Vcc = s->socket.Vcc;
381 config->Vpp1 = config->Vpp2 = s->socket.Vpp;
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200382 return 0;
Dominik Brodowski64f34642008-08-02 17:00:46 +0200383 }
384
385 config->Attributes = c->Attributes | CONF_VALID_CLIENT;
386 config->Vcc = s->socket.Vcc;
387 config->Vpp1 = config->Vpp2 = s->socket.Vpp;
388 config->IntType = c->IntType;
389 config->ConfigBase = c->ConfigBase;
390 config->Status = c->Status;
391 config->Pin = c->Pin;
392 config->Copy = c->Copy;
393 config->Option = c->Option;
394 config->ExtStatus = c->ExtStatus;
395 config->Present = config->CardValues = c->CardValues;
396 config->IRQAttributes = c->irq.Attributes;
397 config->AssignedIRQ = s->irq.AssignedIRQ;
398 config->BasePort1 = c->io.BasePort1;
399 config->NumPorts1 = c->io.NumPorts1;
400 config->Attributes1 = c->io.Attributes1;
401 config->BasePort2 = c->io.BasePort2;
402 config->NumPorts2 = c->io.NumPorts2;
403 config->Attributes2 = c->io.Attributes2;
404 config->IOAddrLines = c->io.IOAddrLines;
405
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200406 return 0;
Dominik Brodowski64f34642008-08-02 17:00:46 +0200407} /* pccard_get_configuration_info */
408
409
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700410/*======================================================================
411
412 These manage a ring buffer of events pending for one user process
413
414======================================================================*/
415
416
417static int queue_empty(user_info_t *user)
418{
419 return (user->event_head == user->event_tail);
420}
421
422static event_t get_queued_event(user_info_t *user)
423{
424 user->event_tail = (user->event_tail+1) % MAX_EVENTS;
425 return user->event[user->event_tail];
426}
427
428static void queue_event(user_info_t *user, event_t event)
429{
430 user->event_head = (user->event_head+1) % MAX_EVENTS;
431 if (user->event_head == user->event_tail)
432 user->event_tail = (user->event_tail+1) % MAX_EVENTS;
433 user->event[user->event_head] = event;
434}
435
Dominik Brodowskidc109492005-06-27 16:28:50 -0700436void handle_event(struct pcmcia_socket *s, event_t event)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700437{
438 user_info_t *user;
439 for (user = s->user; user; user = user->next)
440 queue_event(user, event);
441 wake_up_interruptible(&s->queue);
442}
443
444
445/*======================================================================
446
447 bind_request() and bind_device() are merged by now. Register_client()
448 is called right at the end of bind_request(), during the driver's
449 ->attach() call. Individual descriptions:
450
451 bind_request() connects a socket to a particular client driver.
452 It looks up the specified device ID in the list of registered
453 drivers, binds it to the socket, and tries to create an instance
454 of the device. unbind_request() deletes a driver instance.
455
456 Bind_device() associates a device driver with a particular socket.
457 It is normally called by Driver Services after it has identified
458 a newly inserted card. An instance of that driver will then be
459 eligible to register as a client of this socket.
460
461 Register_client() uses the dev_info_t handle to match the
462 caller with a socket. The driver must have already been bound
463 to a socket with bind_device() -- in fact, bind_device()
464 allocates the client structure that will be used.
465
466======================================================================*/
467
Dominik Brodowskidc109492005-06-27 16:28:50 -0700468static int bind_request(struct pcmcia_socket *s, bind_info_t *bind_info)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700469{
470 struct pcmcia_driver *p_drv;
471 struct pcmcia_device *p_dev;
472 int ret = 0;
473 unsigned long flags;
474
Dominik Brodowskidc109492005-06-27 16:28:50 -0700475 s = pcmcia_get_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700476 if (!s)
477 return -EINVAL;
478
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200479 pr_debug("bind_request(%d, '%s')\n", s->sock,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700480 (char *)bind_info->dev_info);
481
482 p_drv = get_pcmcia_driver(&bind_info->dev_info);
483 if (!p_drv) {
484 ret = -EINVAL;
485 goto err_put;
486 }
487
488 if (!try_module_get(p_drv->owner)) {
489 ret = -EINVAL;
490 goto err_put_driver;
491 }
492
493 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100494 list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700495 if (p_dev->func == bind_info->function) {
496 if ((p_dev->dev.driver == &p_drv->drv)) {
497 if (p_dev->cardmgr) {
498 /* if there's already a device
499 * registered, and it was registered
500 * by userspace before, we need to
501 * return the "instance". */
502 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
Dominik Brodowskifd238232006-03-05 10:45:09 +0100503 bind_info->instance = p_dev;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700504 ret = -EBUSY;
505 goto err_put_module;
506 } else {
507 /* the correct driver managed to bind
508 * itself magically to the correct
509 * device. */
510 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
511 p_dev->cardmgr = p_drv;
512 ret = 0;
513 goto err_put_module;
514 }
515 } else if (!p_dev->dev.driver) {
516 /* there's already a device available where
517 * no device has been bound to yet. So we don't
518 * need to register a device! */
519 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
520 goto rescan;
521 }
522 }
523 }
524 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
525
526 p_dev = pcmcia_device_add(s, bind_info->function);
527 if (!p_dev) {
528 ret = -EIO;
529 goto err_put_module;
530 }
531
532rescan:
533 p_dev->cardmgr = p_drv;
534
535 /* if a driver is already running, we can abort */
536 if (p_dev->dev.driver)
537 goto err_put_module;
538
539 /*
540 * Prevent this racing with a card insertion.
541 */
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100542 mutex_lock(&s->skt_mutex);
Jeff Garzik4deb7c12006-10-20 14:44:23 -0700543 ret = bus_rescan_devices(&pcmcia_bus_type);
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100544 mutex_unlock(&s->skt_mutex);
Jeff Garzik4deb7c12006-10-20 14:44:23 -0700545 if (ret)
546 goto err_put_module;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700547
548 /* check whether the driver indeed matched. I don't care if this
549 * is racy or not, because it can only happen on cardmgr access
550 * paths...
551 */
552 if (!(p_dev->dev.driver == &p_drv->drv))
553 p_dev->cardmgr = NULL;
554
555 err_put_module:
556 module_put(p_drv->owner);
557 err_put_driver:
558 put_driver(&p_drv->drv);
559 err_put:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700560 pcmcia_put_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700561
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100562 return ret;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700563} /* bind_request */
564
Dominik Brodowski33519dd2005-06-27 16:28:53 -0700565#ifdef CONFIG_CARDBUS
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700566
Dominik Brodowski33519dd2005-06-27 16:28:53 -0700567static struct pci_bus *pcmcia_lookup_bus(struct pcmcia_socket *s)
568{
569 if (!s || !(s->state & SOCKET_CARDBUS))
570 return NULL;
571
572 return s->cb_dev->subordinate;
573}
574#endif
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700575
Dominik Brodowskidc109492005-06-27 16:28:50 -0700576static int get_device_info(struct pcmcia_socket *s, bind_info_t *bind_info, int first)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700577{
578 dev_node_t *node;
579 struct pcmcia_device *p_dev;
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100580 struct pcmcia_driver *p_drv;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700581 unsigned long flags;
582 int ret = 0;
583
584#ifdef CONFIG_CARDBUS
585 /*
586 * Some unbelievably ugly code to associate the PCI cardbus
587 * device and its driver with the PCMCIA "bind" information.
588 */
589 {
590 struct pci_bus *bus;
591
Dominik Brodowskidc109492005-06-27 16:28:50 -0700592 bus = pcmcia_lookup_bus(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700593 if (bus) {
594 struct list_head *list;
595 struct pci_dev *dev = NULL;
596
597 list = bus->devices.next;
598 while (list != &bus->devices) {
599 struct pci_dev *pdev = pci_dev_b(list);
600 list = list->next;
601
602 if (first) {
603 dev = pdev;
604 break;
605 }
606
607 /* Try to handle "next" here some way? */
608 }
609 if (dev && dev->driver) {
610 strlcpy(bind_info->name, dev->driver->name, DEV_NAME_LEN);
611 bind_info->major = 0;
612 bind_info->minor = 0;
613 bind_info->next = NULL;
614 return 0;
615 }
616 }
617 }
618#endif
619
620 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
621 list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
622 if (p_dev->func == bind_info->function) {
623 p_dev = pcmcia_get_dev(p_dev);
624 if (!p_dev)
625 continue;
626 goto found;
627 }
628 }
629 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
630 return -ENODEV;
631
632 found:
633 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
634
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100635 p_drv = to_pcmcia_drv(p_dev->dev.driver);
636 if (p_drv && !p_dev->_locked) {
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700637 ret = -EAGAIN;
638 goto err_put;
639 }
640
641 if (first)
Dominik Brodowskifd238232006-03-05 10:45:09 +0100642 node = p_dev->dev_node;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700643 else
Dominik Brodowskifd238232006-03-05 10:45:09 +0100644 for (node = p_dev->dev_node; node; node = node->next)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700645 if (node == bind_info->next)
646 break;
647 if (!node) {
648 ret = -ENODEV;
649 goto err_put;
650 }
651
652 strlcpy(bind_info->name, node->dev_name, DEV_NAME_LEN);
653 bind_info->major = node->major;
654 bind_info->minor = node->minor;
655 bind_info->next = node->next;
656
657 err_put:
658 pcmcia_put_dev(p_dev);
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100659 return ret;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700660} /* get_device_info */
661
662
663static int ds_open(struct inode *inode, struct file *file)
664{
665 socket_t i = iminor(inode);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700666 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700667 user_info_t *user;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100668 static int warning_printed;
Jonathan Corbet0bec0bb2008-05-15 09:25:03 -0600669 int ret = 0;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700670
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200671 pr_debug("ds_open(socket %d)\n", i);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700672
Jonathan Corbet0bec0bb2008-05-15 09:25:03 -0600673 lock_kernel();
Dominik Brodowskidc109492005-06-27 16:28:50 -0700674 s = pcmcia_get_socket_by_nr(i);
Jonathan Corbet0bec0bb2008-05-15 09:25:03 -0600675 if (!s) {
676 ret = -ENODEV;
677 goto out;
678 }
Dominik Brodowskidc109492005-06-27 16:28:50 -0700679 s = pcmcia_get_socket(s);
Jonathan Corbet0bec0bb2008-05-15 09:25:03 -0600680 if (!s) {
681 ret = -ENODEV;
682 goto out;
683 }
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700684
685 if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700686 if (s->pcmcia_state.busy) {
Dominik Brodowskidc109492005-06-27 16:28:50 -0700687 pcmcia_put_socket(s);
Jonathan Corbet0bec0bb2008-05-15 09:25:03 -0600688 ret = -EBUSY;
689 goto out;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700690 }
691 else
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700692 s->pcmcia_state.busy = 1;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700693 }
694
695 user = kmalloc(sizeof(user_info_t), GFP_KERNEL);
696 if (!user) {
Dominik Brodowskidc109492005-06-27 16:28:50 -0700697 pcmcia_put_socket(s);
Jonathan Corbet0bec0bb2008-05-15 09:25:03 -0600698 ret = -ENOMEM;
699 goto out;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700700 }
701 user->event_tail = user->event_head = 0;
702 user->next = s->user;
703 user->user_magic = USER_MAGIC;
704 user->socket = s;
705 s->user = user;
706 file->private_data = user;
707
Dominik Brodowskic352ec82005-09-13 01:25:03 -0700708 if (!warning_printed) {
709 printk(KERN_INFO "pcmcia: Detected deprecated PCMCIA ioctl "
Benjamin Herrenschmidt73d58582006-05-15 09:43:53 -0700710 "usage from process: %s.\n", current->comm);
Dominik Brodowskic352ec82005-09-13 01:25:03 -0700711 printk(KERN_INFO "pcmcia: This interface will soon be removed from "
712 "the kernel; please expect breakage unless you upgrade "
713 "to new tools.\n");
714 printk(KERN_INFO "pcmcia: see http://www.kernel.org/pub/linux/"
715 "utils/kernel/pcmcia/pcmcia.html for details.\n");
716 warning_printed = 1;
717 }
718
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700719 if (s->pcmcia_state.present)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700720 queue_event(user, CS_EVENT_CARD_INSERTION);
Jonathan Corbet0bec0bb2008-05-15 09:25:03 -0600721out:
722 unlock_kernel();
723 return ret;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700724} /* ds_open */
725
726/*====================================================================*/
727
728static int ds_release(struct inode *inode, struct file *file)
729{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700730 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700731 user_info_t *user, **link;
732
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200733 pr_debug("ds_release(socket %d)\n", iminor(inode));
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700734
735 user = file->private_data;
736 if (CHECK_USER(user))
737 goto out;
738
739 s = user->socket;
740
741 /* Unlink user data structure */
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100742 if ((file->f_flags & O_ACCMODE) != O_RDONLY)
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700743 s->pcmcia_state.busy = 0;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100744
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700745 file->private_data = NULL;
746 for (link = &s->user; *link; link = &(*link)->next)
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100747 if (*link == user)
748 break;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700749 if (link == NULL)
750 goto out;
751 *link = user->next;
752 user->user_magic = 0;
753 kfree(user);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700754 pcmcia_put_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700755out:
756 return 0;
757} /* ds_release */
758
759/*====================================================================*/
760
761static ssize_t ds_read(struct file *file, char __user *buf,
762 size_t count, loff_t *ppos)
763{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700764 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700765 user_info_t *user;
766 int ret;
767
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200768 pr_debug("ds_read(socket %d)\n", iminor(file->f_path.dentry->d_inode));
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700769
770 if (count < 4)
771 return -EINVAL;
772
773 user = file->private_data;
774 if (CHECK_USER(user))
775 return -EIO;
776
777 s = user->socket;
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700778 if (s->pcmcia_state.dead)
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100779 return -EIO;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700780
781 ret = wait_event_interruptible(s->queue, !queue_empty(user));
782 if (ret == 0)
783 ret = put_user(get_queued_event(user), (int __user *)buf) ? -EFAULT : 4;
784
785 return ret;
786} /* ds_read */
787
788/*====================================================================*/
789
790static ssize_t ds_write(struct file *file, const char __user *buf,
791 size_t count, loff_t *ppos)
792{
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200793 pr_debug("ds_write(socket %d)\n", iminor(file->f_path.dentry->d_inode));
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700794
795 if (count != 4)
796 return -EINVAL;
797 if ((file->f_flags & O_ACCMODE) == O_RDONLY)
798 return -EBADF;
799
800 return -EIO;
801} /* ds_write */
802
803/*====================================================================*/
804
805/* No kernel lock - fine */
806static u_int ds_poll(struct file *file, poll_table *wait)
807{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700808 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700809 user_info_t *user;
810
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200811 pr_debug("ds_poll(socket %d)\n", iminor(file->f_path.dentry->d_inode));
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700812
813 user = file->private_data;
814 if (CHECK_USER(user))
815 return POLLERR;
816 s = user->socket;
817 /*
818 * We don't check for a dead socket here since that
819 * will send cardmgr into an endless spin.
820 */
821 poll_wait(file, &s->queue, wait);
822 if (!queue_empty(user))
823 return POLLIN | POLLRDNORM;
824 return 0;
825} /* ds_poll */
826
827/*====================================================================*/
828
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100829static int ds_ioctl(struct inode *inode, struct file *file,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700830 u_int cmd, u_long arg)
831{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700832 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700833 void __user *uarg = (char __user *)arg;
834 u_int size;
835 int ret, err;
836 ds_ioctl_arg_t *buf;
837 user_info_t *user;
838
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200839 pr_debug("ds_ioctl(socket %d, %#x, %#lx)\n", iminor(inode), cmd, arg);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700840
841 user = file->private_data;
842 if (CHECK_USER(user))
843 return -EIO;
844
845 s = user->socket;
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700846 if (s->pcmcia_state.dead)
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100847 return -EIO;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700848
849 size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100850 if (size > sizeof(ds_ioctl_arg_t))
851 return -EINVAL;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700852
853 /* Permission check */
854 if (!(cmd & IOC_OUT) && !capable(CAP_SYS_ADMIN))
855 return -EPERM;
856
857 if (cmd & IOC_IN) {
858 if (!access_ok(VERIFY_READ, uarg, size)) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200859 pr_debug("ds_ioctl(): verify_read = %d\n", -EFAULT);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700860 return -EFAULT;
861 }
862 }
863 if (cmd & IOC_OUT) {
864 if (!access_ok(VERIFY_WRITE, uarg, size)) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200865 pr_debug("ds_ioctl(): verify_write = %d\n", -EFAULT);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700866 return -EFAULT;
867 }
868 }
869 buf = kmalloc(sizeof(ds_ioctl_arg_t), GFP_KERNEL);
870 if (!buf)
871 return -ENOMEM;
872
873 err = ret = 0;
874
Dominik Brodowski93740742006-11-19 11:21:27 -0500875 if (cmd & IOC_IN) {
876 if (__copy_from_user((char *)buf, uarg, size)) {
877 err = -EFAULT;
878 goto free_out;
879 }
880 }
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700881
882 switch (cmd) {
883 case DS_ADJUST_RESOURCE_INFO:
884 ret = pcmcia_adjust_resource_info(&buf->adjust);
885 break;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700886 case DS_GET_CONFIGURATION_INFO:
887 if (buf->config.Function &&
Dominik Brodowskidc109492005-06-27 16:28:50 -0700888 (buf->config.Function >= s->functions))
Dominik Brodowski926c5402008-08-03 12:15:11 +0200889 ret = -EINVAL;
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100890 else {
891 struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->config.Function);
Daniel Ritzf47ad212006-07-30 03:03:47 -0700892 ret = pccard_get_configuration_info(s, p_dev, &buf->config);
893 pcmcia_put_dev(p_dev);
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100894 }
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700895 break;
896 case DS_GET_FIRST_TUPLE:
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100897 mutex_lock(&s->skt_mutex);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700898 pcmcia_validate_mem(s);
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100899 mutex_unlock(&s->skt_mutex);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700900 ret = pccard_get_first_tuple(s, BIND_FN_ALL, &buf->tuple);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700901 break;
902 case DS_GET_NEXT_TUPLE:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700903 ret = pccard_get_next_tuple(s, BIND_FN_ALL, &buf->tuple);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700904 break;
905 case DS_GET_TUPLE_DATA:
906 buf->tuple.TupleData = buf->tuple_parse.data;
907 buf->tuple.TupleDataMax = sizeof(buf->tuple_parse.data);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700908 ret = pccard_get_tuple_data(s, &buf->tuple);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700909 break;
910 case DS_PARSE_TUPLE:
911 buf->tuple.TupleData = buf->tuple_parse.data;
Dominik Brodowski2f3061e2008-08-31 15:50:33 +0200912 ret = pcmcia_parse_tuple(&buf->tuple, &buf->tuple_parse.parse);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700913 break;
914 case DS_RESET_CARD:
Dominik Brodowski994917f2008-08-31 15:20:26 +0200915 ret = pcmcia_reset_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700916 break;
917 case DS_GET_STATUS:
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100918 if (buf->status.Function &&
919 (buf->status.Function >= s->functions))
Dominik Brodowski926c5402008-08-03 12:15:11 +0200920 ret = -EINVAL;
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100921 else {
922 struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->status.Function);
Daniel Ritzf47ad212006-07-30 03:03:47 -0700923 ret = pccard_get_status(s, p_dev, &buf->status);
924 pcmcia_put_dev(p_dev);
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100925 }
926 break;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700927 case DS_VALIDATE_CIS:
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100928 mutex_lock(&s->skt_mutex);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700929 pcmcia_validate_mem(s);
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100930 mutex_unlock(&s->skt_mutex);
Dominik Brodowski84897fc2009-10-18 23:51:09 +0200931 ret = pccard_validate_cis(s, &buf->cisinfo.Chains);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700932 break;
933 case DS_SUSPEND_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700934 ret = pcmcia_suspend_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700935 break;
936 case DS_RESUME_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700937 ret = pcmcia_resume_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700938 break;
939 case DS_EJECT_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700940 err = pcmcia_eject_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700941 break;
942 case DS_INSERT_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700943 err = pcmcia_insert_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700944 break;
945 case DS_ACCESS_CONFIGURATION_REGISTER:
946 if ((buf->conf_reg.Action == CS_WRITE) && !capable(CAP_SYS_ADMIN)) {
947 err = -EPERM;
948 goto free_out;
949 }
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100950
Dominik Brodowski926c5402008-08-03 12:15:11 +0200951 ret = -EINVAL;
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100952
953 if (!(buf->conf_reg.Function &&
954 (buf->conf_reg.Function >= s->functions))) {
955 struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->conf_reg.Function);
Benjamin Herrenschmidt73d58582006-05-15 09:43:53 -0700956 if (p_dev) {
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100957 ret = pcmcia_access_configuration_register(p_dev, &buf->conf_reg);
Benjamin Herrenschmidt73d58582006-05-15 09:43:53 -0700958 pcmcia_put_dev(p_dev);
959 }
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100960 }
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700961 break;
962 case DS_GET_FIRST_REGION:
963 case DS_GET_NEXT_REGION:
964 case DS_BIND_MTD:
965 if (!capable(CAP_SYS_ADMIN)) {
966 err = -EPERM;
967 goto free_out;
968 } else {
Minchan Kima9c56952009-06-16 15:33:44 -0700969 printk_once(KERN_WARNING
970 "2.6. kernels use pcmciamtd instead of memory_cs.c and do not require special\n");
971 printk_once(KERN_WARNING "MTD handling any more.\n");
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700972 }
973 err = -EINVAL;
974 goto free_out;
975 break;
976 case DS_GET_FIRST_WINDOW:
Magnus Damm0bdf9b32006-12-13 19:46:53 +0900977 ret = pcmcia_get_window(s, &buf->win_info.handle, 1,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700978 &buf->win_info.window);
979 break;
980 case DS_GET_NEXT_WINDOW:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700981 ret = pcmcia_get_window(s, &buf->win_info.handle,
Magnus Damm0bdf9b32006-12-13 19:46:53 +0900982 buf->win_info.handle + 1, &buf->win_info.window);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700983 break;
984 case DS_GET_MEM_PAGE:
Magnus Damm16456eb2006-12-13 19:46:48 +0900985 ret = pcmcia_get_mem_page(s, buf->win_info.handle,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700986 &buf->win_info.map);
987 break;
988 case DS_REPLACE_CIS:
Dominik Brodowski53efec92008-07-28 19:44:05 +0200989 ret = pcmcia_replace_cis(s, buf->cisdump.Data, buf->cisdump.Length);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700990 break;
991 case DS_BIND_REQUEST:
992 if (!capable(CAP_SYS_ADMIN)) {
993 err = -EPERM;
994 goto free_out;
995 }
996 err = bind_request(s, &buf->bind_info);
997 break;
998 case DS_GET_DEVICE_INFO:
999 err = get_device_info(s, &buf->bind_info, 1);
1000 break;
1001 case DS_GET_NEXT_DEVICE:
1002 err = get_device_info(s, &buf->bind_info, 0);
1003 break;
1004 case DS_UNBIND_REQUEST:
1005 err = 0;
1006 break;
1007 default:
1008 err = -EINVAL;
1009 }
1010
Dominik Brodowski4c89e882008-08-03 10:07:45 +02001011 if ((err == 0) && (ret != 0)) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +02001012 pr_debug("ds_ioctl: ret = %d\n", ret);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001013 switch (ret) {
Dominik Brodowski610e2372008-08-03 11:58:53 +02001014 case -ENODEV:
1015 case -EINVAL:
1016 case -EBUSY:
1017 case -ENOSYS:
1018 err = ret;
1019 break;
Dominik Brodowski610e2372008-08-03 11:58:53 +02001020 case -ENOMEM:
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001021 err = -ENOSPC; break;
Dominik Brodowski635d19b2008-08-03 11:47:29 +02001022 case -ENOSPC:
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001023 err = -ENODATA; break;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001024 default:
1025 err = -EIO; break;
1026 }
1027 }
1028
1029 if (cmd & IOC_OUT) {
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001030 if (__copy_to_user(uarg, (char *)buf, size))
1031 err = -EFAULT;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001032 }
1033
1034free_out:
1035 kfree(buf);
1036 return err;
1037} /* ds_ioctl */
1038
1039/*====================================================================*/
1040
Arjan van de Vend54b1fd2007-02-12 00:55:34 -08001041static const struct file_operations ds_fops = {
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001042 .owner = THIS_MODULE,
1043 .open = ds_open,
1044 .release = ds_release,
1045 .ioctl = ds_ioctl,
1046 .read = ds_read,
1047 .write = ds_write,
1048 .poll = ds_poll,
1049};
1050
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001051void __init pcmcia_setup_ioctl(void)
1052{
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001053 int i;
1054
1055 /* Set up character device for user mode clients */
1056 i = register_chrdev(0, "pcmcia", &ds_fops);
Dominik Brodowski1a8ceaf2005-06-27 16:29:00 -07001057 if (i < 0)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001058 printk(KERN_NOTICE "unable to find a free device # for "
Dominik Brodowski1a8ceaf2005-06-27 16:29:00 -07001059 "Driver Services (error=%d)\n", i);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001060 else
1061 major_dev = i;
1062
1063#ifdef CONFIG_PROC_FS
akpm@linux-foundation.org97094dc2008-04-29 10:47:54 -07001064 proc_pccard = proc_mkdir("bus/pccard", NULL);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001065 if (proc_pccard)
Alexey Dobriyane6be4a82009-09-21 17:03:55 -07001066 proc_create("drivers", 0, proc_pccard, &pccard_drivers_proc_fops);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001067#endif
1068}
1069
1070
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001071void __exit pcmcia_cleanup_ioctl(void)
1072{
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001073#ifdef CONFIG_PROC_FS
1074 if (proc_pccard) {
1075 remove_proc_entry("drivers", proc_pccard);
akpm@linux-foundation.org97094dc2008-04-29 10:47:54 -07001076 remove_proc_entry("bus/pccard", NULL);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001077 }
1078#endif
1079 if (major_dev != -1)
1080 unregister_chrdev(major_dev, "pcmcia");
1081}