linux串口驅動分析——開啟裝置

來源:互聯網
上載者:User

標籤:

  串口驅動是由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 = 0;  ...  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] = {    [0] = {        .port = {            .lock        = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[0].port.lock),            .iotype        = UPIO_MEM,            .irq        = IRQ_S3CUART_RX0,            .uartclk    = 0,            .fifosize    = 16,            .ops        = &s3c24xx_serial_ops,            .flags        = UPF_BOOT_AUTOCONF,            .line        = 0,        }    },    ...}

函數操作集

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 != 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 */    return ret; err:    s3c24xx_serial_shutdown(port);    return ret;

這個函數主要做了四件事情,代碼已高亮標出:

  1、開啟接收使能

  2、註冊資料接收中斷

  3、開啟發送使能

  4、註冊資料發送中斷

至此,linux串口驅動程式開啟裝置的實現已分析完畢。如果有疑問或建議,歡迎指出。

 

linux串口驅動分析——開啟裝置

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.