精华内容
下载资源
问答
  • 2021-05-13 18:45:40

    在设备开发中,常用到基于USB的虚拟串口,此类接口在linux平台上被枚举为ttyUSB设备。

    当有多个ttyUSB设备时,常常导致分不清是哪个功能接口。

    其实还是可以很容易分出来的,在sysfs中通过以下步骤查看可以轻而易举的搞得一清二楚。

    查看sys目录,会看到bus子目录

    /#: ls /sys

    block     class     devices   firmware  kernel    pmu       zte

    bus       dev       dwc_usb   fs        module    power

    查看bus子目录,会有USB子目录

    /#: ls /sys/bus

    clocksource  i2c          rpmsg_zx29   serio        usb

    cpu          platform     scsi         spi          usb-serial

    查看USB子目录,会有devices和drivers子目录

    / # ls sys/bus/usb

    devices            drivers_autoprobe  uevent

    drivers            drivers_probe

    在devices目录下,即是所有的USB设备

    / # ls sys/bus/usb/devices

    1-0:1.0  1-1      1-1:1.0  1-1:1.1  1-1:1.2  1-1:1.3  1-1:1.4  1-1:1.6  usb1

    任选一个查看,比如选择1-1:1.2,可以看到该设备的诸多属性

    / # ls sys/bus/usb/devices/1-1:1.2

    bAlternateSetting     driver                subsystem

    bInterfaceClass       ep_03                 supports_autosuspend

    bInterfaceNumber      ep_83                 ttyUSB0

    bInterfaceProtocol    interface             uevent

    bInterfaceSubClass    modalias

    bNumEndpoints         power

    同时可以看到,它所对应的ttyUSB设备是ttyUSB0,但是这个是哪个接口,是什么功能呢?

    其实1-1:1.2这个名字已经表明了是接口2,但是对于普通人来说很难去记,还是进一步查看确认一下才好。查看接口号:

    bInterfaceNumber代表接口号,可以看到是02

    / # cat sys/bus/usb/devices/1-1:1.2/bInterfaceNumber

    02

    查看对应的功能接口描述,interface代表功能接口描述,可以看到是USB-AT,表明是AT口

    / # cat sys/bus/usb/devices/1-1:1.2/interface

    USB-AT

    由此可知,ttyUSB0对应的是AT口。

    其他的所有接口也可以通过该方法查看。

    更多相关内容
  • LinuxTTY

    2021-12-16 16:07:37
    LinuxTTY1.串行端口终端(/dev/ttySn)2.虚拟终端(/dev/pty/)3.控制终端(/dev/tty)4.控制台终端(/dev/ttyn, /dev/console)5.其它类型 终端是一种字符型设备,它有多种类型,通常使用tty来简称各种类型的终端...


    终端是一种字符型设备,它有多种类型,通常使用tty来简称各种类型的终端设备。
    tty是Teletype的缩写。Teletype是最早出现的一种终端 设备,很象电传打字机,是由Teletype公司生产的。设备名放在特殊文件目录/dev/下,终端特殊设备文件一般有以下几种:

    1.控制终端(/dev/tty)

    tty是所有终端的统称,包括串口、控制台终端以及伪终端设备。通过tty命令可以知道当前具体是什么终端(所以tty也代表当前的终端,echo hello > /dev/tty都会显示在当前的终端中,可能是上面的任意一种终端)。/dev/tty是当前进程的控制终端的设备文件,可以使用命令”ps –ax”来查看进程与哪个控制终端相连。

    对于你登录的shell,/dev/tty就是你使用的终端,设备号是(5,0)。使用命令”tty”可以查看它 具体对应哪个实际终端设备。/dev/tty有些类似于到实际所使用终端设备的一个联接。

    2.串行端口终端(/dev/ttySn)

    串行端口终端(Serial Port Terminal)是使用计算机串行端口连接的终端设备。

    计算机把每个串行端口都看作是一个字符设备。有段时间这些串行端口设备通常被称为终端设备,因为 那时它的最大用途就是用来连接终端。这些串行端口所对应的设备名称是/dev/ttyS0(或/dev/tts/0)、/dev /ttyS1(或/dev/tts/1)等,分别对应于DOS系统下的COM1、COM2等。

    若要向一个端口发送数据,可以在命令行上把标准输出重定向到这些特殊文件名上即可。例如,在命令行提示符下键入:echo test > /dev/ttyS1会把单词”test”发送到连接在ttyS1(COM2)端口的设备上。

    3.虚拟终端(/dev/pty/)

    虚拟终端(dev/pts/n)或者叫伪终端,是成对的逻辑终端设备,例如/dev/pty/n(或着在设备文件系统中是 /dev/ptyn和/dev/ttypn)。

    远程登陆的用户,就是使用telnet、ssh等远程登陆的用户,他的终端显示就是pts/n。pts是pty的实现方法,与ptmx配合使用实现pty。

    4.控制台终端(/dev/ttyn, /dev/console)

    在 UNIX系统中,计算机显示器通常被称为控制台终端(Console)。它仿真了类型为Linux的一种终端(TERM=Linux),并且有一些设备特 殊文件与之相关联:tty0、tty1、tty2等。当你在控制台上登录时,使用的是tty1。使用Alt+[F1—F6]组合键时,我们就可以切换到 tty2、tty3等上面去。tty1 –tty6等称为虚拟终端,而tty0则是当前所使用虚拟终端的一个别名,系统所产生的信息会发送到该终端上。因此不管当前正在使用哪个虚拟终端,系统信息都会发送到控制台终端上。

    你可以登录到不同的虚拟终端上去,因而可以让系统同时有几个不同的会话期存在。只有系统或超级用户root可以向/dev/tty0进行写操作,

    5.其它类型

    还针对很多不同的字符设备存在有很多其它种类的终端设备特殊文件。例如针对ISDN设备的/dev/ttyIn终端设备等。这里不再赘述。

    展开全文
  • 这就是我们今天要讨论的问题Tty架构如下所示:如上图所示,用户空间主要是通过设备文件同tty_core交互.tty_core根据用空间操作的类型再选择跟linediscipline和tty_driver交互.例如设置硬件的ioctl指令就直接交给tty_...
  • linux虚拟tty驱动(kernel4.9版本以上),可产生多个tty串口设备于/dev/下,本人在Hi3516上交叉编译并应用,实现多个虚拟串口同时控制一个实际串口的操作
  • 什么是TTY https://blog.csdn.net/goooooooooo/article/details/1302301?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522164226408016780255250096%2522%252C%2522scm%2522%253A%252220140713.130102334...

    什么是TTY
    https://blog.csdn.net/goooooooooo/article/details/1302301?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522164226408016780255250096%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=164226408016780255250096&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduend~default-1-1302301.first_rank_v2_pc_rank_v29&utm_term=tty&spm=1018.2226.3001.4187

    命令行界面、终端、Shell、TTY,都是什么呢?

    https://blog.csdn.net/weixin_44709571/article/details/88539064?ops_request_misc=&request_id=&biz_id=102&utm_term=windows%E4%B8%8Btty&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduweb~default-8-88539064.first_rank_v2_pc_rank_v29&spm=1018.2226.3001.4187

    linux+getty+串口_linux下tty,控制台,虚拟终端,串口,console(控制台终端)详解…

    https://blog.csdn.net/weixin_35916518/article/details/112923681?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522164226447316780274120700%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=164226447316780274120700&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_ecpm_v1~rank_v31_ecpm-7-112923681.first_rank_v2_pc_rank_v29&utm_term=windows%E4%B8%8Btty&spm=1018.2226.3001.4187

    tty文件命令 linux,Linux命令学习手册-tty命令

    https://blog.csdn.net/weixin_36462094/article/details/116550275?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522164226447316780274120700%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=164226447316780274120700&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_ecpm_v1~rank_v31_ecpm-11-116550275.first_rank_v2_pc_rank_v29&utm_term=windows%E4%B8%8Btty&spm=1018.2226.3001.4187

    linux下/dev/tty, /dev/tty0, /dev/console区别

    https://blog.csdn.net/lqxandroid2012/article/details/78924840?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522164226447316780274120700%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=164226447316780274120700&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_ecpm_v1~rank_v31_ecpm-14-78924840.first_rank_v2_pc_rank_v29&utm_term=windows%E4%B8%8Btty&spm=1018.2226.3001.4187

    展开全文
  • 对于Linux内核tty设备的一点理解,可以初学者更加的理解linux下的TTY
  • Linux系统TTY串口驱动实例详解

    千次阅读 2022-03-18 16:15:48
    tty核心是对整个tty设备的抽象,对用户提供统一的接口,tty线路规程是对传输数据的格式化,tty驱动则是面向tty设备的硬件驱动。它们的关系如下图: 简单来分的话可以说成两层,一层是下层我们的串口驱动层,它直接与...

    简介

    在Linux系统中,终端是一类字符型设备,它包括多种类型,通常使用tty来简称各种类型的终端设备。由于串口也是一种终端,因此这里引入终端这个概念 。
    Linux tty子系统包含:tty核心,tty线路规程和tty驱动。tty核心是对整个tty设备的抽象,对用户提供统一的接口,tty线路规程是对传输数据的格式化,tty驱动则是面向tty设备的硬件驱动。它们的关系如下图:
    在这里插入图片描述
    简单来分的话可以说成两层,一层是下层我们的串口驱动层,它直接与硬件相接触,我们需要填充一个 struct uart_ops 的结构体,另一层是上层 tty 层,包括 tty 核心以及线路规程,它们各自都有一个 ops 结构,用户空通过间是 tty 注册的字符设备节点来访问,这么说来如上图所示涉及到了4个 ops 结构了,层层跳转。下面,就来分析分析它们的层次结构。

    源码详解

    从整个串口驱动注册程序来看,该程序只做了两件事:
    1、注册uart_driver;
    2、注册platform_driver,也就是uart_add_one_port();
    具体请细看下面的源码分析:
    一、uart_driver的注册:
    在 s3c2440 平台,它是这样来注册串口驱动的,分配一个struct uart_driver 简单填充,并调用uart_register_driver 注册到内核中去。

    static struct uart_driver s3c24xx_uart_drv = {
    	.owner		= THIS_MODULE,
    	.dev_name	= "s3c2410_serial",
    	.nr		= CONFIG_SERIAL_SAMSUNG_UARTS,
    	.cons		= S3C24XX_SERIAL_CONSOLE,
    	.driver_name	= S3C24XX_SERIAL_NAME,
    	.major		= S3C24XX_SERIAL_MAJOR,
    	.minor		= S3C24XX_SERIAL_MINOR,
    };
    static int __init s3c24xx_serial_modinit(void)
    {
    	int ret;
     
    	ret = uart_register_driver(&s3c24xx_uart_drv);
    	if (ret < 0) {
    		printk(KERN_ERR "failed to register UART driver\n");
    		return -1;
    	}
     
    	return 0;
    }
    

    uart_driver 中,我们只是填充了一些名字、设备号等信息,这些都是不涉及底层硬件访问的,那是怎么回事呢?来看一下完整的 uart_driver 结构或许就明白了。

    struct uart_driver {
    	struct module		*owner;	/* 拥有该uart_driver的模块,一般为THIS_MODULE */
    	const char		*driver_name;	/* 串口驱动名,串口设备文件名以驱动名为基础 */
    	const char		*dev_name;	/* 串口设备名 */
    	int			 major;			/* 主设备号 */
    	int			 minor;			/* 次设备号 */
    	int			 nr;			/* 该uart_driver支持的串口个数(最大) */
    	struct console		*cons;	/* 其对应的console.若该uart_driver支持serial console,否则为NULL */
     
    	/* 下面这俩,初始化为NULL */
    	struct uart_state	*state;	/* 下层,串口驱动层 */
    	struct tty_driver	*tty_driver;	/* tty相关 */
    };
    

    在我们上边填充的结构体中,有两个成员未被赋值,对于tty_driver 代表的是上层,它会在 register_uart_driver 中的过程中赋值,而uart_state 则代表下层,uart_state 也会在register_uart_driver 的过程中分配空间,但是它里面真正设置硬件相关的东西是 uart_state->uart_port ,这个uart_port 是需要我们从其它地方调用 uart_add_one_port 来添加的。

    下面先分析串口驱动层的uart_state:

    struct uart_state {
    	struct tty_port		port;
     
    	int			pm_state;
    	struct circ_buf		xmit;
    	struct tasklet_struct	tlet;
    	struct uart_port	*uart_port;	// 对应于一个串口设备
    };
    

    分配空间uart_driver->uart_state[nr]空间,即申请 nr 个 uart_state 空间,用来存放驱动所支持的串口(端口)的物理信息;

    struct uart_port {
    	spinlock_t		lock;			/* port lock */
    	unsigned long		iobase;			/* io端口基地址(物理) */
    	unsigned char __iomem	*membase;		/* io内存基地址(虚拟) */
    	unsigned int		(*serial_in)(struct uart_port *, int);
    	void			(*serial_out)(struct uart_port *, int, int);
    	unsigned int		irq;			/* 中断号 */
    	unsigned long		irqflags;		/* 中断标志  */
    	unsigned int		uartclk;		/* 串口时钟 */
    	unsigned int		fifosize;		/* 串口缓冲区大小 */
    	unsigned char		x_char;			/* xon/xoff char */
    	unsigned char		regshift;		/* 寄存器位移 */
    	unsigned char		iotype;			/* IO访问方式 */
    	unsigned char		unused1;
     
    	unsigned int		read_status_mask;	/* 关心 Rx error status */
    	unsigned int		ignore_status_mask;	/* 忽略 Rx error status */
    	struct uart_state	*state;			/* pointer to parent state */
    	struct uart_icount	icount;			/* 串口信息计数器 */
     
    	struct console		*cons;			/* struct console, if any */
    #if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(SUPPORT_SYSRQ)
    	unsigned long		sysrq;			/* sysrq timeout */
    #endif
     
    	upf_t			flags;
     
    	unsigned int		mctrl;			/* 当前的Moden 设置 */
    	unsigned int		timeout;		/* character-based timeout */
    	unsigned int		type;			/* 端口类型 */
    	const struct uart_ops	*ops;		/* 串口端口操作函数 */
    	unsigned int		custom_divisor;
    	unsigned int		line;			/* 端口索引 */
    	resource_size_t		mapbase;		/* io内存物理基地址 */
    	struct device		*dev;			/* 父设备 */
    	unsigned char		hub6;			/* this should be in the 8250 driver */
    	unsigned char		suspended;
    	unsigned char		unused[2];
    	void			*private_data;		/* generic platform data pointer */
    };
    

    这个结构体,是需要我们自己来填充的,比如我们 s3c2440 有3个串口,那么就需要填充3个 uart_port ,并且通过 uart_add_one_port 添加uart_driver->uart_state->uart_port 中去。当然 uart_driver 有多个 uart_state ,每个 uart_state 有一个 uart_port 。在 uart_port 里还有一个非常重要的成员 struct uart_ops *ops ,这个也是需要我们自己来实现的,后面代码会详细分析从用户层到硬件层是如何一步步通过ops进行调用的。

    struct uart_ops {
    	unsigned int	(*tx_empty)(struct uart_port *);	 /* 串口的Tx FIFO缓存是否为空 */
    	void		(*set_mctrl)(struct uart_port *, unsigned int mctrl);	/* 设置串口modem控制 */
    	unsigned int	(*get_mctrl)(struct uart_port *);	/* 获取串口modem控制 */
    	void		(*stop_tx)(struct uart_port *);		/* 禁止串口发送数据 */
    	void		(*start_tx)(struct uart_port *);	/* 使能串口发送数据 */	
    	void		(*send_xchar)(struct uart_port *, char ch);	/* 发送xChar */
    	void		(*stop_rx)(struct uart_port *);		/* 禁止串口接收数据 */
    	void		(*enable_ms)(struct uart_port *);	/* 使能modem的状态信号 */
    	void		(*break_ctl)(struct uart_port *, int ctl);	/* 设置break信号 */
    	int			(*startup)(struct uart_port *);		/* 启动串口,应用程序打开串口设备文件时,该函数会被调用 */
    	void		(*shutdown)(struct uart_port *);/* 关闭串口,应用程序关闭串口设备文件时,该函数会被调用 */
    	void		(*flush_buffer)(struct uart_port *);
    	void		(*set_termios)(struct uart_port *, struct ktermios *new,
    				       struct ktermios *old);	/* 设置串口参数 */
    	void		(*set_ldisc)(struct uart_port *);/* 设置线路规程 */
    	void		(*pm)(struct uart_port *, unsigned int state,
    			      unsigned int oldstate);	/* 串口电源管理 */
    	int		    (*set_wake)(struct uart_port *, unsigned int state);
     
    	/*
    	 * Return a string describing the type of the port
    	 */
    	const char *(*type)(struct uart_port *);
     
    	/*
    	 * Release IO and memory resources used by the port.
    	 * This includes iounmap if necessary.
    	 */
    	void		(*release_port)(struct uart_port *);
     
    	/*
    	 * Request IO and memory resources used by the port.
    	 * This includes iomapping the port if necessary.
    	 */
    	int		(*request_port)(struct uart_port *);	/* 申请必要的IO端口/IO内存资源,必要时还可以重新映射串口端口 */
    	void		(*config_port)(struct uart_port *, int); /* 执行串口所需的自动配置 */
    	int		(*verify_port)(struct uart_port *, struct serial_struct *); /* 核实新串口的信息 */
    	int		(*ioctl)(struct uart_port *, unsigned int, unsigned long);
    #ifdef CONFIG_CONSOLE_POLL
    	void	(*poll_put_char)(struct uart_port *, unsigned char);
    	int		(*poll_get_char)(struct uart_port *);
    #endif
    };
    

    2、上层tty_core层
    tty 层要从 register_uart_driver 来看起了,因为 tty_driver 是在注册过程中构建的,我们也就顺便了解了注册过程。

    int uart_register_driver(struct uart_driver *drv)
    {
    	struct tty_driver *normal = NULL;
    	int i, retval;
     
     
    	/* 根据driver支持的最大设备数,申请n个 uart_state 空间,每一个 uart_state 都有一个uart_port */
    	drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);
    	
    	/* tty层:分配一个 tty_driver ,并将drv->tty_driver 指向它 */
    	normal  = alloc_tty_driver(drv->nr);
    	drv->tty_driver = normal;
    	
    	/* 对 tty_driver 进行设置 */
    	normal->owner		= drv->owner;
    	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;	/* driver->state->tty_port */
     
    		tty_port_init(port);
    		port->close_delay     = 500;	/* .5 seconds */
    		port->closing_wait    = 30000;	/* 30 seconds */
    		/* 初始化 tasklet */
    		tasklet_init(&state->tlet, uart_tasklet_action,
    			     (unsigned long)state);
    	}
    	
    	/* tty层:注册 driver->tty_driver */
    	retval = tty_register_driver(normal);
     
    }
     
    

    uart_register_driver(&s3c24xx_uart_drv)注册驱动时会有下面几个操作:
    1、分配空间uart_driver->uart_state[nr]空间,即申请 nr 个 uart_state 空间,用来存放驱动所支持的串口(端口)的物理信息;
    2、分配tty_driver,将dev_name/major/minor/nr赋值给tty_driver;
    3、设置ty_core层的ops为strucy tty_operations uart_ops,设置flags为TTY_DRIVER_REAL_RAM|TTY_DRIVER_DYNAMIC_DEV;
    4、初始化tty_port:uart_driver->uart_state[nr]->tty_port,如ttybuffer、flush_to_ldisc、tty_port->ops=&uart_port_ops(struct uart_port_ops uart_port_ops);
    5、注册tty_driver,后面从源码中可以分析出uart驱动的注册,实际就是tty_driver的注册,都是将uart的参数传给tty_driver,然后注册字符设备、分配设备文件、将驱动写进总线管理的tty_driver链表中;

    注:从代码可以看到uart_register_drive()函数中最终要调用tty_register_driver()函数来注册tty驱动,因此与用户空间打交道的工作完全交给了 tty_driver ,而且这一部分都是内核实现好的,我们不需要修改,了解一下工作原理即可;

    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,	// 当termios设置被改变时又tty核心调用
    	.set_ldisc	= uart_set_ldisc,		// 设置线路规程函数
    	.stop		= uart_stop,	
    	.start		= uart_start,
    	.hangup		= uart_hangup,		// 挂起函数,当驱动挂起tty设备时调用
    	.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,	// 获得当前tty的线路规程的设置
    	.tiocmset	= uart_tiocmset,	// 设置当前tty线路规程的设置
    #ifdef CONFIG_CONSOLE_POLL
    	.poll_init	= uart_poll_init,
    	.poll_get_char	= uart_poll_get_char,
    	.poll_put_char	= uart_poll_put_char,
    #endif
    };
    

    这个是 tty 核心的 ops ,简单一看,后面分析调用关系时,我们在来看具体的里边的函数,下面来看 tty_driver 的注册。

    int tty_register_driver(struct tty_driver *driver)
    {
    	int error;
    	int i;
    	dev_t dev;
    	void **p = NULL;
     
    	if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) {
    		p = kzalloc(driver->num * 2 * sizeof(void *), GFP_KERNEL);
    	}
    	
    	/* 如果没有主设备号则申请 */
    	if (!driver->major) {
    		error = alloc_chrdev_region(&dev, driver->minor_start,
    						driver->num, driver->name);
    	} else {
    		dev = MKDEV(driver->major, driver->minor_start);
    		error = register_chrdev_region(dev, driver->num, driver->name);
    	}
     
    	if (p) { /* 为线路规程和termios分配空间 */
    		driver->ttys = (struct tty_struct **)p;
    		driver->termios = (struct ktermios **)(p + driver->num);
    	} else {
    		driver->ttys = NULL;
    		driver->termios = NULL;
    	}
     
    	/* 创建字符设备,使用 tty_fops */
    	cdev_init(&driver->cdev, &tty_fops);
    	driver->cdev.owner = driver->owner;
    	error = cdev_add(&driver->cdev, dev, driver->num);
     
    	mutex_lock(&tty_mutex);
    	
    	/* 将该 driver->tty_drivers 添加到全局链表 tty_drivers */
    	list_add(&driver->tty_drivers, &tty_drivers);
    	mutex_unlock(&tty_mutex);
     
    	if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) {
    		for (i = 0; i < driver->num; i++)
    		    tty_register_device(driver, i, NULL);
    	}
    	
    	/* 向proc文件系统注册driver */
    	proc_tty_register_driver(driver);
    	driver->flags |= TTY_DRIVER_INSTALLED;
    	return 0;
    }
    

    从上面源码可以分析到:
    1、为线路规程和termios分配空间,并使 tty_driver 相应的成员指向它们。
    2、注册字符设备,名字是 uart_driver->name 我们这里是“ttySAC”,文件操作函数集是 tty_fops。
    3、将该 uart_driver->tty_drivers 添加到全局链表 tty_drivers 。
    4、向 proc 文件系统添加 driver。

    二、注册platform_driver驱动
    该函数就是实现将驱动挂到platform总线上去,总线接管设备和驱动的管理工作。

    int s3c24xx_serial_init(struct platform_driver *drv,
    			struct s3c24xx_uart_info *info)
    {
    	dbg("s3c24xx_serial_init(%p,%p)\n", drv, info);
     
    #ifdef CONFIG_PM
    	drv->suspend = s3c24xx_serial_suspend;
    	drv->resume = s3c24xx_serial_resume;
    #endif
     
    	return platform_driver_register(drv);
    }
    
    static void __exit s3c2440_serial_exit(void)
    {
    	platform_driver_unregister(&s3c2440_serial_driver);
    }
     
    module_init(s3c2440_serial_init);
    module_exit(s3c2440_serial_exit);
    

    然后我们分析一下platform_driver函数:

    static struct platform_driver s3c2440_serial_driver = {
        .probe        = s3c2440_serial_probe,
        .remove        = __devexit_p(s3c24xx_serial_remove),
        .driver        = {
            .name    = "s3c2440-uart",
            .owner    = THIS_MODULE,
        },
    };
    

    在平台设备注册驱动的时候,总线会对驱动和设备匹配,如果匹配成功,将调用驱动的prob函数,我们具体追一下s3c2440_serial_driver 的prob函数:

    int s3c24xx_serial_probe(struct platform_device *dev,
    			 struct s3c24xx_uart_info *info)
    {
    	struct s3c24xx_uart_port *ourport;
    	int ret;
     
    	dbg("s3c24xx_serial_probe(%p, %p) %d\n", dev, info, probe_index);
     
    	ourport = &s3c24xx_serial_ports[probe_index];
    	probe_index++;
     
    	dbg("%s: initialising port %p...\n", __func__, ourport);
     
    	ret = s3c24xx_serial_init_port(ourport, info, dev);
    	if (ret < 0)
    		goto probe_err;
     
    	dbg("%s: adding port\n", __func__);
    	uart_add_one_port(&s3c24xx_uart_drv, &ourport->port);
    	platform_set_drvdata(dev, &ourport->port);
     
    	ret = device_create_file(&dev->dev, &dev_attr_clock_source);
    	if (ret < 0)
    		printk(KERN_ERR "%s: failed to add clksrc attr.\n", __func__);
     
    	ret = s3c24xx_serial_cpufreq_register(ourport);
    	if (ret < 0)
    		dev_err(&dev->dev, "failed to add cpufreq notifier\n");
     
    	return 0;
     
     probe_err:
    	return ret;
    }
    

    我们来分析上面这段代码:
    这段代码首先从s3c24xx_serial_ports数组中寻找一个元素,这个数组里保存的是各个串口的信息。
    假如说找到了串口0,拿到串口0后调用s3c24xx_serial_init_port完成串口的初始化,看看初始化函数:

    /* s3c24xx_serial_init_port
     *
     * initialise a single serial port from the platform device given
     */
     
    static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
    				    struct s3c24xx_uart_info *info,
    				    struct platform_device *platdev)
    {
    	struct uart_port *port = &ourport->port;
    	struct s3c2410_uartcfg *cfg;
    	struct resource *res;
    	int ret;
     
    	dbg("s3c24xx_serial_init_port: port=%p, platdev=%p\n", port, platdev);
     
    	if (platdev == NULL)
    		return -ENODEV;
     
    	cfg = s3c24xx_dev_to_cfg(&platdev->dev);
     
    	if (port->mapbase != 0)
    		return 0;
     
    	if (cfg->hwport > CONFIG_SERIAL_SAMSUNG_UARTS) {
    		printk(KERN_ERR "%s: port %d bigger than %d\n", __func__,
    		       cfg->hwport, CONFIG_SERIAL_SAMSUNG_UARTS);
    		return -ERANGE;
    	}
     
    	/* setup info for port */
    	port->dev	= &platdev->dev;
    	ourport->info	= info;
     
    	/* copy the info in from provided structure */
    	ourport->port.fifosize = info->fifosize;
     
    	dbg("s3c24xx_serial_init_port: %p (hw %d)...\n", port, cfg->hwport);
     
    	port->uartclk = 1;
     
    	if (cfg->uart_flags & UPF_CONS_FLOW) {
    		dbg("s3c24xx_serial_init_port: enabling flow control\n");
    		port->flags |= UPF_CONS_FLOW;
    	}
     
    	/* sort our the physical and virtual addresses for each UART */
     
    	res = platform_get_resource(platdev, IORESOURCE_MEM, 0);// 取得物理地址
    	if (res == NULL) {
    		printk(KERN_ERR "failed to find memory resource for uart\n");
    		return -EINVAL;
    	}
     
    	dbg("resource %p (%lx..%lx)\n", res, res->start, res->end);
     
    	port->mapbase = res->start;
    	port->membase = S3C_VA_UART + res->start - (S3C_PA_UART & 0xfff00000); // 静态映射
    	ret = platform_get_irq(platdev, 0);
    	if (ret < 0)
    		port->irq = 0;
    	else {
    		port->irq = ret;
    		ourport->rx_irq = ret;
    		ourport->tx_irq = ret + 1;
    	}
    	
    	ret = platform_get_irq(platdev, 1);
    	if (ret > 0)
    		ourport->tx_irq = ret;
     
    	ourport->clk	= clk_get(&platdev->dev, "uart");
     
    	dbg("port: map=%08x, mem=%08x, irq=%d (%d,%d), clock=%ld\n",
    	    port->mapbase, port->membase, port->irq,
    	    ourport->rx_irq, ourport->tx_irq, port->uartclk);
     
    	/* reset the fifos (and setup the uart) */
    	s3c24xx_serial_resetport(port, cfg);
    	return 0;
    }
    

    上面代码主要完成3项工作:
    1、取串口的基地址
    2、取串口的中断号
    3、复位FIFO
    在回到s3c24xx_serial_probe函数,在初始化串口后,接下来完成下面的操作:
    1、添加端口uart_add_one_port
    2、添加属性文件,这样在sys下面就可以看到串口的信息了
    3、初始化动态频率调节s3c24xx_serial_cpufreq_register。

    至此uart_driver和platform_driver都已注册完毕,后续章节会细讲TTY驱动数据的收发过程。

    展开全文
  • Linux 终端(TTY)

    2021-11-24 00:01:11
    为了支持这些 TTY 设备Linux 实现了一个叫做 TTY 的子系统。所以 TTY 既指终端,也指 LinuxTTY 子系统,当然 TTY 还有更丰富(混乱)的含义,本文试图把它们解释清楚。本文中演示部分使用的环境为 ubuntu 18.04...
  • Linux 系统中,终端设备非常重要,没有终端设备,系统将无法向用户反馈信息,Linux中包含控制台、串口和伪终端3 类终端设备
  • 前言本文将从驱动工程师的角度去看TTY framework:它怎么抽象、管理各个TTY设备?它提供了哪些编程接口以方便TTY driver的开发?怎么利用这些接口编写一个TTY driver?等等。注1:话说介绍各个framework的时候,我...
  • Linux终端tty设备驱动

    2017-07-24 16:34:09
    Linux系统中,终端设备非常重要,没有终端设备,系统将无法向用户反馈信息,Linux中包含控制台、串口和伪终端3类终端设备
  • linux tty个数修改

    2020-12-21 10:28:09
    自动启用的tty@.service数量,默认为6指tty2-tty7 ReserveVT 不包含在NAutoVTs个数中,启用的tty@.service eg: NAutoVTs=3,ReserveVT=6表示启用tty2,3,7 + tty6 关于默认具体是哪个tty,系统不同可能有差异。 2...
  • 一键批量关闭 Linuxtty 的方法

    千次阅读 2019-11-04 16:26:08
    一键批量关闭 Linuxtty 的方法 一 背景 在日常工作中,由于各种原因,可能需要关闭一些不必要的 tty。比如:服务器被非法登录、忘记关闭某些设备上已登录的 tty、终止一些不使用的tty等场景就需要批量强制关闭 ...
  • Linuxtty设备介绍

    千次阅读 2018-12-17 21:13:29
    本文转载于:对于Linux内核tty设备的一点理解 目录 前言 一、终端按照其自身能力分类 二、linux系统的终端设备 1、 控制台 2、 伪终端pty(pseudo-tty) 3、 串口终端(/dev/ttySn) 4、 其它类型终端 三、...
  • 如何查看linux下串口是否可用?串口名称等? http://zhidao.baidu.com/question/419148559.html 查看串口是否可用,可以对串口发送数据比如对com1口,echo lyjie126 > /dev/ttyS0 查看串口名称使用 ls -l /dev/ttyS*...
  • linux 关闭终端 tty

    2021-05-12 16:24:17
    跟踪用 -o Read an old-type wtmp file (written by linux-libc5 applications). -n -n 或- 设置列出名单的显示列数 -w Display full user and domain names in the output -R 不显示登入系统的主机名称或IP(省略 ...
  • ttyLinux系统的设备特殊文件目录/dev/下。 终端特殊设备文件一般有以下几种: 1、串行端口终端(/dev/ttySn) 串行端口终端(Serial Port Terminal)是使用计算机串行端口连接的终端设备。计算机把每个串行端口都看作...
  •   在Linux系统中,终端是一种字符型设备,它有多种类型,通常使用tty来简称各种类型的终端设备tty是Teletype的缩写,Teletype是最早出现的一种终端设备,很像电传打字机,是由Teletype公司生产的。   Linux中...
  • 概述Linux TTY/PTS的区别

    2021-01-20 15:03:32
    在计算机出来以前,人们就已经在使用一种叫teletype的设备,用来相互之间传递信息,看起来像下面这样: +----------+ Physical Line +----------+ | teletype |<--------------------->| teletype | +-------...
  • 主要是:/dev/tty、/dev/ttyn、/dev/ttySn、/dev/ttyUSB*区别。 1、/dev/tty 当前控制终端Terminal 2、/dev/ttyn 和 /dev/...3、/dev/ttySn(一般为/dev/ttyS0) 串行端口终端,接串口线使用的端口设备 4、/dev...
  • Linux:减少tty数量

    2021-05-17 16:47:20
    在我们使用linux的时候,tty系统默认是给出7个,前六个是terminal,最后一个用于X。但是我们其实有些时候是使用不到那么多的tty,要改变tty数量可以通过修改/etc/inittab来实现,具体如下:[root@localhost ~]# cat ...
  • Linux下的tty和pts详解

    2022-03-17 11:08:11
    Linux下的tty和pts详解 今天在在使用who和ps命令的时候,出现tty1或者pts/0,因为不太懂就查了一下: 使用tty命令可以查看现在使用的终端标识; 使用ctrl+alt+[F1~F8]来切换操作终端 使用echo “test xxx” > ...
  • Linuxtty和pts指的是什么发布时间:2020-11-17 14:55:05来源:亿速云阅读:135...Linux中的tty表示终端设备的名称,是一种字符型设备,具有多种类型;pts指的是伪终端,当打开一个终端时为pts/0,再次打开一个终...
  • 对于tty设备的打开操作,即用户调用read函数来读取设备的文件的数据,首先经过vfs层、字符设备驱动层,到达tty_open()函数,经过tty_core层、serial_core等层后,主要完成一下工作: 1、首先通过dev_t,再tty_driver...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 52,334
精华内容 20,933
关键字:

linux 查看tty 设备