微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > Linux下的串口总线驱动(三)

Linux下的串口总线驱动(三)

时间:11-22 来源:互联网 点击:

}

}

mutex_unlock(&tty_mutex);

return -ENODEV;

}

driver = get_tty_driver(device, &index);

if (!driver) {

mutex_unlock(&tty_mutex);

return -ENODEV;

}

got_driver:

if (!tty) {

//检查我们是否重复打开一个已经存在的tty

tty = tty_driver_lookup_tty(driver, inode, index);

if (IS_ERR(tty)) {

mutex_unlock(&tty_mutex);

return PTR_ERR(tty);

}

}

if (tty) {

retval = tty_reopen(tty); //重新打开

if (retval)

tty = ERR_PTR(retval);

} else

tty = tty_init_dev(driver, index, 0); //初始化,为需要打开的终端建立tty_struct结构体

mutex_unlock(&tty_mutex);

tty_driver_kref_put(driver);

if (IS_ERR(tty))

return PTR_ERR(tty);

filp->private_data = tty; //设置私有数据

file_move(filp, &tty->tty_files);

check_tty_count(tty, "tty_open");

if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&

tty->driver->subtype == PTY_TYPE_MASTER)

noctty = 1;

#ifdef TTY_DEBUG_HANGUP

printk(KERN_DEBUG "opening %s...", tty->name);

#endif

if (!retval) {

if (tty->ops->open)

retval = tty->ops->open(tty, filp); //调用tty_operations下的open函数

else

retval = -ENODEV;

}

filp->f_flags = saved_flags;

if (!retval && test_bit(TTY_EXCLUSIVE, &tty->flags) &&

!capable(CAP_SYS_ADMIN))

retval = -EBUSY;

if (retval) {

#ifdef TTY_DEBUG_HANGUP

printk(KERN_DEBUG "error %d in opening %s...", retval,

tty->name);

#endif

tty_release_dev(filp);

if (retval != -ERESTARTSYS)

return retval;

if (signal_pending(current))

return retval;

schedule();

//需要复位f_op,以防挂起

if (filp->f_op == &hung_up_tty_fops)

filp->f_op = &tty_fops;

goto retry_open;

}

mutex_lock(&tty_mutex);

spin_lock_irq(¤t->sighand->siglock);

if (!noctty &&

current->signal->leader &&

!current->signal->tty &&

tty->session == NULL)

__proc_set_tty(current, tty);

spin_unlock_irq(¤t->sighand->siglock);

mutex_unlock(&tty_mutex);

return 0;

}

在上面这个open函数中,我们主要涉及为需要打开的终端建立tty_struct结构体而执行的一条代码tty_init_dev(driver, index, 0),同时看到了怎么调用tty_operations下的open函数。在此我们好好看看tty_init_dev(driver, index, 0)的内幕吧。

struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,

int first_ok)

{

struct tty_struct *tty;

int retval;

//检查是否pty被多次打开

if (driver->subtype == PTY_TYPE_MASTER &&

(driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok)

return ERR_PTR(-EIO);

if (!try_module_get(driver->owner))

return ERR_PTR(-ENODEV);

tty = alloc_tty_struct(); //分配tty_struct结构体

if (!tty)

goto fail_no_mem;

initialize_tty_struct(tty, driver, idx); //初始化tty_struct结构体

retval = tty_driver_install_tty(driver, tty);

if (retval < 0) {

free_tty_struct(tty);

module_put(driver->owner);

return ERR_PTR(retval);

}

retval = tty_ldisc_setup(tty, tty->link); //调用ldisc下open

if (retval)

goto release_mem_out;

return tty;

fail_no_mem:

module_put(driver->owner);

return ERR_PTR(-ENOMEM);

release_mem_out:

if (printk_ratelimit())

printk(KERN_INFO "tty_init_dev: ldisc open failed, "

"clearing slot %d\n", idx);

release_tty(tty, idx);

return ERR_PTR(retval);

}

我们继续跟踪tty_init_dev中的initialize_tty_struct(tty, driver, idx)函数实现吧

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_ldisc_init(tty); // tty_ldisc的初始化,

tty->session = NULL;

tty->pgrp = NULL;

tty->overrun_time = jiffies;

tty->buf.head = tty->buf.tail = NULL;

tty_buffer_init(tty);

mutex_init(&tty->termios_mutex);

mutex_init(&tty->ldisc_mutex);

init_waitqueue_head(&tty->write_wait);

init_waitqueue_head(&tty->read_wait);

INIT_WORK(&tty->hangup_work, do_tty_hangup);

mutex_init(&tty->atomic_read_lock);

mutex_init(&tty->atomic_write_lock);

mutex_init(&tty->output_lock);

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top