tty驱动

参考:http://www.wowotech.net/tty_framework/435.html

一、框架 

用户层只要初始化后注册进tty_core即可 

二、读写流程

1. 读:

usr_buf--->ld线程里阻塞读---> tty_port[struct tty_bufhead    buf]会唤醒

2.写

usr_buf--->copy到tty_struct的buf----->copy到tty_port的buf(可选,也可以直接拷贝到驱动自定义的buf里

3. open关键,通过子设备号,找到tty_driver,然后初始化tty_struct,填充到tty_driver的tty_struct数组里,并且在tty_driver的tty_port数组里对用下表找到tty_port挂载在tty_struct.tty_port

总结:用户层总是与tty_struct结构体打交道。最后都会调用到tty_driver-->ops里,主要又客户自己实现

 

三、代码梳理

1. serial模块

static int __init xuartps_init(void)
{
	int retval = 0;

	/* Register the xuartps driver with the serial core */
	retval = uart_register_driver(&xuartps_uart_driver);-------》注册tty_driver
	if (retval)
		return retval;

	/* Register the platform driver */
	retval = platform_driver_register(&xuartps_platform_driver);---->注册tty_port
	if (retval)
		uart_unregister_driver(&xuartps_uart_driver);

	return retval;
}
int uart_register_driver(struct uart_driver *drv)
{
    struct tty_driver *normal;
    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);--------->ops需要用户侧实现

    	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;--------》需要用户侧实现,该处只是分别tty_port数组,挂载 
                                                tty_driver上,后续将具体的填充
		port->close_delay     = HZ / 2;	/* .5 seconds */
		port->closing_wait    = 30 * HZ;/* 30 seconds */
	}

    retval = tty_register_driver(normal);

红色圈里为注册tty_driver实现:生成cdev[]数组,tty_struct[], tty_port[] ,后续注册会填充该数组。 

static int xuartps_probe(struct platform_device *pdev)
{
    port = xuartps_get_port();---------》通过设备树,找到id.具体参考链接文档。
    rc = uart_add_one_port(&xuartps_uart_driver, port);----》xuartps_uart_driver 提前注册
}

int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
{
    	tty_dev = tty_port_register_device_attr(port, drv->tty_driver,
			uport->line, uport->dev, port, tty_dev_attr_groups);
}

struct device *tty_port_register_device_attr(struct tty_port *port,
		struct tty_driver *driver, unsigned index,
		struct device *device, void *drvdata,
		const struct attribute_group **attr_grp)
{
	tty_port_link_device(port, driver, index);-----》将port放在tty_port数组里
	return tty_register_device_attr(driver, index, device, drvdata,----》创建设备文件
			attr_grp);
}

 

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,
.....
}

static int uart_write(struct tty_struct *tty,
					const unsigned char *buf, int count)
{
    circ = &state->xmit; ------->用户自己定义的buf
    	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);拷贝buf
		circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1);
		buf += c;
		count -= c;
		ret += c;
	}

    uart_start(tty);-------》启动发送中断
}

 

2. sdio_uart

static int __init sdio_uart_init(void)
{
    sdio_uart_tty_driver = tty_drv = alloc_tty_driver(UART_NR);
    
    tty_drv->driver_name = "sdio_uart";
	tty_drv->name =   "ttySDIO";
	tty_drv->major = 0;  /* dynamically allocated */
	tty_drv->minor_start = 0;
	tty_drv->type = TTY_DRIVER_TYPE_SERIAL;
	tty_drv->subtype = SERIAL_TYPE_NORMAL;
	tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
	tty_drv->init_termios = tty_std_termios;
	tty_drv->init_termios.c_cflag = B4800 | CS8 | CREAD | HUPCL | CLOCAL;
	tty_drv->init_termios.c_ispeed = 4800;
	tty_drv->init_termios.c_ospeed = 4800;
	tty_set_operations(tty_drv, &sdio_uart_ops);------->自己实现
    
    ret = tty_register_driver(tty_drv);

    ret = sdio_register_driver(&sdio_uart_driver);-------》注册tty_port
}

 

static int sdio_uart_probe(struct sdio_func *func,
			   const struct sdio_device_id *id)
{
    tty_port_init(&port->port);
    port->port.ops = &sdio_uart_port_ops; //用户自己实现
    
    ret = sdio_uart_add_port(port); //放到自己定义的数组里,后续通过port找到sdio_port

    dev = tty_port_register_device(&port->port, 注册
				sdio_uart_tty_driver, port->index, &func->dev);
}

 

