Linux串口终端初始化.docx

上传人:b****6 文档编号:4718613 上传时间:2022-12-07 格式:DOCX 页数:13 大小:19.07KB
下载 相关 举报
Linux串口终端初始化.docx_第1页
第1页 / 共13页
Linux串口终端初始化.docx_第2页
第2页 / 共13页
Linux串口终端初始化.docx_第3页
第3页 / 共13页
Linux串口终端初始化.docx_第4页
第4页 / 共13页
Linux串口终端初始化.docx_第5页
第5页 / 共13页
点击查看更多>>
下载资源
资源描述

Linux串口终端初始化.docx

《Linux串口终端初始化.docx》由会员分享,可在线阅读,更多相关《Linux串口终端初始化.docx(13页珍藏版)》请在冰豆网上搜索。

Linux串口终端初始化.docx

Linux串口终端初始化

1.串口初始化过程

   start_kernel()

       |-----...

       |-----setup_arch()

       |-----...

       |-----build_all_zonelists()

       |-----page_alloc_init()

       |-----...

       |-----trap_init()

       |-----...

       |-----console_init()

       |-----...

       |-----mem_init()

       |-----...

       `-----rest_init()  --->kernel_thread()-->init()-->do_basic_setup()

1.1console_init()

[drivers/char/tty_io.c]

/*只作基本的初始化,详细的初始化在后面做*/

void__initconsole_init(void)

{

   initcall_t*call;

   /*SetupthedefaultTTYlinediscipline.*/

   (void)tty_register_ldisc(N_TTY,&tty_ldisc_N_TTY);

   /*

    *setuptheconsoledevicesothatlaterbootsequencescan

    *informaboutproblemsetc..

    */

#ifdefCONFIG_EARLY_PRINTK

   disable_early_printk();

#endif

   call=__con_initcall_start;

   while(call<__con_initcall_end){

       (*call)();

       call++;

   }

}

然后执行依次执行.con_initcall.init节中的函数,该节的每项为一个函数指针,使用宏console_initcall(FUNC_NAME)将函数指针填入,该宏定义于[include/linux/init.h]:

#defineconsole_initcall(fn)\

   staticinitcall_t__initcall_##fn\

   __attribute_used____attribute__((__section__(".con_initcall.init")))=fn

initcall_t为一函数指针:

typedefint(*initcall_t)(void);

如:

console_initcall(serial8250_console_init)则展开为:

staticinitcall_t__initcall_serial8250_console_init=__attribute_used__\

                       __attribute__((__section__(".con_initcall.init")))=serial8250_console_init;

即定义一个函数指针,使其指向serial8250_console_init,并使用gcc的__attribute__扩展,将其链接入.con_initcall.init节,方便管理。

一个典型的.con_initcall.init节的内容为:

...

Disassemblyofsection.con_initcall.init:

80234f90<__initcall_serial8250_console_init>:

80234f90:

  802328e4   lbv1,10468(at)        #这是一个函数指针,指向serial8250_console_init

80234f94<__initcall_early_uart_console_init>:

  

80234f94:

  80232ce4   lbv1,11492(at)

...

因此console_init()所做的,就是:

   console_init()

       |-----tty_register_ldisc()          /*Installalinediscipline,[drivers/char/tty_io.c]*/

       |-----serial8250_console_init()  

       `-----early_uart_console_init()

1.1.1serial8250_console_init

serial8250_console_init()定义于[drivers/serial/8250.c]

staticint__initserial8250_console_init(void)

{

   serial8250_isa_init_ports();

   register_console(&serial8250_console);

   return0;

}

console_initcall(serial8250_console_init);

staticstructuart_8250_portserial8250_ports[UART_NR];

staticvoid__initserial8250_isa_init_ports(void)

