linux uart 驱动中 open、read、write调用层次

//Linux kernel release 2.6.xx
//linux uart 驱动中接收和发送函数的调用层次,记录如下:
module_init(s3c24xx_serial_modinit);			//drivers/serial/samsung.c
uart_register_driver(&s3c24xx_uart_drv);
	tty_register_driver(normal);				//drivers/serial/serial_core.c
		cdev_init(&driver->cdev, &tty_fops);	//drivers/char/tty_io.c 注册字符设备,指定fops
		//进入参数tty_fops中,在tty_fops中有
		
		**//1. open ---> tty_open(tty_ops里面的) ---> uart_open(uart_ops里面的) ---> uart_start** 
		open		//应用层。 tty_fops中有   .open		= tty_open
			tty_open  //drivers/char/tty_io.c。tty_open函数中有 tty->ops->open(tty, filp);   ops是:tty_operations结构指针
				uart_open  //serial/serial_core.c中有static const struct tty_operations uart_ops = {
						   //.open		= uart_open,
					uart_startup(state, 0);	//uport是struct uart_port结构。 在struct uart_port (一个串口)中,ops类型是 struct 		   
					                        // uart_ops结构此函数中有 uport->ops->startup(uport);			
											// .startup	= s3c24xx_serial_startup, (在drivers/serial/samsung.c结构 
											// static struct uart_ops s3c24xx_serial_ops = { 中)
					//在probe函数中,.probe	= s5p_serial_probe, --> s3c24xx_serial_probe(pdev, s5p_uart_inf[pdev->id]);
												//在s3c24xx_serial_probe函数中,获取端口 ourport = &s3c24xx_serial_ports[dev->id]; 
												//在数组s3c24xx_serial_ports中包含了函数集 .ops= &s3c24xx_serial_ops,
						s3c24xx_serial_startup,	//使能串口中断、串口时钟
							request_irq(ourport->rx_irq, s3c24xx_serial_rx_chars, 0,s3c24xx_serial_portname(port), ourport);
							//指定串口中断函数
							request_irq(ourport->tx_irq, s3c24xx_serial_tx_chars, 0,s3c24xx_serial_portname(port), ourport); 
								s3c24xx_serial_rx_chars		//直接读寄存器
	
	
**// 2. 写调用流程为 write---> tty_write ---> n_tty_write(线路规程里面) ---> uart_write ---> uart_start  --> __uart_start --> 进入函数s3c24xx_serial_rx_chars**
write
	tty_write
		do_tty_write(ld->ops->write, tty, file, buf, count);	//参数 ld->ops->write;  struct tty_ldisc *ld;
		//进入结构tty_ldisc,里面包含struct tty_ldisc { struct tty_ldisc_ops *ops; ... };	
		struct tty_ldisc_ops tty_ldisc_N_TTY = {
			.write           = n_tty_write,  //调用n_tty_write

			n_tty_write()	//函数中有  tty->ops->write(tty, b, nr); ,tty是tty_struct类型。  进入tty_struct中的 struct tty_operations *ops中				
							//struct tty_operations uart_ops = { .write = uart_write,
				uart_write()
					uart_start()
						__uart_start()  //此函数中有 port->ops->start_tx(port);
									  //进入ops结构中 .start_tx	= s3c24xx_serial_start_tx,
						//使能发送
							s3c24xx_serial_tx_chars()	//使能后自动调用中断发送函数
		
**//3. 读调用流程为**		
read
	tty_read	// if (ld->ops->read) ; struct tty_ldisc *ld;
	//进入结构 tty_ldisc ,里面包含struct tty_ldisc { struct tty_ldisc_ops *ops; ... };	
	struct tty_ldisc_ops tty_ldisc_N_TTY = {
		.read            = n_tty_read,
	
		n_tty_read
			copy_from_read_buf(struct tty_struct *tty, unsigned char __user **b, size_t *nr)
				 copy_to_user(*b, &tty->read_buf[tty->read_tail], n); //从read_buf读数据,当驱动里面有数据的时候,驱动就将数据往 read_buf 里面送
																	  //
				s3c24xx_serial_rx_chars(中断函数)
					uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN,ch, flag); /* 9. 将接收到的字符发送到串口驱动的buf(tty->tty_bufhead中) */
						tty_insert_flip_char(tty, ch, flag);
							tb->char_buf_ptr[tb->used++] = ch;	//struct tty_buffer *tb = tty->buf.tail;
						
					tty_flip_buffer_push(tty);	/*serial/samsung.c   10. 把串口驱动收到的数据发送到线路规程的 read_buf */
						flush_to_ldisc(&tty->buf.work.work);	//tty_buffer.c 402行
							disc->ops->receive_buf();   //struct tty_ldisc *disc;
							进入结构tty_ldisc
							struct tty_ldisc {
								struct tty_ldisc_ops *ops;		
								};
							进入结构 tty_ldisc_ops
							struct tty_ldisc_ops tty_ldisc_N_TTY = {		//char/n_tty.c
							.receive_buf     = n_tty_receive_buf,
							
							n_tty_receive_buf()
								n_tty_receive_break()
									put_tty_queue()
										put_tty_queue_nolock()
											tty->read_buf[tty->read_head] = c;
				
				
综上,中断函数中获取数据的调用层次为:s3c24xx_serial_rx_chars()--->uart_insert_char()---->tty_insert_flip_char()
    -->tty_flip_buffer_push()-->flush_to_ldisc()--->n_tty_receive_buf()--->n_tty_receive_char()
				
			
				
				
				
				
				
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux内核UART设备驱动注册流程如下: 1. 分配tty_driver结构体 在驱动初始化时,首先需要分配一个tty_driver结构体,该结构体描述了tty设备的驱动属性信息,包括驱动名称、打开、关闭、读写等操作的回调函数指针等。 2. 注册tty_driver 调用tty_register_driver函数,将tty_driver结构体注册到内核,该函数会将tty_driver结构体添加到tty_drivers链表,同时会创建一个tty_class结构体和一个tty_class_dev结构体,并将其关联起来。 3. 创建tty设备节点 调用tty_register_device函数,该函数会根据tty_driver结构体的信息创建tty设备节点,并将其添加到tty_drivers链表。 4. 设置tty设备驱动回调函数 在tty_driver结构体设置相应的驱动回调函数,例如open、close、readwrite等操作的回调函数指针。 5. 注册tty设备驱动与硬件设备的关联 在驱动初始化时,需要将tty设备驱动与硬件设备进行关联,通常是通过platform_device_register函数将platform_device结构体注册到内核,并调用platform_driver_register函数将platform_driver结构体注册到内核。 6. 实现tty设备驱动回调函数 在驱动初始化时,需要实现相应的tty设备驱动回调函数,例如open、close、readwrite等操作的回调函数。当用户调用相应的操作时,内核会自动调用相应的回调函数执行相应的操作。 7. 注销tty设备驱动驱动卸载时,需要调用tty_unregister_driver函数注销tty_driver结构体,并释放相关资源。同时也需要注销与硬件设备的关联关系。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值