什么是分离分层的概念?
如前面的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的时候出现下面现象:
#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; }