0
点赞
收藏
分享

微信扫一扫

汽车电子 CIS 学习(二) 之port_driver、proto_driver、vdev_driver注册代码分析

天蓝Sea 2022-03-21 阅读 56



汽车电子 CIS 学习(一) 之 UART PORT

  • ​​二、车机目录介绍​​
  • ​​三、port_driver、proto_driver、vdev_driver注册代码分析​​
  • ​​3.1 cis_register_port_driver 注册代码分析​​
  • ​​3.2 cis_register_proto_driver 注册代码分析​​
  • ​​3.3 cis_attach 绑定代码分析​​
  • ​​3.4 cis_register_vdev_driver 注册代码分析​​
  • ​​3.5 cis_attach 触发绑定的时间​​



在前文 《​​汽车电子 CIS 学习(一) 之 四大结构体​​》 中,主要是对车机CIS 中的四大结构体进行了在概的描述。

二、车机目录介绍

如下是CIS 代码的目录结构,

汽车电子 CIS 学习(二) 之port_driver、proto_driver、vdev_driver注册代码分析_代码分析

  1. 一级目录 /cis/ 在第一级目录中,主要是CIS的架构实现的通用代码,
    主要代码为, cis_core.c , cis_log.c , cis_uart.c , cis_protp,cis_common_proto.c

  2. 二级目录 /cis/vdev 主要是实现具体的通用功能 cis_pa.c,cis_key.c,cis_can.c 等。

  3. 二级目录 /cis/10001h 该目录主要是包括了具体车厂的实现代码。


三、port_driver、proto_driver、vdev_driver注册代码分析

3.1 cis_register_port_driver 注册代码分析

在 port 注册函数中,主要就是将 port_st 的结构体信息赋值给 cis_port_st[index] 全局数组。

后续使用port的时候,就根据该全局数组来进行遍历。

/* port register */
int cis_register_port_driver(struct cis_port_struct *port_st)
{
index = CIS_ARRAY_INDEX_ALIGN(port_st->port_type);
cis_port_st[index].port_type = port_st->port_type;
cis_port_st[index].port_attr = port_st->port_attr;
cis_port_st[index].port_drv = port_st->port_drv;
}



3.2 cis_register_proto_driver 注册代码分析

如同前面的 port 数组一样,proto 也是上将结构体信息保存在 cis_proto_st[index] 全局数组中。

/* protocol register */
int cis_register_proto_driver(struct cis_proto_struct *proto_st)
{
index = CIS_ARRAY_INDEX_ALIGN(proto_st->proto_type);
cis_proto_st[index].proto_type = proto_st->proto_type;
cis_proto_st[index].proto_fmt = proto_st->proto_fmt;
cis_proto_st[index].proto_drv = proto_st->proto_drv;
cis_proto_st[index].proto_send = proto_st->proto_send;
}



3.3 cis_attach 绑定代码分析

attach 的目的,就是将 port 程 proto 关连起来。

我们来看下attach 的代码:

在cis_attach_param 包括,我们当前要注册的 port 和 proto 的相关信息。

//绑定端口和协议
cis_attach(&cis_attach_param);

struct cis_attach_struct cis_attach_param = {
.port_id = CIS_PORT_ID_UART0, // 1
.type.port_type = CIS_PORT_TYPE_UART, // 1
.type.proto_type = CIS_PROTO_TYPE_SGM, // 1
.port_attr = &cis_port_param,
------>
+ struct cis_port_attribute cis_port_param = {
+ .name = "/dev/ttyHSL2", // uart 2
+ .termios = {
+ .c_cflag = B38400, // rate 38400
+ },
+ };
+<-------

};

绑定端口和协议的目的就是,

在全局数组 cis_attach_st[index] 中将 端口port 和协议 proto的属性和方法关连起来,

这样通过 索引 index 就能找到对应的 port 和 proto 所有的信息。



在cis_attach 函数中:

(1) 首先解析到分绑定的 port 和 proto 各自的 index。

(2) 判断该cis_attach_st 全局数组中该 index 的对应的状态,如果已经处于绑定状态则直接返回。

(3) 接下来,经过一系列的检查,检测传递的参数是否正确(包括 type,attr, port_drv,proto_fmt,proto_drv 等等)

(4) 将port 和 proto 的放在 cis_attach_st[index] 全局数组中。

(5)更port 端口的attr 到 cis_attach_st 全局数组中。

(6)调用 proto 的start 函数,正式开始进入正事,在start 函数中会创建一个 kthread线程。

(7)更新全局数组的绑定状态 cis_attach_st[id_index].state = CIS_ATTACH_DONE;

