Chinaunix首页 | 论坛 | 博客
  • 博客访问: 154047
  • 博文数量: 72
  • 博客积分: 3680
  • 博客等级: 中校
  • 技术积分: 1051
  • 用 户 组: 普通用户
  • 注册时间: 2010-08-22 13:51
文章分类
文章存档

2010年(72)

我的朋友

分类: LINUX

2010-09-24 08:42:50

CS8900A 驱动程序分析

                                                                                                                                        

 

1.   寄存器

 

·LINECTL0112H

LINECTL
决定CS8900的基本配置和物理接口。例如:设置初始值为00d3H,选择物理接口为10BASE-T,并使能设备的发送和接收控制位。

·RXCTL
0104H

RXCTL
控制CS8900接收特定数据报。设置RXTCL的初始值为0d05H,表示接收网络上的广播或者目标地址同本地物理地址相同的正确数据包。

·RXCFG
0102H

RXCFG
控制CS8900接收到特定数据报后会引发接收中断。RXCFG可设置为0103H,这样当收到一个正确的数据报后,CS8900会产生一个接收中断。

·BUSCT
0116H

BUSCT
可控制芯片的I/O接口的一些操作。设置初始值为8017H,打开CS8900的中断总控制位。

·ISQ
0120H

ISQ
是网卡芯片的中断状态寄存器,内部映射接收中断状态寄存器和发送中断状态寄存器的内容。


·PORT0
0000H
发送和接收数据时,CPU通过PORT0传递数据。

·TXCMD
0004H
发送控制寄存器,如果写入数据00C0H,那么网卡芯片在全部数据写入后开始发送数据。

·TXLENG
0006H
发送数据长度寄存器,发送数据时,首先写入发送数据长度,然后将数据通过PORT0写入芯片。

以上为几个最主要的工作寄存器(为16位)。
系统工作时,应首先对网卡芯片进行初始化,即写寄存器LINECTLRXCTL RCCFGBUSCT

发数据时,写控制寄存器TXCMD,并将发送数据长度写入TXLENG,然后将数据依次写入PORT0口,网卡芯片将数据组织为链路层类型并添加填充位和CRC校验送到网络。

 

 

 

 

 

 

 

 

 

2.   程序框架

 

2.1           模块注册

 

static int __init init_cs8900a_s3c2410(void)

{

    struct net_local *lp;

    int ret = 0;

 

    dev_cs89x0.irq = irq;

    dev_cs89x0.base_addr = io;

    dev_cs89x0.init = cs89x0_probe;

   

    request_region(dev_cs89x0.base_addr, NETCARD_IO_EXTENT, "cs8900a");

 

    if (register_netdev(&dev_cs89x0) != 0)

}

 

 

2.2           设备检测

 

static int __init cs89x0_probe1(struct net_device *dev, int ioaddr)

{

 

    /* get the chip type */

    rev_type = readreg(dev, PRODUCT_ID_ADD);

    lp->chip_type = rev_type &~ REVISON_BITS;

    lp->chip_revision = ((rev_type & REVISON_BITS) >> 8) + 'A';

 

    if (lp->chip_type != CS8900)

   {

      printk(__FILE__ ": wrong device driver!\n");

      ret = -ENODEV;

      goto after_kmalloc;

    }

 

 

 

    dev->dev_addr[0] = 0x00;

    dev->dev_addr[1] = 0x00;

    dev->dev_addr[2] = 0xc0;

    dev->dev_addr[3] = 0xff;

    dev->dev_addr[4] = 0xee;

    dev->dev_addr[5] = 0x08;

    set_mac_address(dev, dev->dev_addr);

 

    dev->irq = IRQ_LAN;

    printk(", IRQ %d", dev->irq);

 

    dev->open      = net_open;

    dev->stop       = net_close;

    dev->tx_timeout  = net_timeout;

    dev->watchdog_timeo  = 3 * HZ;

    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;

 

    /* Fill in the fields of the device structure with ethernet values. */

    ether_setup(dev);

}

 

 

2.3           数据发送

 

static int net_send_packet(struct sk_buff *skb, struct net_device *dev)

{

 

    netif_stop_queue(dev);

 

    /* initiate a transmit sequence */

    writeword(dev, TX_CMD_PORT, lp->send_cmd);

    writeword(dev, TX_LEN_PORT, skb->len);

 

    /* Test to see if the chip has allocated memory for the packet */

    if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0)

   {         

      spin_unlock_irq(&lp->lock);

      DPRINTK(1, "cs89x0: Tx buffer not free!\n");

      return 1;

    }

    /* Write the contents of the packet */

    writeblock(dev, skb->data, skb->len);

 

    return 0;

}

 

 

2.4           中断

 

 

static void net_interrupt(int irq, void *dev_id, struct pt_regs * regs)

{

 

    while ((status = readword(dev, ISQ_PORT)))

{

      switch(status & ISQ_EVENT_MASK) {

      case ISQ_RECEIVER_EVENT:

      /* Got a packet(s). */

      net_rx(dev);

      break;

     

      case ISQ_TRANSMITTER_EVENT:

      lp->stats.tx_packets++;

      netif_wake_queue(dev);   /* Inform upper layers. */

      break;

}

 

 

2.5           接收

 

static void net_rx(struct net_device *dev) {

 

    status = inw(ioaddr + RX_FRAME_PORT);

    if ((status & RX_OK) == 0) {

      count_rx_errors(status, lp);

      return;

    }

 

    length = inw(ioaddr + RX_FRAME_PORT);

 

    /* Malloc up new buffer. */

    skb = dev_alloc_skb(length + 2);

   

if (skb == NULL) {

      lp->stats.rx_dropped++;

      return;

    }

    skb_reserve(skb, 2);

/*  mac头是14个字节,一开始保留两个字节,正是为了保证ip头的开始是四字节对齐的。*/

    skb->len = length;

    skb->dev = dev;

    readblock(dev, skb->data, skb->len);

 

 

    skb->protocol=eth_type_trans(skb,dev);

    netif_rx(skb);

}

 

 

阅读(721) | 评论(0) | 转发(0) |
0

上一篇:配置H-jtag

下一篇:DM9000 驱动程序分析

给主人留下些什么吧!~~