[BACK]Return to device.c CVS log [TXT][DIR] Up to [local] / prex-old / sys / kern

Annotation of prex-old/sys/kern/device.c, Revision 1.1.1.1.2.1

1.1       nbrk        1: /*-
                      2:  * Copyright (c) 2005-2007, Kohsuke Ohtani
                      3:  * All rights reserved.
                      4:  *
                      5:  * Redistribution and use in source and binary forms, with or without
                      6:  * modification, are permitted provided that the following conditions
                      7:  * are met:
                      8:  * 1. Redistributions of source code must retain the above copyright
                      9:  *    notice, this list of conditions and the following disclaimer.
                     10:  * 2. Redistributions in binary form must reproduce the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer in the
                     12:  *    documentation and/or other materials provided with the distribution.
                     13:  * 3. Neither the name of the author nor the names of any co-contributors
                     14:  *    may be used to endorse or promote products derived from this software
                     15:  *    without specific prior written permission.
                     16:  *
                     17:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
                     18:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     19:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     20:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
                     21:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     22:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     23:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     24:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     25:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     26:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     27:  * SUCH DAMAGE.
                     28:  */
                     29:
                     30: /*
                     31:  * device.c - device I/O support routines
                     32:  */
                     33:
                     34: /*
1.1.1.1.2.1! nbrk       35:  * The device_* system calls are interfaces for user mode
        !            36:  * applications to access the specific device object which is
        !            37:  * handled by the related device driver. A device driver is an
        !            38:  * execution module different from a kernel on Prex. The routines
        !            39:  * in this file have the following role to handle the device I/O.
1.1       nbrk       40:  *
                     41:  *  - Manage the name space for device objects.
1.1.1.1.2.1! nbrk       42:  *  - Forward user I/O requests to the drivers after checking
        !            43:  *    parameters.
1.1       nbrk       44:  *
1.1.1.1.2.1! nbrk       45:  * The driver module(s) and kernel are dynamically linked
        !            46:  * at system boot.
1.1       nbrk       47:  */
                     48:
                     49: #include <kernel.h>
                     50: #include <irq.h>
                     51: #include <page.h>
                     52: #include <kmem.h>
                     53: #include <task.h>
                     54: #include <timer.h>
                     55: #include <sched.h>
                     56: #include <exception.h>
                     57: #include <vm.h>
                     58: #include <device.h>
                     59: #include <system.h>
                     60:
                     61: /* forward declarations */
1.1.1.1.2.1! nbrk       62: static device_t         device_create(struct devio *, const char *, int);
        !            63: static int      device_destroy(device_t);
        !            64: static int      device_broadcast(int, int);
        !            65:
        !            66: static void     machine_bootinfo(struct boot_info **);
        !            67: static void     _machine_reset(void);
        !            68: static void     _machine_idle(void);
        !            69: static int      _task_capable(cap_t);
        !            70: static void    *_phys_to_virt(void *);
        !            71: static void    *_virt_to_phys(void *);
1.1       nbrk       72:
1.1.1.1.2.1! nbrk       73: #ifdef DEBUG
        !            74: #define _debug_attach  debug_attach
        !            75: #define _debug_dump    debug_dump
        !            76: #define _printf                printf
        !            77: #define _panic         panic
        !            78: #else
        !            79: #define _debug_attach  nosys
        !            80: #define _debug_dump    nosys
        !            81: #define _printf                nosys
        !            82: #define _panic         machine_reset
