首页 技术 正文
技术 2022年11月16日
0 收藏 545 点赞 3,332 浏览 11176 个字

一、UART初始化

1. kernel-3.18/drivers/misc/mediatek/uart/uart.c

 static int __init mtk_uart_init(void)
{
int ret = ; tx_history.buffer = kzalloc(UART_HISTORY_DATA_SIZE, GFP_KERNEL);
rx_history.buffer = kzalloc(UART_HISTORY_DATA_SIZE, GFP_KERNEL);
tx_history.index = -;
rx_history.index = -; if (!tx_history.buffer || !rx_history.buffer)
return -ENOMEM; #ifndef CONFIG_MTK_SERIAL_CONSOLE
mtk_uart_init_ports();
#endif #if defined(ENABLE_SYSFS)
mtk_uart_sysfs();
#endif ret = uart_register_driver(&mtk_uart_drv); if (ret)
return ret; ret = platform_driver_register(&mtk_uart_dev_drv); if (ret) {
uart_unregister_driver(&mtk_uart_drv);
return ret;
}
#ifdef CONFIG_PM
mtk_uart_init_ops();
#endif #ifdef ENABLE_RAW_DATA_DUMP
mtk_uart_init_debug_spinlock();
#endif
spin_lock_init(&mtk_uart_bt_lock);
return ret;
}

第 21 行调用 uart_register_driver 函数注册 mtk_uart_drv。

mtk_uart_drv 结构如下:

 static struct uart_driver mtk_uart_drv = {
.owner = THIS_MODULE,
.driver_name = DRV_NAME,
.dev_name = "ttyMT",
.major = UART_MAJOR,
.minor = UART_MINOR,
.nr = UART_NR,
#if defined(CONFIG_MTK_SERIAL_CONSOLE) && !defined(CONFIG_MTK_SERIAL_MODEM_TEST)
.cons = &mtk_uart_console,
#endif
};
 static struct console mtk_uart_console = {
.name = "ttyMT",
#if !defined(CONFIG_MTK_SERIAL_MODEM_TEST)
/*don't configure UART4 as console */
.write = mtk_uart_console_write,
.setup = mtk_uart_console_setup,
#endif
.device = uart_console_device,
.flags = CON_PRINTBUFFER,
.index = -,
.data = &mtk_uart_drv,
};

uart_register_driver 函数定义在 kernel-3.18/drivers/tty/serial/serial_core.c 文件中,

 /**
* uart_register_driver - register a driver with the uart core layer
* @drv: low level driver structure
*
* Register a uart driver with the core driver. We in turn register
* with the tty layer, and initialise the core driver per-port state.
*
* We have a proc file in /proc/tty/driver which is named after the
* normal driver.
*
* drv->port should be NULL, and the per-port structures should be
* registered using uart_add_one_port after this call has succeeded.
*/
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 = ; 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;
port->close_delay = HZ / ; /* .5 seconds */
port->closing_wait = * HZ;/* 30 seconds */
} retval = tty_register_driver(normal);
if (retval >= )
return retval; for (i = ; i < drv->nr; i++)
tty_port_destroy(&drv->state[i].port);
put_tty_driver(normal);
out_kfree:
kfree(drv->state);
out:
return -ENOMEM;
}

第 33行,uart驱动与tty_driver关联起来。

第 43 行,设置 uart 的初始波特率。

第 46 行,将 tty_driver 的操作集统一设为了 uart_ops.这样就使得从用户空间下来的操作可以找到正确的 serial_core 的操作函数。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,
.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
};

第 56 行,uart_port_ops 结构体如下:

static const struct tty_port_operations uart_port_ops = {
.activate = uart_port_activate,
.shutdown = uart_port_shutdown,
.carrier_raised = uart_carrier_raised,
.dtr_rts = uart_dtr_rts,
};

第 61 行,调用 tty_register_driver 函数,其所在文件为 kernel-3.18/drivers/tty/tty_io.c。

 /*
* Called by a tty driver to register itself.
*/
int tty_register_driver(struct tty_driver *driver)
{
int error;
int i;
dev_t dev;
struct device *d; 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);
}
if (error < )
goto err; if (driver->flags & TTY_DRIVER_DYNAMIC_ALLOC) {
error = tty_cdev_add(driver, dev, 0, driver->num);
if (error)
goto err_unreg_char;
} mutex_lock(&tty_mutex);
list_add(&driver->tty_drivers, &tty_drivers);
mutex_unlock(&tty_mutex); if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) {
for (i = ; i < driver->num; i++) {
d = tty_register_device(driver, i, NULL);
if (IS_ERR(d)) {
error = PTR_ERR(d);
goto err_unreg_devs;
}
}
}
proc_tty_register_driver(driver);
driver->flags |= TTY_DRIVER_INSTALLED;
return ; err_unreg_devs:
for (i--; i >= ; i--)
tty_unregister_device(driver, i); mutex_lock(&tty_mutex);
list_del(&driver->tty_drivers);
mutex_unlock(&tty_mutex); err_unreg_char:
unregister_chrdev_region(dev, driver->num);
err:
return error;
}
EXPORT_SYMBOL(tty_register_driver);

MKDEV 宏定义在 include/linux/kdev_t.h 头文件,#define MKDEV(ma,mi) (((ma)<< MINORBITS) | (mi)) 作用是将主设备号和次设备号转换成 dev_t 类型。

register_chrdev_region 为一个字符驱动获取一个或多个设备编号。

调用 cdev_add() 函数,将cdev添加到系统中去。

因normal->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; 故没有调用tty_register_device来创建ttyMT0~ttyMT3设备。

调用proc_tty_register_driver创建/proc/tty/driver/mtk-uart文件。其driver->ops->proc_fops 为uart_ops结构体中的uart_proc_fops函数。

回到 uart_register_driver函数,调用 put_tty_driver 函数,当注册失败时,判断引用计数注销驱动。

二、回到 mtk_uart_init 函数,调用 platform_driver_register 函数注册 mtk_uart_dev_drv。

static struct platform_driver mtk_uart_dev_drv = {
.probe = mtk_uart_probe,
.remove = mtk_uart_remove,
#ifdef CONFIG_PM
.suspend = mtk_uart_suspend,
.resume = mtk_uart_resume,
#endif
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
#ifdef CONFIG_OF
.of_match_table = apuart_of_ids,
#endif
#ifdef CONFIG_PM
.pm = &mtk_uart_pm_ops,
#endif }
};

mtk_uart_probe函数如下:

static int mtk_uart_probe(struct platform_device *pdev)
{
struct mtk_uart *uart;
int err;
#if !defined(CONFIG_FPGA_EARLY_PORTING)
#if !defined(CONFIG_MTK_CLKMGR)
static const char * const clk_uart_name[] = {
"uart0-main",
"uart1-main",
"uart2-main",
"uart3-main",
"uart4-main",
};
struct mtk_uart_setting *uart_setting = NULL;
#endif
#if !defined(CONFIG_MTK_LEGACY)
/* for GPIO pinctrl */
struct pinctrl *ppinctrl = NULL;
#endif
#endif /* !defined(CONFIG_FPGA_EARLY_PORTING) */#ifdef CONFIG_OF
if (pdev->dev.of_node) {
struct device_node *node = pdev->dev.of_node; err = of_property_read_u32(node, "cell-index", &pdev->id);
if (err)
pr_err("[DTS] get uart platform_device id fail!!\n");
}
if (pdev->id >= UART_NR) {
pr_err("DTS cell ID %d > UART nuber %d\n", pdev->id, UART_NR);
return -ENODEV;
}
#endif
uart = &mtk_uarts[pdev->id];
MSG_FUNC_ENTRY();/* For clock setting */
#if !defined(CONFIG_MTK_CLKMGR) && !defined(CONFIG_FPGA_EARLY_PORTING)
uart_setting = get_uart_default_settings(pdev->id);
uart_setting->clk_uart_main = devm_clk_get(&pdev->dev, clk_uart_name[pdev->id]);
if (IS_ERR(uart_setting->clk_uart_main)) {
pr_err("[UART%d][CCF]cannot get %s clock. ptr_err:%ld\n", pdev->id, clk_uart_name[pdev->id]
, PTR_ERR(uart_setting->clk_uart_main));
return PTR_ERR(uart_setting->clk_uart_main);
}
pr_debug("[UART%d][CCF]clk_uart%d_main:%p\n", pdev->id, pdev->id, uart_setting->clk_uart_main); if (pdev->id == ) {
struct clk *clk_uart0_dma = devm_clk_get(&pdev->dev, "uart-apdma"); if (IS_ERR(clk_uart0_dma)) {
pr_err("[UART][CCF]cannot get clk_uart0_dma clock. ptr_err:%ld\n", PTR_ERR(clk_uart0_dma));
return PTR_ERR(clk_uart0_dma);
}
set_uart_dma_clk(pdev->id, clk_uart0_dma);
pr_debug("[UART][CCF]clk_uart0_dma:%p\n", clk_uart0_dma);
}
#else /* !defined(CONFIG_MTK_CLKMGR) && !defined(CONFIG_FPGA_EARLY_PORTING) */
pr_debug("[UART][CCF]mtk_uart_probe CONFIG_MTK_CLKMGR or CONFIG_FPGA_EARLY_PORTING is defined!\n");
#endif /*!defined(CONFIG_MTK_CLKMGR) && !defined(CONFIG_FPGA_EARLY_PORTING) *//* For GPIO setting */
#if !defined(CONFIG_MTK_LEGACY) && !defined(CONFIG_FPGA_EARLY_PORTING)
ppinctrl = devm_pinctrl_get(&pdev->dev);
if (IS_ERR(ppinctrl)) {
err = PTR_ERR(ppinctrl);
pr_err("[UART%d][PinC]cannot find pinctrl. ptr_err:%ld\n", pdev->id, PTR_ERR(ppinctrl));
set_uart_pinctrl(pdev->id, NULL);
} else {
set_uart_pinctrl(pdev->id, ppinctrl);
}
pr_debug("[UART%d][PinC]set idx:%d, ppinctrl:%p\n", pdev->id, pdev->id, ppinctrl);
#else /* !defined(CONFIG_MTK_LEGACY) && !defined(CONFIG_FPGA_EARLY_PORTING) */
pr_debug("[UART][PinC]mtk_uart_probe CONFIG_MTK_LEGACY or CONFIG_FPGA_EARLY_PORTING is defined!\n");
#endif /* !defined(CONFIG_MTK_LEGACY) && !defined(CONFIG_FPGA_EARLY_PORTING) */ if (uart->setting->support_33bits) {
pdev->dev.coherent_dma_mask = DMA_BIT_MASK();
if (dma_set_mask(&pdev->dev, DMA_BIT_MASK())) {
dev_err(&pdev->dev, "dma_set_mask return error.\n");
return -EINVAL;
}
} else {
pdev->dev.coherent_dma_mask = DMA_BIT_MASK();
}
uart->port.dev = &pdev->dev;
err = uart_add_one_port(&mtk_uart_drv, &uart->port);
if (!err)
platform_set_drvdata(pdev, uart);#if defined(ENABLE_VFIFO)
err = mtk_uart_vfifo_create(uart);
if (err) {
mtk_uart_vfifo_delete(uart);
DEV_ERR("create vff buffer fail:%d\n", err);
}
#endif
return err;
}

