九鼎创展论坛中文版English
登录 | 立即注册 设为首页收藏本站 切换到宽版
查看: 4028|回复: 0

支持异步通知的globalfifo平台设备驱动程序及其测试代码

[复制链接]
发表于 2014-10-10 23:18:22 | 显示全部楼层 |阅读模式
驱动:
  1. #include <linux/module.h>
  2. #include <linux/types.h>
  3. #include <linux/fs.h>
  4. #include <linux/errno.h>
  5. #include <linux/mm.h>//内存管理头文件,含有页面大小定义和一些页面释放函数原型
  6. #include <linux/sched.h>
  7. #include <linux/init.h>
  8. #include <linux/cdev.h>
  9. #include <asm/io.h>//I/O头文件,以宏的嵌入汇编程序形式定义对I/O端口操作的函数。
  10. #include <asm/system.h>//系统头文件,定义了设置或修改描述符/中断门等的嵌入式汇编宏。
  11. #include <asm/uaccess.h>//包含了copy_to_user、copy_from_user等内核访问用户进程内存地址的函数定义
  12. #include <linux/slab.h>//包含了kcalloc、kzalloc内存分配函数的定义。
  13. #include <linux/poll.h>

  14. //--------------platform_device------------
  15. #include <linux/platform_device.h>

  16. //-------------class_create,device_create------
  17. #include <linux/device.h>

  18. /*用udev机制自动添加设备节点*/
  19. struct class *globalfifo_class;


  20. #define GLOBALFIFO_SIZE    0x1000    /*全局内存最大4K字节*/
  21. #define MEM_CLEAR 0x1  /*清0全局内存*/
  22. #define GLOBALFIFO_MAJOR 0    /*预设的globalfifo的主设备号*/

  23. #define DEVICE_NAME "globalfifo"

  24. static int globalfifo_major = GLOBALFIFO_MAJOR;

  25. /*globalfifo设备结构体*/
  26. struct globalfifo_dev                                    
  27. {                                                        
  28.   struct cdev cdev; /*cdev结构体*/                       
  29.   unsigned char mem[GLOBALFIFO_SIZE]; /*全局内存*/
  30.   unsigned int current_len;/*fifo 有效数据长度*/
  31.   struct semaphore sem;/*并发控制用的信号量*/
  32.   wait_queue_head_t r_wait;/*阻塞读用的等待队列头*/
  33.   wait_queue_head_t w_wait;/*阻塞写用的等待队列头*/
  34.   struct fasync_struct *async_queue;/*异步结构体指针*/
  35. };

  36. struct globalfifo_dev *globalfifo_devp; /*设备结构体指针*/
  37. /*文件打开函数*/
  38. int globalfifo_open(struct inode *inode, struct file *filp)
  39. {
  40.   /*将设备结构体指针赋值给文件私有数据指针*/
  41.   struct globalfifo_dev *dev;
  42.   dev=container_of(inode->i_cdev,struct globalfifo_dev,cdev);//通过结构体成员的指针找到对应结构体的指针
  43.   filp->private_data = dev;
  44.   return 0;
  45. }

  46. /* ioctl设备控制函数 */
  47. static int globalfifo_ioctl(struct inode *inodep, struct file *filp, unsigned
  48.   int cmd, unsigned long arg)
  49. {
  50.   struct globalfifo_dev *dev = filp->private_data;/*获得设备结构体指针*/

  51.   switch (cmd)
  52.   {
  53.     case MEM_CLEAR:
  54.       if(down_interruptible(&dev->sem))/*获取信号量*/
  55.           return -ERESTARTSYS;
  56.       
  57.       memset(dev->mem, 0, GLOBALFIFO_SIZE);  //mem数组名,即空间首地址   

  58.       up(&dev->sem);
  59.       printk(KERN_INFO "globalfifo is set to zero\n");
  60.       break;

  61.     default:
  62.       return  - EINVAL;
  63.   }
  64.   return 0;
  65. }

  66. /*读函数*/
  67. static ssize_t globalfifo_read(struct file *filp, char __user *buf, size_t size,
  68.   loff_t *ppos)
  69. {
  70.   
  71.   int ret = 0;
  72.   struct globalfifo_dev *dev = filp->private_data; /*获得设备结构体指针*/
  73.   DECLARE_WAITQUEUE(wait,current);/*define wait queue*/


  74.   if(down_interruptible(&dev->sem))/*获得信号量*/
  75.       {
  76.       return -ERESTARTSYS;
  77.       }

  78.    add_wait_queue(&dev->r_wait,&wait);/*进入读等待队列头*/
  79.    

  80.   /*等待fifo非空并检测用户空间是否要求非阻塞访问*/
  81.   while(dev->current_len==0)
  82.       {
  83.        if(filp->f_flags &O_NONBLOCK)
  84.            {
  85.                ret = -EAGAIN;
  86.             goto out;
  87.            }
  88.        __set_current_state(TASK_INTERRUPTIBLE);/*改变进程状态为睡眠*/

  89.        /*********************************************************/
  90.        up(&dev->sem);/*释放信号量,防止死锁*/
  91.        /*********************************************************/

  92.        schedule();/*调度其他进程执行,开始睡眠*/
  93.       
  94.        if(signal_pending(current))/*如果是因为信号唤醒*/
  95.            {
  96.                ret = -ERESTARTSYS;/*重新执行系统调用*/
  97.             goto out2;
  98.            } else

  99.         if(down_interruptible(&dev->sem))
  100.             {
  101.                 return -ERESTARTSYS;
  102.             }
  103.     }

  104.   

  105.   /*内核空间->用户空间*/
  106.   if(size>dev->current_len)
  107.       size=dev->current_len;
  108.   if (copy_to_user(buf,dev->mem,size))
  109.   {
  110.     ret =  - EFAULT;   /* Bad address */
  111.     goto out;
  112.   }
  113.   else
  114.   {
  115.     memcpy(dev->mem,dev->mem+size,size);/*fifo数据前移*/
  116.     dev->current_len -=size;/*有效数据长度减少*/

  117.     printk(KERN_INFO"read %d bytes(s),current_len:%d \n",size,dev->current_len);
  118.    
  119.     wake_up_interruptible(&dev->w_wait);/*唤醒写等待队列*/
  120.     ret= size;
  121.   }
  122.   out:
  123.       up(&dev->sem);/*释放信号量*/
  124.   out2:
  125.       remove_wait_queue(&dev->r_wait,&wait);
  126.   __set_current_state(TASK_RUNNING);
  127.   return ret;
  128. }

  129. /*写函数*/
  130. static ssize_t globalfifo_write(struct file *filp, const char __user *buf,
  131.   size_t size, loff_t *ppos)
  132. {

  133.   int ret = 0;
  134.   struct globalfifo_dev *dev = filp->private_data; /*获得设备结构体指针*/
  135.   DECLARE_WAITQUEUE(wait,current);/*define wait queue*/


  136.   if(down_interruptible(&dev->sem))/*获得信号量*/
  137.       {
  138.       return -ERESTARTSYS;
  139.       }

  140.    add_wait_queue(&dev->w_wait,&wait);/*进入写等待队列*/
  141.    

  142.   /*等待fifo非满并检测用户空间是否要求非阻塞访问*/
  143.   while(dev->current_len==GLOBALFIFO_SIZE)
  144.       {
  145.        if(filp->f_flags &O_NONBLOCK)
  146.            {
  147.                ret = -EAGAIN;
  148.             goto out;
  149.            }
  150.        __set_current_state(TASK_INTERRUPTIBLE);/*改变进程状态为睡眠*/

  151.        up(&dev->sem);/*释放信号量,防止死锁*/

  152.        schedule();/*调度其他进程执行,开始睡眠*/
  153.       
  154.        if(signal_pending(current))
  155.            {
  156.                ret = -ERESTARTSYS;
  157.             goto out2;
  158.            } else

  159.         if(down_interruptible(&dev->sem))
  160.             {
  161.                 return -ERESTARTSYS;
  162.             }
  163.     }

  164.   

  165.   /*内核空间<-用户空间*/
  166.   if(size>GLOBALFIFO_SIZE-dev->current_len)
  167.       size=GLOBALFIFO_SIZE-dev->current_len;
  168.   if (copy_from_user(dev->mem+dev->current_len,buf,size))
  169.   {
  170.     ret =  - EFAULT;   /* Bad address */
  171.     goto out;
  172.   }
  173.   else
  174.   {
  175.     dev->current_len +=size;/*有效数据长度减少*/

  176.     printk(KERN_INFO"write %d bytes(s),current_len:%d \n",size,dev->current_len);
  177.    
  178.     wake_up_interruptible(&dev->r_wait);/*唤醒读等待队列*/

  179.     /*产生异步读信号*/
  180.     if(dev->async_queue)
  181.         kill_fasync(&dev->async_queue,SIGIO,POLL_IN);
  182.    
  183.     ret= size;
  184.   }
  185.   out:
  186.       up(&dev->sem);/*释放信号量*/
  187.   out2:
  188.       remove_wait_queue(&dev->w_wait,&wait);
  189.   __set_current_state(TASK_RUNNING);
  190.   return ret;
  191. }

  192. static unsigned int globalfifo_poll(struct file *filp,poll_table *wait)
  193. {
  194.     unsigned int mask=0;
  195.     struct globalfifo_dev *dev=filp->private_data;
  196.     if(down_interruptible(&dev->sem))
  197.         {
  198.             return -ERESTARTSYS;
  199.         }

  200.     poll_wait(filp,&dev->w_wait,wait);/*将对应的等待队列头添加到poll_table*/
  201.     poll_wait(filp,&dev->w_wait,wait);
  202.     /*fifo非空*/
  203.     if(dev->current_len!=0)
  204.         mask |=POLLIN|POLLRDNORM;/*标示数据可获得*/
  205.     /*fifo非满*/
  206.     if(dev->current_len!=GLOBALFIFO_SIZE)
  207.         mask |=POLLOUT|POLLWRNORM;/*标示数据可获得*/

  208.     up(&dev->sem);
  209.     return mask;

  210. }

  211. static int globalfifo_fasync(int fd,struct file *filp,int mode)
  212. {
  213.     struct globalfifo_dev *dev =filp->private_data;
  214.     return fasync_helper(fd,filp,mode,&dev->async_queue);
  215. }

  216. /*文件释放函数*/
  217. int globalfifo_release(struct inode *inode, struct file *filp)
  218. {
  219.     /*将文件从异步通知列表里删除*/
  220.     globalfifo_fasync(-1,filp,0);
  221.   return 0;
  222. }

  223. /*文件操作结构体*/
  224. static const struct file_operations globalfifo_fops =
  225. {
  226.   .owner = THIS_MODULE,
  227.   .read = globalfifo_read,
  228.   .write = globalfifo_write,
  229.   .ioctl = globalfifo_ioctl,
  230.   .open = globalfifo_open,
  231.   .release = globalfifo_release,
  232.   .poll = globalfifo_poll,
  233.   .fasync=globalfifo_fasync,
  234. };

  235. /*初始化并注册cdev*/
  236. static void globalfifo_setup_cdev(struct globalfifo_dev *dev, int index)
  237. {
  238.   int err, devno = MKDEV(globalfifo_major, index);

  239.   cdev_init(&dev->cdev, &globalfifo_fops);
  240.   dev->cdev.owner = THIS_MODULE;
  241.   dev->cdev.ops = &globalfifo_fops;
  242.   err = cdev_add(&dev->cdev, devno, 1);
  243.   if (err)
  244.     printk(KERN_NOTICE "Error %d ", err);
  245. }

  246. static int __devinit globalfifo_probe(struct platform_device *pdev)
  247. {
  248.     printk("in the globalfifo_probe!!\n");
  249.     int result;
  250.     dev_t devno = MKDEV(globalfifo_major, 0);
  251.    
  252.     /* 申请设备号*/
  253.     if (globalfifo_major)
  254.       result = register_chrdev_region(devno, 1, DEVICE_NAME);
  255.     else  /* 动态申请设备号 */
  256.     {
  257.       result = alloc_chrdev_region(&devno, 0, 1,DEVICE_NAME);
  258.       globalfifo_major = MAJOR(devno);
  259.     }  
  260.     if (result < 0)
  261.       return result;
  262.       
  263.     /* 动态申请设备结构体的内存*/
  264.     globalfifo_devp = kmalloc(sizeof(struct globalfifo_dev), GFP_KERNEL);//kmalloc()内核空间;malloc()用户空间。返回起始地址
  265.     if (!globalfifo_devp)     /*申请失败*/
  266.     {
  267.       result =    - ENOMEM;
  268.       goto fail_malloc;
  269.     }
  270.     memset(globalfifo_devp, 0, sizeof(struct globalfifo_dev));//把此内存空间清零
  271.    
  272.     globalfifo_setup_cdev(globalfifo_devp, 0);//注册设备
  273.    
  274.     /*udev机制可以自动添加设备节点,只需要添加xxx_class这个类,以及device_create()*/
  275.     globalfifo_class = class_create(THIS_MODULE, "globalfifo_class");/*在sys目录下创建xx_class这个类,/sys/class/~*/
  276.     device_create(globalfifo_class, NULL, globalfifo_devp->cdev.dev,  DEVICE_NAME, DEVICE_NAME);/*自动创建设备/dev/$DEVICE_NAME*/
  277.    
  278.     init_MUTEX(&globalfifo_devp->sem);/*初始化信号量*/
  279.     init_waitqueue_head(&globalfifo_devp->r_wait);/*初始化读写等待队列*/
  280.     init_waitqueue_head(&globalfifo_devp->w_wait);
  281.    
  282.     printk("globalfifo driver installed!\n");
  283.     printk("globalfifo_major is:%d\n",globalfifo_major);
  284.     printk("the device name is %s\n",DEVICE_NAME);
  285.    
  286.     return 0;
  287.    
  288.     fail_malloc: unregister_chrdev_region(devno, 1);
  289.     return result;

  290. }

  291. static int __devexit globalfifo_remove(struct platform_device *pdev)
  292. {
  293.     printk("in the globalfifo_remove!!\n");
  294.     device_destroy(globalfifo_class, globalfifo_devp->cdev.dev);
  295.     class_destroy(globalfifo_class);
  296.    
  297.     cdev_del(&globalfifo_devp->cdev);    /*注销cdev*/
  298.     kfree(globalfifo_devp);     /*释放设备结构体内存*/
  299.     unregister_chrdev_region(MKDEV(globalfifo_major, 0), 1); /*释放设备号*/
  300.     printk("globalfifo driver uninstalled!\n");
  301.     return 0;

  302. }

  303. static struct platform_driver globalfifo_device_driver={
  304.     .probe=globalfifo_probe,
  305.     .remove=globalfifo_remove,
  306.     .driver={
  307.         .name=DEVICE_NAME,
  308.         .owner=THIS_MODULE,
  309.         },
  310. };

  311. /*设备驱动模块加载函数*/
  312. static int __init globalfifo_init(void)
  313. {
  314.     return platform_driver_register(&globalfifo_device_driver);
  315. }

  316. /*模块卸载函数*/
  317. static void __exit globalfifo_exit(void)
  318. {
  319.     platform_driver_unregister(&globalfifo_device_driver);
  320. }

  321. MODULE_AUTHOR("mhb@SEU");
  322. MODULE_LICENSE("Dual BSD/GPL");

  323. module_param(globalfifo_major, int, S_IRUGO);

  324. module_init(globalfifo_init);
  325. module_exit(globalfifo_exit);
复制代码
测试程序:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <fcntl.h>
  5. #include <sys/ioctl.h>
  6. #include <signal.h>

  7. void input_handler(int signum)
  8. {
  9.     printf("signum is ;%d\n",signum);
  10. }

  11. int main()
  12. {
  13.     int fd,oflags;
  14.     fd=open("/dev/globalfifo",O_RDWR,S_IRUSR|S_IWUSR);
  15.     if(fd != -1) {
  16.         /*启动信号驱动机制*/
  17.         signal(SIGIO,input_handler);/*让input_handler 处理SIGIO信号*/
  18.         fcntl(fd,F_SETOWN,getpid());
  19.         oflags=fcntl(fd,F_GETFL);
  20.         fcntl(fd,F_SETFL,oflags|FASYNC);
  21.         while(1)
  22.             {
  23.                 sleep(100);
  24.             }
  25.     } else
  26.         {
  27.             printf("device open failed!\n");
  28.         }


  29.     return 0;   

  30. }
复制代码
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|深圳市九鼎创展科技官方论坛 ( 粤ICP备11028681号-2  

GMT+8, 2024-12-14 01:37 , Processed in 0.021598 second(s), 21 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表