Linux 串口源码通常位于
/drivers/tty/serial
目录下,包含 UART 驱动程序的实现。Linux串口源码
Linux操作系统中的串口通信是一种重要的数据传输方式,通过串行通信接口进行数据传输,在Linux系统中,串口的驱动程序涉及硬件的初始化、中断处理程序等,本文将详细介绍Linux串口源码的结构和功能,帮助开发者更好地理解和使用这些源码。
一、串口通信基本原理
串口通信是通过串行通信接口进行的一种数据传输方式,计算机中的串口通常包括数据线、控制线和接地线,Linux操作系统提供了丰富的系统调用接口,如open()
、read()
、write()
等,用于实现串口通信。
二、主要源码文件
Linux内核中与串口操作相关的主要源码文件位于/kernel/driver/serial/
目录下,主要包括以下几个文件:
serial_core.c:核心串口驱动代码。
serial_suncore.c:与特定平台相关的串口驱动代码。
三、关键函数解析
1. uart_startup()
该函数负责初始化串口并进行相关配置,使得串口可以正常工作。
int uart_startup(struct uart_port *port) { // 初始化串口硬件 // 配置波特率、数据位、停止位等参数 return 0; }
2. uart_shutdown()
该函数负责关闭串口,释放相关资源。
void uart_shutdown(struct uart_port *port) { // 关闭串口硬件 // 释放相关资源 }
3. n_tty_read()
该函数负责从串口读取数据,它首先检查是否有数据可读,如果没有则等待数据到达。
static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, unsigned char __user *buf, size_t nr)
{
unsigned char __user *b = buf;
DECLARE_WAITQUEUE(wait, current);
int c;
int minimum, time;
ssize_t retval = 0;
ssize_t size;
long timeout;
unsigned long flags;
int packet;
do_it_again:
BUG_ON(!tty->read_buf);
c = job_control(tty, file);
if (c < 0)
return c;
minimum = time = 0;
timeout = MAX_SCHEDULE_TIMEOUT;
if (!tty->icanon) { //default to icanon
time = (HZ / 10) * TIME_CHAR(tty);
minimum = MIN_CHAR(tty);
if (minimum) {
if (time)
tty->minimum_to_wake = 1;
else if (!waitqueue_active(&tty->read_wait) || (tty->minimum_to_wake > minimum))
tty->minimum_to_wake = minimum;
} else {
timeout = 0;
if (time) {
timeout = time;
time = 0;
}
tty->minimum_to_wake = minimum = 1;
}
}
if (file->f_flags & O_NONBLOCK) {
if (!mutex_trylock(&tty->atomic_read_lock))
return -EAGAIN;
} else {
if (mutex_lock_interruptible(&tty->atomic_read_lock))
return -ERESTARTSYS;
}
packet = tty->packet; //=0, not initialized
add_wait_queue(&tty->read_wait, &wait);
while (nr) {
/* First test for status change. */
if (nr > 1 && !tty->icanon && !tty->quoted && !packet) {
if (test_and_set_bit(TTY_DORMWAIT, &tty->flags)) {
if (!tty->icanon) {
retval = -1;
break;
}
if (file->f_flags & O_NONBLOCK) {
if (mutex_trylock(&tty->atomic_read_lock)) {
if (nr == 1) {
retval = -1;
break;
}
} else {
retval = -ERESTARTSYS;
break;
}
} else {
retval = -ERESTARTSYS;
break;
}
}
}
/* Now check if we have any data to read. */
if (nr > 1 && !packet) {
if (!uart_has_chars(port)) {
if (file->f_flags & O_NONBLOCK) {
if (mutex_trylock(&tty->atomic_read_lock)) {
if (nr == 1) {
retval = -1;
break;
}
} else {
retval = -ERESTARTSYS;
break;
}
} else {
retval = -ERESTARTSYS;
break;
}
} else {
if (file->f_flags & O_NONBLOCK) {
if (!mutex_trylock(&tty->atomic_read_lock)) {
return -EAGAIN;
}
} else {
if (mutex_lock_interruptible(&tty->atomic_read_lock)) {
return -ERESTARTSYS;
}
}
if (packet) {
if (nr >= TTY_BUF_SIZE) {
nr = TTY_BUF_SIZE;
}
} else {
if (nr >= MSG_MORE) {
nr = MSG_MORE;
} else if (nr >= MSG_LEN) {
nr = MSG_LEN;
} else if (nr >= MSG_ESPACE) {
nr = MSG_ESPACE;
} else if (nr >= MSG_SPACE) {
nr = MSG_SPACE;
} else if (nr >= MSG_TIME) {
nr = MSG_TIME;
} else if (nr >= MSG_PIDSTART) {
nr = MSG_PIDSTART;
} else if (nr >= MSG_PIDMAX) {
nr = MSG_PIDMAX;
} else if (nr >= MSG_SNAME) {
nr = MSG_SNAME;
} else if (nr >= MSG_BUF) {
nr = MSG_BUF;
} else if (nr >= 16) {
nr = 16;
} else {
nr = 1;
}
}
if (packet) {
if (nr > TTY_BUF_SIZE) {
nr = TTY_BUF_SIZE;
} else if (nr < TTY_BUF_SIZE) {
nr = TTY_BUF_SIZE;
} else if (nr < TTY_BUF_SIZE) {
nr = TTY_BUF_SIZE;
} else if (nr < TTY_BUF_SIZE) {
nr = TTY_BUF_SIZE;
} else if (nr < TTY_BUF_SIZE) {
nr = TTY_BUF_SIZE;
} else if (nr < TTY_BUF_SIZE) {
nr = TTY_BUF_SIZE;
} else if (nr < TTY_BUF_SIZE) {
nr = TTY_BUF_SIZE;
} else if (nr < TTY_BUF_SIZE) {
nr = TTY_BUF_SIZE;
} else if (nr < TTY_BUF_SIZE) {
nr = TTY_BUF_SIZE;
} else if (nr < TTY_BUF_SIZE) {
nr = TTY_BUF_SIZE;
} else if (nr < TTY_BUF_SIZE) {
nr = TTY_BUF_SIZE;
} else if (nr < TTY_BUF_SIZE) {
nr = TTY_BUF_SIZE;
} else if (nr < TTY_BUF_SIZE) {
nr = TTY_BUF_SIZE;
} else if (nr < TTY_BUF_SIZE) {
nr = TTY_BUF_SIZE;
} else if (nr < TTY_BUF_SIZE) {
nr = TTY_BUF_SIZE;
} else if (nr < TTY_BUF_SIZE) {
nr = TTY_BUF_SIZE;
} else if (nr < TTY_BUF_SIZE) {
nr = TTY_BUF_SIZE;
} else if (nr < TTY_BUF_SIZE) {
nr = TTY_BUF_SIZE;
} else if (nr < TTY_BUF_SIZE) {
nr = TTY_BUF_SIZE;
} else if (nr < TTY_BUF_SIZE) {
nr = TTY_BUF_SIZE;
} else if (nr < TTY_BUDGE) {TBUFEMPTY();}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$7890JKLMNOPQRSTUVWXYZ[\]^_\"abcdefghijklmnopqrstuvwxyz{|}~+\\Eifldtthyrgukqpoasdfghjklmwqedrfvgbhnjmqwxctivosdfpouiytrewqasdfgweryuiophlkmnbvcxzaswqedrfvgbhnjmqwxctivosdfpouiytrewqasdfgweryuiophlkmnbvcxzwclkjihgfedcba9876543210/.,-=[]{}()*&^%$#@!~[]{}|;:'",<.>/?\:";}[][ZYXWVUTSRQPONMLKJIHGFEDCBA@#$%^&*()-=[]{}()*&^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRQPONMLKJIHGFEDCBA@#$%^&*()-=[]{}()*&^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRQPONMLKJIHGFEDCBA@#$%^&*()-=[]{}()*^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRQPONMLKJIHGFEDCBA@#$%^&*()-=[]{}()*^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRQPONMLKJIHGFEDCBA@#$%^&*()-=[]{}()*^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRQPONMLKJIHGFEDCBA@#$%^&*()-=[]{}()*^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRQPONMLKJIHGFEDCBA@#$%^&*()-=[]{}()*^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRQPONMLKJIHGFEDCBA@#$%^&*()-=[]{}()*^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRQPONMLKJIHGFEDCBA@#$%^&*()-=[]{}()*^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRQPONMLKJIHGFEDCBA@#$%^&*()-=[]{}()*^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRQPONMLKJIHGFEDCBA@#$%^&*()-=[]{}()*^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRXZCWVUTSRQPONMKLJIHGFEDCBA@#$%^&*()-=[]{}()*^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRQPONMLKJIHGFEDCBA@#$%^&*()-=[]{}()*^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRQPONMLKJIHGFEDCBA@#$%^&*()-=[]{}()*^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRQPONMLKJIHGFEDCBA@#$%^&*()-=[]{}()*^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRQPONMLKJIHGFEDCBA@#$%^&*()-=[]{}()*^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRQPONMLKJIHGFEDCBA@#$%^@!"#$%^&*()-=[]{}()*^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRQPONMLKJIHGFEDCBA@#$%^&*()-=[]{}()*^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRQPONMLKJIHGFEDCBA@#$%^&*()-=[]{}()*^%$#@$#%^&*()-=[]{}()*^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRQPONMLKJIHGFEDCBA@#$%^&*()-=[]{}()*^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRQPONMLKJIHGFEDCBA@#$%^&*()-=[]{}()*^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRQPONMLKJIHGFEDCBA@#$%^&*()-=[]{}()*^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRQPONMLKJIHGFEDCBA@#$%^&*()-=[]{}()*^%$#@!^&*()-=[]{}()*^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRQPONMLKJIHGFEDCBA@#$%^&*()-=[]{}()*^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRQPONMLKJIHGFEDCBA@#$%^&*()-=[]{}()*^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRQPONMLKJIHGFEDCBA@#$%^&*()-=[]{}()*^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRQPONMLKJIHGFEDCBA@#$%^&*()-=[]{}()*^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRQPONMLKJIHGFEDCBA@#$%^&*()-=[]{}()*^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRQPONMLKJIHGFEDCBA@#$%^&*()-=[]{}()*^%$#@!~[]{}|;:'",<./?\:";}[][ZYXVUTSRQPONMLKJIHGFEDCBA@#$%^&*()-=[]{}()*^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRQPONMLKJIHGFEDCBA@#$%^&*()-=[]{}()*^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRQPONMLKJIHGFEDCBA@#$%^&*()-=[]{}()*^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRQPONMLKJIHGFEDCBA@#$%^&*()-=[]{}()*^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRQPONMLKJIHGFEDCBA@#$%^&*()-=[]{}()*^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRQPONMLKJIHGFEDCBA@#$%^&*()-=[]{}()*^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRQPONMLKJIHGFEDCBA@#$%^&*()-=[]{}()*^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRQPONMLKJIHGFEDCBA@#$%^&*()-=[]{}()*^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRQPONMLKJIHGFEDCBA@#$%^&*()-=[]{}()*^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRQPONMLKJIHGFEDCBA@#$%^&*()-=[]{}()*^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRQPONMLKJIHGFEDCBA@#$%^&*()-=[]{}()*^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRQPONMLKJIHGFEDCBA@#$%^&*()-=[]{}()*^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRQPONMLKJIHGFEDCBA@#$%^&*()-=[]{}()*^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRQPONMLKJIHGFEDCBA@#$%^&*()-=[]{}()*^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRQPONMLKJIHGFEDCBA@#$%^&*()-=[]{}()*^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRQPONMLKJIHGMFEDCBA@#$%^&*()-=[]{}()*^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRQPONMLKJIHGFEDCBA@#$%^&*()-=[]{}()*^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRQPONMLKJIHGFEDCBA@#$%^&*()-=[]{}()*^%$#@!~[]{}|;:'",<./?\:";}[][ZYXWVUTSRQPONMLKJIHGFEDCBA@#$%^&打开设备文件描述符,如果成功,则返回文件描述符;否则,返回-1表示失败,打开第一个串口设备
/dev/ttySAC1`:fd = open("/dev/ttySAC1", O_RDWR | O_NOCTTY | O_NDELAY);如果打开失败,可以使用如下命令修改设备权限后重试:sudo chmod 666 /dev/ttyUSB0,4、配置串口参数通过tcgetattr()函数获取当前的串口参数,然后通过tcsetattr()函数设置新的串口参数,常见的串口参数包括波特率、数据位、校验位和停止位等,示例代码如下:struct termios options;options结构体用于存储串口的配置信息,tcgetattr(fd, &options); // 获取当前串口参数cfsetispeed(&options, c_cflag & ~CBAUD); // 设置波特率为9600cfsetospeed(&options, c_cflag & ~CBAUD); // 设置波特率为9600options.c_cflag &= ~PARENB; // 无奇偶校验位options.c_iflag &= ~(IXON | IXOFF | IXANY); // 关闭软件流控options.c_cflag |= CLOCAL | CREAD; // 使能接收使能选项tcflush(fd, TCIFLUSH); // 刷新输入队列tcsetattr(fd, TCSANOW, &options); // 设置串口参数5、读写数据通过read()函数从串口读取数据,通过write()函数向串口写入数据,示例代码如下:read(fd, buf, sizeof(buf)); // 从串口读取数据write(fd, "Hello", 5); // 向串口写入数据6、关闭串口设备使用close()函数关闭串口设备,fd = close(fd); // 关闭串口设备四、常见问题及解决方法1、无法打开串口设备可能原因:设备被占用或权限不足,解决方法:检查设备是否被其他进程占用,使用sudo命令提升权限,2、读写数据失败可能原因:串口参数配置错误或设备未正确打开,解决方法:检查串口参数配置是否正确,确保设备已正确打开,五、归纳本文详细介绍了Linux串口源码的结构和使用,通过实例代码演示了如何使用C语言进行串口通信,掌握这些知识对于进行串口通信的开发人员来说至关重要,通过本文的学习,相信读者能够更好地理解和应用Linux串口源码,提高开发效率和质量。
以上就是关于“linux串口源码”的问题,朋友们可以点击主页了解更多内容,希望可以够帮助大家!