调用uart_add_one_port向串口驱动添加一个端口。其具体实现在Kernel-3.18/drivers/tty/serial/Serial_core.c

/**
* uart_add_one_port - attach a driver-defined port structure
* @drv: pointer to the uart low level driver structure for this port
* @uport: uart port structure to use for this port.
*
* This allows the driver to register its own uart_port structure
* with the core driver. The main purpose is to allow the low
* level uart drivers to expand uart_port, rather than having yet
* more levels of structures.
*/
int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
{
struct uart_state *state;
struct tty_port *port;
int ret = ;
struct device *tty_dev;
int num_groups; BUG_ON(in_interrupt()); if (uport->line >= drv->nr)
return -EINVAL; state = drv->state + uport->line;
port = &state->port; mutex_lock(&port_mutex);
mutex_lock(&port->mutex);
if (state->uart_port) {
ret = -EINVAL;
goto out;
} state->uart_port = uport;
state->pm_state = UART_PM_STATE_UNDEFINED; uport->cons = drv->cons;
uport->state = state; /*
* If this port is a console, then the spinlock is already
* initialised.
*/
if (!(uart_console(uport) && (uport->cons->flags & CON_ENABLED))) {
spin_lock_init(&uport->lock);
lockdep_set_class(&uport->lock, &port_lock_key);
}
if (uport->cons && uport->dev)
of_console_check(uport->dev->of_node, uport->cons->name, uport->line); uart_configure_port(drv, state, uport); num_groups = ;
if (uport->attr_group)
num_groups++; uport->tty_groups = kcalloc(num_groups, sizeof(*uport->tty_groups),
GFP_KERNEL);
if (!uport->tty_groups) {
ret = -ENOMEM;
goto out;
}
uport->tty_groups[] = &tty_dev_attr_group;
if (uport->attr_group)
uport->tty_groups[] = uport->attr_group; /*
* Register the port whether it's detected or not. This allows
* setserial to be used to alter this port's parameters.
*/
tty_dev = tty_port_register_device_attr(port, drv->tty_driver,
uport->line, uport->dev, port, uport->tty_groups);
if (likely(!IS_ERR(tty_dev))) {
device_set_wakeup_capable(tty_dev, );
} else {
dev_err(uport->dev, "Cannot register tty device on line %d\n",
uport->line);
} /*
* Ensure UPF_DEAD is not set.
*/
uport->flags &= ~UPF_DEAD; out:
mutex_unlock(&port->mutex);
mutex_unlock(&port_mutex); return ret;
}

调用uart_configure_port函数进行端口配置。

调用tty_port_register_device_attr创建ttyMT0~ttyMT3设备。

下一篇: 小程序rpx
相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,491
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,907
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,740
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,493
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:8,132
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:5,294