android 伪终端,伪终端pty的原理及使用

1. what is pseudo termina 伪终端(Pseudo Terminal)是成对的逻辑终端设备(即master和slave设备, 对master的操作会反映到slave上)。

例 如/dev/ptyp3和/dev/ttyp3(或者在设备文件系统中分别是/dev/pty/m3和 /dev/pty/s3)。它们与实际物理设备并不直接相关。如果一个程序把ptyp3(master设备)看作是一个串行端口设备,则它对该端口的读/ 写操作会反映在该逻辑终端设备对应的另一个ttyp3(slave设备)上面。而ttyp3则是另一个程序用于读写操作的逻辑设备。

这 样,两个程序就可以通过这种逻辑设备进行互相交流,而其中一个使用ttyp3的程序则认为自己正在与一个串行端口进行通信。这很象是逻辑设备对之间的管道 操作。对于ttyp3(s3),任何设计成使用一个串行端口设备的程序都可以使用该逻辑设备。但对于使用ptyp3的程序,则需要专门设计来使用 ptyp3(m3)逻辑设备。

/***************************************/

支持两种类型的pty:

CONFIG_UNIX98_PTYS=y

CONFIG_LEGACY_PTYS=y

CONFIG_LEGACY_PTY_COUNT=16

/***************************************/

2. How to implement pty in kernel drivers/tty/pty.c

module_init(pty_init);

static int __init pty_init(void)

{

legacy_pty_init();

unix98_pty_init();

return 0;

}

这里只关注legacy pty,两者本质上是一样的,只是细节上不同而已:

/***************************************/

2.1 legacy_pty_init static void __init legacy_pty_init(void)

{

struct tty_driver *pty_driver, *pty_slave_driver;

1]有关全局变量legacy_count static int legacy_count = CONFIG_LEGACY_PTY_COUNT;

if (legacy_count <= 0)

return;

2]分配一对tty_driver: pty_deiver and pty_slave_derver   并初始化,注意其中的other成员,两者的tty_operations基本相同,

只是master多了一个ioctl函数

/*

static const struct tty_operations master_pty_ops_bsd = {

.install = pty_install,

.open = pty_open,

.close = pty_close,

.write = pty_write,

.write_room = pty_write_room,

.flush_buffer = pty_flush_buffer,

.chars_in_buffer = pty_chars_in_buffer,

.unthrottle = pty_unthrottle,

.set_termios = pty_set_termios,

.ioctl = pty_bsd_ioctl,

.resize = pty_resize

};

static const struct tty_operations slave_pty_ops_bsd = {

.install = pty_install,

.open = pty_open,

.close = pty_close,

.write = pty_write,

.write_room = pty_write_room,

.flush_buffer = pty_flush_buffer,

.chars_in_buffer = pty_chars_in_buffer,

.unthrottle = pty_unthrottle,

.set_termios = pty_set_termios,

.resize = pty_resize

};

*/

pty_driver = alloc_tty_driver(legacy_count);     if (!pty_driver)

panic("Couldn't allocate pty driver");

pty_slave_driver = alloc_tty_driver(legacy_count);

if (!pty_slave_driver)

panic("Couldn't allocate pty slave driver");

pty_driver->driver_name = "pty_master";

pty_driver->name = "pty";

pty_driver->major = PTY_MASTER_MAJOR;

pty_driver->minor_start = 0;

pty_driver->type = TTY_DRIVER_TYPE_PTY;

pty_driver->subtype = PTY_TYPE_MASTER;

pty_driver->init_termios = tty_std_termios;

pty_driver->init_termios.c_iflag = 0;

pty_driver->init_termios.c_oflag = 0;

pty_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;

pty_driver->init_termios.c_lflag = 0;

pty_driver->init_termios.c_ispeed = 38400;

pty_driver->init_termios.c_ospeed = 38400;

pty_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW;

pty_driver->other = pty_slave_driver;

tty_set_operations(pty_driver, &master_pty_ops_bsd);

pty_slave_driver->driver_name = "pty_slave";

pty_slave_driver->name = "ttyp";

pty_slave_driver->major = PTY_SLAVE_MAJOR;

pty_slave_driver->minor_start = 0;

