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

  首先在串口初始化中会先注册一个串口驱动,函数原型为

  int uart_register_driver(struct uart_driver *drv)

  在这个函数中会调用注册tty驱动的函数

  int tty_register_driver(struct tty_driver *driver)
  {
    ...
    cdev_init(&driver->cdev, &tty_fops);
    ...
  }

从这一句代码可以看出串口实质上也是一个字符设备。用soucesight对参数tty_fops进行回溯,可以找出应用程序与tty架构的函数调用关系表file_operations

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,
};

可以看出应用程序中的open函数实际上是tty架构中的tty_open函数,查看该函数

static int tty_open(struct inode *inode, struct file *filp)
{
  struct tty_struct *tty = NULL;
    int noctty, retval;
    struct tty_driver *driver;
    int index;
    dev_t device = inode->i_rdev;
    unsigned saved_flags = filp->f_flags;
  ...
  if (tty->ops->open)
  ...
}

这里调用到了tty->ops中的open函数,是struct tty_operations类型的,实际上是uart_ops这一结构

static const struct tty_operations uart_ops = {
.open = uart_open,
...
};

可以看出这里又调用到了uart_open函数

static int uart_open(struct tty_struct *tty, struct file *filp)
{
  ...
  retval = uart_startup(tty, state, 0);
  ...
}
 
static int uart_startup(struct tty_struct *tty, struct uart_state *state, int init_hw)
{
  struct uart_port *uport = state->uart_port;
struct tty_port *port = &state->port;
unsigned long page;
int retval = ;
  ...
  retval = uport->ops->startup(uport);
  ...
}

层层调用之后到这里,调用到uport结构中的函数,uport为struct uart_port类型,每一个uart_port对应一个串口设备,也就是说这里已经调用到了底层驱动的startup函数。在串口初始化时用数组来初始化uart_port

static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS] = {
[] = {
.port = {
.lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[].port.lock),
.iotype = UPIO_MEM,
.irq = IRQ_S3CUART_RX0,
.uartclk = ,
.fifosize = ,
.ops = &s3c24xx_serial_ops,
.flags = UPF_BOOT_AUTOCONF,
.line = ,
}
},
...
}

函数操作集

static struct uart_ops s3c24xx_serial_ops = {
.pm = s3c24xx_serial_pm,
.tx_empty = s3c24xx_serial_tx_empty,
.get_mctrl = s3c24xx_serial_get_mctrl,
.set_mctrl = s3c24xx_serial_set_mctrl,
.stop_tx = s3c24xx_serial_stop_tx,
.start_tx = s3c24xx_serial_start_tx,
.stop_rx = s3c24xx_serial_stop_rx,
.enable_ms = s3c24xx_serial_enable_ms,
.break_ctl = s3c24xx_serial_break_ctl,
.startup = s3c24xx_serial_startup,
.shutdown = s3c24xx_serial_shutdown,
.set_termios = s3c24xx_serial_set_termios,
.type = s3c24xx_serial_type,
.release_port = s3c24xx_serial_release_port,
.request_port = s3c24xx_serial_request_port,
.config_port = s3c24xx_serial_config_port,
.verify_port = s3c24xx_serial_verify_port,
};

所以,retval = uport->ops->startup(uport);这里最终调用了s3c24xx_serial_startup函数,真相基本上已经浮出水面。应用程序中的open函数通过tty架构,层层调用,最后调用到了samsung.c驱动文件中的s3c24xx_serial_startup函数。

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 != ) {
printk(KERN_ERR "cannot get irq %d\n", ourport->rx_irq);
return ret;
} ourport->rx_claimed = ; 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 = ; dbg("s3c24xx_serial_startup ok\n"); /* the port reset code should have done the correct
* register setup for the port controls */ return ret; err:
s3c24xx_serial_shutdown(port);
return ret;

这个函数主要做了四件事情,代码已高亮标出:

  1、打开接收使能

  2、注册数据接收中断

  3、打开发送使能

  4、注册数据发送中断

至此,linux串口驱动程序打开设备的实现已分析完毕。如果有疑问或建议,欢迎指出。

