tty驱动初步了解学习

一、linux tty驱动框架

本人是linux驱动初学者,最近在初步学习uart驱动,在这记录下来自己的理解
linux3.10
soc:君正x1000e

四位大佬写的很好
https://blog.csdn.net/cosmoslhf/article/details/16945009
https://blog.csdn.net/lizuobin2/article/details/51801183
https://blog.csdn.net/Luckiers/article/details/123577836
https://blog.csdn.net/mike8825/article/details/107598833

在Linux kernel中,tty驱动不像于spi,iic等那么架构简单,它是一个庞大的系统,它的框架大体如下图一。我们作为普通的驱动开发移植人员,不会从零写tty驱动,一般都是厂家根据现有的tty驱动和自家芯片修改,拿到板子按照厂家的配置,串口应该使能直接使用的。但是开发的过程中也有可能需要用到串口,一般会修改serial驱动,这样我们不会动tty_core层。

Linux tty子系统包含:tty核心(tty_core),tty线路规程(tty_line_discipine)和tty驱动(tty_driver)。tty核心是对整个tty设备的抽象,对用户提供统一的接口,tty线路规程是对传输数据的格式化,tty驱动则是面向tty设备的硬件驱动。
图一在这里插入图片描述

二、uart驱动数据架构

1、主要用到的数据架构图二

图二
在这里插入图片描述
uart_driver描述uart设备,其他下面有2个重要的结构体uart_state(用于描述底层硬件信息),tty_drvier(tty层驱动)。
uart_driver结构体

struct uart_driver {
   
	struct module		*owner;
	const char		*driver_name;//串口驱动名字
	const char		*dev_name;//设备名字
	int			 major;
	int			 minor;
	int			 nr;
	struct console		*cons;

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

	 */
	struct uart_state	*state;//底层指定硬件参数
	struct tty_driver	*tty_driver;//tty层
};

一般来说一个芯片具有多个串口,比如君正x1000e具有3个串口,那uart_state应该有多个,每个保存一个串口信息。
tty_prot是TTY device的一种抽象

circ_buf是一个发送缓存,在写数据时,当tty层调用驱动提供的写函数时,数据会首先进入circ_buf的环形缓存区,然后由uart_port从缓存区中取数据,将其写入到串口设备中。
当uart_port从串口设备接收到数据时,它会直接将数据放入tty的缓存中(tty缓存属于tty_port),进而放入对应的line discipline的缓存区中。
在这里插入图片描述
uart_state结构体
uart_state中最重要的结构体成员uart_port
uart_state->uart_port(在这保存硬件串口信息)

truct uart_port {
   
	spinlock_t		lock;			/* port lock */
	unsigned long		iobase;			/* io基地址 */
	unsigned char __iomem	*membase;		/*内存基地址 */
	unsigned int		(*serial_in)(struct uart_port *, int);//串口接受函数指针
	void			(*serial_out)(struct uart_port *, int, int);//串口发送函数指针
	void			(*set_termios)(struct uart_port *,
				               struct ktermios *new,
				               struct ktermios *old);
	int			(*handle_irq)(struct uart_port *);
	void			(*pm)(struct uart_port *, unsigned int state,
				      unsigned int old);
	void			(*handle_break)(struct uart_port *);
	unsigned int		irq;			/* irq number */
	unsigned long		irqflags;		/* irq flags  */
	unsigned int		uartclk;		/* base uart clock */
	unsigned int		fifosize;		/* tx fifo size */
	unsigned char		x_char;			/* xon/xoff char */
	unsigned char		regshift;		/* reg offset shift */
	unsigned char		iotype;			/* io访问方式 */
	unsigned char		unused1;
....
	unsigned int		mctrl;			/* 当前控制模式*/
	unsigned int		timeout;		/* character-based timeout */
	unsigned int		type;			/* port type */
	const struct uart_ops	*ops;
	unsigned int		custom_divisor;
	unsigned int		line;			/* port index */
	resource_size_t		mapbase;		/* for ioremap */
	struct device		*dev;			/* parent device */
	unsigned char		hub6;			/* this should be in the 8250 driver */
	unsigned char		suspended;
	unsigned char		irq_wake;
	unsigned char		unused[2];
	void			*private_data;		/* generic platform data pointer */
};

tty_port结构体
保存着tty层驱动信息


struct tty_driver {
   
	int	magic;		/* magic number for this structure */
	struct kref kref;	/* Reference management */
	struct cdev *cdevs;
	struct module	*owner;
	const char	*driver_name;
	const char	*name;
	int	name_base;	/* offset of printed name */
	int	major;		/* major device number */
	int	minor_start;	/* start of minor device number */
	unsigned int	num;	/* number of devices allocated */
	short	type;		/* type of tty driver */
	short	subtype;	/* subtype of tty driver */
	struct ktermios init_termios; /* Initial termios */
	unsigned long	flags;		/* tty driver flags */
	struct proc_dir_entry *proc_entry; /* /proc fs entry */
	struct tty_driver *other; /* only used for the PTY driver */

	/*
	 * Pointer to the tty data structures
	 */
	struct tty_struct **ttys;
	struct tty_port **ports;
	struct ktermios **termios;
	void *driver_state;

	/*
	 * Driver methods
	 */

	const struct tty_operations *ops;
	struct list_head tty_drivers;
};

三、uart驱动编写步骤

uart它是linux在tty的基础上又做了一层封装,得益于该封装层,可以比较容易的编写新的串口驱动程序。
只需要2大步
(1)uart_register_driver函数注册一个串口设备
(2)platform_driver_register注册一个平台设备(最后执行uart_add_one_port)

驱动大概框架


static int serial_jz47xx_startup(struct uart_port *port)
{
   
	/*request_irq注册驱动*/
	retval = request_irq(up->port.irq, serial_jz47xx_irq, 0, up->name, up);//request irq
	if (retval)
		return retval;

	/*清理寄存器*/

	/*初始化串口*/

	/*使能中断*/
}
/*操作集合*/
struct uart_ops serial_jz47xx_pops = {
   
	/*回调函数*/
	.startup	= serial_jz47xx_startup,//start endport
	....
};

static struct uart_driver serial_jz47xx_reg = {
   
	.owner		= THIS_MODULE,		
	.driver_name	= "JZ47XX serial",  //串口驱动名字
	.dev_name	= "ttyS",     //串口设备名字
	.major		= TTY_MAJOR,    //主设备号
	.minor		= 64,
	.nr		= PORT_NR,/* 该uart_driver支持的串口个数(最大) */
	.cons		= JZ47XX_CONSOLE,	/* 其对应的console.若该uart_driver支持serial console,否则为NULL */
};


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值