Chinaunix首页 | 论坛 | 博客
  • 博客访问: 32552
  • 博文数量: 6
  • 博客积分: 100
  • 博客等级: 民兵
  • 技术积分: 70
  • 用 户 组: 普通用户
  • 注册时间: 2011-03-31 22:59
文章分类

全部博文(6)

文章存档

2012年(5)

2011年(1)

我的朋友

分类: 系统运维

2012-03-24 00:15:50

/* 
 * 驱动学习 globalfifo.c 
 * 内核版本2.6.27之前的创建设备节点的函数是struct class_device class_device_create 
 * class_device_destory
 */
  1. #include <linux/module.h>
  2. #include <linux/slab.h>
  3. #include <linux/types.h>
  4. #include <linux/fs.h>
  5. #include <linux/errno.h>
  6. #include <linux/mm.h>
  7. #include <linux/sched.h>
  8. #include <linux/moduleparam.h>
  9. #include <linux/init.h>
  10. #include <linux/cdev.h>
  11. #include <linux/wait.h>
  12. #include <linux/poll.h>
  13. #include <linux/device.h>

  14. #include <asm/io.h>
  15. #include <asm/system.h>
  16. #include <asm/uaccess.h>

  17. #define GLOBALMEM_SIZE 0x1000
  18. #define MEM_CLEAN 0x01
  19. #define GLOBALMEM_MAJOR 0

  20. struct globalfifo_dev
  21. {
  22.     unsigned int leng;
  23.     struct cdev cdev;
  24.      struct semaphore sem;
  25.     unsigned char mem[GLOBALMEM_SIZE];
  26.     wait_queue_head_t r_wait;
  27.     wait_queue_head_t w_wait;
  28.     struct fasync_struct *async_queue;
  29. };

  30. static struct globalfifo_dev *globalfifo_devp;
  31. static struct class *global_class;
  32. static struct device *global_device;
  33. static int globalfifo_major = GLOBALMEM_MAJOR;

  34. MODULE_AUTHOR("RIVER");
  35. MODULE_LICENSE("Dual BSD/GPL");

  36. static ssize_t globalfifo_read(struct file *filp, char __user *buf,size_t size, loff_t *f_ops)
  37. {
  38.     struct globalfifo_dev *dev = filp->private_data;
  39.     int ret;
  40.     DECLARE_WAITQUEUE(rwait, current);

  41.     down(&dev->sem);
  42.     add_wait_queue(&dev->r_wait, &rwait);

  43.     if(dev->leng == 0)
  44.     {
  45.         if(filp->f_flags & O_NONBLOCK)
  46.         {
  47.             ret = -EAGAIN;
  48.             goto out;
  49.         }
  50.         set_current_state(TASK_INTERRUPTIBLE);
  51.         up(&dev->sem);

  52.         schedule();
  53.         if(signal_pending(current)) //awake by signal
  54.         {
  55.             ret = -ERESTARTSYS;
  56.             goto out1;
  57.         }
  58.         down(&dev->sem);
  59.     }

  60.     if(size > dev->leng)
  61.         size = dev->leng;
  62.             
  63.     if(copy_to_user(buf,(void *)dev->mem, size))
  64.     {
  65.         ret = -EFAULT;
  66.         goto out;
  67.     }
  68.     else
  69.     {
  70.         memcpy(dev->mem, dev->mem + size, dev->leng - size);
  71.         dev->leng -= size;
  72.         printk(KERN_INFO "read %d bytes current leng=%d \n", size, dev->leng);
  73.         wake_up_interruptible(&dev->w_wait);
  74.         ret = size;
  75.     }
  76. out:
  77.     up(&dev->sem);
  78. out1:
  79.     remove_wait_queue(&dev->r_wait, &rwait);
  80.     set_current_state(TASK_RUNNING);
  81.     return ret;
  82. }

  83. static ssize_t globalfifo_write(struct file *filp,const char __user *buf, size_t size, loff_t *f_ops)
  84. {
  85.     struct globalfifo_dev *dev = filp->private_data;
  86.     int ret;
  87.     DECLARE_WAITQUEUE(wwait, current);

  88.     down(&dev->sem);
  89.     add_wait_queue(&dev->w_wait, &wwait);

  90.     if(dev->leng == GLOBALMEM_SIZE)
  91.     {
  92.         if(filp->f_flags & O_NONBLOCK)
  93.         {
  94.             ret = -EAGAIN;
  95.             goto out;
  96.         }
  97.     
  98.      __set_current_state(TASK_INTERRUPTIBLE);
  99.      up(&dev->sem); //avoid deadlock
  100.      schedule();
  101. // interruptible_sleep_on(&dev->w_wait);
  102.      if(signal_pending(current))
  103.      {
  104.      ret = -ERESTARTSYS;
  105.      goto out1;
  106.      }

  107.      down(&dev->sem);
  108.     }

  109.     if(size > GLOBALMEM_SIZE - dev->leng)
  110.         size = GLOBALMEM_SIZE- dev->leng;

  111.     if(copy_from_user(dev->mem,buf,size))
  112.     {
  113.         ret = - EFAULT;
  114.         goto out;
  115.     }
  116.     else
  117.     {
  118.         ret = size;
  119.         dev->leng += size;
  120.         printk(KERN_INFO "written %d bytes leng=%d\n", size, dev->leng);
  121.         wake_up_interruptible(&dev->r_wait);

  122.         if(dev->async_queue) //async read signal
  123.          kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
  124.     }

  125. out:    
  126.     up(&dev->sem);
  127. out1:
  128.     remove_wait_queue(&dev->w_wait, &wwait);
  129.     set_current_state(TASK_RUNNING);

  130.     return ret;
  131. }

  132. static int globalfifo_ioctl(struct inode *inode,struct file *filp,unsigned int cmd, unsigned long arg)
  133. {
  134.     struct globalfifo_dev *dev = filp->private_data;

  135.     switch(cmd)
  136.     {
  137.         case MEM_CLEAN:
  138.             if(down_interruptible(&dev->sem))
  139.             {
  140.                 return -ERESTARTSYS;
  141.             }
  142.             
  143.             memset(dev->mem,0,GLOBALMEM_SIZE);
  144.             printk(KERN_INFO "globalfifo is set to zero %d\n",MEM_CLEAN);
  145.             up(&dev->sem);
  146.             
  147.             break;

  148.         default:
  149.             return - EINVAL;
  150.     }
  151.     return 0;
  152. }

  153. static unsigned int globalfifo_poll(struct file *filp, struct poll_table_struct *wait)
  154. {
  155.     unsigned int mask = 0;
  156.     struct globalfifo_dev *dev = filp->private_data;

  157.     down(&dev->sem);
  158.     poll_wait(filp, &dev->r_wait, wait);
  159.     poll_wait(filp, &dev->w_wait, wait);

  160.     if(dev->leng != 0)
  161.         mask |= POLLIN | POLLRDNORM;

  162.     if(dev->leng != GLOBALMEM_SIZE)
  163.         mask |= POLLOUT | POLLWRBAND;

  164.     up(&dev->sem);
  165.     return mask;
  166. }

  167. static int globalfifo_fasync(int fd, struct file *filp, int mode)
  168. {
  169.     struct globalfifo_dev *dev = filp->private_data;

  170.     return fasync_helper(fd, filp, mode, &dev->async_queue);
  171. }
  172.     
  173. static int globalfifo_open(struct inode *inode, struct file *filp)
  174. {
  175.     struct globalfifo_dev *dev;

  176.     dev = container_of(inode->i_cdev,struct globalfifo_dev,cdev);
  177.     filp->private_data = dev;

  178.     return 0;
  179. }

  180. static int globalfifo_release(struct inode *inode, struct file *filp)
  181. {
  182.     globalfifo_fasync(-1, filp, 0);

  183.     return 0;
  184. }


  185.     
  186. static struct file_operations globalfifo_fops =
  187. {
  188.     .owner = THIS_MODULE,
  189.     .read = globalfifo_read,
  190.     .write = globalfifo_write,
  191.     .ioctl = globalfifo_ioctl,
  192.     .poll = globalfifo_poll,
  193.     .open = globalfifo_open,
  194.     .release = globalfifo_release,
  195.     .fasync = globalfifo_fasync,
  196. };

  197. static void globalfifo_setup_cdev(struct globalfifo_dev *dev,int index)
  198. {
  199.     int err;
  200.     dev_t devno = MKDEV(globalfifo_major,index);

  201.     cdev_init(&dev->cdev,&globalfifo_fops);
  202.     dev->cdev.owner = THIS_MODULE;
  203.     dev->cdev.ops = &globalfifo_fops;
  204.     err = cdev_add(&dev->cdev,devno,1);
  205.     if(err)
  206.         printk(KERN_NOTICE "Error %d adding globalfifo %d",err,index);
  207.     init_MUTEX(&dev->sem);
  208.     init_waitqueue_head(&dev->r_wait);
  209.     init_waitqueue_head(&dev->w_wait);
  210. }

  211. static int __init globalfifo_init(void)
  212. {
  213.     int result;
  214.     dev_t devno;

  215.     if(globalfifo_major)
  216.     {
  217.         devno = MKDEV(globalfifo_major,0);
  218.         result = register_chrdev_region(devno,1,"globalfifo");
  219.     }
  220.     else
  221.     {
  222.         result = alloc_chrdev_region(&devno,0,1,"globalfifo");
  223.         globalfifo_major = MAJOR(devno);
  224.     }

  225.     if(result < 0)
  226.         return result;

  227.     globalfifo_devp = kmalloc(sizeof(struct globalfifo_dev),GFP_KERNEL);
  228.     if(!globalfifo_devp)
  229.     {
  230.         result = - ENOMEM;
  231.         goto fail_malloc;
  232.     }

  233.     memset(globalfifo_devp,0,sizeof(struct globalfifo_dev));
  234.     globalfifo_setup_cdev(globalfifo_devp,0);
  235.     global_class = class_create(THIS_MODULE, "globalfifo");
  236.     if(IS_ERR(global_class))
  237.     {
  238.         result = -EFAULT;
  239.         goto fail_malloc;
  240.     }
  241.     global_device = device_create(global_class, NULL, MKDEV(globalfifo_major,0), NULL, "globalfifo");

  242.     return 0;

  243. fail_malloc:
  244.     unregister_chrdev_region(devno,1);
  245.     return result;
  246. }

  247. static void __exit globalfifo_exit(void)
  248. {
  249.     cdev_del(&globalfifo_devp->cdev);
  250.     kfree(globalfifo_devp);
  251.     device_destroy(global_class, MKDEV(globalfifo_major, 0));
  252.     class_destroy(global_class);
  253.     unregister_chrdev_region(MKDEV(globalfifo_major,0),1);
  254. }

  255. module_param(globalfifo_major,int,S_IRUGO);

  256. module_init(globalfifo_init);
  257. module_exit(globalfifo_exit);
