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)