1. serial 层的初始化
以IMX6的串口驱动为例,文件在drivers/tty/serial/imx.c,初始化概述如下:
module_init(imx_serial_init)
-->uart_register_driver(&imx_reg);
-->tty_set_operations(normal, &uart_ops);
-->driver->ops = op;
-->tty_register_driver(normal);
-->dev = MKDEV(driver->major, driver->minor_start);
-->error = register_chrdev_region(dev, driver->num, driver->name); //注册字符设备ttymxc0~4
-->tty_cdev_add(driver, dev, 0, driver->num);
-->cdev_init(&driver->cdevs[index], &tty_fops);
-->cdev->ops = fops; //将我们定义好的file_operaionts与cdev关联起来
-->platform_driver_register(&serial_imx_driver);
-->driver_register(&drv->driver);
2. 具体代码分析
初始化过程中注册和关联的五个重要结构体
#define DEV_NAME "ttymxc"
static struct uart_driver imx_reg = {
.owner = THIS_MODULE,
.driver_name = DRIVER_NAME,
.dev_name = DEV_NAME, //ttymxc
.major = SERIAL_IMX_MAJOR,
.minor = MINOR_START,
.nr = ARRAY_SIZE(imx_ports),
.cons = IMX_CONSOLE,
};
static struct uart_ops imx_pops = {
.tx_empty = imx_tx_empty,
.set_mctrl = imx_set_mctrl,
.get_mctrl = imx_get_mctrl,
.stop_tx = imx_stop_tx,
.start_tx = imx_start_tx,
.stop_rx = imx_stop_rx,
.enable_ms = imx_enable_ms,
.break_ctl = imx_break_ctl,
.startup = imx_startup,
.shutdown = imx_shutdown,
.flush_buffer = imx_flush_buffer,
.set_termios = imx_set_termios,
.type = imx_type,
.config_port = imx_config_port,
.verify_port = imx_verify_port,
#if defined(CONFIG_CONSOLE_POLL)
.poll_get_char = imx_poll_get_char,
.poll_put_char = imx_poll_put_char,
#endif
};
static struct platform_driver serial_imx_driver = {
.probe = serial_imx_probe,
.remove = serial_imx_remove,
.suspend = serial_imx_suspend,
.resume = serial_imx_resume,
.id_table = imx_uart_devtype,
.driver = {
.name = "imx-uart",
.owner = THIS_MODULE,
.of_match_table = imx_uart_dt_ids,
},
};
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
};
static const struct file_operations tty_fops = {
.llseek = no_llseek,
.read = tty_read,
.write = tty_write,
.poll = tty_poll,
.unlocked_ioctl = tty_ioctl,
.compat_ioctl = tty_compat_ioctl,
.open = tty_open,
.release = tty_release,
.fasync = tty_fasync,
};
驱动入口函数
static int __init imx_serial_init(void)
{
ret = uart_register_driver(&imx_reg); //1.关键结构体的注册
ret = platform_driver_register(&serial_imx_driver); //2.关键结构体的注册
······
return ret;
}
module_init(imx_serial_init);
注册串口驱动 imx_reg
//serial_core.c
int uart_register_driver(struct uart_driver *drv)
{
struct tty_driver *normal;
normal = alloc_tty_driver(drv->nr);
drv->tty_driver = normal;
//drv是传进来的imx_reg
normal->driver_name = drv->driver_name; //即imx_reg->driver_name
normal->name = drv->dev_name; //即imx_reg->dev_name
normal->major = drv->major; //即imx_reg->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); //3.关键结构体的赋值,设置normal->ops = uart_ops
······
retval = tty_register_driver(normal);
}
//tty_io.c
int tty_register_driver(struct tty_driver *driver)
{
if (!driver->major) //imx_reg->major有设置,所以这里不成立
······
else {
dev = MKDEV(driver->major, driver->minor_start);
error = register_chrdev_region(dev, driver->num, driver->name); //注册字符设备ttymxc0~4
}
if (driver->flags & TTY_DRIVER_DYNAMIC_ALLOC)
error = tty_cdev_add(driver, dev, 0, driver->num);
list_add(&driver->tty_drivers, &tty_drivers); //将tty_driver(即传进来的normal)添加到全局链表tty_drivers
if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) {
for (i = 0; i < driver->num; i++)
d = tty_register_device(driver, i, NULL); //暂时没分析到
}
proc_tty_register_driver(driver);
driver->flags |= TTY_DRIVER_INSTALLED;
return 0;
}
static int tty_cdev_add(struct tty_driver *driver, dev_t dev,
unsigned int index, unsigned int count)
{
cdev_init(&driver->cdevs[index], &tty_fops); //4. 关键结构体的赋值,将tty_fops和字符设备cdev联系起来,注意tty_fops是file_operaionts类型哦,操作字符设备的接口集
driver->cdevs[index].owner = driver->owner;
return cdev_add(&driver->cdevs[index], dev, count);
}
//char_dev.c
void cdev_init(struct cdev *cdev, const struct file_operations *fops)
{
memset(cdev, 0, sizeof *cdev);
INIT_LIST_HEAD(&cdev->list);
kobject_init(&cdev->kobj, &ktype_cdev_default);
cdev->ops = fops; //关键操作
}
注册平台驱动 serial_imx_driver
int platform_driver_register(struct platform_driver *drv)
{
drv->driver.bus = &platform_bus_type;
if (drv->probe)
drv->driver.probe = platform_drv_probe;
if (drv->remove)
drv->driver.remove = platform_drv_remove;
if (drv->shutdown)
drv->driver.shutdown = platform_drv_shutdown;
return driver_register(&drv->driver);
}