1.1       nbrk       83: static void nosys(void);
                     84: #endif
                     85:
                     86: typedef void (*dkifn_t)(void);
                     87:
                     88: #define DKIENT(func)   (dkifn_t)(func)
                     89:
                     90: /*
                     91:  * Driver-Kernel Interface (DKI)
                     92:  */
                     93: static const dkifn_t driver_service[] = {
                     94:        /*  0 */ DKIENT(device_create),
                     95:        /*  1 */ DKIENT(device_destroy),
                     96:        /*  2 */ DKIENT(device_broadcast),
                     97:        /*  3 */ DKIENT(umem_copyin),
                     98:        /*  4 */ DKIENT(umem_copyout),
                     99:        /*  5 */ DKIENT(umem_strnlen),
                    100:        /*  6 */ DKIENT(kmem_alloc),
                    101:        /*  7 */ DKIENT(kmem_free),
                    102:        /*  8 */ DKIENT(kmem_map),
                    103:        /*  9 */ DKIENT(page_alloc),
                    104:        /* 10 */ DKIENT(page_free),
                    105:        /* 11 */ DKIENT(page_reserve),
                    106:        /* 12 */ DKIENT(irq_attach),
                    107:        /* 13 */ DKIENT(irq_detach),
                    108:        /* 14 */ DKIENT(irq_lock),
                    109:        /* 15 */ DKIENT(irq_unlock),
                    110:        /* 16 */ DKIENT(timer_callout),
                    111:        /* 17 */ DKIENT(timer_stop),
                    112:        /* 18 */ DKIENT(timer_delay),
                    113:        /* 19 */ DKIENT(timer_count),
                    114:        /* 20 */ DKIENT(timer_hook),
                    115:        /* 21 */ DKIENT(sched_lock),
                    116:        /* 22 */ DKIENT(sched_unlock),
                    117:        /* 23 */ DKIENT(sched_tsleep),
                    118:        /* 24 */ DKIENT(sched_wakeup),
                    119:        /* 25 */ DKIENT(sched_dpc),
1.1.1.1.2.1! nbrk      120:        /* 26 */ DKIENT(_task_capable),
1.1       nbrk      121:        /* 27 */ DKIENT(exception_post),
                    122:        /* 28 */ DKIENT(machine_bootinfo),
1.1.1.1.2.1! nbrk      123:        /* 29 */ DKIENT(_machine_reset),
        !           124:        /* 30 */ DKIENT(_machine_idle),
        !           125:        /* 31 */ DKIENT(_phys_to_virt),
        !           126:        /* 32 */ DKIENT(_virt_to_phys),
        !           127:        /* 33 */ DKIENT(_debug_attach),
        !           128:        /* 34 */ DKIENT(_debug_dump),
        !           129:        /* 35 */ DKIENT(_printf),
        !           130:        /* 36 */ DKIENT(_panic),
1.1       nbrk      131: };
                    132:
                    133: static struct list device_list;                /* list of the device objects */
                    134:
                    135: /*
                    136:  * Increment reference count on an active device.
1.1.1.1.2.1! nbrk      137:  * It returns 0 on success, or -1 if the device is invalid.
1.1       nbrk      138:  */
                    139: static int
                    140: device_hold(device_t dev)
                    141: {
                    142:        int err = -1;
                    143:
                    144:        sched_lock();
                    145:        if (device_valid(dev)) {
1.1.1.1.2.1! nbrk      146:                dev->refcnt++;
1.1       nbrk      147:                err = 0;
                    148:        }
                    149:        sched_unlock();
                    150:        return err;
                    151: }
                    152:
                    153: /*
1.1.1.1.2.1! nbrk      154:  * Decrement the reference count on a device. If the
        !           155:  * reference count becomes zero, we can release the
        !           156:  * resource for the target device. Assumes the device
        !           157:  * is already validated by caller.
1.1       nbrk      158:  */
                    159: static void
                    160: device_release(device_t dev)
                    161: {
                    162:
                    163:        sched_lock();
1.1.1.1.2.1! nbrk      164:        if (--dev->refcnt == 0) {
1.1       nbrk      165:                list_remove(&dev->link);
                    166:                kmem_free(dev);
                    167:        }
                    168:        sched_unlock();
                    169: }
                    170:
                    171: /*
                    172:  * Look up a device object by device name.
                    173:  * Return device ID on success, or NULL on failure.
                    174:  * This must be called with scheduler locked.
                    175:  */
                    176: static device_t
                    177: device_lookup(const char *name)
                    178: {
                    179:        list_t head, n;
                    180:        device_t dev;
                    181:
                    182:        if (name == NULL)
                    183:                return NULL;
                    184:
                    185:        head = &device_list;
                    186:        for (n = list_first(head); n != head; n = list_next(n)) {
                    187:                dev = list_entry(n, struct device, link);
                    188:                if (!strncmp(dev->name, name, MAXDEVNAME))
                    189:                        return dev;
                    190:        }
                    191:        return NULL;
                    192: }
                    193:
                    194: /*
                    195:  * device_create - create new device object.
                    196:  *
                    197:  * A device object is created by the device driver to provide
                    198:  * I/O services to applications.
                    199:  * Returns device ID on success, or 0 on failure.
                    200:  */
                    201: static device_t
                    202: device_create(struct devio *io, const char *name, int flags)
                    203: {
                    204:        device_t dev;
                    205:        size_t len;
                    206:
                    207:        ASSERT(irq_level == 0);
                    208:
                    209:        len = strnlen(name, MAXDEVNAME);
                    210:        if (len == 0 || len >= MAXDEVNAME)      /* Invalid name? */
                    211:                return 0;
                    212:
                    213:        sched_lock();
                    214:        if ((dev = device_lookup(name)) != NULL) {
                    215:                /*
                    216:                 * Error - the device name is already used.
                    217:                 */
                    218:                sched_unlock();
                    219:                return 0;
                    220:        }
                    221:        if ((dev = kmem_alloc(sizeof(struct device))) == NULL) {
                    222:                sched_unlock();
                    223:                return 0;
                    224:        }
                    225:        strlcpy(dev->name, name, len + 1);
                    226:        dev->devio = io;
                    227:        dev->flags = flags;
1.1.1.1.2.1! nbrk      228:        dev->refcnt = 1;
1.1       nbrk      229:        dev->magic = DEVICE_MAGIC;
                    230:        list_insert(&device_list, &dev->link);
                    231:        sched_unlock();
                    232:        return dev;
                    233: }
                    234:
                    235: /*
1.1.1.1.2.1! nbrk      236:  * Destroy a device object. If some other threads still
        !           237:  * refer the target device, the destroy operating will be
        !           238:  * pending until its reference count becomes 0.
1.1       nbrk      239:  */
                    240: static int
                    241: device_destroy(device_t dev)
                    242: {
                    243:        int err = 0;
                    244:
                    245:        ASSERT(irq_level == 0);
                    246:
                    247:        sched_lock();
                    248:        if (device_valid(dev))
                    249:                device_release(dev);
                    250:        else
                    251:                err = ENODEV;
                    252:        sched_unlock();
                    253:        return err;
                    254: }
                    255:
                    256: /*
                    257:  * device_open - open the specified device.
                    258:  *
1.1.1.1.2.1! nbrk      259:  * Even if the target driver does not have an open
        !           260:  * routine, this function does not return an error. By
        !           261:  * using this mechanism, an application can check whether
        !           262:  * the specific device exists or not. The open mode
        !           263:  * should be handled by an each device driver if it is
        !           264:  * needed.
1.1       nbrk      265:  */
                    266: int
                    267: device_open(const char *name, int mode, device_t *devp)
                    268: {
                    269:        char str[MAXDEVNAME];
                    270:        device_t dev;
                    271:        size_t len;
                    272:        int err = 0;
                    273:
                    274:        if (!task_capable(CAP_DEVIO))
                    275:                return EPERM;
                    276:
                    277:        if (umem_strnlen(name, MAXDEVNAME, &len))
                    278:                return EFAULT;
                    279:        if (len == 0)
                    280:                return ENOENT;
                    281:        if (len >= MAXDEVNAME)
                    282:                return ENAMETOOLONG;
                    283:
1.1.1.1.2.1! nbrk      284:        if (umem_copyin(name, str, len + 1))
1.1       nbrk      285:                return EFAULT;
                    286:
                    287:        sched_lock();
                    288:        if ((dev = device_lookup(str)) == NULL) {
                    289:                sched_unlock();
                    290:                return ENXIO;
                    291:        }
                    292:        device_hold(dev);
                    293:        sched_unlock();
                    294:
                    295:        if (dev->devio->open != NULL)
1.1.1.1.2.1! nbrk      296:                err = (*dev->devio->open)(dev, mode);
1.1       nbrk      297:
                    298:        if (!err)
1.1.1.1.2.1! nbrk      299:                err = umem_copyout(&dev, devp, sizeof(dev));
1.1       nbrk      300:        device_release(dev);
                    301:        return err;
                    302: }
                    303:
                    304: /*
                    305:  * device_close - close a device.
                    306:  *
                    307:  * Even if the target driver does not have close routine,
                    308:  * this function does not return any errors.
                    309:  */
                    310: int
                    311: device_close(device_t dev)
                    312: {
                    313:        int err = 0;
                    314:
                    315:        if (!task_capable(CAP_DEVIO))
                    316:                return EPERM;
                    317:
                    318:        if (device_hold(dev))
                    319:                return ENODEV;
                    320:
                    321:        if (dev->devio->close != NULL)
1.1.1.1.2.1! nbrk      322:                err = (*dev->devio->close)(dev);
1.1       nbrk      323:
                    324:        device_release(dev);
                    325:        return err;
                    326: }
                    327:
                    328: /*
                    329:  * device_read - read from a device.
                    330:  *
1.1.1.1.2.1! nbrk      331:  * Actual read count is set in "nbyte" as return.
1.1       nbrk      332:  * Note: The size of one block is device dependent.
                    333:  */
                    334: int
                    335: device_read(device_t dev, void *buf, size_t *nbyte, int blkno)
                    336: {
                    337:        size_t count;
                    338:        int err;
                    339:
                    340:        if (!task_capable(CAP_DEVIO))
                    341:                return EPERM;
                    342:
                    343:        if (device_hold(dev))
                    344:                return ENODEV;
                    345:
                    346:        if (dev->devio->read == NULL) {
                    347:                device_release(dev);
                    348:                return EBADF;
                    349:        }
1.1.1.1.2.1! nbrk      350:        if (umem_copyin(nbyte, &count, sizeof(count))) {
1.1       nbrk      351:                device_release(dev);
                    352:                return EFAULT;
                    353:        }
1.1.1.1.2.1! nbrk      354:        err = (*dev->devio->read)(dev, buf, &count, blkno);
1.1       nbrk      355:        if (err == 0)
1.1.1.1.2.1! nbrk      356:                err = umem_copyout(&count, nbyte, sizeof(count));
        !           357:
1.1       nbrk      358:        device_release(dev);
                    359:        return err;
                    360: }
                    361:
                    362: /*
                    363:  * device_write - write to a device.
1.1.1.1.2.1! nbrk      364:  *
        !           365:  * Actual write count is set in "nbyte" as return.
1.1       nbrk      366:  */
                    367: int
                    368: device_write(device_t dev, void *buf, size_t *nbyte, int blkno)
                    369: {
                    370:        size_t count;
                    371:        int err;
                    372:
                    373:        if (!task_capable(CAP_DEVIO))
                    374:                return EPERM;
                    375:
                    376:        if (device_hold(dev))
                    377:                return ENODEV;
                    378:
                    379:        if (dev->devio->write == NULL) {
                    380:                device_release(dev);
                    381:                return EBADF;
                    382:        }
1.1.1.1.2.1! nbrk      383:        if (umem_copyin(nbyte, &count, sizeof(count))) {
1.1       nbrk      384:                device_release(dev);
                    385:                return EFAULT;
                    386:        }
1.1.1.1.2.1! nbrk      387:        err = (*dev->devio->write)(dev, buf, &count, blkno);
1.1       nbrk      388:        if (err == 0)
1.1.1.1.2.1! nbrk      389:                err = umem_copyout(&count, nbyte, sizeof(count));
1.1       nbrk      390:
                    391:        device_release(dev);
                    392:        return err;
                    393: }
                    394:
                    395: /*
1.1.1.1.2.1! nbrk      396:  * device_ioctl - I/O control request.
1.1       nbrk      397:  *
                    398:  * A command and an argument are completely device dependent.
1.1.1.1.2.1! nbrk      399:  * The ioctl routine of each driver must validate the user buffer
        !           400:  * pointed by the arg value.
1.1       nbrk      401:  */
                    402: int
