|
我这段时间在学习编写linux下的设备驱动程序,
仿照《linux设备驱动程序 第二版》编写了一个块设备驱动程序实例
编译没问题,编译完后,我把块设备驱动模块加载到系统中
然后我创建了两个块设备文件bf0,bf1
当我使用如下命令时,结果出现无法退出的现象(系统始终运行cp命令,除了CTRL+ALT+DEL外,任何方法都无法让该进程退出,你可以用我的程序试试)
cp tmp bf0 //tmp是任意一个文件,主要是测验是否能读写块设备bf0
肯请各位兄弟姐妹指教,万分感谢
下面是我的程序源代码(这些代码只能在2.4。x的内核中运行):
sbull.h文件的源代码
[code:1]#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;[/code:1]
sbull.c文件的源代码
[code:1]#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);[/code:1][/code] |
|