zoukankan      html  css  js  c++  java
  • 内核驱动系列字符设备驱动流程

    内核模块基础:

    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 内核模块的编译,简单示例如

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

    字符设备驱动:

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

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

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

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

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

    #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>//for kfree
    #include <linux/kernel.h>
    
    #define GLOBALMEM_SIZE 0x1000
    #define MEM_CLEAR 0x1
    #define GLOBALMEM_MAJOR 250
    #define GLOBALMEM_MAGIC 'j' //for the command of ioctl
    #define MEM_CLEAN_IO (GLOBALMEM_MAGIC, 0)
    
    static int globalmem_major = GLOBALMEM_MAJOR;
    struct globalmem_dev {
    	struct cdev cdev;
    	unsigned char mem[GLOBALMEM_SIZE];
    };
    struct  globalmem_dev *globalmem_devp;
    //use the private_data for more than one device
    int globalmem_open (struct inode *inode, struct file *filp)
    {
    	struct globalmem_dev *dev;
    	dev = container_of (inode->i_cdev, struct globalmem_dev, cdev);
    	filp->private_data = dev;
    	return 0;
    }
    int globalmem_release (struct inode *inode, struct file *filp)
    {
    	return 0;
    }
    static ssize_t globalmem_read (struct file *filp, 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 0;
    	if (count > GLOBALMEM_SIZE - p)
    		count = GLOBALMEM_SIZE - p;
    	if (copy_to_user (buf, (void *) (dev->mem + p), count))
    		ret = -EFAULT;
    	else {
    		*ppos += count;
    		ret = count;
    		printk (KERN_INFO "read %d bytes(s) from %ld\n", count, 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;
    	size_t count = size;
    	int ret = 0;
    	struct globalmem_dev *dev = filp->private_data;
    
    	if (p >= GLOBALMEM_SIZE)
    		return 0;
    	if (count > GLOBALMEM_SIZE-p)
    		count = GLOBALMEM_SIZE - p;
    	if (copy_from_user (dev->mem+p, buf, count))
    		ret = -EFAULT;
    	else {
    		*ppos += count;
    		ret = count;
    		printk (KERN_INFO "written %d bytes from %ld\n", count, p);
    	}
    	return ret;
    }
    static loff_t globalmem_llseek (struct file *filp, loff_t offset, int orig)
    {
    	loff_t ret;
    	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;
    		default:
    			ret = -EINVAL;
    	}
    	return ret;
    }
    
    static int globalmem_ioctl (struct inode *inodep, 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);
    			printk (KERN_INFO "globalmem is set to zero\n");
    			break;
    		default:
    			return -EINVAL;
    	}
    	return 0;
    }
    
    static const struct file_operations globalmem_fops = {
    	.owner = THIS_MODULE,
    	.llseek = globalmem_llseek,
    	.read = globalmem_read,
    	.write = globalmem_write,
    	.ioctl = globalmem_ioctl,
    	.open = globalmem_open,
    	.release = globalmem_release,
    };
    static void globalmem_setup_cdev (struct globalmem_dev *dev, int index)
    {
    	int err;
    	int devno = MKDEV (globalmem_major, 0);
    
    	cdev_init (&dev->cdev, &globalmem_fops);
    	dev->cdev.owner = THIS_MODULE;
    	err = cdev_add (&dev->cdev, devno, 1);
    	if (err)
    		printk (KERN_NOTICE "Error %d adding globalmem", err);
    }
    int globalmem_init (void)
    {
    	int result;
    	dev_t devno = MKDEV (globalmem_major, 0);
    	if (globalmem_major)
    		result = register_chrdev_region (devno, 2, "globalmem");
    	else {
    		result = alloc_chrdev_region (&devno, 0, 2, "globalmem");
    		globalmem_major = MAJOR (devno);
    	}
    	if (result < 0)
    		return result;
    	globalmem_devp = kmalloc (2 * sizeof (struct globalmem_dev),
    			GFP_KERNEL);
    	if (!globalmem_devp) {
    		result = -ENOMEM;
    		goto fail_malloc; //use goto for exception handling
    	}
    	memset (globalmem_devp, 0, 2 * sizeof (struct globalmem_dev));
    	globalmem_setup_cdev (&globalmem_devp[0], 0);
    	globalmem_setup_cdev (&globalmem_devp[1], 1);
    	return 0;
    
    fail_malloc: unregister_chrdev_region (devno, 1);
    return result;
    }
    
    void globalmem_exit (void)
    {
    	cdev_del (&(globalmem_devp[0].cdev));
    	cdev_del (&(globalmem_devp[1].cdev));
    	kfree (globalmem_devp);
    	unregister_chrdev_region (MKDEV (globalmem_major, 0), 2);
    }
    
    MODULE_AUTHOR ("ljia");
    MODULE_LICENSE ("Dual BSD/GPL");
    module_param (globalmem_major, int, S_IRUGO);
    module_init (globalmem_init);
    module_exit (globalmem_exit);
    

      

  • 相关阅读:
    JavaScript Patterns 5.7 Object Constants
    JavaScript Patterns 5.6 Static Members
    JavaScript Patterns 5.5 Sandbox Pattern
    JavaScript Patterns 5.4 Module Pattern
    JavaScript Patterns 5.3 Private Properties and Methods
    JavaScript Patterns 5.2 Declaring Dependencies
    JavaScript Patterns 5.1 Namespace Pattern
    JavaScript Patterns 4.10 Curry
    【Android】如何快速构建Android Demo
    【Android】如何实现ButterKnife
  • 原文地址:https://www.cnblogs.com/liujiahi/p/2216564.html
Copyright © 2011-2022 走看看