📄 if_dm9000.c
字号:
unsigned short u16tab[64];
sc = (struct eth_drv_sc *)ndp->device_instance;
priv = (struct dm9000 *)sc->driver_private;
priv->sc = sc;
#ifdef CYG_HAL_DM9000_PRESENT
if (!CYG_HAL_DM9000_PRESENT())
return 0;
#endif
id = getreg(priv, DM_VIDL);
id |= getreg(priv, DM_VIDH) << 8;
id |= getreg(priv, DM_PIDL) << 16;
id |= getreg(priv, DM_PIDH) << 24;
if (id != 0x90000A46)
return 0;
#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
cyg_drv_interrupt_create(priv->interrupt,
0,
(cyg_addrword_t)sc,
dm9000_isr,
eth_drv_dsr,
&priv->interrupt_handle,
&priv->interrupt_object);
cyg_drv_interrupt_attach(priv->interrupt_handle);
cyg_drv_interrupt_acknowledge(priv->interrupt);
cyg_drv_interrupt_unmask(priv->interrupt);
#endif // !CYGPKG_IO_ETH_DRIVERS_STAND_ALONE
for (i = 0; i < 64; i++)
u16tab[i] = eeprom_read(priv, i);
u16tab[3] &= ~0xc;
u16tab[3] |= 4;
u16tab[6] &= 0xfe00;
u16tab[6] |= 6;
#if 0
eeprom_write(priv, 6, u16tab[6]);
eeprom_write(priv, 3, u16tab[3]);
#endif
eeprom_reload(priv);
do {
for (i = 0; i < 64; i++)
u16tab[i] = eeprom_read(priv, i);
} while ((u16tab[0] | u16tab[1] | u16tab[2]) == 0);
priv->mac_address[0] = u16tab[0];
priv->mac_address[1] = u16tab[0] >> 8;
priv->mac_address[2] = u16tab[1];
priv->mac_address[3] = u16tab[1] >> 8;
priv->mac_address[4] = u16tab[2];
priv->mac_address[5] = u16tab[2] >> 8;
if (!initialize_nic(priv))
return 0;
// Initialize upper level driver
(sc->funs->eth_drv->init)(sc, &(priv->mac_address[0]) );
return 1;
}
// ------------------------------------------------------------------------
//
// API Function : dm9000_start
//
// ------------------------------------------------------------------------
static void
dm9000_start( struct eth_drv_sc *sc, unsigned char *enaddr, int flags )
{
struct dm9000 *priv = (struct dm9000 *)sc->driver_private;
// turn on receiver
putreg(priv, DM_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN);
// unmask interrupt
putreg(priv, DM_IMR, IMR_PAR | IMR_PTM | IMR_PRM);
priv->active = 1;
}
// ------------------------------------------------------------------------
//
// API Function : dm9000_stop
//
// ------------------------------------------------------------------------
static void
dm9000_stop( struct eth_drv_sc *sc )
{
struct dm9000 *priv = (struct dm9000 *)sc->driver_private;
// turn on receiver
putreg(priv, DM_RCR, 0);
// mask interrupts
putreg(priv, DM_IMR, IMR_PAR);
priv->active = 0;
}
// ------------------------------------------------------------------------
//
// API Function : dm9000_recv
//
// ------------------------------------------------------------------------
static void
dm9000_recv( struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len )
{
struct dm9000 *priv = (struct dm9000 *)sc->driver_private;
struct eth_drv_sg *sg = sg_list;
cyg_uint8 tmpbuf[4];
char *p;
int len, total_len, nread, n, leftover;
total_len = priv->rxlen;
nread = leftover = 0;
// diag_printf("dm9000_recv: total_len=%d\n", total_len);
do {
p = (char *)sg->buf;
len = sg->len;
// diag_printf("recv: buf=%p len=%d to_read=%d, leftover=%d\n", p, len, total_len - nread, leftover);
if ((nread + len) > total_len)
len = total_len - nread;
if (leftover) {
if (leftover <= len) {
memcpy(p, tmpbuf + (sizeof(tmpbuf) - leftover), leftover);
p += leftover;
len -= leftover;
nread += leftover;
leftover = 0;
} else {
memcpy(p, tmpbuf + (sizeof(tmpbuf) - leftover), len);
leftover -= len;
p += len;
nread += len;
len = 0;
}
}
while (len >= sizeof(tmpbuf)) {
n = priv->read_data(priv, p);
nread += n;
len -= n;
p += n;
}
while (len > 0) {
n = priv->read_data(priv, tmpbuf);
if (n <= len) {
memcpy(p, tmpbuf, n);
len -= n;
nread += n;
p += n;
} else {
memcpy(p, tmpbuf, len);
nread += len;
leftover = n - len;
len = 0;
}
}
++sg;
} while (nread < total_len);
#ifdef DEBUG_DUMP
for (sg = sg_list; sg < (sg_list + sg_len); sg++) {
diag_printf("\n");
diag_dump_buf(sg->buf, sg->len);
}
#endif
}
// ------------------------------------------------------------------------
//
// API Function : dm9000_can_send
//
// ------------------------------------------------------------------------
static int
dm9000_can_send(struct eth_drv_sc *sc)
{
struct dm9000 *priv = (struct dm9000 *)sc->driver_private;
if (!priv->active || priv->txbusy || priv->reset_pending)
return 0;
return 1;
}
// ------------------------------------------------------------------------
//
// API Function : dm9000_send
//
// ------------------------------------------------------------------------
static void
dm9000_send(struct eth_drv_sc *sc,
struct eth_drv_sg *sg_list, int sg_len,
int total_len, unsigned long key)
{
struct dm9000 *priv = (struct dm9000 *)sc->driver_private;
struct eth_drv_sg *sg;
cyg_uint8 tmpbuf[4];
int i, len, n, save_len, tail_extra;
char *p;
#ifdef DEBUG
diag_printf("dm9000_send: NCR[%02x] NSR[%02x] TRPA[%04x]\n",
getreg(priv, DM_NCR), getreg(priv, DM_NSR),
getreg(priv, DM_TRPAL) | (getreg(priv, DM_TRPAH) << 8)
);
#endif
#ifdef DEBUG_DUMP
for (sg = sg_list; sg < (sg_list + sg_len); sg++) {
diag_printf("\n");
diag_dump_buf(sg->buf, sg->len);
}
#endif
priv->txbusy = 1;
sg = sg_list;
save_len = total_len;
tail_extra = 0;
/* Disable all interrupts */
putreg(priv, DM_IMR, IMR_PAR);
HAL_WRITE_UINT8(priv->io_addr, DM_MWCMD);
while (total_len > 0) {
len = sg->len;
if (len > total_len)
len = total_len;
p = (char *)sg->buf;
/* write any left over partial words by combining them with the start
* of this sg block */
if (tail_extra) {
int head_extra = sizeof(tmpbuf) - tail_extra;
memcpy(tmpbuf + tail_extra, p, head_extra);
p += head_extra;
len -= head_extra;
for (i = 0; i < sizeof(tmpbuf) && total_len > 0; i += n) {
n = priv->write_data(priv, tmpbuf + i);
total_len -= n;
}
tail_extra = 0;
}
/* write out whole words */
while (len >= priv->buswidth) {
n = priv->write_data(priv, p);
len -= n;
total_len -= n;
p += n;
}
/* if we have some left over partial words... */
if (len > 0) {
/* combine them with the next sg block if available */
if (total_len > len ) {
tail_extra = len;
memcpy(tmpbuf, p, tail_extra);
} else {
/* otherwise just write this last partial word */
n = priv->write_data(priv, p);
total_len -= n;
}
}
sg++;
}
priv->txkey = key;
putreg(priv, DM_TXPLL, save_len);
putreg(priv, DM_TXPLH, save_len >> 8);
putreg(priv, DM_TCR, TCR_TXREQ);
/* Re-enable interrupt */
putreg(priv, DM_IMR, IMR_PAR | IMR_PTM | IMR_PRM);
}
// ------------------------------------------------------------------------
//
// API Function : dm9000_poll
//
// ------------------------------------------------------------------------
static void
dm9000_poll(struct eth_drv_sc *sc)
{
struct dm9000 *priv = (struct dm9000 *)sc->driver_private;
cyg_uint8 status, rxstat;
cyg_uint16 pkt_stat, pkt_len;
int i;
// mask interrupts
putreg(priv, DM_IMR, IMR_PAR);
// get and clear staus
status = getreg(priv, DM_ISR);
putreg(priv, DM_ISR, status);
// check for rx done
if (1 /*status & ISR_PRS*/) {
cyg_uint8 hdr[4]; /* 4 byte Rx pkt hdr */
getreg(priv, DM_MRCMDX); /* dummy read */
HAL_READ_UINT8(priv->io_data, rxstat);
// check for packet ready
if (rxstat == 1) {
HAL_WRITE_UINT8(priv->io_addr, DM_MRCMD);
for (i = 0; i < 4;)
i += priv->read_data(priv, hdr + i);
pkt_stat = hdr[0] | (hdr[1] << 8);
pkt_len = hdr[2] | (hdr[3] << 8);
#ifdef DEBUG
diag_printf("pkt_stat=%04x pkt_len=%04x\n", pkt_stat, pkt_len);
#endif
if (pkt_len < 0x40) {
diag_printf("packet too short: %d (0x%04x)\n", pkt_len, pkt_len);
i = 0;
while (i < pkt_len)
i += priv->read_data(priv, hdr);
} else if (pkt_len > 1536) {
priv->reset_pending = 1;
diag_printf("packet too long: %d (0x%04x)\n", pkt_len, pkt_len);
} else if (pkt_stat & 0xbf00) {
diag_printf("bad packet status: 0x%04x\n", pkt_stat);
i = 0;
while (i < pkt_len)
i += priv->read_data(priv, hdr);
} else {
// receive packet
priv->rxlen = pkt_len;
(sc->funs->eth_drv->recv)(sc, pkt_len);
}
} else if (rxstat > 1) {
// this should never happen.
diag_printf("unknown rxstat byte: %d\n", rxstat);
priv->reset_pending = 1;
}
}
// check transmit status
if (status & ISR_PTS) {
cyg_uint8 txstat;
txstat = getreg(priv, DM_NSR);
if (txstat & (NSR_TX1END | NSR_TX2END)) {
if (txstat & NSR_TX1END)
txstat = getreg(priv, DM_TSRI);
else
txstat = getreg(priv, DM_TSRII);
if (txstat & TSR_COL) {
// collision
}
if (getreg(priv, DM_TRPAL) & 3) {
// NIC bug detected. Need to reset.
priv->reset_pending = 1;
diag_printf("NIC collision bug detected!\n");
}
(sc->funs->eth_drv->tx_done)(sc, priv->txkey, 0);
priv->txbusy = 0;
}
}
if (priv->reset_pending && !priv->txbusy) {
initialize_nic(priv);
// turn on receiver
putreg(priv, DM_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN);
priv->reset_pending = 0;
}
// unmask interrupts
putreg(priv, DM_IMR, IMR_PAR | IMR_PTM | IMR_PRM);
}
// ------------------------------------------------------------------------
//
// API Function : dm9000_deliver
//
// ------------------------------------------------------------------------
static void
dm9000_deliver(struct eth_drv_sc *sc)
{
struct dm9000 *priv = (struct dm9000 *)sc->driver_private;
dm9000_poll(sc);
#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
cyg_drv_interrupt_unmask(priv->interrupt);
#endif
}
// ------------------------------------------------------------------------
//
// API Function : dm9000_int_vector
//
// ------------------------------------------------------------------------
static int
dm9000_int_vector(struct eth_drv_sc *sc)
{
struct dm9000 *priv = (struct dm9000 *)sc->driver_private;
return priv->interrupt;
}
// ------------------------------------------------------------------------
//
// API Function : dm9000_ioctl
//
// ------------------------------------------------------------------------
static int
dm9000_ioctl(struct eth_drv_sc *sc, unsigned long key,
void *data, int data_length)
{
struct dm9000 *priv = (struct dm9000 *)sc->driver_private;
cyg_uint8 *esa = (cyg_uint8 *)data;
int i;
switch (key) {
#ifdef ETH_DRV_GET_MAC_ADDRESS
case ETH_DRV_GET_MAC_ADDRESS:
memcpy(esa, priv->mac_address, sizeof(priv->mac_address));
return 0;
#endif
#ifdef ETH_DRV_SET_MAC_ADDRESS
case ETH_DRV_SET_MAC_ADDRESS:
for (i = 0; i < sizeof(priv->mac_address); i++) {
priv->mac_address[i] = esa[i];
putreg(priv, DM_PAR + i, priv->mac_address[i]);
}
#if defined(CYGSEM_DEVS_ETH_DAVICOM_DM9000_WRITE_EEPROM)
for (i = 0; i < sizeof(priv->mac_address) / 2; i++)
eeprom_write(priv, i, priv->mac_address[2*i] | (priv->mac_address[2*i+1] << 8));
#else
diag_printf("dm9000: eeprom write disabled\n");
#endif
return 0;
#endif
}
return -1;
}
// ------------------------------------------------------------------------
// EOF if_dm9000.c
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -