请注意, linux的应用层对字符设备都是采取文件读写的方式,所以说我们的驱动程序也是用的是文件的形式。
我们需要把所有的驱动程序封装到文件的读写形式里面。
1、 static int XXX_open(struct inode *inode, struct file *file) //这个函数是挂载到struct file_operations open里面的。
此函数需要完成对各种引脚或者总线的硬件初始化,中断初始化 等等
2、static ssize_t XXX_write(struct file *file, const char __user *buf, size_t count, loff_t* ppos) //这个函数是挂载到struct file_operations write里面的。
在此函数中 我们可以给引脚赋值。
3. static struct file_operations XXX_XXX_fops = {
.owner = THIS_MODULE,
.open = first_drv_open,
.write = first_drv_write,
}
这个结构体是一个文件的结构我们把前面的读写函数都挂载到这里。
4、XXX_init //这个函数是注册在module_init
这个函数会给设备分配设备号,映射绝对地址给内核的虚拟地址。
在此函数中我们会用到以下的函数:
register_chrdev: Register a major number for character devices.
int register_chrdev ( | unsigned int | major, |
const char * | name, | |
const struct file_operations * | fops); |
Arguments
major
major device number or 0 for dynamic allocation //如果0的话将会自动的分配驱动设备号 如果写入别的数值则会按照数值去分配设备号
name
name of this range of devices //这个驱动设备的名字
fops
-
file operations associated with this devices //这是存入上面的那个文件的结构体
class_create — create a struct class structure //这个结构体只是给class_device_create 用的
class_create(struct module* owner, const char* name) //pointer to the module that is to “own” this struct class (always THIS_MODULE), the name is the name of this range of devices.ioremap(pysical address, length) : give the absolute address of pin address to kernel
class_device_create(firstdrv_class, NULL, MKDEV(major, 0), NULL, "xyz"); 还不是太能理解这个函数 不过他能够自动的返回一个设备。我们可以知道这个设备的设备号。
5. module_init : 这是一个宏,会把XXX_init注册进入内核
6. module_exit: 这是一个宏,会调用XXX_Exit函数把设备从内核卸载。(rmmod 会调用这个函数。)
7.int first_drv_exit(void) 其中会用到的函数:
unregister_chrdev()取消函数的注册
class_device_unregister()卸载设备类型(想当于卸载了此设备)
iounmap()卸载了绝对地址和相对地址之间的关系。
//这个函数必须有 证书许可证
MODULE_LICENSE("GPL"); //MUST BE INCLUDED
关于中断的函数
1.request_irq
Synopsis
int request_irq ( | unsigned int | irq, |
irq_handler_t | handler, | |
unsigned long | irqflags, | |
const char * | devname, | |
void * | dev_id); |
Arguments
irq
Interrupt line to allocate
handler
Function to be called when the IRQ occurs
irqflags
Interrupt type flags
devname
An ascii name for the claiming device
dev_id
A cookie passed back to the handler function
Description
This call allocates interrupt resources and enables the interrupt line and IRQ handling. From the point this call is made your handler function may be invoked. Since your handler function must clear any interrupt the board raises, you must take care both to initialise your hardware and to set up the interrupt handler in the right order.
Dev_id must be globally unique. Normally the address of the device data structure is used as the cookie. Since the handler receives this value it makes sense to use it.
If your interrupt is shared you must pass a non NULL dev_id as this is required when freeing the interrupt.
2. free_irq() normally write in XX_XXX_Close function
3. wait_event_interruptible(button_waitq, ev_press);
static DECLARE_WAIT_QUEUE_HEAD(button_waitq); //这个宏定义了一个事件, 从而从休眠中脱离,程序会直接跳到中断里面,然后执行中断,在中断中ev_press = 1. 当为1的时候XXX_read函数退出休眠可以执行后面的内容,然后请在执行之后ev_press 清0。