1.1.1.1.2.1! nbrk      403: device_ioctl(device_t dev, u_long cmd, void *arg)
1.1       nbrk      404: {
1.1.1.1.2.1! nbrk      405:        int err = EBADF;
1.1       nbrk      406:
                    407:        if (!task_capable(CAP_DEVIO))
                    408:                return EPERM;
                    409:
                    410:        if (device_hold(dev))
                    411:                return ENODEV;
                    412:
                    413:        if (dev->devio->ioctl != NULL)
1.1.1.1.2.1! nbrk      414:                err = (*dev->devio->ioctl)(dev, cmd, arg);
1.1       nbrk      415:
                    416:        device_release(dev);
                    417:        return err;
                    418: }
                    419:
                    420: /*
                    421:  * device_broadcast - broadcast an event to all device objects.
                    422:  *
1.1.1.1.2.1! nbrk      423:  * If "force" argument is true, a kernel will continue event
1.1       nbrk      424:  * notification even if some driver returns error. In this case,
                    425:  * this routine returns EIO error if at least one driver returns
                    426:  * an error.
                    427:  *
                    428:  * If force argument is false, a kernel stops the event processing
                    429:  * when at least one driver returns an error. In this case,
                    430:  * device_broadcast will return the error code which is returned
                    431:  * by the driver.
                    432:  */
                    433: static int
                    434: device_broadcast(int event, int force)
                    435: {
                    436:        device_t dev;
                    437:        list_t head, n;
                    438:        int err, ret = 0;
                    439:
                    440:        sched_lock();
                    441:        head = &device_list;
                    442:        for (n = list_first(head); n != head; n = list_next(n)) {
                    443:                dev = list_entry(n, struct device, link);
1.1.1.1.2.1! nbrk      444:                if (dev->devio->event != NULL) {
        !           445:                        /*
        !           446:                         * Call driver's event routine.
        !           447:                         */
        !           448:                        err = (*dev->devio->event)(event);
        !           449:                        if (err) {
        !           450:                                if (force)
        !           451:                                        ret = EIO;
        !           452:                                else {
        !           453:                                        ret = err;
        !           454:                                        break;
        !           455:                                }
1.1       nbrk      456:                        }
                    457:                }
                    458:        }
                    459:        sched_unlock();
                    460:        return ret;
                    461: }
                    462:
                    463: /*
                    464:  * Return device information (for devfs).
                    465:  */
                    466: int
                    467: device_info(struct info_device *info)
                    468: {
                    469:        u_long index, target = info->cookie;
                    470:        device_t dev;
                    471:        struct devio *io;
                    472:        list_t head, n;
1.1.1.1.2.1! nbrk      473:        int err = ESRCH;
1.1       nbrk      474:
                    475:        sched_lock();
                    476:        index = 0;
                    477:        head = &device_list;
1.1.1.1.2.1! nbrk      478:        for (n = list_first(head); n != head; n = list_next(n)) {
1.1       nbrk      479:                dev = list_entry(n, struct device, link);
                    480:                io = dev->devio;
1.1.1.1.2.1! nbrk      481:                if (index == target) {
        !           482:                        info->id = dev;
        !           483:                        info->flags = dev->flags;
        !           484:                        strlcpy(info->name, dev->name, MAXDEVNAME);
        !           485:                        err = 0;
1.1       nbrk      486:                        break;
1.1.1.1.2.1! nbrk      487:                }
        !           488:                index++;
1.1       nbrk      489:        }
                    490:        sched_unlock();
1.1.1.1.2.1! nbrk      491:        return err;
1.1       nbrk      492: }
                    493:
                    494: #ifndef DEBUG
