驱动分为:字符设备驱动,块设备驱动和网络设备驱动。
字符设备驱动是操作字节流,不允许随机访问。
块设备允许随机访问。
字符设备比较基础,下面给出编写字符驱动的方法。
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
MODULE_LICENSE ("GPL");
static int __init hello_2_init (void)
{
printk (KERN_INFO "Hello world\n");
return 0;
}
static void __exit hello_2_exit (void)
{
printk (KERN_INFO "Goodbye world\n");
}
module_init (hello_2_init);
module_exit (hello_2_exit);
最简单的驱动模型:1.加载模块 2.卸载模块 3.许可证声明
以下是典型的字符设备驱动的编写:
#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/cdev.h> MODULE_LICENSE ("GPL"); int hello_major = 250; int hello_minor = 0; int number_of_devices = 1; struct cdev cdev; dev_t dev = 0; struct file_operations hello_fops = { .owner = THIS_MODULE }; static void char_reg_setup_cdev (void) { int error, devno = MKDEV (hello_major, hello_minor); cdev_init (&cdev, &hello_fops); cdev.owner = THIS_MODULE; // cdev.ops = &hello_fops; error = cdev_add (&cdev, devno , 1); if (error) printk (KERN_NOTICE "Error %d adding char_reg_setup_cdev", error); } static int __init hello_2_init (void) { int result; dev = MKDEV (hello_major, hello_minor); result = register_chrdev_region (dev, number_of_devices, "hello"); if (result<0) { printk (KERN_WARNING "hello: can't get major number %d\n", hello_major); return result; } char_reg_setup_cdev (); printk (KERN_INFO "Registered character driver\n"); return 0; } static void __exit hello_2_exit (void) { dev_t devno = MKDEV (hello_major, hello_minor); cdev_del (&cdev); unregister_chrdev_region (devno, number_of_devices); printk (KERN_INFO "char driver cleaned up\n"); } module_init (hello_2_init); module_exit (hello_2_exit);
第一步:在加载函数中首先申请设备
dev = MKDEV (hello_major, hello_minor);
这是个宏函数#define MKDEV(major,minor) (((major) << MINORBITS) | (minor))
返回一个dev_t类型的数据,它是主设备号和此设备号的拼接,内核中定义前12位是主设备号,后20位是次设备号。
第二步:注册设备节点号
result = register_chrdev_region (dev, number_of_devices, "hello");静态申请
alloc_chrdev_region动态创建节点。
第一个参数是链接的设备号,第二个是有几个设备,第三个参数数设备的名称
第三步:注册设备
char_reg_setup_cdev ();
static void char_reg_setup_cdev (void)
{
int error, devno = MKDEV (hello_major, hello_minor);
cdev_init (&cdev, &hello_fops);
cdev.owner = THIS_MODULE;
error = cdev_add (&cdev, devno , 1);
if (error)
printk (KERN_NOTICE "Error %d adding char_reg_setup_cdev", error);
}
首先初始化cdev结构体,初始化结构体的函数里面的第二个参数是一个结构体,在此初始化前
要先把这个结构体填充,然后add来注册设备。
struct file_operations hello_fops = {
.owner = THIS_MODULE
};
file_operations类型里有很多操作,包括read,write等
通过这些操作基本上的功能就会实现。