⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sbull.c

📁 Linux Device Drivers 2nd 经典书籍的配套源码
💻 C
📖 第 1 页 / 共 2 页
字号:
#endif                                  {    while(1) {        INIT_REQUEST;        printk("<1>request %p: cmd %i sec %li (nr. %li)\n", CURRENT,               CURRENT->cmd,               CURRENT->sector,               CURRENT->current_nr_sectors);        end_request(1); /* success */    }}#elif defined(SBULL_MULTIQUEUE)  /* 2.4 only *//* * Clean up this request. */int sbull_end_request(struct request *req, int status){    if (end_that_request_first(req, status, DEVICE_NAME))        return 1;    end_that_request_last(req);    return 0;}void sbull_request(request_queue_t *q){    Sbull_Dev *device;    struct request *req;    int status;    /* Find our device */    device = sbull_locate_device (blkdev_entry_next_request(&q->queue_head));    if (device->busy) /* no race here - io_request_lock held */        return;    device->busy = 1;    /* Process requests in the queue */    while(! list_empty(&q->queue_head)) {    /* Pull the next request off the list. */        req = blkdev_entry_next_request(&q->queue_head);        blkdev_dequeue_request(req);        spin_unlock_irq (&io_request_lock);        spin_lock(&device->lock);    /* Process all of the buffers in this (possibly clustered) request. */        do {            status = sbull_transfer(device, req);        } while (end_that_request_first(req, status, DEVICE_NAME));        spin_unlock(&device->lock);        spin_lock_irq (&io_request_lock);        end_that_request_last(req);    }    device->busy = 0;}/* * Tell the block layer where to queue a request. */request_queue_t *sbull_find_queue(kdev_t device){    int devno = DEVICE_NR(device);    if (devno >= sbull_devs) {        static int count = 0;        if (count++ < 5) /* print the message at most five times */            printk(KERN_WARNING "sbull: request for unknown device\n");        return NULL;    }    return &sbull_devices[devno].queue;}#else /* not SBULL_MULTIQUEUE */#ifdef LINUX_24                                 void sbull_request(request_queue_t *q)#else                                           void sbull_request()                            #endif                                          {    Sbull_Dev *device;    int status;    while(1) {        INIT_REQUEST;  /* returns when queue is empty */        /* Which "device" are we using? */        device = sbull_locate_device (CURRENT);        if (device == NULL) {            end_request(0);            continue;        }        /* Perform the transfer and clean up. */	spin_lock(&device->lock);        status = sbull_transfer(device, CURRENT);        spin_unlock(&device->lock);        end_request(status);     }}#endif /* not SBULL_EMPTY_REQUEST nor SBULL_MULTIQUEUE *//* * Finally, the module stuff */int sbull_init(void){    int result, i;    /*     * Copy the (static) cfg variables to public prefixed ones to allow     * snoozing with a debugger.     */    sbull_major    = major;    sbull_devs     = devs;    sbull_rahead   = rahead;    sbull_size     = size;    sbull_blksize  = blksize;    sbull_hardsect = hardsect;#ifdef LINUX_20    /* Hardsect can't be changed :( */    if (hardsect != 512) {        printk(KERN_ERR "sbull: can't change hardsect size\n");        hardsect = sbull_hardsect = 512;    }#endif    /*     * Register your major, and accept a dynamic number     */    result = register_blkdev(sbull_major, "sbull", &sbull_bdops);    if (result < 0) {        printk(KERN_WARNING "sbull: can't get major %d\n",sbull_major);        return result;    }    if (sbull_major == 0) sbull_major = result; /* dynamic */    major = sbull_major; /* Use `major' later on to save typing */    /*     * Assign the other needed values: request, rahead, size, blksize,     * hardsect. All the minor devices feature the same value.     * Note that `sbull' defines all of them to allow testing non-default     * values. A real device could well avoid setting values in global     * arrays if it uses the default values.     */    read_ahead[major] = sbull_rahead;    result = -ENOMEM; /* for the possible errors */    sbull_sizes = kmalloc(sbull_devs * sizeof(int), GFP_KERNEL);    if (!sbull_sizes)        goto fail_malloc;    for (i=0; i < sbull_devs; i++) /* all the same size */        sbull_sizes[i] = sbull_size;    blk_size[major]=sbull_sizes;    sbull_blksizes = kmalloc(sbull_devs * sizeof(int), GFP_KERNEL);    if (!sbull_blksizes)        goto fail_malloc;    for (i=0; i < sbull_devs; i++) /* all the same blocksize */        sbull_blksizes[i] = sbull_blksize;    blksize_size[major]=sbull_blksizes;    sbull_hardsects = kmalloc(sbull_devs * sizeof(int), GFP_KERNEL);    if (!sbull_hardsects)        goto fail_malloc;    for (i=0; i < sbull_devs; i++) /* all the same hardsect */        sbull_hardsects[i] = sbull_hardsect;    hardsect_size[major]=sbull_hardsects;    /* FIXME: max_readahead and max_sectors */         /*      * allocate the devices -- we can't have them static, as the number     * can be specified at load time     */    sbull_devices = kmalloc(sbull_devs * sizeof (Sbull_Dev), GFP_KERNEL);    if (!sbull_devices)        goto fail_malloc;    memset(sbull_devices, 0, sbull_devs * sizeof (Sbull_Dev));    for (i=0; i < sbull_devs; i++) {        /* data and usage remain zeroed */        sbull_devices[i].size = 1024 * sbull_size;        init_timer(&(sbull_devices[i].timer));        sbull_devices[i].timer.data = (unsigned long)(sbull_devices+i);        sbull_devices[i].timer.function = sbull_expires;        spin_lock_init(&sbull_devices[i].lock);    }    /*     * Get the queue set up, and register our (nonexistent) partitions.     */  #ifdef SBULL_MULTIQUEUE    for (i = 0; i < sbull_devs; i++) {        blk_init_queue(&sbull_devices[i].queue, sbull_request);        blk_queue_headactive(&sbull_devices[i].queue, 0);    }    blk_dev[major].queue = sbull_find_queue;#else#  ifdef LINUX_24    if (noqueue)        blk_queue_make_request(BLK_DEFAULT_QUEUE(major), sbull_make_request);    else#  endif /* LINUX_24 */        blk_init_queue(BLK_DEFAULT_QUEUE(major), sbull_request);#endif    /* A no-op in 2.4.0, but all drivers seem to do it anyway */    for (i = 0; i < sbull_devs; i++)            register_disk(NULL, MKDEV(major, i), 1, &sbull_bdops,                            sbull_size << 1);#ifndef SBULL_DEBUG    EXPORT_NO_SYMBOLS; /* otherwise, leave global symbols visible */#endif    printk ("<1>sbull: init complete, %d devs, size %d blks %d hs %d\n",                    sbull_devs, sbull_size, sbull_blksize, sbull_hardsect);#ifdef SBULL_MULTIQUEUE    printk ("<1>sbull: Using multiqueue request\n");#elif defined(LINUX_24)    if (noqueue)            printk (KERN_INFO "sbull: using direct make_request\n");#endif#ifdef DO_RAW_INTERFACE    sbullr_init();#endif    return 0; /* succeed */  fail_malloc:    read_ahead[major] = 0;    if (sbull_sizes) kfree(sbull_sizes);    blk_size[major] = NULL;    if (sbull_blksizes) kfree(sbull_blksizes);    blksize_size[major] = NULL;    if (sbull_hardsects) kfree(sbull_hardsects);    hardsect_size[major] = NULL;    if (sbull_devices) kfree(sbull_devices);    unregister_blkdev(major, "sbull");    return result;}void sbull_cleanup(void){    int i;/* * Before anything else, get rid of the timer functions.  Set the "usage" * flag on each device as well, under lock, so that if the timer fires up * just before we delete it, it will either complete or abort.  Otherwise * we have nasty race conditions to worry about. */    for (i = 0; i < sbull_devs; i++) {        Sbull_Dev *dev = sbull_devices + i;        del_timer(&dev->timer);        spin_lock(&dev->lock);        dev->usage++;        spin_unlock(&dev->lock);    }#ifdef DO_RAW_INTERFACE    sbullr_release();#endif        /* flush it all and reset all the data structures */    for (i=0; i<sbull_devs; i++)        fsync_dev(MKDEV(sbull_major, i)); /* flush the devices */    unregister_blkdev(major, "sbull");/* * Fix up the request queue(s) */#ifdef SBULL_MULTIQUEUE    for (i = 0; i < sbull_devs; i++)            blk_cleanup_queue(&sbull_devices[i].queue);    blk_dev[major].queue = NULL;#else    blk_cleanup_queue(BLK_DEFAULT_QUEUE(major));#endif       /* Clean up the global arrays */    read_ahead[major] = 0;    kfree(blk_size[major]);    blk_size[major] = NULL;    kfree(blksize_size[major]);    blksize_size[major] = NULL;    kfree(hardsect_size[major]);    hardsect_size[major] = NULL;    /* FIXME: max_readahead and max_sectors */     /* finally, the usual cleanup */    for (i=0; i < sbull_devs; i++) {        if (sbull_devices[i].data)            vfree(sbull_devices[i].data);    }    kfree(sbull_devices);}/* * Below here is the "raw device" implementation, available only * in 2.4. */#ifdef DO_RAW_INTERFACE/* * Transfer an iovec */static int sbullr_rw_iovec(Sbull_Dev *dev, struct kiobuf *iobuf, int rw,                int sector, int nsectors){    struct request fakereq;    struct page *page;    int offset = iobuf->offset, ndone = 0, pageno, result;    /* Perform I/O on each sector */    fakereq.sector = sector;    fakereq.current_nr_sectors = 1;    fakereq.cmd = rw;        for (pageno = 0; pageno < iobuf->nr_pages; pageno++) {        page = iobuf->maplist[pageno];        while (ndone < nsectors) {            /* Fake up a request structure for the operation */            fakereq.buffer = (void *) (kmap(page) + offset);            result = sbull_transfer(dev, &fakereq);	    kunmap(page);            if (result == 0)                return ndone;            /* Move on to the next one */            ndone++;            fakereq.sector++;            offset += SBULLR_SECTOR;            if (offset >= PAGE_SIZE) {                offset = 0;                break;            }        }    }    return ndone;}/* * Handle actual transfers of data. */static int sbullr_transfer (Sbull_Dev *dev, char *buf, size_t count,                loff_t *offset, int rw){    struct kiobuf *iobuf;           int result;        /* Only block alignment and size allowed */    if ((*offset & SBULLR_SECTOR_MASK) || (count & SBULLR_SECTOR_MASK))        return -EINVAL;    if ((unsigned long) buf & SBULLR_SECTOR_MASK)        return -EINVAL;    /* Allocate an I/O vector */    result = alloc_kiovec(1, &iobuf);    if (result)        return result;    /* Map the user I/O buffer and do the I/O. */    result = map_user_kiobuf(rw, iobuf, (unsigned long) buf, count);    if (result) {        free_kiovec(1, &iobuf);        return result;    }    spin_lock(&dev->lock);    result = sbullr_rw_iovec(dev, iobuf, rw, *offset >> SBULLR_SECTOR_SHIFT,                    count >> SBULLR_SECTOR_SHIFT);    spin_unlock(&dev->lock);    /* Clean up and return. */    unmap_kiobuf(iobuf);    free_kiovec(1, &iobuf);    if (result > 0)        *offset += result << SBULLR_SECTOR_SHIFT;    return result << SBULLR_SECTOR_SHIFT;}/* * Read and write syscalls. */ssize_t sbullr_read(struct file *filp, char *buf, size_t size, loff_t *off){    Sbull_Dev *dev = sbull_devices + MINOR(filp->f_dentry->d_inode->i_rdev);    return sbullr_transfer(dev, buf, size, off, READ);}ssize_t sbullr_write(struct file *filp, const char *buf, size_t size,                loff_t *off){    Sbull_Dev *dev = sbull_devices + MINOR(filp->f_dentry->d_inode->i_rdev);    return sbullr_transfer(dev, (char *) buf, size, off, WRITE);}static int sbullr_registered = 0;static struct file_operations sbullr_fops = {   read:        sbullr_read,   write:       sbullr_write,   open:        sbull_open,   release:     sbull_release,   ioctl:	sbull_ioctl,};static void sbullr_init(){    int result;            /* Simplify the math */    if (sbull_hardsect != SBULLR_SECTOR) {        printk(KERN_NOTICE "Sbullr requires hardsect = %d\n", SBULLR_SECTOR);        return;    }    SET_MODULE_OWNER(&sbullr_fops);    result = register_chrdev(sbullr_major, "sbullr", &sbullr_fops);    if (result >= 0)        sbullr_registered = 1;    if (sbullr_major == 0)        sbullr_major = result;}static void sbullr_release(){    if (sbullr_registered)        unregister_chrdev(sbullr_major, "sbullr");}#endif /* DO_RAW_INTERFACE */module_init(sbull_init);module_exit(sbull_cleanup);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -