taxuewuhen 发表于 2005-5-29 04:40:48

编写块设备驱动程序时遇到的困惑,请指教

我这段时间在学习编写linux下的设备驱动程序,
仿照《linux设备驱动程序 第二版》编写了一个块设备驱动程序实例
编译没问题,编译完后,我把块设备驱动模块加载到系统中
然后我创建了两个块设备文件bf0,bf1
当我使用如下命令时,结果出现无法退出的现象(系统始终运行cp命令,除了CTRL+ALT+DEL外,任何方法都无法让该进程退出,你可以用我的程序试试)
cp tmp bf0 //tmp是任意一个文件,主要是测验是否能读写块设备bf0

肯请各位兄弟姐妹指教,万分感谢


下面是我的程序源代码(这些代码只能在2.4。x的内核中运行):
sbull.h文件的源代码

#include <linux/ioctl.h>

#define SBULL_MAJOR 0       /* dynamic major by default */
#define SBULL_DEVS 2      /* two disks */
#define SBULL_RAHEAD 2      /* two sectors */
#define SBULL_SIZE 2048   /* two megs each */
#define SBULL_BLKSIZE 1024/* 1k blocks */
#define SBULL_HARDSECT 512/* 2.2 and 2.4 can used different values */

typedef struct Sbull_Dev {
    int size;
    char *data;
}                Sbull_Dev;

sbull.c文件的源代码

#ifndef __KERNEL__
#define __KERNEL__
#endif
#ifndef MODULE
#define MODULE
#endif

#include <linux/config.h>
#include <linux/module.h>

#include <linux/kernel.h> /* printk() */
#include <linux/slab.h> /* kmalloc() */
#include <linux/fs.h>   /* everything... */
#include <linux/errno.h>/* error codes */
#include <linux/types.h>/* size_t */
#include <asm/uaccess.h>


#define MAJOR_NR sbull_major /* force definitions on in blk.h */
static int sbull_major; /* must be declared before including blk.h */

#define DEVICE_NR(device) MINOR(device)   /* sbull has no partition bits */
#define DEVICE_NAME "sbull"               /* name for messaging */
#define DEVICE_REQUEST sbull_request

#include <linux/blk.h>

#include "sbull.h"      /* local definitions */

/*
* Non-prefixed symbols are static. They are meant to be assigned at
* load time. Prefixed symbols are not static, so they can be used in
* debugging. They are hidden anyways by register_symtab() unless
* SBULL_DEBUG is defined.
*/
static int major    = SBULL_MAJOR;
static int devs   = SBULL_DEVS;
static int rahead   = SBULL_RAHEAD;
static int size   = SBULL_SIZE;
static int blksize= SBULL_BLKSIZE;
static int hardsect = SBULL_HARDSECT;

int sbull_devs, sbull_rahead, sbull_size;
int sbull_blksize, sbull_hardsect;

/* The following items are obtained through kmalloc() in sbull_init() */
Sbull_Dev *sbull_devices;
int *sbull_blksizes = NULL;
int *sbull_sizes = NULL;
int *sbull_hardsects = NULL;

/*
* Open and close
*/

int sbull_open (struct inode *inode, struct file *filp)
{
    MOD_INC_USE_COUNT;
    return 0;          /* success */
}

int sbull_release (struct inode *inode, struct file *filp)
{
    MOD_DEC_USE_COUNT;
    return 0;
}



/*
* The file operations
*/

struct block_device_operations sbull_bdops = {
    open:               sbull_open,
    release:            sbull_release,
};


/*
* Find the device for this request.
*/
static Sbull_Dev *sbull_locate_device(const struct request *req)
{
    int devno;
    Sbull_Dev *device;

    /* Check if the minor number is in range */
    devno = DEVICE_NR(req->rq_dev);
    if (devno >= sbull_devs)
      return NULL;
    device = sbull_devices + devno;/* Pick it out of our device array */
   
    return device;
}

/*
* Perform an actual transfer.
*/
static int sbull_transfer(Sbull_Dev *device, const struct request *req)
{
    int size;
    char *ptr;
   
    ptr = device->data + req->sector * sbull_hardsect;
    size = req->current_nr_sectors * sbull_hardsect;

    /* Make sure that the transfer fits within the device. */
    if (ptr + size > device->data + sbull_blksize*sbull_size)
      return 0;

    /* Looks good, do the transfer. */
    switch(req->cmd) {
      case READ:
            memcpy(req->buffer, ptr, size); /* from sbull to buffer */
            return 1;
      case WRITE:
            memcpy(ptr, req->buffer, size); /* from buffer to sbull */
            return 1;
      default:
            /* can't happen */
            return 0;
    }
}


void sbull_request(request_queue_t *q)
{
    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. */
      status = sbull_transfer(device, CURRENT);
      end_request(status);
    }
}

/*
* 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;

    /*
   * 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;

   
    /*
   * 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++) {
      sbull_devices[i].size = 1024 * sbull_size;
        sbull_devices[i].data = kmalloc(sbull_size * sbull_blksize * sizeof (char), GFP_KERNEL);
    }

    /*
   * Get the queue set up, and register our (nonexistent) partitions.
   */
      blk_init_queue(BLK_DEFAULT_QUEUE(major), sbull_request);
   
    /* 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);

    printk ("<1>sbull: init complete, %d devs, size %d blks %d hs %d\n",
                  sbull_devs, sbull_size, sbull_blksize, sbull_hardsect);

    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;

   
    /* 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)
*/
    blk_cleanup_queue(BLK_DEFAULT_QUEUE(major));

    /* 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)
            kfree(sbull_devices[i].data);
    }
    kfree(sbull_devices);
}

module_init(sbull_init);
module_exit(sbull_cleanup);
页: [1]
查看完整版本: 编写块设备驱动程序时遇到的困惑,请指教