tty driver(3)

关于operations有file, tty, lisc, and tty_port 4种分别是在什么情况下调用的?

1. 通过设备文件节点调到注册的 tty_fops

有关设备结点的文件系统调用,可以看char device:

tty_register_driver -> cdev_init(&driver->cdev, &tty_fops);
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,

};

2. tty_open 的具体实现

当open tty设备结点时,tty_open会被调用。
static int tty_open(struct inode *inode, struct file *filp)
{
    struct tty_struct *tty;
    int noctty, retval;
    struct tty_driver *driver = NULL;
    int index;
    dev_t device = inode->i_rdev;
    unsigned saved_flags = filp->f_flags;
    /*分配tty_file_private结构体内存,并赋值到file->private_data*/
    tty_alloc_file(filp);
         /*device != MKDEV(TTYAUX_MAJOR【5】, 0)
         *tty_register_driver中动态生成的dev,不是5,所以return NULL
         *
/
    tty = tty_open_current_tty(device, filp);
    if(!tty){
        driver = tty_lookup_driver(device, filp, &noctty, &index);
        tty = tty_driver_lookup_tty(driver, inode, index);
    }
    if(!tty)
        tty = tty_init_dev(driver, index);

    tty_add_file(tty, filp);

    if (tty->ops->open)
        retval = tty->ops->open(tty, filp);
    
    return 0;
}


2.1 tty_lookup_driver

/**
 *    tty_lookup_driver - lookup a tty driver for a given device file
 *    @device: device number
 *    @filp: file pointer to tty
 *    @noctty: set if the device should not become a controlling tty
 *    @index: index for the device in the @return driver
 *    @return: driver for this inode (with increased refcount)
 */
static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp,
        int *noctty, int *index)
{
    struct tty_driver *driver;
    driver = get_tty_driver(device, index);
    return driver;

}

2.1.2 get_tty_driver


/**    通过 dev_t 就找到了对应的tty_driver
 *    get_tty_driver - find device of a tty
 *    @dev_t: device identifier
 *    @index: returns the index of the tty
 *
 *    This routine returns a tty driver structure, given a device number
 *    and also passes back the index number.
 */

static struct tty_driver *get_tty_driver(dev_t device, int *index)
{
    struct tty_driver *p;

    list_for_each_entry(p, &tty_drivers, tty_drivers) {
        dev_t base = MKDEV(p->major, p->minor_start);
        if (device < base || device >= base + p->num)
            continue;
        *index = device - base;
        return tty_driver_kref_get(p);
    }
    return NULL;
}

2.2 tty_driver_lookup_tty

/**
 *    tty_driver_lookup_tty() - find an existing tty, if any
 *    @driver: the driver for the tty
 *    @idx:     the minor number
 *
 *    Return the tty, if found or ERR_PTR() otherwise.
 */
static struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver,
        struct inode *inode, int idx)
{
    if (driver->ops->lookup)
        return driver->ops->lookup(driver, inode, idx);

    return driver->ttys[idx];
}


2.3 tty_init_dev

/**
 *    tty_init_dev        -    initialise a tty device
 *    @driver: tty driver we are opening a device on
 *    @idx: device index
 *    @ret_tty: returned tty structure
 */
struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx)
{
    struct tty_struct *tty;
    int retval;
    /*allocated and initialized tty_struct to 0*/
    tty = alloc_tty_struct();
    if (!tty) {
        retval = -ENOMEM;
        goto err_module_put;
    }
    initialize_tty_struct(tty, driver, idx);

    retval = tty_driver_install_tty(driver, tty);
    if (retval < 0)
        goto err_deinit_tty;

    /*
     * Structures all installed ... call the ldisc open routines.
     * If we fail here just call release_tty to clean up.  No need
     * to decrement the use counts, as release_tty doesn't care.
     */
    retval = tty_ldisc_setup(tty, tty->link);
    if (retval)
        goto err_release_tty;
    return tty;
}

2.3.1 initialize_tty_struct


/**
 *    initialize_tty_struct
 *    @tty: tty to initialize
 *
 *    This subroutine initializes a tty structure that has been newly
 *    allocated.
 */

void initialize_tty_struct(struct tty_struct *tty,
        struct tty_driver *driver, int idx)
{
    memset(tty, 0, sizeof(struct tty_struct));
    kref_init(&tty->kref);
    tty->magic = TTY_MAGIC;

    tty->session = NULL;
    tty->pgrp = NULL;
    tty->overrun_time = jiffies;
    /*有关tty_buffer*/
    tty_buffer_init(tty);
    /*有关mutex*/
    mutex_init(&tty->termios_mutex);
    mutex_init(&tty->ldisc_mutex);
    mutex_init(&tty->atomic_read_lock);
    mutex_init(&tty->atomic_write_lock);
    mutex_init(&tty->output_lock);
    mutex_init(&tty->echo_lock);
    /*有关waitqueue_head*/
    init_waitqueue_head(&tty->write_wait);
    init_waitqueue_head(&tty->read_wait);
    /*有关work*/
    INIT_WORK(&tty->hangup_work, do_tty_hangup);
    INIT_WORK(&tty->SAK_work, do_SAK_work);
    /*有关spin lock*/
    spin_lock_init(&tty->read_lock);
    spin_lock_init(&tty->ctrl_lock);

