ARM-第八次

作者: 帅碧 | 来源:发表于2017-01-13 16:10 被阅读9次

    1.主设备号:表示某类设备
    2.次设备号:表示某个设备

    文件描述符fd

    • 通过文件描述符的下标得到文件指针,通过文件指针的地址,访问文件信息得到(文件标志,当前位置偏移量,v节点指针),调用一次则占用一个文件下标即一个文件信息

    驱动函数

    
    C库:  fopen fclose fread fwrite fseek ftell
    
    系统
    调用  open  close  read  write  lseek  lseek
    
    驱动
    程序  open release read write  llseek  llseek(驱动程序里完成核心操作,辅助操作系统代替完成)
    
    

    驱动函数的代码

    /*======================================================================
        A globalmem driver as an example of char device drivers  
       
        The initial developer of the original code is Hiro Wang
        <author@linuxdriver.cn>. All Rights Reserved.
    ======================================================================*/
    #include <linux/module.h>
    #include <linux/types.h>
    #include <linux/fs.h>
    #include <linux/errno.h>
    #include <linux/mm.h>
    #include <linux/sched.h>
    #include <linux/init.h>
    #include <linux/cdev.h>
    #include <asm/io.h>
    #include <asm/system.h>
    #include <asm/uaccess.h>
    
    #include <linux/slab.h>
    
    #define GLOBALMEM_SIZE  0x1000  /*全局内存最大4K字节*/
    #define MEM_CLEAR 0x1  /*清0全局内存*/
    #define GLOBALMEM_MAJOR 288    /*预设的globalmem的主设备号*/
    
    static int globalmem_major = GLOBALMEM_MAJOR;
    /*globalmem设备结构体*/
    struct globalmem_dev                                     
    {                                                        
      struct cdev cdev; /*cdev结构体*/                       
      unsigned char mem[GLOBALMEM_SIZE]; /*全局内存*/        
    };
    
    struct globalmem_dev *globalmem_devp; /*设备结构体指针*/
    /*文件打开函数*/
    int globalmem_open(struct inode *inode, struct file *filp)//参数是系统调用open()函数时,内核空间执行的辅助代码传给驱动函数open
    {
      /*将设备结构体指针赋值给文件私有数据指针*/
      filp->private_data = globalmem_devp;
      return 0;
    }
    /*文件释放函数*/
    int globalmem_release(struct inode *inode, struct file *filp)
    {
      return 0;
    }
    
    /* ioctl设备控制函数 */
    /* old version
    static int globalmem_ioctl(struct inode *inodep, struct file *filp, unsigned
      int cmd, unsigned long arg)*/
      //可以去操作状态寄存器与控制寄存器(read,write只能操作数据寄存器,想要得到状态,或者修改运行状态只能用ioctl驱动函数)
    static long globalmem_ioctl(struct file *filp, unsigned
      int cmd, unsigned long arg)
    {
      struct globalmem_dev *dev = filp->private_data;/*获得设备结构体指针*/
    
      switch (cmd)//请求做什么
      {
        case MEM_CLEAR://对那个空间做清空操作
          memset(dev->mem, 0, GLOBALMEM_SIZE);      
          filp->f_pos = 0;
          printk(KERN_INFO "globalmem is set to zero\n");
          break;
    
        default:
          return  - EINVAL;
      }
      return 0;
    }
    
    /*读函数*/
    static ssize_t globalmem_read(struct file *filp, char __user *buf, size_t size,loff_t *ppos)//第一个参数:文件描述符,第二个参数:buf里面保存的是用户空间的地址,第三个参数:读size个字节,第四个参数:当前位置
    {
      unsigned long p =  *ppos;//当前位置,在文件里多少字节
      unsigned int count = size;
      int ret = 0;
      struct globalmem_dev *dev = filp->private_data; /*获得设备结构体指针*/
    
      /*分析和获取有效的写长度*/
      if (p >= GLOBALMEM_SIZE)//表示p指向的全局内存外面去了,越界,即是异常判断
        return count ?  - ENXIO: 0;
      if (count > GLOBALMEM_SIZE - p)//期望读的字节数大与还剩下的字节数
        count = GLOBALMEM_SIZE - p;//
    
      /*内核空间->用户空间*/
      if (copy_to_user(buf, (void*)(dev->mem + p), count))//从p指向的当前位置开始读内核空间地址的count字节的内容读用户空间
      {
        ret =  - EFAULT;//失败,返回一个非法值
      }
      else
      {
        *ppos += count;//
        ret = count;//
        
        printk(KERN_INFO "read %d bytes(s) from %d\n", count, (int)p);
      }
    
      return ret;
    }
    
    /*写函数*/
    static ssize_t globalmem_write(struct file *filp, const char __user *buf,
      size_t size, loff_t *ppos)
    {
      unsigned long p =  *ppos;
      unsigned int count = size;
      int ret = 0;
      struct globalmem_dev *dev = filp->private_data; /*获得设备结构体指针*/
      
      /*分析和获取有效的写长度*/
      if (p >= GLOBALMEM_SIZE)
        return count ?  - ENXIO: 0;
      if (count > GLOBALMEM_SIZE - p)
        count = GLOBALMEM_SIZE - p;
        
      /*用户空间->内核空间*/
      if (copy_from_user(dev->mem + p, buf, count))//把用户空间里的内容count个字节写到内核空间里去
        ret =  - EFAULT;
      else
      {
        *ppos += count;//当前位置指示器要变大
        ret = count;//实际写的字节数
        
        printk(KERN_INFO "written %d bytes(s) from %d\n", count, (int)p);
      }
    
      return ret;
    }
    
    /* seek文件定位函数 */
    static loff_t globalmem_llseek(struct file *filp, loff_t offset, int orig)
    {//orig:
      loff_t ret = 0;
      switch (orig)
      {
        //文件头开始偏移
        case 0:   /*相对文件开始位置偏移*/
          if (offset < 0)
          {
            ret =  - EINVAL;
            break;
          }
          if ((unsigned int)offset > GLOBALMEM_SIZE)
          {
            ret =  - EINVAL;
            break;
          }
          //当前位置偏移量等于要偏移的字节数
          filp->f_pos = (unsigned int)offset;
          ret = filp->f_pos;//返回实际偏移的数
          break;
        case 1:   /*相对文件当前位置偏移*/
          if ((filp->f_pos + offset) > GLOBALMEM_SIZE)
          {
            ret =  - EINVAL;
            break;
          }
          if ((filp->f_pos + offset) < 0)
          {
            ret =  - EINVAL;
            break;
          }
          filp->f_pos += offset;
          ret = filp->f_pos;
          break;
        case 2:   /*相对文件尾位置偏移*/
          if (offset > 0)
          {
            ret =  - EINVAL;
            break;
          }
          if ((0-offset) > GLOBALMEM_SIZE)
          {
            ret =  - EINVAL;
            break;
          }
          filp->f_pos = GLOBALMEM_SIZE + offset;
          ret = filp->f_pos;
          break;
        default:
          ret =  - EINVAL;
          break;
      }
      return ret;
    }
    
    /*文件操作结构体*/
    static const struct file_operations globalmem_fops =
    {//const表示只读变量
    //以下是内核驱动函数
      .owner = THIS_MODULE,//固定填THIS
      .llseek = globalmem_llseek,
      .read = globalmem_read,
      .write = globalmem_write,
      .unlocked_ioctl = globalmem_ioctl,
      .open = globalmem_open,
      .release = globalmem_release,//相当于close
    };
    
    /*初始化并注册cdev*/
    //传进来一个指针和此设备号
    static void globalmem_setup_cdev(struct globalmem_dev *dev, int index)
    {
      int err, devno = MKDEV(globalmem_major, index);//将设备加入内核管理
    
      //cdev_init第一个传的结构体第一个成员的地址
      //第二个是一个结构体类型变量的初始化
      //有了结构体变量的首地址,就能查看别的所有的成员内容
      cdev_init(&dev->cdev, &globalmem_fops);//将fops里的对象的指针赋值给dev_cdev,open之后,找到与打开的设备号相同的设备
      dev->cdev.owner = THIS_MODULE;
     // dev->cdev.ops = &globalmem_fops;
      err = cdev_add(&dev->cdev, devno, 1);//添加到字符设备链表里面
      if (err)
        printk(KERN_NOTICE "Error %d when adding cdev %d", err, index);
    }
    
    /*设备驱动模块加载函数*/
    static int __init globalmem_init(void)
    {
      int result = -1;
      dev_t devno = MKDEV(globalmem_major, 0);//globalmem_major:主设备号,0:次设备号,dev_t:整型
    
      /* 申请设备号*/
      if (globalmem_major)//向内核提问,这个设备号是否已经被占用了,如果占用了就失败了,没有占用我就占用成功
      {
        result = register_chrdev_region(devno, 1, "globalmem");//在第一个目录下有一个设备文件,名字为globalmem
      }
      if(result < 0)  /* 动态申请设备号 */
      {//占用了,就向内核提问,有没有空的主设备号
        result = alloc_chrdev_region(&devno, 0, 1, "globalmem");
        globalmem_major = MAJOR(devno);//将主设备号放到globalmem_major中
      }  
      if (result < 0)
        return result;
        
      /* 动态申请设备结构体的内存*/
      globalmem_devp = (struct globalmem_dev *)kmalloc(sizeof(struct globalmem_dev), GFP_KERNEL);//kmalloc内核不能用C库的malloc,只能用kmalloc,需要空间只是一小块是就用GFP_KERNEL
      if (!globalmem_devp)    /*申请失败*/
      {
        result =  - ENOMEM;
        goto fail_malloc;
      }
      memset(globalmem_devp, 0, sizeof(struct globalmem_dev));//空间里是不确定的内容,所以要memset清除
      
      globalmem_setup_cdev(globalmem_devp, 0);
      return 0;
    
      fail_malloc: unregister_chrdev_region(devno, 1);
      return result;
    }
    
    /*模块卸载函数*/
    static void __exit globalmem_exit(void)
    {
      cdev_del(&globalmem_devp->cdev);   /*注销cdev*/
      kfree(globalmem_devp);     /*释放设备结构体内存*/
      unregister_chrdev_region(MKDEV(globalmem_major, 0), 1); /*释放设备号*/
    }
    
    MODULE_AUTHOR("Hiro Wang");
    MODULE_LICENSE("Dual BSD/GPL");
    
    module_param(globalmem_major, int, S_IRUGO);
    
    module_init(globalmem_init);
    module_exit(globalmem_exit);
    
    

    测试驱动函数的代码

    /*包含操作系统的头文件*/
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <sys/ioctl.h>
    
    /*包含C库的头文件*/
    #include <stdio.h>
    
    /*包含第三方库的头文件*/
    
    
    /*包含自定义的头文件*/
    
    int main(void)
    {
        int fd=-1;
        char buf[20]="1234567890123456789";
        char outbuf[20]="";
        fd=open("/dev/globalmem",O_RDWR);
        if(fd<0)
        {   
            printf("Open failed\n");
            return 1;
        }
        write(fd,buf,20);
        lseek(fd,0,SEEK_SET);
        read(fd,outbuf,20);
        printf("Outbuf:%s\n",outbuf);
    
        ioctl(fd,1,0);
    
        write(fd,"hello",6);
        lseek(fd,0,SEEK_SET);
        read(fd,outbuf,6);
        printf("Outbuf:%s\n",outbuf);
    
        close(fd);
        return 0;
    }
    
    
    • 运行结果,首先将globalmem驱动函数下载到开发板的
    Paste_Image.png
    • 运行结果,再者将写好的测试驱动程序的代码编译,如下编译,-Wall,能很好的把一些看不到的警告显示出来
    Paste_Image.png
    • 运行结果,再将测试代码下载到开发板里,结果出现顺序乱掉是因为驱动程序里的printk函数的优先级比printf的优先级高
    Paste_Image.png Paste_Image.png

    1.以上的代码的问题:读和写只能非阻塞,不能阻塞(即程序不能进行睡眠)
    2.如果同时打开两个设备文件的话,则会发生进程问题

    升级版

    1.驱动函数

    /*======================================================================
        A globalfifo driver as an example of char device drivers  
        This example is to introduce poll,blocking and non-blocking access
          
        The initial developer of the original code is Baohua Song
        <author@linuxdriver.cn>. All Rights Reserved.
    ======================================================================*/
    #include <linux/module.h>
    #include <linux/types.h>
    #include <linux/fs.h>
    #include <linux/errno.h>
    #include <linux/mm.h>
    #include <linux/sched.h>
    #include <linux/init.h>
    #include <linux/cdev.h>
    #include <asm/io.h>
    #include <asm/system.h>
    #include <asm/uaccess.h>
    #include <linux/poll.h>
    
    #include <linux/slab.h>
    #define GLOBALFIFO_SIZE 0x1000  /*È«ŸÖfifo×îŽó4K×ÖœÚ*/
    #define FIFO_CLEAR 0x1  /*Çå0È«ŸÖÄÚŽæµÄ³€¶È*/
    #define GLOBALFIFO_MAJOR 253    /*Ô€ÉèµÄglobalfifoµÄÖ÷É豞ºÅ*/
    
    static int globalfifo_major = GLOBALFIFO_MAJOR;
    /*globalfifoÉ豞œá¹¹Ìå*/
    struct globalfifo_dev                                     
    {                                                        
      struct cdev cdev; /*cdevœá¹¹Ìå*/                       
      unsigned int current_len;    /*¿¿¿¿*/
      unsigned char mem[GLOBALFIFO_SIZE]; /*¿¿¿¿*/        
      wait_queue_head_t r_wait; /*¿¿¿¿¿*/     
      wait_queue_head_t w_wait; /*¿¿¿¿¿*/     
    };
    
    struct globalfifo_dev *globalfifo_devp; /*É豞œá¹¹ÌåÖžÕë*/
    /*ÎÄŒþŽò¿ªº¯Êý*/
    int globalfifo_open(struct inode *inode, struct file *filp)
    {
      /*œ«É豞œá¹¹ÌåÖžÕëž³ÖµžøÎÄŒþËœÓÐÊýŸÝÖžÕë*/
      filp->private_data = globalfifo_devp;
      return 0;
    }
    /*ÎÄŒþÊͷź¯Êý*/
    int globalfifo_release(struct inode *inode, struct file *filp)
    {
      return 0;
    }
    
    /* ioctlÉ豞¿ØÖƺ¯Êý */
    static long globalfifo_ioctl(struct file *filp, unsigned
      int cmd, unsigned long arg)
    {
      struct globalfifo_dev *dev = filp->private_data;/*»ñµÃÉ豞œá¹¹ÌåÖžÕë*/
    
      switch (cmd)
      {
        case FIFO_CLEAR:
          dev->current_len = 0;
          memset(dev->mem,0,GLOBALFIFO_SIZE);
          printk(KERN_INFO "globalfifo is set to zero\n");      
          break;
    
        default:
          return  - EINVAL;
      }
      return 0;
    }
    
    static unsigned int globalfifo_poll(struct file *filp, poll_table *wait)
    {
      unsigned int mask = 0;
      struct globalfifo_dev *dev = filp->private_data; /*»ñµÃÉ豞œá¹¹ÌåÖžÕë*/
      
      poll_wait(filp, &dev->r_wait, wait);
      poll_wait(filp, &dev->w_wait, wait);  
      /*fifo·Ç¿Õ*/
      if (dev->current_len != 0)//¿¿¿¿¿¿¿0
      {
        mask |= POLLIN | POLLRDNORM;//¿¿¿¿|¿¿
      }
      /*fifo·ÇÂú*/
      if (dev->current_len != GLOBALFIFO_SIZE)//¿¿¿¿¿¿¿¿¿¿¿
      {
        mask |= POLLOUT | POLLWRNORM; /*¿¿¿¿|¿¿*/
      }
         
      return mask;
    }
    
    
    /*globalfifo¶Áº¯Êý*/
    static ssize_t globalfifo_read(struct file *filp, char __user *buf, size_t count,
      loff_t *ppos)
    {
      int ret;
      struct globalfifo_dev *dev = filp->private_data; //»ñµÃÉ豞œá¹¹ÌåÖžÕë
      DECLARE_WAITQUEUE(wait, current); //¿¿¿¿¿¿,¿¿¿THis¿¿,¿¿¿¿wait¿¿
    
      add_wait_queue(&dev->r_wait, &wait); //¿¿¿¿¿¿¿¿¿¿
    
      /**/
      //printk("Driver:"KERN_INFO"Have no data in device!\n");
      //¿¿¿¿¿1,¿¿¿¿¿¿,¿¿¿0,¿¿¿¿¿
      //¿¿¿¿¿¿¿¿¿,¿¿¿¿¿¿¿0,¿¿¿¿¿¿,¿read¿¿¿¿¿¿
      if((filp->f_flags & O_NONBLOCK) && dev->current_len == 0){
         //printk("Driver:"KERN_INFO"device is set as NONBLOACK!\n");
         ret =  - EAGAIN;
         //¿¿¿¿¿¿¿goto
         goto out;
         //¿¿¿¿¿¿¿,¿¿¿¿¿¿¿,¿¿¿¿¿
      }else if(!(filp->f_flags & O_NONBLOCK)){
         //printk("Driver:"KERN_INFO"device is set as BLOACK!\n");
         //printk("Driver:"KERN_INFO"Before schedule function!\n");
         //¿¿¿¿¿¿¿¿¿,¿¿¿¿,interruptible¿¿¿¿,¿¿dev->current_len>0¿¿¿¿¿¿¿¿¿¿,¿¿¿¿¿¿¿¿¿¿write¿¿,¿¿dev_current_len¿¿¿¿¿¿¿¿
         wait_event_interruptible(dev->r_wait,dev->current_len > 0);
         //printk("Driver:"KERN_INFO"After schedule function!\n");
         if (signal_pending(current))//¿¿¿¿¿¿¿¿¿¿¿¿,¿
         //Èç¹ûÊÇÒòΪÐźŻœÐÑ
         {
            ret =  - ERESTARTSYS;
            goto out;
         }
      }
      //printk("Driver:"KERN_INFO"Start read data!\n");
    
      /*¿¿¿¿¿¿¿¿¿¿¿*/
      if (count > dev->current_len)
        count = dev->current_len;//¿¿¿¿¿¿¿¿¿
    
      if (copy_to_user(buf, dev->mem, count))
      {
        ret =  - EFAULT;
        goto out;
      }
      else
      {
        //¿¿¿¿,¿¿¿¿¿¿¿¿¿¿¿¿¿,¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿,¿¿¿¿¿¿¿¿¿¿¿¿¿¿
        memcpy(dev->mem, dev->mem + count, dev->current_len - count); //fifoÊýŸÝÇ°ÒÆ
        dev->current_len -= count; //ÓÐЧÊýŸÝ³€¶ÈŒõÉÙ
        printk(KERN_INFO "read %d bytes(s),current_len:%d\n", count, dev->current_len);
         
        wake_up_interruptible(&dev->w_wait); //¿¿¿¿¿¿¿,¿¿¿¿¿¿¿,¿¿¿¿¿¿¿¿,¿¿¿¿¿¿¿¿¿¿¿,¿¿¿¿¿
        ret = count;
      }
    out:
       remove_wait_queue(&dev->r_wait, &wait); //
       set_current_state(TASK_RUNNING);//¿¿¿¿¿¿¿¿¿¿¿¿¿
       return ret;
    }
    
    
    /*globalfifoÐŽ²Ù×÷*/
    static ssize_t globalfifo_write(struct file *filp, const char __user *buf,
      size_t count, loff_t *ppos)
    {
      struct globalfifo_dev *dev = filp->private_data; //»ñµÃÉ豞œá¹¹ÌåÖžÕë
      int ret;
      DECLARE_WAITQUEUE(wait, current); //¶šÒåµÈŽý¶ÓÁÐ
      add_wait_queue(&dev->w_wait, &wait); //œøÈëÐŽµÈŽý¶ÓÁÐÍ·
      if ((filp->f_flags & O_NONBLOCK)&& (dev->current_len >= GLOBALFIFO_SIZE))
      {
         ret =  - EAGAIN;
         goto out;
      }
      else if(!(filp->f_flags & O_NONBLOCK))
      {
        //¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿,¿¿¿¿,¿¿¿¿¿¿¿¿¿
         wait_event_interruptible(dev->w_wait,dev->current_len < GLOBALFIFO_SIZE);
         if (signal_pending(current))//¿¿¿¿¿¿¿¿¿¿,¿¿¿¿¿
         {
            ret =  - ERESTARTSYS;
            goto out;
         }
      }
    
      /**/
      if (count > GLOBALFIFO_SIZE - dev->current_len)
        count = GLOBALFIFO_SIZE - dev->current_len;
      //¿¿¿¿¿¿¿
      if (copy_from_user(dev->mem + dev->current_len, buf, count))
      {
        ret =  - EFAULT;
        goto out;
      }
      else
      {
        dev->current_len += count;
        printk(KERN_INFO "written %d bytes(s),current_len:%d\n", count, dev
          ->current_len);
    
        wake_up_interruptible(&dev->r_wait); //¿¿¿¿¿¿
        
        ret = count;//¿¿¿¿¿¿¿¿¿
      }
    
      out: 
      remove_wait_queue(&dev->w_wait, &wait); //
      set_current_state(TASK_RUNNING);//¿¿¿¿¿¿¿¿¿¿¿¿¿
      return ret;
    }
    
    
    /*ÎÄŒþ²Ù×÷œá¹¹Ìå*/
    static const struct file_operations globalfifo_fops =
    {
      .owner = THIS_MODULE,
      .read = globalfifo_read,
      .write = globalfifo_write,
      .unlocked_ioctl = globalfifo_ioctl,
      .poll = globalfifo_poll,//¿¿¿¿¿¿¿¿
      .open = globalfifo_open,
      .release = globalfifo_release,
    };
    
    /*³õÊŒ»¯²¢×¢²ácdev*/
    static void globalfifo_setup_cdev(struct globalfifo_dev *dev, int index)
    {
      int err, devno = MKDEV(globalfifo_major, index);
    
      cdev_init(&dev->cdev, &globalfifo_fops);
      dev->cdev.owner = THIS_MODULE;
    //  dev->cdev.ops = &globalfifo_fops;
      err = cdev_add(&dev->cdev, devno, 1);
      if (err)
        printk(KERN_NOTICE "Error %d adding LED%d", err, index);
    }
    
    /*É豞Çý¶¯Ä£¿éŒÓÔغ¯Êý*/
    static __init int globalfifo_init(void)
    {
      int ret = 0;
      dev_t devno = MKDEV(globalfifo_major, 0);
    
      /* ÉêÇëÉ豞ºÅ*/
      if (globalfifo_major)
        ret = register_chrdev_region(devno, 1, "globalfifo");
      if(ret < 0)  /* ¶¯Ì¬ÉêÇëÉ豞ºÅ */
      {
        ret = alloc_chrdev_region(&devno, 0, 1, "globalfifo");
        globalfifo_major = MAJOR(devno);
      }
      if (ret < 0)
        return ret;
      /* ¶¯Ì¬ÉêÇëÉ豞œá¹¹ÌåµÄÄÚŽæ*/
      globalfifo_devp = kmalloc(sizeof(struct globalfifo_dev), GFP_KERNEL);
      if (!globalfifo_devp)    /*ÉêÇëʧ°Ü*/
      {
        ret =  - ENOMEM;
        goto fail_malloc;
      }
    
      memset(globalfifo_devp, 0, sizeof(struct globalfifo_dev));
    
      globalfifo_setup_cdev(globalfifo_devp, 0);
    
      init_waitqueue_head(&globalfifo_devp->r_wait); /*¿¿¿¿¿¿¿*/
      init_waitqueue_head(&globalfifo_devp->w_wait); /**/
    
      return 0;
    
      fail_malloc: unregister_chrdev_region(devno, 1);
      return ret;
    }
    
    
    /*Ä£¿éжÔغ¯Êý*/
    static __exit void globalfifo_exit(void)
    {
      cdev_del(&globalfifo_devp->cdev);   /*×¢Ïúcdev*/
      kfree(globalfifo_devp);     /*ÊÍ·ÅÉ豞œá¹¹ÌåÄÚŽæ*/
      unregister_chrdev_region(MKDEV(globalfifo_major, 0), 1); /*ÊÍ·ÅÉ豞ºÅ*/
    }
    
    MODULE_AUTHOR("Hiro Wang");
    MODULE_LICENSE("Dual BSD/GPL");
    
    module_param(globalfifo_major, int, S_IRUGO);
    
    module_init(globalfifo_init);
    module_exit(globalfifo_exit);
    
    

    数据结构

    • 对同类型的元素进行管理的学科
      1.元素之间的逻辑关系(1)同属一个集合 (2)元素之间存在一对一的关系:线性关系,线性表(栈(stack):先进后出(在一端做插入,同一端做删除),队列(queue):先进先出(在一端做插入,在另一端做删除)) (3)一对多的关系:树形关系 (4)多对多的关系:图形关系
      2.元素之间的存储方式(1)顺序存储(数组定义,动态分配)(2)链式存储(节点的空间只能动态分配)

    select(多功能复用)

    最终版

    1.驱动函数

    /*======================================================================
        A globalfifo driver as an example of char device drivers  
        This example is to introduce poll,blocking and non-blocking access
          
        The initial developer of the original code is Baohua Song
        <author@linuxdriver.cn>. All Rights Reserved.
    ======================================================================*/
    #include <linux/module.h>
    #include <linux/types.h>
    #include <linux/fs.h>
    #include <linux/errno.h>
    #include <linux/mm.h>
    #include <linux/sched.h>
    #include <linux/init.h>
    #include <linux/cdev.h>
    #include <asm/io.h>
    #include <asm/system.h>
    #include <asm/uaccess.h>
    #include <linux/poll.h>
    
    #include <linux/slab.h>
    #define GLOBALFIFO_SIZE 0x1000  /*È«ŸÖfifo×îŽó4K×ÖœÚ*/
    #define FIFO_CLEAR 0x1  /*Çå0È«ŸÖÄÚŽæµÄ³€¶È*/
    #define GLOBALFIFO_MAJOR 253    /*Ô€ÉèµÄglobalfifoµÄÖ÷É豞ºÅ*/
    
    static int globalfifo_major = GLOBALFIFO_MAJOR;
    /*globalfifoÉ豞œá¹¹Ìå*/
    struct globalfifo_dev                                     
    {                                                        
      struct cdev cdev; /*cdevœá¹¹Ìå*/                       
      unsigned int current_len;    /*fifoÓÐЧÊýŸÝ³€¶È*/
      unsigned char mem[GLOBALFIFO_SIZE]; /*È«ŸÖÄÚŽæ*/        
      struct semaphore sem; /*²¢·¢¿ØÖÆÓõÄÐźÅÁ¿*/           
      wait_queue_head_t r_wait; /*×èÈû¶ÁÓõĵȎý¶ÓÁÐÍ·*/     
      wait_queue_head_t w_wait; /*×èÈûÐŽÓõĵȎý¶ÓÁÐÍ·*/     
    };
    
    struct globalfifo_dev *globalfifo_devp; /*É豞œá¹¹ÌåÖžÕë*/
    /*ÎÄŒþŽò¿ªº¯Êý*/
    int globalfifo_open(struct inode *inode, struct file *filp)
    {
      /*œ«É豞œá¹¹ÌåÖžÕëž³ÖµžøÎÄŒþËœÓÐÊýŸÝÖžÕë*/
      filp->private_data = globalfifo_devp;
      return 0;
    }
    /*ÎÄŒþÊͷź¯Êý*/
    int globalfifo_release(struct inode *inode, struct file *filp)
    {
      return 0;
    }
    
    /* ioctlÉ豞¿ØÖƺ¯Êý */
    static long globalfifo_ioctl(struct file *filp, unsigned
      int cmd, unsigned long arg)
    {
      struct globalfifo_dev *dev = filp->private_data;/*»ñµÃÉ豞œá¹¹ÌåÖžÕë*/
    
      switch (cmd)
      {
        case FIFO_CLEAR:
            down(&dev->sem); //¿¿¿¿p¿¿      
          dev->current_len = 0;
          memset(dev->mem,0,GLOBALFIFO_SIZE);//¿¿¿¿¿¿
          up(&dev->sem); //¿¿¿¿v¿¿
             
          printk(KERN_INFO "globalfifo is set to zero\n");      
          break;
    
        default:
          return  - EINVAL;
      }
      return 0;
    }
    
    static unsigned int globalfifo_poll(struct file *filp, poll_table *wait)
    {
      unsigned int mask = 0;
      struct globalfifo_dev *dev = filp->private_data; /*»ñµÃÉ豞œá¹¹ÌåÖžÕë*/
      
      down(&dev->sem);
      
      poll_wait(filp, &dev->r_wait, wait);
      poll_wait(filp, &dev->w_wait, wait);  
      /*fifo·Ç¿Õ*/
      if (dev->current_len != 0)
      {
        mask |= POLLIN | POLLRDNORM; /*±êÊŸÊýŸÝ¿É»ñµÃ*/
      }
      /*fifo·ÇÂú*/
      if (dev->current_len != GLOBALFIFO_SIZE)
      {
        mask |= POLLOUT | POLLWRNORM; /*±êÊŸÊýŸÝ¿ÉÐŽÈë*/
      }
         
      up(&dev->sem);
      return mask;
    }
    
    
    /*globalfifo¶Áº¯Êý*/
    static ssize_t globalfifo_read(struct file *filp, char __user *buf, size_t count,
      loff_t *ppos)
    {
      int ret;
      struct globalfifo_dev *dev = filp->private_data; //
      DECLARE_WAITQUEUE(wait, current); //¶šÒåµÈŽý¶ÓÁÐ
    
      down(&dev->sem); //p¿¿,¿¿¿¿p¿¿¿¿¿¿¿,¿¿¿¿
      add_wait_queue(&dev->r_wait, &wait); //œøÈë¶ÁµÈŽý¶ÓÁÐÍ·
    
      /* µÈŽýFIFO·Ç¿Õ */
      if (dev->current_len == 0)//¿¿¿¿¿¿
      {
        printk("Driver:"KERN_INFO"Have no data in device!\n");
        if (filp->f_flags &O_NONBLOCK)//¿¿¿¿¿¿¿¿¿¿
        {
          printk("Driver:"KERN_INFO"device is set as NONBLOACK!\n");
          ret =  - EAGAIN;
          goto out;
        } 
        __set_current_state(TASK_INTERRUPTIBLE); //¿¿¿¿¿¿¿¿¿¿¿¿
        up(&dev->sem);//¿¿¿¿¿¿¿,¿¿¿¿¿¿¿¿¿¿¿¿¿¿
    
        printk("Driver:"KERN_INFO"device is set as BLOCK!\n");
        printk("Driver:"KERN_INFO"Before schedule function!\n");
    
        schedule(); //¿¿¿¿¿¿¿¿¿
        printk("Driver:"KERN_INFO"After schedule function!\n");
        if (signal_pending(current))//¿¿¿¿¿¿¿¿¿
        //Èç¹ûÊÇÒòΪÐźŻœÐÑ
        {
          ret =  - ERESTARTSYS;
          goto out2;
        }
    
        down(&dev->sem);//¿¿p¿¿
      }
      printk("Driver:"KERN_INFO"Start read data!\n");
    
      /* ¿œ±ŽµœÓû§¿ÕŒä */
      if (count > dev->current_len)
        count = dev->current_len;
    
      if (copy_to_user(buf, dev->mem, count))
      {
        ret =  - EFAULT;
        goto out;
      }
      else
      {
        memcpy(dev->mem, dev->mem + count, dev->current_len - count); //fifoÊýŸÝÇ°ÒÆ
        dev->current_len -= count; //ÓÐЧÊýŸÝ³€¶ÈŒõÉÙ
        printk(KERN_INFO "read %d bytes(s),current_len:%d\n", count, dev->current_len);
         
        wake_up_interruptible(&dev->w_wait); //»œÐÑÐŽµÈŽý¶ÓÁÐ
        
        ret = count;
      }
      out: up(&dev->sem); //ÊÍ·ÅÐźÅÁ¿
      out2:remove_wait_queue(&dev->w_wait, &wait); //ŽÓžœÊôµÄµÈŽý¶ÓÁÐÍ·ÒƳý
      set_current_state(TASK_RUNNING);
      return ret;
    }
    
    
    /*globalfifoÐŽ²Ù×÷*/
    static ssize_t globalfifo_write(struct file *filp, const char __user *buf,
      size_t count, loff_t *ppos)
    {
      struct globalfifo_dev *dev = filp->private_data; //»ñµÃÉ豞œá¹¹ÌåÖžÕë
      int ret;
      DECLARE_WAITQUEUE(wait, current); //¶šÒåµÈŽý¶ÓÁÐ
    
      down(&dev->sem); //»ñÈ¡ÐźÅÁ¿
      add_wait_queue(&dev->w_wait, &wait); //œøÈëÐŽµÈŽý¶ÓÁÐÍ·
    
      /* µÈŽýFIFO·ÇÂú */
      if (dev->current_len == GLOBALFIFO_SIZE)
      {
        if (filp->f_flags &O_NONBLOCK)
        //Èç¹ûÊÇ·Ç×èÈû·ÃÎÊ
        {
          ret =  - EAGAIN;
          goto out;
        } 
        __set_current_state(TASK_INTERRUPTIBLE); //žÄ±äœø³Ì׎̬Ϊ˯Ãß
        up(&dev->sem);
    
        schedule(); //µ÷¶ÈÆäËûœø³ÌÖŽÐÐ
        if (signal_pending(current))
        //Èç¹ûÊÇÒòΪÐźŻœÐÑ
        {
          ret =  - ERESTARTSYS;
          goto out2;
        }
    
        down(&dev->sem); //»ñµÃÐźÅÁ¿
      }
    
      /*ŽÓÓû§¿ÕŒä¿œ±ŽµœÄں˿Ռä*/
      if (count > GLOBALFIFO_SIZE - dev->current_len)
        count = GLOBALFIFO_SIZE - dev->current_len;
    
      if (copy_from_user(dev->mem + dev->current_len, buf, count))
      {
        ret =  - EFAULT;
        goto out;
      }
      else
      {
        dev->current_len += count;
        printk(KERN_INFO "written %d bytes(s),current_len:%d\n", count, dev
          ->current_len);
    
        wake_up_interruptible(&dev->r_wait); //»œÐѶÁµÈŽý¶ÓÁÐ
        
        ret = count;
      }
    
      out: up(&dev->sem); //ÊÍ·ÅÐźÅÁ¿
      out2:remove_wait_queue(&dev->w_wait, &wait); //ŽÓžœÊôµÄµÈŽý¶ÓÁÐÍ·ÒƳý
      set_current_state(TASK_RUNNING);
      return ret;
    }
    
    
    /*ÎÄŒþ²Ù×÷œá¹¹Ìå*/
    static const struct file_operations globalfifo_fops =
    {
      .owner = THIS_MODULE,
      .read = globalfifo_read,
      .write = globalfifo_write,
      .unlocked_ioctl = globalfifo_ioctl,
      .poll = globalfifo_poll,
      .open = globalfifo_open,
      .release = globalfifo_release,
    };
    
    /*³õÊŒ»¯²¢×¢²ácdev*/
    static void globalfifo_setup_cdev(struct globalfifo_dev *dev, int index)
    {
      int err, devno = MKDEV(globalfifo_major, index);
    
      cdev_init(&dev->cdev, &globalfifo_fops);
      dev->cdev.owner = THIS_MODULE;
      dev->cdev.ops = &globalfifo_fops;
      err = cdev_add(&dev->cdev, devno, 1);
      if (err)
        printk(KERN_NOTICE "Error %d adding LED%d", err, index);
    }
    
    /*É豞Çý¶¯Ä£¿éŒÓÔغ¯Êý*/
    static __init int globalfifo_init(void)
    {
      int ret = 0;
      dev_t devno = MKDEV(globalfifo_major, 0);
    
      /* ÉêÇëÉ豞ºÅ*/
      if (globalfifo_major)
        ret = register_chrdev_region(devno, 1, "globalfifo");
      if(ret < 0)  /* ¶¯Ì¬ÉêÇëÉ豞ºÅ */
      {
        ret = alloc_chrdev_region(&devno, 0, 1, "globalfifo");
        globalfifo_major = MAJOR(devno);
      }
      if (ret < 0)
        return ret;
      /* ¶¯Ì¬ÉêÇëÉ豞œá¹¹ÌåµÄÄÚŽæ*/
      globalfifo_devp = kmalloc(sizeof(struct globalfifo_dev), GFP_KERNEL);
      if (!globalfifo_devp)    /*ÉêÇëʧ°Ü*/
      {
        ret =  - ENOMEM;
        goto fail_malloc;
      }
    
      memset(globalfifo_devp, 0, sizeof(struct globalfifo_dev));
    
      globalfifo_setup_cdev(globalfifo_devp, 0);
    
      sema_init(&globalfifo_devp->sem,1);   /*³õÊŒ»¯ÐźÅÁ¿*/
      init_waitqueue_head(&globalfifo_devp->r_wait); /*³õÊŒ»¯¶ÁµÈŽý¶ÓÁÐÍ·*/
      init_waitqueue_head(&globalfifo_devp->w_wait); /*³õÊŒ»¯ÐŽµÈŽý¶ÓÁÐÍ·*/
    
      return 0;
    
      fail_malloc: unregister_chrdev_region(devno, 1);
      return ret;
    }
    
    
    /*Ä£¿éжÔغ¯Êý*/
    static __exit void globalfifo_exit(void)
    {
      cdev_del(&globalfifo_devp->cdev);   /*×¢Ïúcdev*/
      kfree(globalfifo_devp);     /*ÊÍ·ÅÉ豞œá¹¹ÌåÄÚŽæ*/
      unregister_chrdev_region(MKDEV(globalfifo_major, 0), 1); /*ÊÍ·ÅÉ豞ºÅ*/
    }
    
    MODULE_AUTHOR("Hiro Wang");
    MODULE_LICENSE("Dual BSD/GPL");
    
    module_param(globalfifo_major, int, S_IRUGO);
    
    module_init(globalfifo_init);
    module_exit(globalfifo_exit);
    
    int select(int nfds, fd_set *readfds, fd_set *writefds,
                      fd_set *exceptfds, struct timeval *timeout);
    
    

    1.int nfds的值为:最大的文件描述符的下标+1,即为有几个文件描述符
    2.fd_set:是一个结构体的类型

    • 简单代替读写操作的命令
      (1) cat /dev/设备文件/ (读操作)
      (2)sudo echo afghajhi > /dev/globalfifo (写操作)
      (3)select 则要写测试代码(调用select函数)
    open 设备文件
    while(1)
    {
        FD_CLR
        FD_SET
        select();//返回值为设备文件有数据可读的个数
        if(FD_ISSET())
        {
        }
        if(FD_ISSET())
        {
        }
    }
    判断返回值(<0错误,>0正确,=0)
    
    • 测试驱动程序的读和写,运行结果为如下
    Paste_Image.png Paste_Image.png

    LED驱动函数

    1.GPIO:IO口,通用输入/输出

    驱动函数

    #include <linux/miscdevice.h>
    #include <linux/delay.h>
    #include <asm/irq.h>
    #include <mach/regs-gpio.h>
    #include <mach/hardware.h>
    #include <linux/kernel.h>
    #include <linux/module.h>
    #include <linux/init.h>
    #include <linux/mm.h>
    #include <linux/fs.h>
    #include <linux/types.h>
    #include <linux/delay.h>
    #include <linux/moduleparam.h>
    #include <linux/slab.h>
    #include <linux/errno.h>
    #include <linux/ioctl.h>
    #include <linux/cdev.h>
    #include <linux/string.h>
    #include <linux/list.h>
    #include <linux/pci.h>
    #include <linux/gpio.h>
    #include <asm/uaccess.h>
    #include <asm/atomic.h>
    #include <asm/unistd.h>
    
    
    #define DEVICE_NAME "leds"
    
    static unsigned long led_table [] = {
        S3C2410_GPB(5),
        S3C2410_GPB(6),
        S3C2410_GPB(7),
        S3C2410_GPB(8),
    };
    
    static unsigned int led_cfg_table [] = {
        S3C2410_GPIO_OUTPUT,
        S3C2410_GPIO_OUTPUT,
        S3C2410_GPIO_OUTPUT,
        S3C2410_GPIO_OUTPUT,
    };
    
    static int sbc2440_leds_ioctl(
        struct inode *inode, 
        struct file *file, 
        unsigned int cmd, 
        unsigned long arg)
    {
        switch(cmd) {
        case 0:
        case 1:
            if (arg > 4) {
                return -EINVAL;
            }
            s3c2410_gpio_setpin(led_table[arg], !cmd);
            return 0;
        default:
            return -EINVAL;
        }
    }
    
    static struct file_operations dev_fops = {
        .owner  =   THIS_MODULE,
        .ioctl  =   sbc2440_leds_ioctl,
    };
    
    static struct miscdevice misc = {
        .minor = MISC_DYNAMIC_MINOR,
        .name = DEVICE_NAME,
        .fops = &dev_fops,
    };
    
    static int __init dev_init(void)
    {
        int ret;
    
        int i;
        
        for (i = 0; i < 4; i++) {
            s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]);
            s3c2410_gpio_setpin(led_table[i], 0);
        }
    
        ret = misc_register(&misc);
    
        printk (DEVICE_NAME"\tinitialized\n");
    
        return ret;
    }
    
    static void __exit dev_exit(void)
    {
        misc_deregister(&misc);
    }
    
    module_init(dev_init);
    module_exit(dev_exit);
    MODULE_LICENSE("GPL");
    MODULE_AUTHOR("FriendlyARM Inc.");
    
    

    测试代码

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <sys/ioctl.h>
    #include <unistd.h>
    
    int main(int argc,char *argv[])
    {
        int cmd=-1;
        int ledno=-1;
        int fd=-1;
        if(argc<3)
        {
            printf("Usage is testleds 0 2\n");
            return 1;
        }
        sscanf(argv[1],"%d",&cmd);
        sscanf(argv[2],"%d",&ledno);
        if(cmd<0 ||cmd>1)
        {   
            printf("The second arguments is error\n");
            return 2;
        }
        if(ledno<1||ledno>4)
        {
            printf("The third arguments is error\n");
            return 3;
        }
        ledno--;
        fd=open("/dev/leds",O_RDWR);
        if(fd<0)
        {
            printf("Open /dev/leds failed\n");
            return 4;
        }
        ioctl(fd,cmd,ledno);
        close(fd);
        return 0;
    }
    
    
    • 运行结果为
    Paste_Image.png

    volatile

    1.是可变的关键字

    • 一个整型变量,如果没有前面的关键字,编译器可以会用寄存器去访问,提高效率,但当另一个进程要进行修改这个变量时,此时这两个得到的值就不同,所以不要编译器帮我们进行优化,此时要加volatile关键字

    相关文章

      网友评论

        本文标题:ARM-第八次

        本文链接:https://www.haomeiwen.com/subject/vbnjbttx.html