~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/drivers/pcmcia/ds.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.