一、读操作实现
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 <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#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 <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
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
实现结果:
 



















