Example #1
0
static irqreturn_t elp_interrupt(int irq, void *dev_id)
{
	int len;
	int dlen;
	int icount = 0;
	struct net_device *dev;
	elp_device *adapter;
	unsigned long timeout;

	dev = dev_id;
	adapter = (elp_device *) dev->priv;

	spin_lock(&adapter->lock);

	do {
		/*
		 * has a DMA transfer finished?
		 */
		if (inb_status(dev->base_addr) & DONE) {
			if (!adapter->dmaing) {
				printk(KERN_WARNING "%s: phantom DMA completed\n", dev->name);
			}
			if (elp_debug >= 3) {
				printk(KERN_DEBUG "%s: %s DMA complete, status %02x\n", dev->name, adapter->current_dma.direction ? "tx" : "rx", inb_status(dev->base_addr));
			}

			outb_control(adapter->hcr_val & ~(DMAE | TCEN | DIR), dev);
			if (adapter->current_dma.direction) {
				dev_kfree_skb_irq(adapter->current_dma.skb);
			} else {
				struct sk_buff *skb = adapter->current_dma.skb;
				if (skb) {
					if (adapter->current_dma.target) {
				  	/* have already done the skb_put() */
				  	memcpy(adapter->current_dma.target, adapter->dma_buffer, adapter->current_dma.length);
					}
					skb->protocol = eth_type_trans(skb,dev);
					adapter->stats.rx_bytes += skb->len;
					netif_rx(skb);
					dev->last_rx = jiffies;
				}
			}
			adapter->dmaing = 0;
			if (adapter->rx_backlog.in != adapter->rx_backlog.out) {
				int t = adapter->rx_backlog.length[adapter->rx_backlog.out];
				adapter->rx_backlog.out = backlog_next(adapter->rx_backlog.out);
				if (elp_debug >= 2)
					printk(KERN_DEBUG "%s: receiving backlogged packet (%d)\n", dev->name, t);
				receive_packet(dev, t);
			} else {
				adapter->busy = 0;
			}
		} else {
			/* has one timed out? */
			check_3c505_dma(dev);
		}

		/*
		 * receive a PCB from the adapter
		 */
		timeout = jiffies + 3*HZ/100;
		while ((inb_status(dev->base_addr) & ACRF) != 0 && time_before(jiffies, timeout)) {
			if (receive_pcb(dev, &adapter->irx_pcb)) {
				switch (adapter->irx_pcb.command)
				{
				case 0:
					break;
					/*
					 * received a packet - this must be handled fast
					 */
				case 0xff:
				case CMD_RECEIVE_PACKET_COMPLETE:
					/* if the device isn't open, don't pass packets up the stack */
					if (!netif_running(dev))
						break;
					len = adapter->irx_pcb.data.rcv_resp.pkt_len;
					dlen = adapter->irx_pcb.data.rcv_resp.buf_len;
					if (adapter->irx_pcb.data.rcv_resp.timeout != 0) {
						printk(KERN_ERR "%s: interrupt - packet not received correctly\n", dev->name);
					} else {
						if (elp_debug >= 3) {
							printk(KERN_DEBUG "%s: interrupt - packet received of length %i (%i)\n", dev->name, len, dlen);
						}
						if (adapter->irx_pcb.command == 0xff) {
							if (elp_debug >= 2)
								printk(KERN_DEBUG "%s: adding packet to backlog (len = %d)\n", dev->name, dlen);
							adapter->rx_backlog.length[adapter->rx_backlog.in] = dlen;
							adapter->rx_backlog.in = backlog_next(adapter->rx_backlog.in);
						} else {
							receive_packet(dev, dlen);
						}
						if (elp_debug >= 3)
							printk(KERN_DEBUG "%s: packet received\n", dev->name);
					}
					break;

					/*
					 * 82586 configured correctly
					 */
				case CMD_CONFIGURE_82586_RESPONSE:
					adapter->got[CMD_CONFIGURE_82586] = 1;
					if (elp_debug >= 3)
						printk(KERN_DEBUG "%s: interrupt - configure response received\n", dev->name);
					break;

					/*
					 * Adapter memory configuration
					 */
				case CMD_CONFIGURE_ADAPTER_RESPONSE:
					adapter->got[CMD_CONFIGURE_ADAPTER_MEMORY] = 1;
					if (elp_debug >= 3)
						printk(KERN_DEBUG "%s: Adapter memory configuration %s.\n", dev->name,
						       adapter->irx_pcb.data.failed ? "failed" : "succeeded");
					break;

					/*
					 * Multicast list loading
					 */
				case CMD_LOAD_MULTICAST_RESPONSE:
					adapter->got[CMD_LOAD_MULTICAST_LIST] = 1;
					if (elp_debug >= 3)
						printk(KERN_DEBUG "%s: Multicast address list loading %s.\n", dev->name,
						       adapter->irx_pcb.data.failed ? "failed" : "succeeded");
					break;

					/*
					 * Station address setting
					 */
				case CMD_SET_ADDRESS_RESPONSE:
					adapter->got[CMD_SET_STATION_ADDRESS] = 1;
					if (elp_debug >= 3)
						printk(KERN_DEBUG "%s: Ethernet address setting %s.\n", dev->name,
						       adapter->irx_pcb.data.failed ? "failed" : "succeeded");
					break;


					/*
					 * received board statistics
					 */
				case CMD_NETWORK_STATISTICS_RESPONSE:
					adapter->stats.rx_packets += adapter->irx_pcb.data.netstat.tot_recv;
					adapter->stats.tx_packets += adapter->irx_pcb.data.netstat.tot_xmit;
					adapter->stats.rx_crc_errors += adapter->irx_pcb.data.netstat.err_CRC;
					adapter->stats.rx_frame_errors += adapter->irx_pcb.data.netstat.err_align;
					adapter->stats.rx_fifo_errors += adapter->irx_pcb.data.netstat.err_ovrrun;
					adapter->stats.rx_over_errors += adapter->irx_pcb.data.netstat.err_res;
					adapter->got[CMD_NETWORK_STATISTICS] = 1;
					if (elp_debug >= 3)
						printk(KERN_DEBUG "%s: interrupt - statistics response received\n", dev->name);
					break;

					/*
					 * sent a packet
					 */
				case CMD_TRANSMIT_PACKET_COMPLETE:
					if (elp_debug >= 3)
						printk(KERN_DEBUG "%s: interrupt - packet sent\n", dev->name);
					if (!netif_running(dev))
						break;
					switch (adapter->irx_pcb.data.xmit_resp.c_stat) {
					case 0xffff:
						adapter->stats.tx_aborted_errors++;
						printk(KERN_INFO "%s: transmit timed out, network cable problem?\n", dev->name);
						break;
					case 0xfffe:
						adapter->stats.tx_fifo_errors++;
						printk(KERN_INFO "%s: transmit timed out, FIFO underrun\n", dev->name);
						break;
					}
					netif_wake_queue(dev);
					break;

					/*
					 * some unknown PCB
					 */
				default:
					printk(KERN_DEBUG "%s: unknown PCB received - %2.2x\n", dev->name, adapter->irx_pcb.command);
					break;
				}
			} else {
				printk(KERN_WARNING "%s: failed to read PCB on interrupt\n", dev->name);
				adapter_reset(dev);
			}
		}

	} while (icount++ < 5 && (inb_status(dev->base_addr) & (ACRF | DONE)));

	prime_rx(dev);

	/*
	 * indicate no longer in interrupt routine
	 */
	spin_unlock(&adapter->lock);
	return IRQ_HANDLED;
}
Example #2
0
static int __init elplus_setup(struct net_device *dev)
{
	elp_device *adapter = dev->priv;
	int i, tries, tries1, okay;
	unsigned long timeout;
	unsigned long cookie = 0;
	int err = -ENODEV;

	SET_MODULE_OWNER(dev);

	/*
	 *  setup adapter structure
	 */

	dev->base_addr = elp_autodetect(dev);
	if (!dev->base_addr)
		return -ENODEV;

	adapter->send_pcb_semaphore = 0;

	for (tries1 = 0; tries1 < 3; tries1++) {
		outb_control((adapter->hcr_val | CMDE) & ~DIR, dev);
		/* First try to write just one byte, to see if the card is
		 * responding at all normally.
		 */
		timeout = jiffies + 5*HZ/100;
		okay = 0;
		while (time_before(jiffies, timeout) && !(inb_status(dev->base_addr) & HCRE));
		if ((inb_status(dev->base_addr) & HCRE)) {
			outb_command(0, dev->base_addr);	/* send a spurious byte */
			timeout = jiffies + 5*HZ/100;
			while (time_before(jiffies, timeout) && !(inb_status(dev->base_addr) & HCRE));
			if (inb_status(dev->base_addr) & HCRE)
				okay = 1;
		}
		if (!okay) {
			/* Nope, it's ignoring the command register.  This means that
			 * either it's still booting up, or it's died.
			 */
			printk(KERN_ERR "%s: command register wouldn't drain, ", dev->name);
			if ((inb_status(dev->base_addr) & 7) == 3) {
				/* If the adapter status is 3, it *could* still be booting.
				 * Give it the benefit of the doubt for 10 seconds.
				 */
				printk("assuming 3c505 still starting\n");
				timeout = jiffies + 10*HZ;
				while (time_before(jiffies, timeout) && (inb_status(dev->base_addr) & 7));
				if (inb_status(dev->base_addr) & 7) {
					printk(KERN_ERR "%s: 3c505 failed to start\n", dev->name);
				} else {
					okay = 1;  /* It started */
				}
			} else {
				/* Otherwise, it must just be in a strange
				 * state.  We probably need to kick it.
				 */
				printk("3c505 is sulking\n");
			}
		}
		for (tries = 0; tries < 5 && okay; tries++) {

			/*
			 * Try to set the Ethernet address, to make sure that the board
			 * is working.
			 */
			adapter->tx_pcb.command = CMD_STATION_ADDRESS;
			adapter->tx_pcb.length = 0;
			cookie = probe_irq_on();
			if (!send_pcb(dev, &adapter->tx_pcb)) {
				printk(KERN_ERR "%s: could not send first PCB\n", dev->name);
				probe_irq_off(cookie);
				continue;
			}
			if (!receive_pcb(dev, &adapter->rx_pcb)) {
				printk(KERN_ERR "%s: could not read first PCB\n", dev->name);
				probe_irq_off(cookie);
				continue;
			}
			if ((adapter->rx_pcb.command != CMD_ADDRESS_RESPONSE) ||
			    (adapter->rx_pcb.length != 6)) {
				printk(KERN_ERR "%s: first PCB wrong (%d, %d)\n", dev->name, adapter->rx_pcb.command, adapter->rx_pcb.length);
				probe_irq_off(cookie);
				continue;
			}
			goto okay;
		}
		/* It's broken.  Do a hard reset to re-initialise the board,
		 * and try again.
		 */
		printk(KERN_INFO "%s: resetting adapter\n", dev->name);
		outb_control(adapter->hcr_val | FLSH | ATTN, dev);
		outb_control(adapter->hcr_val & ~(FLSH | ATTN), dev);
	}
	printk(KERN_ERR "%s: failed to initialise 3c505\n", dev->name);
	goto out;

      okay:
	if (dev->irq) {		/* Is there a preset IRQ? */
		int rpt = probe_irq_off(cookie);
		if (dev->irq != rpt) {
			printk(KERN_WARNING "%s: warning, irq %d configured but %d detected\n", dev->name, dev->irq, rpt);
		}
		/* if dev->irq == probe_irq_off(cookie), all is well */
	} else		       /* No preset IRQ; just use what we can detect */
		dev->irq = probe_irq_off(cookie);
	switch (dev->irq) {    /* Legal, sane? */
	case 0:
		printk(KERN_ERR "%s: IRQ probe failed: check 3c505 jumpers.\n",
		       dev->name);
		goto out;
	case 1:
	case 6:
	case 8:
	case 13:
		printk(KERN_ERR "%s: Impossible IRQ %d reported by probe_irq_off().\n",
		       dev->name, dev->irq);
		       goto out;
	}
	/*
	 *  Now we have the IRQ number so we can disable the interrupts from
	 *  the board until the board is opened.
	 */
	outb_control(adapter->hcr_val & ~CMDE, dev);

	/*
	 * copy Ethernet address into structure
	 */
	for (i = 0; i < 6; i++)
		dev->dev_addr[i] = adapter->rx_pcb.data.eth_addr[i];

	/* find a DMA channel */
	if (!dev->dma) {
		if (dev->mem_start) {
			dev->dma = dev->mem_start & 7;
		}
		else {
			printk(KERN_WARNING "%s: warning, DMA channel not specified, using default\n", dev->name);
			dev->dma = ELP_DMA;
		}
	}

	/*
	 * print remainder of startup message
	 */
	printk(KERN_INFO "%s: 3c505 at %#lx, irq %d, dma %d, ",
	       dev->name, dev->base_addr, dev->irq, dev->dma);
	printk("addr %02x:%02x:%02x:%02x:%02x:%02x, ",
	       dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
	       dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);

	/*
	 * read more information from the adapter
	 */

	adapter->tx_pcb.command = CMD_ADAPTER_INFO;
	adapter->tx_pcb.length = 0;
	if (!send_pcb(dev, &adapter->tx_pcb) ||
	    !receive_pcb(dev, &adapter->rx_pcb) ||
	    (adapter->rx_pcb.command != CMD_ADAPTER_INFO_RESPONSE) ||
	    (adapter->rx_pcb.length != 10)) {
		printk("not responding to second PCB\n");
	}
	printk("rev %d.%d, %dk\n", adapter->rx_pcb.data.info.major_vers, adapter->rx_pcb.data.info.minor_vers, adapter->rx_pcb.data.info.RAM_sz);

	/*
	 * reconfigure the adapter memory to better suit our purposes
	 */
	adapter->tx_pcb.command = CMD_CONFIGURE_ADAPTER_MEMORY;
	adapter->tx_pcb.length = 12;
	adapter->tx_pcb.data.memconf.cmd_q = 8;
	adapter->tx_pcb.data.memconf.rcv_q = 8;
	adapter->tx_pcb.data.memconf.mcast = 10;
	adapter->tx_pcb.data.memconf.frame = 10;
	adapter->tx_pcb.data.memconf.rcv_b = 10;
	adapter->tx_pcb.data.memconf.progs = 0;
	if (!send_pcb(dev, &adapter->tx_pcb) ||
	    !receive_pcb(dev, &adapter->rx_pcb) ||
	    (adapter->rx_pcb.command != CMD_CONFIGURE_ADAPTER_RESPONSE) ||
	    (adapter->rx_pcb.length != 2)) {
		printk(KERN_ERR "%s: could not configure adapter memory\n", dev->name);
	}
	if (adapter->rx_pcb.data.configure) {
		printk(KERN_ERR "%s: adapter configuration failed\n", dev->name);
	}

	dev->open = elp_open;				/* local */
	dev->stop = elp_close;				/* local */
	dev->get_stats = elp_get_stats;			/* local */
	dev->hard_start_xmit = elp_start_xmit;		/* local */
	dev->tx_timeout = elp_timeout;			/* local */
	dev->watchdog_timeo = 10*HZ;
	dev->set_multicast_list = elp_set_mc_list;	/* local */
	dev->ethtool_ops = &netdev_ethtool_ops;		/* local */

	memset(&(adapter->stats), 0, sizeof(struct net_device_stats));
	dev->mem_start = dev->mem_end = 0;

	err = register_netdev(dev);
	if (err)
		goto out;

	return 0;
out:
	release_region(dev->base_addr, ELP_IO_EXTENT);
	return err;
}
Example #3
0
int elplus_probe(struct device *dev)