{

   structuart_8250_port*up;

   staticintfirst=1;

   inti;

   if(!

first)

       return;

   first=0;

   for(i=0;i

       structuart_8250_port*up=&serial8250_ports[i];

       up->port.line=i;

       spin_lock_init(&up->port.lock);

       init_timer(&up->timer);

       up->timer.function=serial8250_timeout;

       /*

        *ALPHA_KLUDGE_MCRneedstobekilled.

        */

       up->mcr_mask=~ALPHA_KLUDGE_MCR;

       up->mcr_force=ALPHA_KLUDGE_MCR;

       up->port.ops=&serial8250_pops;

   }

   for(i=0,up=serial8250_ports;

        i

        i++,up++){

       up->port.iobase  =old_serial_port[i].port;

       up->port.irq     =irq_canonicalize(old_serial_port[i].irq);

       up->port.uartclk=old_serial_port[i].baud_base*16;

       up->port.flags   =old_serial_port[i].flags;

       up->port.hub6    =old_serial_port[i].hub6;

       up->port.membase=old_serial_port[i].iomem_base;

       up->port.iotype  =old_serial_port[i].io_type;

       up->port.regshift=old_serial_port[i].iomem_reg_shift;

       if(share_irqs)

           up->port.flags|=UPF_SHARE_IRQ;

   }

}

serial8250_isa_init_ports()所做的事即使用old_serial_port来初始化structuart_8250_port结构数组serial8250_ports.这个old_serial_port定义为:

staticconststructold_serial_portold_serial_port[]={

   SERIAL_PORT_DFNS   /*definedinasm/serial.h*/

};

[include/asm-mips/serial.h]

#defineSERIAL_PORT_DFNS               \

   DDB5477_SERIAL_PORT_DEFNS          \

   EV64120_SERIAL_PORT_DEFNS          \

   IP32_SERIAL_PORT_DEFNS                         \

   JAZZ_SERIAL_PORT_DEFNS             \

   STD_SERIAL_PORT_DEFNS              \

   MOMENCO_OCELOT_G_SERIAL_PORT_DEFNS     \

   MOMENCO_OCELOT_C_SERIAL_PORT_DEFNS     \

   MOMENCO_OCELOT_SERIAL_PORT_DEFNS       \

   MOMENCO_OCELOT_3_SERIAL_PORT_DEFNS     \

   BCM947XX_SERIAL_PORT_DEFNS         \

   BCM56218_SERIAL_PORT_DEFNS

这个根据具体的平台配置,使用相应的宏定义.如当CONFIG_HAVE_STD_PC_SERIAL_PORT时:

#ifdefCONFIG_HAVE_STD_PC_SERIAL_PORT

#defineSTD_SERIAL_PORT_DEFNS         \

   /*UARTCLK  PORTIRQ    FLAGS       */         \

   {0,BASE_BAUD,0x3F8,4,STD_COM_FLAGS},/*ttyS0*/\

   {0,BASE_BAUD,0x2F8,3,STD_COM_FLAGS},/*ttyS1*/\

   {0,BASE_BAUD,0x3E8,4,STD_COM_FLAGS},/*ttyS2*/\

   {0,BASE_BAUD,0x2E8,3,STD_COM4_FLAGS},/*ttyS3*/

#else/*CONFIG_HAVE_STD_PC_SERIAL_PORTS*/

#defineSTD_SERIAL_PORT_DEFNS

#endif/*CONFIG_HAVE_STD_PC_SERIAL_PORTS*/

否则为空宏

serial8250_isa_init_ports()后,serial8250_console_init()调用register_console(&serial8250_console)注册一个structconsole结构:

staticstructuart_driverserial8250_reg;

staticstructconsoleserial8250_console={

   .name      ="ttyS",

   .write     =serial8250_console_write,

   .device    =uart_console_device,

   .setup     =serial8250_console_setup,

   .flags     =CON_PRINTBUFFER,

   .index     =-1,

   .data      =&serial8250_reg,

};

其用来描述一个serial8250的console.

这个register_console()定义于[kernel/printk.c]

1.1.2early_uart_console_init()

[drivers/serial/8250_early.c]

staticstructconsoleearly_uart_console__initdata={

   .name  ="uart",

   .write=early_uart_write,

   .setup=early_uart_setup,

   .flags=CON_PRINTBUFFER,

   .index=-1,

};

staticint__initearly_uart_console_init(void)

{

   if(!

early_uart_registered){

       register_console(&early_uart_console);

       early_uart_registered=1;

   }

   return0;

}

console_initcall(early_uart_console_init);

