什么是分离分层的概念?
如前面的input子系统所述,分离分层概念可以如下图所示:
input.c和buttons.c,evdev.c形成分层的概念,buttons.c和evdev.c形成分离的概念,一边是硬件相关的代码由编写驱动的人员编写,一边是纯软件是由linux内核所提供的。
总线驱动设备模型:
该模型有三个结构体:
struct bus_type,struct device和struct device_driver。详细的设备模型内容可以参考http://blog.csdn.net/longshan_2009/article/details/10098573
如上图所示:
device_add的作用:
1.把device放入bus的dev链表中
2.从bus的drv链表中取出每一个drv,再使用bus上的match函数判断drv是否支持dev
3.若可以支持,则调用drv的probe函数
driver_register的作用:
1.将driver放入到bus的drv链表中。
2.从bus上的devices链表中取出每一个dev,再使用bus上的match函数判断drv是否支持dev
3.若可以支持,则调用drv的probe函数
综上所述:总线,设备,驱动模型只是一个driver和dev建立链接的一种机制而已。
当一个文件夹中有多个模块文件,就需要将Makefile修改:
obj-m += led_dev.o
obj-m += led_drv.o
led_dev.c
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
static struct resource s3c_led_resource[] = {
[0] = {
.start = 0x7F008830,
.end = 0x7F008830 + 8 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = 1,
.end = 1,
.flags = IORESOURCE_IRQ,//表示led灯接到寄存器的第几个引脚
}
};
void led_release(struct device *dev)
{
}
struct platform_device led_dev = {
.name = "s3c-led",
.id = -1,
.num_resources = ARRAY_SIZE(s3c_led_resource),
.resource = s3c_led_resource,
.dev = {
.release = led_release,//这个函数在rmmod led_dev的时候会使用到,最终调用到led_remove
}
};
static int led_devices_init(void)
{
platform_device_register(&led_dev);
return 0;
}
static void led_devices_exit(void)
{
platform_device_unregister(&led_dev);
}
module_init(led_devices_init);
module_exit(led_devices_exit);
MODULE_LICENSE("GPL");
如果不加release函数的话,在rmmod led_dev的时候出现下面现象:
led_drv.c
#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
static int led_probe(struct platform_device *pdev)
{
printk("Led probe !!!\n");
return 0;
}
static int led_remove(struct platform_device *dev)
{
printk("Led remove !!!\n");
return 0;
}
struct platform_driver led_driver = {
.probe = led_probe,
.remove = led_remove,
.driver = {
.name = "s3c-led",
.owner = THIS_MODULE,
},
};
static int led_driver_init(void)
{
platform_driver_register(&led_driver);
return 0;
}
static void led_driver_exit(void)
{
platform_driver_unregister(&led_driver);
}
module_init(led_driver_init);
module_exit(led_driver_exit);
MODULE_LICENSE("GPL");
具体操作led:
只需要修改led_drv.c即可:
#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <asm/uaccess.h>
#include <linux/device.h>
#include <asm/io.h>
#include <linux/fs.h>
struct class *led_dev_class;
struct device *led_dev;
int major;
static int pin;
static volatile unsigned long *gpiocon;
static volatile unsigned long *gpiodat;
static int led_drv_open(struct inode *inode, struct file *file)
{
//设置gpio为输出引脚
*gpiocon &= ~(0x3 << (pin*4)); //pin为从led_dev.c获取到的resource
*gpiocon |= (0x1 << (pin*4));
return 0;
}
ssize_t led_drv_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos)
{
int val;
copy_from_user(&val,buf,len);
if(val == 1){
//点灯
*gpiodat &= ~(1 << pin );
}else if(val == 0){
//灭灯
*gpiodat |= (1 << pin );
}
return sizeof(buf);
}
static struct file_operations led_drv_fops = {
.owner = THIS_MODULE,
.open = led_drv_open,
.write = led_drv_write,
};
static int led_probe(struct platform_device *pdev)
{
printk("Led probe !!!\n");
struct resource *res ;
res = platform_get_resource(pdev,IORESOURCE_MEM,0); //获取到标志为IORESORCE_MEM的res
gpiocon = ioremap(res->start,res->end - res->start + 1);
gpiodat = gpiocon + 1;
res = platform_get_resource(pdev,IORESOURCE_IRQ,0);
pin = res->start;
major = register_chrdev(0,"led_drv",&led_drv_fops);
led_dev_class = class_create(THIS_MODULE,"led_class");
led_dev = device_create(led_dev_class,NULL,MKDEV(major,0),NULL,"led");
return 0;
}
static int led_remove(struct platform_device *dev)
{
printk("Led remove !!!\n");
device_destroy(led_dev_class,MKDEV(major,0));
class_destroy(led_dev_class);
unregister_chrdev(major,"led_drv");
iounmap(gpiocon);
return 0;
}
struct platform_driver led_driver = {
.probe = led_probe,
.remove = led_remove,
.driver = {
.name = "s3c-led",
.owner = THIS_MODULE,
},
};
static int led_driver_init(void)
{
platform_driver_register(&led_driver);
return 0;
}
static void led_driver_exit(void)
{
platform_driver_unregister(&led_driver);
}
module_init(led_driver_init);
module_exit(led_driver_exit);
MODULE_LICENSE("GPL");
测试程序:
#include <stdio.h>
#include <fcntl.h>
int main(int argc , char **argv)
{
int fd ;
int val;
if(argc < 2){
printf("Usage : %s <on/off> \n",argv[0]);
return -1;
}
if(!strcmp(argv[1],"on")){
val = 1;
}else if(!strcmp(argv[1],"off")){
val = 0;
}
fd = open("/dev/led",O_RDWR); //打开设备节点/dev/led
if(fd < 0){
printf("Can not open devices\n");
return -1;
}
write(fd,&val,4);//向设备节点做写操作
return 0;
}