// 首先系统启动时, 函数指针会调用con_init(), 代码在drivers/tty/vt/vt.c,函数指针代码如下:
/** Initialize the console device. This is called *early*, so* we can't necessarily depend on lots of kernel help here.* Just do some early initializations, and do the complex setup* later.*/
void __init console_init(void)
{
initcall_t *call;/* Setup the default TTY line discipline. */
tty_ldisc_begin();/*
* set up the console device so that later boot sequences can
* inform about problems etc..
*/
call = __con_initcall_start;
while (call < __con_initcall_end) {
(*call)();
call++;
}
}
// 对于我使用的pxa平台pxa.c中的uart驱动并未使用console_initcall(serial_pxa_init);而是用了下面的方式, 如下:
int __init serial_pxa_init(void)
{int ret;ret = uart_register_driver(&serial_pxa_reg);if (ret != 0)return ret;ret = platform_driver_register(&serial_pxa_driver);if (ret != 0)uart_unregister_driver(&serial_pxa_reg);return ret;
}void __exit serial_pxa_exit(void)
{platform_driver_unregister(&serial_pxa_driver);uart_unregister_driver(&serial_pxa_reg);
}module_init(serial_pxa_init);
/* 此方式为常规的设备驱动模块注册,所以按照这个段的链接顺序遍历函数指针并后续探测设备.
下面我们具体看下log信息:
[ 0.000000] ----------console_init----------
[ 0.000000] -------func pointer run-------start= c0019848, end= (null)
再看下地址0xc0019848的函数是什么,利用readelf(arm的)来看下是什么? 如下:
33064: c0019848 612 FUNC LOCAL DEFAULT 1 con_init
这样其实这里只有一个函数,就是con_init了.
然后到uart正真注册的时候将会把他替换掉,如下:
serial_pxa_probe ---> uart_add_one_port ---> uart_configure_port ---> register_console
这样uart就注册上了,其他tty相关的这里就不讲述了.
下面我们看看上层printf打印驱动中所需要的函数部分: */
struct uart_ops serial_pxa_pops = {
.tx_empty = serial_pxa_tx_empty,
.set_mctrl = serial_pxa_set_mctrl,
.get_mctrl = serial_pxa_get_mctrl,
.stop_tx = serial_pxa_stop_tx,
.start_tx = serial_pxa_start_tx,
.stop_rx = serial_pxa_stop_rx,
.enable_ms = serial_pxa_enable_ms,
.break_ctl = serial_pxa_break_ctl,
.startup = serial_pxa_startup,
.shutdown = serial_pxa_shutdown,
.set_termios = serial_pxa_set_termios,
.pm = serial_pxa_pm,
.type = serial_pxa_type,
.release_port = serial_pxa_release_port,
.request_port = serial_pxa_request_port,
.config_port = serial_pxa_config_port,
.verify_port = serial_pxa_verify_port,
};
/* 这个便是驱动代码给上面注册的函数了, 先看下第一个函数吧:serial_pxa_startup*/
static int serial_pxa_startup(struct uart_port *port)
{
struct uart_pxa_port *up = (struct uart_pxa_port *)port;
unsigned long flags;
int retval;if (port->line == 3) /* HWUART */
up->mcr |= UART_MCR_AFE;
else
up->mcr = 0;up->port.uartclk = clk_get_rate(up->clk);/*
* Allocate the IRQ
*/
retval = request_irq(up->port.irq, serial_pxa_irq, 0, up->name, up);
if (retval)
return retval;/*
* Clear the FIFO buffers and disable them.
* (they will be reenabled in set_termios())
*/
serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
serial_out(up, UART_FCR, 0);/*
* Clear the interrupt registers.
*/
(void) serial_in(up, UART_LSR);
(void) serial_in(up, UART_RX);
(void) serial_in(up, UART_IIR);
(void) serial_in(up, UART_MSR);/*
* Now, initialize the UART
*/
serial_out(up, UART_LCR, UART_LCR_WLEN8);spin_lock_irqsave(&up->port.lock, flags);
up->port.mctrl |= TIOCM_OUT2;
serial_pxa_set_mctrl(&up->port, up->port.mctrl);
spin_unlock_irqrestore(&up->port.lock, flags);/*
* Finally, enable interrupts. Note: Modem status interrupts
* are set via set_termios(), which will be occurring imminently
* anyway, so we don't enable them here.
*/
if (up->dma_enable) {
uart_pxa_dma_init(up);
up->rx_stop = 0;
pxa_uart_receive_dma_start(up);
up->ier = UART_IER_DMAE | UART_IER_UUE | UART_IER_RTOIE;
tasklet_init(&up->tklet, uart_task_action, (unsigned long)up);
} else {
up->ier = UART_IER_RLSI | UART_IER_RDI |
UART_IER_RTOIE | UART_IER_UUE;
}
serial_out(up, UART_IER, up->ier);/*
* And clear the interrupt registers again for luck.
*/
(void) serial_in(up, UART_LSR);
(void) serial_in(up, UART_RX);
(void) serial_in(up, UART_IIR);
(void) serial_in(up, UART_MSR);return 0;
}/* 要读明白这块代码首先需要把uart的寄存器部分手册再仔细阅读下,然后再来看会比较好,或者边看代码边看手册,首先得到了uart的时钟,然后请求中断,中断处理函数内容如下:*/
static inline irqreturn_t serial_pxa_irq(int irq, void *dev_id)
{
struct uart_pxa_port *up = dev_id;
unsigned int iir, lsr;iir = serial_in(up, UART_IIR);
if (iir & UART_IIR_NO_INT)
return IRQ_NONE;/* timer is not active */
if (!mod_timer(&up->pxa_timer, jiffies + PXA_TIMER_TIMEOUT)) {
#ifdef CONFIG_PXA95x
dvfm_disable_lowpower(up->dvfm_dev_idx[PXA_UART_RX]);
#elif defined(CONFIG_WAKELOCK) && defined(CONFIG_CPU_PXA910)
wake_lock(&up->idle_lock[PXA_UART_RX]);
#else
pm_qos_update_request(&up->qos_idle[PXA_UART_RX],
PM_QOS_CONSTRAINT);
#endif
}lsr = serial_in(up, UART_LSR);
if (up->dma_enable) {
if (UART_LSR_FIFOE & lsr)
pxa_uart_receive_dma_err(up, &lsr);if (iir & UART_IIR_TOD)
dma_receive_chars(up, &lsr);
} else {
if (lsr & UART_LSR_DR)
receive_chars(up, &lsr);check_modem_status(up);
if (lsr & UART_LSR_THRE) {
transmit_chars(up);
/* wait Tx empty */
while (!serial_pxa_tx_empty(\
(struct uart_port *)dev_id))
;
}
}return IRQ_HANDLED;
}
/*
中断处理函数中先获得中断验证寄存器的内容,然后验证是否有中断等待处理(pending),没有的话直接返回;
假如有的话那么继续下去。定时器部分就不看了,因为那部分代码我也没太看懂,有高手的话补充下... ...下面读LSR寄存器(这个寄存器被读数据状态发送状态),所以非常重要,有一些发送过程中的错误在这里一般会有记录。所以下面就是根据一些触发中断后的状态信息去做相应处理了,如下:
假设dma启用的话,先判断是否FIFI错误,手册上说是至少一个校验错误,帧错误,或者是break indication for any of the chars in the FIFO,这个寄存器在所有错误字节被从FIFO中读后才被reset。所以下面就调用相应的错误处理了。这里就不展开了,下面的代码都是一系列的错误处理。
下面再判断是否是FIFO模式下Time out interrupt,是的话那么调用dma_receive_chars,这是启用DMA的情况,那么不启用DMA的情况这个函数变为receive_chars,然后就是调用check_modem_status这个函数了,这个函数其实很简单就是读MSR寄存器,然后检查寄存器的字段是否改变了, 对于CTS字段改变的结果是或者交换数据或者停止,不启用DMA就到这里了。
这个处理函数还有些具体函数被展开,只能以后再慢慢补充。下面回到serial_pxa_startup这个函数,注册中断完事后,下面注释里面也讲的很清楚了,然后再清除中断寄存器,再然后就是这个函数serial_out(up, UART_LCR, UART_LCR_WLEN8);了,他很简单就是指定word length select,有7位和8位,这里指定了8位。下面明天再续了,今天没时间写了。
*/
详细解决方案
pxa2128 linux kernel console_init 控制台初始化
热度:23 发布时间:2023-12-15 03:40:55.0
相关解决方案
- linux+tomcat部署JSP项目有关问题,找不到jar依赖包
- linux 上log4j使用,日志输出的配置
- linux 上Tomcat不解析.war包
- 使用moto sdk 6.2 for linux 模拟器调试 蓝牙程序时的有关问题
- 文件下传到系统中后,没有执行权限(linux)
- linux 命令 求解解决方法
- Linux,Java,net国内市场的占有率怎么
- Linux 和windows中文乱码解决办法
- linux 上安装oracle10g
- linux 下安装oracle10g,该如何解决
- oralce 11g 32位 for linux RH5 安装神奇有关问题
- linux g_serial 的模块装配!
- 求真相,linux &arm 和c\c++有关的开发真的如何悲剧吗
- linux 如何运行c程序
- arm-linux-gcc下的字节对齐有关问题
- 好久没来CSDN了,散分,顺便说一句如何没有嵌入式开发(linux)
- linux下怎么使用arm-linux-gcc编译器
- 怪事【AT91RM9200+LINUX+PC6脚】
- linux+wifi+ap的一些有关问题
- linux 装置模型
- linux 有关问题
- linux 下汇编有关问题3,高人指教!
- linux 下汇编有关问题2,高人指教!
- linux 下汇编有关问题,高人指教!
- linux 下汇编有关问题,高人指教,初学,
- linux 下汇编有关问题4,高人指教!
- redhat5 linux 下汇编有关问题
- linux 上 WebSphere日志中文乱码
- suse linux 11上安装wepsphere6.1 报错?
- linux ubuntu 安装webspher,该如何解决