首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

FPGA嵌入式系统的Linux设备驱动程序开发

FPGA嵌入式系统的Linux设备驱动程序开发

摘 要:基于FPGA 嵌入式系统,在PowerPC 架构的Linux2.6 操作系统环境下,对通用输入输出接口(GPIO)控制器的驱动,采用平台设备机制进行中断控制管理。通过该管理机制,将GPIO 设备本身的资源注册进内核,由内核统一管理。在参照Linux2.6 内核源码有关平台设备驱动的基础上,编写和测试了GPIO 设备的驱动程序。该驱动程序已在Xilinx 公司FPGA 开发板ML403 上验证,并且稳定运行。
从Linux 2.6 起引入了平台设备机制,即platform device driver 机制,Linux 中大部分设备驱动都可以使用这套机制[1]。和传统的device driver 机制(通过driverregister 函数进行注册)相比,十分明显的优势在于platform 机制将设备本身的资源注册进内核,由内核统一管理,在驱动程序中使用这些资源时通过platform device 提供的标准接口进行申请并使用[2]。这样提高了驱动和资源管理的独立性,并且拥有较好的可移植性和安全性。文中讨论的GPIO 设备具有双重身份:平台设备与混杂设备(miscdevice)。平台设备意味着GPIO控制器设备是属于平台的独立模块;混杂设备(即主设备号为10)是一种特殊的字符型设备,描述了GPIO 控制器的访问方式是顺序的[1]。
1 Linux中平台设备驱动开发流程
ML403 开发板采用vertex-4 系列FPGA,集成了PowerPC405 硬核,带有内核管理单元(MMU),因此可以在该开发板上运行Linux2.6 操作系统。在嵌入式Linux2.6 操作系统中,通过Platform 机制,对外设进行管理。开发设备驱动的流程如图1 所示:


1.1 定义platform_device
在Linux 2.6 内核中platform 设备用结构体platform_device 来描述, 该结构体定义在kernel\include\linux\platform_device.h 中:
struct platform_device {
const char * name; //平台设备的设备名
u32 id; //平台设备的设备ID
struct device dev; //设备结构体
u32 num_resources; //平台设备使用的各类资源数

struct resource * resource; //资源
};

该结构一个重要的元素是resource,它存入了最为重要的设备资源信息。在嵌入式开发工具EDK 中生成BSP( 板级支持包)的时候有一个设备参数头文件xparameter.h,里面定义了相关设备的设备数量、地址资源、中断资源和时钟资源等。在添加平台设备信息的时候需要用到该头文件中定义的地址信息和中断信息,Xilinx 公司的Virtex-4 平台设备是在kernel/arch/ppc/syslib/virtex_devices.c 中定义的,在编写驱动之前,需要在该文件中添加有关GPIO 控制器的设备定义:
/*
* ML300/ML403 Gpio Device: shortcut macro for single instance
*/
#define XPAR_GPIO(num) { \
.name = "xilinx_gpio", \
.id = num, \
.dev.platform_data=XPAR_GPIO_##num##
_IS_DUAL, \
.num_resources = 2, \
.resource = (struct resource[]) { \
{ \
.start=XPAR_GPIO_##num##_B
ASEADDR, \

.end=XPAR_GPIO_##num##_HI
GHADDR, \
.flags = IORESOURCE_MEM, \
}, \
{ \
.start=XPAR_INTC_0_GPIO_##n
um##_VEC_ID, \
.flags = IORESOURCE_IRQ, \
}, \
}, \
}
/* GPIO instances */
#if defined(XPAR_GPIO_0_BASEADDR)
XPAR_GPIO(0),
#endif
#if defined(XPAR_GPIO_1_BASEADDR)
XPAR_GPIO(1),
#endif
#if defined(XPAR_GPIO_2_BASEADDR)
XPAR_GPIO(2),
#endif

上述的代码定义了GPIO 设备名称——xilinx_gpio,XPAR_GPIO 平台设备结构中name 元素和设备
驱动的platform_driver 结构体中的driver.name 必须是相同的。这是因为在平台设备驱动注册时会对所有已注册的platform_device 中的name 和当前注册的platform_driver 的driver.name 进行比较, 使得platfrom_device 和platform_driver 建立关联,只有找到相同的名称的platfomr_device 才能注册成功。在平台设备的描述中GPIO 设备定义了2 个资源,一个是I/O空间资源,描述了GPIO 控制器设备所占用的总线地址范围,IORESOURCE_MEM 表示第1 组描述的是内存类型的资源信息;另一个是中断资源,描述了设备的中断号,IORESOURCE_IRQ 表示第2 组描述的是中断资源信息,设备驱动会根据类型来获取相应的资源信息。本文共用到三个GPIO 设备XPAR_GPIO(0),XPAR_GPIO(1),XPAR_GPIO(2)。

1.2 注册platform_device
virtex_devices.c 中的platform_device 是在系统启动时,使用virtex_init(void)函数进行注册。

同时被注册还有很多virtex 平台的设备,该函数是在系统初始化阶段调用,驱动注册时需要匹配内核中所有已注册的设备名,因此platform_device 设备的注册过程必须在相应设备驱动加载之前被调用。
1.3 定义platform_driver
与平台设备对应的平台设备驱动程序由struct platform_driver 描述:
struct platform_driver {
int (*probe)(struct platform_device *); //探测
int (*remove)(struct platform_device *); //移除
void (*shutdown)(struct platform_device *);//关闭
int (*suspend)(struct platform_device *, pm_
message_t state); //挂起

int (*resume)(struct platform_device *); //恢复
struct device_driver driver;
};

GPIO 的驱动程序中结构体struct platform_driver主要实现了xgpio_driver 的探测和移除函数。代码如下:
static struct platform_driver xgpio_driver = {
.probe = xgpio_probe,
.remove = xgpio_remove,
.driver = {
.name = xilinx_gpio,
.bus = &platform_bus_type,
.owner = THIS_MODULE,
}

1.4 注册platform_driver
最后需要调用platform_driver_register()函数注册平台设备驱动,在注册成功后会调用platform_driver结构元素probe 函数指针,进入probe 函数后,需要获取设备的资源信息。注册平台设备驱动的实现函数如下:
static int __init xgpio_init(void)
{
return platform_driver_register (&xgpio_
driver);
}

2 GPIO控制器设备驱动
Linux 是保护模式的操作系统,内核和应用程序分别运行在完全分离的虚拟地址空间,用户空间的进程一般不能直接访问硬件。设备驱动充当了硬件和应用软件之间的纽带,它与底层硬件直接打交道,按照硬件设备的具体工作方式读写设备寄存器,完成设备的轮询、中断处理、DMA 通信,进行物理内存向虚拟内存的映射,最终使通信设备能收发数据,使显示设备能否显示文字和画面,使存储设备能够记录文件和数据[1]。

2.1 GPIO 控制器的平台设备驱动函数实现
使用platform_driver_register(&xgpio_driver)注册GPIO 设备驱动成功后,利用系统探测函数probe(),获取设备需要的资源信息。在探测函数中,需要通过platform_get_resource()函数分别获得GPIO内存和IRQ资源:
struct resource * platform_get_resource(struct platform_device *dev, unsigned int type, unsigned int num);

根据参数type 所指定的类型,IORESOURCE_MEM 和IORESOURCE_IRQ 来获取指定的资源。
返回列表