首页 > 代码库 > arm-linux学习:最简驱动模块

arm-linux学习:最简驱动模块

内核驱动

linux操作系统支持多种硬件平台和处理器平台,但是每个硬件平台的其它外设是不完全相同的,外设芯片的性能也是在不断提升的,要兼容这些外设硬件,就必须有一个灵活的设备驱动层。

 

驱动分类

是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后数据。字符设备是面向流的设备,常见的字符设备有鼠标、键盘、串口、控制台和LED设备等。字符设备在 /dev/ 目录下会有一个设备文件,例如串口: /dev/ttySAC0 ,应用层使用打开文件写入读取文件等操作来控制外设。

是指可以从设备的任意位置读取一定长度数据的设备。块设备包括硬盘、磁盘、U盘和SD卡等。实际上linux中自带了nand flash驱动,所以我们块设备驱动不作为重点研究。 

最简驱动模块

一个最简单的驱动模块要做以下几件事情

向内核注册模块初始化函数

实现文件操作file_operation结构体,包含几个函数指针 open(),read() 

向内核注册模块的销毁函数

下面是一个具体的代码例子:

#include <linux/module.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/device.h>static int first_drv_open(struct inode * inode,struct file * file)

{

        printk("open!");

        return 0;

}static int first_drv_write(struct file * file,const char __user *buf ,size_t count,loff_t * ppos)

{

        printk("close!");

        return 0;

}

 static struct file_operations first_drv_fops={

        .owner = THIS_MODULE,

        .open  = first_drv_open,

        .write = first_drv_write,

} ;int major;static int my_drv_init(void)

    {

        major=register_chrdev(0,"first_drv",&first_drv_fops);

        printk("module_init\\n");

        return 0;

}static void my_drv_exit(void)

{

        printk("module_exit\\n");

        unregister_chrdev(major,"first_drv");

}

module_init(my_drv_init);

module_exit(my_drv_exit);

MODULE_LICENSE("GPL");

驱动模块编译后的格式为.ko,使用insmod命令将模块插入

insmod my_first_drv.ko

之后在 /proc/devices 中就可以找到这个模块了

cat /proc/devices

proc挂载在/proc目录下,提供操作系统的一些信息如进程信息和内存参数管理等。左侧是设备号,右侧是设备名

但是这个模块还没有一个设备文件,不过可以手动创建,设备文件的主设备号要和/proc/devices 分配的设备号一致

#include <linux/module.h>

#include <linux/kernel.h>

#include <linux/fs.h>

#include <linux/device.h>static struct class * firstdrv_class;static struct class_device *firstdrv_class_dev;static int first_drv_open(struct inode * inode,struct file * file)

{

    printk("open!");

    return 0;

}static int first_drv_write(struct file * file,const char __user *buf ,size_t count,loff_t * ppos)

{

    printk("close!");

    return 0;

}static struct file_operations first_drv_fops={

    .owner = THIS_MODULE,

    .open  = first_drv_open,

    .write = first_drv_write,

} ;int major;static int my_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");

    printk("module_init\\n");

    return 0;

}static void my_drv_exit(void)

{

    printk("module_exit\\n");

    unregister_chrdev(major,"first_drv");

    class_device_unregister(firstdrv_class_dev);

    class_destroy(firstdrv_class);

}

module_init(my_drv_init);

module_exit(my_drv_exit);

MODULE_LICENSE("GPL");

重新insmod模块,可以看到 /etc/XYZ 这个设备文件已经被驱动模块注册好了

文章来源:Joy & Owl

arm-linux学习:最简驱动模块