// SPDX-License-Identifier: GPL-2.0-only /* * Amiga Linux/68k 8390 based PCMCIA Ethernet Driver for the Amiga 1200 * * (C) Copyright 1997 Alain Malek * (Alain.Malek@cryogen.com) * * ---------------------------------------------------------------------------- * * This program is based on * * ne.c: A general non-shared-memory NS8390 ethernet driver for linux * Written 1992-94 by Donald Becker. * * 8390.c: A general NS8390 ethernet driver core for linux. * Written 1992-94 by Donald Becker. * * cnetdevice: A Sana-II ethernet driver for AmigaOS * Written by Bruce Abbott (bhabbott@inhb.co.nz) * * ---------------------------------------------------------------------------- *
*/
#define NE1SM_START_PG 0x20 /* First page of TX buffer */ #define NE1SM_STOP_PG 0x40 /* Last page +1 of RX ring */ #define NESM_START_PG 0x40 /* First page of TX buffer */ #define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */
staticint apne_probe1(struct net_device *dev, int ioaddr);
/* use MANUAL_CONFIG and MANUAL_OFFSET for enabling IO by hand you can find the values to use by looking at the cnet.device config file example (the default values are for the CNET40BC card)
*/
/* Reset card. Who knows what dain-bramaged state it was left in. */
{ unsignedlong reset_start_time = jiffies;
outb(inb(ioaddr + NE_RESET), ioaddr + NE_RESET);
while ((inb(ioaddr + NE_EN0_ISR) & ENISR_RESET) == 0) if (time_after(jiffies, reset_start_time + 2*HZ/100)) {
pr_cont(" not found (no reset ack).\n"); return -ENODEV;
}
outb(0xff, ioaddr + NE_EN0_ISR); /* Ack all intr. */
}
#ifndef MANUAL_HWADDR0
/* Read the 16 bytes of station address PROM. We must first initialize registers, similar to NS8390_init(eifdev, 0). We can't reliably read the SAPROM address without this.
(I learned the hard way!). */
{ struct {unsignedlong value, offset; } program_seq[] = {
{E8390_NODMA+E8390_PAGE0+E8390_STOP, NE_CMD}, /* Select page 0*/
{0x48, NE_EN0_DCFG}, /* Set byte-wide (0x48) access. */
{0x00, NE_EN0_RCNTLO}, /* Clear the count regs. */
{0x00, NE_EN0_RCNTHI},
{0x00, NE_EN0_IMR}, /* Mask completion irq. */
{0xFF, NE_EN0_ISR},
{E8390_RXOFF, NE_EN0_RXCR}, /* 0x20 Set to monitor */
{E8390_TXOFF, NE_EN0_TXCR}, /* 0x02 and loopback mode. */
{32, NE_EN0_RCNTLO},
{0x00, NE_EN0_RCNTHI},
{0x00, NE_EN0_RSARLO}, /* DMA starting at 0x0000. */
{0x00, NE_EN0_RSARHI},
{E8390_RREAD+E8390_START, NE_CMD},
}; for (i = 0; i < ARRAY_SIZE(program_seq); i++) {
outb(program_seq[i].value, ioaddr + program_seq[i].offset);
}
/* At this point, wordlength *only* tells us if the SA_prom is doubled up or not because some broken PCI cards don't respect the byte-wide request in program_seq above, and hence don't have doubled up values.
These broken cards would otherwise be detected as an ne1000. */
if (wordlength == 2) for (i = 0; i < 16; i++)
SA_prom[i] = SA_prom[i+i];
if (wordlength == 2) { /* We must set the 8390 for word mode. */
outb(0x49, ioaddr + NE_EN0_DCFG);
start_page = NESM_START_PG;
stop_page = NESM_STOP_PG;
} else {
start_page = NE1SM_START_PG;
stop_page = NE1SM_STOP_PG;
}
/* Set up the rest of the parameters. */ if (neX000) {
name = (wordlength == 2) ? "NE2000" : "NE1000";
} elseif (ctron) {
name = (wordlength == 2) ? "Ctron-8" : "Ctron-16";
start_page = 0x01;
stop_page = (wordlength == 2) ? 0x40 : 0x20;
} else {
pr_cont(" not found.\n"); return -ENXIO;
}
#else
wordlength = 2; /* We must set the 8390 for word mode. */
outb(0x49, ioaddr + NE_EN0_DCFG);
start_page = NESM_START_PG;
stop_page = NESM_STOP_PG;
pcmcia_ack_int(pcmcia_get_intreq()); /* ack PCMCIA int req */
pcmcia_enable_irq();
apne_owned = 1;
return 0;
}
/* Hard reset the card. This used to pause for the same period that a
8390 reset command required, but that shouldn't be necessary. */ staticvoid
apne_reset_8390(struct net_device *dev)
{ unsignedlong reset_start_time = jiffies; struct ei_device *ei_local = netdev_priv(dev);
init_pcmcia();
netif_dbg(ei_local, hw, dev, "resetting the 8390 t=%ld...\n", jiffies);
/* This check _should_not_ be necessary, omit eventually. */ while ((inb(NE_BASE+NE_EN0_ISR) & ENISR_RESET) == 0) if (time_after(jiffies, reset_start_time + 2*HZ/100)) {
netdev_err(dev, "ne_reset_8390() did not complete.\n"); break;
}
outb(ENISR_RESET, NE_BASE + NE_EN0_ISR); /* Ack intr. */
}
/* Grab the 8390 specific header. Similar to the block_input routine, but we don't need to be concerned with ring wrap as the header will be at
the start of a page, so we optimize accordingly. */
staticvoid
apne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
{
int nic_base = dev->base_addr; int cnt; char *ptrc; short *ptrs;
/* This *shouldn't* happen. If it does, it's the last thing you'll see */ if (ei_status.dmaing) {
netdev_err(dev, "DMAing conflict in ne_get_8390_hdr " "[DMAstat:%d][irqlock:%d][intr:%d].\n",
ei_status.dmaing, ei_status.irqlock, dev->irq); return;
}
/* Block input and output, similar to the Crynwr packet driver. If you are porting to a new ethercard, look at the packet driver source for hints. The NEx000 doesn't share the on-board packet memory -- you have to put
the packet out through the "remote DMA" dataport using outb. */
staticvoid
apne_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
{ int nic_base = dev->base_addr; char *buf = skb->data; char *ptrc; short *ptrs; int cnt;
/* This *shouldn't* happen. If it does, it's the last thing you'll see */ if (ei_status.dmaing) {
netdev_err(dev, "DMAing conflict in ne_block_input " "[DMAstat:%d][irqlock:%d][intr:%d].\n",
ei_status.dmaing, ei_status.irqlock, dev->irq); return;
}
ei_status.dmaing |= 0x01;
outb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
outb(ENISR_RDC, nic_base + NE_EN0_ISR);
outb(count & 0xff, nic_base + NE_EN0_RCNTLO);
outb(count >> 8, nic_base + NE_EN0_RCNTHI);
outb(ring_offset & 0xff, nic_base + NE_EN0_RSARLO);
outb(ring_offset >> 8, nic_base + NE_EN0_RSARHI);
outb(E8390_RREAD+E8390_START, nic_base + NE_CMD); if (ei_status.word16) {
ptrs = (short*)buf; for (cnt = 0; cnt < (count>>1); cnt++)
*ptrs++ = inw(NE_BASE + NE_DATAPORT); if (count & 0x01) {
buf[count-1] = inb(NE_BASE + NE_DATAPORT);
}
} else {
ptrc = buf; for (cnt = 0; cnt < count; cnt++)
*ptrc++ = inb(NE_BASE + NE_DATAPORT);
}
staticvoid
apne_block_output(struct net_device *dev, int count, constunsignedchar *buf, constint start_page)
{ int nic_base = NE_BASE; unsignedlong dma_start; char *ptrc; short *ptrs; int cnt;
/* Round the count up for word writes. Do we need to do this? What effect will an odd byte count have on the 8390?
I should check someday. */ if (ei_status.word16 && (count & 0x01))
count++;
/* This *shouldn't* happen. If it does, it's the last thing you'll see */ if (ei_status.dmaing) {
netdev_err(dev, "DMAing conflict in ne_block_output." "[DMAstat:%d][irqlock:%d][intr:%d]\n",
ei_status.dmaing, ei_status.irqlock, dev->irq); return;
}
ei_status.dmaing |= 0x01; /* We should already be in page 0, but to be safe... */
outb(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base + NE_CMD);
outb(ENISR_RDC, nic_base + NE_EN0_ISR);
/* Now the normal output. */
outb(count & 0xff, nic_base + NE_EN0_RCNTLO);
outb(count >> 8, nic_base + NE_EN0_RCNTHI);
outb(0x00, nic_base + NE_EN0_RSARLO);
outb(start_page, nic_base + NE_EN0_RSARHI);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.