LDD 第六章 scull pipe驱动 : 演示休眠与唤醒
scull pipe结构体:
struct scullp_dev {
wait_queue_head_t inq, outq; /* read and write queues */
char *buffer, *end; /* begin of buf, end of buf */
int buffersize; /* used in pointer arithmetic */
char *rp, *wp; /* where to read, where to write */
int nreaders, nwriters; /* number of openings for r/w */
struct fasync_struct *async_queue; /* asynchronous readers */
struct semaphore sem; /* mutual exclusion semaphore */
struct cdev cdev; /* Char device structure */
};
int scullp_major = 0; // 表示要动态分配主设备号
int scullp_minor = 0; // 次设备号
int scullp_nr_devs = 1; // 设备数
int scull_p_buffer = 4000; // 缓冲区大小
file_operations 结构体:
/*
* The file operations for the pipe device
* (some are overlayed with bare scull)
*/
struct file_operations scull_pipe_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = scull_p_read,
.write = scull_p_write,
.poll = scull_p_poll,
.open = scull_p_open,
.release = scull_p_release,
.fasync = scull_p_fasync,
};
初始化和退出函数:
/*
* Set up the char_dev structure for this device.
*/
static void scullp_setup_cdev(struct scullp_dev *dev, int index)
{
int err, devno = MKDEV(scullp_major, scullp_minor + index);
cdev_init(&dev->cdev, &scull_pipe_fops);
dev->cdev.owner = THIS_MODULE;
dev->cdev.ops = &scull_pipe_fops;
err = cdev_add (&dev->cdev, devno, 1);
/* Fail gracefully if need be */
if (err)
printk(KERN_NOTICE "Error %d adding scull%d", err, index);
}
void scullp_cleanup_module(void)
{
int i;
dev_t devno = MKDEV(scullp_major, scullp_minor);
if (!scullp_dev)
return; /* nothing else to release */
for (i = 0; i < scullp_nr_devs; i++) {
cdev_del(&scullp_dev[i].cdev);
kfree(scullp_dev[i].buffer);
}
kfree(scullp_dev);
unregister_chrdev_region(devno, scullp_nr_devs);
scullp_dev = NULL; /* pedantic */
}
int scullp_init(void)
{
int result, i;
dev_t dev = 0;
/*
* Get a range of minor numbers to work with, asking for a dynamic
* major unless directed otherwise at load time.
*/
if (scullp_major) {
dev = MKDEV(scullp_major, scullp_minor);
result = register_chrdev_region(dev, scullp_nr_devs, "scullp");
} else {
result = alloc_chrdev_region(&dev, scullp_minor, scullp_nr_devs,
"scullp");
scullp_major = MAJOR(dev);
}
if (result < 0) {
printk(KERN_WARNING "scull: can't get major %d\n", scullp_major);
return result;
}
/*
* allocate the devices -- we can't have them static, as the number
* can be specified at load time
*/
scullp_dev = kmalloc(scullp_nr_devs * sizeof(struct scullp_dev), GFP_KERNEL);
if (!scullp_dev) {
result = -ENOMEM;
goto fail; /* Make this more graceful */
}
memset(scullp_dev, 0, scullp_nr_devs * sizeof(struct scullp_dev));
/* Initialize each device. */
for (i = 0; i < scullp_nr_devs; i++) {
init_waitqueue_head(&(scullp_dev[i].inq));
init_waitqueue_head(&(scullp_dev[i].outq));
init_MUTEX(&scullp_dev[i].sem);
scullp_setup_cdev(scullp_dev + i, i);
}
return 0; /* succeed */
fail:
scullp_cleanup_module();
return result;
}
module_init(scullp_init);
module_exit(scullp_cleanup_module);
装载脚本:
#!/bin/sh
module="scull"
device="scull"
mode="664"
/sbin/insmod ./$module.ko $* || exit 1
major=$(awk "\$2==\"$module\" {print \$1}" /proc/devices)
# scull pipe
rm -f /dev/${device}p
mknod /dev/${device}p c $major 0
测试:
# cat /dev/scullp &
scull: "cat" reading: going to sleep
# echo "hello">/dev/scullp
scull: Going to accept 6 bytes to c39c2000 from 40001000
scull: "sh" did write 6 bytes
scull: "cat" did read 6 bytes
hscull: "cat" reading: going to sleep
ello
所有代码在这里
此外Makefile中这部分内容用于调试的时候使用:
# enable / disable debugging and
# don't forget to set current log level to 8:
# echo 8 >/proc/sys/kernel/printk
# run this command on your mini2440 develop board
DEBUG = y
ifeq ($(DEBUG),y)
DEBFLAGS = -DSCULL_DEBUG
else
DEBFLAGS =
endif
EXTRA_CFLAGS += $(DEBFLAGS)