Linux串口驱动程序(3)-打开设备
先来分析一下串口打开的过程:
1、用户调用open函数打开串口设备文件;
2、在内核中通过tty子系统,把open操作层层传递到串口驱动程序中;
3、在串口驱动程序中的xx_open最终实现这个操作。
这里主要有2个点需要我们重点分析,一个是open函数的传递过程,而是串口驱动程序XXX_open函数的实现。
1.open函数传递
打开uart_register_driver函数,里面就是实现注册串口驱动,在最后有一个tty_register_driver函数,这个函数实际上就是注册一个字符设备。在注册过程中有一个重要的结构:
static const struct file_operations tty_fops = {
.llseek = no_llseek,.read = tty_read,.write = tty_write,.poll = tty_poll,.unlocked_ioctl = tty_ioctl,.compat_ioctl = tty_compat_ioctl,.open = tty_open,.release = tty_release,.fasync = tty_fasync,};
这就是tty_fops结构,里面的tty_open就是响应用户的open操作的。这这个open函数里面肯定不是直接完成串口打开的,它调用了uart_ops里面的open函数:
static const struct tty_operations uart_ops = {
.open = uart_open,.close = uart_close,.write = uart_write,.put_char = uart_put_char,.flush_chars = uart_flush_chars,.write_room = uart_write_room,.chars_in_buffer= uart_chars_in_buffer,.flush_buffer = uart_flush_buffer,.ioctl = uart_ioctl,.throttle = uart_throttle,.unthrottle = uart_unthrottle,.send_xchar = uart_send_xchar,.set_termios = uart_set_termios,.set_ldisc = uart_set_ldisc,.stop = uart_stop,.start = uart_start,.hangup = uart_hangup,.break_ctl = uart_break_ctl,.wait_until_sent= uart_wait_until_sent,ifdef CONFIG_PROC_FS
.proc_fops = &uart_proc_fops,endif
.tiocmget = uart_tiocmget,.tiocmset = uart_tiocmset,ifdef CONFIG_CONSOLE_POLL
.poll_init = uart_poll_init,.poll_get_char = uart_poll_get_char,.poll_put_char = uart_poll_put_char,endif
};
可以看到最终调用的是uart_open函数,这个函数中使用uart_startup(state, 0);实现串口的打开,这个最终又是由s3c24xx_serial_ops里面的s3c24xx_serial_startup函数来实现的。下面分析这个函数。
2.串口打开流程分析
static int s3c24xx_serial_startup(struct uart_port *port)
{
struct s3c24xx_uart_port *ourport = to_ourport(port);int ret;dbg("s3c24xx_serial_startup: port=%p (%08lx,%p)
", port->map , port->mem );rx_enabled(port) = 1; // 使能接收ret = request_irq(ourport->rx_irq, s3c24xx_serial_rx_chars, 0, s3c24xx_serial_portname(port), ourport); // 为数据接收注册中断程序if (ret != 0) { printk(KERN_ERR "cannot get irq %d
", ourport->rx_irq); return ret;}ourport->rx_claimed = 1; // 使能发送dbg("requesting tx irq...
");tx_enabled(port) = 1;ret = request_irq(ourport->tx_irq, s3c24xx_serial_tx_chars, 0, s3c24xx_serial_portname(port), ourport); // 为数据发送注册中断程序if (ret) { printk(KERN_ERR "cannot get irq %d
", ourport->tx_irq); goto err;}ourport->tx_claimed = 1;dbg("s3c24xx_serial_startup ok
");/* the port reset code should have done the correct * register setup for the port controls */if (port->line == 2) { s3c2410_gpio_cfgpin(S3C2410_GPH(6), S3C2410_GPH6_TXD2); s3c2410_gpio_pullup(S3C2410_GPH(6), 1); s3c2410_gpio_cfgpin(S3C2410_GPH(7), S3C2410_GPH7_RXD2); s3c2410_gpio_pullup(S3C2410_GPH(7), 1);}return ret;err:
s3c24xx_serial_shutdown(port);return ret;}
它完成下面的工作:
1、使能接收rx_enabled
2、为数据接收注册中断程序request_irq
3、使能发送tx_enabled
4、为数据发送注册中断程序request_irq
作者:小虾米_2018
来源:CSDN
原文:https://blog.csdn.net/qq_22847457/article/details/91608501
版权声明:本文为博主原创文章,转载请附上博文链接!
继续阅读与本文标签相同的文章
-
hanlp添加自定义字典的步骤介绍
2026-05-24栏目: 教程
-
阿里云ECS服务器被植入挖矿木马解决过程分享
2026-05-24栏目: 教程
-
新增2款开发工具:base64编码解码,unicode编码解码
2026-05-24栏目: 教程
-
Trie树/字典树的简介及实现
2026-05-24栏目: 教程
-
全排列打印
2026-05-24栏目: 教程
