您的位置:首页 > 其它

platform设备驱动简介

2013-07-08 21:19 225 查看
简介:
目的:说白了就是为了将设备与驱动分离,通过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:资源类型

资源类型的定义:
当flags为IORESOURCE_MEM的时候,start、end表示该platform_device占据的内存的开始地址和结束地址

当flags为IORESOURCE_IRQ时,start、end表示该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");
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: