?? ethernetif.c
字號:
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
/*
* This file is a skeleton for developing Ethernet network interface
* drivers for lwIP. Add code to the low_level functions and do a
* search-and-replace for the word "ethernetif" to replace it with
* something that better describes your network interface.
*
* THIS CODE NEEDS TO BE FIXED - IT IS NOT In SYNC WITH CURRENT ETHARP API
*/
#include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/mem.h"
#include "lwip/pbuf.h"
#include "lwip/sys.h"
#include "lwip/stats.h"
#include "netif/etharp.h"
#include "Dm9000.h"
#include "hardware.h"
/* Define those to better describe your network interface. */
#define PIOBData ((volatile u16_t *)(P_IOB_Data))
#define PIOBDir ((volatile u16_t *)(P_IOB_Dir))
#define PIOAData ((volatile u16_t *)(P_IOA_Data))
#define PIOADir ((volatile u16_t *)(P_IOA_Dir))
enum DM9K_PHY_mode {
DM9K_10MHD = 0,
DM9K_100MHD = 1,
DM9K_10MFD = 4,
DM9K_100MFD = 5,
DM9K_AUTO = 8,
DM9K_DISCONN = 9
};
extern void delay(u16_t);
u16_t inb(int port)
{
int iData,i;
*PIOBData=0x4070; //置位
*PIOADir=0x0000;
*PIOBData=0x0070|port; //cs 拉低
*PIOBData=0x0020|port; //讀數(shù)據(jù)&地址
*PIOADir=0x0000;
iData=*PIOAData; //
*PIOBData=0x0070|port; //cs拉低
*PIOBData=0x4070|port; //置位
*PIOADir=0xffff;
return(iData & 0x00ff);
}
void outb(int data,int port)
{
int i;
*PIOADir=0xffff;
*PIOAData=data;
*PIOBData=0x4070|port; //置位
*PIOBData=0x0070|port; //cs
*PIOBData=0x0010|port; //寫數(shù)據(jù)
*PIOBData=0x4070; //置位
}
u16_t inw(int port)
{
int iData,i;
*PIOBData=0x4070; //置位
*PIOADir=0x0000;
*PIOBData=0x0070|port; //cs
*PIOBData=0x0020|port; //讀數(shù)據(jù)
iData=*PIOAData; //
*PIOBData=0x0070|port; //cs
*PIOBData=0x4070|port; //置位
*PIOADir=0xffff;
return(iData);
}
void outw(int data,int port)
{
int i;
*PIOADir=0xffff;
*PIOAData=data;
*PIOBData=0x4070|port; //置位
*PIOBData=0x0070|port; //cs
*PIOBData=0x0010|port; //寫數(shù)據(jù)
*PIOBData=0x0070|port; //cs
*PIOBData=0x4070|port; //置位
}
void r_pack(unsigned int len,unsigned int *payload) //連續(xù)接收數(shù)據(jù),接收緩沖區(qū)起始地址為payload,接收長度為len(以字為單位)
{
unsigned int i,j=0;
*PIOBData=0x4074; //置位
*PIOADir=0x0000;
for(j=0;j<len;j++)
{
//*PIOBData=0x0070; //cs
*PIOBData=0x0024; //讀數(shù)據(jù)
*(payload++)=*PIOAData; //
//*PIOBData=0x0074; //cs
*PIOBData=0x0034; //wr pull high
//*PIOBData=0x4074; //置位
}
*PIOADir=0xffff;
}
void drop(unsigned int len) //連續(xù)接收數(shù)據(jù),接收緩沖區(qū)起始地址為payload,接收長度為len(以字為單位)
{
unsigned int i,j=0;
*PIOBData=0x4070; //置位
*PIOADir=0x0000;
for(j=0;j<len;j++)
{
//*PIOBData=0x0074; //cs
*PIOBData=0x0024; //讀數(shù)據(jù)
*PIOBData=0x0034; //cs
//*PIOBData=0x4074; //置位
}
*PIOADir=0xffff;
}
void s_pack(unsigned int len,unsigned int *payload)
{
unsigned int i,j=0;
*PIOBData=0x4070; //置位
*PIOADir=0xffff;
for(j=0;j<len;j++)
{
*PIOAData=*(payload++); //
*PIOBData=0x4074; //置位
//*PIOBData=0x0070; //cs
//*PIOBData=0x0074; //cs
*PIOBData=0x0014; //寫數(shù)據(jù)
//*PIOBData=0x0034; //wr pull high
//*PIOBData=0x0074; //cs
*PIOBData=0x4074; //置位
}
}
void delay(u16_t delay_time);
static const struct eth_addr ethbroadcast = {{0xffff,0xffff,0xffff}};
/* Forward declarations. */
static void ethernetif_input(struct netif *netif);
static err_t ethernetif_output(struct netif *netif, struct pbuf *p,struct ip_addr *ipaddr);
typedef struct EtherDev{
u16_t base_addr;
struct eth_addr dev_addr;
u8_t op_mode; /* PHY operation mode */
u8_t io_mode; /* 0:word, 2:byte */
u16_t link_mode;
//u16_t runt_length_counter; /* counter: RX length < 64byte */
//u16_t long_length_counter; /* counter: RX length > 1514byte */
//u16_t reset_counter; /* counter: RESET */
u16_t reset_rx_status; /* RESET caused by RX Statsus wrong */
//u16_t rx_fifo_errors;
//u16_t rx_crc_errors;
//u16_t rx_length_errors;
u16_t rx_packets;
u16_t tx_packets;
//u16_t drop_packets;
} Dm9000_t;
/* Global variable declaration ----------------------------- */
static struct EtherDev * dmfe_dev = NULL;
/* function declaration ------------------------------------- */
int dmfe_probe(struct EtherDev *);
static int dmfe_stop(struct EtherDev *);
static void dmfe_init_DM9K(struct EtherDev *);
volatile static u8_t ior(int);
static void iow(int, u8_t);
volatile static u16_t phy_read( int);
static void phy_write(int, u16_t);
static u16_t read_srom_word(int);
#if 0
u32_t CRC_32(u8_t *CRC_Data , u16_t Data_len);
static void DM9K_hash_table(struct EtherDev *);
static unsigned long cal_CRC(u8_t *, unsigned int, u8_t);
struct dev_mc_list mc2 = {NULL,(0x01,0x02,0x03,0x04,0x05,0x05)};
struct dev_mc_list mc1 = {&mc2,(0xFF,0xFF,0xFF,0xFF,0xFF,0xFF)};
#endif
/* from DM9K linux driver */
/* Search DM9K board, allocate space and register it
*/
struct EtherDev *init_etherdev(struct EtherDev *dev, u16_t opt)
{
dev = mem_malloc(sizeof (struct EtherDev));
memset(dev,0,sizeof (struct EtherDev));
return(dev);
}
int dmfe_probe(struct EtherDev *dev)
{
u32_t id_val;
u16_t iobase = DM9K_MIN_IO;
u16_t i, DM9K_found = FALSE,oft;
DMFE_DBUG(0, "dmfe_probe()",0);
/* Search All DM9K NIC */
outb(DM9K_VID_L, iobase);
id_val = inb(iobase + 4);
outb(DM9K_VID_H, iobase);
id_val |= inb(iobase + 4) << 8;
outb(DM9K_PID_L, iobase);
id_val |= (u32_t)inb(iobase + 4) << 16;
outb(DM9K_PID_H, iobase);
id_val |= (u32_t)inb(iobase + 4) << 24;
if (id_val == DM9K_ID) {
DEBUGF(DM9K_DEBUG | DBG_TRACE , ("<DM9K> I/O: %x, VID: %x \n",iobase, id_val));
DM9K_found = TRUE;
/* Init network device */
dev = init_etherdev(dev, 0);
/* Allocated board information structure */
dmfe_dev = dev;
dev->base_addr = iobase;
#if 0
dev->mc_list = &mc1;
dev->mc_count = 2;
#endif
dev->dev_addr.addr[0]=0x6000;
dev->dev_addr.addr[1]=0x006e;
dev->dev_addr.addr[2]=0x0090;
for (i = 0, oft = 0x10; i < 6; i++, oft++)
iow(oft, GETMAC(dev->dev_addr, i));
/* Set Node Address */
}
return DM9K_found ? 0:-ENODEV;
}
/*
Open the interface.
The interface is opened whenever "ifconfig" actives it.
*/
void low_level_init(struct netif *netif)
{
struct EtherDev * dev = netif->state;
dmfe_init_DM9K(dev);
}
/* Set PHY operationg mode
*/
static void set_PHY_mode(u16_t op_mode)
{
u16_t phy_reg4 = 0x01e1, phy_reg0=0x1000;
switch(op_mode) {
case DM9K_10MHD: phy_reg4 = 0x21;
phy_reg0 = 0x0000;
break;
case DM9K_10MFD: phy_reg4 = 0x41;
phy_reg0 = 0x1100;
break;
case DM9K_100MHD: phy_reg4 = 0x81;
phy_reg0 = 0x2000;
break;
case DM9K_100MFD: phy_reg4 = 0x101;
phy_reg0 =0x3100;
break;
}
phy_write(4, phy_reg4); /* Set PHY media mode */
phy_write(0, phy_reg0); /* Tmp */
iow( 0x1e, 0x01); /* Let GPIO0 output */
iow( 0x1f, 0x00); /* Enable PHY */
}
/*
Hardware start transmission.
Send a packet to media from the upper layer.
*/
err_t
low_level_output(struct netif *netif, struct pbuf *skb)
{
struct EtherDev *dev = netif->state;
u16_t * data_ptr;
int i, tmplen;
struct pbuf *q;
/* Disable all interrupt */
/* Move data to DM9K TX RAM */
ior(0x05);
outb(0xf8, DM9KADDR);
#if 0
if (db->io_mode == DM9K_BYTE_MODE) {
/* Byte mode */
for (i = 0; i < skb->len; i++)
outb((data_ptr[i] & 0xff), DM9KADDR);
while(1);
} else
#endif
if (dev->io_mode == DM9K_WORD_MODE) {
/* Word mode */
for(q = skb ; q != NULL; q = q->next) {
/* Send the data from the pbuf to the interface, one pbuf at a
time. The size of the data in each pbuf is kept in the ->len
variable. */
if ((q->len % 2) && (q->next !=NULL))
{
DEBUGF(DM9K_DEBUG | DBG_TRACE, ("data error ! odd bytes. q->len\n",q->len));
while(1);
}
data_ptr = q->payload;
tmplen = (q->len + 1) / 2;
s_pack(tmplen, data_ptr);
}
dev->tx_packets++;
/* Set TX length to DM9K */
iow( 0xfc, skb->tot_len & 0xff);
iow( 0xfd, (skb->tot_len >> 8) & 0xff);
iow( 0x02, 0x01);
while (!( ior( 0x01) & (4 | 8)));
return ERR_OK;
}
}
/* Initilize DM9K board
*/
static void dmfe_init_DM9K(struct EtherDev *dev)
{
/* RESET device */
iow( 0, 3);
delay(100); /* delay 100us */
iow( 0, 0);
iow( 0, 3);
delay(100); /* delay 100us */
iow( 0, 0);
/* I/O mode */
dev->io_mode = ior( 0xfe) >> 6; /* ISR bit7:6 keeps I/O mode */
DEBUGF(DM9K_DEBUG | DBG_TRACE, ("io_mode = %d\n", dev->io_mode));
delay(200); /* delay 100us */
/* Set PHY */
dev->op_mode = DM9K_10MFD;
set_PHY_mode(dev->op_mode);
delay(500);
if (!(ior(NSR) &1<<6))
dev->link_mode = DM9K_DISCONN;
else dev->link_mode = dev->op_mode;
//while(!(ior( NSR) & 1<<6));
/* Init needed register value */
/* Program operating register */
iow( 0x00, DM9K_REG00);
iow( 0x02, 0); /* TX Polling clear */
iow( 0x08, 0x3f); /* Less 3Kb, 200us */
iow( 0x09, DM9K_REG09); /* Flow Control : High/Low Water */
iow( 0x0a, DM9K_REG0A); /* Flow Control */
iow( 0x2f, 0); /* Special Mode */
iow( 0x01, 0x2c); /* clear TX status */
iow( 0xfe, 0x0f); /* Clear interrupt status */
/* Set address filter table */
#if 0
DM9K_hash_table(dev);
#endif
/* Activate DM9K */
iow( 0x05, DM9K_REG05 | 1); /* RX enable */
iow( 0xff, DM9K_REGFF); /* Enable TX/RX interrupt mask */
/* Init Driver variable */
}
/*
Stop the interface.
The interface is stopped when it is brought.
*/
static int dmfe_stop(struct EtherDev *dev)
{
DMFE_DBUG(0, "dmfe_stop", 0);
/* RESET devie */
phy_write( 0x00, 0x8000); /* PHY RESET */
delay(200);
iow( 0x1f, 0x01); /* Power-Down PHY */
iow( 0xff, 0x80); /* Disable all interrupt */
iow( 0x05, 0x00); /* Disable RX */
delay(200);
/* Dump Statistic counter */
#if DM9K_DEBUG
Print("\nRX FIFO OVERFLOW %lx\n", db->stats.rx_fifo_errors);
Print("RX CRC %lx\n", db->stats.rx_crc_errors);
Print("RX LEN Err %lx\n", dev->rx_length_errors);
Print("RX LEN < 64byte %x\n", dev->runt_length_counter);
Print("RX LEN > 1514byte %x\n", dev->long_length_counter);
Print("RESET %x\n", dev->reset_counter);
#endif
return 0;
}
/*
Received a packet and pass to upper layer
*/
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -