一、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设备。

MTK UART串口调试的更多相关文章

  1. Linux下使用putty进行UART串口调试【转】

    本文转载自:http://blog.csdn.net/xzongyuan/article/details/11593101 版权声明:本文为博主原创文章,未经博主允许不得转载. 使用putty进行串口 ...

  2. RPi 2B UART作为调试口或者普通串口

    /************************************************************************************** * RPi 2B UAR ...

  3. (三) UART 串口通讯

    UART  : university asynchronous receiver and transmitter UART  // 通用异步接收器和发送器 为什么要有串口:因为许多嵌入式设备没有显示屏 ...

  4. keil中的串口调试:

    keil中串口的虚拟调试信息在通过View-serial windows-#usart1/2/3/4/debug(printf)可以看到.当然也可以通过虚拟串口VSPD+串口调试助手在外部实现,方法如 ...

  5. 【接口时序】3、UART串口收发的原理与Verilog实现

    一.软件平台与硬件平台 软件平台: 1.操作系统:Windows-8.1 2.开发套件:ISE14.7 3.仿真工具:ModelSim-10.4-SE 硬件平台: 1.FPGA型号:XC6SLX45- ...

  6. 第十六章 IIC协议详解+UART串口读写EEPROM

    十六.IIC协议详解+Uart串口读写EEPROM 本文由杭电网友曾凯峰根据小梅哥FPGA IIC协议基本概念公开课内容整理并最终编写Verilog代码实现使用串口读写EEPROM的功能. 以下为原文 ...

  7. stm32中如何进行printf重定向用于串口调试输出

    1 在main中包含stdio.h 文件 2 Target选项框里选Use MicroLib 选项 3 在main中添加UART1_Configuration()初始化的代码 Uart1初始化,voi ...

  8. 基于STM32之UART串口通信协议(一)详解

    一.前言 1.简介 写的这篇博客,是为了简单讲解一下UART通信协议,以及UART能够实现的一些功能,还有有关使用STM32CubeMX来配置芯片的一些操作,在后面我会以我使用的STM32F429开发 ...

  9. 【HC89S003F4开发板】 3串口调试

    HC89S003F4开发板串口调试 使用资料自带的demo 主程序 /************************************系统初始化************************ ...

随机推荐

  1. linux系列之-—02 设置和查看环境变量

    一.Linux环境变量种类 按变量的生存周期来划分,Linux变量可分为两类: 1 永久的:需要修改配置文件,变量永久生效. 2 临时的:使用export命令声明即可,变量在关闭shell时失效. 二 ...

  2. GIS+=地理信息+行业+大数据——纽约公开11亿条出租车和Uber原始数据下载及分析

    一览众山小编辑团队 原文/ Todd Schneider 翻译/ 沈玮薇 陈翚 文献/ 蒋理 校核/ 众山小编辑/ 众山小 排版/ 徐颖 2014-2015 © 转载请注明:源自公众号"一览 ...

  3. 显示和隐藏Mac隐藏文件的命令

    显示Mac隐藏文件的命令:defaults write com.apple.finder AppleShowAllFiles -bool true 隐藏Mac隐藏文件的命令:defaults writ ...

  4. HTML5开发移动web应用—JQuery Mobile(1)

    JQuery Mobile是一个简单易用的web移动app开发框架.使用它就像使用jQuery一样,引入必要的文件就可以. 最基础的jQuery Mobile文件的结构代码例如以下: <body ...

  5. Spark 性能相关參数配置具体解释-shuffle篇

    作者:刘旭晖 Raymond 转载请注明出处 Email:colorant at 163.com BLOG:http://blog.csdn.net/colorant/ 随着Spark的逐渐成熟完好, ...

  6. 关于angular JS 中$timeOut 的一些不正常情况下的$destory

    最近项目中存在的问题头疼脑热了好一会. 我先简单说明下问题是由,使用$timeOut循环调用的时候由于页面存在异步加载会出现反复执行循环反复调用$timeOut,怎么清除跳出循环都不管用.于是查到了如 ...

  7. centos 6 7 differences 区别

    命令 centos6 centos7 ifconfig 有 有 yum install -y net-tools 服务管理 chkconfig /etc/init.d/服务 systemctl sys ...

  8. 在JS中将JSON的字符串解析成JSON数据格式

    使用eval函数来解析 <script> var data="{root: [{name:'1',value:'0'},{name:'6101',value:'北京市'},{na ...

  9. windows 复制 文本文件内容 到剪切板

    shell  打开 type filename | clip

  10. Problem binding to [bigdata-server-01:9000] java.net.BindException: Cannot assign requested address;

    If the port is "0", then the OS is looking for any free port -so the port-in-use and port- ...