Linux驱动开发(一):字符设备

目的:实现最简单的点灯操作。

Linux一切皆文件,应用程序访问某个物理设备(文件)时,首先通过open, read, write等库函数调用系统调用接口(System call interface),系统调用通过传进来的系统调用号操作虚拟文件系统(Virtual File System),VFS再根据目标文件类型去找相应的驱动程序。
应用程序和VFS之间的接口是系统调用,而VFS与文件系统以及设备文件之间的接口是file_iperations结构体成员函数。
在这里插入图片描述

struct file_operations结构体

Linux通过注册+回调的方式将驱动程序和系统调用联系起来。file_operations 中包含对文件进行打开,关闭,读写,控制等一些成员函数。
具体的成员函数参考:Linux 字符设备驱动结构(四)—— file_operations 结构体知识解析

static struct file_operations led_drv_fops = {
    .owner = THIS_MODULE,
    .open = led_drv_open,
    .write = led_drv_write,
};

驱动加载函数

/* 使用insmod命令安装驱动时会调用此函数 */
int led_drv_init(void){
    int minor = 0;

    GPIOB = (GPIO *)ioremap(GPIOB_BASE, sizeof(GPIO));      // 地址映射

    major = register_chrdev(0, "led_drv", &led_drv_fops);   // 注册驱动, 0表示动态分配主设备号
    leddrv_class = class_create(THIS_MODULE, "led_drv");
    // leddrv_class_dev = class_device_create(leddrv_class, NULL, MKDEV(major, 0), NULL, "led");     // 从3.0开始改为device_create()
    leddrv_dev[minor] = device_create(leddrv_class, NULL, MKDEV(major, 0), NULL, "leds");

    for(minor = 1; minor < 3; minor++){
        leddrv_dev[minor] = device_create(leddrv_class, NULL, MKDEV(major, minor), NULL, "led%d", minor);
    }

    led_init();
    printk("led_drv_init\n");
end:
    return 0;
}

module_init(led_drv_init);
  • ioremap将物理地址映射到内核虚拟地址。
  • register_chrdev注册字符设备。
  • class_create用于动态创建设备的逻辑类。---- linux驱动的类class及其节点
  • device_create用于动态的创建逻辑设备。会在/dev目录下创建与逻辑类对应的设备文件。例如上面的程序创建了/dev/leds/dev/led1/dev/led2。主设备号相同,次设备号分别为012
  • 最后通过宏module_init的修饰,将加载函数链接到.initcall段,方便内核寻找。

驱动卸载函数

void led_drv_exit(void){
    int minor;

    unregister_chrdev(major, "led_drv");   // 卸载驱动

    for(minor = 0; minor < 3; minor++){
        device_unregister(leddrv_dev[minor]);   // 与device_create()对应
    }

    class_destroy(leddrv_class);    // 与class_create()对应
    iounmap(GPIOB);
}

module_exit(led_drv_exit);
  • unregister_chrdev删除字符设备。
  • device_unregister会删除/sys/devices/virtual下对应的设备目录,以及/dev下对应的设备文件。
  • class_destroy删除设备的逻辑类。
  • module_exit修饰。

几个内核结构体

  • struct file代表一个已经打开的文件,系统中的每个打开的文件在内核空间都有一个关联的 struct file。
  • struct inode内核使用inode结构体在内核内部表示一个文件。

更多:Linux 字符设备驱动结构(三)—— file、inode结构体及chardevs数组等相关知识解析

Makefile

KERN_DIR = ~/linux-3.4.y

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
  • KERN_DIR是内核目录,编译模块前要先编译内核。
  • make -C $(KERN_DIR) M=pwdmodules ->解释
  • obj-m表示生成独立的.ko文件,obj-y表示该模块编译到zImage

工程文件

01_LED: first_drv.c

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章