zoukankan      html  css  js  c++  java
  • Linux学习 :字符设备框架

    一.系统功能框架

    U-boot : 启动内核

    linux kernel: 启动应用

    应用: open,read,write 都是通过C库实现,汇编就相当于swi val,引发中断,通过系统调用接口在异常中断调用不同处理函数(VFS)。

    二.字符设备驱动框架

    1.编写驱动:open , read, write 等功能函数的实现:

       static int led_drv_open(struct inode *inode, struct file *file){
          printk("led_drv_open ");
          return 0;

       }

       static int led_drv_write(struct file *file, const char __user *buf, size_t count, loff_t* ppos){
          printk("led_drv_write ");
          return 0;
       }

    2.注册驱动:

      ①构造file_operations结构:  
          static struct file_operation led_drv_fops = {
            .owner = THIS_MODULE,
            .open = led_drv_open,
            .write = led_drv_write,
          }

      ②注册驱动:
        入口函数: 

               int major; 
             int led_drv_init(void){
                major = register_chrdev(0, "led_drv", &led_drv_fops);  //注册字符设备,major-主设备号 mior-次设备号,app根据设备类型和主设备号调用具体驱动。
                //创建设备节点:
                //... class_create(THIS_MODULE, "led_drv");
                //... clase_device_create(...);
                return 0;
             }
        修饰入口函数: module_init(led_drv_init);
        
        出口函数:void led_drv_exit(void){
                unregister_chrdev(major, "led_drv");  
             }
        修饰出口函数: module_exit(led_drv_exit);

      ③编译:

          Makefile :

            KERN_DIR=/work/system/linux-2.6.22.6  //本地编译过的linux源码目录
            all:
                make -C $(KERN_DIR) M=`pwd` modules
            clean:
                make -C $(KERN_DIR) M=`pwd` modules clean
                rm -rf modules.order
            obj-m  += led_drv.o

      ④加载:

          insmod led_drv.ko
          cat /proc/devices

      

    三.參考代碼:

    驱动程序:first_drv.c

    #include <linux/module.h>
    #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 <asm/arch/regs-gpio.h>
    #include <asm/hardware.h>
    
    static struct class *firstdrv_class;
    static struct class_device    *firstdrv_class_dev;
    
    volatile unsigned long *gpfcon = NULL;
    volatile unsigned long *gpfdat = NULL;
    
    
    static int first_drv_open(struct inode *inode, struct file *file)
    {
        //printk("first_drv_open
    ");
        /* 配置GPF4,5,6为输出 */
        *gpfcon &= ~((0x3<<(4*2)) | (0x3<<(5*2)) | (0x3<<(6*2)));
        *gpfcon |= ((0x1<<(4*2)) | (0x1<<(5*2)) | (0x1<<(6*2)));
        return 0;
    }
    
    static ssize_t first_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
    {
        int val;
    
        //printk("first_drv_write
    ");
    
        copy_from_user(&val, buf, count); //    copy_to_user();
    
        if (val == 1)
        {
            // 点灯
            *gpfdat &= ~((1<<4) | (1<<5) | (1<<6));
        }
        else
        {
            // 灭灯
            *gpfdat |= (1<<4) | (1<<5) | (1<<6);
        }
        
        return 0;
    }
    
    static struct file_operations first_drv_fops = {
        .owner  =   THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
        .open   =   first_drv_open,     
        .write    =    first_drv_write,       
    };
    
    
    int major;
    static int first_drv_init(void)
    {
        major = register_chrdev(0, "first_drv", &first_drv_fops); // 注册, 告诉内核
    
        firstdrv_class = class_create(THIS_MODULE, "firstdrv");
    
        firstdrv_class_dev = class_device_create(firstdrv_class, NULL, MKDEV(major, 0), NULL, "xyz"); /* /dev/xyz */
    
        gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);
        gpfdat = gpfcon + 1;
    
        return 0;
    }
    
    static void first_drv_exit(void)
    {
        unregister_chrdev(major, "first_drv"); // 卸载
    
        class_device_unregister(firstdrv_class_dev);
        class_destroy(firstdrv_class);
        iounmap(gpfcon);
    }
    
    module_init(first_drv_init);
    module_exit(first_drv_exit);
    
    
    MODULE_LICENSE("GPL");

    测试程序:firstdrvtest.c

    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <stdio.h>
    
    /* firstdrvtest on
      * firstdrvtest off
      */
    int main(int argc, char **argv)
    {
        int fd;
        int val = 1;
        fd = open("/dev/xyz", O_RDWR);
        if (fd < 0)
        {
            printf("can't open!
    ");
        }
        if (argc != 2)
        {
            printf("Usage :
    ");
            printf("%s <on|off>
    ", argv[0]);
            return 0;
        }
    
        if (strcmp(argv[1], "on") == 0)
        {
            val  = 1;
        }
        else
        {
            val = 0;
        }
        
        write(fd, &val, 4);
        return 0;
    }

    Makefile:

    KERN_DIR = /work/system/linux-2.6.22.6
    
    all:
        make -C $(KERN_DIR) M=`pwd` modules 
    
    clean:
        make -C $(KERN_DIR) M=`pwd` modules clean
        rm -rf modules.order
    
    obj-m    += first_drv.o

     


        


          


            

  • 相关阅读:
    【转】VS2010中 C++创建DLL图解
    [转]error: 'retainCount' is unavailable: not available in automatic reference counting mode
    [转]关于NSAutoreleasePool' is unavailable: not available in automatic reference counting mode的解决方法
    【转】 Tomcat v7.0 Server at localhost was unable to start within 45
    【转】Server Tomcat v7.0 Server at localhost was unable to start within 45 seconds. If
    【转】SVN管理多个项目版本库
    【转】eclipse安装SVN插件的两种方法
    【转】MYSQL启用日志,和查看日志
    【转】Repository has not been enabled to accept revision propchanges
    【转】SVN库的迁移
  • 原文地址:https://www.cnblogs.com/blogs-of-lxl/p/5865613.html
Copyright © 2011-2022 走看看