分类: LINUX
2014-03-27 23:35:17
高版本的linux2.6内核中已经把kgdb集成到内核中了,但若想在s3c2440平台上使用kgdb还需对内核做一些修改。
下面我们就来分析一下如何修改内核使kgdb可用。
在drivers/serial/kgdboc.c文件中有一行代码module_init(init_kgdboc),所以在内核启动的时候会调用init_kgdboc
函数,函数调用关系为init_kgdboc->configure_kgdboc->tty_find_polling_driver,函数tty_find_polling_driver主要
做的工作是根据命令行参数kgdboc在已经注册的tty设备中选择对应的设备,这里假设我们用串口2作为kgdb所使用
的串口,则设置u-boot引导参数bootargs时有这么一句kgdboc=ttySAC2 kgdbwait,这样就选则串口2作为kgdb的
通信串口了。但是tty_find_polling_driver函数存在一个问题,if (strncmp(name, p->name, len) != 0)这句应该改为
if (strncmp(name, p->driver_name, len) != 0)因为串口2的p->name是s3c2410-uart,p->driver_name才是ttySAC。
我们继续朝下,tty_find_polling_driver中找到tty设备后调用设备的poll_init函数(p->ops->poll_init)。
那串口2的poll_init的函数是在哪定义的呢?在文件drivers/serial/samsung.c中有这么一句
module_init(s3c24xx_serial_modinit);这样s3c24xx_serial_modinit将在初始化的时候被调用,调用关系如下:
s3c24xx_serial_modinit->uart_register_driver,在函数uart_register_driver中有这么一句tty_set_operations(normal, &uart_ops);
到这里我们就知道串口2的poll_init函数在uart_ops中被初始化即为uart_poll_init:
static const struct tty_operations uart_ops = {
......
#ifdef CONFIG_CONSOLE_POLL
.poll_init = uart_poll_init,
.poll_get_char = uart_poll_get_char,
.poll_put_char = uart_poll_put_char,
#endif
};
我们注意到这里在配置内核的时候要定义CONFIG_CONSOLE_POLL宏。所以串口2的poll_init即为uart_poll_init函数,这个函数主要做一些验
证工作,这里有一个关键的地方if (!(port->ops->poll_get_char && port->ops->poll_put_char))检测串口的poll_get_char和poll_put_char
有没有定义,在2.6.34.14内核中这两个函数没有定义我们要在文件drivers/serial/samsung.c中添加,代码如下:
static void s3c24xx_serial_get_char(struct uart_port *port)
{
unsigned int ufcon = rd_regl(port, S3C2410_UFCON);
unsigned long ufstat, utrstat;
while(1){
if (ufcon & S3C2410_UFCON_FIFOMODE) {
ufstat = rd_regl(port, S3C2410_UFSTAT);
if(ufstat & 0x3f)
return rd_regl(port, S3C2410_URXH);
}
else{
utrstat = rd_regl(port, S3C2410_UTRSTAT);
if(utrstat & 0x01)
return rd_regl(port, S3C2410_URXH);
}
barrier();
}
}
static int
s3c24xx_serial_txrdy(struct uart_port *port, unsigned int ufcon)
{
struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);
unsigned long ufstat, utrstat;
if (ufcon & S3C2410_UFCON_FIFOMODE) {
/* fifo mode - check amount of data in fifo registers... */
ufstat = rd_regl(port, S3C2410_UFSTAT);
return (ufstat & info->tx_fifofull) ? 0 : 1;
}
/* in non-fifo mode, we go and use the tx buffer empty */
utrstat = rd_regl(port, S3C2410_UTRSTAT);
return (utrstat & S3C2410_UTRSTAT_TXE) ? 1 : 0;
}
static void s3c24xx_serial_put_char(struct uart_port *port,unsigned char ch)
{
unsigned int ufcon = rd_regl(port, S3C2410_UFCON);
while (!s3c24xx_serial_txrdy(port, ufcon))
barrier();
wr_regb(port, S3C2410_UTXH, ch);
}
static struct uart_ops s3c24xx_serial_ops = {
.poll_put_char = s3c24xx_serial_put_char,
.poll_get_char = s3c24xx_serial_get_char,
};
添加这些代码后kgdb就可以正确的初始化了,现在回到init_kgdboc函数,最终会把串口2的tty_driver赋值给kgdb_tty_driver,
以后kgdb就可以通过kgdb_tty_driver接送和发送串口2的数据了。
最后多说一句要用在想使用kgdb要在配置内核的时候勾选上相关的选项。