Ejemplo n.º 1
0
void can_rx_disable_filtering(void)
{
	set_mode(REQOP_CONFIG);

	clear_filter_mask(2);

	set_rx_mode(0, RXM_ANY);

	/* TODO: Check if rollover is on */
	set_rx_mode(1, RXM_ANY);

	set_mode(REQOP_NORMAL);
}
Ejemplo n.º 2
0
static void w89c840_reset(struct nic *nic)
{
    int i;

    writel(0x00000001, ioaddr + PCIBusCfg);

    init_ring();

    writel(virt_to_bus(w840private.rx_ring), ioaddr + RxRingPtr);
    writel(virt_to_bus(w840private.tx_ring), ioaddr + TxRingPtr);

    for (i = 0; i < ETH_ALEN; i++)
        writeb(nic->node_addr[i], ioaddr + StationAddr + i);

    

    writel(0xE010, ioaddr + PCIBusCfg);

    writel(0, ioaddr + RxStartDemand);
    w840private.csr6 = 0x20022002;
    check_duplex();
    set_rx_mode();

    
    writel(0x1A0F5, ioaddr + IntrStatus);
    writel(0x1A0F5, ioaddr + IntrEnable);

#if defined(W89C840_DEBUG)
    printf("winbond-840 : Done reset.\n");
#endif
}
Ejemplo n.º 3
0
//////////////////////
// rx_fetch_pkt: read packet into buffer if available
//
//	returns number of bytes transferred to pkt, 0 if no data available
//
byte rx_fetch_pkt(pkt_t *pkt) {

	// Does the radio have business for us?
	if (!rx_pkt_ready()) return 0;		// quick out if our packet interrupt hasn't fired

	if (!(rf_read_status() & (1<<IPKVALID))) {
#ifdef RADIO_DEBUG
		sp("rx: int no pkt!");
#endif
		return 0;
	}

#ifdef RADIO_DEBUG
	sp("rx_ got _packet");
#endif

	led_on();

	byte length = rf_read_register(REG_RECEIVED_PACKET_LENGTH);

	// If the packet length is bigger than our buffer We Have A Situation.
	// Clip to our max packet size; set_rx_mode() will clear the fifo,
	// silently discarding the excess.
	//
	if (length > RF_PACKET_SIZE) length = RF_PACKET_SIZE;

	rx_get_pkt(REG_FIFO, length, pkt);
	rx_packet_count++;						// got one? count it
	set_rx_mode();
	led_off();

	log_packet('R', pkt, length);

	return length;
}
Ejemplo n.º 4
0
int can_rx_set_filter(struct can_id id, unsigned int mask)
{
	int ret;

	set_mode(REQOP_CONFIG);

	ret = set_rx_filter(id, mask);

	set_rx_mode(0, RXM_BOTH);

	/* TODO: Check if rollover is on */
	set_rx_mode(1, RXM_BOTH);

	set_mode(REQOP_NORMAL);

	return ret;
}
Ejemplo n.º 5
0
static void rtl_reset(struct eth_device *dev)
{
	int i;

	outb(CmdReset, ioaddr + ChipCmd);

	cur_rx = 0;
	cur_tx = 0;

	/* Give the chip 10ms to finish the reset. */
	for (i=0; i<100; ++i){
		if ((inb(ioaddr + ChipCmd) & CmdReset) == 0) break;
		udelay (100); /* wait 100us */
	}


	for (i = 0; i < ETH_ALEN; i++)
		outb(dev->enetaddr[i], ioaddr + MAC0 + i);

	/* Must enable Tx/Rx before setting transfer thresholds! */
	outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);
	outl((RX_FIFO_THRESH<<13) | (RX_BUF_LEN_IDX<<11) | (RX_DMA_BURST<<8),
		ioaddr + RxConfig);		/* accept no frames yet!  */
	outl((TX_DMA_BURST<<8)|0x03000000, ioaddr + TxConfig);

	/* The Linux driver changes Config1 here to use a different LED pattern
	 * for half duplex or full/autodetect duplex (for full/autodetect, the
	 * outputs are TX/RX, Link10/100, FULL, while for half duplex it uses
	 * TX/RX, Link100, Link10).  This is messy, because it doesn't match
	 * the inscription on the mounting bracket.  It should not be changed
	 * from the configuration EEPROM default, because the card manufacturer
	 * should have set that to match the card.  */

#ifdef	DEBUG_RX
	printf("rx ring address is %X\n",(unsigned long)rx_ring);
