1 bus-drv-dev模型简介
前面的输入子系统,采用了分层设计,今天就引入驱动设计的分层分离的概念,linux系统中bus-drv-dev模型正是基于这种思想设计的。
总线bus
总线就是处理器与设备之间的一个通道,所有的设备通过总线和处理器连接,是一个虚拟的概念。在linux内核中被抽象为bus_type结构体,在include/linux/device.h文件中定义,代码如下图,其中成员match函数主要用于平台注册device和driver的时候,进行匹配用的。
设备device
device与硬件相关,被抽象为一个结构体。通过调用platform_device_add函数,将device放入到bus的dev链表中;再从bus的drv链表中取出每一个drv,通过bus的match函数判断drv是否支持dev;若支持,则可以调用drv的probe函数。
驱动driver
driver是关于操作硬件设备的稳定的代码,被抽象为一个结构体。同样的道理,调用platform_driver_register将drv放入到bus的drv链表中;在取出dev链表中的dev,通过bus的match函数比较;若有匹配的dev,则可以调用dev的probe函数。
2 编写LED驱动
(1)创建两个驱动文件led_dev.c和led_drv.c文件。
(2)在led_dev.c文件中定义led_device结构体,在入口函数中调用platform_device_register函数注册设备,在出口函数中调用platform_device_unregister函数卸载设备。
-
/* 分配/设置/注册一个platform_device */
-
-
#include <linux/kernel.h>
-
#include <linux/types.h>
-
#include <linux/interrupt.h>
-
#include <linux/list.h>
-
#include <linux/timer.h>
-
#include <linux/init.h>
-
#include <linux/serial_core.h>
-
#include <linux/platform_device.h>
-
-
static struct resource led_resource[] = {
-
[0] = {
-
.start = 0x56000050,
-
.end = 0x56000050 + 8 - 1,
-
.flags = IORESOURCE_MEM,
-
},
-
[1] = {
-
.start = 4,
-
.end = 4,
-
.flags = IORESOURCE_IRQ,
-
}
-
-
};
-
-
static void led_device_release(struct device * pdev)
-
{
-
-
}
-
-
static struct platform_device led_device = {
-
.name = "myled",
-
.id = -1,
-
.num_resources = ARRAY_SIZE(led_resource),
-
.resource = led_resource,
-
.dev = {
-
.release = led_device_release,
-
},
-
};
-
-
int led_dev_init(void)
-
{
-
platform_device_register(&led_device);
-
-
return 0;
-
}
-
-
-
void led_dev_exit()
-
{
-
platform_device_unregister(&led_device);
-
}
-
-
-
module_init(led_dev_init);
-
module_exit(led_dev_exit);
-
-
MODULE_LICENSE("GPL");
-
(3)led_drv.c文件中,首先定义结构体led_drv,主要实现led_drv_probe函数和led_drv_remove函数。在入口处调用platform_driver_register注册driver驱动,出口处调用platform_driver_unregister卸载驱动。
-
-
/* 分配/设置/注册一个platform_drv */
-
-
#include <linux/delay.h>
-
#include <linux/module.h>
-
#include <linux/kernel.h>
-
#include <linux/fs.h>
-
#include <linux/moduleparam.h>
-
#include <linux/interrupt.h>
-
#include <linux/ioport.h>
-
#include <linux/init.h>
-
#include <linux/serio.h>
-
#include <linux/err.h>
-
#include <linux/rcupdate.h>
-
#include <linux/platform_device.h>
-
#include <asm/uaccess.h>
-
#include <asm/irq.h>
-
#include <asm/io.h>
-
#include <asm/arch/regs-gpio.h>
-
#include <asm/hardware.h>
-
-
int major = 0;
-
static struct class *cls;
-
static struct class_device *led_class_dev;
-
volatile unsigned long *gpfcon = NULL;
-
volatile unsigned long *gpfdat = NULL;
-
static int pin;
-
-
static int led_drv_probe(struct platform_device *pdev);
-
static int led_drv_remove(struct platform_device *pdev);
-
-
struct platform_driver led_drv = {
-
.probe = led_drv_probe,
-
.remove = led_drv_remove,
-
.driver = {
-
.name = "myled",
-
}
-
};
-
-
static int led_open(struct inode *inode, struct file *file)
-
{
-
//printk("first_drv_open ");
-
-
/* 配置GPF4、5、6位输出 */
-
*gpfcon &= ~(0x3<<(pin*2));
-
*gpfcon |= (0x1<<(pin*2));
-
return 0;
-
}
-
-
static ssize_t led_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
-
{
-
int val;
-
//printk("first_drv_wrie ");
-
-
copy_from_user(&val, buf, count); //
-
-
if(val == 1)
-
{
-
//亮灯
-
*gpfdat &= ~(1<<pin);
-
}
-
else
-
{
-
//灭灯
-
*gpfdat |= (1<<pin);
-
}
-
return 0;
-
}
-
-
static struct file_operations led_drv_fops = {
-
.owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
-
.open = led_open,
-
.write = led_write,
-
};
-
-
static int led_drv_probe(struct platform_device *pdev)
-
{
-
struct resource *res;
-
-
/* 根据platform_device的资源进行ioremap */
-
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
gpfcon = (volatile unsigned long *)ioremap(res->start, res->end - res->start +1);
-
gpfdat = gpfcon + 1;
-
-
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-
pin = res->start;
-
-
/* 注册一个字符设备 */
-
major = register_chrdev(0, "led", &led_drv_fops);
-
-
cls = class_create(THIS_MODULE, "leddrv");
-
led_class_dev = class_device_create(cls, NULL, MKDEV(major, 0), NULL,"led");
-
-
-
printk("led_drv_probe, found led ");
-
return 0;
-
}
-
-
-
static int led_drv_remove(struct platform_device *pdev)
-
{
-
/* 根据platform_device的资源进行iounmap */
-
-
/* 卸载一个字符设备 */
-
class_device_unregister(led_class_dev);
-
class_destroy(cls);
-
unregister_chrdev(major, "myled");
-
-
iounmap(gpfcon);
-
-
printk("led_drv_remove, remove led ");
-
return 0;
-
}
-
-
int led_drv_init(void)
-
{
-
platform_driver_register(&led_drv);
-
-
return 0;
-
}
-
-
-
void led_drv_exit()
-
{
-
platform_driver_unregister(&led_drv);
-
}
-
-
-
module_init(led_drv_init);
-
module_exit(led_drv_exit);
-
-
MODULE_LICENSE("GPL");