1. 程式人生 > >串列埠驅動之寫操作

串列埠驅動之寫操作

繼上分析讀操作後。。。。。。。。。。。。。。。。。
“drivers/char/tty_io.c” 此檔案完成核心層函式的實現。包含file_operations結構體與使用者空間進行資料互動。
整體流程如:
tty_write–>do_tty_write–>ld->ops->write(n_tty_write)–>uart_write–>uart_start–>__uart_start(tty)–>port->ops->start_tx(port)

 409 static const struct file_operations tty_fops = {
 410
.llseek = no_llseek, 411 .read = tty_read, 412 .write = tty_write, 413 .poll = tty_poll, 414 .unlocked_ioctl = tty_ioctl, 415 .compat_ioctl = tty_compat_ioctl, 416 .open = tty_open, 417 .release
= tty_release, 418 .fasync = tty_fasync, 419 };

此次分析使用者空間的寫操作即tty_write。
tty_write函式實現在tty_io.c檔案中。

1051 static ssize_t tty_write(struct file *file, const char __user *buf,
1052                                                 size_t count, loff_t *ppos)
1053 {
1054         struct tty_struct *
tty; 1055 struct inode *inode = file->f_path.dentry->d_inode; 1056 ssize_t ret; 1057 struct tty_ldisc *ld; 1058 1059 tty = (struct tty_struct *)file->private_data; 1060 if (tty_paranoia_check(tty, inode, "tty_write")) 1061 return -EIO; 1062 if (!tty || !tty->ops->write || 1063 (test_bit(TTY_IO_ERROR, &tty->flags))) 1064 return -EIO; 1065 /* Short term debug to catch buggy drivers */ 1066 if (tty->ops->write_room == NULL) 1067 printk(KERN_ERR "tty driver %s lacks a write_room method.\n", 1068 tty->driver->name); **1069 ld = tty_ldisc_ref_wait(tty); 1070 if (!ld->ops->write) 1071 ret = -EIO; 1072 else 1073 ret = do_tty_write(ld->ops->write, tty, file, buf, count);** 1074 tty_ldisc_deref(ld); 1075 return ret; 1076 }
 923 static inline ssize_t do_tty_write(
 924         ssize_t (*write)(struct tty_struct *, struct file *, const unsigned char *, size_t),
 925         struct tty_struct *tty,
 926         struct file *file,
 927         const char __user *buf,
 928         size_t count)
 929 {
.......
 977         for (;;) {
 978                 size_t size = count;
 979                 if (size > chunk)
 980                         size = chunk;
 981                 ret = -EFAULT;
 **982                 if (copy_from_user(tty->write_buf, buf, size))
 983                         break;
 984                 ret = write(tty, file, tty->write_buf, size);**
 985                 if (ret <= 0)
 986                         break;
 987                 written += ret;
 988                 buf += ret;
 989                 count -= ret;
 990                 if (!count)
 991                         break;
 992                 ret = -ERESTARTSYS;
 993                 if (signal_pending(current))
 994                         break;
 995                 cond_resched();
 996         }
 997         if (written) {
 998                 struct inode *inode = file->f_path.dentry->d_inode;
 999                 inode->i_mtime = current_fs_time(inode->i_sb);
1000                 ret = written;
1001         }
1002 out:
1003         tty_write_unlock(tty);
1004         return ret;
1005 }

執行傳遞進來的寫函式也就是呼叫線路規程中的寫函式。接下來進入到線路規程函式實現檔案”drivers/char/n_tty.c”。

2080 struct tty_ldisc_ops tty_ldisc_N_TTY = {
2081         .magic           = TTY_LDISC_MAGIC,
2082         .name            = "n_tty",
2083         .open            = n_tty_open,
2084         .close           = n_tty_close,
2085         .flush_buffer    = n_tty_flush_buffer,
2086         .chars_in_buffer = n_tty_chars_in_buffer,
2087         .read            = n_tty_read,
2088         .write           = n_tty_write,
2089         .ioctl           = n_tty_ioctl,
2090         .set_termios     = n_tty_set_termios,
2091         .poll            = n_tty_poll,
2092         .receive_buf     = n_tty_receive_buf,
2093         .write_wakeup    = n_tty_write_wakeup
2094 };

線路規程的寫函式實現如下:

