字符设备驱动读写操作实现

一、读操作实现

ssize_t xxx_read(struct file *filp, char __user *pbuf, size_t count, loff_t *ppos);
完成功能:读取设备产生的数据
参数:
    filp:指向open产生的struct file类型的对象,表示本次read对应的那次open
    pbuf:指向用户空间一块内存,用来保存读到的数据
    count:用户期望读取的字节数
    ppos:对于需要位置指示器控制的设备操作有用,用来指示读取的起始位置,读完后也需要变更位置指示器的指示位置
 返回值:
    本次成功读取的字节数,失败返回-1

put_user(x,ptr)

x:char、int类型的简单变量名

unsigned long copy_to_user (void __user * to, const void * from, unsigned long n)

成功为返回0,失败非0

二、写操作实现

ssize_t xxx_write (struct file *filp, const char __user *pbuf, size_t count, loff_t *ppos);  
完成功能:向设备写入数据
参数:
    filp:指向open产生的struct file类型的对象,表示本次write对应的那次open
    pbuf:指向用户空间一块内存,用来保存被写的数据
    count:用户期望写入的字节数
    ppos:对于需要位置指示器控制的设备操作有用,用来指示写入的起始位置,写完后也需要变更位置指示器的指示位置
 返回值:
    本次成功写入的字节数,失败返回-1

get_user(x,ptr)

x:char、int类型的简单变量名

unsigned long copy_from_user (void * to, const void __user * from, unsigned long n)

成功为返回0,失败非0

实现代码:

mychar.c

#include 
#include 
#include 
#include 
#include 

#define BUF_LEN 100

int major = 11;					//主设备号
int minor = 0;					//次设备号
int char_num = 1;				//设备号数量

struct cdev mydev;

char mydev_buf[BUF_LEN];
int curlen = 0;

int mychar_open (struct inode *pnode, struct file *pfile)//打开设备
{
	printk("open\n");
	return 0;
}

int mychar_close(struct inode *pnode, struct file *pfile)//关闭设备
{
	printk("close\n");
	return 0;
}

ssize_t mychar_read (struct file *pfile, char __user *puser, size_t count, loff_t *p_pos) {
	int size = 0;
	int ret = 0;

	// 确定要读取的数据长度,如果请求大于设备当前数据长度,则读取全部可用数据
	if (count > curlen) {
		size = curlen;
	}
	else {
		size = count;
	}

	// 将设备数据复制到用户空间缓冲区
	ret = copy_to_user(puser, mydev_buf, size);
	if(ret) {
		printk("copy_to_user failed\n");
		return -1;
	}

	// 移动设备内部缓冲区,去除已读取的数据
	memcpy(mydev_buf, mydev_buf + size, curlen - size);

	curlen = curlen - size;
	
	// 返回实际读取的字节数
	return size;
}

ssize_t mychar_write (struct file *pfile, const char __user *puser, size_t count, loff_t *p_pos) {
	int size = 0;
	int ret = 0;

	// 确定要写入的数据长度,如果请求大于设备缓冲区剩余空间,则写入剩余空间大小
	if (count > BUF_LEN - curlen) {
		size = BUF_LEN - curlen;
	}
	else {
		size = count;
	}

	// 从用户空间复制数据到设备缓冲区
	ret = copy_from_user(mydev_buf + curlen, puser, size);
	if(ret) {
		printk("copy_from_user failed\n");
		return -1;
	}

	// 更新设备缓冲区中的数据长度
	curlen = curlen + size;

	 // 返回实际写入的字节数
	return size;
}

struct file_operations myops = {
	.owner = THIS_MODULE,
	.open = mychar_open,
	.read = mychar_read,
	.write = mychar_write,
	.release = mychar_close,
};

int __init mychar_init(void) 
{
	int ret = 0;
	dev_t devno = MKDEV(major, minor);

	/* 手动申请设备号 */
	ret = register_chrdev_region(devno, char_num, "mychar");
	if (ret) {
		/* 动态申请设备号 */
		ret = alloc_chrdev_region(&devno, minor, char_num, "mychar");
		if(ret){
			printk("get devno failed\n");
			return -1;
		}
		/*申请成功 更新设备号*/
		major = MAJOR(devno);
	}
	
	cdev_init(&mydev, &myops);

	mydev.owner = THIS_MODULE;
	cdev_add(&mydev, devno, char_num);

	return 0;
}

void __exit mychar_exit(void) 
{

	dev_t devno = MKDEV(major, minor);
	printk("exit %d\n", devno);
	
	/* 从内核中移除一个字符设备 */
	cdev_del(&mydev);

	/* 回收设备号 */
	unregister_chrdev_region(devno, char_num);

}

MODULE_LICENSE("GPL");
module_init(mychar_init);
module_exit(mychar_exit);

testmychar_app.c

#include 
#include 
#include 
#include 
#include 

int main(int argc, char *argv[])
{
	int fd = -1;
	char buf[32] = "";

	if(argc < 2) {
		printf("The argument is too few\n");
		return -1;
	}

	fd = open(argv[1], O_RDWR);
	if(fd < 0) {
		perror("open");
		return -1;
	}

	write(fd, "hello", 6);

	read(fd, buf, 32);

	printf("buf = %s\n", buf);
	close(fd);
	fd = -1;
	return 0;
}

Makefile

ifeq ($(KERNELRELEASE),)

ifeq ($(ARCH),arm)
KERNELDIR ?= /home/myubuntu/Linux_4412/kernel/linux-3.14 
ROOTFS ?= /opt/4412/rootfs
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
endif
PWD := $(shell pwd)

modules:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules

modules_install:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules INSTALL_MOD_PATH=$(ROOTFS) modules_install

clean:
	rm -rf  *.o  *.ko  .*.cmd  *.mod.*  modules.order  Module.symvers   .tmp_versions

else
# obj-m += myhello.o

# obj-m += mytest.o
# mytest-objs = test.o func.o

# obj-m += testparam.o

obj-m += mychar.o
endif

实现结果:
字符设备驱动读写操作实现_第1张图片

你可能感兴趣的:(驱动开发,linux)