继续分析修改ne.c中ne_probe1的代码(关键的东东全在这里面呢)。接下来就是
outb_p(E8390_NODMA+E8390_PAGE1+E8390_STOP, ioaddr + E8390_CMD);
regd = inb_p(ioaddr + 0x0d);
outb_p(0xff, ioaddr + 0x0d);
读取REGD中的数据,这里,再仔细跟踪一下outb_p这个函数,在x86中,这个就是一个IO口的输出函数,在S3C44B0是存储器和IO统一编址的(或者说不分存储器还是IO),经过了几次宏定义以后,很快找到如下宏代码:
(*(volatile unsigned char *)(a))
和我想的一样,就是靠这个访问外部总线的。我的8019在S3C44B0的Bank 5上,工作在跳线模式,算了一下,起始基地址就是0x0a000600。
这里,需要说明一下我的硬件配置和连接,8019工作在16位模式下,S3C44B0的Bank5配置成16位模式,数据线一对一的连接,地址线错开一位--8019的A0连接S3C44B0的A1……这样,8019的基地址(Reg0的地址)是0x0a000600,Reg1的地址就是0x0a000602……地址不是连续增加的,所以,对应的驱动程序要做相应的修改。查找E8390_CMD的定义,发现,在8390.h中有:
#define E8390_CMDEI_SHIFT(0x00)/* The command register (for all pages)
*/
/* Page 0 register offsets. */
#define EN0_CLDALOEI_SHIFT(0x01)/* Low byte of current local dma addr
RD */
#define EN0_STARTPG EI_SHIFT(0x01)/* Starting page of ring bfr WR */
……
而EI_SHIFT根据不同的配置有两种定义,如下:
#if defined(CONFIG_MAC) || defined(CONFIG_AMIGA_PCMCIA) || \
defined(CONFIG_ARIADNE2) || defined(CONFIG_ARIADNE2_MODULE) || \
defined(CONFIG_HYDRA) || defined(CONFIG_HYDRA_MODULE) || \
defined(CONFIG_ARM_ETHERH) || defined(CONFIG_ARM_ETHERH_MODULE)
#define EI_SHIFT(x) (ei_local->reg_offset[x])
#else
#define EI_SHIFT(x) (x)
#endif
看来,在8390的驱动中已经考虑到了不连续增长的地址的问题了,继续跟踪查看ei_local->regoffset[x]的定义就比较麻烦了。干脆,我用一个笨方法,直接添加:
#elif defined(CONFIG_ARM) || defined(CONFIG_ARM_MODULE)//--by
threewater
#define EI_SHIFT(x) ((x)*2)
对应的,在ne.c也有类似的定义问题:
#define NE_CMD0x00
#define NE_DATAPORT 0x10/* NatSemi-defined port window offset. */
#define NE_RESET0x1f/* Issue a read to reset, a write to clear. */
#define NE_IO_EXTENT0x20
添加成:
#ifdef CONFIG_ARM//--by threewater
#define NE_CMD0x00
#define NE_DATAPORT 0x20/* NatSemi-defined port window offset. */
#define NE_RESET0x3e/* Issue a read to reset, a write to clear. */
#define NE_IO_EXTENT0x40
#else
……
这样,地址偏移的问题就基本解决了。当然,在Ne.c中,也有直接访问reg的代码,比如上面说的代码也相应的添加成:
#ifdef CONFIG_ARM//--add by threewater
regd = inb_p(ioaddr + 0x0d*2);
outb_p(0xff, ioaddr + 0x0d*2);
#else
regd = inb_p(ioaddr + 0x0d);
outb_p(0xff, ioaddr + 0x0d);
我没有看过linux编程的规范,也不知的修改内核有什么规矩,不过,我都是用预处理来添加我自己的代码,从来不直接在原有的代码上修改,我觉得这样更可以保证代码的完整性和可移植性,而且,还容易比较,容易找出问题(当然,如果#if嵌套多了,也很难看的:()。
接下来的初始化8019,就没有什么问题了,然后就是配置网卡的物理地址了。在我的系统上,没有使用8019的初始化配置芯片,物理地址需要在程序中直接写入(其实,就是使用配置芯片,也需要用程序读出再写入的),物理地址可以编译到代码里,也可以存储到flash的一个固定地址中。可以参考ne_probe1里面的例子,照着勒就可以了。剩下注册中断什么的,也就是算好了中断号,照着添加自己的代码。很容易的。
到这里,似乎就没有什么工作了。编译内核,启动,恩Ne2000兼容的网卡找到了,接下来就不正常了。系统报告,反复陷入那个网卡的中断……