当前位置: 首页 > 工具软件 > RTEMS > 使用案例 >

rtems 驱动机制初探

司马自明
2023-12-01

注意,以下博客为我个人目前的理解,不代表正确,仅作参考。

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

 类似资料: