zoukankan      html  css  js  c++  java
  • 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->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 ", 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
    ---------------------

  • 相关阅读:
    Core2.0知识整理
    bootbox.js官方文档
    MongoDB分片详解
    MongoDB高可用集群+MMS集群监控搭建
    使用 AcceptTcpClientAsync 进行 异步 操作
    Windows证书操作
    SQL Server查询所有的表名、字段名、注释
    【转载】ASP.NET Core Web 支付功能接入 微信-扫码支付篇
    【转载】ASP.NET Core Web 支付功能接入 支付宝-电脑网页支付篇
    C#网络编程系列文章
  • 原文地址:https://www.cnblogs.com/ly570/p/11090454.html
Copyright © 2011-2022 走看看