• Linux 内核驱动自动创建设备节点并挂载设备


    *注:本文来自http://blog.csdn.net/lwj103862095/article/details/17470573

    一、首先需要在最开始定义两个数据结构:

    static struct class *firstdrv_class;  
    static struct device *firstdrv_device; 

    二、在init函数里通过class_create和device_create函数创建相应的设备节点,示例代码如下:

    static int first_drv_init(void)  
    {  
        /* 主设备号设置为0表示由系统自动分配主设备号 */  
        major = register_chrdev(0, "first_drv", &first_drv_fops);  
      
        /* 创建firstdrv类 */  
        firstdrv_class = class_create(THIS_MODULE, "firstdrv");  
      
        /* 在firstdrv类下创建xxx设备,供应用程序打开设备*/  
        firstdrv_device = device_create(firstdrv_class, NULL, MKDEV(major, 0), NULL, "xxx");  
        return 0;  
    }  

    三、在exit函数里通过device_destroy、class_unregister、class_destroy函数对设备进行卸载

    static void first_drv_exit(void)  
    {  
        device_destroy(firstdrv_class,MKDEV(major,0));
        class_unregister(firstdrv_class);
        class_destroy(firstdrv_class);
        unregister_chrdev(major, "first_drv");  
    }  

    参考代码一、

        #include <linux/kernel.h>  
        #include <linux/fs.h>  
        #include <linux/init.h>  
        #include <linux/delay.h>  
        #include <asm/uaccess.h>  
        #include <asm/irq.h>  
        #include <asm/io.h>  
        #include <linux/module.h>  
        #include <linux/device.h>     //class_create  
          
        static struct class *firstdrv_class;  
        static struct device *firstdrv_device;  
          
        int major;  
        static int first_drv_open(struct inode * inode, struct file * filp)  
        {  
            printk("first_drv_open
    ");  
            return 0;  
        }  
        static int first_drv_write(struct file * file, const char __user * buffer, size_t count, loff_t * ppos)  
        {  
            printk("first_drv_write
    ");  
            return 0;  
        }  
          
        /* File operations struct for character device */  
        static const struct file_operations first_drv_fops = {  
            .owner      = THIS_MODULE,  
            .open       = first_drv_open,  
            .write      = first_drv_write,  
        };  
          
        /* 驱动入口函数 */  
        static int first_drv_init(void)  
        {  
            /* 主设备号设置为0表示由系统自动分配主设备号 */  
            major = register_chrdev(0, "first_drv", &first_drv_fops);  
          
            /* 创建firstdrv类 */  
            firstdrv_class = class_create(THIS_MODULE, "firstdrv");  
          
            /* 在firstdrv类下创建xxx设备,供应用程序打开设备*/  
            firstdrv_device = device_create(firstdrv_class, NULL, MKDEV(major, 0), NULL, "xxx");  
            return 0;  
        }  
          
        /* 驱动出口函数 */  
        static void first_drv_exit(void)  
        {  
            unregister_chrdev(major, "first_drv");  
            device_unregister(firstdrv_device);  //卸载类下的设备  
            class_destroy(firstdrv_class);      //卸载类  
        }  
          
        module_init(first_drv_init);  //用于修饰入口函数  
        module_exit(first_drv_exit);  //用于修饰出口函数      
          
        MODULE_AUTHOR("LWJ");  
        MODULE_DESCRIPTION("Just for Demon");  
        MODULE_LICENSE("GPL");  //遵循GPL协议  

    参考代码二

    #include <linux/init.h>
    #include <linux/module.h>
    #include <linux/delay.h>
    #include <linux/kernel.h>
    #include <linux/moduleparam.h>
    #include <linux/init.h>
    #include <linux/types.h>
    #include <linux/fs.h>
    #include <mach/regs-gpio.h>
    #include <linux/device.h>
    #include <mach/hardware.h>
    #include <linux/cdev.h>
    #include <asm/uaccess.h>
    #include <linux/errno.h>
    
    
    #include <linux/kernel.h>
    #include <linux/init.h>
    #include <linux/module.h>
    #include <linux/interrupt.h>
    #include <linux/ioport.h>
    #include <linux/gpio.h>
    #include <linux/io.h>
    
    #include <mach/hardware.h>
    #include <mach/map.h> 
    #include <mach/regs-gpio.h>
    #include <mach/gpio-bank-e.h>
    #include <mach/regs-clock.h> 
    #include <asm/irq.h>
    
    #include <plat/gpio-core.h>
    #include <plat/gpio-cfg.h>
    
    //#define DEBUG
    /* 相关引脚定义,方便以后移植 */
    #define DEVICE_NAME "ds18b20"
    #define DQ         2
    #define CFG_IN     0
    #define CFG_OUT    1
    
    // ds18b20主次设备号(动态分配)
    int ds18b20_major = 0;
    int ds18b20_minor = 0;
    int ds18b20_nr_devs = 1;
    
    // 定义设备类型
    static struct ds18b20_device {
        struct cdev cdev;
    };
    struct ds18b20_device ds18b20_dev;
    
    static struct class *ds18b20_class;
    
    /* 函数声明 */
    static int ds18b20_open(struct inode *inode, struct file *filp);
    static int ds18b20_init(void);
    static void write_byte(unsigned char data);
    static unsigned char read_byte(void);
    static ssize_t ds18b20_read(struct file *filp, char __user *buf,
                                size_t count, loff_t *f_pos);
    void ds18b20_setup_cdev(struct ds18b20_device *dev, int index);
    
    
    
    void s3c6410_gpio_cfgpin(unsigned int pin, unsigned int function)
    {
        //s3c_gpio_cfgpin(pin,function);
            unsigned int tmp; 
            tmp = readl(S3C64XX_GPECON); 
            tmp = (tmp & ~(0XF<<pin*4))|(function<<pin*4); 
            writel(tmp, S3C64XX_GPECON); 
    }
    
    void s3c6410_gpio_pullup(unsigned int pin, unsigned int to)
    {
            //s3c_gpio_setpull(pin,to);
            unsigned int tmp; 
            tmp = readl(S3C64XX_GPEPUD); 
            tmp = (tmp & ~(3<<pin*2))|(to<<pin*2); 
            writel(tmp, S3C64XX_GPEPUD); 
    }
    
    unsigned int s3c6410_gpio_getpin(unsigned int pin) 
    { 
            unsigned int tmp;
        tmp = readl(S3C64XX_GPEDAT); 
        tmp = tmp & (1 << (pin));  
    
        return tmp; 
    }
    
    void s3c6410_gpio_setpin(unsigned int pin, unsigned int dat)
    {
            unsigned int tmp; 
        tmp = readl(S3C64XX_GPEDAT); 
        tmp &= ~(1 << (pin)); 
        tmp |= ( (dat) << (pin) ); 
        writel(tmp, S3C64XX_GPEDAT); ;
    }
    
    
    
    /******************************************************************************************************
    ** 函数名称: ds18b20_open()
    ** 函数功能: 打开设备,初始化ds18b20
    ** 入口参数: inode:设备文件信息; filp: 被打开的文件的信息
    ** 出口参数: 成功时返回0,失败返回-1
    ** 备    注:
    ******************************************************************************************************/
    static int ds18b20_open(struct inode *inode, struct file *filp)
    {
        int flag = 0;
        /*struct ds18b20_device *dev;
        dev = container_of(inode->i_cdev, struct ds18b20_device, cdev);
        filp->private_data = dev;*/
    
        flag = ds18b20_init();
        if(flag & 0x01)
        {
    #ifdef DEBUG
            printk(KERN_WARNING "open ds18b20 failed
    ");
    #endif
        return -1;
        }
    #ifdef DEBUG
        printk(KERN_NOTICE "open ds18b20 successful
    ");
    #endif
        return 0;
    }
    
    /******************************************************************************************************
    ** 函数名称: ds18b20_init()
    ** 函数功能: 复位ds18b20
    ** 入口参数: 无
    ** 出口参数: retval:成功返回0,失败返回1
    ** 备    注: 操作时序见ds18b20 datasheet
    ******************************************************************************************************/
    static int ds18b20_init(void)
    {
        int retval = 0;
    
        s3c6410_gpio_cfgpin(DQ, CFG_OUT);
        s3c6410_gpio_pullup(DQ, 0);
    
        s3c6410_gpio_setpin(DQ, 1);
        udelay(2);
        s3c6410_gpio_setpin(DQ, 0);        // 拉低ds18b20总线,复位ds18b20
        udelay(500);                       // 保持复位电平500us
    
        s3c6410_gpio_setpin(DQ, 1);        // 释放ds18b20总线
        udelay(60);
    
        // 若复位成功,ds18b20发出存在脉冲(低电平,持续60~240us)
        s3c6410_gpio_cfgpin(DQ, CFG_IN);
        retval = s3c6410_gpio_getpin(DQ);
    
        udelay(500);
        s3c6410_gpio_cfgpin(DQ, CFG_OUT);
        s3c6410_gpio_pullup(DQ, 0);
        s3c6410_gpio_setpin(DQ, 1);        // 释放总线
        
        return retval;
    }
    
    /******************************************************************************************************
    ** 函数名称: write_byte()
    ** 函数功能: 向18b20写入一个字节数据
    ** 入口参数: data
    ** 出口参数: 无
    ** 备    注:
    ******************************************************************************************************/
    static void write_byte(unsigned char data)
    {
        int i = 0;
    
        s3c6410_gpio_cfgpin(DQ, CFG_OUT);
        s3c6410_gpio_pullup(DQ, 1);
    
        for (i = 0; i < 8; i ++)
        {
            // 总线从高拉至低电平时,就产生写时隙
            s3c6410_gpio_setpin(DQ, 1);
            udelay(2);
            s3c6410_gpio_setpin(DQ, 0);
            s3c6410_gpio_setpin(DQ, data & 0x01);
            udelay(60);
        data >>= 1;
        }
        s3c6410_gpio_setpin(DQ, 1);        // 重新释放ds18b20总线
    }
    
    /******************************************************************************************************
    ** 函数名称: read_byte()
    ** 函数功能: 从ds18b20读出一个字节数据
    ** 入口参数: 无
    ** 出口参数: 读出的数据
    ** 备    注:
    ******************************************************************************************************/
    static unsigned char read_byte(void)
    {
        int i;
        unsigned char data = 0;
    
        for (i = 0; i < 8; i++)
        {
            // 总线从高拉至低,只需维持低电平17ts,再把总线拉高,就产生读时隙
            s3c6410_gpio_cfgpin(DQ, CFG_OUT);
            s3c6410_gpio_pullup(DQ, 0);
            s3c6410_gpio_setpin(DQ, 1);
            udelay(2);
            s3c6410_gpio_setpin(DQ, 0);
            udelay(2);
        s3c6410_gpio_setpin(DQ, 1);
            udelay(8);
            data >>= 1;
        s3c6410_gpio_cfgpin(DQ, CFG_IN);
        if (s3c6410_gpio_getpin(DQ))
            data |= 0x80;
        udelay(50);
        }
        s3c6410_gpio_cfgpin(DQ, CFG_OUT);
        s3c6410_gpio_pullup(DQ, 0);
        s3c6410_gpio_setpin(DQ, 1);        // 释放ds18b20总线
        return data;
    }
    /******************************************************************************************************
    ** 函数名称: ds18b20_read()
    ** 函数功能: 读出18b20的温度
    ** 入口参数: 
    ** 出口参数: 
    ** 备    注:
    ******************************************************************************************************/
    static ssize_t ds18b20_read(struct file *filp, char __user *buf,
                                size_t count, loff_t *f_pos)
    {
        int flag;
        unsigned long err;
        unsigned char result[2] = {0x00, 0x00};
        //struct ds18b20_device *dev = filp->private_data;
    
        flag = ds18b20_init();
        if (flag)
        {
    #ifdef DEBUG
            printk(KERN_WARNING "ds18b20 init failed
    ");
    #endif
            return -1;
        }
        
        write_byte(0xcc);
        write_byte(0x44);
    
        flag = ds18b20_init();
        if (flag)
            return -1;
    
        write_byte(0xcc);
        write_byte(0xbe);
    
        result[0] = read_byte();    // 温度低八位
        result[1] = read_byte();    // 温度高八位
        
        err = copy_to_user(buf, &result, sizeof(result));
        return err ? -EFAULT : min(sizeof(result),count);
    }
    
    /**************************************************************
     * 字符驱动程序的核心,应用程序所调用的open,read等函数最终会
     * 调用这个结构中的对应函数
     *************************************************************/
    static struct file_operations ds18b20_dev_fops = {
        .owner = THIS_MODULE,
        .open = ds18b20_open,
        .read = ds18b20_read,
    };
    
    /******************************************************************************************************
    ** 函数名称: ds18b20_setup_cdev()
    ** 函数功能: 初始化cdev
    ** 入口参数: dev:设备结构体; index:
    ** 出口参数: 无
    ** 备    注:
    ******************************************************************************************************/
    void ds18b20_setup_cdev(struct ds18b20_device *dev, int index)
    {
        int err, devno = MKDEV(ds18b20_major, ds18b20_minor + index);
    
        cdev_init(&dev->cdev, &ds18b20_dev_fops);
        dev->cdev.owner = THIS_MODULE;
        err = cdev_add(&(dev->cdev), devno, 1);
        if (err)
        {
    #ifdef DEBUG
            printk(KERN_NOTICE "ERROR %d add ds18b20
    ", err);
    #endif
        }
    }
    
    /******************************************************************************************************
    ** 函数名称: ds18b20_dev_init()
    ** 函数功能: 为温度传感器分配注册设备号,初始化cdev
    ** 入口参数: 无
    ** 出口参数: 若成功执行,返回0
    ** 备    注:
    ******************************************************************************************************/
    static int __init ds18b20_dev_init(void)
    {
        ds18b20_major = register_chrdev(ds18b20_major, DEVICE_NAME, &ds18b20_dev_fops);
        if (ds18b20_major<0)
        {
        printk(DEVICE_NAME " Can't register major number!
    ");
        return -EIO;
        }
    
        ds18b20_class = class_create(THIS_MODULE, DEVICE_NAME);
        device_create(ds18b20_class, NULL, MKDEV(ds18b20_major, ds18b20_minor), NULL, DEVICE_NAME);
    #ifdef DEBUG
        printk(KERN_WARNING "register ds18b20 driver successful!
    ");
    #endif
        return 0;
    }
    
    /******************************************************************************************************
    ** 函数名称: ds18b20_dev_exit()
    ** 函数功能: 注销设备
    ** 入口参数: 无
    ** 出口参数: 无
    ** 备    注:
    ******************************************************************************************************/
    static void __exit ds18b20_dev_exit(void)
    {
        device_destroy(ds18b20_class, MKDEV(ds18b20_major,ds18b20_minor));
        class_unregister(ds18b20_class);
        class_destroy(ds18b20_class);
        unregister_chrdev(ds18b20_major, DEVICE_NAME);
    #ifdef DEBUG
        printk(KERN_WARNING "Exit ds18b20 driver!
    ");
    #endif
    }
    
    module_init(ds18b20_dev_init);
    module_exit(ds18b20_dev_exit);
    MODULE_LICENSE("Dual BSD/GPL");
    MODULE_AUTHOR("xinli_whut@163.com");
    /******************************************************************************************************
    **                                         文件到此结束
    ******************************************************************************************************/
  • 相关阅读:
    变量与基本数据类型的练习
    04-各数据类型的常用操作
    常用函数
    03-python流程控制
    02-Python输入输出及运算符
    02-补充:逻辑运算符
    线程
    tcp实现并发效果
    生产消费者作业
    作业4.22
  • 原文地址:https://www.cnblogs.com/zlgxzswjy/p/8295222.html
Copyright © 2020-2023  润新知