platform驱动简介

转:http://blog.csdn.net/gotosola/article/details/7459899

简介:

目的:说白了就是为了将设备与驱动分离,通过platform总线进行连接





废话不多说:

相关结构介绍:

1.platform设备

结构体structplatform_device{

const charname;/*设备名*/

u32 id;/*设备id*/

struct device dev;/*设备*/

u32 num_resource;/*设备所使用各类资源数量*/

struct resource resource;/*资源*/

}

这我现在只想说一个成员constcharname;它表示设备的名称,一会我们介绍platform_driver的时候你会看到它的成员driver也有这个字段,platform总线检查这两个字段如果匹配就将platform设备和驱动关联起来





2.platform驱动

structplatform_driver{

int(*probe)(struct platform_device *);

int(*remove)(struct platform_device *);

structdevice_driver driver;

};

这里主要介绍上述3个成员

probe函数:正如字面意思(探针),platform设备与驱动匹配后会调用此函数,我们对字符设备的注册的工作可以在这里完成


remove函数:对字符设备的注销工作在这里完成

driver:包含两个字段

.name:需要与前面的platform_device中的name段保持一致,才能完成匹配

.owner:一般设置为THIS_MODULE



思考:系统如何完成platform设备和驱动的匹配?

系统为platform总线定义了一个bus_type(总线类型)的实例platform_bus_type,在此结构体中有一个成员函数:

.match,系统就是靠这个函数完成匹配的



驱动编写:

编写platform驱动要完成三方面的工作:

1.platform_device的编写

2.platform_driver的编写

3.设备资源和数据的定义



对于platform_device的编写又有两方法:

(1).BSP板文件中实现定义,在板文件中将platform_device被归纳为一个数组,最终通过platform_add_devices()函数统一注册,这个函数内部其实调用了platform_device_register()单个注册平台设备



例如这里我们要实现一个名为“globalfifo”的设备,我们可以找板文件,对于ok6410来说位于arch/arm/match-s3c64XX/match-smdk6410中,添加如下代码:



编译好内核后在/sysfs中会出现如下节点:

/sys/bus/platform/devices/globalfifo/

/sys/devices/platform/globalfifo/



然后你只需要编写对应的platform_driver驱动程序就可以了。

但是这种方法存在缺点,如果你想要改写platform_device就需要重新修改板文件,换句话说需要重新编译内核





(2)第二种是为platform_device单独编写内核模块然后加载到内核中,在本文最后会以此方式给出一个例子程序,这里就不在多做介绍






platform_device设备资源的定义:

platform驱动习惯上将设备资源单独定义,需要的时候再将其加载到内存中去。

Platform设备资源和数据:

structresource{

resource_size_tstart;

resource_size_tend;

constchar *name;

unsignedlong flags;

structresourceparent,*sibling,*child;

};


对于此结构体通常只关心三个字段

start:资源开始值

end:资源结束值

flags:资源类型


资源类型的定义:

flagsIORESOURCE_MEM的时候,startend表示该platform_device占据的内存的开始地址和结束地址


flagsIORESOURCE_IRQ时,startend表示该platform使用的中断号的开始值和结束值


当然对于resource的定义也有两种方法:

1.在板文件中定义

2.platform_device所处的内核模块代码中编写





(1).在板文件中进行定义:

例如DM9000网卡资源的定义




获取资源:

无论是在板文件中定义还是直接在设备代码中定义,我们在platform_driver中要获取这些资源的方都是一样的:

resouce*platform_get_resouce(

structplatform_device *pdev,

intflags;//资源类型

intnum;//资源数组索引

)



(2)platform_device模块文件中定义,

在本文末尾将给出一个例子程序,这里就不在多做介绍






补充:

我们除了可以定义资源以外还可以定义数据

platform_device成员dev里有一个成员叫做platform_data

这个成员就可以存放数据信息

这里还是以DM9000网卡为例:





同样对于它的定义你仍然可以放到platform_device模块中去




数据的获得:

这个很容以在platform驱动模块中直接从pdev(platform_device变量)中去得

:

struct dm9000_plat_data *pdata = pdev->dev.platform_data;









在本文的最后我们以ok6410下的led程序为例,以第二种方法编写一个platform_led驱动

platform_led_dev.c

#include <linux/module.h> 
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/fs.h> 
#include <asm/uaccess.h> /* copy_to_user,copy_from_user */   
#include <linux/pci.h>   
#include <mach/map.h>   
#include <linux/sched.h> 
#include <linux/gpio.h>     

 

 
struct platform_device *my_led_dev; 
 
static int __init platform_dev_init(void) 

     int ret; 
     
//分配一个 platform_device结构体
my_led_dev = platform_device_alloc("platform_led", -1);
     
    ret = platform_device_add(my_led_dev);//将自定义的设备添加到内核设备架构中
     
    if(ret) 
        platform_device_put(my_led_dev);//销毁platform设备结构 
     
    return ret; 

 
static void __exit platform_dev_exit(void) 

    platform_device_unregister(my_led_dev);//注销platform_device

 
