platform总线是一种虚拟的总线,相应的设备则为platform_device,而驱动则为platform_driver。Linux 2.6的设备驱动模型中,把I2C、RTC、LCD等都归纳为platform_device。总线将设备和驱动绑定,在系统每注册一个设备的时候,会寻找与之匹配的驱动;相反的,在系统每注册一个驱动的时候,会寻找与之匹配的设备,而匹配由总线完成。

  platform_match函数首先判断是否有id_table,如果有则使用id_table来进行匹配,否则,判断platform_device和platform_driver成员里的name,如果二者的name字段相同则匹配,如果匹配则调用platform_driver的probe函数,其中对资源进行get、ioremap再注册驱动。

LED总线设备驱动模型程序示例:

1.device:主要设置硬件相关资源

/*led_dev.c*/
#include <linux/module.h>
#include <linux/version.h> #include <linux/init.h> #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> /* 分配/设置/注册一个platform_device */ static struct resource led_resource[] = {
[] = {
.start = 0x56000050, //led控制寄存器地址
.end = 0x56000050 + - ,
.flags = IORESOURCE_MEM, //内存资源
},
[] = {
.start = , //设置引脚号
.end = ,
.flags = IORESOURCE_IRQ, //中断资源
}
}; static void led_release(struct device * dev)
{
  //框架需求要设置一个release函数,不然会报错
} static struct platform_device led_dev = {
.name = "myled",
.id = -,
.num_resources = ARRAY_SIZE(led_resource),
.resource = led_resource,
.dev = {
.release = led_release,
},
}; static int led_dev_init(void)
{
platform_device_register(&led_dev); //注册平台设备
return ;
} static void led_dev_exit(void)
{
platform_device_unregister(&led_dev);
} module_init(led_dev_init);
module_exit(led_dev_exit); MODULE_LICENSE("GPL");

2.driver:注册平台驱动,匹配上设备后调用probe函数:获取device资源,分配、设置、注册字符设备,实现对设备的操作函数(open,read,write)

/*led_drv.c*/

/* 分配/设置/注册一个platform_driver */

#include <linux/module.h>
#include <linux/version.h> #include <linux/init.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/sched.h>
#include <linux/pm.h>
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/irq.h>
#include <asm/uaccess.h>
#include <asm/io.h> static int major; static struct class *cls;
static volatile unsigned long *gpio_con;
static volatile unsigned long *gpio_dat;
static int pin; static int led_open(struct inode *inode, struct file *file)
{
//printk("first_drv_open\n");
/* 配置为输出 */
*gpio_con &= ~(0x3<<(pin*));
*gpio_con |= (0x1<<(pin*));
return ;
} static ssize_t led_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{
int val; //printk("first_drv_write\n"); copy_from_user(&val, buf, count); // copy_to_user(); if (val == )
{
// 点灯
*gpio_dat &= ~(<<pin);
}
else
{
// 灭灯
*gpio_dat |= (<<pin);
} return ;
} static struct file_operations led_fops = {
.owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
.open = led_open,
.write = led_write,
}; static int led_probe(struct platform_device *pdev)
{
struct resource *res; /* 根据platform_device的资源进行ioremap */
res = platform_get_resource(pdev, IORESOURCE_MEM, );
gpio_con = ioremap(res->start, res->end - res->start + );
gpio_dat = gpio_con + ; res = platform_get_resource(pdev, IORESOURCE_IRQ, );
pin = res->start; /* 注册字符设备驱动程序 */ printk("led_probe, found led\n"); major = register_chrdev(, "myled", &led_fops);
  //第一个参数指定类的所有者是哪个模块,第二个参数指定类名。
cls = class_create(THIS_MODULE, "myled");
  //第一个参数指定所要创建的设备所从属的类,第二个参数是这个设备的父设备,如果没有就指定为NULL,第三个参数是设备号,第四个参数是供回调使用的数据,第五个参数是设备名字。
class_device_create(cls, NULL, MKDEV(major, ), NULL, "led"); /* 自动创建设备节点/dev/led(也可手动mknod),新版为device_create(...)*/ return ;
} static int led_remove(struct platform_device *pdev)
{
/* 卸载字符设备驱动程序 */
/* iounmap */
printk("led_remove, remove led\n"); class_device_destroy(cls, MKDEV(major, ));
class_destroy(cls);
unregister_chrdev(major, "myled");
iounmap(gpio_con); return ;
} struct platform_driver led_drv = {
.probe = led_probe,
.remove = led_remove,
.driver = {
.name = "myled",
}
}; static int led_drv_init(void)
{
platform_driver_register(&led_drv);
return ;
} static void led_drv_exit(void)
{
platform_driver_unregister(&led_drv);
} module_init(led_drv_init);
module_exit(led_drv_exit); MODULE_LICENSE("GPL");

3.测试应用程序:

/*led_test.c*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h> /* led_test on
* led_test off
*/
int main(int argc, char **argv)
{
int fd;
int val = ;
fd = open("/dev/led", O_RDWR);
if (fd < )
{
printf("can't open!\n");
}
if (argc != )
{
printf("Usage :\n");
printf("%s <on|off>\n", argv[]);
return ;
} if (strcmp(argv[], "on") == )
{
val = ;
}
else
{
val = ;
} write(fd, &val, );
return ;
}

