Chinaunix首页 | 论坛 | 博客
  • 博客访问: 732601
  • 博文数量: 77
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1173
  • 用 户 组: 普通用户
  • 注册时间: 2014-05-16 11:20
个人简介

将技术做到极致...

文章分类

全部博文(77)

文章存档

2019年(3)

2015年(27)

2014年(47)

分类: LINUX

2014-09-12 14:20:45

内核模块基础:

1 可以通过编译进内核和动态加载内核模块来将驱动模块加载,调试过程中后者比较常用。

2 相关命令: insmod rmmod modinfo lsmod dmesg modinfo cat /proc/devices cat /proc/moduls

3 内核模块程序结构:

  1 模块加载函数 --- module_init (initial_function) 其中initial_functon 常用__init修饰

  2 模块卸载函数 --- module_exit (cleanup_function) 其中cleanup_functon 常用__exit修饰

  3 模块许可声明 (必须) --- MODULE_LICENSE ("DUAL BSD/GPL");

  4 模块参数(可选)--- module_param

  5 模块导出符号 (可选)--- EXPORT_SYMBOL (add_interger);

  6 模块作者等信息声明(可选)--- MODULE_AUTHOR MODULE_DEVICE_TABLE 等

4 内核模块的编译,Makefile简单示例如

点击(此处)折叠或打开

  1. ##一定要注意内核版本与交叉编译工具链相一致,此处的内核目录是目标板的源码目录
  2. obj-m += hello-ioctl.o
  3. ##多文件时加一句 modulename-objs := file1.o file2.o
  4. ARCH ?= arm
  5. CROSS_COMPILE ?= arm-linux-
  6. KERNELDIR := /source/kernel/linux-2.6.35
  7. all:
  8.     make -C $(KERNELDIR) M=$(PWD) modules
  9. clean:
  10.     make -C $(KERNELDIR) M=$(PWD) clean

 

字符设备驱动:

一个字符设备驱动主要由驱动加载与卸载函数 和 file_operations结构体中成员函数组成。

加载模块中主要完成设备号的申请和cdev的注册,而在卸载函数中英实现设备号与cdev的注销。

file_operations结构体成员函数是字符设备驱动与内核的接口,大多数字符设备驱动都会实现

read(), write()和ioctl()函数。

下面使用一个虚拟的globalmem设备来说明字符设备驱动的编写过程:

点击(此处)折叠或打开

  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>
  10. #include <asm/system.h>
  11. #include <asm/uaccess.h>
  12. #include <linux/slab.h>//for kfree
  13. #include <linux/kernel.h>
  14.   
  15. #define GLOBALMEM_SIZE 0x1000
  16. #define MEM_CLEAR 0x1
  17. #define GLOBALMEM_MAJOR 250
  18. #define GLOBALMEM_MAGIC 'j' //for the command of ioctl
  19. #define MEM_CLEAN_IO (GLOBALMEM_MAGIC, 0)
  20.   
  21. static int globalmem_major = GLOBALMEM_MAJOR;
  22. struct globalmem_dev {
  23.     struct cdev cdev;
  24.     unsigned char mem[GLOBALMEM_SIZE];
  25. };
  26. struct globalmem_dev *globalmem_devp;
  27. //use the private_data for more than one device
  28. int globalmem_open (struct inode *inode, struct file *filp)
  29. {
  30.     struct globalmem_dev *dev;
  31.     dev = container_of (inode->i_cdev, struct globalmem_dev, cdev);
  32.     filp->private_data = dev;
  33.     return 0;
  34. }
  35. int globalmem_release (struct inode *inode, struct file *filp)
  36. {
  37.     return 0;
  38. }
  39. static ssize_t globalmem_read (struct file *filp, char __user *buf,
  40.         size_t size, loff_t *ppos)
  41. {
  42.     unsigned long p = *ppos;
  43.     unsigned int count = size;
  44.     int ret = 0;
  45.     struct globalmem_dev *dev = filp->private_data;
  46.     if (p >= GLOBALMEM_SIZE)
  47.         return 0;
  48.     if (count > GLOBALMEM_SIZE - p)
  49.         count = GLOBALMEM_SIZE - p;
  50.     if (copy_to_user (buf, (void *) (dev->mem + p), count))
  51.         ret = -EFAULT;
  52.     else {
  53.         *ppos += count;
  54.         ret = count;
  55.         printk (KERN_INFO "read %d bytes(s) from %ld\n", count, p);
  56.     }
  57.   
  58.     return ret;
  59. }
  60. static ssize_t globalmem_write (struct file *filp, const char __user *buf,
  61.         size_t size, loff_t *ppos)
  62. {
  63.     unsigned long p = *ppos;
  64.     size_t count = size;
  65.     int ret = 0;
  66.     struct globalmem_dev *dev = filp->private_data;
  67.   
  68.     if (p >= GLOBALMEM_SIZE)
  69.         return 0;
  70.     if (count > GLOBALMEM_SIZE-p)
  71.         count = GLOBALMEM_SIZE - p;
  72.     if (copy_from_user (dev->mem+p, buf, count))
  73.         ret = -EFAULT;
  74.     else {
  75.         *ppos += count;
  76.         ret = count;
  77.         printk (KERN_INFO "written %d bytes from %ld\n", count, p);
  78.     }
  79.     return ret;
  80. }
  81. static loff_t globalmem_llseek (struct file *filp, loff_t offset, int orig)
  82. {
  83.     loff_t ret;
  84.     switch (orig) {
  85.         case 0:
  86.             if (offset < 0) {
  87.                 ret = -EINVAL;
  88.                 break;
  89.             }
  90.             if ((unsigned int)offset > GLOBALMEM_SIZE) {
  91.                 ret = -EINVAL;
  92.                 break;
  93.             }
  94.             filp->f_pos = (unsigned int) offset;
  95.             ret = filp->f_pos;
  96.             break;
  97.         case 1:
  98.             if ((filp->f_pos + offset) > GLOBALMEM_SIZE) {
  99.                 ret = -EINVAL;
  100.                 break;
  101.             }
  102.             if ((filp->f_pos + offset) < 0) {
  103.                 ret = -EINVAL;
  104.                 break;
  105.             }
  106.             filp->f_pos += offset;
  107.             ret = filp->f_pos;
  108.             break;
  109.         default:
  110.             ret = -EINVAL;
  111.     }
  112.     return ret;
  113. }
  114.   
  115. static int globalmem_ioctl (struct inode *inodep, struct file *filp, unsigned int cmd, unsigned long arg)
  116. {
  117.     struct globalmem_dev *dev = filp->private_data;
  118.     switch (cmd) {
  119.         case MEM_CLEAR:
  120.             memset (dev->mem, 0, GLOBALMEM_SIZE);
  121.             printk (KERN_INFO "globalmem is set to zero\n");
  122.             break;
  123.         default:
  124.             return -EINVAL;
  125.     }
  126.     return 0;
  127. }
  128.   
  129. static const struct file_operations globalmem_fops = {
  130.     .owner = THIS_MODULE,
  131.     .llseek = globalmem_llseek,
  132.     .read = globalmem_read,
  133.     .write = globalmem_write,
  134.     .ioctl = globalmem_ioctl,
  135.     .open = globalmem_open,
  136.     .release = globalmem_release,
  137. };
  138. static void globalmem_setup_cdev (struct globalmem_dev *dev, int index)
  139. {
  140.     int err;
  141.     int devno = MKDEV (globalmem_major, 0);
  142.   
  143.     cdev_init (&dev->cdev, &globalmem_fops);
  144.     dev->cdev.owner = THIS_MODULE;
  145.     err = cdev_add (&dev->cdev, devno, 1);
  146.     if (err)
  147.         printk (KERN_NOTICE "Error %d adding globalmem", err);
  148. }
  149. int globalmem_init (void)
  150. {
  151.     int result;
  152.     dev_t devno = MKDEV (globalmem_major, 0);
  153.     if (globalmem_major)
  154.         result = register_chrdev_region (devno, 2, "globalmem");
  155.     else {
  156.         result = alloc_chrdev_region (&devno, 0, 2, "globalmem");
  157.         globalmem_major = MAJOR (devno);
  158.     }
  159.     if (result < 0)
  160.         return result;
  161.     globalmem_devp = kmalloc (2 * sizeof (struct globalmem_dev),
  162.             GFP_KERNEL);
  163.     if (!globalmem_devp) {
  164.         result = -ENOMEM;
  165.         goto fail_malloc; //use goto for exception handling
  166.     }
  167.     memset (globalmem_devp, 0, 2 * sizeof (struct globalmem_dev));
  168.     globalmem_setup_cdev (&globalmem_devp[0], 0);
  169.     globalmem_setup_cdev (&globalmem_devp[1], 1);
  170.     return 0;
  171.   
  172. fail_malloc: unregister_chrdev_region (devno, 1);
  173. return result;
  174. }
  175.   
  176. void globalmem_exit (void)
  177. {
  178.     cdev_del (&(globalmem_devp[0].cdev));
  179.     cdev_del (&(globalmem_devp[1].cdev));
  180.     kfree (globalmem_devp);
  181.     unregister_chrdev_region (MKDEV (globalmem_major, 0), 2);
  182. }
  183.   
  184. MODULE_AUTHOR ("cfm");
  185. MODULE_LICENSE ("Dual BSD/GPL");
  186. module_param (globalmem_major, int, S_IRUGO);
  187. module_init (globalmem_init);
  188. module_exit (globalmem_exit);

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