先来分析一下串口打开的过程:

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)\n",
port->mapbase, port->membase);

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\n", ourport->rx_irq);
return ret;
}

ourport->rx_claimed = 1; // 使能发送

dbg("requesting tx irq...\n");

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\n", ourport->tx_irq);
goto err;
}

ourport->tx_claimed = 1;

dbg("s3c24xx_serial_startup ok\n");

/* 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
---------------------

Linux串口驱动程序(3)-打开设备的更多相关文章

  1. linux串口驱动分析——打开设备

    串口驱动是由tty_driver架构实现的.一个应用程序中的函数要操作硬件,首先会经过tty,级级调用之后才会到达驱动之中.本文先介绍应用程序中打开设备的open函数的整个历程. 首先在串口初始化中会 ...

  2. linux串口驱动分析——发送数据

    一.应用程序中write函数到底层驱动历程 和前文提到的一样,首先先注册串口,使用uart_register_driver函数,依次分别为tty_register_driver,cdev_init函数 ...

  3. Linux内核入门到放弃-设备驱动程序-《深入Linux内核架构》笔记

    I/O体系结构 总线系统 PCI(Peripheral Component Interconnect) ISA(Industrial Standard Architecture) SBus IEEE1 ...

  4. Linux设备驱动程序学习----1.设备驱动程序简介

    设备驱动程序简介 更多内容请参考Linux设备驱动程序学习----目录 1. 简介   Linux系统的优点是,系统内部实现细节对所有人都是公开的.Linux内核由大量复杂的代码组成,设备驱动程序可以 ...

  5. linux 下串口独占方式打开

    参考文章: http://blog.csdn.net/rl529014/article/details/51336161  http://blog.csdn.net/lin_fs/article/de ...

  6. storysnail的Linux串口编程笔记

    storysnail的Linux串口编程笔记 作者 He YiJun – storysnail<at>gmail.com 团队 ls 版权 转载请保留本声明! 本文档包含的原创代码根据Ge ...

  7. Linux串口编程详解(转)

    串口本身,标准和硬件 † 串口是计算机上的串行通讯的物理接口.计算机历史上,串口曾经被广泛用于连接计算机和终端设备和各种外部设备.虽然以太网接口和USB接口也是以一个串行流进行数据传送的,但是串口连接 ...

  8. linux串口编程总结

    串口本身.标准和硬件 † 串口是计算机上的串行通讯的物理接口.计算机历史上,串口以前被广泛用于连接计算机和终端设备和各种外部设备.尽管以太网接口和USB接口也是以一个串行流进行数据传送的.可是串口连接 ...

  9. Linux 串口、usb转串口驱动分析(2-2) 【转】

    转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=26807463&id=4186852 Linux 串口.usb转 ...

随机推荐

  1. 转-C++之string判断字符串是否包含某个子串

    转自:https://blog.csdn.net/zhouxinxin0202/article/details/77862615/ 1.string类函数find C++的string类提供了字符串中 ...

  2. 51、tf-idf值提取关键词

    import testWord2vec2 as tw import tensorflow_util as tu import numpy as np model = tw.load_model() n ...

  3. 5、java操作xml,dom4j

    . 1.首先在项目路径下引入dom4j-1.6.1.jar和jaxen-1.1-beta-6.jar包,jaxp方式解析xml文件 <?xml version="1.0" e ...

  4. ubuntu 18.04 自启动

    按下面二种方式打开自启动设置窗口,设置启动参数:(两种方式) 方式一:在桌面左上角的搜索框中输入Startup Applications,打开,点击Add,Name处填open_terminal(自定 ...

  5. PowerDesigner小技巧(整理中)

    1.在修改name的时候,code的值将跟着联动 修改方法:PowerDesign中的选项菜单里修改,在[Tool]-->[General Options]->[Dialog]->[ ...

  6. MyEclipse增强代码补全

    MyElipse的默认代码提示功能隐藏了许多细节,需要开发者手动设置,一起来设置吧,让你的myeclpse更强大. 方法 1 打开MyEclipse 6.0.1,然后“window”→“Prefere ...

  7. 嵌入式C语言4.2 C语言内存空间的使用-指针与修饰符:const,volatile,typedef

    const:变量,只读[不能变] 内存属性: 1. 内存操作的大小 2.内存的变化性,可写可读 char *p; const char *p;     描述字符串,p指向的内容是只读的,不可再次修改 ...

  8. 3.Jmeter 快速入门教程(三-1) --添加响应断言(即loadrunner中所指的检查点)

    上一节课,我们创建了一个测试场景,并进行了少量vuser的负载测试. 有时候我们执行了测试,但是发现并不是所有事务都执行成功了. 那是因为我们只是发起了测试,但并没有对每次请求测试的返回作校验. 所以 ...

  9. Eureka 系列(08)心跳续约与自动过期

    Eureka 系列(08)心跳续约与自动过期 [TOC] Spring Cloud 系列目录 - Eureka 篇 在上一篇 Eureka 系列(07)服务注册与主动下线 中对服务的注册与下线进行了分 ...

  10. ZanUI-WeApp -- 一个颜值高、好用、易扩展的微信小程序 UI 库

    ZanUI-WeApp -- 一个颜值高.好用.易扩展的微信小程序 UI 库:https://cnodejs.org/topic/589d625a5c8036f7019e7a4a 微信小程序之官方UI ...