1922 static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
1923                            const unsigned char *buf, size_t nr)
1924 {
......
1941         while (1) {
1942                 set_current_state(TASK_INTERRUPTIBLE);
1943                 if (signal_pending(current)) {
1944                         retval = -ERESTARTSYS;
1945                         break;
1946                 }
1947                 if (tty_hung_up_p(file) || (tty->link && !tty->link->count)) {
1948                         retval = -EIO;
1949                         break;
1950                 }
1951                 if (O_OPOST(tty) && !(test_bit(TTY_HW_COOK_OUT, &tty->flags))) {
1952                         while (nr > 0) {
1953                                 ssize_t num = process_output_block(tty, b, nr);
1954                                 if (num < 0) {
1955                                         if (num == -EAGAIN)
1956                                                 break;
1957                                         retval = num;
1958                                         goto break_out;
1959                                 }
1960                                 b += num;
1961                                 nr -= num;
1962                                 if (nr == 0)
1963                                         break;
1964                                 c = *b;
1965                                 if (process_output(c, tty) < 0)
1966                                         break;
1967                                 b++; nr--;
1968                         }
1969                         if (tty->ops->flush_chars)
1970                                 tty->ops->flush_chars(tty);
1971                 } else {
1972                         while (nr > 0) {
**1973                                 c = tty->ops->write(tty, b, nr);**
1974                                 if (c < 0) {
1975                                         retval = c;
1976                                         goto break_out;
1977                                 }
1978                                 if (!c)
1979                                         break;
1980                                 b += c;
1981                                 nr -= c;
1982                         }
1983                 }
1984                 if (!nr)
1985                         break;
1986                 if (file->f_flags & O_NONBLOCK) {
1987                         retval = -EAGAIN;
1988                         break;
1989                 }
......
}

粗體部分對tty層的write驅動進行了呼叫。即進入到檔案”drivers/serial/serial_core.c”中。

2283 static const struct tty_operations uart_ops = {
2284         .open           = uart_open,
2285         .close          = uart_close,
**2286         .write          = uart_write,**
2287         .put_char       = uart_put_char,
2288         .flush_chars    = uart_flush_chars,
2289         .write_room     = uart_write_room,
2290         .chars_in_buffer= uart_chars_in_buffer,
2291         .flush_buffer   = uart_flush_buffer,
2292         .ioctl          = uart_ioctl,
2293         .throttle       = uart_throttle,
2294         .unthrottle     = uart_unthrottle,
2295         .send_xchar     = uart_send_xchar,
2296         .set_termios    = uart_set_termios,
2297         .set_ldisc      = uart_set_ldisc,
2298         .stop           = uart_stop,
2299         .start          = uart_start,
2300         .hangup         = uart_hangup,
2301         .break_ctl      = uart_break_ctl,
2302         .wait_until_sent= uart_wait_until_sent,
2303 #ifdef CONFIG_PROC_FS
2304         .proc_fops      = &uart_proc_fops,
2305 #endif
2306         .tiocmget       = uart_tiocmget,
2307         .tiocmset       = uart_tiocmset,
2308 #ifdef CONFIG_CONSOLE_POLL
2309         .poll_init      = uart_poll_init,
2310         .poll_get_char  = uart_poll_get_char,
2311         .poll_put_char  = uart_poll_put_char,
2312 #endif
2313 };

即呼叫tty層的uart_write函式。此函式實現如下:

 498 uart_write(struct tty_struct *tty, const unsigned char *buf, int count)
 499 {
 500         struct uart_state *state = tty->driver_data;
 501         struct uart_port *port;
 502         struct circ_buf *circ;
 503         unsigned long flags;
 504         int c, ret = 0;
 505
 506         /*
 507          * This means you called this function _after_ the port was
 508          * closed.  No cookie for you.
 509          */
 510         if (!state) {
 511                 WARN_ON(1);
 512                 return -EL3HLT;
 513         }
 514
 515         port = state->uart_port;
 516         circ = &state->xmit;
 517
 518         if (!circ->buf)
 519                 return 0;
 520
 521         spin_lock_irqsave(&port->lock, flags);
 522         while (1) {
 523                 c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE);
 524                 if (count < c)
 525                         c = count;
 526                 if (c <= 0)
 527                         break;
 528                 memcpy(circ->buf + circ->head, buf, c);
 529                 circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1);
 530                 buf += c;
 531                 count -= c;
 532                 ret += c;
 533         }
 534         spin_unlock_irqrestore(&port->lock, flags);
 535
 536         uart_start(tty);
 537         return ret;
 538 }

將使用者層資料放進環形緩衝區中,呼叫uart_start(tty);函式。

  92 static void __uart_start(struct tty_struct *tty)
  93 {
  94         struct uart_state *state = tty->driver_data;
  95         struct uart_port *port = state->uart_port;
  96
  97         if (!uart_circ_empty(&state->xmit) && state->xmit.buf &&
  98             !tty->stopped && !tty->hw_stopped)
  99                 port->ops->start_tx(port);
 100 }
 101
 102 static void uart_start(struct tty_struct *tty)
 103 {
 104         struct uart_state *state = tty->driver_data;
 105         struct uart_port *port = state->uart_port;
 106         unsigned long flags;
 107
 108         spin_lock_irqsave(&port->lock, flags);
 109         __uart_start(tty);
 110         spin_unlock_irqrestore(&port->lock, flags);
 111 }

最後呼叫我們在底層驅動裡面自己實現的port->ops->start_tx(port);函式進行資料的傳送。