五 linux 串口驱动

五 linux 串口驱动_第1张图片

一.串口结构体

1.串口驱动结构体

struct uart_driver {
	struct module	*owner;	//模块所有者
	const char	*driver_name;	//驱动名
	const char	*dev_name;	//设备名
	int	 major;	//主设备号
	int	 minor;	//次设备号
	int	 nr;	//支持串口个数
	struct console	*cons;	//控制台设备
	struct uart_state	*state;	//串口状态
	struct tty_driver	*tty_driver;	//tty设备
};

2.串口端口结构体

struct uart_port {
	spinlock_t	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);
	void	(*pm)(struct uart_port *, unsigned int state,unsigned int old);
	unsigned int	irq;	//中断号
	unsigned long	irqflags;	//中断标志
	unsigned int	uartclk;
	unsigned int	fifosize;	//fifo大小	
	unsigned char	x_char;
	unsigned char	regshift;	//寄存器偏移值	
	unsigned char	iotype;	//io访问类型
	unsigned char	unused1;
	unsigned int	read_status_mask;
	unsigned int	ignore_status_mask;
	struct uart_state	*state;	//uart_state结构体	
	struct uart_icount	icount;	//串口使用计数
	struct console	*cons;	//console控制台
#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(SUPPORT_SYSRQ)
	unsigned long	sysrq;
#endif
	upf_t	flags;
	unsigned int	mctrl;
	unsigned int	timeout;
	unsigned int	type;
	const struct uart_ops	*ops;	//串口操作函数集
	unsigned int	custom_divisor;
	unsigned int	line;	//端口号
	resource_size_t	mapbase;
	struct device	*dev;	//设备文件
	unsigned char	hub6;
	unsigned char	suspended;
	unsigned char	irq_wake;
	unsigned char	unused[2];
	void	*private_data;
};

3.操作函数集

struct uart_ops {
	unsigned int	(*tx_empty)(struct uart_port *);	//发送缓冲区为空
	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);
	void	(*stop_rx)(struct uart_port *);	//停止接收
	void	(*enable_ms)(struct uart_port *);	//使能modem状态信息
	void	(*break_ctl)(struct uart_port *, int ctl);
	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 *, int new);
	void	(*pm)(struct uart_port *, unsigned int state,unsigned int oldstate);
	int	(*set_wake)(struct uart_port *, unsigned int state);
	const char *(*type)(struct uart_port *);
	void	(*release_port)(struct uart_port *);	//释放端口
	int	(*request_port)(struct uart_port *);	//请求端口
	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
};

4.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;
};

 

二.串口驱动的注册与注销

注册

int uart_register_driver(struct uart_driver *drv)
{
	struct tty_driver *normal;
	int i, retval;
	BUG_ON(drv->state);
	drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);	//分配uart_state内存
	if (!drv->state)
		goto out;
	normal = alloc_tty_driver(drv->nr);	//分配tty_driver
	if (!normal)
		goto out_kfree;
	drv->tty_driver = normal;	//tty_driver和uart_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;	//tty类型
	normal->subtype		= SERIAL_TYPE_NORMAL;	//tty子类型
	normal->init_termios	= tty_std_termios;		//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);	//设置tty操作函数集

	for (i = 0; i < drv->nr; i++) {	//初始化uart_state
		struct uart_state *state = drv->state + i;
		struct tty_port *port = &state->port;
		tty_port_init(port);	//初始化tty端口
		port->ops = &uart_port_ops;	//tty端口操作函数集
		port->close_delay     = 500;	/* .5 seconds */
		port->closing_wait    = 30000;	/* 30 seconds */
		tasklet_init(&state->tlet, uart_tasklet_action,(unsigned long)state);
	}
	retval = tty_register_driver(normal);	//注册tty驱动
	if (retval >= 0)
		return retval;

	put_tty_driver(normal);	//引用计数
out_kfree:
	kfree(drv->state);
out:
	return -ENOMEM;
}

 注销

void uart_unregister_driver(struct uart_driver *drv)
{
	struct tty_driver *p = drv->tty_driver;
	tty_unregister_driver(p);	//注销tty驱动
	put_tty_driver(p);	//减少引用计数
	kfree(drv->state);
	drv->tty_driver = NULL;
}

三.端口注册与注销