    INIT_LIST_HEAD(&tty->tty_files);
    /*有关行规*/
    tty_ldisc_init(tty);
    
    tty_line_name(driver, idx, tty->name);
    tty->driver = driver;
    tty->ops = driver->ops;
    tty->index = idx;

    tty->dev = tty_get_device(tty);
}
2.3.1.1有关行规
/**
 *    tty_ldisc_init        -    ldisc setup for new tty
 *    @tty: tty being allocated
 *
 *    Set up the line discipline objects for a newly allocated tty. Note that
 *    the tty structure is not completely set up when this call is made.
 */

void tty_ldisc_init(struct tty_struct *tty)
{
    struct tty_ldisc *ld = tty_ldisc_get(N_TTY);
    tty_ldisc_assign(tty, ld);
}

void tty_ldisc_init(struct tty_struct *tty)
{
    struct tty_ldisc *ld = tty_ldisc_get(N_TTY);
    tty_ldisc_assign(tty, ld);
}

static struct tty_ldisc *tty_ldisc_get(int disc)
{
    struct tty_ldisc *ld;
    struct tty_ldisc_ops *ldops;
    /*从全局变量tty_ldiscs中根据disc得到tty_ldisc_ops *
     * 但是指向的内容是什么?
         */
    ldops = get_ldops(disc);
    /*create tty_ldisc*/
    ld = kmalloc(sizeof(struct tty_ldisc), GFP_KERNEL);
    ld->ops = ldops;
    return ld;
}

以下调用序列tty_ldiscs[N_TTY] = tty_ldisc_N_TTY;
start_kernel -> console_init -> tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);
void tty_ldisc_begin(void)
{
    /* Setup the default TTY line discipline. */
    (void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);
}

2.3.2 tty_driver_install_tty


/**
 *    tty_driver_install_tty() - install a tty entry in the driver
 *    @driver: the driver for the tty
 *    @tty: the tty
 */
static int tty_driver_install_tty(struct tty_driver *driver,
                        struct tty_struct *tty)
{
    return driver->ops->install ? driver->ops->install(driver, tty) :
        tty_standard_install(driver, tty);
}

int tty_standard_install(struct tty_driver *driver, struct tty_struct *tty)
{
    int ret = tty_init_termios(tty);
    if (ret)
        return ret;

    tty_driver_kref_get(driver);
    tty->count++;
    driver->ttys[tty->index] = tty;
    return 0;
}

2.3.3 tty_ldisc_setup


 /*    tty_ldisc_setup            -    open line discipline
 *    @tty: tty being shut down
 *    @o_tty: pair tty for pty/tty pairs
 */
int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty)
{
    struct tty_ldisc *ld = tty->ldisc;
    int retval;
    /*调用ldisc:open 函数*/
    retval = tty_ldisc_open(tty, ld);
    /*设置tty flags*/
    tty_ldisc_enable(tty);
    return 0;

}

static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld)
{

        ld->ops->open(tty);

}


static int n_tty_open(struct tty_struct *tty)
{
    /* These are ugly. Currently a malloc failure here can panic */
    if (!tty->read_buf) {
        tty->read_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
        if (!tty->read_buf)
            return -ENOMEM;
    }
    if (!tty->echo_buf) {
        tty->echo_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
    }
    reset_buffer_flags(tty);
    tty_unthrottle(tty);
    tty->column = 0;
    n_tty_set_termios(tty, NULL);
    tty->minimum_to_wake = 1;
    tty->closing = 0;
    return 0;
}


2.4 call into tty_operations open

tty->ops->open(tty, filp)

static int smd_tty_open(struct tty_struct *tty, struct file *f)
{
    int n=tty->index;
    struct smd_tty_info *tty_info = &driver_info->smd_tty[n];

    return tty_port_open(&tty_info->port, tty, f);
}

2.4.1 tty_port_open

int tty_port_open(struct tty_port *port, struct tty_struct *tty,
                            struct file *filp)
{

    tty_port_tty_set(port, tty);/*set the tty member of tty_port to this tty*/

   port->ops->activate(port, tty);/*call into the user specific activate function*/

   return tty_port_block_til_ready(port, tty, filp);/*blocked until port ready*/

}

3.总结

tty_open的主要功能是通过 dev_t查找到注册的 tty_driver, 然后创建 tty_struct,创建 tty_ldisc, 当然还创建了read buffer 等。

tty相关的operations有file, tty, lisc, and tty_port 4种分别是在什么情况下调用的?

不管怎样file的open先被调用,然后是lisc的open,然后是tty driver的,最后是tty_port的。从初始化的过程和内容看核心的数据结构应该是tty_struct.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值