TTY驱动在注册时绑定的操作符关系

本文详细解析了串口在Linux系统中从应用层到驱动层的操作流程,包括tty_io.c层的系统调用描述符tty_fops,以及nuc970_serial.c和n_gsm.c驱动注册时绑定的不同操作描述符uart_ops和gsmtty_ops,阐述了应用层如何通过主、次设备号匹配到具体驱动并调用其接口。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. tty_io.c层的操作描述符

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. nuc972_serial.c驱动注册

//对应驱动层操作,它的上一层是系统调用 tty_io.c的tty_fops
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
};
nuc970_serial.c驱动注册流程:
nuc970serial_init
	uart_register_driver(&nuc970serial_reg)
	uart_register_driver(struct uart_driver *drv)
		struct tty_driver *normal;
		normal = alloc_tty_driver(drv->nr);
		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);  //注意驱动绑定的是 uart_ops
		tty_register_driver(normal);
		tty_register_driver(struct tty_driver *driver)
			tty_cdev_add(driver, dev, 0, driver->num);
				cdev_init(&driver->cdevs[index], &tty_fops); //tty_fops这个操作接口对应的是系统调用时的接口
				list_add(&driver->tty_drivers, &tty_drivers);

3. n_gsm.c驱动注册

//n_gsm.c的驱动层操作,它的上一层对应tty_io.c tty_fops
static const struct tty_operations gsmtty_ops = {
	.install		= gsmtty_install,
	.open			= gsmtty_open,
	.close			= gsmtty_close,
	.write			= gsmtty_write,
	.write_room		= gsmtty_write_room,
	.chars_in_buffer	= gsmtty_chars_in_buffer,
	.flush_buffer		= gsmtty_flush_buffer,
	.ioctl			= gsmtty_ioctl,
	.throttle		= gsmtty_throttle,
	.unthrottle		= gsmtty_unthrottle,
	.set_termios		= gsmtty_set_termios,
	.hangup			= gsmtty_hangup,
	.wait_until_sent	= gsmtty_wait_until_sent,
	.tiocmget		= gsmtty_tiocmget,
	.tiocmset		= gsmtty_tiocmset,
	.break_ctl		= gsmtty_break_ctl,
};
//n_gsm.c的注册流程
gsm_init
	static struct tty_driver *gsm_tty_driver;
	gsm_tty_driver = alloc_tty_driver(256);	
	gsm_tty_driver->driver_name	= "gsmtty";
	gsm_tty_driver->name		= "gsmtty";
	gsm_tty_driver->major		= 0;	/* Dynamic */
	gsm_tty_driver->minor_start	= 0;
	gsm_tty_driver->type		= TTY_DRIVER_TYPE_SERIAL;
	gsm_tty_driver->subtype	= SERIAL_TYPE_NORMAL;
	gsm_tty_driver->flags	= TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV
						| TTY_DRIVER_HARDWARE_BREAK;
	gsm_tty_driver->init_termios	= tty_std_termios; 
	/* Fixme */
	gsm_tty_driver->init_termios.c_lflag &= ~ECHO;
    
	tty_set_operations(gsm_tty_driver, &gsmtty_ops); //注意驱动绑定的是 gsmtty_ops
	
	tty_register_driver(gsm_tty_driver)
		tty_cdev_add(driver, dev, 0, driver->num);
			cdev_init(&driver->cdevs[index], &tty_fops); //tty_fops这个操作接口对应的是系统调用时的接口
			list_add(&driver->tty_drivers, &tty_drivers); //

4. 总结

所以应用层在打开一个串口的时候先调用tty_io.c,即ops描述符为 tty_fops,再到下一层即为驱动注册时绑定的ops描述符,
如果为nuc970_serial.c驱动,则是 uart_ops,所以调用的顺序为 tty_fops-->uart_ops;
如果为n_gsm.c驱动,则是 gsmtty_ops,所以调用的顺序为 tty_fops-->gsmtty_ops;

比如你在打开一个串口,调用的顺序是tty_open[tty_io.c ]-->通过主、次设备号匹配到对应的驱动driver = tty_lookup_driver(device, filp, &noctty, &index)-->然后在是调用驱动的接口操作。tty->ops->open(tty, filp)[gsmtty_ops或者uart_ops]
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值