#endif
	flush_cache((unsigned long)rx_ring, RX_BUF_LEN);
	outl(phys_to_bus((int)rx_ring), ioaddr + RxBuf);

	/* If we add multicast support, the MAR0 register would have to be
	 * initialized to 0xffffffffffffffff (two 32 bit accesses).  Etherboot
	 * only needs broadcast (for ARP/RARP/BOOTP/DHCP) and unicast.	*/

	outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);

	outl(rtl8139_rx_config, ioaddr + RxConfig);

	/* Start the chip's Tx and Rx process. */
	outl(0, ioaddr + RxMissed);

	/* set_rx_mode */
	set_rx_mode(dev);

	/* Disable all known interrupts by setting the interrupt mask. */
	outw(0, ioaddr + IntrMask);
}
Ejemplo n.º 6
0
static void init_registers(struct net_device *dev)
{
	struct netdev_private *np = (struct netdev_private *)dev->priv;
	long ioaddr = dev->base_addr;
	int i;

	for (i = 0; i < 6; i++)
		writeb(dev->dev_addr[i], ioaddr + StationAddr + i);

	/* Initialize other registers. */
	/* Configure the PCI bus bursts and FIFO thresholds.
	   486: Set 8 longword cache alignment, 8 longword burst.
	   586: Set 16 longword cache alignment, no burst limit.
	   Cache alignment bits 15:14	     Burst length 13:8
		0000	<not allowed> 		0000 align to cache	0800 8 longwords
		4000	8  longwords		0100 1 longword		1000 16 longwords
		8000	16 longwords		0200 2 longwords	2000 32 longwords
		C000	32  longwords		0400 4 longwords
	   Wait the specified 50 PCI cycles after a reset by initializing
	   Tx and Rx queues and the address filter list. */
#if defined(__powerpc__)		/* Big-endian */
	writel(0x00100080 | 0xE010, ioaddr + PCIBusCfg);
#elif defined(__alpha__)
	writel(0xE010, ioaddr + PCIBusCfg);
#elif defined(__i386__)
#if defined(MODULE)
	writel(0xE010, ioaddr + PCIBusCfg);
#else
	/* When not a module we can work around broken '486 PCI boards. */
#define x86 boot_cpu_data.x86
	writel((x86 <= 4 ? 0x4810 : 0xE010), ioaddr + PCIBusCfg);
	if (x86 <= 4)
		printk(KERN_INFO "%s: This is a 386/486 PCI system, setting cache "
			   "alignment to %x.\n", dev->name,
			   (x86 <= 4 ? 0x4810 : 0x8010));
#endif
#else
	writel(0xE010, ioaddr + PCIBusCfg);
#warning Processor architecture undefined!
#endif

	if (dev->if_port == 0)
		dev->if_port = np->default_port;

	/* Fast Ethernet; 128 byte Tx threshold; 
		Transmit on; Receive on; */
	np->csr6 = 0x20022002;
	check_duplex(dev);
	set_rx_mode(dev);
	writel(0, ioaddr + RxStartDemand);

	/* Clear and Enable interrupts by setting the interrupt mask. */
	writel(0x1A0F5, ioaddr + IntrStatus);
	writel(0x1A0F5, ioaddr + IntrEnable);

}
Ejemplo n.º 7
0
static void epic_restart(struct net_device *dev)
{
	long ioaddr = dev->base_addr;
	struct epic_private *ep = dev->priv;
	int i;

	/* Soft reset the chip. */
	outl(0x4001, ioaddr + GENCTL);

	printk(KERN_DEBUG "%s: Restarting the EPIC chip, Rx %d/%d Tx %d/%d.\n",
		   dev->name, ep->cur_rx, ep->dirty_rx, ep->dirty_tx, ep->cur_tx);
	udelay(1);

	/* This magic is documented in SMSC app note 7.15 */
	for (i = 16; i > 0; i--)
		outl(0x0008, ioaddr + TEST1);

#if defined(__powerpc__) || defined(__sparc__)		/* Big endian */
	outl(0x0432 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL);
#else
	outl(0x0412 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL);
#endif
	outl(dev->if_port == 1 ? 0x13 : 0x12, ioaddr + MIICfg);
	if (ep->chip_flags & MII_PWRDWN)
		outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);

	for (i = 0; i < 3; i++)
		outl(cpu_to_le16(((u16*)dev->dev_addr)[i]), ioaddr + LAN0 + i*4);

	ep->tx_threshold = TX_FIFO_THRESH;
	outl(ep->tx_threshold, ioaddr + TxThresh);
	outl(ep->mii.full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl);
	outl(ep->rx_ring_dma + (ep->cur_rx%RX_RING_SIZE)*
		sizeof(struct epic_rx_desc), ioaddr + PRxCDAR);
	outl(ep->tx_ring_dma + (ep->dirty_tx%TX_RING_SIZE)*
		 sizeof(struct epic_tx_desc), ioaddr + PTxCDAR);

	/* Start the chip's Rx process. */
	set_rx_mode(dev);
	outl(StartRx | RxQueued, ioaddr + COMMAND);

	/* Enable interrupts by setting the interrupt mask. */
	outl((ep->chip_flags & TYPE2_INTR ? PCIBusErr175 : PCIBusErr170)
		 | CntFull | TxUnderrun
		 | RxError | RxHeader | EpicNapiEvent, ioaddr + INTMASK);

	printk(KERN_DEBUG "%s: epic_restart() done, cmd status %4.4x, ctl %4.4x"
		   " interrupt %4.4x.\n",
		   dev->name, (int)inl(ioaddr + COMMAND), (int)inl(ioaddr + GENCTL),
		   (int)inl(ioaddr + INTSTAT));
	return;
}
Ejemplo n.º 8
0
static int netdev_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
{
	struct netdev_private *np = netdev_priv(dev);

	spin_lock(&np->lock);
	if (debug > 1)
		printk("%s: removing vlanid %d from vlan filter\n", dev->name, vid);
	clear_bit(vid, np->active_vlans);
	set_rx_mode(dev);
	spin_unlock(&np->lock);

	return 0;
}
Ejemplo n.º 9
0
static void tx_timeout(struct net_device *dev)
{
	struct netdev_private *np = (struct netdev_private *)dev->priv;
	long ioaddr = dev->base_addr;

	printk(KERN_WARNING "%s: Transmit timed out, status %8.8x,"
		   " resetting...\n", dev->name, (int)readl(ioaddr + IntrStatus));

#ifndef __alpha__
	{
		int i;
		printk(KERN_DEBUG "  Rx ring %8.8x: ", (int)np->rx_ring);
		for (i = 0; i < RX_RING_SIZE; i++)
			printk(" %8.8x", (unsigned int)np->rx_ring[i].status);
		printk("\n"KERN_DEBUG"  Tx ring %8.8x: ", (int)np->tx_ring);
		for (i = 0; i < TX_RING_SIZE; i++)
			printk(" %8.8x", np->tx_ring[i].status);
		printk("\n");
	}
	printk(KERN_DEBUG "Tx cur %d Tx dirty %d Tx Full %d, q bytes %d.\n",
				np->cur_tx, np->dirty_tx, np->tx_full,np->tx_q_bytes);
	printk(KERN_DEBUG "Tx Descriptor addr %xh.\n",readl(ioaddr+0x4C));

#endif
	spin_lock_irq(&np->lock);
	/*
	 * Under high load dirty_tx and the internal tx descriptor pointer
	 * come out of sync, thus perform a software reset and reinitialize
	 * everything.
	 */

	writel(1, dev->base_addr+PCIBusCfg);
	udelay(1);

	free_rxtx_rings(np);
	init_rxtx_rings(dev);
	init_registers(dev);
	set_rx_mode(dev);

	spin_unlock_irq(&np->lock);

	netif_wake_queue(dev);
	dev->trans_start = jiffies;
	np->stats.tx_errors++;
	return;
}
Ejemplo n.º 10
0
/**************************************************************************
w89c840_reset - Reset adapter
***************************************************************************/
static void w89c840_reset(struct nic *nic)
{
    int i;

    /* Reset the chip to erase previous misconfiguration.
       No hold time required! */
    writel(0x00000001, ioaddr + PCIBusCfg);

    init_ring();

    writel(virt_to_bus(w840private.rx_ring), ioaddr + RxRingPtr);
    writel(virt_to_bus(w840private.tx_ring), ioaddr + TxRingPtr);

    for (i = 0; i < ETH_ALEN; i++)
        writeb(nic->node_addr[i], ioaddr + StationAddr + i);

    /* Initialize other registers. */
    /* Configure the PCI bus bursts and FIFO thresholds.
       486: Set 8 longword cache alignment, 8 longword burst.
       586: Set 16 longword cache alignment, no burst limit.
       Cache alignment bits 15:14         Burst length 13:8
        0000    <not allowed>         0000 align to cache    0800 8 longwords
        4000    8  longwords        0100 1 longword        1000 16 longwords
        8000    16 longwords        0200 2 longwords    2000 32 longwords
        C000    32  longwords        0400 4 longwords
       Wait the specified 50 PCI cycles after a reset by initializing
       Tx and Rx queues and the address filter list. */

    writel(0xE010, ioaddr + PCIBusCfg);

    writel(0, ioaddr + RxStartDemand);
    w840private.csr6 = 0x20022002;
    check_duplex();
    set_rx_mode();

    /* Do not enable the interrupts Etherboot doesn't need them */
/*
    writel(0x1A0F5, ioaddr + IntrStatus);
    writel(0x1A0F5, ioaddr + IntrEnable);
*/
#if defined(W89C840_DEBUG)
    printf("winbond-840 : Done reset.\n");
#endif
}
Ejemplo n.º 11
0
static int
sis900_open(struct device *net_dev)
{
        struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
        long ioaddr = net_dev->base_addr;

        /* Soft reset the chip. */
	sis900_reset(net_dev);

        if (request_irq(net_dev->irq, &sis900_interrupt, SA_SHIRQ, net_dev->name, net_dev)) {
                return -EAGAIN;
        }

        MOD_INC_USE_COUNT;

	sis900_init_rxfilter(net_dev);

	sis900_init_tx_ring(net_dev);
	sis900_init_rx_ring(net_dev);

        set_rx_mode(net_dev);

        net_dev->tbusy = 0;
        net_dev->interrupt = 0;
        net_dev->start = 1;

        /* Enable all known interrupts by setting the interrupt mask. */
	outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxIDLE), ioaddr + imr);
        outl(RxENA, ioaddr + cr);
        outl(IE, ioaddr + ier);

	sis900_check_mode(net_dev, sis_priv->mii);

        /* Set the timer to switch to check for link beat and perhaps switch
           to an alternate media type. */
        init_timer(&sis_priv->timer);
        sis_priv->timer.expires = jiffies + HZ;
        sis_priv->timer.data = (unsigned long)net_dev;
        sis_priv->timer.function = &sis900_timer;
        add_timer(&sis_priv->timer);

        return 0;
}
Ejemplo n.º 12
0
int can_tx_setup(int baudrate)
{
	mcp2515_reset();

	/* Wait until reset finishes. */
	while (1) {
		if (get_mode() == REQOP_CONFIG) {
			break;
		}
	}

	set_baudrate(baudrate);
	enable_intrrupt();

	enable_rollover();
	set_rx_mode(0, RXM_ANY);
	set_mode(REQOP_NORMAL);

	return 0;
}
Ejemplo n.º 13
0
/* Reset and restore all of the 3c589 registers. */
static void tc589_reset(struct net_device *dev)
{
    unsigned int ioaddr = dev->base_addr;
    int i;

    EL3WINDOW(0);
    outw(0x0001, ioaddr + 4);			/* Activate board. */
    outw(0x3f00, ioaddr + 8);			/* Set the IRQ line. */

    /* Set the station address in window 2. */
    EL3WINDOW(2);
    for (i = 0; i < 6; i++)
	outb(dev->dev_addr[i], ioaddr + i);

    tc589_set_xcvr(dev, dev->if_port);

    /* Switch to the stats window, and clear all stats by reading. */
    outw(StatsDisable, ioaddr + EL3_CMD);
    EL3WINDOW(6);
    for (i = 0; i < 9; i++)
	inb(ioaddr+i);
    inw(ioaddr + 10);
    inw(ioaddr + 12);

    /* Switch to register set 1 for normal use. */
    EL3WINDOW(1);

    set_rx_mode(dev);
    outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
    outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
    outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
    /* Allow status bits to be seen. */
    outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD);
    /* Ack all pending events, and set active indicator mask. */
    outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
	 ioaddr + EL3_CMD);
    outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull
	 | AdapterFailure, ioaddr + EL3_CMD);
}
Ejemplo n.º 14
0
//////////////////////
// tx_send_packet: transmit a data packet
//
//	length: length of raw packet including header
//	pkt:	pointer to packet
//
void tx_send_pkt(pkt_t *pkt, uint8_t length) {

	log_packet('T', pkt, length);

	led_on();
	set_tx_packet_length(length);
	tx_send_payload(0x80 + REG_FIFO, length, (uint8_t *)pkt); 	// Clock out payload

	// Set TXON bit to start the tx cycle
	tx_start();
	led_off(); led_on();	// toggle to note time to here
	tx_packet_count++;

	// wait for the packet transmission to complete
	// per p.81 TXON is "Automatically cleared in FIFO mode once the packet is sent"
	// we spin for about 10ms here...
	while (!rf_interrupt()) {;}
	rf_read_status();

	// TODO: consider a better place to restore
	// this one wastes time going back into rx mode during long prints
	set_rx_mode();
	led_off();
}
Ejemplo n.º 15
0
/////////////////////////////////////
// initialize the radio interface
//
// stick with me, this goes on for a while
// "may you live with interesting radios"
//
void init_radio(void) {

	init_leds();

	// Add Bitlash functions specific to this radio
	//	addBitlashFunction("degf", (bitlash_function) func_degf);
	addBitlashFunction("freq", (bitlash_function) func_setfreq);
	addBitlashFunction("rfget", (bitlash_function) func_rfget);
	addBitlashFunction("rfset", (bitlash_function) func_rfset);


	// Set output mode for outputs
	// TODO: Ensure SS is set to output if L01_CSN moves off SS!
	L01_PORT_DD |= (1<<L01_CE | 1<<L01_CSN | 1<<MOSI | 1<<L01_SCK);

	// Set MISO as an input
	L01_PORT_DD &= ~(1<<MISO);
	L01_PORT &= ~(1<<MISO);		// turn off the internal pullup

	rf_end();		// Set -CSN high to deselect radio

	// Initialize SPI interface to the radio
#if F_CPU == 8000000
	// Enable SPI; be the Master; SPI mode 0; set up for 8/2 prescale for 4 MHz clock
	SPCR = 0<<SPIE | 1<<SPE | 1<<MSTR | 0<<CPOL | 0<<CPHA | 0<<SPR1 | 0<<SPR0;
	SPSR = 1<<SPI2X;		// set 2x mode to make /4 into /2, so 4 MHz

#elif F_CPU == 16000000
	//// Enable SPI; be the Master; SPI mode 0; set up for 16/4 prescale for 4 MHz clock
	SPCR = 0<<SPIE | 1<<SPE | 1<<MSTR | 0<<CPOL | 0<<CPHA | 0<<SPR1 | 0<<SPR0; 
	SPSR = 0<<SPI2X;		// 16 MHz does _not_ need 2X mode

#else
	unsupported F_CPU
#endif

	// clear the status and data registers
	int junk = SPSR; 
	junk = SPDR;

	// For RFM22: set CE low to enable radio  (it's ~STBY)
	rf_enable();

	// Got radio?
	for (;;) {
		rf_set_register(REG_OP_MODE_1, 1<<SWRES);		// Reset the radio
		delay(1000);

		// Verify we have a radio, and it is the right type
		byte device_type = rf_read_register(REG_DEVICE_TYPE);
		byte device_version = rf_read_register(REG_VERSION_CODE);

		//printHex(device_type); speol();
		//printHex(device_version); speol();

		if ((device_type == DEVICE_TYPE_RXTX) &&
			((device_version == DEVICE_RFM22_VER_2) || (device_version == DEVICE_RFM22B))) {
			sp("RFM22 go!"); speol();
			break;
		} else {
			sp("No radio."); speol();
		}
	}

	//
	// Set up radio registers for transmit and receive
	//

	// Disable ENPOR and ENCHIPRDY interrupt sources
	// which are enabled by default
	rf_set_register(REG_INTERRUPT_ENABLE_2, 0);

	//set_ready_mode();

	// Configure GPIO0-1 for tx-rx antenna switching
	rf_set_register(REG_GPIO0_CONFIG, (3<<GPIODRV | 1<<PUP | 0x12));	// GPIO0 is TX-State -> TX-Ant control
	rf_set_register(REG_GPIO1_CONFIG, (3<<GPIODRV | 1<<PUP | 0x15));	// GPIO1 is RX-State -> RX-Ant control

	// Configure GPIO2 for 10MHz system clock output
	rf_set_register(REG_MCLK_OUTPUT, MCLK_10MHZ);

	// Data Access Control setup
	// default for REG_DATA_ACCESS_CONTROL is fine: use the packet engine & crc checks
	//	rf_set_register(REG_DATA_ACCESS_CONTROL, (1<<ENPACRX | 1<<ENPACTX | 1<<ENCRC | CRC_CRC16);

	// Frequency setup
	//
	// For North America, the default frequency band "fb" is 0x15 or 21
	// so 21 * 20 MHz = 420 MHz offset + 480 Mhz base = 900 MHz band
	//
	// the default carrier frequency setting "fc" is 0xBB80 = 48000
	//		48000/64000 = 0.75 * 2 * 10000 = 15000
	// giving 900 + 15 = 915 MHz as default frequency
	//
	// TODO: ignoring frequency offset registers for the moment
	//
	// This is equivalent to the default setting:
	//
	// rf_set_register(REG_FREQUENCY_BAND_SELECT, (1<<SBSEL | 1<<HBSEL | 0x15));
	// rf_set_register(REG_NOMINAL_CARRIER_FREQUENCY_HI, 0xbb);
	// rf_set_register(REG_NOMINAL_CARRIER_FREQUENCY_LO, 0x80);
	// or: rfset(0x75,0x75); rfset(0x76,0xbb); rfset(0x77,0x80)
	//
	// Decoding the example from the sample transmit/receive code for 434 MHz
	// band select low band with offset of 19
	// 240 + 19*10 = 430
	//
	// the remaining 4 mhz is to be found in the r76/77 carrier center freq
	// 	0x6400 = 25600
	// 	25600/64000 = 0.4
	// 	0.4 * 10000 = 4000
	//
	// This is the equivalent code to set 434 MHz using our defines:
	//rf_set_register(REG_FREQUENCY_BAND_SELECT, (1<<SBSEL | 0<<HBSEL | 0x13));
	//rf_set_register(REG_NOMINAL_CARRIER_FREQUENCY_HI, 0x64);
	//rf_set_register(REG_NOMINAL_CARRIER_FREQUENCY_LO, 0x00);
	// or from the console: rfset(0x75,0x53); rfset(0x76,0x64); rfset(0x77,0x00)


	// TX Data Rate Setup
	//
	// this fragment from the example sets up for 4800 bps:
	//	spi_write(0x6e, 0x27); // Tx data rate 1
	//	spi_write(0x6f, 0x52); // Tx data rate 0
	//
	// for HBSEL=1, TX_DR = 1000 * txdr / 2^16
	// for HBSEL=0, TX_DR = 1000 * txdr / 2^21
	//
	// the default on this sample part is 0x0a3d => 39.9938 kbps, call it 40kbps
	//
	// inverting the formula:
	// 		value = (baud/1000)*(2^21)/1000	for baud <  30000
	// 		value = (baud/1000)*(2^16)/1000	for baud >= 30000
	//
	// these values are copied from the file doc/rfm-22-calculations.ods:
	//
	//		baud	divisor	divisor, hex
	//		1200	2516	09D4
	//		2400	5033	13A9
	//		4800	10066	2752
	//		9600	20132	4EA4
	//
	//		40000	2621	0A3D	<-- this is the default 6e/6f setting
	//		57600	3774	0EBE
	//		64000	4194	1062
	//		96000	6291	1893
	//		100000  6553    1999
	//		128000	8388	20C4
	//


// Configure the data rate
//
#define TX_DATA_RATE 40000
//#define TX_DATA_RATE 100000

#if TX_DATA_RATE == 40000

	// 40kbps is the factory setting;
	// take all the defaults but turn on FIFO and FSK
	rf_set_register(REG_MODULATION_MODE_CONTROL_2,
		(0<<TRCLK | MOD_FIFO<<DTMOD | 0<<ENINV | 0<<FD_8 | MOD_FSK<<MODTYP));

#elif  TX_DATA_RATE == 100000

	// Set data rate to 100000 bps
	// NOTE: don't forget to double check the TXDTRTSCALE bit in 0x70 if you set below 30k
	rf_set_register(REG_TX_DATA_RATE_HI, 0x19);
	rf_set_register(REG_TX_DATA_RATE_LO, 0x99);

	// Frequency Deviation setup
	//
	// value in increments of 625 Hz
	// default of 0x20 gives 0x20 = 32 * 625 Hz = 20 KHz
	// example uses 45k/625 = 72
	//

#define TX_DEVIATION 50000

#if TX_DEVIATION == 50000

	// for 100kbps, with deviation at 50 kHz = 50000/625 = 80 = 0x050
	// NOTE: high bit goes in REG_MODULATION_CONTROL_2 as FD_8
	rf_set_register(REG_FREQUENCY_DEVIATION, 0x50);

	// Set up for FIFO io and FSK modulation
	// NOTE: high bit of deviation is here!
	rf_set_register(REG_MODULATION_MODE_CONTROL_2, 
		(0<<TRCLK | MOD_FIFO<<DTMOD | 0<<ENINV | 0<<FD_8 | MOD_FSK<<MODTYP));

	// Set up RX Modem Configuration per Table 16
	//
	// For 100kbps/100kHz settings:
	rf_set_register(REG_IF_FILTER_BANDWIDTH, (1<<DWN3_BYPASS | 0<<NDEC_EXP | 0xf<<FILSET));
	rf_set_register(REG_CLOCK_RECOVERY_OVERSAMPLING_RATE, 0x78);
	rf_set_register(REG_CLOCK_RECOVERY_OFFSET_2, (0<<RXOSR_8_10 | 0<<STALLCTRL | 1<<NCOFF_16_19));
	rf_set_register(REG_CLOCK_RECOVERY_OFFSET_1,(0x11));
	rf_set_register(REG_CLOCK_RECOVERY_OFFSET_0,(0x11));
	rf_set_register(REG_CLOCK_RECOVERY_GAIN_1,(0x04));
	rf_set_register(REG_CLOCK_RECOVERY_GAIN_0,(0x46));

#elif TX_DEVIATION == 300000

	// for 100kbps, set deviation at 300 kHz = 300000/625 = 480 = 0x1e0
	// NOTE: high bit goes in REG_MODULATION_CONTROL_2 as FD_8
	rf_set_register(REG_FREQUENCY_DEVIATION, 0xe0);

	// Set up for FIFO io and FSK modulation
	// NOTE: high bit of deviation is here!
	rf_set_register(REG_MODULATION_MODE_CONTROL_2, 
		(0<<TRCLK | MOD_FIFO<<DTMOD | 0<<ENINV | 1<<FD_8 | MOD_FSK<<MODTYP));

	// Set up RX Modem Configuration per Table 16
	//
	// For 100kbps/300kHz settings:
	rf_set_register(REG_IF_FILTER_BANDWIDTH, (1<<DWN3_BYPASS | 0<<NDEC_EXP | 0xe<<FILSET));
	rf_set_register(REG_CLOCK_RECOVERY_OVERSAMPLING_RATE, 0x78);
	rf_set_register(REG_CLOCK_RECOVERY_OFFSET_2, (0<<RXOSR_8_10 | 0<<STALLCTRL | 1<<NCOFF_16_19));
	rf_set_register(REG_CLOCK_RECOVERY_OFFSET_1,(0x11));
	rf_set_register(REG_CLOCK_RECOVERY_OFFSET_0,(0x11));
	rf_set_register(REG_CLOCK_RECOVERY_GAIN_1,(0x00));
	rf_set_register(REG_CLOCK_RECOVERY_GAIN_0,(0xb8));
#else
	unsupported TX_DEVIATION
#endif

#else
	unsupported TX_DATA_RATE
#endif

	// Header Configuration
	//
	// Enable header checking and broadcast matching on all address bytes
	rf_set_register(REG_HEADER_CONTROL_1, (0xf<<BCEN | 0xf<<HDCH));

	// Set up for 4 byte header, variable packet length, 2 byte sync, 0 for MSB Preamble Length
	// 	(default is 0x22: HDLEN 010 Header 3 and 2; Sync Word 3 and 2)
	//
	rf_set_register(REG_HEADER_CONTROL_2, (4<<HDLEN | 0<<FIXPKLEN | 1<<SYNCLEN | 0<<PREALEN8));

	// Preamble Length
	// the default preamble length is 8 nibbles / 32 bits
	// the sample transmit / receive code provided by HopeRF uses 64 nibbles instead(!)
	// the table on page 43 recommends 40 bits (10 nibbles), so we use that here
	//
	// TODO: test with shorter preamble for performance
	//
	rf_set_register(REG_PREAMBLE_LENGTH, (40/4));

	// Preamble Detect Threshold
	//
	// DOCBUG: possible doc issue regarding preamble threshold:
	// 	rfget(0x35) is 0x20 at bootup; this is 4<<3, not 5<<3 per doc p.106
	//	(not to mention register 0x35 is missing from the summary table)
	// 	4 nibbles is 16 bits, but on page 42 it is recommended to use 20 bits
	// so we set PREATH to 20 bits here; that's 5 nibbles
	//
	rf_set_register(REG_PREAMBLE_DETECTION_CONTROL_1, (20/4)<<PREATH);

	// Sync Pattern and Length
	// we use the default sync pattern of 2dd4 with 2 byte check

	// Enable the radio so rf_set_rx_address is a pass-thru below
	radio_go = 1;		// mark the radio as UP

	// Receive address setup: listen on NOOB, and the broadcast address,
	// until setid() is called to provide an updated address.
	// If setid() was called before now, use the cached value.
	// (Tx address is set up per packet)
	//
	rf_set_rx_address((*nodeid) ? nodeid : (char *) DEFAULT_RX_ADDRESS);

	set_rx_mode();		// engage the receiver and off we go
}
Ejemplo n.º 16
0
static int netdev_open(struct net_device *dev)
{
	struct netdev_private *np = dev->priv;
	long ioaddr = dev->base_addr;
	int i;

	/* Do we need to reset the chip??? */

	i = request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev);
	if (i)
		return i;

	if (debug > 1)
		printk(KERN_DEBUG "%s: netdev_open() irq %d.\n",
			   dev->name, dev->irq);

	init_ring(dev);

	writel(np->rx_ring_dma, ioaddr + RxListPtr);
	/* The Tx list pointer is written as packets are queued. */

	for (i = 0; i < 6; i++)
		writeb(dev->dev_addr[i], ioaddr + StationAddr + i);

	/* Initialize other registers. */
	/* Configure the PCI bus bursts and FIFO thresholds. */

	if (dev->if_port == 0)
		dev->if_port = np->default_port;

	np->mcastlock = (spinlock_t) SPIN_LOCK_UNLOCKED;

	set_rx_mode(dev);
	writew(0, ioaddr + IntrEnable);
	writew(0, ioaddr + DownCounter);
	/* Set the chip to poll every N*320nsec. */
	writeb(100, ioaddr + RxDescPoll);
	writeb(127, ioaddr + TxDescPoll);
	netif_start_queue(dev);

	/* Enable interrupts by setting the interrupt mask. */
	writew(IntrRxDone | IntrRxDMADone | IntrPCIErr | IntrDrvRqst | IntrTxDone
		   | StatsMax | LinkChange, ioaddr + IntrEnable);

	writew(StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl1);

	if (debug > 2)
		printk(KERN_DEBUG "%s: Done netdev_open(), status: Rx %x Tx %x "
			   "MAC Control %x, %4.4x %4.4x.\n",
			   dev->name, readl(ioaddr + RxStatus), readb(ioaddr + TxStatus),
			   readl(ioaddr + MACCtrl0),
			   readw(ioaddr + MACCtrl1), readw(ioaddr + MACCtrl0));

	/* Set the timer to check for link beat. */
	init_timer(&np->timer);
	np->timer.expires = jiffies + 3*HZ;
	np->timer.data = (unsigned long)dev;
	np->timer.function = &netdev_timer;				/* timer handler */
	add_timer(&np->timer);

	return 0;
}
Ejemplo n.º 17
0
static int
rtl8129_open(struct device *dev)
{
	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;
	long ioaddr = dev->base_addr;
	int i;

	/* Soft reset the chip. */
	outb(CmdReset, ioaddr + ChipCmd);

	if (request_irq(dev->irq, &rtl8129_interrupt, SA_SHIRQ, dev->name, dev)) {
		return -EAGAIN;
	}

	MOD_INC_USE_COUNT;

	tp->tx_bufs = kmalloc(TX_BUF_SIZE * NUM_TX_DESC, GFP_KERNEL);
	tp->rx_ring = kmalloc(RX_BUF_LEN + 16, GFP_KERNEL);
	if (tp->tx_bufs == NULL ||  tp->rx_ring == NULL) {
		free_irq(dev->irq, dev);
		if (tp->tx_bufs)
			kfree(tp->tx_bufs);
		if (rtl8129_debug > 0)
			printk(KERN_ERR "%s: Couldn't allocate a %d byte receive ring.\n",
				   dev->name, RX_BUF_LEN);
		return -ENOMEM;
	}
	rtl8129_init_ring(dev);

	/* Check that the chip has finished the reset. */
	for (i = 1000; i > 0; i--)
		if ((inb(ioaddr + ChipCmd) & CmdReset) == 0)
			break;

	for (i = 0; i < 6; i++)
		outb(dev->dev_addr[i], ioaddr + MAC0 + i);

	/* Must enable Tx/Rx before setting transfer thresholds! */
	outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);
	outl((RX_FIFO_THRESH << 13) | (RX_BUF_LEN_IDX << 11) | (RX_DMA_BURST<<8),
		 ioaddr + RxConfig);
	outl((TX_DMA_BURST<<8)|0x03000000, ioaddr + TxConfig);
	tp->tx_flag = (TX_FIFO_THRESH<<11) & 0x003f0000;

	tp->full_duplex = tp->duplex_lock;
	if (tp->phys[0] >= 0  ||  (rtl_cap_tbl[tp->chip_id] & HAS_MII_XCVR)) {
		u16 mii_reg5 = mdio_read(dev, tp->phys[0], 5);
		if (mii_reg5 == 0xffff)
			;					/* Not there */
		else if ((mii_reg5 & 0x0100) == 0x0100
				 || (mii_reg5 & 0x00C0) == 0x0040)
			tp->full_duplex = 1;
		if (rtl8129_debug > 1)
			printk(KERN_INFO"%s: Setting %s%s-duplex based on"
				   " auto-negotiated partner ability %4.4x.\n", dev->name,
				   mii_reg5 == 0 ? "" :
				   (mii_reg5 & 0x0180) ? "100mbps " : "10mbps ",
				   tp->full_duplex ? "full" : "half", mii_reg5);
	}

	outb(0xC0, ioaddr + Cfg9346);
	outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1);
	outb(0x00, ioaddr + Cfg9346);

	outl(virt_to_bus(tp->rx_ring), ioaddr + RxBuf);

	/* Start the chip's Tx and Rx process. */
	outl(0, ioaddr + RxMissed);
	set_rx_mode(dev);

	outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);

	dev->tbusy = 0;
	dev->interrupt = 0;
	dev->start = 1;

	/* Enable all known interrupts by setting the interrupt mask. */
	outw(PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver
		 | TxErr | TxOK | RxErr | RxOK, ioaddr + IntrMask);

	if (rtl8129_debug > 1)
		printk(KERN_DEBUG"%s: rtl8129_open() ioaddr %#lx IRQ %d"
			   " GP Pins %2.2x %s-duplex.\n",
			   dev->name, ioaddr, dev->irq, inb(ioaddr + GPPinData),
			   tp->full_duplex ? "full" : "half");

	/* Set the timer to switch to check for link beat and perhaps switch
	   to an alternate media type. */
	init_timer(&tp->timer);
	tp->timer.expires = RUN_AT((24*HZ)/10);			/* 2.4 sec. */
	tp->timer.data = (unsigned long)dev;
	tp->timer.function = &rtl8129_timer;
	add_timer(&tp->timer);

	return 0;
}
Ejemplo n.º 18
0
static int netdev_open(struct device *dev)
{
	struct netdev_private *np = (struct netdev_private *)dev->priv;
	long ioaddr = dev->base_addr;
	int i;

	/* Reset the chip. */
	writew(CmdReset, ioaddr + ChipCmd);

	if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev))
		return -EAGAIN;

	if (debug > 1)
		printk(KERN_DEBUG "%s: netdev_open() irq %d.\n",
			   dev->name, dev->irq);

	MOD_INC_USE_COUNT;

	init_ring(dev);

	writel(virt_to_bus(np->rx_ring), ioaddr + RxRingPtr);
	writel(virt_to_bus(np->tx_ring), ioaddr + TxRingPtr);

	for (i = 0; i < 6; i++)
		writeb(dev->dev_addr[i], ioaddr + StationAddr + i);

	/* Initialize other registers. */
	writew(0x0006, ioaddr + PCIConfig);	/* Tune configuration??? */
	/* Configure the FIFO thresholds. */
	writeb(0x20, ioaddr + TxConfig);	/* Initial threshold 32 bytes */
	np->tx_thresh = 0x20;
	np->rx_thresh = 0x60;				/* Written in set_rx_mode(). */

	if (dev->if_port == 0)
		dev->if_port = np->default_port;

	dev->tbusy = 0;
	dev->interrupt = 0;
	np->in_interrupt = 0;

	set_rx_mode(dev);

	dev->start = 1;

	/* Enable interrupts by setting the interrupt mask. */
	writew(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow| IntrRxDropped|
		   IntrTxDone | IntrTxAbort | IntrTxUnderrun |
		   IntrPCIErr | IntrStatsMax | IntrLinkChange | IntrMIIChange,
		   ioaddr + IntrEnable);

	np->chip_cmd = CmdStart|CmdTxOn|CmdRxOn|CmdNoTxPoll;
	if (np->duplex_lock)
		np->chip_cmd |= CmdFDuplex;
	writew(np->chip_cmd, ioaddr + ChipCmd);

	check_duplex(dev);

	if (debug > 2)
		printk(KERN_DEBUG "%s: Done netdev_open(), status %4.4x "
			   "MII status: %4.4x.\n",
			   dev->name, readw(ioaddr + ChipCmd),
			   mdio_read(dev, np->phys[0], 1));

	/* Set the timer to check for link beat. */
	init_timer(&np->timer);
	np->timer.expires = RUN_AT(1);
	np->timer.data = (unsigned long)dev;
	np->timer.function = &netdev_timer;				/* timer handler */
	add_timer(&np->timer);

	return 0;
}
Ejemplo n.º 19
0
static int epic_open(struct net_device *dev)
{
	struct epic_private *ep = dev->priv;
	long ioaddr = dev->base_addr;
	int i;
	int retval;

	/* Soft reset the chip. */
	outl(0x4001, ioaddr + GENCTL);

	napi_enable(&ep->napi);
	if ((retval = request_irq(dev->irq, &epic_interrupt, IRQF_SHARED, dev->name, dev))) {
		napi_disable(&ep->napi);
		return retval;
	}

	epic_init_ring(dev);

	outl(0x4000, ioaddr + GENCTL);
	/* This magic is documented in SMSC app note 7.15 */
	for (i = 16; i > 0; i--)
		outl(0x0008, ioaddr + TEST1);

	/* Pull the chip out of low-power mode, enable interrupts, and set for
	   PCI read multiple.  The MIIcfg setting and strange write order are
	   required by the details of which bits are reset and the transceiver
	   wiring on the Ositech CardBus card.
	*/
#if 0
	outl(dev->if_port == 1 ? 0x13 : 0x12, ioaddr + MIICfg);
#endif
	if (ep->chip_flags & MII_PWRDWN)
		outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);

