驱动设备的读写操作

int read(int fd, char *buf,int n);+

从设备fd读取n个字节到空间buf中

一、读操作实现------>读数据为内核空间向 用户空间  copy

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:对于需要位置指示器控制的设备操作有用,用来指示读取的起始位置,读完后也需要变更位置指示器的指示位置
ssize_t      ---实际读取的字节数
size_t count--- 期望读取的字节数
 返回值:
    本次成功读取的字节数size,失败返回-1

return size;

put_user(x,ptr)

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

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

void __user * to       用户空间

 const void * from    内核空间

内核空间拷贝到用户空间中去

成功为返回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:对于需要位置指示器控制的设备操作有用,用来指示写入的起始位置,写完后也需要变更位置指示器的指示位置
 返回值:
    本次成功写入的字节数size,失败返回-1

                              ​return size;

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

vi mychar.c

make生成ko文件

make

insmod内核模块  

sudo insmod ./mychar.ko

查阅字符设备用到的设备号(主设备号):

cat /proc/devices | grep 申请设备号时用的名字

cat /proc/devices | grep mychar

创建设备文件(设备节点) :

mknod /dev/??? c 上一步查询到的主设备号 代码中指定初始次设备号

sudo mknod /dev/mydev c 11 0

编写app验证驱动(testmychar_app.c)

将mydev赋予读写权限

sudo chmod a+w /dev/mydev
 

编译运行app,dmesg命令查看内核打印信息
 

.tca /dev/mydev

 mychar.c

#include 
#include 
#include 
#include 
#include 

#define BUF_LEN 100
int major = 11;//主设备号
int minor =0;//次设备号
int mychar_num = 1;//次设备数量
struct cdev mydev;

char mydev_buf[BUF_LEN];
int curlen = 0;//100个字节中已经存有的数据
int mychar_open(struct inode *pnode,struct file *pfile)
{
	printk("mychar_open is called\n");
	return 0;
}

int mychar_close(struct inode *pnode,struct file *pfile)
{
	printk("mychar_close is called\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 ret=0;
	int size = 0;
    if(count>BUF_LEN - curlen)//如果期望写入的数据大小大于100个字节剩余的空间
	{
		size = BUF_LEN - curlen;
	}
	else 
	{
		size = count;
	}
	ret = copy_from_user(mydev_buf,puser,size);
	//将内核空间中size大小的数据写入到内核空间mydev_buf为始的地址中去
	if(ret)
	{
		printk("copy_from_user is failed\n");
		return -1;
	}
	curlen = curlen +size;
	//mydev_buf中存在的数据大小
	return size;

}
struct file_operations myops = {

	.owner = THIS_MODULE,
	.open = mychar_open,
     .release = mychar_close,
	 .read = mychar_read,
	 .write = mychar_write,//一定要记得添加上新加入的含函数
};

int __init mychar_init(void)
{
   int ret = 0;
   dev_t devno = MKDEV(major,minor);//组合成完整的设备号
   /*申请设备号*/
   ret = register_chrdev_region(devno,mychar_num,"mychar");
if(ret)//ret非0,表示失败
{
  ret = alloc_chrdev_region(&devno,minor,mychar_num,"mychar");
//此设备号申请后填写到devno地址中去,从minor开始申请mychar_num个
    if(ret)
	{
		printk("get devno failed\n");
		return -1;
	}
	major = MAJOR(devno);//获取新的设备号,不要遗漏
     //次设备号都是0,所以不用再次提取
}
    //给struct_cdev对象制定操作函数集
	 cdev_init(&mydev,&myops);    
    //将struct_cdev对象添加到内核对应的数据结构里
	mydev.owner = THIS_MODULE;
    cdev_add(&mydev,devno,1);

	return 0;
}

void __exit mychar_exit(void)
{
	dev_t devno = MKDEV(major,minor);
    cdev_del(&mydev);

    unregister_chrdev_region(devno,mychar_num);

}


MODULE_LICENSE("GPL");

module_init(mychar_init);
module_exit(mychar_exit);

 testmychar_app.c 

#include
#include 
#include 
#include 
#include 
#include 



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

	if(argc<2)
	{
		printf("the argument is too few\n");
		return 1;
	}
	fd = open(argv[1],O_RDWR);
	if(fd<0)
	{
		printf("open %s failed\n",argv[1]);
		return 2;
	}
	write(fd,"hello",6);

	read(fd,buf,8);

	printf("buf = %s\n",buf);

	close(fd);
	fd = -1 ;
	return 0;
}

你可能感兴趣的:(数据结构)