/* 驱动Makefile */

KERNELDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules

install:
insmod globalmem.ko
uninstall:
rmmod globalmem.ko

clean:
$(MAKE) -C $(KERNELDIR) M=$(PWD) clean
endif

/* 
 * 驱动验证  global.c
 */

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <fcntl.h>
  5. #include <sys/types.h>
  6. #include <sys/time.h>
  7. #include <sys/stat.h>

  8. #define MAX 512

  9. int main(void)
  10. {
  11.     int fd, fd1;
  12.     char str[MAX] = {0}, buf[25] = {0};
  13.     int i = 0;
  14.     pid_t pid;
  15.     struct timeval to;
  16.     fd_set rfds;
  17.     
  18.     pid = fork();
  19.     while(1)
  20.     {
  21.         if(pid < 0)
  22.         {
  23.             printf("ERR in fork\n");
  24.         }
  25.         else if(pid != 0)
  26.         {
  27.             fd1 = open("/dev/globalfifo",O_RDWR);

  28.             if(fd1 < 0)
  29.             {
  30.                  printf("the globalfifo can't be open\n");
  31.                 continue;
  32.             }
  33.         
  34.             sleep(1);
  35.             snprintf(buf, 10, "hello %d", i++);
  36.             if( i > 3 )
  37.             {
  38.                 i = 0;
  39.                 sleep(3);
  40.                 close(fd1);
  41.                 continue;
  42.             }
  43.             write(fd1, buf, strlen(buf));
  44.             memset(buf, 0, 25);
  45.             close(fd1);
  46.         }
  47.         else
  48.         {
  49.             fd = open("/dev/globalfifo", 0);
  50.             if(fd < 0)
  51.             {
  52.                 printf("the globalfifo can't open\n");
  53.                 continue;
  54.             }
  55.             FD_ZERO(&rfds);
  56.             FD_SET(fd, &rfds);
  57.             to.tv_sec = 3; //timeout 3s
  58.             to.tv_usec = 0;

  59.             select(fd+1, &rfds, NULL, NULL, &to);
  60.             {
  61.                 if(FD_ISSET(fd, &rfds))
  62.                 {
  63.                     read(fd, str, 10);
  64.                     str[10] = 0;
  65.                     printf("%s\n", str);
  66.                     memset(str, 0, 10);
  67.                 }
  68.                 else
  69.                 {
  70.                     printf("time out\n");
  71.                 }
  72.             }
  73.             close(fd);
  74.         }
  75.     }
  76.     return 0;
  77. }