linux串口驱动分析——打开设备的更多相关文章

  1. linux串口驱动分析

    linux串口驱动分析 硬件资源及描写叙述 s3c2440A 通用异步接收器和发送器(UART)提供了三个独立的异步串行 I/O(SIO)port,每一个port都能够在中断模式或 DMA 模式下操作 ...

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

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

  3. Linux串口驱动程序(3)-打开设备

    先来分析一下串口打开的过程: 1.用户调用open函数打开串口设备文件:2.在内核中通过tty子系统,把open操作层层传递到串口驱动程序中:3.在串口驱动程序中的xx_open最终实现这个操作.这里 ...

  4. linux串口驱动分析【转】

    转自:http://blog.csdn.net/hanmengaidudu/article/details/11946591 硬件资源及描述 s3c2440A 通用异步接收器和发送器(UART)提供了 ...

  5. linux的串口驱动分析

    1.串口驱动中的数据结构 • UART驱动程序结构:struct uart_driver  驱动 • UART端口结构: struct uart_port  串口 • UART相关操作函数结构: st ...

  6. Smart210学习记录------linux串口驱动

    转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=27025492&id=327609 一.核心数据结构 串口驱动有 ...

  7. Linux spi驱动分析(二)----SPI核心(bus、device_driver和device)

    一.spi总线注册 这里所说的SPI核心,就是指/drivers/spi/目录下spi.c文件中提供给其他文件的函数,首先看下spi核心的初始化函数spi_init(void).程序如下: 点击(此处 ...

  8. Linux I2C驱动分析(三)----i2c_dev驱动和应用层分析 【转】

    本文转载自:http://blog.chinaunix.net/uid-21558711-id-3959287.html 分类: LINUX 原文地址:Linux I2C驱动分析(三)----i2c_ ...

  9. 基于335X的Linux网口驱动分析

    基于335X的linux网口驱动分析 一. 系统构成 1.  硬件平台 AM335X 2.  LINUX内核版本 4.4.12 二. 网口驱动构架(mdio部分) mdio网口驱动部分 使用 总线.设 ...

随机推荐

  1. 集成对象和 JSON

    想象一下,如果 NSDictionary,NSArray,NSString 呾 NSData 都提供方法 相亏转换 JSON 数据,返样丌径好举? 嗯,等等 – 我们正在使用 Objective-C, ...

  2. BaseAdapter的ArrayIndexOutOfBoundsException

    最近写一个listView中多个listItem布局时,convertView缓存及使用,类似微信的聊天界面的listView,报了一个异常: 11-25 15:51:49.076: E/InputE ...

  3. 苹果Swift编程语言新手教程【中国版】

    Swift代码语言教程:在刚刚过去的WWDC2014大会上,苹果公司新公布了一种编程语言Swift.据悉.Swift语言继承了C语言以及Objective-C的特性,且克服了C语言的兼容性问题.对于广 ...

  4. linux 启动network后报错:device eth0 does not seem to be present, delaying initialization

    问题背景: 在vsphere client中部署ovf模板后启动linux 的network后提示:device eth0 does not seem to be present, delaying ...

  5. 将Apache添加为Linux的服务 实现自启动(转)

    在Linux下用源代码方式编译安装完Apache后,启动关闭Apache可以通过如下命令实现: /app/apache2.2.14/bin/apachectl start | stop | resta ...

  6. Android(java)学习笔记254:ContentProvider使用之内容观察者(观察发出去的短信)

    1.新建一个案例如下: 2. 不需要添加权限,同时这里布局文件不做修改,来到MainActivity,如下: package com.itheima.sendsmslistener; import a ...

  7. Java基础知识强化27:Object类之toString()方法

    1. Object类的toString()方法: public  String  toString():返回该对象的字符串表示 2. 案例演示: (1)Student类: package cn.itc ...

  8. AS 断点调试 debug

    debug面板 点击下图工具栏开启调试会话 此种调试方式是通过冻结应用运行的状态,仿佛时间停止了一般,然后我们逐一观察此时程序的各个参数是否符合我们的预期. 这种调试方法适用于对时间不敏感的程序.也就 ...

  9. poj 2823 Sliding Window(单调队列)

    /* 裸地单调队列.. 第一次写 写的好丑.... */ #include<iostream> #include<cstdio> #include<cstring> ...

  10. HTML5中class选择器属性的解释

    设置有class属性值的元素,可以被css中的选择器调用,也可以在javascript中以getElementsByClassName()方法调用. 可以给各个元素添加class而且名称可以相同与id ...