注册

int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
{
	struct uart_state *state;
	struct tty_port *port;
	int ret = 0;
	struct device *tty_dev;
	BUG_ON(in_interrupt());
	if (uport->line >= drv->nr)
		return -EINVAL;
	state = drv->state + uport->line;	//获取uart_state
	port = &state->port;	//获取tty_port
	mutex_lock(&port_mutex);
	mutex_lock(&port->mutex);
	if (state->uart_port) {
		ret = -EINVAL;
		goto out;
	}
	state->uart_port = uport;	//设置uart_state->uart_port
	state->pm_state = -1;
	uport->cons = drv->cons;	//设置uart_port->cons控制台
	uport->state = state;	//设置uart_port->state
	if (!(uart_console(uport) && (uport->cons->flags & CON_ENABLED))) {
		spin_lock_init(&uport->lock);
		lockdep_set_class(&uport->lock, &port_lock_key);
	}
	uart_configure_port(drv, state, uport);	//配置端口
	tty_dev = tty_register_device(drv->tty_driver, uport->line, uport->dev);	//生成tty设备文件/dev/ttyXXX
	if (likely(!IS_ERR(tty_dev))) {
		device_init_wakeup(tty_dev, 1);
		device_set_wakeup_enable(tty_dev, 0);
	} else
		printk(KERN_ERR "Cannot register tty device on line %d\n",uport->line);
	uport->flags &= ~UPF_DEAD;
 out:
	mutex_unlock(&port->mutex);
	mutex_unlock(&port_mutex);

	return ret;
}

uart_configure_port

static void uart_configure_port(struct uart_driver *drv, struct uart_state *state,struct uart_port *port)
{
	unsigned int flags;
	if (!port->iobase && !port->mapbase && !port->membase)
		return;
	flags = 0;
	if (port->flags & UPF_AUTO_IRQ)	//设置可中断标志
		flags |= UART_CONFIG_IRQ;
	if (port->flags & UPF_BOOT_AUTOCONF) {	//设置自动配置标志
		if (!(port->flags & UPF_FIXED_TYPE)) {
			port->type = PORT_UNKNOWN;
			flags |= UART_CONFIG_TYPE;
		}
		port->ops->config_port(port, flags);	//调用uart_port的config_port方法
	}

	if (port->type != PORT_UNKNOWN) {
		unsigned long flags;
		uart_report_port(drv, port);
		uart_change_pm(state, 0);
		spin_lock_irqsave(&port->lock, flags);
		port->ops->set_mctrl(port, port->mctrl & TIOCM_DTR);	//调用uart_port的set_mctrl方法
		spin_unlock_irqrestore(&port->lock, flags);
		if (port->cons && !(port->cons->flags & CON_ENABLED))	//若console存在且设置了CON_ENABLED标志
			register_console(port->cons);	//注册控制台设备
		if (!uart_console(port))
			uart_change_pm(state, 3);
	}
}

 注销

int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)
{
	struct uart_state *state = drv->state + uport->line;
	struct tty_port *port = &state->port;
	BUG_ON(in_interrupt());
	if (state->uart_port != uport)
		printk(KERN_ALERT "Removing wrong port: %p != %p\n",state->uart_port, uport);
	mutex_lock(&port_mutex);
	mutex_lock(&port->mutex);
	uport->flags |= UPF_DEAD;
	mutex_unlock(&port->mutex);
	tty_unregister_device(drv->tty_driver, uport->line);
	if (port->tty)
		tty_vhangup(port->tty);
	if (uport->type != PORT_UNKNOWN)
		uport->ops->release_port(uport);
	uport->type = PORT_UNKNOWN;
	tasklet_kill(&state->tlet);
	state->uart_port = NULL;
	mutex_unlock(&port_mutex);
	return 0;
}

四.串口对应的tty_driver的操作函数集

1.tty的操作函数集uart_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,
#endif
};

2.open方法

