📄 atarilance.c
字号:
long flags; long *vbr, save_berr; save_flags(flags); cli(); __asm__ __volatile__ ( "movec %/vbr,%0" : "=r" (vbr) : ); save_berr = vbr[2]; __asm__ __volatile__ ( "movel %/sp,%/d1\n\t" "movel #Lberr,%2@\n\t" "moveq #0,%0\n\t" "tstl %3\n\t" "bne 1f\n\t" "moveb %1@,%/d0\n\t" "nop \n\t" "bra 2f\n""1: movew %1@,%/d0\n\t" "nop \n""2: tstl %4\n\t" "beq 2f\n\t" "tstl %3\n\t" "bne 1f\n\t" "clrb %1@\n\t" "nop \n\t" "moveb %/d0,%1@\n\t" "nop \n\t" "bra 2f\n""1: clrw %1@\n\t" "nop \n\t" "movew %/d0,%1@\n\t" "nop \n""2: moveq #1,%0\n""Lberr: movel %/d1,%/sp" : "=&d" (ret) : "a" (regp), "a" (&vbr[2]), "rm" (wordflag), "rm" (writeflag) : "d0", "d1", "memory" ); vbr[2] = save_berr; restore_flags(flags); return( ret );}__initfunc(static unsigned long lance_probe1( struct device *dev, struct lance_addr *init_rec )){ volatile unsigned short *memaddr = (volatile unsigned short *)init_rec->memaddr; volatile unsigned short *ioaddr = (volatile unsigned short *)init_rec->ioaddr; struct lance_private *lp; struct lance_ioreg *IO; int i; static int did_version = 0; unsigned short save1, save2; PROBE_PRINT(( "Probing for Lance card at mem %#lx io %#lx\n", (long)memaddr, (long)ioaddr )); /* Test whether memory readable and writable */ PROBE_PRINT(( "lance_probe1: testing memory to be accessible\n" )); if (!addr_accessible( memaddr, 1, 1 )) goto probe_fail; /* Written values should come back... */ PROBE_PRINT(( "lance_probe1: testing memory to be writable (1)\n" )); save1 = *memaddr; *memaddr = 0x0001; if (*memaddr != 0x0001) goto probe_fail; PROBE_PRINT(( "lance_probe1: testing memory to be writable (2)\n" )); *memaddr = 0x0000; if (*memaddr != 0x0000) goto probe_fail; *memaddr = save1; /* First port should be readable and writable */ PROBE_PRINT(( "lance_probe1: testing ioport to be accessible\n" )); if (!addr_accessible( ioaddr, 1, 1 )) goto probe_fail; /* and written values should be readable */ PROBE_PRINT(( "lance_probe1: testing ioport to be writeable\n" )); save2 = ioaddr[1]; ioaddr[1] = 0x0001; if (ioaddr[1] != 0x0001) goto probe_fail; /* The CSR0_INIT bit should not be readable */ PROBE_PRINT(( "lance_probe1: testing CSR0 register function (1)\n" )); save1 = ioaddr[0]; ioaddr[1] = CSR0; ioaddr[0] = CSR0_INIT | CSR0_STOP; if (ioaddr[0] != CSR0_STOP) { ioaddr[0] = save1; ioaddr[1] = save2; goto probe_fail; } PROBE_PRINT(( "lance_probe1: testing CSR0 register function (2)\n" )); ioaddr[0] = CSR0_STOP; if (ioaddr[0] != CSR0_STOP) { ioaddr[0] = save1; ioaddr[1] = save2; goto probe_fail; } /* Now ok... */ PROBE_PRINT(( "lance_probe1: Lance card detected\n" )); goto probe_ok; probe_fail: return( 0 ); probe_ok: init_etherdev( dev, sizeof(struct lance_private) ); if (!dev->priv) dev->priv = kmalloc( sizeof(struct lance_private), GFP_KERNEL ); lp = (struct lance_private *)dev->priv; MEM = (struct lance_memory *)memaddr; IO = lp->iobase = (struct lance_ioreg *)ioaddr; dev->base_addr = (unsigned long)ioaddr; /* informational only */ lp->memcpy_f = init_rec->slow_flag ? slow_memcpy : memcpy; REGA( CSR0 ) = CSR0_STOP; /* Now test for type: If the eeprom I/O port is readable, it is a * PAM card */ if (addr_accessible( &(IO->eeprom), 0, 0 )) { /* Switch back to Ram */ i = IO->mem; lp->cardtype = PAM_CARD; } else if (*RIEBL_MAGIC_ADDR == RIEBL_MAGIC) { lp->cardtype = NEW_RIEBL; } else lp->cardtype = OLD_RIEBL; if (lp->cardtype == PAM_CARD || memaddr == (unsigned short *)0xffe00000) { /* PAMs card and Riebl on ST use level 5 autovector */ request_irq(IRQ_AUTO_5, lance_interrupt, IRQ_TYPE_PRIO, "PAM/Riebl-ST Ethernet", dev); dev->irq = (unsigned short)IRQ_AUTO_5; } else { /* For VME-RieblCards, request a free VME int; * (This must be unsigned long, since dev->irq is short and the * IRQ_MACHSPEC bit would be cut off...) */ unsigned long irq = atari_register_vme_int(); if (!irq) { printk( "Lance: request for VME interrupt failed\n" ); return( 0 ); } request_irq(irq, lance_interrupt, IRQ_TYPE_PRIO, "Riebl-VME Ethernet", dev); dev->irq = irq; } printk("%s: %s at io %#lx, mem %#lx, irq %d%s, hwaddr ", dev->name, lance_names[lp->cardtype], (unsigned long)ioaddr, (unsigned long)memaddr, dev->irq, init_rec->slow_flag ? " (slow memcpy)" : "" ); /* Get the ethernet address */ switch( lp->cardtype ) { case OLD_RIEBL: /* No ethernet address! (Set some default address) */ memcpy( dev->dev_addr, OldRieblDefHwaddr, 6 ); break; case NEW_RIEBL: lp->memcpy_f( dev->dev_addr, RIEBL_HWADDR_ADDR, 6 ); break; case PAM_CARD: i = IO->eeprom; for( i = 0; i < 6; ++i ) dev->dev_addr[i] = ((((unsigned short *)MEM)[i*2] & 0x0f) << 4) | ((((unsigned short *)MEM)[i*2+1] & 0x0f)); i = IO->mem; break; } for( i = 0; i < 6; ++i ) printk( "%02x%s", dev->dev_addr[i], (i < 5) ? ":" : "\n" ); if (lp->cardtype == OLD_RIEBL) { printk( "%s: Warning: This is a default ethernet address!\n", dev->name ); printk( " Use \"ifconfig hw ether ...\" to set the address.\n" ); } MEM->init.mode = 0x0000; /* Disable Rx and Tx. */ for( i = 0; i < 6; i++ ) MEM->init.hwaddr[i] = dev->dev_addr[i^1]; /* <- 16 bit swap! */ MEM->init.filter[0] = 0x00000000; MEM->init.filter[1] = 0x00000000; MEM->init.rx_ring.adr_lo = offsetof( struct lance_memory, rx_head ); MEM->init.rx_ring.adr_hi = 0; MEM->init.rx_ring.len = RX_RING_LEN_BITS; MEM->init.tx_ring.adr_lo = offsetof( struct lance_memory, tx_head ); MEM->init.tx_ring.adr_hi = 0; MEM->init.tx_ring.len = TX_RING_LEN_BITS; if (lp->cardtype == PAM_CARD) IO->ivec = IRQ_SOURCE_TO_VECTOR(dev->irq); else *RIEBL_IVEC_ADDR = IRQ_SOURCE_TO_VECTOR(dev->irq); if (did_version++ == 0) DPRINTK( 1, ( version )); /* The LANCE-specific entries in the device structure. */ dev->open = &lance_open; dev->hard_start_xmit = &lance_start_xmit; dev->stop = &lance_close; dev->get_stats = &lance_get_stats; dev->set_multicast_list = &set_multicast_list; dev->set_mac_address = &lance_set_mac_address; dev->start = 0; memset( &lp->stats, 0, sizeof(lp->stats) ); return( 1 );}static int lance_open( struct device *dev ){ struct lance_private *lp = (struct lance_private *)dev->priv; struct lance_ioreg *IO = lp->iobase; int i; DPRINTK( 2, ( "%s: lance_open()\n", dev->name )); lance_init_ring(dev); /* Re-initialize the LANCE, and start it when done. */ REGA( CSR3 ) = CSR3_BSWP | (lp->cardtype == PAM_CARD ? CSR3_ACON : 0); REGA( CSR2 ) = 0; REGA( CSR1 ) = 0; REGA( CSR0 ) = CSR0_INIT; /* From now on, AREG is kept to point to CSR0 */ i = 1000000; while (--i > 0) if (DREG & CSR0_IDON) break; if (i < 0 || (DREG & CSR0_ERR)) { DPRINTK( 2, ( "lance_open(): opening %s failed, i=%d, csr0=%04x\n", dev->name, i, DREG )); DREG = CSR0_STOP; return( -EIO ); } DREG = CSR0_IDON; DREG = CSR0_STRT; DREG = CSR0_INEA; dev->tbusy = 0; dev->interrupt = 0; dev->start = 1; DPRINTK( 2, ( "%s: LANCE is open, csr0 %04x\n", dev->name, DREG )); MOD_INC_USE_COUNT; return( 0 );}/* Initialize the LANCE Rx and Tx rings. */static void lance_init_ring( struct device *dev ){ struct lance_private *lp = (struct lance_private *)dev->priv; int i; unsigned offset; lp->lock = 0; lp->tx_full = 0; lp->cur_rx = lp->cur_tx = 0; lp->dirty_tx = 0; offset = offsetof( struct lance_memory, packet_area );/* If the packet buffer at offset 'o' would conflict with the reserved area * of RieblCards, advance it */#define CHECK_OFFSET(o) \ do { \ if (lp->cardtype == OLD_RIEBL || lp->cardtype == NEW_RIEBL) { \ if (((o) < RIEBL_RSVD_START) ? (o)+PKT_BUF_SZ > RIEBL_RSVD_START \ : (o) < RIEBL_RSVD_END) \ (o) = RIEBL_RSVD_END; \ } \ } while(0) for( i = 0; i < TX_RING_SIZE; i++ ) { CHECK_OFFSET(offset); MEM->tx_head[i].base = offset; MEM->tx_head[i].flag = TMD1_OWN_HOST; MEM->tx_head[i].base_hi = 0; MEM->tx_head[i].length = 0; MEM->tx_head[i].misc = 0; offset += PKT_BUF_SZ; } for( i = 0; i < RX_RING_SIZE; i++ ) { CHECK_OFFSET(offset); MEM->rx_head[i].base = offset; MEM->rx_head[i].flag = TMD1_OWN_CHIP; MEM->rx_head[i].base_hi = 0; MEM->rx_head[i].buf_length = -PKT_BUF_SZ; MEM->rx_head[i].msg_length = 0; offset += PKT_BUF_SZ; }}static int lance_start_xmit( struct sk_buff *skb, struct device *dev ){ struct lance_private *lp = (struct lance_private *)dev->priv; struct lance_ioreg *IO = lp->iobase; int entry, len; struct lance_tx_head *head; unsigned long flags; /* Transmitter timeout, serious problems. */ if (dev->tbusy) { int tickssofar = jiffies - dev->trans_start; if (tickssofar < 20) return( 1 ); AREG = CSR0; DPRINTK( 1, ( "%s: transmit timed out, status %04x, resetting.\n", dev->name, DREG )); DREG = CSR0_STOP; /* * Always set BSWP after a STOP as STOP puts it back into * little endian mode. */ REGA( CSR3 ) = CSR3_BSWP | (lp->cardtype == PAM_CARD ? CSR3_ACON : 0); lp->stats.tx_errors++;#ifndef final_version { int i; DPRINTK( 2, ( "Ring data: dirty_tx %d cur_tx %d%s cur_rx %d\n", lp->dirty_tx, lp->cur_tx, lp->tx_full ? " (full)" : "", lp->cur_rx )); for( i = 0 ; i < RX_RING_SIZE; i++ ) DPRINTK( 2, ( "rx #%d: base=%04x blen=%04x mlen=%04x\n", i, MEM->rx_head[i].base, -MEM->rx_head[i].buf_length, MEM->rx_head[i].msg_length )); for( i = 0 ; i < TX_RING_SIZE; i++ ) DPRINTK( 2, ( "tx #%d: base=%04x len=%04x misc=%04x\n", i, MEM->tx_head[i].base, -MEM->tx_head[i].length, MEM->tx_head[i].misc )); }#endif lance_init_ring(dev); REGA( CSR0 ) = CSR0_INEA | CSR0_INIT | CSR0_STRT; dev->tbusy = 0; dev->trans_start = jiffies; return( 0 ); } DPRINTK( 2, ( "%s: lance_start_xmit() called, csr0 %4.4x.\n", dev->name, DREG )); /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ if (test_and_set_bit( 0, (void*)&dev->tbusy ) != 0) { DPRINTK( 0, ( "%s: Transmitter access conflict.\n", dev->name )); return 1; } if (test_and_set_bit( 0, (void*)&lp->lock ) != 0) { DPRINTK( 0, ( "%s: tx queue lock!.\n", dev->name )); /* don't clear dev->tbusy flag. */ return 1; } /* Fill in a Tx ring entry */ if (lance_debug >= 3) { u_char *p; int i; printk( "%s: TX pkt type 0x%04x from ", dev->name, ((u_short *)skb->data)[6]); for( p = &((u_char *)skb->data)[6], i = 0; i < 6; i++ ) printk("%02x%s", *p++, i != 5 ? ":" : "" ); printk(" to "); for( p = (u_char *)skb->data, i = 0; i < 6; i++ ) printk("%02x%s", *p++, i != 5 ? ":" : "" ); printk(" data at 0x%08x len %d\n", (int)skb->data, (int)skb->len ); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -