|
|
1.1 root 1: /*======================================================================
2:
3: PC Card Driver Services
4:
5: ds.c 1.115 2002/10/12 19:03:44
6:
7: The contents of this file are subject to the Mozilla Public
8: License Version 1.1 (the "License"); you may not use this file
9: except in compliance with the License. You may obtain a copy of
10: the License at http://www.mozilla.org/MPL/
11:
12: Software distributed under the License is distributed on an "AS
13: IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14: implied. See the License for the specific language governing
15: rights and limitations under the License.
16:
17: The initial developer of the original code is David A. Hinds
18: <[email protected]>. Portions created by David A. Hinds
19: are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
20:
21: Alternatively, the contents of this file may be used under the
22: terms of the GNU General Public License version 2 (the "GPL"), in
23: which case the provisions of the GPL are applicable instead of the
24: above. If you wish to allow the use of your version of this file
25: only under the terms of the GPL and not to allow others to use
26: your version of this file under the MPL, indicate your decision
27: by deleting the provisions above and replace them with the notice
28: and other provisions required by the GPL. If you do not delete
29: the provisions above, a recipient may use your version of this
30: file under either the MPL or the GPL.
31:
32: ======================================================================*/
33:
34: #include <linux/module.h>
35: #include <linux/init.h>
36: #include <linux/kernel.h>
37: #include <linux/major.h>
38: #include <linux/string.h>
39: #include <linux/errno.h>
40: #include <linux/slab.h>
41: #include <linux/mm.h>
42: #include <linux/fcntl.h>
43: #include <linux/sched.h>
44: #include <linux/timer.h>
45: #include <linux/ioctl.h>
46: #include <linux/proc_fs.h>
47: #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,23))
48: #include <linux/poll.h>
49: #endif
50:
51: /*
52: * <pcmcia/cs.h> defines io_req_t which is not used in this file, but
53: * which clashes with the io_req_t needed for the Mach devices. Rename
54: * it to cardservice_io_req_t to avoid this clash.
55: */
56: #define io_req_t cardservice_io_req_t
57: #include <pcmcia/version.h>
58: #include <pcmcia/cs_types.h>
59: #include <pcmcia/cs.h>
60: #include <pcmcia/bulkmem.h>
61: #include <pcmcia/cistpl.h>
62: #include <pcmcia/ds.h>
63: #undef io_req_t
64:
65: /*====================================================================*/
66:
67: /* Module parameters */
68:
69: MODULE_AUTHOR("David Hinds <[email protected]>");
70: MODULE_DESCRIPTION("PCMCIA Driver Services " CS_RELEASE);
71: MODULE_LICENSE("Dual MPL/GPL");
72:
73: #define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
74:
75: #ifdef PCMCIA_DEBUG
76: INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
77: #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
78: static const char *version =
79: "ds.c 1.115 2002/10/12 19:03:44 (David Hinds)";
80: #else
81: #define DEBUG(n, args...)
82: #endif
83:
84: /*====================================================================*/
85:
86: typedef struct driver_info_t {
87: dev_info_t dev_info;
88: int use_count, status;
89: dev_link_t *(*attach)(void);
90: void (*detach)(dev_link_t *);
91: struct driver_info_t *next;
92: } driver_info_t;
93:
94: typedef struct socket_bind_t {
95: driver_info_t *driver;
96: u_char function;
97: dev_link_t *instance;
98: struct socket_bind_t *next;
99: } socket_bind_t;
100:
101: /* Device user information */
102: #define MAX_EVENTS 32
103: #define USER_MAGIC 0x7ea4
104: #define CHECK_USER(u) \
105: (((u) == NULL) || ((u)->user_magic != USER_MAGIC))
106: typedef struct user_info_t {
107: u_int user_magic;
108: int event_head, event_tail;
109: event_t event[MAX_EVENTS];
110: struct user_info_t *next;
111: } user_info_t;
112:
113: /* Socket state information */
114: typedef struct socket_info_t {
115: client_handle_t handle;
116: int state;
117: user_info_t *user;
118: int req_pending, req_result;
119: wait_queue_head_t queue, request;
120: struct timer_list removal;
121: socket_bind_t *bind;
122: } socket_info_t;
123:
124: #define SOCKET_PRESENT 0x01
125: #define SOCKET_BUSY 0x02
126: #define SOCKET_REMOVAL_PENDING 0x10
127:
128: /*====================================================================*/
129:
130: /* Device driver ID passed to Card Services */
131: static dev_info_t dev_info = "Driver Services";
132:
133: /* Linked list of all registered device drivers */
134: static driver_info_t *root_driver = NULL;
135:
136: static int sockets = 0, major_dev = -1;
137: static socket_info_t *socket_table = NULL;
138:
139: extern struct proc_dir_entry *proc_pccard;
140:
141: /* We use this to distinguish in-kernel from modular drivers */
142: static int init_status = 1;
143:
144: /*====================================================================*/
145:
146: static void cs_error(client_handle_t handle, int func, int ret)
147: {
148: error_info_t err = { func, ret };
149: CardServices(ReportError, handle, &err);
150: }
151:
152: /*======================================================================
153:
154: Register_pccard_driver() and unregister_pccard_driver() are used
155: tell Driver Services that a PC Card client driver is available to
156: be bound to sockets.
157:
158: ======================================================================*/
159:
160: int register_pccard_driver(dev_info_t *dev_info,
161: dev_link_t *(*attach)(void),
162: void (*detach)(dev_link_t *))
163: {
164: driver_info_t *driver;
165: socket_bind_t *b;
166: int i;
167:
168: DEBUG(0, "ds: register_pccard_driver('%s')\n", (char *)dev_info);
169: for (driver = root_driver; driver; driver = driver->next)
170: if (strncmp((char *)dev_info, (char *)driver->dev_info,
171: DEV_NAME_LEN) == 0)
172: break;
173: if (!driver) {
174: driver = kmalloc(sizeof(driver_info_t), GFP_KERNEL);
175: if (!driver) return -ENOMEM;
176: strncpy(driver->dev_info, (char *)dev_info, DEV_NAME_LEN);
177: driver->use_count = 0;
178: driver->status = init_status;
179: driver->next = root_driver;
180: root_driver = driver;
181: }
182:
183: driver->attach = attach;
184: driver->detach = detach;
185: if (driver->use_count == 0) return 0;
186:
187: /* Instantiate any already-bound devices */
188: for (i = 0; i < sockets; i++)
189: for (b = socket_table[i].bind; b; b = b->next) {
190: if (b->driver != driver) continue;
191: b->instance = driver->attach();
192: if (b->instance == NULL)
193: printk(KERN_NOTICE "ds: unable to create instance "
194: "of '%s'!\n", driver->dev_info);
195: }
196:
197: return 0;
198: } /* register_pccard_driver */
199:
200: /*====================================================================*/
201:
202: int unregister_pccard_driver(dev_info_t *dev_info)
203: {
204: driver_info_t *target, **d = &root_driver;
205: socket_bind_t *b;
206: int i;
207:
208: DEBUG(0, "ds: unregister_pccard_driver('%s')\n",
209: (char *)dev_info);
210: while ((*d) && (strncmp((*d)->dev_info, (char *)dev_info,
211: DEV_NAME_LEN) != 0))
212: d = &(*d)->next;
213: if (*d == NULL)
214: return -ENODEV;
215:
216: target = *d;
217: if (target->use_count == 0) {
218: *d = target->next;
219: kfree(target);
220: } else {
221: /* Blank out any left-over device instances */
222: target->attach = NULL; target->detach = NULL;
223: for (i = 0; i < sockets; i++)
224: for (b = socket_table[i].bind; b; b = b->next)
225: if (b->driver == target) b->instance = NULL;
226: }
227: return 0;
228: } /* unregister_pccard_driver */
229:
230: /*====================================================================*/
231:
232: #ifdef HAS_PROC_BUS
233: static int proc_read_drivers(char *buf, char **start, off_t pos,
234: int count, int *eof, void *data)
235: {
236: driver_info_t *d;
237: char *p = buf;
238: for (d = root_driver; d; d = d->next)
239: p += sprintf(p, "%-24.24s %d %d\n", d->dev_info,
240: d->status, d->use_count);
241: return (p - buf);
242: }
243: #endif
244:
245: /*======================================================================
246:
247: These manage a ring buffer of events pending for one user process
248:
249: ======================================================================*/
250:
251: static int queue_empty(user_info_t *user)
252: {
253: return (user->event_head == user->event_tail);
254: }
255:
256: static event_t get_queued_event(user_info_t *user)
257: {
258: user->event_tail = (user->event_tail+1) % MAX_EVENTS;
259: return user->event[user->event_tail];
260: }
261:
262: static void queue_event(user_info_t *user, event_t event)
263: {
264: user->event_head = (user->event_head+1) % MAX_EVENTS;
265: if (user->event_head == user->event_tail)
266: user->event_tail = (user->event_tail+1) % MAX_EVENTS;
267: user->event[user->event_head] = event;
268: }
269:
270: static void handle_event(socket_info_t *s, event_t event)
271: {
272: user_info_t *user;
273: for (user = s->user; user; user = user->next)
274: queue_event(user, event);
275: wake_up_interruptible(&s->queue);
276: }
277:
278: static int handle_request(socket_info_t *s, event_t event)
279: {
280: if (s->req_pending != 0)
281: return CS_IN_USE;
282: if (s->state & SOCKET_BUSY)
283: s->req_pending = 1;
284: handle_event(s, event);
285: if (s->req_pending > 0) {
286: interruptible_sleep_on(&s->request);
287: if (signal_pending(current))
288: return CS_IN_USE;
289: else
290: return s->req_result;
291: }
292: return CS_SUCCESS;
293: }
294:
295: static void handle_removal(u_long sn)
296: {
297: socket_info_t *s = &socket_table[sn];
298: handle_event(s, CS_EVENT_CARD_REMOVAL);
299: s->state &= ~SOCKET_REMOVAL_PENDING;
300: }
301:
302: /*======================================================================
303:
304: The card status event handler.
305:
306: ======================================================================*/
307:
308: static int ds_event(event_t event, int priority,
309: event_callback_args_t *args)
310: {
311: socket_info_t *s;
312: int i;
313:
314: DEBUG(1, "ds: ds_event(0x%06x, %d, 0x%p)\n",
315: event, priority, args->client_handle);
316: s = args->client_data;
317: i = s - socket_table;
318:
319: switch (event) {
320:
321: case CS_EVENT_CARD_REMOVAL:
322: s->state &= ~SOCKET_PRESENT;
323: if (!(s->state & SOCKET_REMOVAL_PENDING)) {
324: s->state |= SOCKET_REMOVAL_PENDING;
325: s->removal.expires = jiffies + HZ/10;
326: add_timer(&s->removal);
327: }
328: break;
329:
330: case CS_EVENT_CARD_INSERTION:
331: s->state |= SOCKET_PRESENT;
332: handle_event(s, event);
333: break;
334:
335: case CS_EVENT_EJECTION_REQUEST:
336: return handle_request(s, event);
337: break;
338:
339: default:
340: handle_event(s, event);
341: break;
342: }
343:
344: return 0;
345: } /* ds_event */
346:
347: /*======================================================================
348:
349: bind_mtd() connects a memory region with an MTD client.
350:
351: ======================================================================*/
352:
353: static int bind_mtd(int i, mtd_info_t *mtd_info)
354: {
355: mtd_bind_t bind_req;
356: int ret;
357:
358: bind_req.dev_info = &mtd_info->dev_info;
359: bind_req.Attributes = mtd_info->Attributes;
360: bind_req.Socket = i;
361: bind_req.CardOffset = mtd_info->CardOffset;
362: ret = CardServices(BindMTD, &bind_req);
363: if (ret != CS_SUCCESS) {
364: cs_error(NULL, BindMTD, ret);
365: printk(KERN_NOTICE "ds: unable to bind MTD '%s' to socket %d"
366: " offset 0x%x\n",
367: (char *)bind_req.dev_info, i, bind_req.CardOffset);
368: return -ENODEV;
369: }
370: return 0;
371: } /* bind_mtd */
372:
373: /*======================================================================
374:
375: bind_request() connects a socket to a particular client driver.
376: It looks up the specified device ID in the list of registered
377: drivers, binds it to the socket, and tries to create an instance
378: of the device. unbind_request() deletes a driver instance.
379:
380: ======================================================================*/
381:
382: static int bind_request(int i, bind_info_t *bind_info)
383: {
384: struct driver_info_t *driver;
385: socket_bind_t *b;
386: bind_req_t bind_req;
387: socket_info_t *s = &socket_table[i];
388: int ret;
389:
390: DEBUG(2, "bind_request(%d, '%s')\n", i,
391: (char *)bind_info->dev_info);
392: for (driver = root_driver; driver; driver = driver->next)
393: if (strcmp((char *)driver->dev_info,
394: (char *)bind_info->dev_info) == 0)
395: break;
396: if (driver == NULL) {
397: driver = kmalloc(sizeof(driver_info_t), GFP_KERNEL);
398: if (!driver) return -ENOMEM;
399: strncpy(driver->dev_info, bind_info->dev_info, DEV_NAME_LEN);
400: driver->use_count = 0;
401: driver->next = root_driver;
402: driver->attach = NULL; driver->detach = NULL;
403: root_driver = driver;
404: }
405:
406: for (b = s->bind; b; b = b->next)
407: if ((driver == b->driver) &&
408: (bind_info->function == b->function))
409: break;
410: if (b != NULL) {
411: bind_info->instance = b->instance;
412: return -EBUSY;
413: }
414: b = kmalloc(sizeof(socket_bind_t), GFP_KERNEL);
415: if (!b)
416: return -ENOMEM;
417:
418: bind_req.Socket = i;
419: bind_req.Function = bind_info->function;
420: bind_req.dev_info = &driver->dev_info;
421: ret = CardServices(BindDevice, &bind_req);
422: if (ret != CS_SUCCESS) {
423: cs_error(NULL, BindDevice, ret);
424: printk(KERN_NOTICE "ds: unable to bind '%s' to socket %d\n",
425: (char *)dev_info, i);
426: kfree(b);
427: return -ENODEV;
428: }
429:
430: /* Add binding to list for this socket */
431: driver->use_count++;
432: b->driver = driver;
433: b->function = bind_info->function;
434: b->instance = NULL;
435: b->next = s->bind;
436: s->bind = b;
437:
438: if (driver->attach) {
439: b->instance = driver->attach();
440: if (b->instance == NULL) {
441: printk(KERN_NOTICE "ds: unable to create instance "
442: "of '%s'!\n", (char *)bind_info->dev_info);
443: return -ENODEV;
444: }
445: }
446:
447: return 0;
448: } /* bind_request */
449:
450: /*====================================================================*/
451:
452: static int get_device_info(int i, bind_info_t *bind_info, int first)
453: {
454: socket_info_t *s = &socket_table[i];
455: socket_bind_t *b;
456: dev_node_t *node;
457:
458: for (b = s->bind; b; b = b->next)
459: if ((strcmp((char *)b->driver->dev_info,
460: (char *)bind_info->dev_info) == 0) &&
461: (b->function == bind_info->function))
462: break;
463: if (b == NULL) return -ENODEV;
464: if ((b->instance == NULL) ||
465: (b->instance->state & DEV_CONFIG_PENDING))
466: return -EAGAIN;
467: if (first)
468: node = b->instance->dev;
469: else
470: for (node = b->instance->dev; node; node = node->next)
471: if (node == bind_info->next) break;
472: if (node == NULL) return -ENODEV;
473:
474: strncpy(bind_info->name, node->dev_name, DEV_NAME_LEN);
475: bind_info->name[DEV_NAME_LEN-1] = '\0';
476: bind_info->major = node->major;
477: bind_info->minor = node->minor;
478: bind_info->next = node->next;
479:
480: return 0;
481: } /* get_device_info */
482:
483: /*====================================================================*/
484:
485: static int unbind_request(int i, bind_info_t *bind_info)
486: {
487: socket_info_t *s = &socket_table[i];
488: socket_bind_t **b, *c;
489:
490: DEBUG(2, "unbind_request(%d, '%s')\n", i,
491: (char *)bind_info->dev_info);
492: for (b = &s->bind; *b; b = &(*b)->next)
493: if ((strcmp((char *)(*b)->driver->dev_info,
494: (char *)bind_info->dev_info) == 0) &&
495: ((*b)->function == bind_info->function))
496: break;
497: if (*b == NULL)
498: return -ENODEV;
499:
500: c = *b;
501: c->driver->use_count--;
502: if (c->driver->detach) {
503: if (c->instance)
504: c->driver->detach(c->instance);
505: } else {
506: if (c->driver->use_count == 0) {
507: driver_info_t **d;
508: for (d = &root_driver; *d; d = &((*d)->next))
509: if (c->driver == *d) break;
510: *d = (*d)->next;
511: kfree(c->driver);
512: }
513: }
514: *b = c->next;
515: kfree(c);
516:
517: return 0;
518: } /* unbind_request */
519:
520: /*======================================================================
521:
522: The user-mode PC Card device interface
523:
524: ======================================================================*/
525:
526: /* Disable all the ds filesystem operations. */
527: #ifndef MACH
528:
529: static int ds_open(struct inode *inode, struct file *file)
530: {
531: socket_t i = MINOR(inode->i_rdev);
532: socket_info_t *s;
533: user_info_t *user;
534:
535: DEBUG(0, "ds_open(socket %d)\n", i);
536: if ((i >= sockets) || (sockets == 0))
537: return -ENODEV;
538: s = &socket_table[i];
539: if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
540: if (s->state & SOCKET_BUSY)
541: return -EBUSY;
542: else
543: s->state |= SOCKET_BUSY;
544: }
545:
546: MOD_INC_USE_COUNT;
547: user = kmalloc(sizeof(user_info_t), GFP_KERNEL);
548: if (!user) {
549: MOD_DEC_USE_COUNT;
550: return -ENOMEM;
551: }
552: user->event_tail = user->event_head = 0;
553: user->next = s->user;
554: user->user_magic = USER_MAGIC;
555: s->user = user;
556: file->private_data = user;
557:
558: if (s->state & SOCKET_PRESENT)
559: queue_event(user, CS_EVENT_CARD_INSERTION);
560: return 0;
561: } /* ds_open */
562:
563: /*====================================================================*/
564:
565: static FS_RELEASE_T ds_release(struct inode *inode, struct file *file)
566: {
567: socket_t i = MINOR(inode->i_rdev);
568: socket_info_t *s;
569: user_info_t *user, **link;
570:
571: DEBUG(0, "ds_release(socket %d)\n", i);
572: if ((i >= sockets) || (sockets == 0))
573: return (FS_RELEASE_T)0;
574: s = &socket_table[i];
575: user = file->private_data;
576: if (CHECK_USER(user))
577: return (FS_RELEASE_T)0;
578:
579: /* Unlink user data structure */
580: if ((file->f_flags & O_ACCMODE) != O_RDONLY)
581: s->state &= ~SOCKET_BUSY;
582: file->private_data = NULL;
583: for (link = &s->user; *link; link = &(*link)->next)
584: if (*link == user) break;
585: if (link == NULL)
586: return (FS_RELEASE_T)0;
587: *link = user->next;
588: user->user_magic = 0;
589: kfree(user);
590:
591: MOD_DEC_USE_COUNT;
592: return (FS_RELEASE_T)0;
593: } /* ds_release */
594:
595: /*====================================================================*/
596:
597: static ssize_t ds_read FOPS(struct inode *inode,
598: struct file *file, char *buf,
599: size_t count, loff_t *ppos)
600: {
601: socket_t i = MINOR(F_INODE(file)->i_rdev);
602: socket_info_t *s;
603: user_info_t *user;
604:
605: DEBUG(2, "ds_read(socket %d)\n", i);
606:
607: if ((i >= sockets) || (sockets == 0))
608: return -ENODEV;
609: if (count < 4)
610: return -EINVAL;
611: s = &socket_table[i];
612: user = file->private_data;
613: if (CHECK_USER(user))
614: return -EIO;
615:
616: if (queue_empty(user)) {
617: interruptible_sleep_on(&s->queue);
618: if (signal_pending(current))
619: return -EINTR;
620: }
621: put_user(get_queued_event(user), (int *)buf);
622: return 4;
623: } /* ds_read */
624:
625: /*====================================================================*/
626:
627: static ssize_t ds_write FOPS(struct inode *inode,
628: struct file *file, const char *buf,
629: size_t count, loff_t *ppos)
630: {
631: socket_t i = MINOR(F_INODE(file)->i_rdev);
632: socket_info_t *s;
633: user_info_t *user;
634:
635: DEBUG(2, "ds_write(socket %d)\n", i);
636:
637: if ((i >= sockets) || (sockets == 0))
638: return -ENODEV;
639: if (count != 4)
640: return -EINVAL;
641: if ((file->f_flags & O_ACCMODE) == O_RDONLY)
642: return -EBADF;
643: s = &socket_table[i];
644: user = file->private_data;
645: if (CHECK_USER(user))
646: return -EIO;
647:
648: if (s->req_pending) {
649: s->req_pending--;
650: get_user(s->req_result, (int *)buf);
651: if ((s->req_result != 0) || (s->req_pending == 0))
652: wake_up_interruptible(&s->request);
653: } else
654: return -EIO;
655:
656: return 4;
657: } /* ds_write */
658:
659: /*====================================================================*/
660:
661: #if (LINUX_VERSION_CODE < VERSION(2,1,23))
662:
663: static int ds_select(struct inode *inode, struct file *file,
664: int sel_type, select_table *wait)
665: {
666: socket_t i = MINOR(inode->i_rdev);
667: socket_info_t *s;
668: user_info_t *user;
669:
670: DEBUG(2, "ds_select(socket %d)\n", i);
671:
672: if ((i >= sockets) || (sockets == 0))
673: return -ENODEV;
674: s = &socket_table[i];
675: user = file->private_data;
676: if (CHECK_USER(user))
677: return -EIO;
678: if (sel_type != SEL_IN)
679: return 0;
680: if (!queue_empty(user))
681: return 1;
682: select_wait(&s->queue, wait);
683: return 0;
684: } /* ds_select */
685:
686: #else
687:
688: static u_int ds_poll(struct file *file, poll_table *wait)
689: {
690: socket_t i = MINOR(F_INODE(file)->i_rdev);
691: socket_info_t *s;
692: user_info_t *user;
693:
694: DEBUG(2, "ds_poll(socket %d)\n", i);
695:
696: if ((i >= sockets) || (sockets == 0))
697: return POLLERR;
698: s = &socket_table[i];
699: user = file->private_data;
700: if (CHECK_USER(user))
701: return POLLERR;
702: POLL_WAIT(file, &s->queue, wait);
703: if (!queue_empty(user))
704: return POLLIN | POLLRDNORM;
705: return 0;
706: } /* ds_poll */
707:
708: #endif
709:
710: /*====================================================================*/
711:
712: #endif /* !defined(MACH) */
713:
714: static int ds_ioctl(struct inode * inode, struct file * file,
715: u_int cmd, u_long arg)
716: {
717: socket_t i = MINOR(inode->i_rdev);
718: socket_info_t *s;
719: u_int size;
720: int ret, err;
721: ds_ioctl_arg_t buf;
722:
723: DEBUG(2, "ds_ioctl(socket %d, %#x, %#lx)\n", i, cmd, arg);
724:
725: if ((i >= sockets) || (sockets == 0))
726: return -ENODEV;
727: s = &socket_table[i];
728:
729: size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
730: if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL;
731:
732: /* Permission check */
733: if (!(cmd & IOC_OUT) && !capable(CAP_SYS_ADMIN))
734: return -EPERM;
735:
736: #ifndef MACH
737: if (cmd & IOC_IN) {
738: err = verify_area(VERIFY_READ, (char *)arg, size);
739: if (err) {
740: DEBUG(3, "ds_ioctl(): verify_read = %d\n", err);
741: return err;
742: }
743: }
744: if (cmd & IOC_OUT) {
745: err = verify_area(VERIFY_WRITE, (char *)arg, size);
746: if (err) {
747: DEBUG(3, "ds_ioctl(): verify_write = %d\n", err);
748: return err;
749: }
750: }
751: #endif
752:
753: err = ret = 0;
754:
755: #ifndef MACH
756: if (cmd & IOC_IN) copy_from_user((char *)&buf, (char *)arg, size);
757: #else
758: if (cmd & IOC_IN) memcpy((char *) &buf, (char *) arg, size);
759: #endif
760:
761: switch (cmd) {
762: case DS_ADJUST_RESOURCE_INFO:
763: ret = CardServices(AdjustResourceInfo, s->handle, &buf.adjust);
764: break;
765: case DS_GET_CARD_SERVICES_INFO:
766: ret = CardServices(GetCardServicesInfo, &buf.servinfo);
767: break;
768: case DS_GET_CONFIGURATION_INFO:
769: ret = CardServices(GetConfigurationInfo, s->handle, &buf.config);
770: break;
771: case DS_GET_FIRST_TUPLE:
772: ret = CardServices(GetFirstTuple, s->handle, &buf.tuple);
773: break;
774: case DS_GET_NEXT_TUPLE:
775: ret = CardServices(GetNextTuple, s->handle, &buf.tuple);
776: break;
777: case DS_GET_TUPLE_DATA:
778: buf.tuple.TupleData = buf.tuple_parse.data;
779: buf.tuple.TupleDataMax = sizeof(buf.tuple_parse.data);
780: ret = CardServices(GetTupleData, s->handle, &buf.tuple);
781: break;
782: case DS_PARSE_TUPLE:
783: buf.tuple.TupleData = buf.tuple_parse.data;
784: ret = CardServices(ParseTuple, s->handle, &buf.tuple,
785: &buf.tuple_parse.parse);
786: break;
787: case DS_RESET_CARD:
788: ret = CardServices(ResetCard, s->handle, NULL);
789: break;
790: case DS_GET_STATUS:
791: ret = CardServices(GetStatus, s->handle, &buf.status);
792: break;
793: case DS_VALIDATE_CIS:
794: ret = CardServices(ValidateCIS, s->handle, &buf.cisinfo);
795: break;
796: case DS_SUSPEND_CARD:
797: ret = CardServices(SuspendCard, s->handle, NULL);
798: break;
799: case DS_RESUME_CARD:
800: ret = CardServices(ResumeCard, s->handle, NULL);
801: break;
802: case DS_EJECT_CARD:
803: ret = CardServices(EjectCard, s->handle, NULL);
804: break;
805: case DS_INSERT_CARD:
806: ret = CardServices(InsertCard, s->handle, NULL);
807: break;
808: case DS_ACCESS_CONFIGURATION_REGISTER:
809: if ((buf.conf_reg.Action == CS_WRITE) && !capable(CAP_SYS_ADMIN))
810: return -EPERM;
811: ret = CardServices(AccessConfigurationRegister, s->handle,
812: &buf.conf_reg);
813: break;
814: case DS_GET_FIRST_REGION:
815: ret = CardServices(GetFirstRegion, s->handle, &buf.region);
816: break;
817: case DS_GET_NEXT_REGION:
818: ret = CardServices(GetNextRegion, s->handle, &buf.region);
819: break;
820: case DS_GET_FIRST_WINDOW:
821: buf.win_info.handle = (window_handle_t)s->handle;
822: ret = CardServices(GetFirstWindow, &buf.win_info.handle,
823: &buf.win_info.window);
824: break;
825: case DS_GET_NEXT_WINDOW:
826: ret = CardServices(GetNextWindow, &buf.win_info.handle,
827: &buf.win_info.window);
828: break;
829: case DS_GET_MEM_PAGE:
830: ret = CardServices(GetMemPage, buf.win_info.handle,
831: &buf.win_info.map);
832: break;
833: case DS_REPLACE_CIS:
834: ret = CardServices(ReplaceCIS, s->handle, &buf.cisdump);
835: break;
836: case DS_BIND_REQUEST:
837: if (!capable(CAP_SYS_ADMIN)) return -EPERM;
838: err = bind_request(i, &buf.bind_info);
839: break;
840: case DS_GET_DEVICE_INFO:
841: err = get_device_info(i, &buf.bind_info, 1);
842: break;
843: case DS_GET_NEXT_DEVICE:
844: err = get_device_info(i, &buf.bind_info, 0);
845: break;
846: case DS_UNBIND_REQUEST:
847: err = unbind_request(i, &buf.bind_info);
848: break;
849: case DS_BIND_MTD:
850: if (!capable(CAP_SYS_ADMIN)) return -EPERM;
851: err = bind_mtd(i, &buf.mtd_info);
852: break;
853: default:
854: err = -EINVAL;
855: }
856:
857: if ((err == 0) && (ret != CS_SUCCESS)) {
858: DEBUG(2, "ds_ioctl: ret = %d\n", ret);
859: switch (ret) {
860: case CS_BAD_SOCKET: case CS_NO_CARD:
861: err = -ENODEV; break;
862: case CS_BAD_ARGS: case CS_BAD_ATTRIBUTE: case CS_BAD_IRQ:
863: case CS_BAD_TUPLE:
864: err = -EINVAL; break;
865: case CS_IN_USE:
866: err = -EBUSY; break;
867: case CS_OUT_OF_RESOURCE:
868: err = -ENOSPC; break;
869: case CS_NO_MORE_ITEMS:
870: err = -ENODATA; break;
871: case CS_UNSUPPORTED_FUNCTION:
872: err = -ENOSYS; break;
873: default:
874: err = -EIO; break;
875: }
876: }
877:
878: #ifndef MACH
879: if (cmd & IOC_OUT) copy_to_user((char *)arg, (char *)&buf, size);
880: #else
881: if (cmd & IOC_OUT) memcpy((char *) arg, (char *) &buf, size);
882: #endif
883:
884: return err;
885: } /* ds_ioctl */
886:
887: /*====================================================================*/
888:
889: #ifndef MACH
890:
891: static struct file_operations ds_fops = {
892: open: ds_open,
893: release: ds_release,
894: ioctl: ds_ioctl,
895: read: ds_read,
896: write: ds_write,
897: #if (LINUX_VERSION_CODE < VERSION(2,1,23))
898: select: ds_select
899: #else
900: poll: ds_poll
901: #endif
902: };
903:
904: #if (LINUX_VERSION_CODE <= VERSION(2,1,17))
905:
906: #undef CONFIG_MODVERSIONS
907: static struct symbol_table ds_symtab = {
908: #include <linux/symtab_begin.h>
909: #undef X
910: #define X(sym) { (void *)&sym, SYMBOL_NAME_STR(sym) }
911: X(register_pccard_driver),
912: X(unregister_pccard_driver),
913: #include <linux/symtab_end.h>
914: };
915:
916: #else
917:
918: EXPORT_SYMBOL(register_pccard_driver);
919: EXPORT_SYMBOL(unregister_pccard_driver);
920:
921: #endif
922:
923: #endif /* !defined(MACH) */
924:
925: /*====================================================================*/
926:
927: int __init init_pcmcia_ds(void)
928: {
929: client_reg_t client_reg;
930: servinfo_t serv;
931: bind_req_t bind;
932: socket_info_t *s;
933: int i, ret;
934:
935: DEBUG(0, "%s\n", version);
936:
937: CardServices(GetCardServicesInfo, &serv);
938: if (serv.Revision != CS_RELEASE_CODE) {
939: printk(KERN_NOTICE "ds: Card Services release does not match!\n");
940: return -EINVAL;
941: }
942: if (serv.Count == 0) {
943: printk(KERN_NOTICE "ds: no socket drivers loaded!\n");
944: return -1;
945: }
946:
947: sockets = serv.Count;
948: socket_table = kmalloc(sockets*sizeof(socket_info_t), GFP_KERNEL);
949: if (!socket_table) return -1;
950: for (i = 0, s = socket_table; i < sockets; i++, s++) {
951: s->state = 0;
952: s->user = NULL;
953: s->req_pending = 0;
954: init_waitqueue_head(&s->queue);
955: init_waitqueue_head(&s->request);
956: s->handle = NULL;
957: init_timer(&s->removal);
958: s->removal.data = i;
959: s->removal.function = &handle_removal;
960: s->bind = NULL;
961: }
962:
963: /* Set up hotline to Card Services */
964: client_reg.dev_info = bind.dev_info = &dev_info;
965: client_reg.Attributes = INFO_MASTER_CLIENT;
966: client_reg.EventMask =
967: CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
968: CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
969: CS_EVENT_EJECTION_REQUEST | CS_EVENT_INSERTION_REQUEST |
970: CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
971: client_reg.event_handler = &ds_event;
972: client_reg.Version = 0x0210;
973: for (i = 0; i < sockets; i++) {
974: bind.Socket = i;
975: bind.Function = BIND_FN_ALL;
976: ret = CardServices(BindDevice, &bind);
977: if (ret != CS_SUCCESS) {
978: cs_error(NULL, BindDevice, ret);
979: break;
980: }
981: client_reg.event_callback_args.client_data = &socket_table[i];
982: ret = CardServices(RegisterClient, &socket_table[i].handle,
983: &client_reg);
984: if (ret != CS_SUCCESS) {
985: cs_error(NULL, RegisterClient, ret);
986: break;
987: }
988: }
989:
990: #ifndef MACH
991: /* Set up character device for user mode clients */
992: i = register_chrdev(0, "pcmcia", &ds_fops);
993: if (i == -EBUSY)
994: printk(KERN_NOTICE "unable to find a free device # for "
995: "Driver Services\n");
996: else
997: major_dev = i;
998: register_symtab(&ds_symtab);
999: #endif
1000:
1001: #ifdef HAS_PROC_BUS
1002: if (proc_pccard)
1003: create_proc_read_entry("drivers", 0, proc_pccard,
1004: proc_read_drivers, NULL);
1005: init_status = 0;
1006: #endif
1007: return 0;
1008: }
1009:
1010: #ifdef MODULE
1011:
1012: int __init init_module(void)
1013: {
1014: return init_pcmcia_ds();
1015: }
1016:
1017: void __exit cleanup_module(void)
1018: {
1019: int i;
1020: #ifdef HAS_PROC_BUS
1021: if (proc_pccard)
1022: remove_proc_entry("drivers", proc_pccard);
1023: #endif
1024: if (major_dev != -1)
1025: unregister_chrdev(major_dev, "pcmcia");
1026: for (i = 0; i < sockets; i++)
1027: CardServices(DeregisterClient, socket_table[i].handle);
1028: sockets = 0;
1029: kfree(socket_table);
1030: }
1031:
1032: #endif
1033:
1034: /*====================================================================*/
1035:
1036: /* Include the interface glue code to GNU Mach. */
1037: #include "../glue/ds.c"
1038:
1039: /*====================================================================*/
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.