blob: 7631faa0caddf5e953123bc451915bd8fbde3a71 [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>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090030#include <linux/slab.h>
Alexey Dobriyane6be4a82009-09-21 17:03:55 -070031#include <linux/seq_file.h>
Jonathan Corbet0bec0bb2008-05-15 09:25:03 -060032#include <linux/smp_lock.h>
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070033#include <linux/workqueue.h>
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070034
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070035#include <pcmcia/cs_types.h>
36#include <pcmcia/cs.h>
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070037#include <pcmcia/cistpl.h>
Dominik Brodowski4aeba012008-06-20 13:24:31 +020038#include <pcmcia/cisreg.h>
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070039#include <pcmcia/ds.h>
40#include <pcmcia/ss.h>
41
42#include "cs_internal.h"
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070043
44static int major_dev = -1;
45
46
47/* Device user information */
48#define MAX_EVENTS 32
49#define USER_MAGIC 0x7ea4
50#define CHECK_USER(u) \
51 (((u) == NULL) || ((u)->user_magic != USER_MAGIC))
52
53typedef struct user_info_t {
54 u_int user_magic;
55 int event_head, event_tail;
56 event_t event[MAX_EVENTS];
57 struct user_info_t *next;
Dominik Brodowskidc109492005-06-27 16:28:50 -070058 struct pcmcia_socket *socket;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -070059} user_info_t;
60
61
Dominik Brodowski855cdf12006-01-10 20:48:59 +010062static struct pcmcia_device *get_pcmcia_device(struct pcmcia_socket *s,
63 unsigned int function)
64{
65 struct pcmcia_device *p_dev = NULL;
Dominik Brodowski855cdf12006-01-10 20:48:59 +010066
Dominik Brodowski00ce99f2010-01-16 09:14:11 +010067 mutex_lock(&s->ops_mutex);
Dominik Brodowski855cdf12006-01-10 20:48:59 +010068 list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
69 if (p_dev->func == function) {
Dominik Brodowski00ce99f2010-01-16 09:14:11 +010070 mutex_unlock(&s->ops_mutex);
Dominik Brodowski855cdf12006-01-10 20:48:59 +010071 return pcmcia_get_dev(p_dev);
72 }
73 }
Dominik Brodowski00ce99f2010-01-16 09:14:11 +010074 mutex_unlock(&s->ops_mutex);
Dominik Brodowski855cdf12006-01-10 20:48:59 +010075 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
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 */
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100184 mutex_lock(&s->ops_mutex);
Dominik Brodowskic5023802008-06-19 19:02:52 +0200185 if ((s->resource_setup_new) &&
186 !(s->resource_setup_old)) {
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100187 mutex_unlock(&s->ops_mutex);
Dominik Brodowskic5023802008-06-19 19:02:52 +0200188 continue;
189 } else if (!(s->resource_setup_old))
190 s->resource_setup_old = 1;
Dominik Brodowskic5023802008-06-19 19:02:52 +0200191
192 switch (adj->Resource) {
193 case RES_MEMORY_RANGE:
194 begin = adj->resource.memory.Base;
195 end = adj->resource.memory.Base + adj->resource.memory.Size - 1;
196 if (s->resource_ops->add_mem)
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100197 ret = s->resource_ops->add_mem(s, adj->Action, begin, end);
Dominik Brodowskic5023802008-06-19 19:02:52 +0200198 case RES_IO_RANGE:
199 begin = adj->resource.io.BasePort;
200 end = adj->resource.io.BasePort + adj->resource.io.NumPorts - 1;
201 if (s->resource_ops->add_io)
202 ret = s->resource_ops->add_io(s, adj->Action, begin, end);
203 }
204 if (!ret) {
205 /* as there's no way we know this is the
206 * last call to adjust_resource_info, we
207 * always need to assume this is the latest
208 * one... */
Dominik Brodowskic5023802008-06-19 19:02:52 +0200209 s->resource_setup_done = 1;
Dominik Brodowskic5023802008-06-19 19:02:52 +0200210 }
Dominik Brodowskicfe5d802010-01-17 19:31:45 +0100211 mutex_unlock(&s->ops_mutex);
Dominik Brodowskic5023802008-06-19 19:02:52 +0200212 }
213 }
214 up_read(&pcmcia_socket_list_rwsem);
215
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100216 return ret;
Dominik Brodowskic5023802008-06-19 19:02:52 +0200217}
218
Dominik Brodowskid7b03642009-11-03 01:05:33 +0100219
220/** pcmcia_get_window
221 */
222static int pcmcia_get_window(struct pcmcia_socket *s, window_handle_t *wh_out,
223 window_handle_t wh, win_req_t *req)
224{
Dominik Brodowski82f88e32009-11-03 01:16:12 +0100225 pccard_mem_map *win;
Dominik Brodowskid7b03642009-11-03 01:05:33 +0100226 window_handle_t w;
227
228 wh--;
229 if (!s || !(s->state & SOCKET_PRESENT))
230 return -ENODEV;
231 if (wh >= MAX_WIN)
232 return -EINVAL;
233 for (w = wh; w < MAX_WIN; w++)
234 if (s->state & SOCKET_WIN_REQ(w))
235 break;
236 if (w == MAX_WIN)
237 return -EINVAL;
238 win = &s->win[w];
Dominik Brodowski82f88e32009-11-03 01:16:12 +0100239 req->Base = win->res->start;
240 req->Size = win->res->end - win->res->start + 1;
241 req->AccessSpeed = win->speed;
Dominik Brodowskid7b03642009-11-03 01:05:33 +0100242 req->Attributes = 0;
Dominik Brodowski82f88e32009-11-03 01:16:12 +0100243 if (win->flags & MAP_ATTRIB)
Dominik Brodowskid7b03642009-11-03 01:05:33 +0100244 req->Attributes |= WIN_MEMORY_TYPE_AM;
Dominik Brodowski82f88e32009-11-03 01:16:12 +0100245 if (win->flags & MAP_ACTIVE)
Dominik Brodowskid7b03642009-11-03 01:05:33 +0100246 req->Attributes |= WIN_ENABLE;
Dominik Brodowski82f88e32009-11-03 01:16:12 +0100247 if (win->flags & MAP_16BIT)
Dominik Brodowskid7b03642009-11-03 01:05:33 +0100248 req->Attributes |= WIN_DATA_WIDTH_16;
Dominik Brodowski82f88e32009-11-03 01:16:12 +0100249 if (win->flags & MAP_USE_WAIT)
Dominik Brodowskid7b03642009-11-03 01:05:33 +0100250 req->Attributes |= WIN_USE_WAIT;
251
252 *wh_out = w + 1;
253 return 0;
254} /* pcmcia_get_window */
255
256
257/** pcmcia_get_mem_page
258 *
259 * Change the card address of an already open memory window.
260 */
261static int pcmcia_get_mem_page(struct pcmcia_socket *skt, window_handle_t wh,
262 memreq_t *req)
263{
264 wh--;
265 if (wh >= MAX_WIN)
266 return -EINVAL;
267
268 req->Page = 0;
Dominik Brodowski82f88e32009-11-03 01:16:12 +0100269 req->CardOffset = skt->win[wh].card_start;
Dominik Brodowskid7b03642009-11-03 01:05:33 +0100270 return 0;
271} /* pcmcia_get_mem_page */
272
273
Dominik Brodowski4aeba012008-06-20 13:24:31 +0200274/** pccard_get_status
275 *
276 * Get the current socket state bits. We don't support the latched
277 * SocketState yet: I haven't seen any point for it.
278 */
279
280static int pccard_get_status(struct pcmcia_socket *s,
281 struct pcmcia_device *p_dev,
282 cs_status_t *status)
283{
284 config_t *c;
285 int val;
286
287 s->ops->get_status(s, &val);
288 status->CardState = status->SocketState = 0;
289 status->CardState |= (val & SS_DETECT) ? CS_EVENT_CARD_DETECT : 0;
290 status->CardState |= (val & SS_CARDBUS) ? CS_EVENT_CB_DETECT : 0;
291 status->CardState |= (val & SS_3VCARD) ? CS_EVENT_3VCARD : 0;
292 status->CardState |= (val & SS_XVCARD) ? CS_EVENT_XVCARD : 0;
293 if (s->state & SOCKET_SUSPEND)
294 status->CardState |= CS_EVENT_PM_SUSPEND;
295 if (!(s->state & SOCKET_PRESENT))
Dominik Brodowski3939c1ef2008-08-03 11:10:56 +0200296 return -ENODEV;
Dominik Brodowski4aeba012008-06-20 13:24:31 +0200297
298 c = (p_dev) ? p_dev->function_config : NULL;
299
300 if ((c != NULL) && (c->state & CONFIG_LOCKED) &&
301 (c->IntType & (INT_MEMORY_AND_IO | INT_ZOOMED_VIDEO))) {
302 u_char reg;
303 if (c->CardValues & PRESENT_PIN_REPLACE) {
304 pcmcia_read_cis_mem(s, 1, (c->ConfigBase+CISREG_PRR)>>1, 1, &reg);
305 status->CardState |=
306 (reg & PRR_WP_STATUS) ? CS_EVENT_WRITE_PROTECT : 0;
307 status->CardState |=
308 (reg & PRR_READY_STATUS) ? CS_EVENT_READY_CHANGE : 0;
309 status->CardState |=
310 (reg & PRR_BVD2_STATUS) ? CS_EVENT_BATTERY_LOW : 0;
311 status->CardState |=
312 (reg & PRR_BVD1_STATUS) ? CS_EVENT_BATTERY_DEAD : 0;
313 } else {
314 /* No PRR? Then assume we're always ready */
315 status->CardState |= CS_EVENT_READY_CHANGE;
316 }
317 if (c->CardValues & PRESENT_EXT_STATUS) {
318 pcmcia_read_cis_mem(s, 1, (c->ConfigBase+CISREG_ESR)>>1, 1, &reg);
319 status->CardState |=
320 (reg & ESR_REQ_ATTN) ? CS_EVENT_REQUEST_ATTENTION : 0;
321 }
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200322 return 0;
Dominik Brodowski4aeba012008-06-20 13:24:31 +0200323 }
324 status->CardState |=
325 (val & SS_WRPROT) ? CS_EVENT_WRITE_PROTECT : 0;
326 status->CardState |=
327 (val & SS_BATDEAD) ? CS_EVENT_BATTERY_DEAD : 0;
328 status->CardState |=
329 (val & SS_BATWARN) ? CS_EVENT_BATTERY_LOW : 0;
330 status->CardState |=
331 (val & SS_READY) ? CS_EVENT_READY_CHANGE : 0;
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200332 return 0;
Dominik Brodowski4aeba012008-06-20 13:24:31 +0200333} /* pccard_get_status */
Dominik Brodowskic5023802008-06-19 19:02:52 +0200334
Roel Kluina0779322008-12-09 22:12:50 +0100335static int pccard_get_configuration_info(struct pcmcia_socket *s,
Dominik Brodowski64f34642008-08-02 17:00:46 +0200336 struct pcmcia_device *p_dev,
337 config_info_t *config)
338{
339 config_t *c;
340
341 if (!(s->state & SOCKET_PRESENT))
Dominik Brodowski3939c1ef2008-08-03 11:10:56 +0200342 return -ENODEV;
Dominik Brodowski64f34642008-08-02 17:00:46 +0200343
344
345#ifdef CONFIG_CARDBUS
346 if (s->state & SOCKET_CARDBUS) {
347 memset(config, 0, sizeof(config_info_t));
348 config->Vcc = s->socket.Vcc;
349 config->Vpp1 = config->Vpp2 = s->socket.Vpp;
350 config->Option = s->cb_dev->subordinate->number;
351 if (s->state & SOCKET_CARDBUS_CONFIG) {
352 config->Attributes = CONF_VALID_CLIENT;
353 config->IntType = INT_CARDBUS;
354 config->AssignedIRQ = s->irq.AssignedIRQ;
355 if (config->AssignedIRQ)
356 config->Attributes |= CONF_ENABLE_IRQ;
357 if (s->io[0].res) {
358 config->BasePort1 = s->io[0].res->start;
359 config->NumPorts1 = s->io[0].res->end -
360 config->BasePort1 + 1;
361 }
362 }
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200363 return 0;
Dominik Brodowski64f34642008-08-02 17:00:46 +0200364 }
365#endif
366
367 if (p_dev) {
368 c = p_dev->function_config;
369 config->Function = p_dev->func;
370 } else {
371 c = NULL;
372 config->Function = 0;
373 }
374
375 if ((c == NULL) || !(c->state & CONFIG_LOCKED)) {
376 config->Attributes = 0;
377 config->Vcc = s->socket.Vcc;
378 config->Vpp1 = config->Vpp2 = s->socket.Vpp;
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200379 return 0;
Dominik Brodowski64f34642008-08-02 17:00:46 +0200380 }
381
382 config->Attributes = c->Attributes | CONF_VALID_CLIENT;
383 config->Vcc = s->socket.Vcc;
384 config->Vpp1 = config->Vpp2 = s->socket.Vpp;
385 config->IntType = c->IntType;
386 config->ConfigBase = c->ConfigBase;
387 config->Status = c->Status;
388 config->Pin = c->Pin;
389 config->Copy = c->Copy;
390 config->Option = c->Option;
391 config->ExtStatus = c->ExtStatus;
392 config->Present = config->CardValues = c->CardValues;
393 config->IRQAttributes = c->irq.Attributes;
394 config->AssignedIRQ = s->irq.AssignedIRQ;
395 config->BasePort1 = c->io.BasePort1;
396 config->NumPorts1 = c->io.NumPorts1;
397 config->Attributes1 = c->io.Attributes1;
398 config->BasePort2 = c->io.BasePort2;
399 config->NumPorts2 = c->io.NumPorts2;
400 config->Attributes2 = c->io.Attributes2;
401 config->IOAddrLines = c->io.IOAddrLines;
402
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200403 return 0;
Dominik Brodowski64f34642008-08-02 17:00:46 +0200404} /* pccard_get_configuration_info */
405
406
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700407/*======================================================================
408
409 These manage a ring buffer of events pending for one user process
410
411======================================================================*/
412
413
414static int queue_empty(user_info_t *user)
415{
416 return (user->event_head == user->event_tail);
417}
418
419static event_t get_queued_event(user_info_t *user)
420{
421 user->event_tail = (user->event_tail+1) % MAX_EVENTS;
422 return user->event[user->event_tail];
423}
424
425static void queue_event(user_info_t *user, event_t event)
426{
427 user->event_head = (user->event_head+1) % MAX_EVENTS;
428 if (user->event_head == user->event_tail)
429 user->event_tail = (user->event_tail+1) % MAX_EVENTS;
430 user->event[user->event_head] = event;
431}
432
Dominik Brodowskidc109492005-06-27 16:28:50 -0700433void handle_event(struct pcmcia_socket *s, event_t event)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700434{
435 user_info_t *user;
436 for (user = s->user; user; user = user->next)
437 queue_event(user, event);
438 wake_up_interruptible(&s->queue);
439}
440
441
442/*======================================================================
443
444 bind_request() and bind_device() are merged by now. Register_client()
445 is called right at the end of bind_request(), during the driver's
446 ->attach() call. Individual descriptions:
447
448 bind_request() connects a socket to a particular client driver.
449 It looks up the specified device ID in the list of registered
450 drivers, binds it to the socket, and tries to create an instance
451 of the device. unbind_request() deletes a driver instance.
452
453 Bind_device() associates a device driver with a particular socket.
454 It is normally called by Driver Services after it has identified
455 a newly inserted card. An instance of that driver will then be
456 eligible to register as a client of this socket.
457
458 Register_client() uses the dev_info_t handle to match the
459 caller with a socket. The driver must have already been bound
460 to a socket with bind_device() -- in fact, bind_device()
461 allocates the client structure that will be used.
462
463======================================================================*/
464
Dominik Brodowskidc109492005-06-27 16:28:50 -0700465static int bind_request(struct pcmcia_socket *s, bind_info_t *bind_info)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700466{
467 struct pcmcia_driver *p_drv;
468 struct pcmcia_device *p_dev;
469 int ret = 0;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700470
Dominik Brodowskidc109492005-06-27 16:28:50 -0700471 s = pcmcia_get_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700472 if (!s)
473 return -EINVAL;
474
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200475 pr_debug("bind_request(%d, '%s')\n", s->sock,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700476 (char *)bind_info->dev_info);
477
478 p_drv = get_pcmcia_driver(&bind_info->dev_info);
479 if (!p_drv) {
480 ret = -EINVAL;
481 goto err_put;
482 }
483
484 if (!try_module_get(p_drv->owner)) {
485 ret = -EINVAL;
486 goto err_put_driver;
487 }
488
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100489 mutex_lock(&s->ops_mutex);
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100490 list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700491 if (p_dev->func == bind_info->function) {
492 if ((p_dev->dev.driver == &p_drv->drv)) {
493 if (p_dev->cardmgr) {
494 /* if there's already a device
495 * registered, and it was registered
496 * by userspace before, we need to
497 * return the "instance". */
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100498 mutex_unlock(&s->ops_mutex);
Dominik Brodowskifd238232006-03-05 10:45:09 +0100499 bind_info->instance = p_dev;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700500 ret = -EBUSY;
501 goto err_put_module;
502 } else {
503 /* the correct driver managed to bind
504 * itself magically to the correct
505 * device. */
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100506 mutex_unlock(&s->ops_mutex);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700507 p_dev->cardmgr = p_drv;
508 ret = 0;
509 goto err_put_module;
510 }
511 } else if (!p_dev->dev.driver) {
512 /* there's already a device available where
513 * no device has been bound to yet. So we don't
514 * need to register a device! */
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100515 mutex_unlock(&s->ops_mutex);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700516 goto rescan;
517 }
518 }
519 }
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100520 mutex_unlock(&s->ops_mutex);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700521
522 p_dev = pcmcia_device_add(s, bind_info->function);
523 if (!p_dev) {
524 ret = -EIO;
525 goto err_put_module;
526 }
527
528rescan:
529 p_dev->cardmgr = p_drv;
530
531 /* if a driver is already running, we can abort */
532 if (p_dev->dev.driver)
533 goto err_put_module;
534
535 /*
536 * Prevent this racing with a card insertion.
537 */
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100538 mutex_lock(&s->skt_mutex);
Jeff Garzik4deb7c12006-10-20 14:44:23 -0700539 ret = bus_rescan_devices(&pcmcia_bus_type);
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100540 mutex_unlock(&s->skt_mutex);
Jeff Garzik4deb7c12006-10-20 14:44:23 -0700541 if (ret)
542 goto err_put_module;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700543
544 /* check whether the driver indeed matched. I don't care if this
545 * is racy or not, because it can only happen on cardmgr access
546 * paths...
547 */
548 if (!(p_dev->dev.driver == &p_drv->drv))
549 p_dev->cardmgr = NULL;
550
551 err_put_module:
552 module_put(p_drv->owner);
553 err_put_driver:
554 put_driver(&p_drv->drv);
555 err_put:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700556 pcmcia_put_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700557
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100558 return ret;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700559} /* bind_request */
560
Dominik Brodowski33519dd2005-06-27 16:28:53 -0700561#ifdef CONFIG_CARDBUS
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700562
Dominik Brodowski33519dd2005-06-27 16:28:53 -0700563static struct pci_bus *pcmcia_lookup_bus(struct pcmcia_socket *s)
564{
565 if (!s || !(s->state & SOCKET_CARDBUS))
566 return NULL;
567
568 return s->cb_dev->subordinate;
569}
570#endif
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700571
Dominik Brodowskidc109492005-06-27 16:28:50 -0700572static int get_device_info(struct pcmcia_socket *s, bind_info_t *bind_info, int first)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700573{
574 dev_node_t *node;
575 struct pcmcia_device *p_dev;
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100576 struct pcmcia_driver *p_drv;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700577 int ret = 0;
578
579#ifdef CONFIG_CARDBUS
580 /*
581 * Some unbelievably ugly code to associate the PCI cardbus
582 * device and its driver with the PCMCIA "bind" information.
583 */
584 {
585 struct pci_bus *bus;
586
Dominik Brodowskidc109492005-06-27 16:28:50 -0700587 bus = pcmcia_lookup_bus(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700588 if (bus) {
589 struct list_head *list;
590 struct pci_dev *dev = NULL;
591
592 list = bus->devices.next;
593 while (list != &bus->devices) {
594 struct pci_dev *pdev = pci_dev_b(list);
595 list = list->next;
596
597 if (first) {
598 dev = pdev;
599 break;
600 }
601
602 /* Try to handle "next" here some way? */
603 }
604 if (dev && dev->driver) {
605 strlcpy(bind_info->name, dev->driver->name, DEV_NAME_LEN);
606 bind_info->major = 0;
607 bind_info->minor = 0;
608 bind_info->next = NULL;
609 return 0;
610 }
611 }
612 }
613#endif
614
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100615 mutex_lock(&s->ops_mutex);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700616 list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
617 if (p_dev->func == bind_info->function) {
618 p_dev = pcmcia_get_dev(p_dev);
619 if (!p_dev)
620 continue;
621 goto found;
622 }
623 }
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100624 mutex_unlock(&s->ops_mutex);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700625 return -ENODEV;
626
627 found:
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100628 mutex_unlock(&s->ops_mutex);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700629
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100630 p_drv = to_pcmcia_drv(p_dev->dev.driver);
631 if (p_drv && !p_dev->_locked) {
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700632 ret = -EAGAIN;
633 goto err_put;
634 }
635
636 if (first)
Dominik Brodowskifd238232006-03-05 10:45:09 +0100637 node = p_dev->dev_node;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700638 else
Dominik Brodowskifd238232006-03-05 10:45:09 +0100639 for (node = p_dev->dev_node; node; node = node->next)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700640 if (node == bind_info->next)
641 break;
642 if (!node) {
643 ret = -ENODEV;
644 goto err_put;
645 }
646
647 strlcpy(bind_info->name, node->dev_name, DEV_NAME_LEN);
648 bind_info->major = node->major;
649 bind_info->minor = node->minor;
650 bind_info->next = node->next;
651
652 err_put:
653 pcmcia_put_dev(p_dev);
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100654 return ret;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700655} /* get_device_info */
656
657
658static int ds_open(struct inode *inode, struct file *file)
659{
660 socket_t i = iminor(inode);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700661 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700662 user_info_t *user;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100663 static int warning_printed;
Jonathan Corbet0bec0bb2008-05-15 09:25:03 -0600664 int ret = 0;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700665
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200666 pr_debug("ds_open(socket %d)\n", i);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700667
Jonathan Corbet0bec0bb2008-05-15 09:25:03 -0600668 lock_kernel();
Dominik Brodowskidc109492005-06-27 16:28:50 -0700669 s = pcmcia_get_socket_by_nr(i);
Jonathan Corbet0bec0bb2008-05-15 09:25:03 -0600670 if (!s) {
671 ret = -ENODEV;
672 goto out;
673 }
Dominik Brodowskidc109492005-06-27 16:28:50 -0700674 s = pcmcia_get_socket(s);
Jonathan Corbet0bec0bb2008-05-15 09:25:03 -0600675 if (!s) {
676 ret = -ENODEV;
677 goto out;
678 }
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700679
680 if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700681 if (s->pcmcia_state.busy) {
Dominik Brodowskidc109492005-06-27 16:28:50 -0700682 pcmcia_put_socket(s);
Jonathan Corbet0bec0bb2008-05-15 09:25:03 -0600683 ret = -EBUSY;
684 goto out;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700685 }
686 else
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700687 s->pcmcia_state.busy = 1;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700688 }
689
690 user = kmalloc(sizeof(user_info_t), GFP_KERNEL);
691 if (!user) {
Dominik Brodowskidc109492005-06-27 16:28:50 -0700692 pcmcia_put_socket(s);
Jonathan Corbet0bec0bb2008-05-15 09:25:03 -0600693 ret = -ENOMEM;
694 goto out;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700695 }
696 user->event_tail = user->event_head = 0;
697 user->next = s->user;
698 user->user_magic = USER_MAGIC;
699 user->socket = s;
700 s->user = user;
701 file->private_data = user;
702
Dominik Brodowskic352ec82005-09-13 01:25:03 -0700703 if (!warning_printed) {
704 printk(KERN_INFO "pcmcia: Detected deprecated PCMCIA ioctl "
Benjamin Herrenschmidt73d58582006-05-15 09:43:53 -0700705 "usage from process: %s.\n", current->comm);
Dominik Brodowskic352ec82005-09-13 01:25:03 -0700706 printk(KERN_INFO "pcmcia: This interface will soon be removed from "
707 "the kernel; please expect breakage unless you upgrade "
708 "to new tools.\n");
709 printk(KERN_INFO "pcmcia: see http://www.kernel.org/pub/linux/"
710 "utils/kernel/pcmcia/pcmcia.html for details.\n");
711 warning_printed = 1;
712 }
713
Marc Zyngier15d0a872010-05-04 13:33:54 +0200714 if (atomic_read(&s->present))
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700715 queue_event(user, CS_EVENT_CARD_INSERTION);
Jonathan Corbet0bec0bb2008-05-15 09:25:03 -0600716out:
717 unlock_kernel();
718 return ret;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700719} /* ds_open */
720
721/*====================================================================*/
722
723static int ds_release(struct inode *inode, struct file *file)
724{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700725 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700726 user_info_t *user, **link;
727
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200728 pr_debug("ds_release(socket %d)\n", iminor(inode));
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700729
730 user = file->private_data;
731 if (CHECK_USER(user))
732 goto out;
733
734 s = user->socket;
735
736 /* Unlink user data structure */
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100737 if ((file->f_flags & O_ACCMODE) != O_RDONLY)
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700738 s->pcmcia_state.busy = 0;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100739
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700740 file->private_data = NULL;
741 for (link = &s->user; *link; link = &(*link)->next)
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100742 if (*link == user)
743 break;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700744 if (link == NULL)
745 goto out;
746 *link = user->next;
747 user->user_magic = 0;
748 kfree(user);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700749 pcmcia_put_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700750out:
751 return 0;
752} /* ds_release */
753
754/*====================================================================*/
755
756static ssize_t ds_read(struct file *file, char __user *buf,
757 size_t count, loff_t *ppos)
758{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700759 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700760 user_info_t *user;
761 int ret;
762
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200763 pr_debug("ds_read(socket %d)\n", iminor(file->f_path.dentry->d_inode));
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700764
765 if (count < 4)
766 return -EINVAL;
767
768 user = file->private_data;
769 if (CHECK_USER(user))
770 return -EIO;
771
772 s = user->socket;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700773 ret = wait_event_interruptible(s->queue, !queue_empty(user));
774 if (ret == 0)
775 ret = put_user(get_queued_event(user), (int __user *)buf) ? -EFAULT : 4;
776
777 return ret;
778} /* ds_read */
779
780/*====================================================================*/
781
782static ssize_t ds_write(struct file *file, const char __user *buf,
783 size_t count, loff_t *ppos)
784{
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200785 pr_debug("ds_write(socket %d)\n", iminor(file->f_path.dentry->d_inode));
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700786
787 if (count != 4)
788 return -EINVAL;
789 if ((file->f_flags & O_ACCMODE) == O_RDONLY)
790 return -EBADF;
791
792 return -EIO;
793} /* ds_write */
794
795/*====================================================================*/
796
797/* No kernel lock - fine */
798static u_int ds_poll(struct file *file, poll_table *wait)
799{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700800 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700801 user_info_t *user;
802
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200803 pr_debug("ds_poll(socket %d)\n", iminor(file->f_path.dentry->d_inode));
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700804
805 user = file->private_data;
806 if (CHECK_USER(user))
807 return POLLERR;
808 s = user->socket;
809 /*
810 * We don't check for a dead socket here since that
811 * will send cardmgr into an endless spin.
812 */
813 poll_wait(file, &s->queue, wait);
814 if (!queue_empty(user))
815 return POLLIN | POLLRDNORM;
816 return 0;
817} /* ds_poll */
818
819/*====================================================================*/
820
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100821static int ds_ioctl(struct inode *inode, struct file *file,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700822 u_int cmd, u_long arg)
823{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700824 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700825 void __user *uarg = (char __user *)arg;
826 u_int size;
827 int ret, err;
828 ds_ioctl_arg_t *buf;
829 user_info_t *user;
830
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200831 pr_debug("ds_ioctl(socket %d, %#x, %#lx)\n", iminor(inode), cmd, arg);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700832
833 user = file->private_data;
834 if (CHECK_USER(user))
835 return -EIO;
836
837 s = user->socket;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700838
839 size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100840 if (size > sizeof(ds_ioctl_arg_t))
841 return -EINVAL;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700842
843 /* Permission check */
844 if (!(cmd & IOC_OUT) && !capable(CAP_SYS_ADMIN))
845 return -EPERM;
846
847 if (cmd & IOC_IN) {
848 if (!access_ok(VERIFY_READ, uarg, size)) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200849 pr_debug("ds_ioctl(): verify_read = %d\n", -EFAULT);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700850 return -EFAULT;
851 }
852 }
853 if (cmd & IOC_OUT) {
854 if (!access_ok(VERIFY_WRITE, uarg, size)) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200855 pr_debug("ds_ioctl(): verify_write = %d\n", -EFAULT);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700856 return -EFAULT;
857 }
858 }
859 buf = kmalloc(sizeof(ds_ioctl_arg_t), GFP_KERNEL);
860 if (!buf)
861 return -ENOMEM;
862
863 err = ret = 0;
864
Dominik Brodowski93740742006-11-19 11:21:27 -0500865 if (cmd & IOC_IN) {
866 if (__copy_from_user((char *)buf, uarg, size)) {
867 err = -EFAULT;
868 goto free_out;
869 }
870 }
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700871
872 switch (cmd) {
873 case DS_ADJUST_RESOURCE_INFO:
874 ret = pcmcia_adjust_resource_info(&buf->adjust);
875 break;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700876 case DS_GET_CONFIGURATION_INFO:
877 if (buf->config.Function &&
Dominik Brodowskidc109492005-06-27 16:28:50 -0700878 (buf->config.Function >= s->functions))
Dominik Brodowski926c5402008-08-03 12:15:11 +0200879 ret = -EINVAL;
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100880 else {
881 struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->config.Function);
Daniel Ritzf47ad212006-07-30 03:03:47 -0700882 ret = pccard_get_configuration_info(s, p_dev, &buf->config);
883 pcmcia_put_dev(p_dev);
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100884 }
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700885 break;
886 case DS_GET_FIRST_TUPLE:
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100887 mutex_lock(&s->skt_mutex);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700888 pcmcia_validate_mem(s);
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100889 mutex_unlock(&s->skt_mutex);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700890 ret = pccard_get_first_tuple(s, BIND_FN_ALL, &buf->tuple);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700891 break;
892 case DS_GET_NEXT_TUPLE:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700893 ret = pccard_get_next_tuple(s, BIND_FN_ALL, &buf->tuple);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700894 break;
895 case DS_GET_TUPLE_DATA:
896 buf->tuple.TupleData = buf->tuple_parse.data;
897 buf->tuple.TupleDataMax = sizeof(buf->tuple_parse.data);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700898 ret = pccard_get_tuple_data(s, &buf->tuple);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700899 break;
900 case DS_PARSE_TUPLE:
901 buf->tuple.TupleData = buf->tuple_parse.data;
Dominik Brodowski2f3061e2008-08-31 15:50:33 +0200902 ret = pcmcia_parse_tuple(&buf->tuple, &buf->tuple_parse.parse);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700903 break;
904 case DS_RESET_CARD:
Dominik Brodowski994917f2008-08-31 15:20:26 +0200905 ret = pcmcia_reset_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700906 break;
907 case DS_GET_STATUS:
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100908 if (buf->status.Function &&
909 (buf->status.Function >= s->functions))
Dominik Brodowski926c5402008-08-03 12:15:11 +0200910 ret = -EINVAL;
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100911 else {
912 struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->status.Function);
Daniel Ritzf47ad212006-07-30 03:03:47 -0700913 ret = pccard_get_status(s, p_dev, &buf->status);
914 pcmcia_put_dev(p_dev);
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100915 }
916 break;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700917 case DS_VALIDATE_CIS:
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100918 mutex_lock(&s->skt_mutex);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700919 pcmcia_validate_mem(s);
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100920 mutex_unlock(&s->skt_mutex);
Dominik Brodowski84897fc2009-10-18 23:51:09 +0200921 ret = pccard_validate_cis(s, &buf->cisinfo.Chains);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700922 break;
923 case DS_SUSPEND_CARD:
Dominik Brodowskif971dbd2010-01-17 18:13:31 +0100924 pcmcia_parse_uevents(s, PCMCIA_UEVENT_SUSPEND);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700925 break;
926 case DS_RESUME_CARD:
Dominik Brodowskif971dbd2010-01-17 18:13:31 +0100927 pcmcia_parse_uevents(s, PCMCIA_UEVENT_RESUME);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700928 break;
929 case DS_EJECT_CARD:
Dominik Brodowskif971dbd2010-01-17 18:13:31 +0100930 pcmcia_parse_uevents(s, PCMCIA_UEVENT_EJECT);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700931 break;
932 case DS_INSERT_CARD:
Dominik Brodowskif971dbd2010-01-17 18:13:31 +0100933 pcmcia_parse_uevents(s, PCMCIA_UEVENT_INSERT);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700934 break;
935 case DS_ACCESS_CONFIGURATION_REGISTER:
936 if ((buf->conf_reg.Action == CS_WRITE) && !capable(CAP_SYS_ADMIN)) {
937 err = -EPERM;
938 goto free_out;
939 }
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100940
Dominik Brodowski926c5402008-08-03 12:15:11 +0200941 ret = -EINVAL;
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100942
943 if (!(buf->conf_reg.Function &&
944 (buf->conf_reg.Function >= s->functions))) {
945 struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->conf_reg.Function);
Benjamin Herrenschmidt73d58582006-05-15 09:43:53 -0700946 if (p_dev) {
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100947 ret = pcmcia_access_configuration_register(p_dev, &buf->conf_reg);
Benjamin Herrenschmidt73d58582006-05-15 09:43:53 -0700948 pcmcia_put_dev(p_dev);
949 }
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100950 }
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700951 break;
952 case DS_GET_FIRST_REGION:
953 case DS_GET_NEXT_REGION:
954 case DS_BIND_MTD:
955 if (!capable(CAP_SYS_ADMIN)) {
956 err = -EPERM;
957 goto free_out;
958 } else {
Minchan Kima9c56952009-06-16 15:33:44 -0700959 printk_once(KERN_WARNING
960 "2.6. kernels use pcmciamtd instead of memory_cs.c and do not require special\n");
961 printk_once(KERN_WARNING "MTD handling any more.\n");
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700962 }
963 err = -EINVAL;
964 goto free_out;
965 break;
966 case DS_GET_FIRST_WINDOW:
Magnus Damm0bdf9b32006-12-13 19:46:53 +0900967 ret = pcmcia_get_window(s, &buf->win_info.handle, 1,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700968 &buf->win_info.window);
969 break;
970 case DS_GET_NEXT_WINDOW:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700971 ret = pcmcia_get_window(s, &buf->win_info.handle,
Magnus Damm0bdf9b32006-12-13 19:46:53 +0900972 buf->win_info.handle + 1, &buf->win_info.window);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700973 break;
974 case DS_GET_MEM_PAGE:
Magnus Damm16456eb2006-12-13 19:46:48 +0900975 ret = pcmcia_get_mem_page(s, buf->win_info.handle,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700976 &buf->win_info.map);
977 break;
978 case DS_REPLACE_CIS:
Dominik Brodowski53efec92008-07-28 19:44:05 +0200979 ret = pcmcia_replace_cis(s, buf->cisdump.Data, buf->cisdump.Length);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700980 break;
981 case DS_BIND_REQUEST:
982 if (!capable(CAP_SYS_ADMIN)) {
983 err = -EPERM;
984 goto free_out;
985 }
986 err = bind_request(s, &buf->bind_info);
987 break;
988 case DS_GET_DEVICE_INFO:
989 err = get_device_info(s, &buf->bind_info, 1);
990 break;
991 case DS_GET_NEXT_DEVICE:
992 err = get_device_info(s, &buf->bind_info, 0);
993 break;
994 case DS_UNBIND_REQUEST:
995 err = 0;
996 break;
997 default:
998 err = -EINVAL;
999 }
1000
Dominik Brodowski4c89e882008-08-03 10:07:45 +02001001 if ((err == 0) && (ret != 0)) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +02001002 pr_debug("ds_ioctl: ret = %d\n", ret);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001003 switch (ret) {
Dominik Brodowski610e2372008-08-03 11:58:53 +02001004 case -ENODEV:
1005 case -EINVAL:
1006 case -EBUSY:
1007 case -ENOSYS:
1008 err = ret;
1009 break;
Dominik Brodowski610e2372008-08-03 11:58:53 +02001010 case -ENOMEM:
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001011 err = -ENOSPC; break;
Dominik Brodowski635d19b2008-08-03 11:47:29 +02001012 case -ENOSPC:
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001013 err = -ENODATA; break;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001014 default:
1015 err = -EIO; break;
1016 }
1017 }
1018
1019 if (cmd & IOC_OUT) {
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001020 if (__copy_to_user(uarg, (char *)buf, size))
1021 err = -EFAULT;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001022 }
1023
1024free_out:
1025 kfree(buf);
1026 return err;
1027} /* ds_ioctl */
1028
1029/*====================================================================*/
1030
Arjan van de Vend54b1fd2007-02-12 00:55:34 -08001031static const struct file_operations ds_fops = {
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001032 .owner = THIS_MODULE,
1033 .open = ds_open,
1034 .release = ds_release,
1035 .ioctl = ds_ioctl,
1036 .read = ds_read,
1037 .write = ds_write,
1038 .poll = ds_poll,
1039};
1040
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001041void __init pcmcia_setup_ioctl(void)
1042{
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001043 int i;
1044
1045 /* Set up character device for user mode clients */
1046 i = register_chrdev(0, "pcmcia", &ds_fops);
Dominik Brodowski1a8ceaf2005-06-27 16:29:00 -07001047 if (i < 0)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001048 printk(KERN_NOTICE "unable to find a free device # for "
Dominik Brodowski1a8ceaf2005-06-27 16:29:00 -07001049 "Driver Services (error=%d)\n", i);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001050 else
1051 major_dev = i;
1052
1053#ifdef CONFIG_PROC_FS
akpm@linux-foundation.org97094dc2008-04-29 10:47:54 -07001054 proc_pccard = proc_mkdir("bus/pccard", NULL);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001055 if (proc_pccard)
Alexey Dobriyane6be4a82009-09-21 17:03:55 -07001056 proc_create("drivers", 0, proc_pccard, &pccard_drivers_proc_fops);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001057#endif
1058}
1059
1060
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001061void __exit pcmcia_cleanup_ioctl(void)
1062{
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001063#ifdef CONFIG_PROC_FS
1064 if (proc_pccard) {
1065 remove_proc_entry("drivers", proc_pccard);
akpm@linux-foundation.org97094dc2008-04-29 10:47:54 -07001066 remove_proc_entry("bus/pccard", NULL);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001067 }
1068#endif
1069 if (major_dev != -1)
1070 unregister_chrdev(major_dev, "pcmcia");
1071}