1.1.1.1.2.1! nbrk      495: /*
        !           496:  * nonexistent driver service.
        !           497:  */
1.1       nbrk      498: static void
                    499: nosys(void)
                    500: {
                    501: }
                    502: #endif
                    503:
                    504: /*
                    505:  * Check the capability of the current task.
                    506:  */
                    507: static int
1.1.1.1.2.1! nbrk      508: _task_capable(cap_t cap)
1.1       nbrk      509: {
                    510:
                    511:        return task_capable(cap);
                    512: }
                    513:
                    514: /*
                    515:  * Return boot information
                    516:  */
                    517: static void
                    518: machine_bootinfo(struct boot_info **info)
                    519: {
                    520:        ASSERT(info != NULL);
                    521:
                    522:        *info = boot_info;
                    523: }
                    524:
                    525: static void
1.1.1.1.2.1! nbrk      526: _machine_reset(void)
1.1       nbrk      527: {
                    528:
                    529:        machine_reset();
                    530: }
                    531:
                    532: static void
1.1.1.1.2.1! nbrk      533: _machine_idle(void)
1.1       nbrk      534: {
                    535:
                    536:        machine_idle();
                    537: }
                    538:
                    539: /*
1.1.1.1.2.1! nbrk      540:  *  Address translation (physical -> virtual)
1.1       nbrk      541:  */
                    542: static void *
