注意,以下博客为我个人目前的理解,不代表正确,仅作参考。
rtems 4.10.2
Device Driver相关的函数
rtems_configuration_table Configuration = {
....
CONFIGURE_MAXIMUM_DRIVERS, /* maximum device drivers */
....
};
#ifndef CONFIGURE_MAXIMUM_DRIVERS
#define CONFIGURE_MAXIMUM_DRIVERS CONFIGURE_NUMBER_OF_DRIVERS
#endif
#define CONFIGURE_NUMBER_OF_DRIVERS \
((sizeof(Device_drivers) / sizeof(rtems_driver_address_table)))
rtems_driver_address_table Device_drivers[] = {
....
#ifdef CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
CONSOLE_DRIVER_TABLE_ENTRY,
#endif
#ifdef CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
CLOCK_DRIVER_TABLE_ENTRY,
#endif
.....
这里看出,在配置头文件里面,定义了一个结构体数组 Device_drivers 保存的是各个驱动
结构体的入口,每个驱动可以配置。
CONFIGURE_MAXIMUM_DRIVERS 就是计算出这个结构体数组有多少个元素。
这里就是系统的多个驱动可以配置的原理。
然后看这个驱动是怎么被初始化的。
boot_card.c 文件中
void rtems_initialize_data_structures(void)
调用
_IO_Manager_initialization
函数里面设置了这个全局变量,系统配置了多少个驱动,就在这里
number_of_drivers = Configuration.maximum_drivers;
_IO_Number_of_drivers = number_of_drivers;
回到 boot_card 函数 ,执行器件驱动初始化
rtems_initialize_device_drivers();
void _IO_Initialize_all_drivers( void )
for ( major=0 ; major < _IO_Number_of_drivers ; major ++ )
(void) rtems_io_initialize( major, 0, NULL );
根据多少个驱动,分别调用 rtems_io_initialize,注意,这类的多少个驱动的含义是多少类。
例如 console 和 clock 是不同类型。 console 下面可能有多个uart可以绑定。像linux那样。用
major 和 minor 区分
rtems_device_driver_entry callout;
callout = _IO_Driver_address_table[major].initialization_entry;
return callout ? callout(major, minor, argument) : RTEMS_SUCCESSFUL;
很简单,其实就是调用每个驱动已经注册进去的 initialization_entry 函数。
for ( index = 0 ; index < drivers_in_table ; index++ )
_IO_Driver_address_table[index] = driver_table[index];
number_of_drivers = drivers_in_table;
driver_table = Configuration.Device_driver_table;
Device_drivers, 其实最终就是指向这个。
例如console驱动
#define CONSOLE_DRIVER_TABLE_ENTRY \
{ console_initialize, console_open, console_close, \
console_read, console_write, console_control }
可见 console_initialize 就是console的初始化函数,看看他是怎么具体和uart联系起来的。
rtems_device_driver console_initialize(
rtems_device_major_number major,
rtems_device_minor_number minor_arg,
void *arg
)
首先初始化 termios ,生成信号量等。
rtems_termios_initialize();
接着查找存在的
for (minor=0; minor < Console_Port_Count ; minor++) {
/*
* First perform the configuration dependent probe, then the
* device dependent probe
*/
if ((!Console_Port_Tbl[minor].deviceProbe ||
Console_Port_Tbl[minor].deviceProbe(minor)) &&
Console_Port_Tbl[minor].pDeviceFns->deviceProbe(minor)) {
这里的逻辑是
如果deviceProbe 指针不为空,则执行 deviceProbe 初始化,如果失败,则直接退出
如果成功了,还需要执行 pDeviceFns->deviceProbe(minor) 的初始化,如果都成功了
表示console使用这个设备,所以这里的操作其实是 probe,检测设备存在。
/*
* Use this device for the console
*/
break;
}
}
摘要 Console_Port_Tbl 这个其实是用户
console_tbl Console_Port_Tbl[] = {
{
"/dev/com0", /* sDeviceName */
SERIAL_CUSTOM, /* deviceType */
&uart_fns, /* pDeviceFns */
NULL, /* deviceProbe */
...... /* ulIntVector - NOT USED */
}
};
console_fns uart_fns =
{
libchip_serial_default_probe,
uart_first_open,
uart_last_close,
uart_read,
uart_write,
uart_init,
uart_write_polled, /* not used in this driver */
uart_set_attributes,
FALSE /* TRUE if interrupt driven, FALSE if not. */
};
这里看到了,uart_fns 的各种操作函数是嵌在 Console_Port_Tbl 里面的。
如果有多个 uart口,所以 Console_Port_Tbl 里面就有多个乘员。
查找成功了,于是执行操作
Console_Port_Tbl[minor].pDeviceFns->deviceInitialize(Console_Port_Minor);
这里其实就是调用了 uart_init
在这里写 uart的初始化函数就行了。
就这样,console 和 uart 联系起来了,的读写操作,其实都是向uart传递的。
其实还可以用户自己指定驱动
#define CONFIGURE_HAS_OWN_DEVICE_DRIVER_TABLE
#ifdef CONFIGURE_INIT
rtems_driver_address_table Device_drivers[5] = {
CONSOLE_DRIVER_TABLE_ENTRY,
CLOCK_DRIVER_TABLE_ENTRY,
TTY1_DRIVER_TABLE_ENTRY,
TTY2_DRIVER_TABLE_ENTRY,
{NULL, NULL, NULL, NULL, NULL, NULL}
};
#endif
Etual
2012-12-18