MTK UART串口调试
一、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串口调试的更多相关文章
- Linux下使用putty进行UART串口调试【转】
本文转载自:http://blog.csdn.net/xzongyuan/article/details/11593101 版权声明:本文为博主原创文章,未经博主允许不得转载. 使用putty进行串口 ...
- RPi 2B UART作为调试口或者普通串口
/************************************************************************************** * RPi 2B UAR ...
- (三) UART 串口通讯
UART : university asynchronous receiver and transmitter UART // 通用异步接收器和发送器 为什么要有串口:因为许多嵌入式设备没有显示屏 ...
- keil中的串口调试:
keil中串口的虚拟调试信息在通过View-serial windows-#usart1/2/3/4/debug(printf)可以看到.当然也可以通过虚拟串口VSPD+串口调试助手在外部实现,方法如 ...
- 【接口时序】3、UART串口收发的原理与Verilog实现
一.软件平台与硬件平台 软件平台: 1.操作系统:Windows-8.1 2.开发套件:ISE14.7 3.仿真工具:ModelSim-10.4-SE 硬件平台: 1.FPGA型号:XC6SLX45- ...
- 第十六章 IIC协议详解+UART串口读写EEPROM
十六.IIC协议详解+Uart串口读写EEPROM 本文由杭电网友曾凯峰根据小梅哥FPGA IIC协议基本概念公开课内容整理并最终编写Verilog代码实现使用串口读写EEPROM的功能. 以下为原文 ...
- stm32中如何进行printf重定向用于串口调试输出
1 在main中包含stdio.h 文件 2 Target选项框里选Use MicroLib 选项 3 在main中添加UART1_Configuration()初始化的代码 Uart1初始化,voi ...
- 基于STM32之UART串口通信协议(一)详解
一.前言 1.简介 写的这篇博客,是为了简单讲解一下UART通信协议,以及UART能够实现的一些功能,还有有关使用STM32CubeMX来配置芯片的一些操作,在后面我会以我使用的STM32F429开发 ...
- 【HC89S003F4开发板】 3串口调试
HC89S003F4开发板串口调试 使用资料自带的demo 主程序 /************************************系统初始化************************ ...
随机推荐
- 《从0到1》读书笔记第一章"未来的挑战"第2记:做老子还是做孙子
从1到N VS 从0到1 - 别让自己的小鸡鸡抓在别人的手上 近几年国内互联网创业上非常流行一种C2C(也就是Copy to China - 复制到中国)的创业模式,打的就是一个时间差和地域差.将在国 ...
- [LeedCode OJ]#85 Maximal Rectangle
[ 声明:版权全部,转载请标明出处.请勿用于商业用途. 联系信箱:libin493073668@sina.com] 题目链接:https://leetcode.com/problems/maxima ...
- [Algorithm] Linked List Data Structure in JavaScript
A linked list is a collection of items where each item points to the next one in the list. Because o ...
- Selenium系列之--08 操作已打开的浏览器
Can Selenium interact with an existing browser session? 参考上面的文章 1. 建一个ReuseWebDriver类 import java.io ...
- C# 将cookie写入WebBrowser
string cookie = ""; foreach (string c in cookie.Split(';')) { string[] item = c.Split('=') ...
- IO模式——同步(堵塞、非堵塞)、异步
为什么IO模式非常重要?由于现代的计算机和操作系统的架构决定了CPU是稀缺资源,大家都要来一起竞争.而IO(特别是网络相关的IO)的速度往往较慢.所以怎样进行IO就有了多种模式,包含同步.异步.堵塞. ...
- Fighting regressions with git bisect---within git bisect algorithm
https://www.kernel.org/pub/software/scm/git/docs/git-bisect-lk2009.html Fighting regressions with gi ...
- hessian实战1
服务端: 1.新建MAVEN HessianServer 项目 2.新建接口 Basic public interface Basic { String hello(String name); Str ...
- BUAAOO P13-P14 UML Interaction
- [转]JavaScript
javascript 1. oncontextmenu="window.event.returnValue=false" 将彻底屏蔽鼠标右键 <table border on ...