Chinaunix首页 | 论坛 | 博客
  • 博客访问: 959040
  • 博文数量: 116
  • 博客积分: 3923
  • 博客等级: 中校
  • 技术积分: 1337
  • 用 户 组: 普通用户
  • 注册时间: 2009-04-23 01:22
文章分类

全部博文(116)

文章存档

2013年(1)

2012年(17)

2011年(69)

2009年(29)

分类: LINUX

2011-12-25 13:42:08

刚看了华清远见的《Linux设备驱动开发详解》,突然就想动手慢慢的实践一番,就当作笔记吧,先来个简单的驱动,其实就是里面的例子,不过感觉写的还是很不错,自己也动手尝试一下:

  1. /*
  2.  * file: gmemd.c
  3.  * history:
  4.  * 20111205: initial
  5.  * 20111205: support async event to app level
  6.  */
  7. #include <linux/init.h>
  8. #include <linux/module.h>
  9. #include <linux/cdev.h>
  10. #include <linux/fs.h>
  11. #include <linux/signal.h>

  12. #include <asm/uaccess.h>

  13. #define GMEMD_MAJOR 221

  14. #define MEM_CLEAR 0x01

  15. #define DEMO_NAME "demo_dev"
  16. #define MEM_SIZE 1024

  17. static int gmemd_major = GMEMD_MAJOR;


  18. typedef struct demo_dev_st
  19. {
  20.     struct cdev cdev;
  21.     unsigned char mem[MEM_SIZE];
  22.     struct fasync_struct *async_queue;
  23. }demo_dev_t;

  24. static struct demo_dev_st* __demo_devp=0;


  25. static int __demo_open (struct inode *inode, struct file *filp)
  26. {
  27.     filp->private_data = __demo_devp;
  28.     printk("==>trace: %s\n", __func__);
  29.     return 0;
  30. }



  31. static ssize_t __demo_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
  32. {
  33.     int ret = 0;
  34.     unsigned long pos = *ppos;
  35.     unsigned long count = size;
  36.     
  37.     struct demo_dev_st* devp = filp->private_data;
  38.     
  39.     printk("==>trace: %s, size=%d, pos=%d\n", __func__, size, pos);
  40.     
  41. #if 0
  42.     if (pos >= MEM_SIZE)
  43.         return count ? -ENXIO : 0;
  44.     if (count > MEM_SIZE - pos)
  45.         count = MEM_SIZE - pos;
  46. #else
  47.     {
  48.         int i=0;
  49.         while (i<MEM_SIZE-1 && devp->mem[i]) i++;
  50.         if (i==MEM_SIZE-1)
  51.         {
  52.             devp->mem[i]=0;
  53.         }
  54.         count = i;
  55.     }
  56. #endif
  57.     
  58.     if (copy_to_user(buf, (void*)(devp->mem+pos), count))
  59.     {
  60.         ret = -EFAULT;
  61.     }
  62.     else
  63.     {
  64. #if 0
  65.         *ppos += count;
  66. #else
  67.         *ppos = 0;
  68. #endif
  69.         ret = count;
  70.     }
  71.     return ret;
  72. }

  73. static ssize_t __demo_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
  74. {
  75.     int ret = 0;
  76.     unsigned long pos = *ppos;
  77.     unsigned long count = size;
  78.     
  79.     struct demo_dev_st* devp = filp->private_data;
  80.     
  81.     printk("==>trace: %s, size=%d, pos=%d\n", __func__, size, pos);
  82.     
  83.     if (pos >= MEM_SIZE)
  84.         return count ? -ENXIO : 0;
  85.     if (count > MEM_SIZE - pos)
  86.         count = MEM_SIZE - pos;
  87.     
  88.     if (copy_from_user(devp->mem+pos,buf,count))
  89.     {
  90.         ret = -EFAULT;
  91.     }
  92.     else
  93.     {
  94. #if 0
  95.         *ppos= count;
  96. #else
  97.         *ppos= 0;
  98. #endif
  99.         ret = count;
  100.         if (devp->async_queue)
  101.             kill_fasync(&devp->async_queue, SIGIO, POLL_IN);
  102.     }
  103.     return ret;
  104. }

  105. static int __demo_fasync(int fd, struct file *filp, int mode)
  106. {
  107.     struct demo_dev_st* devp = filp->private_data;
  108.     printk("==>trace: %s\n", __func__);
  109.     
  110.     return fasync_helper(fd, filp, mode, &devp->async_queue);
  111. }

  112. static loff_t __demo_llseek(struct file *filp, loff_t offset, int orig)
  113. {
  114.     loff_t ret = 0;
  115.     
  116.     struct demo_dev_st* devp = filp->private_data;
  117.     
  118.     printk("==>trace: %s, orig=%d, offset=%d\n", __func__, orig, offset);
  119.     
  120.     switch(orig)
  121.     {
  122.     case 0: /* offset from the 0 position of the file */
  123.         if (offset < 0 || (unsigned int)offset > MEM_SIZE)
  124.         {
  125.             ret = -EINVAL;
  126.             break;
  127.         }
  128.         ret = filp->f_pos = (unsigned int)offset;
  129.         break;
  130.     case 1: /* offset from the current position */
  131.         if ((filp->f_pos+offset)<0||(filp->f_pos+offset)>MEM_SIZE)
  132.         {
  133.             ret = -EINVAL;
  134.             break;
  135.         }
  136.         filp->f_pos += offset;
  137.         ret = filp->f_pos;
  138.         break;
  139.     default:
  140.         ret = -EINVAL;
  141.         break;
  142.     }
  143.     
  144.     return ret;
  145. }


  146. static long __demo_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
  147. {
  148.     long ret = 0;
  149.     
  150.     struct demo_dev_st* devp = filp->private_data;
  151.     switch(cmd)
  152.     {
  153.     case MEM_CLEAR:
  154.         memset(devp->mem, 0, MEM_SIZE);
  155.         break;
  156.     default:
  157.         ret = -EINVAL;
  158.         break;
  159.     }
  160.     return ret;
  161. }

  162. static int __demo_release(struct inode *inode, struct file *filp)
  163. {
  164.     struct demo_dev_st* devp = filp->private_data;
  165.     printk("==>trace: %s\n", __func__);
  166.     __demo_fasync(-1, filp, 0);
  167.     return 0;
  168. }


  169. static struct file_operations gmemd_fops =
  170. {
  171.     .owner = THIS_MODULE,
  172.         .read = __demo_read,
  173.         .write = __demo_write,
  174.         .open = __demo_open,
  175.         .release = __demo_release,
  176.         .fasync = __demo_fasync,
  177.         .llseek = __demo_llseek,
  178.         .ioctl = __demo_ioctl,
  179. };

  180. static int __gmemd_init()
  181. {
  182.     int ret = 0;
  183.     dev_t devno = MKDEV(gmemd_major, 0);
  184.     
  185.     printk("==>trace: %s\n", __func__);
  186.     
  187.     if (gmemd_major)
  188.     {
  189.         ret = register_chrdev_region(devno,1,DEMO_NAME);
  190.     }
  191.     else
  192.     {
  193.         ret = alloc_chrdev_region(&devno, 0, 1, DEMO_NAME);
  194.         gmemd_major = MAJOR(devno);
  195.     }
  196.     if (ret < 0)
  197.         return ret;
  198.     
  199.     __demo_devp=kmalloc(sizeof(demo_dev_t),GFP_KERNEL); /* __get_free_pages */
  200.     
  201.     if (!__demo_devp)
  202.     {
  203.         ret = -ENOMEM;
  204.         goto __err_exit;
  205.     }
  206.     memset(__demo_devp, 0, sizeof(demo_dev_t));
  207.     
  208.     cdev_init(&__demo_devp->cdev , &gmemd_fops);
  209.     __demo_devp->cdev.owner = THIS_MODULE;
  210.     ret = cdev_add(&__demo_devp->cdev, devno, 1);
  211.     if (ret)
  212.         printk(KERN_INFO "error to cdev_add() ... \n");
  213.     
  214.     return ret;
  215.     
  216. __err_exit:
  217.     unregister_chrdev_region(devno, 1);
  218.     
  219.     return ret;
  220. }

  221. static void __gmemd_exit()
  222. {
  223.     printk("==>trace: %s\n", __func__);
  224.     cdev_del(&__demo_devp->cdev);
  225.     kfree(__demo_devp);
  226.     __demo_devp=0;
  227.     unregister_chrdev_region(MKDEV(gmemd_major,0), 1);
  228. }

  229. module_init(__gmemd_init);
  230. module_exit(__gmemd_exit);

  231. MODULE_AUTHOR("vincent");
  232. MODULE_DESCRIPTION("nothing to say...");
  233. MODULE_LICENSE("GPL");
  234. MODULE_ALIAS("test");

