上文说的是串口的platform部分,自然这次说的就是串口的tty部分。
现在就要追溯到上文s3c24xx_serial_modinit函数中的uart_register_driver(&s3c24xx_uart_drv)函数:
-
static struct uart_driver s3c24xx_uart_drv = {
-
.owner = THIS_MODULE,
-
.dev_name = "s3c2410_serial",
-
.nr = 3,
-
.cons = S3C24XX_SERIAL_CONSOLE,
-
.driver_name = S3C24XX_SERIAL_NAME, //#define S3C24XX_SERIAL_NAME "ttySAC"
-
.major = S3C24XX_SERIAL_MAJOR, //#define S3C24XX_SERIAL_MAJOR 204
-
.minor = S3C24XX_SERIAL_MINOR, //#define S3C24XX_SERIAL_MINOR 64
-
};
-
int uart_register_driver(struct uart_driver *drv)
-
{
-
struct tty_driver *normal = NULL;
-
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);
-
retval = -ENOMEM;
-
if (!drv->state)
-
goto out;
-
-
normal = alloc_tty_driver(drv->nr); //分配tty_driver
-
if (!normal)
-
goto out;
-
-
drv->tty_driver = normal;
-
-
normal->owner = drv->owner; //将uart_driver中的相关信息赋值给tty_driver
-
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; //给tty_driver设置默认的线路设置 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); //给tty_driver设置默认的操作函数uart_ops,这是由内核为我们实现的一个tty_operations结构体实例。
-
-
/*
-
* Initialise the UART state(s).
-
*/
-
for (i = 0; i < drv->nr; i++) {
-
struct uart_state *state = drv->state + i;
-
-
state->close_delay = 500; /* .5 seconds */
-
state->closing_wait = 30000; /* 30 seconds */
-
-
mutex_init(&state->mutex);
-
}
-
-
retval = tty_register_driver(normal); //调用tty_register_driver
-
out:
-
if (retval < 0) {
-
put_tty_driver(normal);
-
kfree(drv->state);
-
}
-
return retval;
-
}
那么我们就继续分析下tty_register_driver,整个函数的作用是分配字符设备,并进行初始化和注册。
-
int tty_register_driver(struct tty_driver *driver)
-
{
-
…… …… ……
-
/*driver->minor_start=*/
-
if (!driver->major) {
-
-
error = alloc_chrdev_region(&dev, driver->minor_start, driver->num,
-
driver->name);
-
if (!error) {
-
driver->major = MAJOR(dev);
-
driver->minor_start = MINOR(dev);
-
}
-
} else {
-
dev = MKDEV(driver->major, driver->minor_start);
-
error = register_chrdev_region(dev, driver->num, driver->name);
-
}
-
…… …… ……
-
cdev_init(&driver->cdev, &tty_fops); //设备绑定了tty_fops这个file_operations结构体实例
-
driver->cdev.owner = driver->owner;
-
error = cdev_add(&driver->cdev, dev, driver->num);
-
…… …… ……
-
}
这样,以后在用户层对串口设备进行读写等操作时,就会执行tty_fops中的相关函数,即:
-
static const struct file_operations tty_fops = {
-
.llseek = no_llseek,
-
.read = tty_read,
-
.write = tty_write,
-
.poll = tty_poll,
-
.ioctl = tty_ioctl,
-
.compat_ioctl = tty_compat_ioctl,
-
.open = tty_open,
-
.release = tty_release,
-
.fasync = tty_fasync,
-
};
例如其中的tty_open函数:
-
static int tty_open(struct inode * inode, struct file * filp)
-
{
-
………… ………… …………
-
retval = tty->driver->open(tty, filp); //这个就是在调用tty_driver中的open函数,即uart_ops实例中的uart_open
-
………… ………… …………
-
}
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,
-
.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
-
.read_proc = uart_read_proc,
-
#endif
-
.tiocmget = uart_tiocmget,
-
.tiocmset = uart_tiocmset,
-
};
对uart_ops中的uart_oepn进行分析,发现如下调用关系:
-
uart_open
-
uart_startup(state, 0);
-
port->ops->startup(port); //uart_ops结构体中的startup函数 (通tty_operations的uart_ops实例不同)
而s3c2440的uart_ops结构体定义如下:
-
static struct uart_ops s3c24xx_serial_ops = {
-
.pm = s3c24xx_serial_pm,
-
.tx_empty = s3c24xx_serial_tx_empty,
-
.get_mctrl = s3c24xx_serial_get_mctrl,
-
.set_mctrl = s3c24xx_serial_set_mctrl,
-
.stop_tx = s3c24xx_serial_stop_tx,
-
.start_tx = s3c24xx_serial_start_tx,
-
.stop_rx = s3c24xx_serial_stop_rx,
-
.enable_ms = s3c24xx_serial_enable_ms,
-
.break_ctl = s3c24xx_serial_break_ctl,
-
.startup = s3c24xx_serial_startup,
-
.shutdown = s3c24xx_serial_shutdown,
-
.set_termios = s3c24xx_serial_set_termios,
-
.type = s3c24xx_serial_type,
-
.release_port = s3c24xx_serial_release_port,
-
.request_port = s3c24xx_serial_request_port,
-
.config_port = s3c24xx_serial_config_port,
-
.verify_port = s3c24xx_serial_verify_port,
-
};
其被赋值于:
-
static struct s3c24xx_uart_port s3c24xx_serial_ports[NR_PORTS] = {
-
[0] = {
-
.port = {
-
.lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[0].port.lock),
-
.iotype = UPIO_MEM,
-
.irq = IRQ_S3CUART_RX0,
-
.uartclk = 0,
-
.fifosize = 16,
-
.ops = &s3c24xx_serial_ops, //见这里
-
.flags = UPF_BOOT_AUTOCONF,
-
.line = 0,
-
}
-
},
-
[1] = {
-
.port = {
-
.lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[1].port.lock),
-
.iotype = UPIO_MEM,
-
.irq = IRQ_S3CUART_RX1,
-
.uartclk = 0,
-
.fifosize = 16,
-
.ops = &s3c24xx_serial_ops,
-
.flags = UPF_BOOT_AUTOCONF,
-
.line = 1,
-
}
-
},
-
#if NR_PORTS > 2
-
-
[2] = {
-
.port = {
-
.lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[2].port.lock),
-
.iotype = UPIO_MEM,
-
.irq = IRQ_S3CUART_RX2,
-
.uartclk = 0,
-
.fifosize = 16,
-
.ops = &s3c24xx_serial_ops,
-
.flags = UPF_BOOT_AUTOCONF,
-
.line = 2,
-
}
-
}
-
#endif
-
};
到这个时候,我们就需要分析下,在上文 基于Linux2.6.22和s3c2440的串口驱动简析---(1) 最后说到 s3c2440_serial_probe,那么这个函数的功能是什么呢?对其分析会发现如下的调用关系:
-
s3c2410_serial_probe
-
s3c24xx_serial_probe(dev, &s3c2410_uart_inf);
-
ourport = &s3c24xx_serial_ports[probe_index]; //此处引用了上面的s3c24xx_serial_ports
-
s3c24xx_serial_init_port(ourport, info, dev); //完成硬件寄存器初始化
-
s3c24xx_serial_resetport(port, cfg);
-
(info->reset_port)(port, cfg); ---> s3c2410_serial_resetport
-
uart_add_one_port(&s3c24xx_uart_drv, &ourport->port);
-
state = drv->state + port->line; //将s3c24xx_serial_ports中的uart_port赋给了uart_driver中的uart_state->port
-
state->port = port;
-
uart_configure_port(drv, state, port);
-
port->ops->config_port(port, flags); //port->flags & UPF_BOOT_AUTOCONF
-
tty_register_device(drv->tty_driver, port->line, port->dev); //这个是关键, tty_register_device
-
device_create(tty_class, device, dev, name);
-
device_register(dev);
-
device_add(dev);
-
tty部分总结:
当用户对tty驱动所分配的设备节点进行系统调用时,tty_driver所拥有的tty_operations中的成员函数会被tty核心调用,之后串口核心层的uart_ops中的成员函数会被tty_operations中的成员函数再次调用。
这样,由于内核已经将tty核心层和tty驱动层实现了,那么我们需要做的就是对具体的设备,实现串口核心层的uart_ops、uart_ports、uart_driver等结构体实例。
至此,tty_register_driver和tty_register_device都被调用了。整个过程还是比较繁琐的,不知道有没有写清楚~~
阅读(287) | 评论(0) | 转发(0) |