static const struct tty_operations sdio_uart_ops = {
	.open			= sdio_uart_open,
	.close			= sdio_uart_close,
	.write			= sdio_uart_write,
	.write_room		= sdio_uart_write_room,
	.chars_in_buffer	= sdio_uart_chars_in_buffer,
	.send_xchar		= sdio_uart_send_xchar,
}

static int sdio_uart_write(struct tty_struct *tty, const unsigned char *buf,
			   int count)
{
    struct sdio_uart_port *port = tty->driver_data;
	int ret;

	if (!port->func)
		return -ENODEV;

    //拷贝到机子定义的fifo里
	ret = kfifo_in_locked(&port->xmit_fifo, buf, count, &port->write_lock);
	if (!(port->ier & UART_IER_THRI)) {
		int err = sdio_uart_claim_func(port);
		if (!err) {
			sdio_uart_start_tx(port);
			sdio_uart_irq(port->func);
			sdio_uart_release_func(port);
		} else
			ret = err;
	}

	return ret;
}

 

3. usb_serial

 

以ch341为例说明:

1. seria_bus的注册

static int __init usb_serial_init(void)
{
    usb_serial_tty_driver = alloc_tty_driver(SERIAL_TTY_MINORS);
    
    result = bus_register(&usb_serial_bus_type);---------》usb_serial_bus 总线注册

    usb_serial_tty_driver->driver_name = "usbserial";
	usb_serial_tty_driver->name = "ttyUSB";
	usb_serial_tty_driver->major = SERIAL_TTY_MAJOR;
	usb_serial_tty_driver->minor_start = 0;
	usb_serial_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
	usb_serial_tty_driver->subtype = SERIAL_TYPE_NORMAL;
	usb_serial_tty_driver->flags = TTY_DRIVER_REAL_RAW |
						TTY_DRIVER_DYNAMIC_DEV;
	usb_serial_tty_driver->init_termios = tty_std_termios;
	usb_serial_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD
							| HUPCL | CLOCAL;
	usb_serial_tty_driver->init_termios.c_ispeed = 9600;
	usb_serial_tty_driver->init_termios.c_ospeed = 9600;
	tty_set_operations(usb_serial_tty_driver, &serial_ops);
	result = tty_register_driver(usb_serial_tty_driver);   //tty_driver注册
	if (result) {
		pr_err("%s - tty_register_driver failed\n", __func__);
		goto exit_reg_driver;
	}

	/* register the USB driver */
	result = usb_register(&usb_serial_driver); //图中:drv1注册
	if (result < 0) {
		pr_err("%s - usb_register failed\n", __func__);
		goto exit_tty;
	}

}

 

// drv注册
static struct usb_serial_driver * const serial_drivers[] = {
	&ch341_device, NULL
};

module_usb_serial_driver(serial_drivers, id_table);-------》

int usb_serial_register_drivers(struct usb_serial_driver *const serial_drivers[],
				const char *name,
				const struct usb_device_id *id_table)
{
    struct usb_driver *udriver;
    //usb_drv注册
	rc = usb_register(udriver); usb_drv注册, 自己注册一个driver
	if (rc)
		return rc;
    udriver->probe = usb_serial_probe;  --------------》probe

	for (sd = serial_drivers; *sd; ++sd) {
		(*sd)->usb_driver = udriver;
		rc = usb_serial_register(*sd);  ---------》usb_serial_drv注册
		if (rc)
			goto failed;
	}
}

//usb_serial_drv注册
static int usb_serial_register(struct usb_serial_driver *driver)
{    
    retval = usb_serial_bus_register(driver);
}

//dev注册
1. 这对usb_dev 是platform产生,匹配usb_driver
static int usb_serial_probe(struct usb_interface *interface,
			       const struct usb_device_id *id)
{

    struct usb_serial_port *port;

    	for (i = 0; i < max_endpoints; ++i) {
		port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL);
		if (!port)
			goto probe_error;
		tty_port_init(&port->port);
		port->port.ops = &serial_port_ops;
		port->serial = serial;
		spin_lock_init(&port->lock);
		/* Keep this for private driver use for the moment but
		   should probably go away */
		INIT_WORK(&port->work, usb_serial_port_work);
		serial->port[i] = port;
		port->dev.parent = &interface->dev;
		port->dev.driver = NULL;
		port->dev.bus = &usb_serial_bus_type; --------->bus
		port->dev.release = &usb_serial_port_release;
		device_initialize(&port->dev);
	}
    ,,,,,,
    retval = device_add(&port->dev);
    //后续进行probe  ,借用bus的probe,而不是在drv的probe
}
// bus probe
static int usb_serial_device_probe(struct device *dev)
{
    tty_register_device(usb_serial_tty_driver, minor, dev); //tty_por注册
}

 

相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页