DSP

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函数。 在这个函数里,它首先取得consoletty_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_driverconsole并返回。在内核中,实际使用的consolebfin_serial_consoledrivers/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; } 在这里consoledata指向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中的