int cis_attach(struct cis_attach_struct *attach_st)
{
id_index = CIS_ARRAY_INDEX_ALIGN(attach_st->port_id); // val - 1 = 1 - 1 =0
port_index = CIS_ARRAY_INDEX_ALIGN(attach_st->type.port_type);
proto_index = CIS_ARRAY_INDEX_ALIGN(attach_st->type.proto_type);

//#5.3 如果已经绑定过了,则直接返回
if (cis_attach_st[id_index].state == CIS_ATTACH_DONE)
return CIS_OK;

//#5.4 判断 port_type 是否是支持的类型: UART | USB
if ((cis_port_st[port_index].port_type == CIS_PORT_TYPE_UART) || (cis_port_st[port_index].port_type == CIS_PORT_TYPE_USB)) {
// 判断该类型的属性 (端口号 及 波特率)
if (!cis_port_st[port_index].port_attr) {
printk(KERN_ERR"ERR:%s port_attr is NULL!\n", __func__);
return CIS_ERR;
}
}
//#5.5 判断该type 的驱动函数
if (!cis_port_st[port_index].port_drv) {
printk(KERN_ERR"ERR:%s port_drv is NULL!\n",__func__);
return CIS_ERR;
}

/* proto */
if (!cis_proto_st[proto_index].proto_fmt) {
printk(KERN_ERR"ERR:%s proto_fmt is NULL!\n",__func__);
return CIS_ERR;
}

if (!cis_proto_st[proto_index].proto_drv) {
printk(KERN_ERR"ERR:%s proto_drv is NULL!\n",__func__);
return CIS_ERR;
}

if (!cis_proto_st[proto_index].proto_send) {
printk(KERN_ERR"ERR:%s proto_send is NULL!\n",__func__);
return CIS_ERR;
}
/* need to handle again */
//#5.6 将所有的参数 都统一存放在 cis_attach_st[] 数组中
// port口 ID / port口 TYPE / 对应的协议 proto TYPE
cis_attach_st[id_index].port_id = attach_st->port_id;
cis_attach_st[id_index].type.port_type = attach_st->type.port_type;
cis_attach_st[id_index].type.proto_type = attach_st->type.proto_type;

// port口 attr / 对应的port口的驱动函数
cis_attach_st[id_index].port_attr = cis_port_st[port_index].port_attr;
cis_attach_st[id_index].port_drv = cis_port_st[port_index].port_drv;

// proteo协议的格式 / 协议的驱动 / 协议 send 函数
cis_attach_st[id_index].proto_fmt = cis_proto_st[proto_index].proto_fmt;
cis_attach_st[id_index].proto_drv = cis_proto_st[proto_index].proto_drv;
cis_attach_st[id_index].vdev_drv.send = cis_proto_st[proto_index].proto_send;


//#5.7 更新attr属性
if ((cis_port_st[port_index].port_type == CIS_PORT_TYPE_UART) || (cis_port_st[port_index].port_type == CIS_PORT_TYPE_USB)) {
cis_update_port_attribute(attach_st);
------>
index = CIS_ARRAY_INDEX_ALIGN(attach_st->port_id);
//#5.8 获得波特率 及 对应的name
//.c_cflag = B38400
cis_attach_st[index].port_attr->termios.c_cflag |= attach_st->port_attr->termios.c_cflag;
//.name = "/dev/ttyHSL2"
memcpy(cis_attach_st[index].port_attr->name, attach_st->port_attr->name, strlen(attach_st->port_attr->name));
<-----
}
if (!cis_attach_st[id_index].proto_drv->start) {
printk(KERN_ERR"ERR:%s proto_start is NULL!\n", __func__);
return CIS_ERR;
}
//#5.8 start attach proto
cis_attach_st[id_index].proto_drv->start(&cis_attach_st[id_index]);
//#5.9 更新状态为 CIS_ATTACH_DONE
cis_attach_st[id_index].state = CIS_ATTACH_DONE;

return CIS_OK;
}



3.4 cis_register_vdev_driver 注册代码分析

前面讲了,虚拟设备其实就是 搭载在 port 端口上 且 使用 该proto 协议的 设备。

因些,注册虚拟设备的前提是 已经有绑定成功的 port 和 proto 。

如下,注册代码中,注册虚拟函数主要就是,

将虚拟设备的 类型vdev_type 和 接收函数vdev_recv 这两个信息 和 cis_attach_st 绑定起来。

这样,当协议proto 的recv 函数接收并解析到数据后,就可能通过 该vdev_recv 函数来将数据传递给对应的 虚拟函数 进行处理。

//# 注册虚拟函数, 将操作函数赋值给cis_attach_st.vdev_drv
/* virtual device register */
int cis_register_vdev_driver(struct cis_vdev_struct *vdev_st)
{
id_index = CIS_ARRAY_INDEX_ALIGN(vdev_st->port_id);
vdev_index = CIS_ARRAY_INDEX_ALIGN(vdev_st->vdev_type);

cis_attach_st[id_index].type.vdev_type[vdev_index] = vdev_st->vdev_type;
cis_attach_st[id_index].vdev_drv.recv[vdev_index] = vdev_st->vdev_recv;
}

3.5 cis_attach 触发绑定的时间

目前代码中,cis_attach 是在 cis_init_task 中调用的:

static DECLARE_WORK(cis_init_work, cis_init_task);

static void cis_init_task(struct work_struct *work)
{
cis_attach(&cis_attach_param);

cis_init_task 是一个work, 名字为 cis_init_work.

接下来,我们来看下 cis_init_work调用的场景。

static int __init cis_io_init(void)
{
if (cis_proc_create())
return CIS_ERR;

schedule_work(&cis_init_work);
return CIS_OK;
}
late_initcall(cis_io_init);

可以看出 触发绑定的时间为 系统开机的过程,初始化时才会触发的。



举报

相关推荐

0 条评论