汤臣倍健网站建设方案,wordpress后台怎么登入,网站的互动功能,网上购物网站开发主要的文件操作方法实现文件操作函数有很多的操作接口#xff0c;驱动编程需要实现这些接口#xff0c;在用户编程时候系统调用时候会调用到这些操作structfile_operations {...loff_t (*llseek) (structfile *, loff_t,int);ssize_t (*read) (structfile *,char__user *,siz…主要的文件操作方法实现文件操作函数有很多的操作接口驱动编程需要实现这些接口在用户编程时候系统调用时候会调用到这些操作structfile_operations {...loff_t (*llseek) (structfile *, loff_t,int);ssize_t (*read) (structfile *,char__user *,size_t, loff_t *);ssize_t (*write) (structfile *,constchar__user *,size_t, loff_t *);int(*open) (structinode *,structfile *);int(*release) (structinode *,structfile *);...};以上只列出了主要的操作下面会依次介绍:本次的测试代码上传在char_step2结构体首先 我们会模拟写一个不操作任何设备而仅仅是存储的一个驱动。定义自己的一个结构体为structsimple_dev{chardata[MAX_SIMPLE_LEN];loff_t count;structsemaphore semp;};data 保存数据 count表示文件的数据有效的位置 semp是一个信号量锁在以后的编程中使用之后的程序中结构体也会做相应的变化以适应linux编写驱动的习惯open方法打开设备并进一步初始化工作在没有定义open方法时内核以一种默认的方式打开设备保证每次都能正确打开。open方法中有有struct inode参数包含了设备号程序中可以使用次设备号得到正操作的设备在struct file中主要的操作是private_data指针他可以传递任何自己创建的结构。总得说来open方法的作用有31、获得操作的设备(通过设备号)2、进一步的初始化设备3、初始化file结构体的private_datastaticintsimple_open(structinode *inodp,structfile *filp){structsimple_dev *temp_dev NULL;intminor 0;#if SIMPLE_DEBUGprintk(KERN_INFO In %s \n, __func__);#endifminor iminor(inodp);//获得操作的设备的次设备号if(minor DEV_COUNT-1){printk(KERN_ERR the char dev in invalid \n);return-ENODEV;}#if SIMPLE_DEBUGprintk(KERN_INFO the minor is %d \n, minor);#endiftemp_dev char2_dev[minor];//获得真正操作的设备/* 进一步 初始化设备 因为是操作一个模拟的设备 故省去*/filp-private_data temp_dev; //初始化 private_datareturn0;}release方法主要是对open进一步初始化的操作的反操作比如open时候分配了内存在release时就需要释放它等例子中因为操作内存设备故在release时无需做什么事read方法read 是把设备中的数据传递给调用者主要步骤1、检测偏移量有效(有些设备驱动不需要检测)2、检测用户空间地址有效3、将数据传给用户(在此步骤中调用的函数可能会自己检测步骤2)4、调整偏移量5、返回读到的数据长度(read write 用法相对灵活不要依赖上边的步骤,设备驱动程序要根据设备特性去设计此方法)这里先介绍一个会检测用户空间地址是否有效的copy函数用户调用read读设备而在内核空间就是将数据传给用户是一个to的操作unsignedlong__must_check copy_to_user(void__user *to,constvoid*from, unsignedlongn)__must_check表述必须检测其返回值操作成功返回0不成功返回负的错误码to是用户空间指针 也就是read函数传入的用户空间的指针from指向设备要传送的数据n标识传入长度上图是 摘自LDD3上的经典视图 应该比较能说明read的方法staticssize_t simple_read(structfile *filp,char__user *userstr,size_tcount, loff_t *loff){structsimple_dev *dev NULL;intdata_remain 0;interr;#if SIMPLE_DEBUGprintk(KERN_INFO In %s \n, __func__);#endifdev filp-private_data;data_remain dev-count - *loff;if(MAX_SIMPLE_LEN {printk(KERN_ERR the offset is illegal in func %s \n,__func__ );return-EINVAL;}elseif(data_remain 0){printk(KERN_WARNING there was not much data in the device\n);return0;}else{if(count data_remain){#if SIMPLE_DEBUGprintk(KERN_INFO the data is less than the user want to read\n);#endifcount data_remain;}else{}}err copy_to_user(userstr, (dev-data)(*loff), count); //调用内核函数进行数据拷贝它会检测用户地址是否有效if(err ! 0){printk(KERN_ERR an error occured when copy data to user\n);returnerr;}else{#if SIMPLE_DEBUGprintk(KERN_INFO data copy to user OK\n);#endif*loff *loff count; //调整偏移量returncount;//返回写入的数据量}}write方法与read类似 它是从用户传数据给设备驱动从内核空间看就是一个从用户空间取数据 是一个from操作long__must_check strncpy_from_user(char*dst,constchar__user *src,longcount)dst 驱动保存数据的地址src 用户空间传入的数据count 标识数据长度staticssize_t simple_write(structfile *filp,constchar__user *userstr,size_tcount, loff_t *loff){structsimple_dev *dev NULL;interr;intremain_space 0;#if SIMPLE_DEBUGprintk(KERN_INFO In %s\n,__func__);#endifdev filp-private_data;if(MAX_SIMPLE_LEN *loff)//检测偏移量{printk(KERN_ERR the offset is illegal in func %s\n, __func__);return-EINVAL;}else{remain_space MAX_SIMPLE_LEN - *loff;if(count remain_space){#if SIMPLE_DEBUGprintk(KERN_WARNING the data is to long to write to the device\n);#endifcount remain_space;}else{}}err copy_from_user((dev-data)(*loff),userstr,count);//取得数据if(err ! 0){printk(KERN_ERR an error occured when copy data from user\n);returnerr;}else{#if SIMPLE_DEBUGprintk(KERN_INFO data copy from user OK\n);#endif*loff *loff count; //跳着偏移if(*loff dev-count){dev-count *loff;}else{}returncount;//返回写入的数据量}}lseek方法根据用户传入的参数调整文件偏移modeSEEK_SET从文件起始处开始偏移SEEK_CUR从文件当前位置计算偏移SEEK_END从文件末尾计算偏移file结构的f_pos保存了文件的偏移量在调整文件偏移后需要 更新file中得f_pos成员staticloff_t simple_llseek(structfile *filp, loff_t loff,intmode){structsimple_dev *dev NULL;loff_t tmp_len;#if SIMPLE_DEBUGprintk(KERN_INFO In %s\n,__func__);#endifdev filp-private_data;switch( mode ){caseSEEK_SET:if( loff {printk(KERN_ERR cant move above file line %d \n, __LINE__);return-1;}elseif(loff dev-count){printk(KERN_ERR offset is too long line %d\n, __LINE__);return-1;}else{filp-f_pos loff;}break;caseSEEK_CUR:if((tmp_len filp-f_posloff) {printk(KERN_ERR cant move above file line %d \n, __LINE__);return-1;}elseif(tmp_len dev-count){printk(KERN_ERR offset is too long line %d\n, __LINE__);return-1;}else{filp-f_pos tmp_len;}break;caseSEEK_END:if((tmp_len dev-countloff ) {printk(KERN_ERR cant move above file line %d \n, __LINE__);return-1;}elseif(tmp_len dev-count){printk(KERN_ERR offset is too long line %d\n, __LINE__);return-1;}else{filp-f_pos tmp_len;}break;default:printk(KERN_INFO illigal lseek mode! \n);return-1;break;}returnfilp-f_pos;}