LDD3 scull pipe 模块

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)


你可能感兴趣的:(LDD3 scull pipe 模块)