uclinux-2008R1-RC8(bf561)到VDSP5的移植(58): unable to
2019-07-13 17:02发布
生成海报
快乐虾
http://blog.csdn.net/lights_joy/
lights@hb165.com
本文适用于
ADI bf561 DSP
优视BF561EVB开发板
uclinux-2008r1-rc8 (移植到vdsp5)
Visual DSP++ 5.0
欢迎转载,但请保留作者信息
碰到一个郁闷的问题,提示” unable to open an initial console”后再没有下文了。
搜了下这个错误出现的位置,在init_post函数中:
if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)
printk(KERN_WARNING "Warning: unable to open an initial console./n");
刚开始以为是没有正确建立/dev/console的缘故,但是跟踪进去后才发现不是那么回事,/dev/console已经正确的创建了,问题出现在tty_open函数。
在这个函数里,它首先取得console的tty_driver:
if (device == MKDEV(TTYAUX_MAJOR,1)) {
driver = console_device(&index);
if (driver) {
/* Don't let /dev/console block */
filp->f_flags |= O_NONBLOCK;
noctty = 1;
goto got_driver;
}
mutex_unlock(&tty_mutex);
return -ENODEV;
}
看下console_device的实现:
/*
* Return the console tty driver structure and its associated index
*/
struct tty_driver *console_device(int *index)
{
struct console *c;
struct tty_driver *driver = NULL;
acquire_console_sem();
for (c = console_drivers; c != NULL; c = c->next) {
if (!c->device)
continue;
driver = c->device(c, index);
if (driver)
break;
}
release_console_sem();
return driver;
}
它将查找所有可用的console,找到一个提供了tty_driver的console并返回。在内核中,实际使用的console由bfin_serial_console(drivers/serial/bfin_5xx.c)这个全局变量来描述。在这个结构体中提供了device回调函数用以取得这个console所使用的tty_driver:
static struct console bfin_serial_console = {
.name = BFIN_SERIAL_NAME,
.write = bfin_serial_console_write,
.device = uart_console_device,
.setup = bfin_serial_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
.data = &bfin_serial_reg,
};
看看uart_console_device函数(drivers/serial/serial_core.c)的代码:
struct tty_driver *uart_console_device(struct console *co, int *index)
{
struct uart_driver *p = co->data;
*index = co->index;
return p->tty_driver;
}
在这里console的data指向bfin_serial_reg,这也是一个全局变量,其定义在drivers/serial/bfin_5xx.c文件中:
static struct uart_driver bfin_serial_reg = {
.owner = THIS_MODULE,
.driver_name = "bfin-uart",
.dev_name = BFIN_SERIAL_NAME,
.major = BFIN_SERIAL_MAJOR,
.minor = BFIN_SERIAL_MINOR,
.nr = NR_PORTS,
.cons = BFIN_SERIAL_CONSOLE,
};
这里没有明确指出它使用的tty_driver。它将在uart_register_driver函数中动态创建。
/**
* 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 = NULL;
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);
retval = -ENOMEM;
if (!drv->state)
goto out;
normal = alloc_tty_driver(drv->nr);
if (!normal)
goto out;
drv->tty_driver = normal;
normal->owner = drv->owner;
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 = 0; i < drv->nr; i++) {
struct uart_state *state = drv->state + i;
state->close_delay = 500; /* .5 seconds */
state->closing_wait = 30000; /* 30 seconds */
mutex_init(&state->mutex);
}
retval = tty_register_driver(normal);
out:
if (retval < 0) {
put_tty_driver(normal);
kfree(drv->state);
}
return retval;
}
从这个函数知道,通过uart_driver->tty_driver可以取得一个uart_driver对应的tty_driver,而通过tty_driver->driver_state则可以取得相应的uart_driver,它们相互引用。通过tty_set_operations函数的调用,tty_driver取得了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,
.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
.read_proc = uart_read_proc,
#endif
.tiocmget = uart_tiocmget,
.tiocmset = uart_tiocmset,
};
现在回到tty_open函数上来。
在取得console driver之后,tty_open接着进行如下调用:
retval = init_dev(driver, index, &tty);
在这个调用中,初始化了一个tty_struct,并将此结构体中的driver成员设置为指向bfin_serial_console这个全局变量指定的tty_driver,也就是在uart_register_driver函数中创建的那个结构体,接下来:
if (tty->driver->open)
retval = tty->driver->open(tty, filp);
else
retval = -ENODEV;
从uart_register_driver函数可知,tty->driver->open这个回调函数指向uart_ops中的
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