运行
#gcc -o fifo global.c
#./fifo
 hello0
 hello1
 hello2
 timeout
 ....

/*
 * 异步通知程序
 */

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <sys/types.h>
  5. #include <sys/stat.h>
  6. #include <fcntl.h>
  7. #include <signal.h>

  8. #define MAX_LEN 30

  9. int fd = -1;

  10. void input_handle(int sig)
  11. {
  12.     char buf[MAX_LEN] = {0};
  13.     int len;

  14.     printf("receive buf from globalfifo, signal = %d\n", sig);
  15.     if(fd > 0)
  16.     {
  17.         len = read(fd, &buf, MAX_LEN);
  18.         buf[len] = 0;
  19.         printf("%s\n", buf);
  20.         close(fd);
  21. fd = -1;
  22.     }
  23. }

  24. int main(void)
  25. {
  26.     int flag;

  27.     fd = open("/dev/globalfifo", 0);
  28.     if(fd > 0)
  29.     {
  30.         signal(SIGIO, input_handle);
  31.         fcntl(fd, F_SETOWN, getpid());
  32.         flag = fcntl(fd, F_GETFL);
  33.         fcntl(fd, F_SETFL, flag | FASYNC);
  34.         sleep(5);
  35.     }
  36.     else
  37.     {
  38.         perror("open /dev/globalfifo");
  39.     }

  40.     return 0;
  41. }
运行#./fifo,  再开一个终端#echo 'hello' > /dev/globalfifo
receive buf from globalfifo, signal = 29
hello

阅读(2343) | 评论(1) | 转发(1) |
给主人留下些什么吧!~~

桔子T恤2012-03-27 22:32:27

内核版本2.6.27之前的创建设备节点的函数是struct class_device class_device_create