您现在的位置: 华盟网 >> 编程 >> Vc >> 正文

编译uclinux console实现

2012/6/7 作者:不详 来源: 华盟收集
导读 我们知道,在uclinux初始化过程中,直到console_init调用之前是没有任何输出的,它们的输出都放在__log_buf这个缓冲内的,在console_…

  我们知道,在uclinux初始化过程中,直到console_init调用之前是没有任何输出的,它们的输出都放在__log_buf这个缓冲内的,在console_init调用时再将这个缓冲区内的数据一次性输出。

  那么console_init又做了什么工作呢?

  /*

  * 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. */

  (void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);

  /*

  * set up the console device so that later boot sequences can

  * inform about problems etc

  */

  #ifdef CONFIG_EARLY_PRINTK

  disable_early_printk();

  #endif

  call = __con_initcall_start;

  while (call < __con_initcall_end) {

  (*call)();

  call++;

  }

  }

  从这个函数大致可以猜出,console和串口的初始化操作应该是由__con_initcall_start到__con_initcall_end之间的函数调用来完成的。那么放到这段空间中的函数是怎么来的呢?又是什么函数可以放在这段空间中呢?

  让我们看看LDF文件中对这两个符号的定义吧:

  ___con_initcall_start = .;

  INPUT_SECTIONS($LIBRARIES_SML3_CM(。con_initcall.init))

  ___con_initcall_end = .;

  原来,这段空间中存放的是。con_initcall.init这个段的内容,也就是说只要在数据代码中声明。con_initcall.init就可以了。

  在uclinux的头文件中搜索initcall,发现了这样一个定义:

  #define console_initcall(fn)

  static initcall_t __initcall_##fn

  __attribute_used__ __attribute__((__section__(".con_initcall.init")))=fn

  再看看drivers/serial/bfin_5xx.c中有这样一行:

  console_initcall(bfin_serial_rs_console_init);

  从这里就可以看出它声明了一个函数指针变量,这个变量就放在。con_initcall.init这个数据段中,且这个指针的值指向bfin_serial_rs_console_init函数。这样在console_init函数中就可以通过这个函数指针调用bfin_serial_rs_console_init函数。而对bf561串口的初始化就是在bfin_serial_rs_console_init函数中完成的,这个函数同时还将缓冲区内的数据从串口输出。

  在移植这部分代码的时候碰到了一个问题,在bfin_5xx.c中有一个函数bfin_serial_set_termios,它的作用是实际设置串口参数,但是在设置参数之前它要求发送缓冲区为空:

  do {

  lsr = UART_GET_LSR(uart);

  } while (!(lsr & TEMT));

  即它要示UART_LSR寄存器中的TEMT这个位为1,但是实际运行到这里的时候,这一位为0,因此进入死循环。

  跟踪发现,在head.s中有一段设置UART的代码:

  /* Initialise UART*/

  p0.h = hi(UART_LCR);

  p0.l = lo(UART_LCR);

  r0 = 0x80(Z); /*未修改前为0x0(Z)*/

  w[p0] = r0.L; /* To enable DLL writes */

  ssync;

  p0.h = hi(UART_DLL);

  p0.l = lo(UART_DLL);

  r0 = 0x0(Z);

  w[p0] = r0.L;

  ssync;

  p0.h = hi(UART_DLH);

  p0.l = lo(UART_DLH);

  r0 = 0x00(Z);

  w[p0] = r0.L;

  ssync;

  p0.h = hi(UART_GCTL);

  p0.l = lo(UART_GCTL);

  r0 = 0x0(Z);

  w[p0] = r0.L; /* To enable UART clock */

  ssync;

  我们知道在设置UART_DLL和UART_DLH时必须将UART_LCR的最高位设置为1,但是原始代码中却未设置,这样就造成了设置UART_DLL的失败,此时UART_LCR的TEMT标志将被设置为0,从而导致了死循环问题的发生。将上述红色标志的代码修改后解决此问题。

  不过奇怪的是,uclinux在gcc下编译居然不会有这样的问题发生!!为什么??

  程序运行到这里,就已经可以通过串口看到先前输出缓冲区中的数据了,先自我庆祝一下!哈哈!

  Linux version 2.6.19.3-ADI-2007R1.1-svn (wmz@gtw.com) (vdsp 4.5) #2 Tue Sep 25 1

  1:24:43 CST 2007

  Blackfin support (C) 2004-2007 Analog Devices, Inc.

  Compiled for ADSP-BF561 Rev 0.3

  Blackfin Linux support by http://blackfin.uclinux.org/

  Processor Speed: 594 MHz core clock and 99 Mhz System Clock

  Board Memory: 4MB

  Kernel Managed Memory: 4MB

  Memory map:

  text = 0x00010000-0x00020544

  init = 0x00020544-0x0002d014

  data = 0x0002fa08-0x00032cc4

  stack = 0x00030000-0x00032000

  bss = 0x00032cc4-0x00032cc4

  available = 0x00032cc4-0x003ff000

  Data Cache Enabled

  Hardware Trace Enabled

  Built 1 zonelists. Total pages: 1016

  Kernel command line:

  注意SDRAM是有意改为4M的,不是错误,呵呵。

                  微信群名称:华盟黑白之道二群   华盟-黑白之道⑦QQ群: 9430885

  • 上一篇编程:

  • 下一篇编程:
  • 网友评论
      验证码
     

    关注

    分享

    0

    讨论

    2

    猜你喜欢

    论坛最新贴

    编程栏目相关内容