[ECOS] eCos DP83902a driver
Mikael Starvik
mikael.starvik@axis.com
Fri Mar 21 18:07:00 GMT 2003
Hi,
I have been using the eCos NS DP83902a driver together with an Asix
ax88796 chip (ne2000 compatible). I have included a diff with a few
things I had to fix to get it to work.
1. The Asix device can't change page and start DMA in the same command.
Command has been spitted in two commands.
2. Implementation of ETH_DRV_SET_MAC_ADDRESS has been added
3. The packet header and packet data was word-swapped. I am not sure if
this is because I use the device in 80186 mode or if there is any other
reason. Anyway I made it possible to configure that the driver should
swap the bytes (maybe this should be a CDL option instead).
4. There is a bug in the Asix chip that implies that DMA complete status
is never set (according to the data sheet the DMA is always ready). An
option has been added that can be used to disable the wait for DMA
complete.
Please comment on the changes and suggest improvements.
PS. I have only tested the driver with RedBoot but we also have a Linux
driver (where we had to fix item 4 above) that has been tested for
several days with maximum load. DS.
Thanks
/Mikael
Index: if_dp83902a.c
===================================================================
RCS file: /usr/local/cvs/linux/os/ecos/packages/devs/eth/ns/dp83902a/current/src/if_dp83902a.c,v
retrieving revision 1.1.1.3
diff -u -r1.1.1.3 if_dp83902a.c
--- if_dp83902a.c 26 Feb 2002 13:40:52 -0000 1.1.1.3
+++ if_dp83902a.c 21 Mar 2003 14:39:56 -0000
@@ -58,6 +58,7 @@
#include <pkgconf/system.h>
#include <cyg/infra/cyg_type.h>
#include <cyg/hal/hal_arch.h>
+#include <cyg/hal/hal_endian.h>
#include <cyg/infra/diag.h>
#include <cyg/hal/drv_api.h>
#define __ECOS
@@ -247,6 +248,7 @@
DP_OUT(base, DP_P1_PAR0+i, enaddr[i]);
}
// Enable and start device
+ DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_STOP);
DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
DP_OUT(base, DP_TCR, DP_TCR_NORMAL); // Normal transmit operations
DP_OUT(base, DP_RCR, DP_RCR_AB); // Accept broadcast, no errors, no multicast
@@ -261,8 +263,16 @@
dp83902a_control(struct eth_drv_sc *sc, unsigned long key,
void *data, int data_len)
{
+ dp83902a_priv_data_t *dp = (dp83902a_priv_data_t *)sc->driver_private;
+ int i;
+
switch (key) {
case ETH_DRV_SET_MAC_ADDRESS:
+ if (data_len != ETHER_ADDR_LEN)
+ return -2;
+ memcpy(dp->esa, data, ETHER_ADDR_LEN);
+ for (i = 0; i < ETHER_ADDR_LEN; i++)
+ DP_OUT(dp->base, DP_P1_PAR0+i, dp->esa[i]);
return 0;
break;
default:
@@ -410,6 +420,9 @@
len -= 2;
if (len >= 0)
tmp |= *data++;
+#ifdef CYGHWR_NS_DP83902A_PLF_WORD_SWAP
+ tmp = CYG_SWAP16(tmp);
+#endif
DP_OUT_DATA(dp->data, tmp);
#if DEBUG & 4
diag_printf(" %04x", tmp);
@@ -450,12 +463,14 @@
CYGACC_CALL_IF_DELAY_US(1);
#endif
+#ifndef CYGHWR_NS_DP83902A_PLF_NO_DMA_COMPLETE
// Wait for DMA to complete
do {
DP_IN(base, DP_ISR, isr);
} while ((isr & DP_ISR_RDC) == 0);
// Then disable DMA
DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
+#endif
CR_DOWN();
// Start transmit if not already going
@@ -518,8 +533,13 @@
#ifdef CYGHWR_NS_DP83902A_PLF_16BIT_DATA
cyg_uint16 tmp;
DP_IN_DATA(dp->data, tmp);
+#ifdef CYGHWR_NS_DP83902A_PLF_WORD_SWAP
+ rcv_hdr[i++] = tmp & 0xff;
+ rcv_hdr[i++] = (tmp >> 8) & 0xff;
+#else
rcv_hdr[i++] = (tmp >> 8) & 0xff;
rcv_hdr[i++] = tmp & 0xff;
+#endif
#else
DP_IN_DATA(dp->data, rcv_hdr[i++]);
#endif
@@ -605,6 +625,17 @@
diag_printf(" %04x", tmp);
if (0 == (++dx % 8)) diag_printf("\n ");
#endif
+#ifdef CYGHWR_NS_DP83902A_PLF_WORD_SWAP
+ *data++ = tmp & 0xff;
+ mlen--;
+ if (0 == mlen) {
+ saved_char = (tmp >> 8) & 0xff;
+ saved = true;
+ } else {
+ *data++ = (tmp >> 8) & 0xff;
+ mlen--;
+ }
+#else
*data++ = (tmp >> 8) & 0xff;
mlen--;
if (0 == mlen) {
@@ -614,6 +645,7 @@
*data++ = tmp & 0xff;
mlen--;
}
+#endif
}
#else
{
--
Before posting, please read the FAQ: http://sources.redhat.com/fom/ecos
and search the list archive: http://sources.redhat.com/ml/ecos-discuss
More information about the Ecos-discuss
mailing list