学习ldd3--llseek(第六章)

作者:张伟AreS
/*******************************************************************************/
参考刘昊昱博客分析LDD3源代码,
代码:D:\学习\个人学习笔记及网络经典文章\学习LDD3笔记\ldd3_examples\scull\main.c
 
定位 用户空间函数:
  
   int lseek(int fd,off_t offset,int whence);
  
   功能:将文件读写指针相对whence移动offset个字节,操作成功时,返回文件指针相对文件头的位置。
   第一个参数fd是要操作的文件描述符。
   第二个参数指定文件操作指针的偏移量。注意,文件的读和写使用的是同一个文件操作指针。
   第三个参数指定移动文件操作指针的参考点。
   这个参数通常取值为以下宏:
   SEEK_SET:表示相对文件起始位置。
   SEEK_CUR:表示相对文件操作指针当前位置。
   SEEK_END:表示相对文件结束位置。
  
   offset可以取负值,表现向前移动。
   leek(fd,0,SEEK_END)返回的就是文件长度
  
  
   #include
   #include
   #include  
   #include  
   #include  
   #include  
   #define BUF_SIZE 50 
   #define DEVICE_FILE "/dev/scull" 
   
    int main(int argc, char *argv[]) 
    { 
      int fd;
      int num;  
      char buf[BUF_SIZE]; 
     
      fd = open(DEVICE_FILE, O_RDWR); 
       if(fd < 0)  19.19   
       {       
         printf("open scull error!\n"); 
          return -1;  22.22  
           } 
          
    memset(buf, 0, BUF_SIZE); 
    num = read(fd, buf, BUF_SIZE);//num为真实读取的字节数 ,调用驱动程序中read函数读取的字节存入buf
    buf[num] = 0;
    printf("%s\n", buf);
    lseek(fd, 2, SEEK_SET);  //使用SEEK_SET宏,将文件操作指针移动到文件起始位置加上2个字节处
   
    write(fd, "aa", 2); //写入两个字符’a’
    num = read(fd, buf, BUF_SIZE); 
    buf[num] = 0; 
    printf("%s\n", buf); 
   
    lseek(fd, 2, SEEK_SET);
    num = read(fd, buf, BUF_SIZE);
    buf[num] = 0;
    printf("%s\n", buf);
    lseek(fd, 0, SEEK_SET);
    lseek(fd, 2, SEEK_CUR);  //使用SEEK_CUR宏,将文件操作指针移动到文件操作指针当前位置加上2个字节处
    num = read(fd, buf, BUF_SIZE);
    buf[num] = 0;
    printf("%s\n", buf);
    lseek(fd, 0, SEEK_SET);
    lseek(fd, 0, SEEK_END);//使用SEEK_END宏,将文件操作指针移动到文件结束处
    memset(buf, 0, BUF_SIZE);
    printf("read return value is %d.\n", read(fd, buf, BUF_SIZE)); 
   return 0; 
   } 
    
    
    
驱动中llseek:
   
   用户空间的lseek函数的定位功能在驱动程序中是由llseek函数实现的。
   注意,要完成对文件的定位操作,还需要read、write函数的配合,读写完成后必须更新文件操作指针位置。
   即使驱动程序中没有实现llseek函数,有某些情况下,设备也是可以完成定位操作的,
   内核通过修改filp->f_pos来执行定位,filp->f_pos是文件的当前读写位置。
   但是,如果定位操作需要涉及设备的物理操作,就必须实现llseek函数了。
scull设备的llseek函数代码如下:    
loff_t scull_llseek(struct file *filp, loff_t off, int whence)
{
 struct scull_dev *dev = filp->private_data;
 loff_t newpos;
 switch(whence) {
   case 0: /* SEEK_SET */
  newpos = off;
  break;
   case 1: /* SEEK_CUR */
  newpos = filp->f_pos + off;
  break;
   case 2: /* SEEK_END */
  newpos = dev->size + off;//这里是唯一与设备相关的操作,取得设备文件的大小
  break;
   default: /* can't happen */
  return -EINVAL;
 }
 if (newpos < 0) return -EINVAL;
 filp->f_pos = newpos;//更新文件读写指针位置
 return newpos;//文件指针相对文件头的位置
}
scull的read和write函数读写文件后,总是更新文件操作指针的位置,定位功能需要llseek与read、write的配合。
对于某些设备文件来说,定位功能是没有意义的,例如键盘
应该在我们的open函数中调用nonseekable_open,通知内核设备不支持llseek。
该函数的函数原型如下:
int nonseekable_open(struct inode *inode; struct file *filp); 

你可能感兴趣的:(嵌入式)