Linux 驱动开发1: 模块化驱动

最简单的模块

  • hello.c

    #include 
    
    int hello_init(void)
    {
        printk("Hello module init\n");
        return 0;
    }
    
    void hello_exit(void)
    {
        printk("Hello module exit\n");
    }
    
    module_init(hello_init);
    module_exit(hello_exit);
    
    MODULE_LICENSE("GPL");
    
  • Makefile

    KDIR ?= /lib/modules/`uname -r`/build
    
    obj-m += hello.o
    
    module:
        make -C $(KDIR) M=$(PWD) modules
    
    clean:
        make -C $(KDIR) M=$(PWD) clean
    
  • 运行

    $ make
    
    $ sudo insmod hello.ko
    $ lsmod | grep hello
    $ cat /proc/modules | grep hello
    
    $ sudo rmmod hello
    $ dmesg | tail
    

获取主设备号

  • hello.c

    #include 
    #include 
    
    /* 设置主设备号, 0 则由系统创建 */
    static int major = 0;
    
    static int hello_init(void)
    {
        int result;
        dev_t dev = MKDEV(major, 0);
    
        /* 配置主设备号 */
        if(major)
            result = register_chrdev_region(dev, 1, "hello");
        else        
        {
            /* major 为 0 则动态创建 */
            result = alloc_chrdev_region(&dev, 0, 1, "hello");
            major = MAJOR(dev);
        }
    
        if(result < 0)
        {
            printk("register device error\n");
            return result;
        }
    
        printk("register device major %d\n", major);
    
        return 0;
    }
    
    static void hello_exit(void)
    {
        dev_t dev = MKDEV(major, 0);
    
        unregister_chrdev_region(dev, 1);
    
        printk("unregister device major %d\n", major);
    }
    
    module_init(hello_init);
    module_exit(hello_exit);
    
    MODULE_LICENSE("GPL");
    
  • 运行

    $ make 
    $ sudo insmod hello.ko
    $ dmesg | tail 
    $ cat  /proc/devices | grep hello
    
    $ sudo rmmod hello
    $ dmesg | tail 
    $ cat  /proc/devices | grep hello
    

添加字符设备

  • hello.c

    #include 
    #include 
    #include 
    
    /* 填入希望绑定的主设备号, 0 则由系统决定 */
    static int major = 0;
    
    static struct cdev mycdev;
    
    #define MIN(a, b) (((a) < (b)) ? (a) : (b))
    
    static int hello_open(struct inode *node, struct file *file)
    {
        printk("open hello module\n");
    
        return 0;
    }
    
    static ssize_t hello_read(struct file *file, char __user *buf, size_t size, loff_t *ofs)
    {
        int n, m;
        char say[] = "Hello World\n";
        
        if(*ofs >= sizeof(say))
            return 0;
        
        m = MIN(sizeof(say) - *ofs, size);
    
        n = copy_to_user(buf, say + *ofs, m);
        *ofs += m - n;
        
        return m - n;
    }
    
    static struct file_operations fops = {
        .owner = THIS_MODULE,
        .open = hello_open,
        .read = hello_read,
    };
    
    static int hello_init(void)
    {
        int result;
        dev_t dev = MKDEV(major, 0);
    
        /* 配置主设备号 */
        if(major)
            result = register_chrdev_region(dev, 1, "hello");
        else        
        {
            /* major 为 0 则动态创建 */
            result = alloc_chrdev_region(&dev, 0, 1, "hello");
            major = MAJOR(dev);
        }
    
        if(result < 0)
        {
            printk("register device error\n");
            return result;
        }
    
        printk("register device major %d\n", major);
    
        /* 添加字符设备 */
        cdev_init(&mycdev, &fops);
        mycdev.owner = THIS_MODULE;
    
        cdev_add(&mycdev, dev, 1);
    
        return 0;
    }
    
    static void hello_exit(void)
    {
        cdev_del(&mycdev);
    
        unregister_chrdev_region(MKDEV(major, 0), 1);
    
        printk("unregister device major %d\n", major);
    }
    
    module_init(hello_init);
    module_exit(hello_exit);
    
    MODULE_LICENSE("GPL");
    
  • 运行

    
    $ make 
    $ sudo insmod hello.ko
    $ cat  /proc/devices | grep hello
    # 填入获取的主设备号, 这里是 511
    $ sudo mknod /dev/hello c 511 0
    $ cat /dev/hello
    Hello World
    

你可能感兴趣的:(Linux 驱动开发1: 模块化驱动)