• TTY驱动分层思想


    上中下三层

    底层部分: uart层
    关注UART或者其他底层串行硬件特征的底层驱动程序

    中间层部分:即tty驱动层
    和底层驱动程序接口的tty驱动程序层,将上层驱动程序和形形色色的硬件进行了隔离

    上层部分:ldisc 线路规划层
    加工用于和tty驱动程序交换数据的线路规程

    关系:
    底层UART驱动 与 TTY驱动 负责从硬件是哪个收发数据,而上层线路规程驱动负责处理这些数据,并在内核空间与用户空间之间传递数据。


    底层部分: uart驱动层
    关注UART或者其他底层串行硬件特征的底层驱动程序

    drivers\tty\serial\tty_virtual.c

    static struct uart_ops ttyx_ops = {
            .tx_empty=       ttyx_tx_empty,
            .set_mctrl=     ttyx_set_mctrl,
            .get_mctrl=     ttyx_get_mctrl,
            .stop_tx=        ttyx_stop_tx,
            .start_tx=       ttyx_start_tx,
            .stop_rx=        ttyx_stop_rx,
            .enable_ms=      ttyx_enable_ms,
            .break_ctl=      ttyx_break_ctl,
            .startup=        ttyx_startup,
            .shutdown=       ttyx_shutdown,
    		.set_termios=    ttyx_termios,
            .type=           ttyx_type,
            .release_port=   ttyx_release_port,
            .request_port=   ttyx_request_port,
            .config_port=    ttyx_config_port,
            .verify_port=    ttyx_verify_port,
    };
    
    
    static struct uart_driver ttyx_uart_driver = {
    
    
            owner:                  THIS_MODULE,
            major:        		 	SERIAL_TTYX_MAJOR,
            driver_name:            "ttyx",
            dev_name:               "ttyx",
            minor:                  MINOR_START,
            nr:                     NR_PORTS,
            cons:                   NULL
    };
    
    
    static int vtty_probe(struct platform_device *pdev)
    {
        unsigned char i;
    	int ret=0;
    	
    	printk(KERN_ALERT "%s!!--in--\n", __func__);
    
    	ret=uart_register_driver(&ttyx_uart_driver);
    	if (ret)
    	{
        	printk(KERN_ERR "Couldn't register ttyx uart driver\n");
        	return ret;
    	}
    	
    	for(i =0;iport.line     = i;
        	s->port.ops      = &ttyx_ops;
        	s->port.uartclk  = CRASTAL_CLK;
        	s->port.fifosize = TXFIFO_SIZE; 
        	s->port.iobase   = i+1;
        	s->port.iotype   = SERIAL_IO_PORT;
    		//该属性 需要设置 UPF_FIXED_PORT 位。否则 注册过程中 会将 s->port.type强制设置为 空 !!!
        	s->port.flags    = UPF_FIXED_PORT;// ASYNC_BOOT_AUTOCONF
    		s->port.type = PORT_HONGDIAN;
        	ret = uart_add_one_port(&ttyx_uart_driver, &s->port);
       		if(ret<0)
       		{
        		printk(KERN_ALERT "uart_add_one_port failed for line i:= %d with error %d\n",i,ret);
       		}else{
       			printk(KERN_INFO "uart_add_one_port success for line i:= %d with right %d\n",i,ret);
       		}
    	}
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70

    中间层部分:即tty驱动层
    和底层驱动程序接口的tty驱动程序层,将上层驱动程序和形形色色的硬件进行了隔离

    serial_core.c

    struct uart_port {
    	...
    	const struct uart_ops	*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,
    #endi
    }
    
    
    
    int uart_register_driver(struct uart_driver *drv)
    {
    	
    	struct tty_driver *normal;
    	int i, retval;
    
    	BUG_ON(drv->state);
    
    	/*
    	 * Maybe we should be using a slab cache for this, especially if
    	 * we have a large number of ports to handle.
    	 */
    	drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);
    	if (!drv->state)
    		goto out;
    
    	normal = alloc_tty_driver(drv->nr);
    	if (!normal)
    		goto out_kfree;
    
    
    	drv->tty_driver = normal;
    
    	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;
    
    		tty_port_init(port);
    		port->ops = &uart_port_ops;
    	}
    
    	retval = tty_register_driver(normal);
    	if (retval >= 0){
    	return retval;
    
    	}
    		
    
    	for (i = 0; i < drv->nr; i++)
    		tty_port_destroy(&drv->state[i].port);
    	put_tty_driver(normal);
    out_kfree:
    	kfree(drv->state);
    out:
    	return -ENOMEM;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102

    上层部分:ldisc 线路规划层
    加工用于和tty驱动程序交换数据的线路规程

    drivers\tty\n_tty.c

    struct tty_ldisc_ops {
    ....
    	int	(*open)(struct tty_struct *);
    	void	(*close)(struct tty_struct *);
    	void	(*flush_buffer)(struct tty_struct *tty);
    	ssize_t	(*chars_in_buffer)(struct tty_struct *tty);
    	ssize_t	(*read)(struct tty_struct *tty, struct file *file,
    			unsigned char __user *buf, size_t nr);
    	ssize_t	(*write)(struct tty_struct *tty, struct file *file,
    	...
    };
    
    struct tty_ldisc {
    	struct tty_ldisc_ops *ops;
    	struct tty_struct *tty;
    };
    
    
    struct tty_ldisc_ops tty_ldisc_N_TTY = {
    	.magic           = TTY_LDISC_MAGIC,
    	.name            = "n_tty",
    	.open            = n_tty_open,
    	.close           = n_tty_close,
    	.flush_buffer    = n_tty_flush_buffer,
    	.chars_in_buffer = n_tty_chars_in_buffer,
    	.read            = n_tty_read,
    	.write           = n_tty_write,
    	.ioctl           = n_tty_ioctl,
    	.set_termios     = n_tty_set_termios,
    	.poll            = n_tty_poll,
    	.receive_buf     = n_tty_receive_buf,
    	.write_wakeup    = n_tty_write_wakeup,
    	.fasync		 = n_tty_fasync,
    	.receive_buf2	 = n_tty_receive_buf2,
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
  • 相关阅读:
    【GlobalMapper精品教程】027:路径剖面和和视线工具的使用
    微服务的灰度发布就该这样设计
    HTML做一个节日页面【六一儿童节】纯HTML代码
    【Java+SpringBoot】智慧景区信息管理系统(源码+远程部署+代码讲解+答辩教学)
    Hadoop Hbase
    debian 12.5 使用官方源、清华源等,无法安装wget、mysql,如何解决?(操作系统-linux)
    C#拾遗补漏之goto跳转语句
    Java的指针、引用与C++的指针、引用的对比
    11. 一文快速学懂常用工具——网络工具(下)
    [源码解析] TensorFlow 分布式环境(1) --- 总体架构
  • 原文地址:https://blog.csdn.net/LinuxArmbiggod/article/details/127839912