0
点赞
收藏
分享

微信扫一扫

汽车电子 CIS 学习(三) 之 UART PORT代码分析

芝婵 2022-03-21 阅读 54



汽车电子 CIS 学习(三) 之 UART PORT代码分析

  • ​​四、Uart Port 代码分析​​
  • ​​4.1 Uart Port 初始化​​
  • ​​4.2 打开函数cis_uart_open​​
  • ​​4.3 关闭函数cis_uart_close​​
  • ​​4.4 写函数cis_uart_write​​
  • ​​4.5 读函数cis_uart_read​​




之所以是Uart Port 的原因,是因为我们车机中的MCU 和车机是通过UART 来通信的。


CIS 架构是为MCU 在车机上虚拟化所搭建的,


所以,软件上车机和MCU 通信,必须通过CIS 架构中 uart port 的read 或者 write。

接下来,我们主要是分析下 uart port 做的一些工作。

四、Uart Port 代码分析

4.1 Uart Port 初始化

在 init 初始化函数中,主要是调用 cis_register_port_driver 注册 uart port 端口。

static int __init cis_uart_init(void)
{
cis_register_port_driver(&cis_uart_port);
return CIS_OK;
}

late_initcall(cis_uart_init);



cis_uart_port 定义如下:

cis_uart_attr 中主要是对 uart 的一些配置信息。

cis_uart_drv 中主要是包括了节点的读写打开关闭操作函数。

struct cis_port_attribute cis_uart_attr = {
.termios = {
.c_cflag = CREAD | HUPCL | CLOCAL | CS8, //控制模式标志
// CREAD:启用字符接收器;
// HUPCL: 关闭时挂断调制解调器;
// CLOCAL: 忽略所有调制解调器的状态行
// CS8 : 8bit
.c_iflag = IGNBRK | IGNPAR, //输入模式标志
// IGNBRK:忽略BREAK键输入
// IGNPAR: 忽略输入行中的中止状态
.c_oflag = 0, //输出模式标志
.c_lflag = 0, //本地模式标志
.c_cc[VTIME] = 10,
.c_cc[VMIN] = 1,
//设置MIN值,read调用将一直等待,
//直到有MIN个字符可读的时候才返回,返回是读取的字符数量。
//到达文件结尾的时候返回0
},
};

struct cis_port_driver cis_uart_drv = {
.open = cis_uart_open,
.read = cis_uart_read,
.write = cis_uart_write,
.close = cis_uart_close,
};

struct cis_port_struct cis_uart_port = {
.port_type = CIS_PORT_TYPE_UART,
.port_attr = &cis_uart_attr,
.port_drv = &cis_uart_drv,
};



4.2 打开函数cis_uart_open

static struct file g_cis_file;
static struct file *filp;

static struct file_operations g_cis_fop;
static struct file_operations cis_tty_fops;
static struct file_operations *fops;

static int cis_uart_open(struct cis_port_attribute *port_attr)
{
struct tty_struct *tty;
mm_segment_t fs;
//(1) 初始化默认的tty操作函数结构体
tty_default_fops(&cis_tty_fops);
//(2)获取设备的端口号
num = sscanf(port_attr->name, "/dev/ttyHSL%d", &line);

filp = &g_cis_file;
filp->f_op = &g_cis_fop;
filp->f_path.dentry = &dentry;

inodep = &g_cis_inode;
inodep->i_rdev = MKDEV(SERIAL_IMX_MAJOR, MINOR_START) + line; // major:207 minor:5

fops = &cis_tty_fops;
ret = fops->open(inodep, filp); //打开节点

fs = get_fs();
set_fs(KERNEL_DS);

if(fops->unlocked_ioctl(filp, TIOCGETD, (long)&old_ldisc) < 0){
printk(KERN_ERR"ERR:filp->f_op->unlocked_ioctl!\n");
} else {
printk("Old ldisc is %d\n", old_ldisc);
}

if(fops->unlocked_ioctl(filp, TIOCSETD, (long)&ldisc) < 0){
printk(KERN_ERR"ERR:filp->f_op->unlocked_ioctl!\n");
}
set_fs(fs);
tty = ((struct tty_file_private *)filp->private_data)->tty;
if (!tty) {
printk(KERN_ERR "tty is null");
fops->release(inodep, filp);
return ret;
}

/* set uart port attribute */
//memcpy(&tty->termios, &port_attr->termios, sizeof(struct ktermios));
//(3)配置串口
tty_set_termios(tty, &(port_attr->termios));

printk(KERN_INFO"%s open %s successful...\n",
__func__, port_attr->name);

return ret;
}

在上述代码中

(1) 初始化默认的tty操作函数结构体 tty_default_fops(&cis_tty_fops);

tty_default_fops(&cis_tty_fops);
==========>
void tty_default_fops(struct file_operations *fops)
{
*fops = tty_fops;
}

struct file_operations {
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
int (*iterate) (struct file *, struct dir_context *);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
int (*flush) (struct file *, fl_owner_t id);
int (*release) (struct inode *, struct file *);
int (*fsync) (struct file *, loff_t, loff_t, int datasync);
int (*aio_fsync) (struct kiocb *, int datasync);
int (*fasync) (int, struct file *, int);
int (*lock) (struct file *, int, struct file_lock *);
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
int (*check_flags)(int);
int (*flock) (struct file *, int, struct file_lock *);
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
int (*setlease)(struct file *, long, struct file_lock **, void **);
long (*fallocate)(struct file *file, int mode, loff_t offset, loff_t len);
int (*show_fdinfo)(struct seq_file *m, struct file *f);
};

(3)配置串口 tty_set_termios

