自学内容网 自学内容网

ftdi_sio驱动学习笔记 5 - 读写操作

目录

1. ftdi_prepare_write_buffer

2. ftdi_process_read_urb


读写相关操作对应的函数:

.process_read_urb =ftdi_process_read_urb,
.prepare_write_buffer =ftdi_prepare_write_buffer,

实际读写并不是ftdi_sio操作的,是通过内核标准的usb serial实现。

1. ftdi_prepare_write_buffer

static int ftdi_prepare_write_buffer(struct usb_serial_port *port,
void *dest, size_t size)

参数dest是目标缓冲区的地址,用于存放准备好的数据。size是该数据的长度。这个函数用于准备一个USB数据包以便通过FTDI芯片发送到串口或其他异步通信端口。这个函数并不是直接发送数据,而是为数据发送做准备。

这个函数是把写入的数据更新到port->write_fifo,但是分2种情况,如果是非SIO的设备,比较简单,直接拷贝就可以了。

count = kfifo_out_locked(&port->write_fifo, dest, size, &port->lock);
port->icount.tx += count;

而对于SIO的设备,需要每个packet的第一个字节特殊处理,该字节的位0为1,位1为0,位2-7为该packet内数据的长度。

unsigned char *buffer = dest;
int i, len, c;

count = 0;
spin_lock_irqsave(&port->lock, flags);
for (i = 0; i < size - 1; i += priv->max_packet_size) {
len = min_t(int, size - i, priv->max_packet_size) - 1;
c = kfifo_out(&port->write_fifo, &buffer[i + 1], len);
if (!c)
break;
port->icount.tx += c;
buffer[i] = (c << 2) + 1;
count += c + 1;
}
spin_unlock_irqrestore(&port->lock, flags);

真正写数据是标准的usb写,所以在ftdi_sio中没有处理。

2. ftdi_process_read_urb

static void ftdi_process_read_urb(struct urb *urb)

当 URB 完成从 FTDI 芯片读取数据后,ftdi_process_read_urb将被调用来解析和处理这些数据。它会检查读取的数据并将其适当地传递给更高层的串行通信协议栈。

数据在urb->transfer_buffer

for (i = 0; i < urb->actual_length; i += priv->max_packet_size) {
len = min_t(int, urb->actual_length - i, priv->max_packet_size);
count += ftdi_process_packet(port, priv, &data[i], len);
}

而tty_flip_buffer_push是通知tty去线路规程获取从串口过来的数据

if (count)
tty_flip_buffer_push(&port->port);

对于ftdi_process_packet,这个函数用于处理FTDI芯片的USB串口数据包。该数据包分3个部分。

  • 第一个字节的处理:
#define FTDI_STATUS_B0_MASK(FTDI_RS0_CTS | FTDI_RS0_DSR | FTDI_RS0_RI | FTDI_RS0_RLSD)

status = buf[0] & FTDI_STATUS_B0_MASK;
if (status != priv->prev_status) {
char diff_status = status ^ priv->prev_status;

if (diff_status & FTDI_RS0_CTS)
port->icount.cts++;
if (diff_status & FTDI_RS0_DSR)
port->icount.dsr++;
if (diff_status & FTDI_RS0_RI)
port->icount.rng++;
if (diff_status & FTDI_RS0_RLSD) {
struct tty_struct *tty;

port->icount.dcd++;
tty = tty_port_tty_get(&port->port);
if (tty)
usb_serial_handle_dcd_change(port, tty,
status & FTDI_RS0_RLSD);
tty_kref_put(tty);
}

wake_up_interruptible(&port->port.delta_msr_wait);
priv->prev_status = status;
}

如果状态发生变化,则根据变化的状态值更新相应的计数器(如CTS、DSR、RI和DCD)。如果RLSD状态发生变化,则进一步处理DCD状态的变化,包括更新计数器和调用处理函数。最后,唤醒等待状态变化的进程,并更新之前的状志值。

  • 第二个字节的处理:
/* save if the transmitter is empty or not */
if (buf[1] & FTDI_RS_TEMT)
priv->transmit_empty = 1;
else
priv->transmit_empty = 0;

if (len == 2)
return 0;/* status only */

检查FTDI设备的发送缓冲区是否为空,并设置相应的状态标志。

#define FTDI_RS_ERR_MASK (FTDI_RS_BI | FTDI_RS_PE | FTDI_RS_FE | FTDI_RS_OE)

if (buf[1] & FTDI_RS_ERR_MASK) {
/*
* Break takes precedence over parity, which takes precedence
* over framing errors. Note that break is only associated
* with the last character in the buffer and only when it's a
* NUL.
*/
if (buf[1] & FTDI_RS_BI && buf[len - 1] == '\0') {
port->icount.brk++;
brkint = true;
}
if (buf[1] & FTDI_RS_PE) {
flag = TTY_PARITY;
port->icount.parity++;
} else if (buf[1] & FTDI_RS_FE) {
flag = TTY_FRAME;
port->icount.frame++;
}
/* Overrun is special, not associated with a char */
if (buf[1] & FTDI_RS_OE) {
port->icount.overrun++;
tty_insert_flip_char(&port->port, 0, TTY_OVERRUN);
}
}

这里是处理串口通信数据错误的。它根据buf[1]中的位来判断出现了哪种错误:break(断路)、parity(奇偶校验错误)、framing(帧错误)或overrun(缓冲区溢出错误)。每种错误都有相应的处理方式,如计数器增加或插入特定字符到缓冲区。其中,break错误仅在最后一个字符为NUL时才被计数。

  • 其他数据
if (brkint || port->sysrq) {
for (i = 2; i < len; i++) {
if (brkint && i == len - 1) {
if (usb_serial_handle_break(port))
return len - 3;
flag = TTY_BREAK;
}
if (usb_serial_handle_sysrq_char(port, buf[i]))
continue;
tty_insert_flip_char(&port->port, buf[i], flag);
}
} else {
tty_insert_flip_string_fixed_flag(&port->port, buf + 2, flag,
len - 2);
}

根据条件处理USB串行端口的数据,并将其插入到tty flip缓冲区中。如果brkintport->sysrq为真,则对每个字符进行特殊处理;否则,直接将数据插入到缓冲区。在特殊处理过程中,如果遇到特定条件,会调用usb_serial_handle_break函数处理中断,或调用usb_serial_handle_sysrq_char函数处理系统请求字符。最终,数据通过tty_insert_flip_char函数插入到缓冲区中。


原文地址:https://blog.csdn.net/pq113_6/article/details/140437775

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!