static int uart_open(struct tty_struct *tty, struct file *filp)
{
	struct uart_driver *drv = (struct uart_driver *)tty->driver->driver_state;
	struct uart_state *state;
	struct tty_port *port;
	int retval, line = tty->index;

	BUG_ON(!tty_locked());
	pr_debug("uart_open(%d) called\n", line);
	retval = -ENODEV;
	if (line >= tty->driver->num)
		goto fail;
	state = uart_get(drv, line);	//获取uart_state
	if (IS_ERR(state)) {
		retval = PTR_ERR(state);
		goto fail;
	}
	port = &state->port;	//获取tty_port
	tty->driver_data = state;
	state->uart_port->state = state;
	tty->low_latency = (state->uart_port->flags & UPF_LOW_LATENCY) ? 1 : 0;
	tty->alt_speed = 0;
	tty_port_tty_set(port, tty);
	if (tty_hung_up_p(filp)) {
		retval = -EAGAIN;
		port->count--;
		mutex_unlock(&port->mutex);
		goto fail;
	}
	if (port->count == 1)
		uart_change_pm(state, 0);
	retval = uart_startup(tty, state, 0);	//启动串口
	mutex_unlock(&port->mutex);
	if (retval == 0)
		retval = tty_port_block_til_ready(port, tty, filp);
fail:
	return retval;
}

uart_startup

static int uart_startup(struct tty_struct *tty, struct uart_state *state, int init_hw)
{
	struct uart_port *uport = state->uart_port;	//获取uart_port
	struct tty_port *port = &state->port;	//获取tty_port
	unsigned long page;
	int retval = 0;

	if (port->flags & ASYNC_INITIALIZED)
		return 0;
	set_bit(TTY_IO_ERROR, &tty->flags);
	if (uport->type == PORT_UNKNOWN)
		return 0;
	if (!state->xmit.buf) {
		/* This is protected by the per port mutex */
		page = get_zeroed_page(GFP_KERNEL);
		if (!page)
			return -ENOMEM;
		state->xmit.buf = (unsigned char *) page;
		uart_circ_clear(&state->xmit);
	}
	retval = uport->ops->startup(uport);	//调用uart_port的startup方法
	if (retval == 0) {
		if (init_hw) {
			uart_change_speed(tty, state, NULL);
			if (tty->termios->c_cflag & CBAUD)
				uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR);
		}
		if (port->flags & ASYNC_CTS_FLOW) {
			spin_lock_irq(&uport->lock);
			if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS))
				tty->hw_stopped = 1;
			spin_unlock_irq(&uport->lock);
		}
		set_bit(ASYNCB_INITIALIZED, &port->flags);
		clear_bit(TTY_IO_ERROR, &tty->flags);
	}
	if (retval && capable(CAP_SYS_ADMIN))
		retval = 0;
	return retval;
}

3.写方法

static int uart_write(struct tty_struct *tty,const unsigned char *buf, int count)
{
	struct uart_state *state = tty->driver_data;	//获取uart_state
	struct uart_port *port;
	struct circ_buf *circ;
	unsigned long flags;
	int c, ret = 0;
	if (!state) {
		WARN_ON(1);
		return -EL3HLT;
	}
	port = state->uart_port;	//获取uart_port
	circ = &state->xmit;
	if (!circ->buf)
		return 0;

	spin_lock_irqsave(&port->lock, flags);
	while (1) {
		c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE);
		if (count < c)
			c = count;
		if (c <= 0)
			break;
		memcpy(circ->buf + circ->head, buf, c);
		circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1);
		buf += c;
		count -= c;
		ret += c;
	}
	spin_unlock_irqrestore(&port->lock, flags);
	uart_start(tty);	//调用uart_start方法
	return ret;
}

uart_start

static void uart_start(struct tty_struct *tty)
{
	struct uart_state *state = tty->driver_data;	//获取tty_state
	struct uart_port *port = state->uart_port;	//获取uart_port
	unsigned long flags;

	spin_lock_irqsave(&port->lock, flags);
	__uart_start(tty);		//调用__uart_start函数
	spin_unlock_irqrestore(&port->lock, flags);
}

uart_start>>>__uart_start

static void __uart_start(struct tty_struct *tty)
{
	struct uart_state *state = tty->driver_data;	//获取uart_state
	struct uart_port *port = state->uart_port;	//获取uart_port
	if (!uart_circ_empty(&state->xmit) && state->xmit.buf &&!tty->stopped && !tty->hw_stopped)
		port->ops->start_tx(port);	//调用uart_port的start_tx方法
}



 


 




 




 

你可能感兴趣的:(五 linux 串口驱动)