开篇分割线,驱动开发和应用是完全两条路子,系统里面应用程序想要通过名称或者句柄找到驱动的必要条件就是,驱动已经被注册到了系统里了,那么我们的第一篇就聊聊他是如何被注册到系统里面的,直接上图看下其调用关系:
首先我们看到系统初始化过程中,需要对板载硬件进行初始化,调用rt_hw_board_init,而内部使用大量的预编译宏进行开关控制各个硬件部分是不是需要进行初始化,接下来看下函数rt_hw_usart_init:
int rt_hw_usart_init(void)
{
rt_size_t obj_num = sizeof(uart_obj) / sizeof(struct stm32_uart);
struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
rt_err_t result = 0;
stm32_uart_get_dma_config();
for (int i = 0; i < obj_num; i++)
{
uart_obj[i].config = &uart_config[i];
uart_obj[i].serial.ops = &stm32_uart_ops;
uart_obj[i].serial.config = config;
/* register UART device */
result = rt_hw_serial_register(&uart_obj[i].serial, uart_obj[i].config->name,
RT_DEVICE_FLAG_RDWR
| RT_DEVICE_FLAG_INT_RX
| RT_DEVICE_FLAG_INT_TX
| uart_obj[i].uart_dma_flag
, NULL);
RT_ASSERT(result == RT_EOK);
}
return result;
}
这里我们先不分析代码里面的大部分内容,而是迎来了系统为我们提供的第一个注册函数rt_hw_serial_register,它是你理解注册的第一步接下来我们看下这个函数的原形:
/*
* serial register
*/
rt_err_t rt_hw_serial_register(rt_device_t device, const char* name, rt_uint32_t flag, struct serial_device *serial)
{
RT_ASSERT(device != RT_NULL);
device->type = RT_Device_Class_Char;
device->rx_indicate = RT_NULL;
device->tx_complete = RT_NULL;
device->init = rt_serial_init;
device->open = rt_serial_open;
device->close = rt_serial_close;
device->read = rt_serial_read;
device->write = rt_serial_write;
device->control = rt_serial_control;
device->user_data = serial;
/* register a character device */
return rt_device_register(device, name, RT_DEVICE_FLAG_RDWR | flag);
}
我们注意下它的输入参数,这非常重要,第一个就是一个对象实体(当然C语言中就是一个结构体变量),第二个参数我们得给这个对象起个名字,这样方便我们的应用更好的找到我们的对象,第三个参数是对象的人设(举个例子它可以进行那些操作的合集,比如或者读or写),四个参数则是这个对象的私有数据(user_data,也就是我和别人不一样的点),这个函数的主要任务就是,定义设备的类型:RT_Device_Class_Char,并且设备的动作赋真实可操作的值:初始化/打开/关闭/读/写/控制操作。
最后的最后它需要调用系统提供的rt_device_register完成最终的注册,原型如下:
最后的最后我们倒序的方式回忆一下,设备注册都做了什么:
rt_device_register:设备对象dev 与设备name 建立联系,并赋值挣得操作flag类型。
rt_hw_serial_register:设备对象dev的操作方法具体赋值,私有数据赋值和类型赋值,丰富dev对象,然后调用rt_device_register。
rt_hw_usart_init:传入真实的设备操作方法,比如我们用的是stm32芯片,这里就需要将真实的硬件驱动操作方法,串口配置参数传入到serial结构体中,下一章我们会基于这个API讲讲设备驱动的详细实现细节。