(1)初始化CS8900A芯片
对于CS8900A芯片,初始化函数是通过cs89x0_probe()和cs89x0_probe1()函数来实现。 int cs89x0_probe(struct device *dev) {
int base_addr = CS8900_BASE;
return cs89x0_probe1(dev,base_addr); }
其中CS8900_BASE是I/O被映射到的基地址。 static int cs89x0_probel(struct device *dev, int ioaddr) {
irq2dev_map[0] = dev; ……
/* 初始化寄存器,建立片选和芯片工作方式*/
*(volatile unsigned char *)0xfffff42b |= 0x01; /* output /sleep */
*(volatile unsigned short *)0xfffff428 |= 0x0101; /* not sleeping */ *(volatile unsigned char *)0xfffff42b &= ~0x02; /* input irq5 */ *(volatile unsigned short *)0xfffff428 &= ~0x0202;/* irq5 fcn on */ *(volatile unsigned short *)0xfffff102 = 0x8000; /* 0x04000000 */ *(volatile
unsigned
short
*)0xfffff112
=
0x01e1
;
/*128k,2ws,FLASH,en*/
??
/* 初始化设备结构*/ if (dev->priv == NULL){
dev->priv = kmalloc(sizeof(struct net_local),GFP_KERNEL);
memset(dev->priv, 0, sizeof(struct net_local)); }
dev->base_addr = ioaddr;
lp = (struct net_local *)dev->priv; ??
/* 取得芯片类型*/
rev_type = readreg(dev, PRODUCT_ID_ADD); lp->chip_type = rev_type &~ REVISON_BITS;
lp->chip_revision = ((rev_type & REVISON_BITS) >> 8) + 'A'; lp->send_cmd = TX_AFTER_ALL; ??
/*注册接口方法*/ dev->open = net_open; dev->stop = net_close;
dev->hard_start_xmit = net_send_packet; dev->get_stats = net_get_stats;
dev->set_multicast_list = &set_multicast_list;
dev->set_mac_address = &set_mac_address; ??
ether_setup(dev); }
(2)编写设备打开函数与关闭函数
打开和关闭一个网络接口是由ifconfig命令来完成的。当使用ifconfig为一个接口赋地址时,它完成两项工作。第一,它通过ioctl(SIOCSIFADDR)(即Socket I/O Control Set InterFace ADDRess)来赋地址;第二,它通过ioctl(SIOCSIFFLAGS)(即Socket I/O Control Set InterFace FLAGS)对dev->flag中的IFF_UP置位来打开接口。
CS8900A是一个ISA设备,不支持共享中断,但是这在嵌入式系统外设比较少的情况下对系统的性能没什么影响。另外,在接口可以和外界通信以前,还需要将芯片上的硬件地址复制到dev->dev_addr指针指向的空间上,这个工作也可以在初始化函数cs89x0_probe1中完成。
设备打开函数net_open的基本流程如下:
① 没有在初始化函数中注册中断号和I/O地址,则在设备打开时要进行注册;
② 将该设备挂到irq2dev_map中。若使用基于中断的数据接收方式,以后就可以通过中断号和irq2dev_map数组直接查找相应的设备了;
③ 初始化物理设备的寄存器;
④ 设置接口相应的dev的私有数据结构(dev->priv)中的一些字段;
⑤ 设置dev中的tbusy,interrupt和start等字段。 设备关闭函数net_close()与打开函数动作相反。 (3)数据包发送/接收函数的编写
在CS8900A芯片的I/O模式下,数据包的发送流程
① 发送一个传输命令到TxCMD端口(I/O base + 0004h),使芯片进入发送状态;
② 将要发送数据帧的长度发送到TxLength端口(I/O base + 0006h);
③ 通过信息包指针端口(I/O base +000Ch)读取Burst寄存器(寄存器18),判断Rdy4TxNOW位(第8位)的值。如果Rdy4TxNOW值为1,则跳到第4步;如果Rdy4TxNOW位的值为0,驱动程序将等待一段时间,再判断Rdy4TxNOW的值,直到它为1为止。另外,如果程序中Rdy4TxiE(寄存器BufCFG的第8位)被置为1,当CS8900A的发送缓冲区可写时,Rdy4Tx(寄存器BufEvent的第8位)将被置为1,并触发一个中断,这时候就不需要判断Rdy4TxNOW了;
④ 程序发送函数将反复执行写指令,将数据发送到接收/发送数据端口(I/O base +0000h)。
net_rx()函数的操作流程如下: ① 申请skb缓存区存储新的数据包; ② 从硬件中读取新到达的数据;
③ 调用函数netif_rx(),将新的数据包向网络协议的上一层传送; ④ 修改接口的统计函数。 4)中断处理函数的编写
一般的中断服务程序的基本流程如下: ① 确定发生中断的具体网络接口
② 打开标志位dev->interrupt,表示本服务程序正在被使用; ③ 读取中断状态寄存器,根据寄存器判断中断发生的原因。有两种可能,一种是有新数据包到达;另一种是上次的数据传输已完成。
④ 若是因为有新数据包到达,则调用接收数据包的子函数net_rx();
⑤ 如果中断是上次传输引起,则通知协议的上一层,修改接口的统计信息,关闭标志位tbusy,为下次传输做准备;
⑥ 关闭标志位interrupt。
CS8900A驱动程序的中断处理函数的实现代码如下:
void cs8900_interrupt(int irq, void *dev_id, struct pt_regs * regs) {
struct device *dev = (struct device *)(irq2dev_map[/* FIXME */0]);
struct net_local *lp; int ioaddr, status; dev = irq2dev_map[0]; dev->interrupt = 1;
百度搜索“77cn”或“免费范文网”即可找到本站免费阅读全部范文。收藏本站方便下次阅读,免费范文网,提供经典小说教育文库嵌入式系统设计大学教程 - 习题与解答(8)在线全文阅读。
相关推荐: