OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [pcmcia/] [ds.c] - Blame information for rev 1275

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.