TTY驱动分层思想

上中下三层

底层部分: uart层
关注UART或者其他底层串行硬件特征的底层驱动程序

中间层部分:即tty驱动层
和底层驱动程序接口的tty驱动程序层,将上层驱动程序和形形色色的硬件进行了隔离

上层部分:ldisc 线路规划层
加工用于和tty驱动程序交换数据的线路规程

关系:
底层UART驱动 与 TTY驱动 负责从硬件是哪个收发数据,而上层线路规程驱动负责处理这些数据,并在内核空间与用户空间之间传递数据。


底层部分: uart驱动层
关注UART或者其他底层串行硬件特征的底层驱动程序

drivers\tty\serial\tty_virtual.c

static struct uart_ops ttyx_ops = {
        .tx_empty=       ttyx_tx_empty,
        .set_mctrl=     ttyx_set_mctrl,
        .get_mctrl=     ttyx_get_mctrl,
        .stop_tx=        ttyx_stop_tx,
        .start_tx=       ttyx_start_tx,
        .stop_rx=        ttyx_stop_rx,
        .enable_ms=      ttyx_enable_ms,
        .break_ctl=      ttyx_break_ctl,
        .startup=        ttyx_startup,
        .shutdown=       ttyx_shutdown,
		.set_termios=    ttyx_termios,
        .type=           ttyx_type,
        .release_port=   ttyx_release_port,
        .request_port=   ttyx_request_port,
        .config_port=    ttyx_config_port,
        .verify_port=    ttyx_verify_port,
};


static struct uart_driver ttyx_uart_driver = {


        owner:                  THIS_MODULE,
        major:        		 	SERIAL_TTYX_MAJOR,
        driver_name:            "ttyx",
        dev_name:               "ttyx",
        minor:                  MINOR_START,
        nr:                     NR_PORTS,
        cons:                   NULL
};


static int vtty_probe(struct platform_device *pdev)
{
    unsigned char i;
	int ret=0;
	
	printk(KERN_ALERT "%s!!--in--\n", __func__);

	ret=uart_register_driver(&ttyx_uart_driver);
	if (ret)
	{
    	printk(KERN_ERR "Couldn't register ttyx uart driver\n");
    	return ret;
	}
	
	for(i =0;i<NR_PORTS;i++)
	{
    	struct ttyvx_port *s = &ttyxs[i];
    	s->port.line     = i;
    	s->port.ops      = &ttyx_ops;
    	s->port.uartclk  = CRASTAL_CLK;
    	s->port.fifosize = TXFIFO_SIZE; 
    	s->port.iobase   = i+1;
    	s->port.iotype   = SERIAL_IO_PORT;
		//该属性 需要设置 UPF_FIXED_PORT 位。否则 注册过程中 会将 s->port.type强制设置为 空 !!!
    	s->port.flags    = UPF_FIXED_PORT;// ASYNC_BOOT_AUTOCONF
		s->port.type = PORT_HONGDIAN;
    	ret = uart_add_one_port(&ttyx_uart_driver, &s->port);
   		if(ret<0)
   		{
    		printk(KERN_ALERT "uart_add_one_port failed for line i:= %d with error %d\n",i,ret);
   		}else{
   			printk(KERN_INFO "uart_add_one_port success for line i:= %d with right %d\n",i,ret);
   		}
	}

	return 0;
}

中间层部分:即tty驱动层
和底层驱动程序接口的tty驱动程序层,将上层驱动程序和形形色色的硬件进行了隔离

serial_core.c

struct uart_port {
	...
	const struct uart_ops	*ops;
}

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,
#endi
}



int uart_register_driver(struct uart_driver *drv)
{
	
	struct tty_driver *normal;
	int i, retval;

	BUG_ON(drv->state);

	/*
	 * Maybe we should be using a slab cache for this, especially if
	 * we have a large number of ports to handle.
	 */
	drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);
	if (!drv->state)
		goto out;

	normal = alloc_tty_driver(drv->nr);
	if (!normal)
		goto out_kfree;


	drv->tty_driver = normal;

	normal->driver_name	= drv->driver_name;
	normal->name		= drv->dev_name;
	normal->major		= drv->major;
	normal->minor_start	= drv->minor;
	normal->type		= TTY_DRIVER_TYPE_SERIAL;
	normal->subtype		= SERIAL_TYPE_NORMAL;
	normal->init_termios	= tty_std_termios;
	normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
	normal->init_termios.c_ispeed = normal->init_termios.c_ospeed = 9600;
	normal->flags		= TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
	normal->driver_state    = drv;
	tty_set_operations(normal, &uart_ops);

	/*
	 * Initialise the UART state(s).
	 */
	for (i = 0; i < drv->nr; i++) {
		struct uart_state *state = drv->state + i;
		struct tty_port *port = &state->port;

		tty_port_init(port);
		port->ops = &uart_port_ops;
	}

	retval = tty_register_driver(normal);
	if (retval >= 0){
	return retval;

	}
		

	for (i = 0; i < drv->nr; i++)
		tty_port_destroy(&drv->state[i].port);
	put_tty_driver(normal);
out_kfree:
	kfree(drv->state);
out:
	return -ENOMEM;
}

上层部分:ldisc 线路规划层
加工用于和tty驱动程序交换数据的线路规程

drivers\tty\n_tty.c

struct tty_ldisc_ops {
....
	int	(*open)(struct tty_struct *);
	void	(*close)(struct tty_struct *);
	void	(*flush_buffer)(struct tty_struct *tty);
	ssize_t	(*chars_in_buffer)(struct tty_struct *tty);
	ssize_t	(*read)(struct tty_struct *tty, struct file *file,
			unsigned char __user *buf, size_t nr);
	ssize_t	(*write)(struct tty_struct *tty, struct file *file,
	...
};

struct tty_ldisc {
	struct tty_ldisc_ops *ops;
	struct tty_struct *tty;
};


struct tty_ldisc_ops tty_ldisc_N_TTY = {
	.magic           = TTY_LDISC_MAGIC,
	.name            = "n_tty",
	.open            = n_tty_open,
	.close           = n_tty_close,
	.flush_buffer    = n_tty_flush_buffer,
	.chars_in_buffer = n_tty_chars_in_buffer,
	.read            = n_tty_read,
	.write           = n_tty_write,
	.ioctl           = n_tty_ioctl,
	.set_termios     = n_tty_set_termios,
	.poll            = n_tty_poll,
	.receive_buf     = n_tty_receive_buf,
	.write_wakeup    = n_tty_write_wakeup,
	.fasync		 = n_tty_fasync,
	.receive_buf2	 = n_tty_receive_buf2,
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Linux老A

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值