字符设备驱动框架及测试程序

1. 驱动框架

1.1 驱动文件: my_cdev.c

#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/slab.h>


#define MAX_DEV_CNT 65535 


/*define my device*/
struct my_cdev {
	int len;
	unsigned char buf[100];
	struct cdev cdev;
};
struct my_cdev *my_cdev;

static dev_t dev_num;

struct class *my_cdev_class;

static ssize_t my_cdev_read(struct file *file, char __user *buffer, size_t count,
			  loff_t *ppos)
{
	struct my_cdev *dev = file->private_data;

	if (copy_to_user(buffer, &dev->buf, count)) 
		printk("read failed.\n");

	return sizeof(int);
}

static ssize_t my_cdev_write(struct file *file, const char __user *buffer,
			   size_t count, loff_t *ppos)
{
	struct my_cdev *dev = file->private_data;
	int i;

	if (copy_from_user(&dev->buf, buffer, count))
		printk("write failed.\n");
	for (i = 0; i < count; i++)
		printk("dev->buf[%d] = %c\n", i, dev->buf[i]);

	return sizeof(int);
}


	
static int my_cdev_open(struct inode *inode, struct file *file)
{

	struct my_cdev *mycd;

	mycd  = container_of(inode->i_cdev, struct my_cdev, cdev);
    	file->private_data = mycd;

	printk("my char device is opened.\n");

	return 0;
}


static int my_cdev_release(struct inode *inode, struct file *filp)
{	
	printk("my char device is closed.\n");
	return 0;
}

static const struct file_operations my_cdev_fops = {
	.owner		= THIS_MODULE,
	.read		= my_cdev_read,
	.write		= my_cdev_write,
	.open		= my_cdev_open,
	.release	= my_cdev_release,
};

int __init my_cdev_init(void)
{
	int ret = 0;

	/*1. alloc memory for my device defined.*/
	my_cdev = kzalloc(sizeof(struct my_cdev), GFP_KERNEL);	
	if (!my_cdev) {
		printk("can't alloc memory for this device.\n");
		goto err;
		ret = -ENOMEM;
	}

	/*2. register device number for the char device.*/
	ret = alloc_chrdev_region(&dev_num, 0, MAX_DEV_CNT, "my_cdev"); //a dynamic way.
	if (ret < 0) {
		printk("register the device number failed.\n");
		goto err;
	}

	/*3. initialize and add the char device.*/ 
	cdev_init(&my_cdev->cdev, &my_cdev_fops);
	ret = cdev_add(&my_cdev->cdev, dev_num, MAX_DEV_CNT);
	if (ret < 0){
		printk("add the device failed.\n");
		goto cdev_add_failed;
	}

	/*4. create a device class and export the device's info into userspace.*/ 
	my_cdev_class = class_create(THIS_MODULE, "mycdev");	//create a class under /sys/class/ dir.

	if (IS_ERR(my_cdev_class)) {
		printk(KERN_ERR "Error creating mycdev class.\n");
		cdev_del(&my_cdev->cdev);
		goto cdev_add_failed;
	}
	device_create(my_cdev_class, NULL, dev_num, NULL, "my_cdev");


	printk("my chardev initialized.\n");
	return ret;

cdev_add_failed:
	unregister_chrdev_region(dev_num, MAX_DEV_CNT);	
err:
	kfree(my_cdev);

	return ret;
}

void __exit my_cdev_exit(void)
{
	device_destroy(my_cdev_class, dev_num);
	class_destroy(my_cdev_class);
	cdev_del(&my_cdev->cdev);
	unregister_chrdev_region(dev_num, MAX_DEV_CNT);	
	printk("my chardev removed.\n");

}

module_init(my_cdev_init);
module_exit(my_cdev_exit);

MODULE_LICENSE("GPL"); 
MODULE_AUTHOR("2247720389@qq.com");
MODULE_DESCRIPTION("A char device driver frame");
  

1.2 Makefile

obj-m += my_cdev.o
KERN_DIR := /lib/modules/$(shell uname -r)/build

all:
	$(MAKE) -C $(KERN_DIR) M=`pwd` modules

.PHONY: clean
clean:
	make -C $(KERN_DIR) M=`pwd` clean

2. 驱动测试程序

2.1 测试文件: my_cdev_test.c

/* a test for my_cdev driver */

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>

#define W_SIZE 10
#define R_SIZE 8

int main(int argc, char **argv)
{

	int fd;
	unsigned char w_buffer[100] = {'h','e','l','l','o','w','o','r','l','d'};
	unsigned char r_buffer[100] = {0};
	int i;
	int ret;

	fd = open("/dev/my_cdev", O_RDWR);
	if (fd < 0)
		printf("can't open the device!\n");
	printf("***hello world*** fd = %d\n", fd);

	ret = write(fd, w_buffer, W_SIZE);
	if (ret == -1)
		printf("sorry, write failed.\n");
	
	ret = read(fd, r_buffer, R_SIZE);
	if (ret == -1)
		printf("sorry, read failed.\n");
	for (i = 0; i < R_SIZE; i++)
		printf("r_buffer[%d] = %c\n", i, r_buffer[i]);

	close(fd);
	
	return 0;
	
}

2.2 Makefile

all: 
	gcc -o my_cdev_test my_cdev_test.c

clean:
	rm -rf *.o
	rm -rf my_cdev_test

3. 测试结果(全程打开dmesg)

3.0 全程打开dmesg

# dmesg -w

3.1 加载driver

# insmod my_cdev.ko
# cat /proc/devices

在这里插入图片描述

# ls -a /sys/class/mycdev/my_cdev/

在这里插入图片描述

3.2 运行test程序

# ./my_cdev_test

在这里插入图片描述

3.3 卸载driver

# rmmod my_cdev
driver卸载后,再次查看/proc/devices和/sys/class,则无my_cdev信息。

4. 附dmesg

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值