/**
* tty_set_termios - update termios values
* @tty: tty to update
* @new_termios: desired new value
*
* Perform updates to the termios values set on this terminal. There
* is a bit of layering violation here with n_tty in terms of the
* internal knowledge of this function.
*
* Locking: termios_rwsem
*/

int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
{
/*
* Perform the actual termios internal changes under lock.
*/
/* FIXME: we need to decide on some locking/ordering semantics
for the set_termios notification eventually */
old_termios = tty->termios;
tty->termios = *new_termios;

/* See if packet mode change of state. */
if (tty->link && tty->link->packet) {
int extproc = (old_termios.c_lflag & EXTPROC) |
(tty->termios.c_lflag & EXTPROC);
int old_flow = ((old_termios.c_iflag & IXON) &&
(old_termios.c_cc[VSTOP] == '\023') &&
(old_termios.c_cc[VSTART] == '\021'));
int new_flow = (I_IXON(tty) &&
STOP_CHAR(tty) == '\023' &&
START_CHAR(tty) == '\021');
if ((old_flow != new_flow) || extproc) {
spin_lock_irqsave(&tty->ctrl_lock, flags);
if (old_flow != new_flow) {
tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
if (new_flow)
tty->ctrl_status |= TIOCPKT_DOSTOP;
else
tty->ctrl_status |= TIOCPKT_NOSTOP;
}
if (extproc)
tty->ctrl_status |= TIOCPKT_IOCTL;
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
wake_up_interruptible(&tty->link->read_wait);
}
}

if (tty->ops->set_termios)
(*tty->ops->set_termios)(tty, &old_termios);
else
tty_termios_copy_hw(&tty->termios, &old_termios);

ld = tty_ldisc_ref(tty);
if (ld != NULL) {
if (ld->ops->set_termios)
(ld->ops->set_termios)(tty, &old_termios);
tty_ldisc_deref(ld);
}
up_write(&tty->termios_rwsem);
return 0;
}
EXPORT_SYMBOL_GPL(tty_set_termios);



4.3 关闭函数cis_uart_close

在关闭函数中,主要是对文件进行关闭。

void cis_uart_close(struct cis_port_attribute *port_attr)
{
mm_segment_t fs;

fs = get_fs();
set_fs(KERNEL_DS);

if(fops->unlocked_ioctl(&g_cis_file, TIOCSETD, (long)&old_ldisc) < 0){
printk(KERN_ERR"ERR:filp->f_op->unlocked_ioctl!\n");
}
set_fs(fs);

(void)filp_close(&g_cis_file, current->files);

return;
}



4.4 写函数cis_uart_write

在cis_uart_write 中主要是调用 cis_tty_write_data函数来发关数据的。

int cis_uart_write(struct cis_port_attribute *port_attr, unsigned char *data, unsigned char len)
{
wr_num = cis_tty_write_data(data, len);
return wr_num;
}

cis_tty_write_data 函数的参数为 要发送的数据 和 数据的长度,如下:

ssize_t cis_tty_write_data(const unsigned char *buf, size_t nr)
{
struct cis_uart *cu = gcu;
struct tty_struct *tty = cu->tty;
const unsigned char *b = buf;
DECLARE_WAITQUEUE(wait, current); // 创建一个等待队列 wait
int c;
ssize_t retval = 0;

add_wait_queue(&cu->write_wait, &wait); // 将write_wait 放入等待队列中
while (1) {
set_current_state(TASK_INTERRUPTIBLE); // 将当前队列设置为任务可被中断唤醒
while (nr > 0) {
c = tty->ops->write(tty, b, nr); // 调用tty 字符设备的write 函数
if (c < 0) {
retval = c;
goto break_out;
}
if (!c)
break;
b += c;
nr -= c;
}
if (!nr)
break;
schedule(); // 触发调度, 避免因为写数据占用CPU资源,导致一些更加重要的工作没法运行
}
break_out:
__set_current_state(TASK_RUNNING); // 将当前进程设置为运行状态
remove_wait_queue(&cu->write_wait, &wait); // 将write_wait 从wait 等待队列中移除

return (b - buf) ? b - buf : retval;
}



4.5 读函数cis_uart_read

ssize_t cis_tty_read_data(unsigned char *buf, size_t nr)
{
struct cis_uart *cu = gcu;
unsigned char *b = buf;
DECLARE_WAITQUEUE(wait, current); // 创建一个等待队列 wait

add_wait_queue(&cu->read_wait, &wait); //将当前 read_wait 队列加入 等待wait 中
while (nr) {
if (cis_force_exit)
break;
/* This statement must be first before checking for input
so that any interrupt will set the state back to TASK_RUNNING. */
set_current_state(TASK_INTERRUPTIBLE); // 将当前队列设置为可中断

if (!cis_input_available_p(cu, 0)) {
=====================>
//不断的判断串口是否有收到数据,如果正常收到数据(且数据 != 0x1C),则开如读取数据,否则继续休眠
if (cu->read_cnt >= (amt ? amt : 1)) {
while (count < cu->read_cnt) {
pos = cu->read_tail + count++;
pos &= (CIS_TTY_BUF_SIZE - 1);
if (cu->read_buf[pos] == 0x1C)
return 1;
}
}
<=====================
//trace10_num++;
timeout = schedule_timeout(timeout);
//trace11_num++;
continue;
}
__set_current_state(TASK_RUNNING);

/* The copy function takes the read lock and handles
locking internally for this case */

uncopied = cis_copy_from_read_buf(cu, &b, &nr);
if (uncopied)
uncopied = cis_copy_from_read_buf(cu, &b, &nr);

if (uncopied) {
retval = -EFAULT;
}
break;
}
remove_wait_queue(&cu->read_wait, &wait);
__set_current_state(TASK_RUNNING);
if(!retval)
retval = b - buf;
return retval;
}




举报

相关推荐

0 条评论