{
    elp_device adapter;
    int            i;

    CHECK_NULL(dev);

    /*
     *  setup adapter structure
     */

    adapter.io_addr = dev->base_addr = elp_autodetect(dev);
    if ( !adapter.io_addr )
        return -ENODEV;

    /*
     *  As we enter here from bootup, the adapter should have IRQs enabled,
     *  but we can as well enable them anyway.
     */
    OUTB(INB(dev->base_addr+PORT_CONTROL) | CONTROL_CMDE,
         dev->base_addr+PORT_CONTROL);
    autoirq_setup(0);

    /*
     * use ethernet address command to probe for board in polled mode
     * (this also makes us the IRQ that we need for automatic detection)
     */
    adapter.tx_pcb.command = CMD_STATION_ADDRESS;
    adapter.tx_pcb.length  = 0;
    if (!send_pcb   (&adapter, &adapter.tx_pcb) ||
            !receive_pcb(&adapter, &adapter.rx_pcb) ||
            (adapter.rx_pcb.command != CMD_ADDRESS_RESPONSE) ||
            (adapter.rx_pcb.length != 6)) {
        printk("%s: not responding to first PCB\n", dev->name);
        return -ENODEV;
    }
    if (dev->irq) { /* Is there a preset IRQ? */
        if (dev->irq != autoirq_report(0)) {
            printk("%s: Detected IRQ doesn't match user-defined one.\n",dev->name);
            return -ENODEV;
        }
        /* if dev->irq == autoirq_report(0), all is well */
    } else /* No preset IRQ; just use what we can detect */
        dev->irq=autoirq_report(0);
    switch (dev->irq) { /* Legal, sane? */
    case 0:
        printk("%s: No IRQ reported by autoirq_report().\n",dev->name);
        printk("%s: Check the jumpers of your 3c505 board.\n",dev->name);
        return -ENODEV;
    case 1:
    case 6:
    case 8:
    case 13:
        printk("%s: Impossible IRQ %d reported by autoirq_report().\n",
               dev->name,
               dev->irq);
        return -ENODEV;
    }
    /*
     *  Now we have the IRQ number so we can disable the interrupts from
     *  the board until the board is opened.
     */
    OUTB(INB(dev->base_addr+PORT_CONTROL) & ~CONTROL_CMDE,
         dev->base_addr+PORT_CONTROL);

    /*
     * copy ethernet address into structure
     */
    for (i = 0; i < 6; i++)
        dev->dev_addr[i] = adapter.rx_pcb.data.eth_addr[i];

    /*
     * print remainder of startup message
     */
#if (ELP_KERNEL_TYPE < 2)
    printk("%s: 3c505 card found at I/O 0x%x using IRQ%d has address %s\n",
           dev->name, dev->base_addr, dev->irq, eth_print(dev->dev_addr));
#else
    printk("%s: 3c505 card found at I/O 0x%x using IRQ%d has address %02x:%02x:%02x:%02x:%02x:%02x\n",
           dev->name, dev->base_addr, dev->irq,
           dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
           dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
#endif

    /*
     * initialise the device
     */
    elp_init(dev);
    return 0;
}
Example #4
0
static void elp_interrupt(int reg_ptr)

{
    int len;
    int dlen;
    int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2);
    struct device *dev;
    elp_device * adapter;
    int timeout;

    if (irq < 0 || irq > 15) {
        printk ("elp_interrupt(): illegal IRQ number found in interrupt routine (%i)\n", irq);
        return;
    }

    /* FIXME: How do I do this kind of check without a fixed IRQ? */
#if 0
    if (irq != ELP_IRQ) {
        printk ("elp_interrupt(): - interrupt routine has incorrect IRQ of %i\n", irq);
        return;
    }
#endif

    dev = irq2dev_map[irq];

    if (dev == NULL) {
        printk ("elp_interrupt(): irq %d for unknown device.\n", irq);
        return;
    }

    adapter = (elp_device *) dev->priv;

    CHECK_NULL(adapter);

    if (dev->interrupt)
        if (elp_debug >= 2)
            printk("%s: Re-entering the interrupt handler.\n", dev->name);
    dev->interrupt = 1;

    /*
     * allow interrupts (we need timers!)
     */
    sti();

    /*
     * receive a PCB from the adapter
     */
    timeout = jiffies + TIMEOUT;
    while ((INB(adapter->io_addr+PORT_STATUS)&STATUS_ACRF) != 0 &&
            jiffies < timeout) {

        if (receive_pcb(adapter, &adapter->irx_pcb)) {

            switch (adapter->irx_pcb.command) {

            /*
             * 82586 configured correctly
             */
            case CMD_CONFIGURE_82586_RESPONSE:
                adapter->got[CMD_CONFIGURE_82586] = 1;
                if (elp_debug >= 3)
                    printk("%s: interrupt - configure response received\n", dev->name);
                break;

            /*
             * Adapter memory configuration
             */
            case CMD_CONFIGURE_ADAPTER_RESPONSE:
                adapter->got[CMD_CONFIGURE_ADAPTER_MEMORY] = 1;
                if (elp_debug >= 3)
                    printk("%s: Adapter memory configuration %s.",dev->name,
                           adapter->irx_pcb.data.failed?"failed":"succeeded");
                break;

            /*
             * Multicast list loading
             */
            case CMD_LOAD_MULTICAST_RESPONSE:
                adapter->got[CMD_LOAD_MULTICAST_LIST] = 1;
                if (elp_debug >= 3)
                    printk("%s: Multicast address list loading %s.",dev->name,
                           adapter->irx_pcb.data.failed?"failed":"succeeded");
                break;

            /*
             * Station address setting
             */
            case CMD_SET_ADDRESS_RESPONSE:
                adapter->got[CMD_SET_STATION_ADDRESS] = 1;
                if (elp_debug >= 3)
                    printk("%s: Ethernet address setting %s.",dev->name,
                           adapter->irx_pcb.data.failed?"failed":"succeeded");
                break;


            /*
             * received board statistics
             */
            case CMD_NETWORK_STATISTICS_RESPONSE:
                adapter->stats.rx_packets += adapter->irx_pcb.data.netstat.tot_recv;
                adapter->stats.tx_packets += adapter->irx_pcb.data.netstat.tot_xmit;
                adapter->stats.rx_crc_errors += adapter->irx_pcb.data.netstat.err_CRC;
                adapter->stats.rx_frame_errors += adapter->irx_pcb.data.netstat.err_align;
                adapter->stats.rx_fifo_errors += adapter->irx_pcb.data.netstat.err_ovrrun;
                adapter->got[CMD_NETWORK_STATISTICS] = 1;
                if (elp_debug >= 3)
                    printk("%s: interrupt - statistics response received\n", dev->name);
                break;

            /*
             * received a packet
             */
            case CMD_RECEIVE_PACKET_COMPLETE:
                /* if the device isn't open, don't pass packets up the stack */
                if (dev->start == 0)
                    break;
                len = adapter->irx_pcb.data.rcv_resp.pkt_len;
                dlen = adapter->irx_pcb.data.rcv_resp.buf_len;
                if (adapter->irx_pcb.data.rcv_resp.timeout != 0) {
                    printk("%s: interrupt - packet not received correctly\n", dev->name);
                } else {
                    if (elp_debug >= 3)
                        printk("%s: interrupt - packet received of length %i (%i)\n", dev->name, len, dlen);
                    receive_packet(dev, adapter, dlen);
                    if (elp_debug >= 3)
                        printk("%s: packet received\n", dev->name);
                }
                if (dev->start && !start_receive(adapter, &adapter->itx_pcb))
                    if (elp_debug >= 2)
                        printk("%s: interrupt - failed to send receive start PCB\n", dev->name);
                if (elp_debug >= 3)
                    printk("%s: receive procedure complete\n", dev->name);

                break;

            /*
             * sent a packet
             */
            case CMD_TRANSMIT_PACKET_COMPLETE:
                if (elp_debug >= 3)
                    printk("%s: interrupt - packet sent\n", dev->name);
                if (dev->start == 0)
                    break;
                if (adapter->irx_pcb.data.xmit_resp.c_stat != 0)
                    if (elp_debug >= 2)
                        printk("%s: interrupt - error sending packet %4.4x\n",
                               dev->name, adapter->irx_pcb.data.xmit_resp.c_stat);
                dev->tbusy = 0;
#if (ELP_KERNEL_TYPE < 3)
                mark_bh(INET_BH);
#else
                mark_bh(NET_BH);
#endif
                break;

            /*
             * some unknown PCB
             */
            default:
                printk("%s: unknown PCB received - %2.2x\n", dev->name, adapter->irx_pcb.command);
                break;
            }
        } else
            printk("%s: failed to read PCB on interrupt\n", dev->name);
    }
    if (jiffies >= timeout)
        TIMEOUT_MSG();

    /*
     * indicate no longer in interrupt routine
     */
    dev->interrupt = 0;
}
static int __init elplus_setup(struct net_device *dev)
{
	elp_device *adapter = netdev_priv(dev);
	int i, tries, tries1, okay;
	unsigned long timeout;
	unsigned long cookie = 0;
	int err = -ENODEV;


	dev->base_addr = elp_autodetect(dev);
	if (!dev->base_addr)
		return -ENODEV;

	adapter->send_pcb_semaphore = 0;

	for (tries1 = 0; tries1 < 3; tries1++) {
		outb_control((adapter->hcr_val | CMDE) & ~DIR, dev);
		timeout = jiffies + 5*HZ/100;
		okay = 0;
		while (time_before(jiffies, timeout) && !(inb_status(dev->base_addr) & HCRE));
		if ((inb_status(dev->base_addr) & HCRE)) {
			outb_command(0, dev->base_addr);	
			timeout = jiffies + 5*HZ/100;
			while (time_before(jiffies, timeout) && !(inb_status(dev->base_addr) & HCRE));
			if (inb_status(dev->base_addr) & HCRE)
				okay = 1;
		}
		if (!okay) {
			pr_err("%s: command register wouldn't drain, ", dev->name);
			if ((inb_status(dev->base_addr) & 7) == 3) {
				pr_cont("assuming 3c505 still starting\n");
				timeout = jiffies + 10*HZ;
				while (time_before(jiffies, timeout) && (inb_status(dev->base_addr) & 7));
				if (inb_status(dev->base_addr) & 7) {
					pr_err("%s: 3c505 failed to start\n", dev->name);
				} else {
					okay = 1;  
				}
			} else {
				pr_cont("3c505 is sulking\n");
			}
		}
		for (tries = 0; tries < 5 && okay; tries++) {

			adapter->tx_pcb.command = CMD_STATION_ADDRESS;
			adapter->tx_pcb.length = 0;
			cookie = probe_irq_on();
			if (!send_pcb(dev, &adapter->tx_pcb)) {
				pr_err("%s: could not send first PCB\n", dev->name);
				probe_irq_off(cookie);
				continue;
			}
			if (!receive_pcb(dev, &adapter->rx_pcb)) {
				pr_err("%s: could not read first PCB\n", dev->name);
				probe_irq_off(cookie);
				continue;
			}
			if ((adapter->rx_pcb.command != CMD_ADDRESS_RESPONSE) ||
			    (adapter->rx_pcb.length != 6)) {
				pr_err("%s: first PCB wrong (%d, %d)\n", dev->name,
					adapter->rx_pcb.command, adapter->rx_pcb.length);
				probe_irq_off(cookie);
				continue;
			}
			goto okay;
		}
		pr_info("%s: resetting adapter\n", dev->name);
		outb_control(adapter->hcr_val | FLSH | ATTN, dev);
		outb_control(adapter->hcr_val & ~(FLSH | ATTN), dev);
	}
	pr_err("%s: failed to initialise 3c505\n", dev->name);
	goto out;

      okay:
	if (dev->irq) {		
		int rpt = probe_irq_off(cookie);
		if (dev->irq != rpt) {
			pr_warning("%s: warning, irq %d configured but %d detected\n", dev->name, dev->irq, rpt);
		}
		
	} else		       
		dev->irq = probe_irq_off(cookie);
	switch (dev->irq) {    
	case 0:
		pr_err("%s: IRQ probe failed: check 3c505 jumpers.\n",
		       dev->name);
		goto out;
	case 1:
	case 6:
	case 8:
	case 13:
		pr_err("%s: Impossible IRQ %d reported by probe_irq_off().\n",
		       dev->name, dev->irq);
		       goto out;
	}
	outb_control(adapter->hcr_val & ~CMDE, dev);

	for (i = 0; i < 6; i++)
		dev->dev_addr[i] = adapter->rx_pcb.data.eth_addr[i];

	
	if (!dev->dma) {
		if (dev->mem_start) {
			dev->dma = dev->mem_start & 7;
		}
		else {
			pr_warning("%s: warning, DMA channel not specified, using default\n", dev->name);
			dev->dma = ELP_DMA;
		}
	}

	pr_info("%s: 3c505 at %#lx, irq %d, dma %d, addr %pM, ",
		dev->name, dev->base_addr, dev->irq, dev->dma, dev->dev_addr);

	adapter->tx_pcb.command = CMD_ADAPTER_INFO;
	adapter->tx_pcb.length = 0;
	if (!send_pcb(dev, &adapter->tx_pcb) ||
	    !receive_pcb(dev, &adapter->rx_pcb) ||
	    (adapter->rx_pcb.command != CMD_ADAPTER_INFO_RESPONSE) ||
	    (adapter->rx_pcb.length != 10)) {
		pr_cont("not responding to second PCB\n");
	}
	pr_cont("rev %d.%d, %dk\n", adapter->rx_pcb.data.info.major_vers,
		adapter->rx_pcb.data.info.minor_vers, adapter->rx_pcb.data.info.RAM_sz);

	adapter->tx_pcb.command = CMD_CONFIGURE_ADAPTER_MEMORY;
	adapter->tx_pcb.length = 12;
	adapter->tx_pcb.data.memconf.cmd_q = 8;
	adapter->tx_pcb.data.memconf.rcv_q = 8;
	adapter->tx_pcb.data.memconf.mcast = 10;
	adapter->tx_pcb.data.memconf.frame = 10;
	adapter->tx_pcb.data.memconf.rcv_b = 10;
	adapter->tx_pcb.data.memconf.progs = 0;
	if (!send_pcb(dev, &adapter->tx_pcb) ||
	    !receive_pcb(dev, &adapter->rx_pcb) ||
	    (adapter->rx_pcb.command != CMD_CONFIGURE_ADAPTER_RESPONSE) ||
	    (adapter->rx_pcb.length != 2)) {
		pr_err("%s: could not configure adapter memory\n", dev->name);
	}
	if (adapter->rx_pcb.data.configure) {
		pr_err("%s: adapter configuration failed\n", dev->name);
	}

	dev->netdev_ops = &elp_netdev_ops;
	dev->watchdog_timeo = 10*HZ;
	dev->ethtool_ops = &netdev_ethtool_ops;		

	dev->mem_start = dev->mem_end = 0;

	err = register_netdev(dev);
	if (err)
		goto out;

	return 0;
out:
	release_region(dev->base_addr, ELP_IO_EXTENT);
	return err;
}