和serial8250_console_init()类似,也是注册一个console结构,表示一个uartconsole

1.2rest_init()

   rest_init()

       |-----...

       |-----smp_prepare_cpus(max_cpus)

       |-----do_pre_smp_initcalls()

       |-----smp_init()

       |-----sched_init_smp()

       |-----cpuset_init_smp()

       |-----do_basic_setup()

       |-----...

       `-----init_post()

1.2.1do_basic_setup()

到do_basic_setup()时,与体系结构相关的部分已经初始化完了,现在开始初始化设备了:

[init/main.c]

staticvoid__initdo_basic_setup(void)

{

   /*driverswillsendhotplugevents*/

   init_workqueues();

   usermodehelper_init();

   driver_init();            /*initializedrivermodel*/

   init_irq_proc();

   

   do_initcalls();        /*顺序执行.initcall.init节中的所有函数*/

}

1.2.1driver_init()

driver_init()定义于[drivers/base/init.c]主要完成driversubsystem的初始化:

void__initdriver_init(void)

{

   /*Thesearethecorepieces*/

   devices_init();

   buses_init();

   classes_init();

   firmware_init();

   hypervisor_init();

   /*Thesearealsocorepieces,butmustcomeafterthe

    *corecorepieces.

    */

   platform_bus_init();

   system_bus_init();

   cpu_dev_init();

   memory_dev_init();

   attribute_container_init();

}

这些函数主要调用subsystem_register()注册一个structsubsystem结构,进入kobjects.

1.2.2do_initcall()

这个于上面console_init()类似,其是顺序执行.initcall.init节中的所有函数:

[init/main.c]

externinitcall_t__initcall_start[],__initcall_end[];

staticvoid__initdo_initcalls(void)

{

   initcall_t*call;

   intcount=preempt_count();

   for(call=__initcall_start;call<__initcall_end;call++){

       char*msg=NULL;

       charmsgbuf[40];

       intresult;

       if(initcall_debug){

           printk("Callinginitcall0x%p",*call);

           print_fn_descriptor_symbol(":

%s()",

                   (unsignedlong)*call);

           printk("\n");

       }

       result=(*call)();

       if(result&&result!

=-ENODEV&&initcall_debug){

           sprintf(msgbuf,"errorcode%d",result);

           msg=msgbuf;

       }

       if(preempt_count()!

=count){

           msg="preemptionimbalance";

           preempt_count()=count;

       }

       if(irqs_disabled()){

           msg="disabledinterrupts";

           local_irq_enable();

       }

       if(msg){

           printk(KERN_WARNING"initcallat0x%p",*call);

           print_fn_descriptor_symbol(":

%s()",

                   (unsignedlong)*call);

           printk(":

returnedwith%s\n",msg);

       }

   }

   /*Makesurethereisnopendingstufffromtheinitcallsequence*/

   flush_scheduled_work();

}

关于符号地址__initcall_start,__initcall_end的来源,则是由编译系统写在[arch/mips/kernel/vmlinux.lds]中:

......

__initcall_start=.;

.initcall.init:

{

*(.initcall0.init)*(.initcall0s.init)*(.initcall1.init)*(.initcall1s.init)*(.initcall2.init)*(.initcall2s.init)*(.initcall3.init)*(.initcall3s.init)*(.initcall4.init)*(.initcall4s.init)*(.initcall5.init)*(.initcall5s.init)*(.initcallrootfs.init)*(.initcall6.init)*(.initcall6s.init)*(.initcall7.init)*(.initcall7s.init)

}

__initcall_end=.;

......

链接时,会被替换为实际的地址矣.

写入.initcall.init节的函数指针,有一组辅助的宏定义于[include/linux/init.h]:

#definepure_initcall(fn)      __define_initcall("0",fn,1)

#definecore_initcall(fn)      __define_initcall("1",fn,1)

#definecore_initcall_sync(fn)     __define_initcall("1s",fn,1s)

#definepostcore_initcall(fn)      __define_initcall("2",fn,2)

#definepostcore_initcall_sync(fn)__define_initcall("2s",fn,2s)

#definearch_initcall(fn)      __define_init

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 工作范文 > 行政公文

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1