pty_slave_driver->type = TTY_DRIVER_TYPE_PTY;

pty_slave_driver->subtype = PTY_TYPE_SLAVE;

pty_slave_driver->init_termios = tty_std_termios;

pty_slave_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;

pty_slave_driver->init_termios.c_ispeed = 38400;

pty_slave_driver->init_termios.c_ospeed = 38400;

pty_slave_driver->flags = TTY_DRIVER_RESET_TERMIOS |

TTY_DRIVER_REAL_RAW;

pty_slave_driver->other = pty_driver;

tty_set_operations(pty_slave_driver, &slave_pty_ops_bsd);

3]注册具体的tty_driver到tty子系统   根据flags,这里创建了dev/pty* and dev/ttyp*

if (tty_register_driver(pty_driver))

panic("Couldn't register pty driver");

if (tty_register_driver(pty_slave_driver))

panic("Couldn't register pty slave driver");

}

2.2 pty_install /*当open 设备文件时,调用函数pty_install,该函数创建了成对的tty_struct*/

static int pty_install(struct tty_driver *driver, struct tty_struct *tty)

{

struct tty_struct *o_tty;

int idx = tty->index;

int retval;

o_tty = alloc_tty_struct();

initialize_tty_struct(o_tty, driver->other, idx);

/* We always use new tty termios data so we can do this

the easy way .. */

retval = tty_init_termios(tty);

retval = tty_init_termios(o_tty);

/*

* Everything allocated ... set up the o_tty structure.

*/

driver->other->ttys[idx] = o_tty;

tty_driver_kref_get(driver->other);

if (driver->subtype == PTY_TYPE_MASTER)

o_tty->count++;

/* Establish the links in both directions */

tty->link   = o_tty;

o_tty->link = tty;

tty_driver_kref_get(driver);

tty->count++;

driver->ttys[idx] = tty;

return 0;

}

2.3 pty 设备的写操作:写数据到虚拟设备对的另一端 /*pty 设备的写操作:写数据到虚拟设备对的另一端*/

/**

*    pty_write        -    write to a pty

*    @tty: the tty we write from

*    @buf: kernel buffer of data

*    @count: bytes to write

*

*    Our "hardware" write method. Data is coming from the ldisc which

*    may be in a non sleeping state. We simply throw this at the other

*    end of the link as if we were an IRQ handler receiving stuff for

*    the other side of the pty/tty pair.

*/

static int pty_write(struct tty_struct *tty, const unsigned char *buf, int c)

{

struct tty_struct *to = tty->link;

if (tty->stopped)

return 0;

if (c > 0) {

/* Stuff the data into the input queue of the other end */

c = tty_insert_flip_string(to, buf, c);

/* And shovel */

if (c) {

tty_flip_buffer_push(to);

tty_wakeup(tty);

}

}

return c;

}

2.4 pty 设备的读操作:虚拟设备的另一端会写数据到 readbuffe /*pty 设备的读操作:虚拟设备的另一端会写数据到 readbuffer*/

也就是说函数tty_insert_flip_string等被调用

3 使用虚拟串口的例子:

3.1] 打开master side 端口:cat ptypb & 注意打开 slave side port 会失败,为什么请查一下?

3.1.1  如果先打开slave port的例子 root@android:/dev # cat ttyp6

pty_open: should open master first, otherwise error

/system/bin/sh: cat: ttyp6: I/O error

root@android:/dev # cat ptyp6

3.1.2 为什么先打开slave 出错 pty_install -> /*如果打开pty设备的类型是 master,则 count++*/

if (driver->subtype == PTY_TYPE_MASTER)

o_tty->count++;

pty_open -> /*如果pty对的另一方 count != 1, 则 return error*/

if (tty->link->count != 1){

pr_err("pty_open: should open master first, otherwise error\n");

goto out;

}

3.2] 打开slave side 端口cat > ttypb root@android:/dev # cat > ttypb

3.3] 输入: 在ttypb设备上输入,在设备ptypb就读出相同的内容

qqq

qqq

qqq

qqq

111111

111111

4444

4444

3.4]另外使用echo "xxxx" > ptypb 虽然写入设备,但是写完后就关闭了设备,不能使用这种方法,只能使用cat

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值