应用层测试用的APP:

  1. /*
  2.  * file: client.c
  3.  * history:
  4.  * 20111205: initial, for test async event in the app level
  5.  */

  6. #include <unistd.h>
  7. #include <fcntl.h>
  8. #include <signal.h>
  9. #include <stdio.h>
  10. #include <sys/stat.h>

  11. #define DEMO_DEV "/dev/gmemd"

  12. static int s_fd=-1;


  13. static void __sig_handler(int signum)
  14. {
  15. #define MAX_BUF 1023
  16.     int count = 0;
  17.     char buf[MAX_BUF+1]= {0};
  18.     
  19.     printf("==>signum:%d\n", signum);
  20.     
  21.     if (s_fd!=-1)
  22.     {
  23.         while ((count=read(s_fd, buf, MAX_BUF))>=MAX_BUF)
  24.         {
  25.             printf("count:%d=>%s\n", count,(buf[MAX_BUF]=0,buf));
  26.         }
  27.         printf("count:%d=>%s\n", count,(buf[count]=0,buf));
  28.     }
  29. }

  30. int main(void)
  31. {
  32.     int fd, oflags;
  33.     printf("wellcome to startup the client program!\n");
  34.     s_fd = fd = open (DEMO_DEV, O_RDWR, S_IRUSR|S_IWUSR);
  35.     if (fd==-1)
  36.     {
  37.         printf("open %s failed!\n", DEMO_DEV);
  38.         return -1;
  39.     }
  40.     else
  41.     {
  42.         printf("open %s successful!\n", DEMO_DEV);
  43.         signal(SIGIO, __sig_handler);
  44.         fcntl(fd, F_SETOWN, getpid());
  45.         oflags = fcntl(fd, F_GETFL);
  46.         fcntl(fd, F_SETFL, oflags|FASYNC);
  47.         while(1);
  48.     }
  49. }


接下来就是Makefile:
  1. #Makefile

  2. obj-m := gmemd.o

  3. KDIR := /usr/src/linux-headers-2.6.24-16-generic

  4. CC := gcc

  5. default:
  6.     make -C $(KDIR) M=$(PWD) modules

  7. client: client.o
  8.     $(CC) -Wall client.c -o client

编译之前发现自己的gcc没下载开发包,需要执行指令:
sudo apt-get install build-essential

然后编译:
make
make client
再加载模块:
insmod gmemd.ko
再查看加载的模块:
lsmod | grep gmemd
再查看注册的设备信息:
cat /proc/devices
再在/dev/目录下创建一个设备节点信息提供给应用层的访问:
mknod /dev/gmemd c 221 0
查看设备节点信息:
ls -l /dev/gmemd
再对设备节点对其读写:
echo "test" > /dev/gmemd
cat /dev/gmemd

测试异步IO响应事件:
./client &
echo "test" > /dev/gmemd

再查看里面printk打印出来的日志信息:
cat /var/log/messages
最后删除设备节点和卸载模块:
rm /dev/gmemd
rmmod gmemd

完成

附件:

 gmemd.rar  







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