ttyS0 as tty in kernel

cat /proc/tty/drive/ttyAMA  可以看tx与rx包

/proc/tty/driver # cat ttyAMA 
serinfo:1.0 driver revision:
0: uart:PL011 rev2 mmio:0x120A0000 irq:21 tx:7455 rx:0 RTS|DTR|DSR|CD|RI
1: uart:PL011 rev2 mmio:0x120A1000 irq:22 tx:0 rx:0 DSR|CD|RI
2: uart:PL011 rev2 mmio:0x120A2000 irq:23 tx:14196 rx:0 RTS|DTR|DSR|CD|RI
3: uart:PL011 rev2 mmio:0x120A3000 irq:24 tx:0 rx:0 DSR|CD|RI

##################################################################################################################
##################################################################################################################
##################################################################################################################
tty:各种类型的终端设备
串口终端:搜索ttyS得到drivers/tty/serial/8250/8250_core.c被使用到了并编译到内核了.
static int __init serial8250_init(void)
{
    int ret;
    //为每一个串口配置port->ops = &serial8250_pops;串口的操作方法.第1点.
    serial8250_isa_init_ports();
...
    /*注册用户层的接口,tty_register_driver注册tty,看第3点.*/
    ret = uart_register_driver(&serial8250_reg);
...
    serial8250_isa_devs = platform_device_alloc("serial8250",
                            PLAT8250_DEV_LEGACY);
...
    ret = platform_device_add(serial8250_isa_devs);
...
    serial8250_register_ports(&serial8250_reg, &serial8250_isa_devs->dev);
...
    ret = platform_driver_register(&serial8250_isa_driver);
...
}
##################################################################################################################
1.
static struct uart_ops serial8250_pops = {
    .tx_empty    = serial8250_tx_empty,
    .set_mctrl    = serial8250_set_mctrl,
    .get_mctrl    = serial8250_get_mctrl,
    .stop_tx    = serial8250_stop_tx,
    .start_tx    = serial8250_start_tx,
    .stop_rx    = serial8250_stop_rx,
    .enable_ms    = serial8250_enable_ms,
    .break_ctl    = serial8250_break_ctl,
    .startup    = serial8250_startup,//配置启动串口,并配置串口中断输入.在打开设备文件时会调用到.
    .shutdown    = serial8250_shutdown,
    .set_termios    = serial8250_set_termios,
    .set_ldisc    = serial8250_set_ldisc,
    .pm        = serial8250_pm,
    .type        = serial8250_type,
    .release_port    = serial8250_release_port,
    .request_port    = serial8250_request_port,
    .config_port    = serial8250_config_port,//配置串口操作方式
    .verify_port    = serial8250_verify_port,
#ifdef CONFIG_CONSOLE_POLL
    .poll_get_char = serial8250_get_poll_char,
    .poll_put_char = serial8250_put_poll_char,
#endif
};
static int serial8250_startup(struct uart_port *port)
{
    //如果配置为中断形式,就调配置中断回调函数:
    retval = serial_link_irq_chain(up);
}
static int serial_link_irq_chain(struct uart_8250_port *up)
{
    ret = request_irq(up->port.irq, serial8250_interrupt,
              irq_flags, "serial", i);
}
static irqreturn_t serial8250_interrupt(int irq, void *dev_id)
{
    //中断调用注册的serial8250_default_handle_irq,第2点.
    if (port->handle_irq(port)) {
    }
}

##################################################################################################################
2.
p->serial_in/serial_out用于读取配置寄存器的.在serial8250_startup和配置serial8250_config_port会调用他.
static void set_io_from_upio(struct uart_port *p)
{
...
    p->serial_in = io_serial_in;
    p->serial_out = io_serial_out;
    p->handle_irq = serial8250_default_handle_irq;
}
##################################################################################################################
3.
int uart_register_driver(struct uart_driver *drv)
{
    tty_set_operations(normal, &uart_ops);//配置tty_driver的操作方法.
    retval = tty_register_driver(normal);注册tty_driver.
}
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,
    .get_icount    = uart_get_icount,
#ifdef CONFIG_CONSOLE_POLL
    .poll_init    = uart_poll_init,
    .poll_get_char    = uart_poll_get_char,
    .poll_put_char    = uart_poll_put_char,
#endif
};
在后面打开设备文件的时候有:
tty_fops.open-->tty_open-->tty->ops->open-->uart_ops.open-->uart_open-->uart_startup-->uart_port_startup--> uport->ops->startup(uport)-->serial8250_startup
做到开始串口初始化的目的.

int tty_register_driver(struct tty_driver *driver)
{
    //这个应该经常看到,注册字符设备,如果有主设备号用register_chrdev_region,没有用alloc_chrdev_region
    if (!driver->major) {
        error = alloc_chrdev_region(&dev, driver->minor_start,
                        driver->num, driver->name);
        if (!error) {
            driver->major = MAJOR(dev);
            driver->minor_start = MINOR(dev);
        }
    } else {
        dev = MKDEV(driver->major, driver->minor_start);
        error = register_chrdev_region(dev, driver->num, driver->name);
    }

    if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) {
        for (i = 0; i < driver->num; i++) {
            //注册每一个如ttyS0,ttyS1的.
            d = tty_register_device(driver, i, NULL);
            if (IS_ERR(d)) {
                error = PTR_ERR(d);
                goto err_unreg_devs;
            }
        }
    }
    proc_tty_register_driver(driver);
}
################
tty_register_device-->tty_register_device_attr
{
...
    retval = tty_cdev_add(driver, devt, index, 1);
    retval = device_register(dev);
}
static int tty_cdev_add(struct tty_driver *driver, dev_t dev,
        unsigned int index, unsigned int count)
{
    /* init here, since reused cdevs cause crashes */
    cdev_init(&driver->cdevs[index], &tty_fops);//为每个设备配置文件操作
    driver->cdevs[index].owner = driver->owner;
    return cdev_add(&driver->cdevs[index], dev, count);
}
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,
};
static int tty_open(struct inode *inode, struct file *filp)
{
    if (tty->ops->open)
        retval = tty->ops->open(tty, filp);
}
##########
4.中断过程
serial8250_default_handle_irq-->serial8250_handle_irq-->serial8250_rx_chars-->tty_flip_buffer_push-->flush_to_ldisc-->disc->ops->receive_buf-->tty_ldisc_N_TTY.receive_buf-->n_tty_receive_buf-->wake_up_interruptible唤醒阻塞
读取过程
tty_read-->ld->ops->read-->tty_ldisc_N_TTY.n_tty_read-->add_wait_queue等待-->ldata->read_buf读取缓冲区-->tty_put_user发给用户层.
输出过程
tty_write-->do_tty_write-->tty_ldisc_N_TTY.n_tty_write-->tty->ops->write-->uart_ops.uart_write-->uart_start-->__uart_start-->port->ops->start_tx-->serial8250_pops.start_tx-->serial8250_start_tx操作硬件了.
5.配置
tty接口的是:
main.c中:    console_init();
对应tty_io.c,接口就过来了.
void __init console_init(void)
{
    initcall_t *call;
    /* Setup the default TTY line discipline. */
    tty_ldisc_begin();
}
void tty_ldisc_begin(void)
{
    /* Setup the default TTY line discipline. */
    (void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);
}

 

tty接口都是一样的,不同的终端接口注册不同的接口罢了.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值