串列埠驅動之寫操作
阿新 • • 發佈:2018-12-30
繼上分析讀操作後。。。。。。。。。。。。。。。。。
“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);函式進行資料的傳送。