blob: c4d7908fa37f1974f413627cd3b274512ec872ae [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
91 return (p_drv);
92}
93
94
95#ifdef CONFIG_PROC_FS
96static struct proc_dir_entry *proc_pccard = NULL;
97
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
161static inline int adjust_irq(struct pcmcia_socket *s, adjust_t *adj) {
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200162 return 0;
Dominik Brodowskic5023802008-06-19 19:02:52 +0200163}
164
165#endif
166
167static int pcmcia_adjust_resource_info(adjust_t *adj)
168{
169 struct pcmcia_socket *s;
Dominik Brodowskide6405e2008-08-03 10:47:59 +0200170 int ret = -ENOSYS;
Dominik Brodowskic5023802008-06-19 19:02:52 +0200171 unsigned long flags;
172
173 down_read(&pcmcia_socket_list_rwsem);
174 list_for_each_entry(s, &pcmcia_socket_list, socket_list) {
175
176 if (adj->Resource == RES_IRQ)
177 ret = adjust_irq(s, adj);
178
179 else if (s->resource_ops->add_io) {
180 unsigned long begin, end;
181
182 /* you can't use the old interface if the new
183 * one was used before */
184 spin_lock_irqsave(&s->lock, flags);
185 if ((s->resource_setup_new) &&
186 !(s->resource_setup_old)) {
187 spin_unlock_irqrestore(&s->lock, flags);
188 continue;
189 } else if (!(s->resource_setup_old))
190 s->resource_setup_old = 1;
191 spin_unlock_irqrestore(&s->lock, flags);
192
193 switch (adj->Resource) {
194 case RES_MEMORY_RANGE:
195 begin = adj->resource.memory.Base;
196 end = adj->resource.memory.Base + adj->resource.memory.Size - 1;
197 if (s->resource_ops->add_mem)
198 ret =s->resource_ops->add_mem(s, adj->Action, begin, end);
199 case RES_IO_RANGE:
200 begin = adj->resource.io.BasePort;
201 end = adj->resource.io.BasePort + adj->resource.io.NumPorts - 1;
202 if (s->resource_ops->add_io)
203 ret = s->resource_ops->add_io(s, adj->Action, begin, end);
204 }
205 if (!ret) {
206 /* as there's no way we know this is the
207 * last call to adjust_resource_info, we
208 * always need to assume this is the latest
209 * one... */
210 spin_lock_irqsave(&s->lock, flags);
211 s->resource_setup_done = 1;
212 spin_unlock_irqrestore(&s->lock, flags);
213 }
214 }
215 }
216 up_read(&pcmcia_socket_list_rwsem);
217
218 return (ret);
219}
220
Dominik Brodowskid7b03642009-11-03 01:05:33 +0100221
222/** pcmcia_get_window
223 */
224static int pcmcia_get_window(struct pcmcia_socket *s, window_handle_t *wh_out,
225 window_handle_t wh, win_req_t *req)
226{
Dominik Brodowski82f88e32009-11-03 01:16:12 +0100227 pccard_mem_map *win;
Dominik Brodowskid7b03642009-11-03 01:05:33 +0100228 window_handle_t w;
229
230 wh--;
231 if (!s || !(s->state & SOCKET_PRESENT))
232 return -ENODEV;
233 if (wh >= MAX_WIN)
234 return -EINVAL;
235 for (w = wh; w < MAX_WIN; w++)
236 if (s->state & SOCKET_WIN_REQ(w))
237 break;
238 if (w == MAX_WIN)
239 return -EINVAL;
240 win = &s->win[w];
Dominik Brodowski82f88e32009-11-03 01:16:12 +0100241 req->Base = win->res->start;
242 req->Size = win->res->end - win->res->start + 1;
243 req->AccessSpeed = win->speed;
Dominik Brodowskid7b03642009-11-03 01:05:33 +0100244 req->Attributes = 0;
Dominik Brodowski82f88e32009-11-03 01:16:12 +0100245 if (win->flags & MAP_ATTRIB)
Dominik Brodowskid7b03642009-11-03 01:05:33 +0100246 req->Attributes |= WIN_MEMORY_TYPE_AM;
Dominik Brodowski82f88e32009-11-03 01:16:12 +0100247 if (win->flags & MAP_ACTIVE)
Dominik Brodowskid7b03642009-11-03 01:05:33 +0100248 req->Attributes |= WIN_ENABLE;
Dominik Brodowski82f88e32009-11-03 01:16:12 +0100249 if (win->flags & MAP_16BIT)
Dominik Brodowskid7b03642009-11-03 01:05:33 +0100250 req->Attributes |= WIN_DATA_WIDTH_16;
Dominik Brodowski82f88e32009-11-03 01:16:12 +0100251 if (win->flags & MAP_USE_WAIT)
Dominik Brodowskid7b03642009-11-03 01:05:33 +0100252 req->Attributes |= WIN_USE_WAIT;
253
254 *wh_out = w + 1;
255 return 0;
256} /* pcmcia_get_window */
257
258
259/** pcmcia_get_mem_page
260 *
261 * Change the card address of an already open memory window.
262 */
263static int pcmcia_get_mem_page(struct pcmcia_socket *skt, window_handle_t wh,
264 memreq_t *req)
265{
266 wh--;
267 if (wh >= MAX_WIN)
268 return -EINVAL;
269
270 req->Page = 0;
Dominik Brodowski82f88e32009-11-03 01:16:12 +0100271 req->CardOffset = skt->win[wh].card_start;
Dominik Brodowskid7b03642009-11-03 01:05:33 +0100272 return 0;
273} /* pcmcia_get_mem_page */
274
275
Dominik Brodowski4aeba012008-06-20 13:24:31 +0200276/** pccard_get_status
277 *
278 * Get the current socket state bits. We don't support the latched
279 * SocketState yet: I haven't seen any point for it.
280 */
281
282static int pccard_get_status(struct pcmcia_socket *s,
283 struct pcmcia_device *p_dev,
284 cs_status_t *status)
285{
286 config_t *c;
287 int val;
288
289 s->ops->get_status(s, &val);
290 status->CardState = status->SocketState = 0;
291 status->CardState |= (val & SS_DETECT) ? CS_EVENT_CARD_DETECT : 0;
292 status->CardState |= (val & SS_CARDBUS) ? CS_EVENT_CB_DETECT : 0;
293 status->CardState |= (val & SS_3VCARD) ? CS_EVENT_3VCARD : 0;
294 status->CardState |= (val & SS_XVCARD) ? CS_EVENT_XVCARD : 0;
295 if (s->state & SOCKET_SUSPEND)
296 status->CardState |= CS_EVENT_PM_SUSPEND;
297 if (!(s->state & SOCKET_PRESENT))
Dominik Brodowski3939c1ef2008-08-03 11:10:56 +0200298 return -ENODEV;
Dominik Brodowski4aeba012008-06-20 13:24:31 +0200299
300 c = (p_dev) ? p_dev->function_config : NULL;
301
302 if ((c != NULL) && (c->state & CONFIG_LOCKED) &&
303 (c->IntType & (INT_MEMORY_AND_IO | INT_ZOOMED_VIDEO))) {
304 u_char reg;
305 if (c->CardValues & PRESENT_PIN_REPLACE) {
306 pcmcia_read_cis_mem(s, 1, (c->ConfigBase+CISREG_PRR)>>1, 1, &reg);
307 status->CardState |=
308 (reg & PRR_WP_STATUS) ? CS_EVENT_WRITE_PROTECT : 0;
309 status->CardState |=
310 (reg & PRR_READY_STATUS) ? CS_EVENT_READY_CHANGE : 0;
311 status->CardState |=
312 (reg & PRR_BVD2_STATUS) ? CS_EVENT_BATTERY_LOW : 0;
313 status->CardState |=
314 (reg & PRR_BVD1_STATUS) ? CS_EVENT_BATTERY_DEAD : 0;
315 } else {
316 /* No PRR? Then assume we're always ready */
317 status->CardState |= CS_EVENT_READY_CHANGE;
318 }
319 if (c->CardValues & PRESENT_EXT_STATUS) {
320 pcmcia_read_cis_mem(s, 1, (c->ConfigBase+CISREG_ESR)>>1, 1, &reg);
321 status->CardState |=
322 (reg & ESR_REQ_ATTN) ? CS_EVENT_REQUEST_ATTENTION : 0;
323 }
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200324 return 0;
Dominik Brodowski4aeba012008-06-20 13:24:31 +0200325 }
326 status->CardState |=
327 (val & SS_WRPROT) ? CS_EVENT_WRITE_PROTECT : 0;
328 status->CardState |=
329 (val & SS_BATDEAD) ? CS_EVENT_BATTERY_DEAD : 0;
330 status->CardState |=
331 (val & SS_BATWARN) ? CS_EVENT_BATTERY_LOW : 0;
332 status->CardState |=
333 (val & SS_READY) ? CS_EVENT_READY_CHANGE : 0;
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200334 return 0;
Dominik Brodowski4aeba012008-06-20 13:24:31 +0200335} /* pccard_get_status */
Dominik Brodowskic5023802008-06-19 19:02:52 +0200336
Roel Kluina0779322008-12-09 22:12:50 +0100337static int pccard_get_configuration_info(struct pcmcia_socket *s,
Dominik Brodowski64f34642008-08-02 17:00:46 +0200338 struct pcmcia_device *p_dev,
339 config_info_t *config)
340{
341 config_t *c;
342
343 if (!(s->state & SOCKET_PRESENT))
Dominik Brodowski3939c1ef2008-08-03 11:10:56 +0200344 return -ENODEV;
Dominik Brodowski64f34642008-08-02 17:00:46 +0200345
346
347#ifdef CONFIG_CARDBUS
348 if (s->state & SOCKET_CARDBUS) {
349 memset(config, 0, sizeof(config_info_t));
350 config->Vcc = s->socket.Vcc;
351 config->Vpp1 = config->Vpp2 = s->socket.Vpp;
352 config->Option = s->cb_dev->subordinate->number;
353 if (s->state & SOCKET_CARDBUS_CONFIG) {
354 config->Attributes = CONF_VALID_CLIENT;
355 config->IntType = INT_CARDBUS;
356 config->AssignedIRQ = s->irq.AssignedIRQ;
357 if (config->AssignedIRQ)
358 config->Attributes |= CONF_ENABLE_IRQ;
359 if (s->io[0].res) {
360 config->BasePort1 = s->io[0].res->start;
361 config->NumPorts1 = s->io[0].res->end -
362 config->BasePort1 + 1;
363 }
364 }
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200365 return 0;
Dominik Brodowski64f34642008-08-02 17:00:46 +0200366 }
367#endif
368
369 if (p_dev) {
370 c = p_dev->function_config;
371 config->Function = p_dev->func;
372 } else {
373 c = NULL;
374 config->Function = 0;
375 }
376
377 if ((c == NULL) || !(c->state & CONFIG_LOCKED)) {
378 config->Attributes = 0;
379 config->Vcc = s->socket.Vcc;
380 config->Vpp1 = config->Vpp2 = s->socket.Vpp;
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200381 return 0;
Dominik Brodowski64f34642008-08-02 17:00:46 +0200382 }
383
384 config->Attributes = c->Attributes | CONF_VALID_CLIENT;
385 config->Vcc = s->socket.Vcc;
386 config->Vpp1 = config->Vpp2 = s->socket.Vpp;
387 config->IntType = c->IntType;
388 config->ConfigBase = c->ConfigBase;
389 config->Status = c->Status;
390 config->Pin = c->Pin;
391 config->Copy = c->Copy;
392 config->Option = c->Option;
393 config->ExtStatus = c->ExtStatus;
394 config->Present = config->CardValues = c->CardValues;
395 config->IRQAttributes = c->irq.Attributes;
396 config->AssignedIRQ = s->irq.AssignedIRQ;
397 config->BasePort1 = c->io.BasePort1;
398 config->NumPorts1 = c->io.NumPorts1;
399 config->Attributes1 = c->io.Attributes1;
400 config->BasePort2 = c->io.BasePort2;
401 config->NumPorts2 = c->io.NumPorts2;
402 config->Attributes2 = c->io.Attributes2;
403 config->IOAddrLines = c->io.IOAddrLines;
404
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200405 return 0;
Dominik Brodowski64f34642008-08-02 17:00:46 +0200406} /* pccard_get_configuration_info */
407
408
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700409/*======================================================================
410
411 These manage a ring buffer of events pending for one user process
412
413======================================================================*/
414
415
416static int queue_empty(user_info_t *user)
417{
418 return (user->event_head == user->event_tail);
419}
420
421static event_t get_queued_event(user_info_t *user)
422{
423 user->event_tail = (user->event_tail+1) % MAX_EVENTS;
424 return user->event[user->event_tail];
425}
426
427static void queue_event(user_info_t *user, event_t event)
428{
429 user->event_head = (user->event_head+1) % MAX_EVENTS;
430 if (user->event_head == user->event_tail)
431 user->event_tail = (user->event_tail+1) % MAX_EVENTS;
432 user->event[user->event_head] = event;
433}
434
Dominik Brodowskidc109492005-06-27 16:28:50 -0700435void handle_event(struct pcmcia_socket *s, event_t event)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700436{
437 user_info_t *user;
438 for (user = s->user; user; user = user->next)
439 queue_event(user, event);
440 wake_up_interruptible(&s->queue);
441}
442
443
444/*======================================================================
445
446 bind_request() and bind_device() are merged by now. Register_client()
447 is called right at the end of bind_request(), during the driver's
448 ->attach() call. Individual descriptions:
449
450 bind_request() connects a socket to a particular client driver.
451 It looks up the specified device ID in the list of registered
452 drivers, binds it to the socket, and tries to create an instance
453 of the device. unbind_request() deletes a driver instance.
454
455 Bind_device() associates a device driver with a particular socket.
456 It is normally called by Driver Services after it has identified
457 a newly inserted card. An instance of that driver will then be
458 eligible to register as a client of this socket.
459
460 Register_client() uses the dev_info_t handle to match the
461 caller with a socket. The driver must have already been bound
462 to a socket with bind_device() -- in fact, bind_device()
463 allocates the client structure that will be used.
464
465======================================================================*/
466
Dominik Brodowskidc109492005-06-27 16:28:50 -0700467static int bind_request(struct pcmcia_socket *s, bind_info_t *bind_info)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700468{
469 struct pcmcia_driver *p_drv;
470 struct pcmcia_device *p_dev;
471 int ret = 0;
472 unsigned long flags;
473
Dominik Brodowskidc109492005-06-27 16:28:50 -0700474 s = pcmcia_get_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700475 if (!s)
476 return -EINVAL;
477
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200478 pr_debug("bind_request(%d, '%s')\n", s->sock,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700479 (char *)bind_info->dev_info);
480
481 p_drv = get_pcmcia_driver(&bind_info->dev_info);
482 if (!p_drv) {
483 ret = -EINVAL;
484 goto err_put;
485 }
486
487 if (!try_module_get(p_drv->owner)) {
488 ret = -EINVAL;
489 goto err_put_driver;
490 }
491
492 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
493 list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
494 if (p_dev->func == bind_info->function) {
495 if ((p_dev->dev.driver == &p_drv->drv)) {
496 if (p_dev->cardmgr) {
497 /* if there's already a device
498 * registered, and it was registered
499 * by userspace before, we need to
500 * return the "instance". */
501 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
Dominik Brodowskifd238232006-03-05 10:45:09 +0100502 bind_info->instance = p_dev;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700503 ret = -EBUSY;
504 goto err_put_module;
505 } else {
506 /* the correct driver managed to bind
507 * itself magically to the correct
508 * device. */
509 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
510 p_dev->cardmgr = p_drv;
511 ret = 0;
512 goto err_put_module;
513 }
514 } else if (!p_dev->dev.driver) {
515 /* there's already a device available where
516 * no device has been bound to yet. So we don't
517 * need to register a device! */
518 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
519 goto rescan;
520 }
521 }
522 }
523 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
524
525 p_dev = pcmcia_device_add(s, bind_info->function);
526 if (!p_dev) {
527 ret = -EIO;
528 goto err_put_module;
529 }
530
531rescan:
532 p_dev->cardmgr = p_drv;
533
534 /* if a driver is already running, we can abort */
535 if (p_dev->dev.driver)
536 goto err_put_module;
537
538 /*
539 * Prevent this racing with a card insertion.
540 */
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100541 mutex_lock(&s->skt_mutex);
Jeff Garzik4deb7c12006-10-20 14:44:23 -0700542 ret = bus_rescan_devices(&pcmcia_bus_type);
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100543 mutex_unlock(&s->skt_mutex);
Jeff Garzik4deb7c12006-10-20 14:44:23 -0700544 if (ret)
545 goto err_put_module;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700546
547 /* check whether the driver indeed matched. I don't care if this
548 * is racy or not, because it can only happen on cardmgr access
549 * paths...
550 */
551 if (!(p_dev->dev.driver == &p_drv->drv))
552 p_dev->cardmgr = NULL;
553
554 err_put_module:
555 module_put(p_drv->owner);
556 err_put_driver:
557 put_driver(&p_drv->drv);
558 err_put:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700559 pcmcia_put_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700560
561 return (ret);
562} /* bind_request */
563
Dominik Brodowski33519dd2005-06-27 16:28:53 -0700564#ifdef CONFIG_CARDBUS
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700565
Dominik Brodowski33519dd2005-06-27 16:28:53 -0700566static struct pci_bus *pcmcia_lookup_bus(struct pcmcia_socket *s)
567{
568 if (!s || !(s->state & SOCKET_CARDBUS))
569 return NULL;
570
571 return s->cb_dev->subordinate;
572}
573#endif
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700574
Dominik Brodowskidc109492005-06-27 16:28:50 -0700575static int get_device_info(struct pcmcia_socket *s, bind_info_t *bind_info, int first)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700576{
577 dev_node_t *node;
578 struct pcmcia_device *p_dev;
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100579 struct pcmcia_driver *p_drv;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700580 unsigned long flags;
581 int ret = 0;
582
583#ifdef CONFIG_CARDBUS
584 /*
585 * Some unbelievably ugly code to associate the PCI cardbus
586 * device and its driver with the PCMCIA "bind" information.
587 */
588 {
589 struct pci_bus *bus;
590
Dominik Brodowskidc109492005-06-27 16:28:50 -0700591 bus = pcmcia_lookup_bus(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700592 if (bus) {
593 struct list_head *list;
594 struct pci_dev *dev = NULL;
595
596 list = bus->devices.next;
597 while (list != &bus->devices) {
598 struct pci_dev *pdev = pci_dev_b(list);
599 list = list->next;
600
601 if (first) {
602 dev = pdev;
603 break;
604 }
605
606 /* Try to handle "next" here some way? */
607 }
608 if (dev && dev->driver) {
609 strlcpy(bind_info->name, dev->driver->name, DEV_NAME_LEN);
610 bind_info->major = 0;
611 bind_info->minor = 0;
612 bind_info->next = NULL;
613 return 0;
614 }
615 }
616 }
617#endif
618
619 spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
620 list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
621 if (p_dev->func == bind_info->function) {
622 p_dev = pcmcia_get_dev(p_dev);
623 if (!p_dev)
624 continue;
625 goto found;
626 }
627 }
628 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
629 return -ENODEV;
630
631 found:
632 spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
633
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100634 p_drv = to_pcmcia_drv(p_dev->dev.driver);
635 if (p_drv && !p_dev->_locked) {
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700636 ret = -EAGAIN;
637 goto err_put;
638 }
639
640 if (first)
Dominik Brodowskifd238232006-03-05 10:45:09 +0100641 node = p_dev->dev_node;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700642 else
Dominik Brodowskifd238232006-03-05 10:45:09 +0100643 for (node = p_dev->dev_node; node; node = node->next)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700644 if (node == bind_info->next)
645 break;
646 if (!node) {
647 ret = -ENODEV;
648 goto err_put;
649 }
650
651 strlcpy(bind_info->name, node->dev_name, DEV_NAME_LEN);
652 bind_info->major = node->major;
653 bind_info->minor = node->minor;
654 bind_info->next = node->next;
655
656 err_put:
657 pcmcia_put_dev(p_dev);
658 return (ret);
659} /* get_device_info */
660
661
662static int ds_open(struct inode *inode, struct file *file)
663{
664 socket_t i = iminor(inode);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700665 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700666 user_info_t *user;
Dominik Brodowskic352ec82005-09-13 01:25:03 -0700667 static int warning_printed = 0;
Jonathan Corbet0bec0bb2008-05-15 09:25:03 -0600668 int ret = 0;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700669
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200670 pr_debug("ds_open(socket %d)\n", i);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700671
Jonathan Corbet0bec0bb2008-05-15 09:25:03 -0600672 lock_kernel();
Dominik Brodowskidc109492005-06-27 16:28:50 -0700673 s = pcmcia_get_socket_by_nr(i);
Jonathan Corbet0bec0bb2008-05-15 09:25:03 -0600674 if (!s) {
675 ret = -ENODEV;
676 goto out;
677 }
Dominik Brodowskidc109492005-06-27 16:28:50 -0700678 s = pcmcia_get_socket(s);
Jonathan Corbet0bec0bb2008-05-15 09:25:03 -0600679 if (!s) {
680 ret = -ENODEV;
681 goto out;
682 }
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700683
684 if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700685 if (s->pcmcia_state.busy) {
Dominik Brodowskidc109492005-06-27 16:28:50 -0700686 pcmcia_put_socket(s);
Jonathan Corbet0bec0bb2008-05-15 09:25:03 -0600687 ret = -EBUSY;
688 goto out;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700689 }
690 else
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700691 s->pcmcia_state.busy = 1;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700692 }
693
694 user = kmalloc(sizeof(user_info_t), GFP_KERNEL);
695 if (!user) {
Dominik Brodowskidc109492005-06-27 16:28:50 -0700696 pcmcia_put_socket(s);
Jonathan Corbet0bec0bb2008-05-15 09:25:03 -0600697 ret = -ENOMEM;
698 goto out;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700699 }
700 user->event_tail = user->event_head = 0;
701 user->next = s->user;
702 user->user_magic = USER_MAGIC;
703 user->socket = s;
704 s->user = user;
705 file->private_data = user;
706
Dominik Brodowskic352ec82005-09-13 01:25:03 -0700707 if (!warning_printed) {
708 printk(KERN_INFO "pcmcia: Detected deprecated PCMCIA ioctl "
Benjamin Herrenschmidt73d58582006-05-15 09:43:53 -0700709 "usage from process: %s.\n", current->comm);
Dominik Brodowskic352ec82005-09-13 01:25:03 -0700710 printk(KERN_INFO "pcmcia: This interface will soon be removed from "
711 "the kernel; please expect breakage unless you upgrade "
712 "to new tools.\n");
713 printk(KERN_INFO "pcmcia: see http://www.kernel.org/pub/linux/"
714 "utils/kernel/pcmcia/pcmcia.html for details.\n");
715 warning_printed = 1;
716 }
717
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700718 if (s->pcmcia_state.present)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700719 queue_event(user, CS_EVENT_CARD_INSERTION);
Jonathan Corbet0bec0bb2008-05-15 09:25:03 -0600720out:
721 unlock_kernel();
722 return ret;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700723} /* ds_open */
724
725/*====================================================================*/
726
727static int ds_release(struct inode *inode, struct file *file)
728{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700729 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700730 user_info_t *user, **link;
731
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200732 pr_debug("ds_release(socket %d)\n", iminor(inode));
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700733
734 user = file->private_data;
735 if (CHECK_USER(user))
736 goto out;
737
738 s = user->socket;
739
740 /* Unlink user data structure */
741 if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700742 s->pcmcia_state.busy = 0;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700743 }
744 file->private_data = NULL;
745 for (link = &s->user; *link; link = &(*link)->next)
746 if (*link == user) break;
747 if (link == NULL)
748 goto out;
749 *link = user->next;
750 user->user_magic = 0;
751 kfree(user);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700752 pcmcia_put_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700753out:
754 return 0;
755} /* ds_release */
756
757/*====================================================================*/
758
759static ssize_t ds_read(struct file *file, char __user *buf,
760 size_t count, loff_t *ppos)
761{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700762 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700763 user_info_t *user;
764 int ret;
765
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200766 pr_debug("ds_read(socket %d)\n", iminor(file->f_path.dentry->d_inode));
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700767
768 if (count < 4)
769 return -EINVAL;
770
771 user = file->private_data;
772 if (CHECK_USER(user))
773 return -EIO;
774
775 s = user->socket;
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700776 if (s->pcmcia_state.dead)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700777 return -EIO;
778
779 ret = wait_event_interruptible(s->queue, !queue_empty(user));
780 if (ret == 0)
781 ret = put_user(get_queued_event(user), (int __user *)buf) ? -EFAULT : 4;
782
783 return ret;
784} /* ds_read */
785
786/*====================================================================*/
787
788static ssize_t ds_write(struct file *file, const char __user *buf,
789 size_t count, loff_t *ppos)
790{
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200791 pr_debug("ds_write(socket %d)\n", iminor(file->f_path.dentry->d_inode));
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700792
793 if (count != 4)
794 return -EINVAL;
795 if ((file->f_flags & O_ACCMODE) == O_RDONLY)
796 return -EBADF;
797
798 return -EIO;
799} /* ds_write */
800
801/*====================================================================*/
802
803/* No kernel lock - fine */
804static u_int ds_poll(struct file *file, poll_table *wait)
805{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700806 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700807 user_info_t *user;
808
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200809 pr_debug("ds_poll(socket %d)\n", iminor(file->f_path.dentry->d_inode));
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700810
811 user = file->private_data;
812 if (CHECK_USER(user))
813 return POLLERR;
814 s = user->socket;
815 /*
816 * We don't check for a dead socket here since that
817 * will send cardmgr into an endless spin.
818 */
819 poll_wait(file, &s->queue, wait);
820 if (!queue_empty(user))
821 return POLLIN | POLLRDNORM;
822 return 0;
823} /* ds_poll */
824
825/*====================================================================*/
826
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700827static int ds_ioctl(struct inode * inode, struct file * file,
828 u_int cmd, u_long arg)
829{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700830 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700831 void __user *uarg = (char __user *)arg;
832 u_int size;
833 int ret, err;
834 ds_ioctl_arg_t *buf;
835 user_info_t *user;
836
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200837 pr_debug("ds_ioctl(socket %d, %#x, %#lx)\n", iminor(inode), cmd, arg);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700838
839 user = file->private_data;
840 if (CHECK_USER(user))
841 return -EIO;
842
843 s = user->socket;
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700844 if (s->pcmcia_state.dead)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700845 return -EIO;
846
847 size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
848 if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL;
849
850 /* Permission check */
851 if (!(cmd & IOC_OUT) && !capable(CAP_SYS_ADMIN))
852 return -EPERM;
853
854 if (cmd & IOC_IN) {
855 if (!access_ok(VERIFY_READ, uarg, size)) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200856 pr_debug("ds_ioctl(): verify_read = %d\n", -EFAULT);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700857 return -EFAULT;
858 }
859 }
860 if (cmd & IOC_OUT) {
861 if (!access_ok(VERIFY_WRITE, uarg, size)) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200862 pr_debug("ds_ioctl(): verify_write = %d\n", -EFAULT);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700863 return -EFAULT;
864 }
865 }
866 buf = kmalloc(sizeof(ds_ioctl_arg_t), GFP_KERNEL);
867 if (!buf)
868 return -ENOMEM;
869
870 err = ret = 0;
871
Dominik Brodowski93740742006-11-19 11:21:27 -0500872 if (cmd & IOC_IN) {
873 if (__copy_from_user((char *)buf, uarg, size)) {
874 err = -EFAULT;
875 goto free_out;
876 }
877 }
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700878
879 switch (cmd) {
880 case DS_ADJUST_RESOURCE_INFO:
881 ret = pcmcia_adjust_resource_info(&buf->adjust);
882 break;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700883 case DS_GET_CONFIGURATION_INFO:
884 if (buf->config.Function &&
Dominik Brodowskidc109492005-06-27 16:28:50 -0700885 (buf->config.Function >= s->functions))
Dominik Brodowski926c5402008-08-03 12:15:11 +0200886 ret = -EINVAL;
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100887 else {
888 struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->config.Function);
Daniel Ritzf47ad212006-07-30 03:03:47 -0700889 ret = pccard_get_configuration_info(s, p_dev, &buf->config);
890 pcmcia_put_dev(p_dev);
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100891 }
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700892 break;
893 case DS_GET_FIRST_TUPLE:
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100894 mutex_lock(&s->skt_mutex);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700895 pcmcia_validate_mem(s);
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100896 mutex_unlock(&s->skt_mutex);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700897 ret = pccard_get_first_tuple(s, BIND_FN_ALL, &buf->tuple);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700898 break;
899 case DS_GET_NEXT_TUPLE:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700900 ret = pccard_get_next_tuple(s, BIND_FN_ALL, &buf->tuple);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700901 break;
902 case DS_GET_TUPLE_DATA:
903 buf->tuple.TupleData = buf->tuple_parse.data;
904 buf->tuple.TupleDataMax = sizeof(buf->tuple_parse.data);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700905 ret = pccard_get_tuple_data(s, &buf->tuple);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700906 break;
907 case DS_PARSE_TUPLE:
908 buf->tuple.TupleData = buf->tuple_parse.data;
Dominik Brodowski2f3061e2008-08-31 15:50:33 +0200909 ret = pcmcia_parse_tuple(&buf->tuple, &buf->tuple_parse.parse);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700910 break;
911 case DS_RESET_CARD:
Dominik Brodowski994917f2008-08-31 15:20:26 +0200912 ret = pcmcia_reset_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700913 break;
914 case DS_GET_STATUS:
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100915 if (buf->status.Function &&
916 (buf->status.Function >= s->functions))
Dominik Brodowski926c5402008-08-03 12:15:11 +0200917 ret = -EINVAL;
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100918 else {
919 struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->status.Function);
Daniel Ritzf47ad212006-07-30 03:03:47 -0700920 ret = pccard_get_status(s, p_dev, &buf->status);
921 pcmcia_put_dev(p_dev);
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100922 }
923 break;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700924 case DS_VALIDATE_CIS:
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100925 mutex_lock(&s->skt_mutex);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700926 pcmcia_validate_mem(s);
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100927 mutex_unlock(&s->skt_mutex);
Dominik Brodowski84897fc2009-10-18 23:51:09 +0200928 ret = pccard_validate_cis(s, &buf->cisinfo.Chains);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700929 break;
930 case DS_SUSPEND_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700931 ret = pcmcia_suspend_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700932 break;
933 case DS_RESUME_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700934 ret = pcmcia_resume_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700935 break;
936 case DS_EJECT_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700937 err = pcmcia_eject_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700938 break;
939 case DS_INSERT_CARD:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700940 err = pcmcia_insert_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700941 break;
942 case DS_ACCESS_CONFIGURATION_REGISTER:
943 if ((buf->conf_reg.Action == CS_WRITE) && !capable(CAP_SYS_ADMIN)) {
944 err = -EPERM;
945 goto free_out;
946 }
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100947
Dominik Brodowski926c5402008-08-03 12:15:11 +0200948 ret = -EINVAL;
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100949
950 if (!(buf->conf_reg.Function &&
951 (buf->conf_reg.Function >= s->functions))) {
952 struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->conf_reg.Function);
Benjamin Herrenschmidt73d58582006-05-15 09:43:53 -0700953 if (p_dev) {
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100954 ret = pcmcia_access_configuration_register(p_dev, &buf->conf_reg);
Benjamin Herrenschmidt73d58582006-05-15 09:43:53 -0700955 pcmcia_put_dev(p_dev);
956 }
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100957 }
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700958 break;
959 case DS_GET_FIRST_REGION:
960 case DS_GET_NEXT_REGION:
961 case DS_BIND_MTD:
962 if (!capable(CAP_SYS_ADMIN)) {
963 err = -EPERM;
964 goto free_out;
965 } else {
Minchan Kima9c56952009-06-16 15:33:44 -0700966 printk_once(KERN_WARNING
967 "2.6. kernels use pcmciamtd instead of memory_cs.c and do not require special\n");
968 printk_once(KERN_WARNING "MTD handling any more.\n");
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700969 }
970 err = -EINVAL;
971 goto free_out;
972 break;
973 case DS_GET_FIRST_WINDOW:
Magnus Damm0bdf9b32006-12-13 19:46:53 +0900974 ret = pcmcia_get_window(s, &buf->win_info.handle, 1,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700975 &buf->win_info.window);
976 break;
977 case DS_GET_NEXT_WINDOW:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700978 ret = pcmcia_get_window(s, &buf->win_info.handle,
Magnus Damm0bdf9b32006-12-13 19:46:53 +0900979 buf->win_info.handle + 1, &buf->win_info.window);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700980 break;
981 case DS_GET_MEM_PAGE:
Magnus Damm16456eb2006-12-13 19:46:48 +0900982 ret = pcmcia_get_mem_page(s, buf->win_info.handle,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700983 &buf->win_info.map);
984 break;
985 case DS_REPLACE_CIS:
Dominik Brodowski53efec92008-07-28 19:44:05 +0200986 ret = pcmcia_replace_cis(s, buf->cisdump.Data, buf->cisdump.Length);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700987 break;
988 case DS_BIND_REQUEST:
989 if (!capable(CAP_SYS_ADMIN)) {
990 err = -EPERM;
991 goto free_out;
992 }
993 err = bind_request(s, &buf->bind_info);
994 break;
995 case DS_GET_DEVICE_INFO:
996 err = get_device_info(s, &buf->bind_info, 1);
997 break;
998 case DS_GET_NEXT_DEVICE:
999 err = get_device_info(s, &buf->bind_info, 0);
1000 break;
1001 case DS_UNBIND_REQUEST:
1002 err = 0;
1003 break;
1004 default:
1005 err = -EINVAL;
1006 }
1007
Dominik Brodowski4c89e882008-08-03 10:07:45 +02001008 if ((err == 0) && (ret != 0)) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +02001009 pr_debug("ds_ioctl: ret = %d\n", ret);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001010 switch (ret) {
Dominik Brodowski610e2372008-08-03 11:58:53 +02001011 case -ENODEV:
1012 case -EINVAL:
1013 case -EBUSY:
1014 case -ENOSYS:
1015 err = ret;
1016 break;
Dominik Brodowski610e2372008-08-03 11:58:53 +02001017 case -ENOMEM:
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001018 err = -ENOSPC; break;
Dominik Brodowski635d19b2008-08-03 11:47:29 +02001019 case -ENOSPC:
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001020 err = -ENODATA; break;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001021 default:
1022 err = -EIO; break;
1023 }
1024 }
1025
1026 if (cmd & IOC_OUT) {
1027 if (__copy_to_user(uarg, (char *)buf, size))
1028 err = -EFAULT;
1029 }
1030
1031free_out:
1032 kfree(buf);
1033 return err;
1034} /* ds_ioctl */
1035
1036/*====================================================================*/
1037
Arjan van de Vend54b1fd2007-02-12 00:55:34 -08001038static const struct file_operations ds_fops = {
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001039 .owner = THIS_MODULE,
1040 .open = ds_open,
1041 .release = ds_release,
1042 .ioctl = ds_ioctl,
1043 .read = ds_read,
1044 .write = ds_write,
1045 .poll = ds_poll,
1046};
1047
1048void __init pcmcia_setup_ioctl(void) {
1049 int i;
1050
1051 /* Set up character device for user mode clients */
1052 i = register_chrdev(0, "pcmcia", &ds_fops);
Dominik Brodowski1a8ceaf2005-06-27 16:29:00 -07001053 if (i < 0)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001054 printk(KERN_NOTICE "unable to find a free device # for "
Dominik Brodowski1a8ceaf2005-06-27 16:29:00 -07001055 "Driver Services (error=%d)\n", i);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001056 else
1057 major_dev = i;
1058
1059#ifdef CONFIG_PROC_FS
akpm@linux-foundation.org97094dc2008-04-29 10:47:54 -07001060 proc_pccard = proc_mkdir("bus/pccard", NULL);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001061 if (proc_pccard)
Alexey Dobriyane6be4a82009-09-21 17:03:55 -07001062 proc_create("drivers", 0, proc_pccard, &pccard_drivers_proc_fops);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001063#endif
1064}
1065
1066
1067void __exit pcmcia_cleanup_ioctl(void) {
1068#ifdef CONFIG_PROC_FS
1069 if (proc_pccard) {
1070 remove_proc_entry("drivers", proc_pccard);
akpm@linux-foundation.org97094dc2008-04-29 10:47:54 -07001071 remove_proc_entry("bus/pccard", NULL);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001072 }
1073#endif
1074 if (major_dev != -1)
1075 unregister_chrdev(major_dev, "pcmcia");
1076}