我现在在写一个eCos上面的usb驱动。我是在cyg_start里面想自己调用,可是我自己调用不成功,就边diag_printf()都不能用了,哪位大哥看可不可以帮我一下。谢谢了。
我的做法是:
1.在自己的驱动代码里面写好char_devtab_entry{…………}里的东西。
2.在cyg_start()里面用
CYG_HAL_TABLE_BEGIN(__KIXRP435_INIT_TAB__,devtab);
CYG_HAL_TABLE_END(__KIXRP435_INIT_TAB_END__,devtab);
extern struct cyg_devtab_entry __KIXRP435_INIT_TAB__[], __KIXRP435_INIT_TAB_END_
3.初始化:
struct cyg_devtab_entry* init_entry;
for(init_entry = __KIXRP435_INIT_TAB__; init_entry != &__KIXRP435_INIT_TAB_END__; init_entry++)
{
(*init_entry->init)(init_entry);
}
cygnus,2008-04-22 17:58:34
难道 说CHAR_DEVTAB_ENTRY不用自己调用,系统会在什么地方调用?
但是我看redboot的源码他就自己调用的啊。
ning,2008-04-23 00:05:54
下面是内核代码的跟踪,你看一下,就基本明白了。
1.用CHAR_DEVTAB_ENTRY定义的数据结构,会放在ecos的.ecos.table.devtab.data数据段中。
io/common/current/include/devtab.h
#define CHAR_DEVTAB_ENTRY(_l,_name,_dep_name,_handlers,_init,_lookup,_priv) \
cyg_devtab_entry_t _l CYG_HAL_TABLE_ENTRY(devtab) = { \
_name, \
_dep_name, \
_handlers, \
_init, \
_lookup, \
_priv, \
CYG_DEVTAB_STATUS_CHAR \
};
#ifndef CYG_HAL_TABLE_ENTRY
#define CYG_HAL_TABLE_ENTRY( _name ) \
CYGBLD_ATTRIB_SECTION(".ecos.table." __xstring(_name) ".data") \
CYGBLD_ATTRIB_USED
#endif
这是我的设备的map文件的.ecos.table.*数据段的显示, br104h_serial_io0是串口设备,
unimac_eth0_netdev是网口设备。
*(SORT(.ecos.table.*))
.ecos.table.devtab.data
0x0003f8cc 0x54 /home/ning/work/lib/install/lib/extras.o
0x0003f904 haldiag_io0
0x0003f8e8 tty_io_diag
0x0003f8cc br104h_serial_io0
.ecos.table.fstab.data
0x0003f920 0x40 /home/ning/work/lib/install/lib/extras.o
0x0003f920 dev_fste
.ecos.table.mtab.data
0x0003f960 0x1c /home/ning/work/lib/install/lib/extras.o
0x0003f960 dev_mte
.ecos.table.mtab.extra
0x0003f97c 0xe0 /home/ning/work/lib/install/lib/extras.o
0x0003f97c cyg_mtab_extra
.ecos.table.netdev.data
0x0003fa5c 0x10 /home/ning/work/lib/install/lib/extras.o
0x0003fa5c unimac_eth0_netdev
.ecos.table.nstab.data
0x0003fa6c 0x1c /home/ning/work/lib/install/lib/extras.o
0x0003fa6c bsd_nste
0x0003fa88 . = ALIGN (0x4)
0x0003fa88 __CTOR_LIST__ = (.)
2. 这里定义了.ecos.table.*数据段,用_label符号可以找到,这样c语言可以直接调用它
hal/common/current/include/hal_tables.h
#ifndef CYG_HAL_TABLE_BEGIN
#define CYG_HAL_TABLE_BEGIN( _label, _name ) \
__asm__(".section \".ecos.table." __xstring(_name) ".begin\",\"aw\"\n" \
".globl " __xstring(CYG_LABEL_DEFN(_label)) "\n" \
".type " __xstring(CYG_LABEL_DEFN(_label)) ",object\n" \
".p2align " __xstring(CYGARC_P2ALIGNMENT) "\n" \
__xstring(CYG_LABEL_DEFN(_label)) ":\n" \
".previous\n" \
)
#endif
#ifndef CYG_HAL_TABLE_END
#define CYG_HAL_TABLE_END( _label, _name ) \
__asm__(".section \".ecos.table." __xstring(_name) ".finish\",\"aw\"\n" \
".globl " __xstring(CYG_LABEL_DEFN(_label)) "\n" \
".type " __xstring(CYG_LABEL_DEFN(_label)) ",object\n" \
".p2align " __xstring(CYGARC_P2ALIGNMENT) "\n" \
__xstring(CYG_LABEL_DEFN(_label)) ":\n" \
".previous\n" \
)
#endif
3. 只要你添加了io模块,也就定义了该表。
io/common/current/src/ioinit.cxx
#include
#include
// This is a dummy class just so we can execute the I/O package
// initialization at it's proper priority
externC void cyg_io_init(void);
class cyg_io_init_class {
public:
cyg_io_init_class(void) {
cyg_io_init();
}
};
// And here's an instance of the class just to make the code run
static cyg_io_init_class _cyg_io_init CYGBLD_ATTRIB_INIT_PRI(CYG_INIT_IO);
// Define table boundaries
CYG_HAL_TABLE_BEGIN( __DEVTAB__, devtab );
CYG_HAL_TABLE_END( __DEVTAB_END__, devtab );
4.该表被初始化的代码,即设备被初始化。
io/common/current/src/iosys.c
void
cyg_io_init(void)
{
static int _init = false;
cyg_devtab_entry_t *t;
if (_init) return;
for (t = &__DEVTAB__[0]; t != &__DEVTAB_END__; t++) {
#ifdef CYGDBG_IO_INIT
diag_printf("Init device '%s'\n", t->name);
#endif
if (t->init(t)) {
t->status |= CYG_DEVTAB_STATUS_AVAIL;
} else {
// What to do if device init fails?
// Device not [currently] available
t->status &= ~CYG_DEVTAB_STATUS_AVAIL;
}
}
_init = true;
}
5. 因此只要你用CHAR_DEVTAB_ENTRY定义了设备,且在ecc文件中添加了使用该设备的模块,这样在eCos初始化的时候,该模块就会被初始化。如果你不是很确定,可以将CYGDBG_IO_INIT打开。eCos的这种做法,主要还是考虑本身的特点“可配置”,用户只要通过配置,就可以添加或删除相应的设备驱动模块,而不需要修改任何代码,是从模块化和耦合性考虑。但代码晦涩了些。
ning,2008-04-23 00:30:44
to 斑竹:
呵呵,早点看到斑竹的关于devtab的精华帖子,我就不必去grep代码了。
to cygnus:
首先建议你看一下map文件,确定你的 __KIXRP435_INIT_TAB__ 的位置对应就是.ecos.table.devtab.data 的位置,否则代码就跑飞了。
另外一个问题就是,如果你添加了io模块,那么你的devtab(里面不仅有你的usb驱动,还有串口驱动等)就被初始化了两遍,一个是在你写的代码里面,另一个是在ioinit.cxx里面(调用cyg_io_init)。你的diag_printf失效的原因可能就是串口驱动被初始化了两遍。
最好的办法就是添加一些diag_printf(),跟一下代码就可以搞定了。添加打印语句一直到串口不工作了,问题就出在那里。
cygnus,2008-04-23 18:59:22
to ning:
谢谢你啊。我看看。再次谢谢
cygnus,2008-04-24 09:26:39
还有一个地方不明白,请问一下cyg_io_init(void)谁去调用呢?我只能追到这里了。
ning,2008-04-24 23:14:41
在vector.S中,在调用cyg_start()前,会调用cyg_hal_invoke_contructors(),该函数调用全局C++的构造函数。在cyg_type.h中定义的CYG_INIT_XXXXXXX确定了各个构造函数的初始化顺序。cyg_io_init()就是在class cyg_io_init_class的构造函数中被调用。
这些在massa的书的第二章有描述,你可以看一下。
cygnus,2008-04-28 15:55:41
184 void
185 cyg_hal_invoke_constructors (void)
186 {
187 #ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
188 static pfunc *p = &__CTOR_END__[-1];
189
190 cyg_hal_stop_constructors = 0;
191 for (; p >= __CTOR_LIST__; p--) {
192 (*p) ();
193 if (cyg_hal_stop_constructors) {
194 p--;
195 break;
196 }
197 }
198 #else
199 pfunc *p;
200
201 for (p = &__CTOR_END__[-1]; p >= __CTOR_LIST__; p--)
202 (*p) ();
203 #endif
204 }
这段代码是eCos系统里的那个总的初始化函数,可是&__CTOR_END__[-1]这里怎么写成了-1, 谢谢。
cygnus,2008-04-28 15:56:32
__CTOR_END__[-1] 这样没有语法问题?
ning,2008-04-28 22:07:39
没有语法问题。
在arm.ld里面
__CTOR_LIST__ = ABSOLUTE (.); KEEP (*(SORT (.ctors*))) __CTOR_END__ = ABSOLUTE (.); \
__DTOR_LIST__ = ABSOLUTE (.); KEEP (*(SORT (.dtors*))) __DTOR_END__ = ABSOLUTE (.); \
代码的实现就是从内存后往前初始化每个构造函数。__DTOR_LIST__为结束地址,因此最后面的函数地址为__CTOR_END__的地址减四,即__CTOR_END__[-1]
cygnus,2008-05-02 11:14:54
谢谢ning的解答,不过我的问题最终找到是因为没有地址映射。大家也要注意哦。
阅读(1829) | 评论(0) | 转发(0) |