4.Makefile

KERN_DIR = /work/system/linux-2.6.22.6

all:
make -C $(KERN_DIR) M=`pwd` modules clean:
make -C $(KERN_DIR) M=`pwd` modules clean
rm -rf modules.order obj-m += led_drv.o
obj-m += led_dev.o

Linux学习 : 总线-设备-驱动模型的更多相关文章

  1. Linux的总线设备驱动模型

    裸机编写驱动比较自由,按照手册实现其功能即可,每个人写出来都有很大不同: 而Linux中还需要按照Linux的驱动模型来编写,也就是需要按照"模板"来写,写出来的驱动就比较统一. ...

  2. Linux中总线设备驱动模型及平台设备驱动实例

    本文将简要地介绍Linux总线设备驱动模型及其实现方式,并不会过多地涉及其在内核中的具体实现,最后,本文将会以平台总线为例介绍设备和驱动程序的实现过程. 目录: 一.总线设备驱动模型总体介绍及其实现方 ...

  3. Linux I2C总线设备驱动模型分析(ov7740)

    1. 框架1.1 硬件协议简介1.2 驱动框架1.3 bus-drv-dev模型及写程序a. 设备的4种构建方法a.1 定义一个i2c_board_info, 里面有:名字, 设备地址 然后i2c_r ...

  4. usb驱动开发4之总线设备驱动模型

    在上文说usb_init函数,却给我们留下了很多岔路口.这次就来好好聊聊关于总线设备驱动模型.这节只讲理论,不讲其中的函数方法,关于函数方法使用参考其他资料. 总线.设备.驱动对应内核结构体分别为bu ...

  5. 总线设备驱动模型---platform篇

    总线设备驱动模型----驱动篇 http://blog.chinaunix.net/uid-27664726-id-3334923.html http://blog.chinaunix.net/uid ...

  6. 芯灵思SinlinxA33开发板 Linux平台总线设备驱动

    1.什么是platform(平台)总线? 相对于USB.PCI.I2C.SPI等物理总线来说,platform总线是一种虚拟.抽象出来的总线,实际中并不存在这样的总线. 那为什么需要platform总 ...

  7. Linux总线设备驱动模型

    1. Linux2.6内核引入总线.设备.驱动模型来描述各种总线(PCI.USB.I2C.SPI)与外围设备及其驱动之间的关系. 2. 在Linux内核中,总线用bus_type结构来描述,定义于文件 ...

  8. Linux平台总线设备驱动

    1. 平台总线(Platform bus)是linux2.6内核加入的一种虚拟总线,其优势在于采用了总线的模型对设备(没有挂到真实总线的设备)与驱动进行了管理,这样提高了程序的可移植性. 2. 平台总 ...

  9. linux学习--字符设备驱动

    目录 1.字符设备驱动抽象结构 2.设备号及设备节点 2.1 设备号分配与管理 2.2 设备节点的生成 3.打开设备文件 linux驱动有基本的接口进行注册和卸载,这里不再做详细说明,本文主要关注li ...

随机推荐

  1. 启动node程序报错:event.js:183 throw er; // unhandled 'error' event

    启动node程序时,报如下错误:

  2. android -------- ConstraintLayout Group和goneMargin(五)

    前面的文章 ConstraintLayout 介绍 (一) ConstraintLayout约束属性 (二) ConstraintLayout 宽高比和偏移量比(三) ConstraintLayout ...

  3. hammer.js方法总结(只做了一个简单的demo)

    html <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <titl ...

  4. 基于react的记账簿开发

    前言 前端是纯 React,后端通过 axios 库请求服务器获得数据. 源码: https://github.com/hfpp2012/react-accounts-app 项目详解: https: ...

  5. c 语言连续输入字符型数据

    #include<stdio.h> #include<stdlib.h> void Input1(char* &str){ // /* 这种情况下想要逐个输入字符串数组 ...

  6. Android测试(二)——drozer使用

    drozer启动: 1)首先在模拟 器或者安卓设备上开启drozer; 2)然后打开adb,转发端口: adb forward tcp:31415 tcp:31415 3)在电脑上开启drozer: ...

  7. bzoj2342: [Shoi2011]双倍回文 pam

    题解:先建pam,然后在fail树上dfs,从上到下的链如果有当前长度最远回文串的一半,那么更新答案 //#pragma GCC optimize(2) //#pragma GCC optimize( ...

  8. Oracle11g温习-第十九章:审计(audit)

    2013年4月27日 星期六 10:52 1.审计的功能:监控用户在database 的 action (操作) 2.审计分类 1) session :在同一个session,相同的语句只产生一个审计 ...

  9. Git中ssh的使用

    远程仓库前期工作(SSH HEY的使用) 1.1.注册GitHub账号 1.2.创建SSH Key 打开Git Bash后,输入ssh-keygen -t rsa -C "youremail ...

  10. [luogu P1438] 无聊的数列

    [luogu P1438] 无聊的数列 题目背景 无聊的YYB总喜欢搞出一些正常人无法搞出的东西.有一天,无聊的YYB想出了一道无聊的题:无聊的数列...(K峰:这题不是傻X题吗) 题目描述 维护一个 ...