module_init(platform_dev_init); 
module_exit(platform_dev_exit); 
 
MODULE_AUTHOR("Sola"); 
MODULE_LICENSE("GPL"); 




platform_led_drv.c
//platform driver 
#include <linux/module.h> 
#include <linux/types.h> 
#include <linux/uaccess.h>
#include <linux/miscdevice.h> 
#include <linux/fs.h> 
#include <linux/init.h> 
#include <linux/platform_device.h>
#include <linux/pci.h>   
#include <mach/map.h>   
#include <mach/regs-gpio.h>   
#include <mach/gpio-bank-m.h>   
#include <plat/gpio-cfg.h>    
#define LED_MAJOR 240

 
static int s3c6410_led_open(struct inode *inode, struct file *file) 

   unsigned tmp;    
          tmp = readl(S3C64XX_GPMCON);    
     tmp = (tmp & ~(0xFFFF))|(0x1111U);      
          writel(tmp, S3C64XX_GPMCON);  
     printk("#########open######\n"); 
     return 0; 

 
 
static int s3c6410_led_close(struct inode *inode, struct file *file)

    printk("#########release######\n"); 
    return 0; 

 
 
static int s3c6410_led_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)

     printk("#########read######\n"); 
     return count; 


static int s3c6410_led_write (struct file *filp, const char __user *buf, size_t count,loff_t *f_pos)

     char wbuf[10]; 
     unsigned tmp;    
     printk("#########write######\n"); 
     copy_from_user(wbuf,buf,count);
  if(wbuf[0]==1)//1号灯亮
     switch(wbuf[1]) 
     { 
         case 0:  //off 
             tmp = readl(S3C64XX_GPMDAT);    
                           tmp |= (0x1U);    
                           writel(tmp, S3C64XX_GPMDAT); 
             break; 
         case 1:  //on 
             tmp = readl(S3C64XX_GPMDAT);    
                           tmp &= ~(0x1U);    
                           writel(tmp, S3C64XX_GPMDAT); 
             break; 
         default : 
             break; 
     }      
 
  if(wbuf[0]==2)//2号灯亮
     switch(wbuf[1]) 
     { 
         case 0:  //off 
             tmp = readl(S3C64XX_GPMDAT);    
                           tmp |= (0x2U);    
                           writel(tmp, S3C64XX_GPMDAT); 
             break; 
         case 1:  //on 
             tmp = readl(S3C64XX_GPMDAT);    
                           tmp &= ~(0x2U);    
                           writel(tmp, S3C64XX_GPMDAT); 
             break; 
         default : 
             break; 
     } 
 
  if(wbuf[0]==3)//3号灯亮
     switch(wbuf[1]) 
     { 
         case 0:  //off 
             tmp = readl(S3C64XX_GPMDAT);    
                           tmp |= (0x4U);    
                           writel(tmp, S3C64XX_GPMDAT); 
             break; 
         case 1:  //on 
             tmp = readl(S3C64XX_GPMDAT);    
                           tmp &= ~(0x4U);    
                           writel(tmp, S3C64XX_GPMDAT); 
             break; 
         default : 
             break; 
     } 
 
  if(wbuf[0]==4)//4号灯亮
     switch(wbuf[1]) 
     { 
         case 0:  //off 
             tmp = readl(S3C64XX_GPMDAT);    
                           tmp |= (0x8U);    
                           writel(tmp, S3C64XX_GPMDAT); 
             break; 
         case 1:  //on 
             tmp = readl(S3C64XX_GPMDAT);    
                           tmp &= ~(0x8U);    
                           writel(tmp, S3C64XX_GPMDAT); 
             break; 
         default : 
             break; 
     } 
     return count; 

 
 
static struct file_operations led_fops = { 
    .owner   =   THIS_MODULE, 
    .open    =   s3c6410_led_open, 
    .release =   s3c6410_led_close,  
    .read    =   s3c6410_led_read,
.write   =   s3c6410_led_write,
}; 

 
 
static int my_plat_probe(struct platform_device *dev) 

    int rc;
printk("Test platform_led dev\n");
//注册设备
rc = register_chrdev(LED_MAJOR,"platform_led",&led_fops);

  if (rc <0) 
     { 
         printk ("register %s char dev error\n","led"); 
         return -1; 
     } 
     printk ("ok!\n"); 
     return 0;   

 
static int my_plat_remove(struct platform_device *dev) 

    printk("my platfrom device has removed.\n");  
    return 0; 

 
struct platform_driver my_led_drv = {  
    .probe = my_plat_probe, 
    .remove = my_plat_remove, 
    .driver = {  
        .owner = THIS_MODULE, 
        .name = "platform_led", 
    }, 
}; 
 
static int __init platform_drv_init(void) 

    int ret; 
 
    ret = platform_driver_register(&my_led_drv); 
     
    return ret; 

 
static void __exit platform_drv_exit(void) 

    platform_driver_unregister(&my_led_drv); 

 
module_init(platform_drv_init); 
module_exit(platform_drv_exit); 
 
MODULE_AUTHOR("Sola"); 
MODULE_LICENSE("GPL"); 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值