1.1.1.1.2.1! nbrk      543: _phys_to_virt(void *phys)
1.1       nbrk      544: {
                    545:
                    546:        return phys_to_virt(phys);
                    547: }
                    548:
                    549: /*
1.1.1.1.2.1! nbrk      550:  *  Address translation (virtual -> physical)
1.1       nbrk      551:  */
                    552: static void *
1.1.1.1.2.1! nbrk      553: _virt_to_phys(void *virt)
1.1       nbrk      554: {
                    555:
                    556:        return virt_to_phys(virt);
                    557: }
                    558:
                    559: /*
                    560:  * Initialize device driver module.
                    561:  */
                    562: void
                    563: device_init(void)
                    564: {
1.1.1.1.2.1! nbrk      565:        struct module *mod;
1.1       nbrk      566:        void (*drv_entry)(const dkifn_t *);
                    567:
                    568:        list_init(&device_list);
                    569:
1.1.1.1.2.1! nbrk      570:        mod = &boot_info->driver;
        !           571:        if (mod == NULL)
1.1       nbrk      572:                return;
                    573:
1.1.1.1.2.1! nbrk      574:        drv_entry = (void (*)(const dkifn_t *))mod->entry;
1.1       nbrk      575:        if (drv_entry == NULL)
                    576:                return;
                    577:        /*
1.1.1.1.2.1! nbrk      578:         * Call all initialization functions in drivers.
1.1       nbrk      579:         */
1.1.1.1.2.1! nbrk      580:        (*drv_entry)(driver_service);
1.1       nbrk      581: }

CVSweb