#if defined(__powerpc__) || defined(__sparc__)		/* Big endian */
	outl(0x4432 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL);
	inl(ioaddr + GENCTL);
	outl(0x0432 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL);
#else
	outl(0x4412 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL);
	inl(ioaddr + GENCTL);
	outl(0x0412 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL);
#endif

	udelay(20); /* Looks like EPII needs that if you want reliable RX init. FIXME: pci posting bug? */

	for (i = 0; i < 3; i++)
		outl(cpu_to_le16(((u16*)dev->dev_addr)[i]), ioaddr + LAN0 + i*4);

	ep->tx_threshold = TX_FIFO_THRESH;
	outl(ep->tx_threshold, ioaddr + TxThresh);

	if (media2miictl[dev->if_port & 15]) {
		if (ep->mii_phy_cnt)
			mdio_write(dev, ep->phys[0], MII_BMCR, media2miictl[dev->if_port&15]);
		if (dev->if_port == 1) {
			if (debug > 1)
				printk(KERN_INFO "%s: Using the 10base2 transceiver, MII "
					   "status %4.4x.\n",
					   dev->name, mdio_read(dev, ep->phys[0], MII_BMSR));
		}
	} else {
		int mii_lpa = mdio_read(dev, ep->phys[0], MII_LPA);
		if (mii_lpa != 0xffff) {
			if ((mii_lpa & LPA_100FULL) || (mii_lpa & 0x01C0) == LPA_10FULL)
				ep->mii.full_duplex = 1;
			else if (! (mii_lpa & LPA_LPACK))
				mdio_write(dev, ep->phys[0], MII_BMCR, BMCR_ANENABLE|BMCR_ANRESTART);
			if (debug > 1)
				printk(KERN_INFO "%s: Setting %s-duplex based on MII xcvr %d"
					   " register read of %4.4x.\n", dev->name,
					   ep->mii.full_duplex ? "full" : "half",
					   ep->phys[0], mii_lpa);
		}
	}

	outl(ep->mii.full_duplex ? 0x7F : 0x79, ioaddr + TxCtrl);
	outl(ep->rx_ring_dma, ioaddr + PRxCDAR);
	outl(ep->tx_ring_dma, ioaddr + PTxCDAR);

	/* Start the chip's Rx process. */
	set_rx_mode(dev);
	outl(StartRx | RxQueued, ioaddr + COMMAND);

	netif_start_queue(dev);

	/* Enable interrupts by setting the interrupt mask. */
	outl((ep->chip_flags & TYPE2_INTR ? PCIBusErr175 : PCIBusErr170)
		 | CntFull | TxUnderrun
		 | RxError | RxHeader | EpicNapiEvent, ioaddr + INTMASK);

	if (debug > 1)
		printk(KERN_DEBUG "%s: epic_open() ioaddr %lx IRQ %d status %4.4x "
			   "%s-duplex.\n",
			   dev->name, ioaddr, dev->irq, (int)inl(ioaddr + GENCTL),
			   ep->mii.full_duplex ? "full" : "half");

	/* Set the timer to switch to check for link beat and perhaps switch
	   to an alternate media type. */
	init_timer(&ep->timer);
	ep->timer.expires = jiffies + 3*HZ;
	ep->timer.data = (unsigned long)dev;
	ep->timer.function = &epic_timer;				/* timer handler */
	add_timer(&ep->timer);

	return 0;
}
Ejemplo n.º 20
0
/* The EL3 interrupt handler. */
static irqreturn_t el3_interrupt(int irq, void *dev_id)
{
    struct net_device *dev = (struct net_device *) dev_id;
    struct el3_private *lp = netdev_priv(dev);
    unsigned int ioaddr;
    __u16 status;
    int i = 0, handled = 1;

    if (!netif_device_present(dev))
	return IRQ_NONE;

    ioaddr = dev->base_addr;

    netdev_dbg(dev, "interrupt, status %4.4x.\n", inw(ioaddr + EL3_STATUS));

    spin_lock(&lp->lock);
    while ((status = inw(ioaddr + EL3_STATUS)) &
	(IntLatch | RxComplete | StatsFull)) {
	if ((status & 0xe000) != 0x2000) {
		netdev_dbg(dev, "interrupt from dead card\n");
		handled = 0;
		break;
	}
	if (status & RxComplete)
		el3_rx(dev);
	if (status & TxAvailable) {
		netdev_dbg(dev, "    TX room bit was handled.\n");
		/* There's room in the FIFO for a full-sized packet. */
		outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
		netif_wake_queue(dev);
	}
	if (status & TxComplete)
		pop_tx_status(dev);
	if (status & (AdapterFailure | RxEarly | StatsFull)) {
	    /* Handle all uncommon interrupts. */
	    if (status & StatsFull)		/* Empty statistics. */
		update_stats(dev);
	    if (status & RxEarly) {		/* Rx early is unused. */
		el3_rx(dev);
		outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
	    }
	    if (status & AdapterFailure) {
		u16 fifo_diag;
		EL3WINDOW(4);
		fifo_diag = inw(ioaddr + 4);
		EL3WINDOW(1);
		netdev_warn(dev, "adapter failure, FIFO diagnostic register %04x.\n",
			    fifo_diag);
		if (fifo_diag & 0x0400) {
		    /* Tx overrun */
		    tc589_wait_for_completion(dev, TxReset);
		    outw(TxEnable, ioaddr + EL3_CMD);
		}
		if (fifo_diag & 0x2000) {
		    /* Rx underrun */
		    tc589_wait_for_completion(dev, RxReset);
		    set_rx_mode(dev);
		    outw(RxEnable, ioaddr + EL3_CMD);
		}
		outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD);
	    }
	}
	if (++i > 10) {
		netdev_err(dev, "infinite loop in interrupt, status %4.4x.\n",
			   status);
		/* Clear all interrupts */
		outw(AckIntr | 0xFF, ioaddr + EL3_CMD);
		break;
	}
	/* Acknowledge the IRQ. */
	outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
    }
    lp->last_irq = jiffies;
    spin_unlock(&lp->lock);
    netdev_dbg(dev, "exiting interrupt, status %4.4x.\n",
	       inw(ioaddr + EL3_STATUS));
    return IRQ_RETVAL(handled);
}
Ejemplo n.º 21
0
static void handle_8139 (pci_device_info_type *device_info)
{
  unsigned int counter;
  u16 port_base = MAX_U16;
  u16 ports = 0;
  realtek_device_type *device;
  unsigned int physical, physical_index;
  ipc_structure_type ipc_structure;

  system_thread_name_set ("Initialising");
  
  for (counter = 0; counter < PCI_NUMBER_OF_RESOURCES; counter++)
  {
    if ((device_info->resource[counter].flags & PCI_RESOURCE_IO) != 0)
    {
      port_base = device_info->resource[counter].start;
      ports = (device_info->resource[counter].end -
               device_info->resource[counter].start + 1);
    }
  }

  if (port_base == MAX_U16)
  {
    log_print_formatted (&log_structure, LOG_URGENCY_ERROR, 
                         "No port range found -- hardware possibly broken or incompatible?");
    return;
  }

  system_call_port_range_register (port_base, ports, "Realtek 8139");

  memory_allocate ((void **) &device, sizeof (realtek_device_type));

  device->port_base = port_base;
  device->irq = device_info->irq;

  /* Initialise the adapter. */

  system_port_out_u8 (port_base + Config1, 0x00);
  
  if (read_eeprom (port_base, 0) != 0xFFFF) 
  {
    for (counter = 0; counter < 3; counter++) 
    {
      ((u16 *)(device->ethernet_address))[counter] =
        system_little_endian_to_native_u16 (read_eeprom (port_base, 
                                                        counter + 7));
    }
  }
  else 
  {
    for (counter = 0; counter < 6; counter++)
    {
      device->ethernet_address[counter] = 
        system_port_in_u8 (port_base + MAC0 + counter);
    }
  }

  log_print_formatted 
    (&log_structure, LOG_URGENCY_INFORMATIVE,
     "Realtek 8139 at 0x%X, IRQ %d, ethernet address: %02X:%02X:%02X:%02X:%02X:%02X",
     port_base, device_info->irq, device->ethernet_address[0], 
     device->ethernet_address[1], device->ethernet_address[2], 
     device->ethernet_address[3], device->ethernet_address[4],
     device->ethernet_address[5]);

  /* Find the connected MII transceivers. */

  for (physical = 0, physical_index = 0; physical < 32 &&
         physical_index < sizeof (device->mii_address); physical++)
  {
    int mii_status = mdio_read (port_base, physical, 1);

    if (mii_status != 0xFFFF && mii_status != 0x0000) 
    {
      device->mii_address[physical_index] = physical;
      physical_index++;

      log_print_formatted (&log_structure, LOG_URGENCY_INFORMATIVE,
                           "MII transceiver found at address %d.",
                           physical);
    }
  }

  if (physical_index == 0) 
  {
    if (realtek_debug > 1)
    {
      log_print_formatted (&log_structure, LOG_URGENCY_INFORMATIVE,
                           "No MII transceivers found! Assuming SYM "
                           "transceiver.");
    }

    device->mii_address[0] = -1;
  }

  /* Soft reset the chip. */

  system_port_out_u8 (port_base + ChipCommand, CommandReset);

  pci_allocate_buffer ((void **) &device->tx_buffers_dma,
                       (void **) &device->tx_buffers,
                       TX_BUFFER_SIZE * NUMBER_OF_TX_DESCRIPTORS);
  pci_allocate_buffer ((void **) &device->rx_ring_dma,
                       (void **) &device->rx_ring,
                       RX_BUFFER_LENGTH + 16);

  device->tx_full = FALSE;
  device->current_rx = 0;
  device->dirty_tx = device->current_tx = 0;

  for (counter = 0; counter < NUMBER_OF_TX_DESCRIPTORS; counter++) 
  {
    device->tx_buffer[counter] = &device->tx_buffers[counter * TX_BUFFER_SIZE];
  }
  
  /* Check that the chip has finished the reset. */

  for (counter = 0; counter < 1000; counter++)
  {
    if ((system_port_in_u8 (port_base + ChipCommand) & CommandReset) == 0)
    {
      break;
    }
  }

  /* Must enable Tx/Rx before setting transfer thresholds! */

  system_port_out_u8 (port_base + ChipCommand, 
                      CommandRxEnable | CommandTxEnable);
  system_port_out_u32 (port_base + RxConfig, 
                       (RX_FIFO_THRESHOLD << 13) | 
                       (RX_BUFFER_LENGTH_INDEX << 11) | 
                       (RX_DMA_BURST << 8));

  system_port_out_u32 (port_base + TxConfig, (TX_DMA_BURST << 8) | 0x03000000);

  if (device->mii_address[0] >= 0) 
  {
    u16 mii_reg5 = mdio_read (port_base, device->mii_address[0], 5);

    if (mii_reg5 == 0xffff)
    {
    }
    else if ((mii_reg5 & 0x0100) == 0x0100 || (mii_reg5 & 0x00C0) == 0x0040)
    {
      device->full_duplex = TRUE;
    }

    log_print_formatted (&log_structure, LOG_URGENCY_INFORMATIVE,
                         "Setting %s%s-duplex based on"
                         " auto-negotiated partner ability %4.4x.\n",
                         mii_reg5 == 0 ? "" :
                         ((mii_reg5 & 0x0180) != 0) ? "100 Mbps " : 
                         "10 Mbps ",
                         device->full_duplex ? "full" : "half", mii_reg5);
  }
  
  system_port_out_u8 (port_base + Config9346, 0xC0);
  system_port_out_u8 (port_base + Config1, device->full_duplex ? 0x60 : 0x20);
  system_port_out_u8 (port_base + Config9346, 0x00);

  system_port_out_u32 (port_base + RxBuffer, (u32) device->rx_ring_dma);
  
  /* Start the chip's Tx and Rx process. */
  
  system_port_out_u32 (port_base + RxMissed, 0);
  set_rx_mode (device);
  
  system_port_out_u8 (port_base + ChipCommand,
                      CommandRxEnable | CommandTxEnable);
  
  /* Enable all known interrupts by setting the interrupt mask. */
  
  system_port_out_u16 (port_base + InterruptMask,
                       PCIError | PCSTimeout | RxUnderrun | RxOverflow | 
                       RxFIFOOverrun | TxError | TxOK | RxError | RxOK);


  if (system_thread_create () == SYSTEM_RETURN_THREAD_NEW)
  {
    system_thread_name_set ("IRQ handler");

    if (system_call_irq_register (device_info->irq, "Realtek 8139") != 
        SYSTEM_RETURN_SUCCESS)
    {
      log_print_formatted (&log_structure, LOG_URGENCY_EMERGENCY, 
                           "Couldn't set up IRQ handler");
      return;
    }

    /* Loop and handle interrupts. */
    
    while (TRUE)
    {
      int bogus_count = max_interrupt_work;
      unsigned status, link_changed = 0;
      
      system_call_irq_wait (device->irq);
      
      do 
      {
        status = system_port_in_u16 (port_base + InterruptStatus);
        
        /* Acknowledge all of the current interrupt sources ASAP, but
           an first get an additional status bit from CSCR. */
        
        if ((status & RxUnderrun) && 
            system_port_in_u16 (port_base + CSCR) & CSCR_LinkChangeBit)
        {
          link_changed = 1;
        }
        
        system_port_out_u16 (port_base + InterruptStatus, status);
        
        if ((status & (PCIError | PCSTimeout | RxUnderrun | RxOverflow | 
                       RxFIFOOverrun | TxError | TxOK | RxError | RxOK)) == 0)
        {
          break;
        }
        
        /* Rx interrupt. */
        
        if ((status & (RxOK | RxUnderrun | RxOverflow | RxFIFOOverrun)) != 0)
        {
          realtek_receive (device);
        }
        
        if ((status & (TxOK | TxError)) != 0) 
        {
          unsigned int dirty_tx = device->dirty_tx;
          
          while (device->current_tx - dirty_tx > 0) 
          {
            int entry = dirty_tx % NUMBER_OF_TX_DESCRIPTORS;
            int txstatus = system_port_in_u32 (port_base + TxStatus0 +
                                               entry * 4);
            
            if ((txstatus & (TxStatusOK | TxUnderrun | TxAborted)) == 0)
            {
              /* It still hasn't been transmitted. */
              
              break;
            }
            
            /* Note: TxCarrierLost is always asserted at 100 Mbps. */
            
            if ((txstatus & (TxOutOfWindow | TxAborted)) != 0)
            {
              /* There was an major error, log it. */
              
              // device->stats.tx_errors++;

              if ((txstatus & TxAborted) != 0)
              {
                // tp->stats.tx_aborted_errors++;

                system_port_out_u32 (port_base + TxConfig, 
                                     (TX_DMA_BURST << 8) | 0x03000001);
              }
              
              if ((txstatus & TxCarrierLost) != 0)
              {
                // tp->stats.tx_carrier_errors++;
              }
              
              if ((txstatus & TxOutOfWindow) != 0)
              {
                // tp->stats.tx_window_errors++;
              }
            }
            else 
            {
              if ((txstatus & TxUnderrun) != 0)
              {
                /* Add 64 to the Tx FIFO threshold. */
                
                if (device->tx_flag < 0x00300000)
                {
                  device->tx_flag += 0x00020000;
                }
                
                // tp->stats.tx_fifo_errors++;
              }
              
              // tp->stats.collisions += (txstatus >> 24) & 15;
              // tp->stats.tx_bytes += txstatus & 0x7ff;
              // tp->stats.tx_packets++;
            }
            
            // if (tp->tx_info[entry].mapping != 0)
            // {
            //   pci_unmap_single (tp->pdev,
            //                     tp->tx_info[entry].mapping,
            //                     tp->tx_info[entry].skb->len,
            //                     PCI_DMA_TODEVICE);
            // tp->tx_info[entry].mapping = 0;
            // }
          
            /* Free the original skb. */
            
            // dev_kfree_skb_irq (tp->tx_info[entry].skb);
            //          tp->tx_info[entry].skb = NULL;
            
            if (device->tx_full) 
            {
              /* The ring is no longer full, wake the queue. */
              
              device->tx_full = FALSE;
              
              // netif_wake_queue(dev);
            }
            
            dirty_tx++;
          }
          
          device->dirty_tx = dirty_tx;
        }
        
        /* Check uncommon events with one test. */
        
        if ((status & (PCIError | PCSTimeout | RxUnderrun | RxOverflow | 
                       RxFIFOOverrun | TxError | RxError)) != 0)
        {
          if (realtek_debug > 2)
          {
            log_print_formatted (&log_structure, LOG_URGENCY_WARNING,
                                 "Abnormal interrupt, status %8.8x.\n",
                                 status);
          }
          
          if (status == 0xFFFFFFFF)
          {
            break;
          }
          
          /* Update the error count. */
          
          // tp->stats.rx_missed_errors += inl(port_base + RxMissed);
          system_port_out_u32 (port_base + RxMissed, 0);
          
          if ((status & RxUnderrun) != 0 && link_changed)
          {
            /* Really link-change on new chips. */
            
            int lpar = system_port_in_u16 (port_base + NWayLPAR);
            int duplex = (lpar & 0x0100) || (lpar & 0x01C0) == 0x0040; 
            
            if (device->full_duplex != duplex) 
            {
              device->full_duplex = duplex;
              
              system_port_out_u8 (port_base + Config9346, 0xC0);
              system_port_out_u8 (port_base + Config1, 
                                  device->full_duplex ? 0x60 : 0x20);
              system_port_out_u8 (port_base + Config9346, 0x00);
            }
            status &= ~RxUnderrun;
          }
          
          if ((status & (RxUnderrun | RxOverflow | RxError |
                         RxFIFOOverrun)) != 0)
          {
            // tp->stats.rx_errors++;
          }
          
          if ((status & (PCSTimeout)) != 0)
          {
            // tp->stats.rx_length_errors++;
          }
          
          if ((status & (RxUnderrun | RxFIFOOverrun)) != 0)
          {
            //  tp->stats.rx_fifo_errors++;
          }
          
          if ((status & RxOverflow) != 0)
          {
            // tp->stats.rx_over_errors++;
            device->current_rx =
              (system_port_in_u16 (port_base + RxBufferAddress) % 
               RX_BUFFER_LENGTH);
            system_port_out_u16 (port_base + RxBufferPointer, device->current_rx - 16);
          }
          
          if ((status & PCIError) != 0) 
          {
            log_print (&log_structure, LOG_URGENCY_WARNING, "PCI Bus error.");
          }
        }
        
        if (--bogus_count < 0) 
        {
          log_print_formatted (&log_structure, LOG_URGENCY_WARNING,
                               "Too much work at interrupt, "
                               "InterruptStatus = 0x%4.4x.",
                               status);
          
          /* Clear all interrupt sources. */
          
          system_port_out_u16 (port_base + InterruptStatus, 0xFFFF);
          break;
        }
      } while (TRUE);
      
      system_call_irq_acknowledge (device->irq);
    }
  }

  /* Now, use the remaining thread for the service handler. */

  system_thread_name_set ("Service handler");

  /* Create the service. */

  if (ipc_service_create ("ethernet", &ipc_structure, &empty_tag) !=
      IPC_RETURN_SUCCESS)
  {
    log_print (&log_structure, LOG_URGENCY_EMERGENCY,
               "Couldn't create ethernet service.");
    return;
  }

  while (TRUE)
  {
    mailbox_id_type reply_mailbox_id;

    ipc_service_connection_wait (&ipc_structure);
    reply_mailbox_id = ipc_structure.output_mailbox_id;

    if (system_thread_create () == SYSTEM_RETURN_THREAD_NEW)
    {
      system_call_thread_name_set ("Handling connection");
      handle_connection (reply_mailbox_id, device);
    }
  }    
}