串口驱动之写操作

继上分析读操作后。。。。。。。。。。。。。。。。。
“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);函数进行数据的发送。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值