blob: d007a2a03830c815d507383c5556ca9a6d37a412 [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) {
Dominik Brodowski059f6672010-03-30 18:07:50 +0200304 mutex_lock(&s->ops_mutex);
Dominik Brodowski4aeba012008-06-20 13:24:31 +0200305 pcmcia_read_cis_mem(s, 1, (c->ConfigBase+CISREG_PRR)>>1, 1, &reg);
Dominik Brodowski059f6672010-03-30 18:07:50 +0200306 mutex_unlock(&s->ops_mutex);
Dominik Brodowski4aeba012008-06-20 13:24:31 +0200307 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) {
Dominik Brodowski059f6672010-03-30 18:07:50 +0200320 mutex_lock(&s->ops_mutex);
Dominik Brodowski4aeba012008-06-20 13:24:31 +0200321 pcmcia_read_cis_mem(s, 1, (c->ConfigBase+CISREG_ESR)>>1, 1, &reg);
Dominik Brodowski059f6672010-03-30 18:07:50 +0200322 mutex_unlock(&s->ops_mutex);
Dominik Brodowski4aeba012008-06-20 13:24:31 +0200323 status->CardState |=
324 (reg & ESR_REQ_ATTN) ? CS_EVENT_REQUEST_ATTENTION : 0;
325 }
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200326 return 0;
Dominik Brodowski4aeba012008-06-20 13:24:31 +0200327 }
328 status->CardState |=
329 (val & SS_WRPROT) ? CS_EVENT_WRITE_PROTECT : 0;
330 status->CardState |=
331 (val & SS_BATDEAD) ? CS_EVENT_BATTERY_DEAD : 0;
332 status->CardState |=
333 (val & SS_BATWARN) ? CS_EVENT_BATTERY_LOW : 0;
334 status->CardState |=
335 (val & SS_READY) ? CS_EVENT_READY_CHANGE : 0;
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200336 return 0;
Dominik Brodowski4aeba012008-06-20 13:24:31 +0200337} /* pccard_get_status */
Dominik Brodowskic5023802008-06-19 19:02:52 +0200338
Roel Kluina0779322008-12-09 22:12:50 +0100339static int pccard_get_configuration_info(struct pcmcia_socket *s,
Dominik Brodowski64f34642008-08-02 17:00:46 +0200340 struct pcmcia_device *p_dev,
341 config_info_t *config)
342{
343 config_t *c;
344
345 if (!(s->state & SOCKET_PRESENT))
Dominik Brodowski3939c1ef2008-08-03 11:10:56 +0200346 return -ENODEV;
Dominik Brodowski64f34642008-08-02 17:00:46 +0200347
348
349#ifdef CONFIG_CARDBUS
350 if (s->state & SOCKET_CARDBUS) {
351 memset(config, 0, sizeof(config_info_t));
352 config->Vcc = s->socket.Vcc;
353 config->Vpp1 = config->Vpp2 = s->socket.Vpp;
354 config->Option = s->cb_dev->subordinate->number;
355 if (s->state & SOCKET_CARDBUS_CONFIG) {
356 config->Attributes = CONF_VALID_CLIENT;
357 config->IntType = INT_CARDBUS;
Dominik Brodowski6f840af2010-03-07 10:51:23 +0100358 config->AssignedIRQ = s->pcmcia_irq;
Dominik Brodowski64f34642008-08-02 17:00:46 +0200359 if (config->AssignedIRQ)
360 config->Attributes |= CONF_ENABLE_IRQ;
361 if (s->io[0].res) {
362 config->BasePort1 = s->io[0].res->start;
363 config->NumPorts1 = s->io[0].res->end -
364 config->BasePort1 + 1;
365 }
366 }
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200367 return 0;
Dominik Brodowski64f34642008-08-02 17:00:46 +0200368 }
369#endif
370
371 if (p_dev) {
372 c = p_dev->function_config;
373 config->Function = p_dev->func;
374 } else {
375 c = NULL;
376 config->Function = 0;
377 }
378
379 if ((c == NULL) || !(c->state & CONFIG_LOCKED)) {
380 config->Attributes = 0;
381 config->Vcc = s->socket.Vcc;
382 config->Vpp1 = config->Vpp2 = s->socket.Vpp;
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200383 return 0;
Dominik Brodowski64f34642008-08-02 17:00:46 +0200384 }
385
386 config->Attributes = c->Attributes | CONF_VALID_CLIENT;
387 config->Vcc = s->socket.Vcc;
388 config->Vpp1 = config->Vpp2 = s->socket.Vpp;
389 config->IntType = c->IntType;
390 config->ConfigBase = c->ConfigBase;
391 config->Status = c->Status;
392 config->Pin = c->Pin;
393 config->Copy = c->Copy;
394 config->Option = c->Option;
395 config->ExtStatus = c->ExtStatus;
396 config->Present = config->CardValues = c->CardValues;
397 config->IRQAttributes = c->irq.Attributes;
Dominik Brodowski6f840af2010-03-07 10:51:23 +0100398 config->AssignedIRQ = s->pcmcia_irq;
Dominik Brodowski64f34642008-08-02 17:00:46 +0200399 config->BasePort1 = c->io.BasePort1;
400 config->NumPorts1 = c->io.NumPorts1;
401 config->Attributes1 = c->io.Attributes1;
402 config->BasePort2 = c->io.BasePort2;
403 config->NumPorts2 = c->io.NumPorts2;
404 config->Attributes2 = c->io.Attributes2;
405 config->IOAddrLines = c->io.IOAddrLines;
406
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200407 return 0;
Dominik Brodowski64f34642008-08-02 17:00:46 +0200408} /* pccard_get_configuration_info */
409
410
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700411/*======================================================================
412
413 These manage a ring buffer of events pending for one user process
414
415======================================================================*/
416
417
418static int queue_empty(user_info_t *user)
419{
420 return (user->event_head == user->event_tail);
421}
422
423static event_t get_queued_event(user_info_t *user)
424{
425 user->event_tail = (user->event_tail+1) % MAX_EVENTS;
426 return user->event[user->event_tail];
427}
428
429static void queue_event(user_info_t *user, event_t event)
430{
431 user->event_head = (user->event_head+1) % MAX_EVENTS;
432 if (user->event_head == user->event_tail)
433 user->event_tail = (user->event_tail+1) % MAX_EVENTS;
434 user->event[user->event_head] = event;
435}
436
Dominik Brodowskidc109492005-06-27 16:28:50 -0700437void handle_event(struct pcmcia_socket *s, event_t event)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700438{
439 user_info_t *user;
440 for (user = s->user; user; user = user->next)
441 queue_event(user, event);
442 wake_up_interruptible(&s->queue);
443}
444
445
446/*======================================================================
447
448 bind_request() and bind_device() are merged by now. Register_client()
449 is called right at the end of bind_request(), during the driver's
450 ->attach() call. Individual descriptions:
451
452 bind_request() connects a socket to a particular client driver.
453 It looks up the specified device ID in the list of registered
454 drivers, binds it to the socket, and tries to create an instance
455 of the device. unbind_request() deletes a driver instance.
456
457 Bind_device() associates a device driver with a particular socket.
458 It is normally called by Driver Services after it has identified
459 a newly inserted card. An instance of that driver will then be
460 eligible to register as a client of this socket.
461
462 Register_client() uses the dev_info_t handle to match the
463 caller with a socket. The driver must have already been bound
464 to a socket with bind_device() -- in fact, bind_device()
465 allocates the client structure that will be used.
466
467======================================================================*/
468
Dominik Brodowskidc109492005-06-27 16:28:50 -0700469static int bind_request(struct pcmcia_socket *s, bind_info_t *bind_info)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700470{
471 struct pcmcia_driver *p_drv;
472 struct pcmcia_device *p_dev;
473 int ret = 0;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700474
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
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100493 mutex_lock(&s->ops_mutex);
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". */
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100502 mutex_unlock(&s->ops_mutex);
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. */
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100510 mutex_unlock(&s->ops_mutex);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700511 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! */
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100519 mutex_unlock(&s->ops_mutex);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700520 goto rescan;
521 }
522 }
523 }
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100524 mutex_unlock(&s->ops_mutex);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700525
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{
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700578 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 int ret = 0;
581
582#ifdef CONFIG_CARDBUS
583 /*
584 * Some unbelievably ugly code to associate the PCI cardbus
585 * device and its driver with the PCMCIA "bind" information.
586 */
587 {
588 struct pci_bus *bus;
589
Dominik Brodowskidc109492005-06-27 16:28:50 -0700590 bus = pcmcia_lookup_bus(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700591 if (bus) {
592 struct list_head *list;
593 struct pci_dev *dev = NULL;
594
595 list = bus->devices.next;
596 while (list != &bus->devices) {
597 struct pci_dev *pdev = pci_dev_b(list);
598 list = list->next;
599
600 if (first) {
601 dev = pdev;
602 break;
603 }
604
605 /* Try to handle "next" here some way? */
606 }
607 if (dev && dev->driver) {
608 strlcpy(bind_info->name, dev->driver->name, DEV_NAME_LEN);
609 bind_info->major = 0;
610 bind_info->minor = 0;
611 bind_info->next = NULL;
612 return 0;
613 }
614 }
615 }
616#endif
617
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100618 mutex_lock(&s->ops_mutex);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700619 list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
620 if (p_dev->func == bind_info->function) {
621 p_dev = pcmcia_get_dev(p_dev);
622 if (!p_dev)
623 continue;
624 goto found;
625 }
626 }
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100627 mutex_unlock(&s->ops_mutex);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700628 return -ENODEV;
629
630 found:
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100631 mutex_unlock(&s->ops_mutex);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700632
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100633 p_drv = to_pcmcia_drv(p_dev->dev.driver);
634 if (p_drv && !p_dev->_locked) {
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700635 ret = -EAGAIN;
636 goto err_put;
637 }
638
Dominik Brodowskib9300aa2010-03-20 19:43:40 +0100639 if (!first) {
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700640 ret = -ENODEV;
641 goto err_put;
642 }
643
Dominik Brodowskib9300aa2010-03-20 19:43:40 +0100644 strlcpy(bind_info->name, dev_name(&p_dev->dev), DEV_NAME_LEN);
645 bind_info->next = NULL;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700646
647 err_put:
648 pcmcia_put_dev(p_dev);
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100649 return ret;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700650} /* get_device_info */
651
652
653static int ds_open(struct inode *inode, struct file *file)
654{
655 socket_t i = iminor(inode);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700656 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700657 user_info_t *user;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100658 static int warning_printed;
Jonathan Corbet0bec0bb2008-05-15 09:25:03 -0600659 int ret = 0;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700660
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200661 pr_debug("ds_open(socket %d)\n", i);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700662
Jonathan Corbet0bec0bb2008-05-15 09:25:03 -0600663 lock_kernel();
Dominik Brodowskidc109492005-06-27 16:28:50 -0700664 s = pcmcia_get_socket_by_nr(i);
Jonathan Corbet0bec0bb2008-05-15 09:25:03 -0600665 if (!s) {
666 ret = -ENODEV;
667 goto out;
668 }
Dominik Brodowskidc109492005-06-27 16:28:50 -0700669 s = pcmcia_get_socket(s);
Jonathan Corbet0bec0bb2008-05-15 09:25:03 -0600670 if (!s) {
671 ret = -ENODEV;
672 goto out;
673 }
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700674
675 if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700676 if (s->pcmcia_state.busy) {
Dominik Brodowskidc109492005-06-27 16:28:50 -0700677 pcmcia_put_socket(s);
Jonathan Corbet0bec0bb2008-05-15 09:25:03 -0600678 ret = -EBUSY;
679 goto out;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700680 }
681 else
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700682 s->pcmcia_state.busy = 1;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700683 }
684
685 user = kmalloc(sizeof(user_info_t), GFP_KERNEL);
686 if (!user) {
Dominik Brodowskidc109492005-06-27 16:28:50 -0700687 pcmcia_put_socket(s);
Jonathan Corbet0bec0bb2008-05-15 09:25:03 -0600688 ret = -ENOMEM;
689 goto out;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700690 }
691 user->event_tail = user->event_head = 0;
692 user->next = s->user;
693 user->user_magic = USER_MAGIC;
694 user->socket = s;
695 s->user = user;
696 file->private_data = user;
697
Dominik Brodowskic352ec82005-09-13 01:25:03 -0700698 if (!warning_printed) {
699 printk(KERN_INFO "pcmcia: Detected deprecated PCMCIA ioctl "
Benjamin Herrenschmidt73d58582006-05-15 09:43:53 -0700700 "usage from process: %s.\n", current->comm);
Dominik Brodowskic352ec82005-09-13 01:25:03 -0700701 printk(KERN_INFO "pcmcia: This interface will soon be removed from "
702 "the kernel; please expect breakage unless you upgrade "
703 "to new tools.\n");
704 printk(KERN_INFO "pcmcia: see http://www.kernel.org/pub/linux/"
705 "utils/kernel/pcmcia/pcmcia.html for details.\n");
706 warning_printed = 1;
707 }
708
Marc Zyngier15d0a872010-05-04 13:33:54 +0200709 if (atomic_read(&s->present))
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700710 queue_event(user, CS_EVENT_CARD_INSERTION);
Jonathan Corbet0bec0bb2008-05-15 09:25:03 -0600711out:
712 unlock_kernel();
713 return ret;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700714} /* ds_open */
715
716/*====================================================================*/
717
718static int ds_release(struct inode *inode, struct file *file)
719{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700720 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700721 user_info_t *user, **link;
722
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200723 pr_debug("ds_release(socket %d)\n", iminor(inode));
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700724
725 user = file->private_data;
726 if (CHECK_USER(user))
727 goto out;
728
729 s = user->socket;
730
731 /* Unlink user data structure */
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100732 if ((file->f_flags & O_ACCMODE) != O_RDONLY)
Dominik Brodowskib5e43912005-06-27 16:28:50 -0700733 s->pcmcia_state.busy = 0;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100734
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700735 file->private_data = NULL;
736 for (link = &s->user; *link; link = &(*link)->next)
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100737 if (*link == user)
738 break;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700739 if (link == NULL)
740 goto out;
741 *link = user->next;
742 user->user_magic = 0;
743 kfree(user);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700744 pcmcia_put_socket(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700745out:
746 return 0;
747} /* ds_release */
748
749/*====================================================================*/
750
751static ssize_t ds_read(struct file *file, char __user *buf,
752 size_t count, loff_t *ppos)
753{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700754 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700755 user_info_t *user;
756 int ret;
757
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200758 pr_debug("ds_read(socket %d)\n", iminor(file->f_path.dentry->d_inode));
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700759
760 if (count < 4)
761 return -EINVAL;
762
763 user = file->private_data;
764 if (CHECK_USER(user))
765 return -EIO;
766
767 s = user->socket;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700768 ret = wait_event_interruptible(s->queue, !queue_empty(user));
769 if (ret == 0)
770 ret = put_user(get_queued_event(user), (int __user *)buf) ? -EFAULT : 4;
771
772 return ret;
773} /* ds_read */
774
775/*====================================================================*/
776
777static ssize_t ds_write(struct file *file, const char __user *buf,
778 size_t count, loff_t *ppos)
779{
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200780 pr_debug("ds_write(socket %d)\n", iminor(file->f_path.dentry->d_inode));
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700781
782 if (count != 4)
783 return -EINVAL;
784 if ((file->f_flags & O_ACCMODE) == O_RDONLY)
785 return -EBADF;
786
787 return -EIO;
788} /* ds_write */
789
790/*====================================================================*/
791
792/* No kernel lock - fine */
793static u_int ds_poll(struct file *file, poll_table *wait)
794{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700795 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700796 user_info_t *user;
797
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200798 pr_debug("ds_poll(socket %d)\n", iminor(file->f_path.dentry->d_inode));
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700799
800 user = file->private_data;
801 if (CHECK_USER(user))
802 return POLLERR;
803 s = user->socket;
804 /*
805 * We don't check for a dead socket here since that
806 * will send cardmgr into an endless spin.
807 */
808 poll_wait(file, &s->queue, wait);
809 if (!queue_empty(user))
810 return POLLIN | POLLRDNORM;
811 return 0;
812} /* ds_poll */
813
814/*====================================================================*/
815
Arnd Bergmann55929332010-04-27 00:24:05 +0200816static int ds_ioctl(struct file *file, u_int cmd, u_long arg)
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700817{
Dominik Brodowskidc109492005-06-27 16:28:50 -0700818 struct pcmcia_socket *s;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700819 void __user *uarg = (char __user *)arg;
820 u_int size;
821 int ret, err;
822 ds_ioctl_arg_t *buf;
823 user_info_t *user;
824
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200825 pr_debug("ds_ioctl(socket %d, %#x, %#lx)\n", iminor(inode), cmd, arg);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700826
827 user = file->private_data;
828 if (CHECK_USER(user))
829 return -EIO;
830
831 s = user->socket;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700832
833 size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100834 if (size > sizeof(ds_ioctl_arg_t))
835 return -EINVAL;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700836
837 /* Permission check */
838 if (!(cmd & IOC_OUT) && !capable(CAP_SYS_ADMIN))
839 return -EPERM;
840
841 if (cmd & IOC_IN) {
842 if (!access_ok(VERIFY_READ, uarg, size)) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200843 pr_debug("ds_ioctl(): verify_read = %d\n", -EFAULT);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700844 return -EFAULT;
845 }
846 }
847 if (cmd & IOC_OUT) {
848 if (!access_ok(VERIFY_WRITE, uarg, size)) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200849 pr_debug("ds_ioctl(): verify_write = %d\n", -EFAULT);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700850 return -EFAULT;
851 }
852 }
853 buf = kmalloc(sizeof(ds_ioctl_arg_t), GFP_KERNEL);
854 if (!buf)
855 return -ENOMEM;
856
857 err = ret = 0;
858
Dominik Brodowski93740742006-11-19 11:21:27 -0500859 if (cmd & IOC_IN) {
860 if (__copy_from_user((char *)buf, uarg, size)) {
861 err = -EFAULT;
862 goto free_out;
863 }
864 }
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700865
866 switch (cmd) {
867 case DS_ADJUST_RESOURCE_INFO:
868 ret = pcmcia_adjust_resource_info(&buf->adjust);
869 break;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700870 case DS_GET_CONFIGURATION_INFO:
871 if (buf->config.Function &&
Dominik Brodowskidc109492005-06-27 16:28:50 -0700872 (buf->config.Function >= s->functions))
Dominik Brodowski926c5402008-08-03 12:15:11 +0200873 ret = -EINVAL;
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100874 else {
875 struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->config.Function);
Daniel Ritzf47ad212006-07-30 03:03:47 -0700876 ret = pccard_get_configuration_info(s, p_dev, &buf->config);
877 pcmcia_put_dev(p_dev);
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100878 }
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700879 break;
880 case DS_GET_FIRST_TUPLE:
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100881 mutex_lock(&s->skt_mutex);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700882 pcmcia_validate_mem(s);
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100883 mutex_unlock(&s->skt_mutex);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700884 ret = pccard_get_first_tuple(s, BIND_FN_ALL, &buf->tuple);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700885 break;
886 case DS_GET_NEXT_TUPLE:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700887 ret = pccard_get_next_tuple(s, BIND_FN_ALL, &buf->tuple);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700888 break;
889 case DS_GET_TUPLE_DATA:
890 buf->tuple.TupleData = buf->tuple_parse.data;
891 buf->tuple.TupleDataMax = sizeof(buf->tuple_parse.data);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700892 ret = pccard_get_tuple_data(s, &buf->tuple);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700893 break;
894 case DS_PARSE_TUPLE:
895 buf->tuple.TupleData = buf->tuple_parse.data;
Dominik Brodowski2f3061e2008-08-31 15:50:33 +0200896 ret = pcmcia_parse_tuple(&buf->tuple, &buf->tuple_parse.parse);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700897 break;
898 case DS_RESET_CARD:
Dominik Brodowski994917f2008-08-31 15:20:26 +0200899 ret = pcmcia_reset_card(s);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700900 break;
901 case DS_GET_STATUS:
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100902 if (buf->status.Function &&
903 (buf->status.Function >= s->functions))
Dominik Brodowski926c5402008-08-03 12:15:11 +0200904 ret = -EINVAL;
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100905 else {
906 struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->status.Function);
Daniel Ritzf47ad212006-07-30 03:03:47 -0700907 ret = pccard_get_status(s, p_dev, &buf->status);
908 pcmcia_put_dev(p_dev);
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100909 }
910 break;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700911 case DS_VALIDATE_CIS:
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100912 mutex_lock(&s->skt_mutex);
Dominik Brodowskidc109492005-06-27 16:28:50 -0700913 pcmcia_validate_mem(s);
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100914 mutex_unlock(&s->skt_mutex);
Dominik Brodowski84897fc2009-10-18 23:51:09 +0200915 ret = pccard_validate_cis(s, &buf->cisinfo.Chains);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700916 break;
917 case DS_SUSPEND_CARD:
Dominik Brodowskif971dbd2010-01-17 18:13:31 +0100918 pcmcia_parse_uevents(s, PCMCIA_UEVENT_SUSPEND);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700919 break;
920 case DS_RESUME_CARD:
Dominik Brodowskif971dbd2010-01-17 18:13:31 +0100921 pcmcia_parse_uevents(s, PCMCIA_UEVENT_RESUME);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700922 break;
923 case DS_EJECT_CARD:
Dominik Brodowskif971dbd2010-01-17 18:13:31 +0100924 pcmcia_parse_uevents(s, PCMCIA_UEVENT_EJECT);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700925 break;
926 case DS_INSERT_CARD:
Dominik Brodowskif971dbd2010-01-17 18:13:31 +0100927 pcmcia_parse_uevents(s, PCMCIA_UEVENT_INSERT);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700928 break;
929 case DS_ACCESS_CONFIGURATION_REGISTER:
930 if ((buf->conf_reg.Action == CS_WRITE) && !capable(CAP_SYS_ADMIN)) {
931 err = -EPERM;
932 goto free_out;
933 }
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100934
Dominik Brodowski926c5402008-08-03 12:15:11 +0200935 ret = -EINVAL;
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100936
937 if (!(buf->conf_reg.Function &&
938 (buf->conf_reg.Function >= s->functions))) {
939 struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->conf_reg.Function);
Benjamin Herrenschmidt73d58582006-05-15 09:43:53 -0700940 if (p_dev) {
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100941 ret = pcmcia_access_configuration_register(p_dev, &buf->conf_reg);
Benjamin Herrenschmidt73d58582006-05-15 09:43:53 -0700942 pcmcia_put_dev(p_dev);
943 }
Dominik Brodowski855cdf12006-01-10 20:48:59 +0100944 }
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700945 break;
946 case DS_GET_FIRST_REGION:
947 case DS_GET_NEXT_REGION:
948 case DS_BIND_MTD:
949 if (!capable(CAP_SYS_ADMIN)) {
950 err = -EPERM;
951 goto free_out;
952 } else {
Minchan Kima9c56952009-06-16 15:33:44 -0700953 printk_once(KERN_WARNING
954 "2.6. kernels use pcmciamtd instead of memory_cs.c and do not require special\n");
955 printk_once(KERN_WARNING "MTD handling any more.\n");
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700956 }
957 err = -EINVAL;
958 goto free_out;
959 break;
960 case DS_GET_FIRST_WINDOW:
Magnus Damm0bdf9b32006-12-13 19:46:53 +0900961 ret = pcmcia_get_window(s, &buf->win_info.handle, 1,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700962 &buf->win_info.window);
963 break;
964 case DS_GET_NEXT_WINDOW:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700965 ret = pcmcia_get_window(s, &buf->win_info.handle,
Magnus Damm0bdf9b32006-12-13 19:46:53 +0900966 buf->win_info.handle + 1, &buf->win_info.window);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700967 break;
968 case DS_GET_MEM_PAGE:
Magnus Damm16456eb2006-12-13 19:46:48 +0900969 ret = pcmcia_get_mem_page(s, buf->win_info.handle,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700970 &buf->win_info.map);
971 break;
972 case DS_REPLACE_CIS:
Dominik Brodowski53efec92008-07-28 19:44:05 +0200973 ret = pcmcia_replace_cis(s, buf->cisdump.Data, buf->cisdump.Length);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700974 break;
975 case DS_BIND_REQUEST:
976 if (!capable(CAP_SYS_ADMIN)) {
977 err = -EPERM;
978 goto free_out;
979 }
980 err = bind_request(s, &buf->bind_info);
981 break;
982 case DS_GET_DEVICE_INFO:
983 err = get_device_info(s, &buf->bind_info, 1);
984 break;
985 case DS_GET_NEXT_DEVICE:
986 err = get_device_info(s, &buf->bind_info, 0);
987 break;
988 case DS_UNBIND_REQUEST:
989 err = 0;
990 break;
991 default:
992 err = -EINVAL;
993 }
994
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200995 if ((err == 0) && (ret != 0)) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200996 pr_debug("ds_ioctl: ret = %d\n", ret);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -0700997 switch (ret) {
Dominik Brodowski610e2372008-08-03 11:58:53 +0200998 case -ENODEV:
999 case -EINVAL:
1000 case -EBUSY:
1001 case -ENOSYS:
1002 err = ret;
1003 break;
Dominik Brodowski610e2372008-08-03 11:58:53 +02001004 case -ENOMEM:
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001005 err = -ENOSPC; break;
Dominik Brodowski635d19b2008-08-03 11:47:29 +02001006 case -ENOSPC:
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001007 err = -ENODATA; break;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001008 default:
1009 err = -EIO; break;
1010 }
1011 }
1012
1013 if (cmd & IOC_OUT) {
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001014 if (__copy_to_user(uarg, (char *)buf, size))
1015 err = -EFAULT;
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001016 }
1017
1018free_out:
1019 kfree(buf);
1020 return err;
1021} /* ds_ioctl */
1022
Arnd Bergmann55929332010-04-27 00:24:05 +02001023static long ds_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
1024{
1025 int ret;
1026
1027 lock_kernel();
1028 ret = ds_ioctl(file, cmd, arg);
1029 unlock_kernel();
1030
1031 return ret;
1032}
1033
1034
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001035/*====================================================================*/
1036
Arjan van de Vend54b1fd2007-02-12 00:55:34 -08001037static const struct file_operations ds_fops = {
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001038 .owner = THIS_MODULE,
1039 .open = ds_open,
1040 .release = ds_release,
Arnd Bergmann55929332010-04-27 00:24:05 +02001041 .unlocked_ioctl = ds_unlocked_ioctl,
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001042 .read = ds_read,
1043 .write = ds_write,
1044 .poll = ds_poll,
1045};
1046
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001047void __init pcmcia_setup_ioctl(void)
1048{
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001049 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
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001067void __exit pcmcia_cleanup_ioctl(void)
1068{
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001069#ifdef CONFIG_PROC_FS
1070 if (proc_pccard) {
1071 remove_proc_entry("drivers", proc_pccard);
akpm@linux-foundation.org97094dc2008-04-29 10:47:54 -07001072 remove_proc_entry("bus/pccard", NULL);
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001073 }
1074#endif
1075 if (major_dev != -1)
1076 unregister_chrdev(major_dev, "pcmcia");
1077}