📄 smc9194.c
字号:
* when done. */ SMC_SELECT_BANK(2); /* enable ALLOCation interrupts ONLY */ outb( IM_ALLOC_INT, ioaddr + INT_MASK ); /* . Allocate 512 bytes of memory. Note that the chip was just . reset so all the memory is available */ smc_outw(MC_ALLOC | 1, ioaddr, MMU_CMD); /* . Wait until positive that the interrupt has been generated */ while (timeout) { byte int_status; int_status = smc_inb(ioaddr, INTERRUPT); if (int_status & IM_ALLOC_INT) break; /* got the interrupt */ timeout--; } /* there is really nothing that I can do here if timeout fails, as autoirq_report will return a 0 anyway, which is what I want in this case. Plus, the clean up is needed in both cases. */ /* DELAY HERE! On a fast machine, the status might change before the interrupt is given to the processor. This means that the interrupt was never detected, and autoirq_report fails to report anything. This should fix autoirq_* problems. */ SMC_DELAY(); SMC_DELAY(); /* and disable all interrupts again */ outb( 0, ioaddr + INT_MASK ); /* clear hardware interrupts again, because that's how it was when I was called... */ cli(); /* and return what I found */ return probe_irq_off(cookie);#else /* NO_AUTOPROBE */ struct devlist *smcdev; for (smcdev = smc_devlist; smcdev->port; smcdev++) { if (smcdev->port == ioaddr) return smcdev->irq; } return 0;#endif}/*---------------------------------------------------------------------- . Function: smc_probe( int ioaddr ) . . Purpose: . Tests to see if a given ioaddr points to an SMC9xxx chip. . Returns a 0 on success . . Algorithm: . (1) see if the high byte of BANK_SELECT is 0x33 . (2) compare the ioaddr with the base register's address . (3) see if I recognize the chip ID in the appropriate register . .--------------------------------------------------------------------- *//*--------------------------------------------------------------- . Here I do typical initialization tasks. . . o Initialize the structure if needed . o print out my vanity message if not done so already . o print out what type of hardware is detected . o print out the ethernet address . o find the IRQ . o set up my private data . o configure the dev structure with my subroutines . o actually GRAB the irq. . o GRAB the region .-----------------------------------------------------------------*/static int __init smc_probe(struct net_device *dev, int ioaddr){ int i, memory, retval; static unsigned version_printed; unsigned int bank; const char *version_string; const char *if_string; /* registers */ word revision_register; word base_address_register; word configuration_register; word memory_info_register; word memory_cfg_register; /* Grab the region so that no one else tries to probe our ioports. */ if (!request_region(ioaddr, SMC_IO_EXTENT, DRV_NAME)) dev->irq = irq; dev->if_port = ifport; /* First, see if the high byte is 0x33 */ bank = inw( ioaddr + BANK_SELECT ); if ( (bank & 0xFF00) != 0x3300 ) { retval = -ENODEV; goto err_out; } /* The above MIGHT indicate a device, but I need to write to further test this. */ outw( 0x0, ioaddr + BANK_SELECT ); bank = inw( ioaddr + BANK_SELECT ); if ( (bank & 0xFF00 ) != 0x3300 ) { retval = -ENODEV; goto err_out; }#if !defined(CONFIG_H8S_EDOSK2674) /* well, we've already written once, so hopefully another time won't hurt. This time, I need to switch the bank register to bank 1, so I can access the base address register */ SMC_SELECT_BANK(1); base_address_register = inw( ioaddr + BASE ); if ( ioaddr != ( base_address_register >> 3 & 0x3E0 ) ) { printk(CARDNAME ": IOADDR %x doesn't match configuration (%x)." "Probably not a SMC chip\n", ioaddr, base_address_register >> 3 & 0x3E0 ); /* well, the base address register didn't match. Must not have been a SMC chip after all. */ retval = -ENODEV; goto err_out; }#else (void)base_address_register; /* Warning suppression */#endif /* check if the revision register is something that I recognize. These might need to be added to later, as future revisions could be added. */ SMC_SELECT_BANK(3); revision_register = smc_inw(ioaddr, REVISION); if ( !chip_ids[ ( revision_register >> 4 ) & 0xF ] ) { /* I don't recognize this chip, so... */ printk(CARDNAME ": IO %x: Unrecognized revision register:" " %x, Contact author. \n", ioaddr, revision_register ); retval = -ENODEV; goto err_out; } /* at this point I'll assume that the chip is an SMC9xxx. It might be prudent to check a listing of MAC addresses against the hardware address, or do some other tests. */ if (version_printed++ == 0) printk("%s", version); /* fill in some of the fields */ dev->base_addr = ioaddr; /* . Get the MAC address (bank 1, regs 4 - 9) */ SMC_SELECT_BANK(1); for (i = 0; i < 6; i += 2) { word address; address = smc_inw(ioaddr, ADDR0 + i); dev->dev_addr[i + 1] = address >> 8; dev->dev_addr[i] = address & 0xFF; } /* get the memory information */ SMC_SELECT_BANK(0); memory_info_register = smc_inw(ioaddr, MIR); memory_cfg_register = smc_inw(ioaddr, MCR); memory = (memory_cfg_register >> 9) & 0x7; /* multiplier */ memory *= 256 * (memory_info_register & 0xFF); memory = ( memory_cfg_register >> 9 ) & 0x7; /* multiplier */ /* Now, I want to find out more about the chip. This is sort of redundant, but it's cleaner to have it in both, rather than having one VERY long probe procedure. */ SMC_SELECT_BANK(3); revision_register = inw( ioaddr + REVISION ); version_string = chip_ids[ ( revision_register >> 4 ) & 0xF ]; if ( !version_string ) { /* I shouldn't get here because this call was done before.... */ retval = -ENODEV; goto err_out; } /* is it using AUI or 10BaseT ? */ if ( dev->if_port == 0 ) { SMC_SELECT_BANK(1); configuration_register = inw( ioaddr + CONFIG ); if ( configuration_register & CFG_AUI_SELECT ) dev->if_port = 2; else dev->if_port = 1; } if_string = interfaces[ dev->if_port - 1 ]; /* now, reset the chip, and put it into a known state */ smc_reset( ioaddr ); /* . If dev->irq is 0, then the device has to be banged on to see . what the IRQ is. . . This banging doesn't always detect the IRQ, for unknown reasons. . a workaround is to reset the chip and try again. . . Interestingly, the DOS packet driver *SETS* the IRQ on the card to . be what is requested on the command line. I don't do that, mostly . because the card that I have uses a non-standard method of accessing . the IRQs, and because this _should_ work in most configurations. . . Specifying an IRQ is done with the assumption that the user knows . what (s)he is doing. No checking is done!!!! . */ if ( dev->irq < 2 ) { int trials; trials = 3; while ( trials-- ) { dev->irq = smc_findirq( ioaddr ); if ( dev->irq ) break; /* kick the card and try again */ smc_reset( ioaddr ); } } if (dev->irq == 0 ) { printk(CARDNAME": Couldn't autodetect your IRQ. Use irq=xx.\n"); retval = -ENODEV; goto err_out; } /* now, print out the card info, in a short format.. */ printk("%s: %s(r:%d) at %#3x IRQ:%d INTF:%s MEM:%db ", dev->name, version_string, revision_register & 0xF, ioaddr, dev->irq, if_string, memory ); /* . Print the Ethernet address */ printk("ADDR: "); for (i = 0; i < 5; i++) printk("%2.2x:", dev->dev_addr[i] ); printk("%2.2x \n", dev->dev_addr[5] ); /* set the private data to zero by default */ memset(dev->priv, 0, sizeof(struct smc_local)); /* Grab the IRQ */ retval = request_irq(dev->irq, &smc_interrupt, 0, DRV_NAME, dev); if (retval) { printk("%s: unable to get IRQ %d (irqval=%d).\n", DRV_NAME, dev->irq, retval); goto err_out; } dev->open = smc_open; dev->stop = smc_close; dev->hard_start_xmit = smc_wait_to_send_packet; dev->tx_timeout = smc_timeout; dev->watchdog_timeo = HZ/20; dev->get_stats = smc_query_statistics; dev->set_multicast_list = smc_set_multicast_list; return 0;err_out: release_region(ioaddr, SMC_IO_EXTENT); return retval;}#if SMC_DEBUG > 2static void print_packet( byte * buf, int length ){#if 0 int i; int remainder; int lines; printk("Packet of length %d \n", length ); lines = length / 16; remainder = length % 16; for ( i = 0; i < lines ; i ++ ) { int cur; for ( cur = 0; cur < 8; cur ++ ) { byte a, b; a = *(buf ++ ); b = *(buf ++ ); printk("%02x%02x ", a, b ); } printk("\n"); } for ( i = 0; i < remainder/2 ; i++ ) { byte a, b; a = *(buf ++ ); b = *(buf ++ ); printk("%02x%02x ", a, b ); } printk("\n");#endif}#endif/* * Open and Initialize the board * * Set up everything, reset the card, etc .. * */static int smc_open(struct net_device *dev){ int ioaddr = dev->base_addr; int i; /* used to set hw ethernet address */ /* clear out all the junk that was put here before... */ memset(dev->priv, 0, sizeof(struct smc_local)); /* reset the hardware */ smc_reset( ioaddr ); smc_enable( ioaddr ); /* Select which interface to use */ SMC_SELECT_BANK( 1 ); if ( dev->if_port == 1 ) { outw( inw( ioaddr + CONFIG ) & ~CFG_AUI_SELECT, ioaddr + CONFIG ); } else if ( dev->if_port == 2 ) { outw( inw( ioaddr + CONFIG ) | CFG_AUI_SELECT, ioaddr + CONFIG ); } /* According to Becker, I have to set the hardware address at this point, because the (l)user can set it with an ioctl. Easily done... */ address |= dev->dev_addr[ i ]; netif_start_queue(dev); return 0;}/*-------------------------------------------------------- . Called by the kernel to send a packet out into the void . of the net. This routine is largely based on . skeleton.c, from Becker. .--------------------------------------------------------*/static void smc_timeout(struct net_device *dev){ /* If we get here, some higher level has decided we are broken. There should really be a "kick me" function call instead. */ printk(KERN_WARNING CARDNAME": transmit timed out, %s?\n", tx_done(dev) ? "IRQ conflict" : "network cable problem"); /* "kick" the adaptor */ smc_reset( dev->base_addr ); smc_enable( dev->base_addr ); dev->trans_start = jiffies; /* clear anything saved */ ((struct smc_local *)dev->priv)->saved_skb = NULL; netif_wake_queue(dev);}/*------------------------------------------------------------- . . smc_rcv - receive a packet from the card . . There is ( at least ) a packet waiting to be read from . chip-memory. . . o Read the status . o If an error, record it . o otherwise, read in the packet --------------------------------------------------------------*/static void smc_rcv(struct net_device *dev){ struct smc_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; int packet_number; word status; word packet_length; /* assume bank 2 */ packet_number = inw( ioaddr + FIFO_PORTS ); if ( packet_number & FP_RXEMPTY ) { /* we got called , but nothing was on the FIFO */ PRINTK((CARDNAME ": WARNING: smc_rcv with nothing on FIFO. \n")); /* don't need to restore anything */ return; } /* start reading from the start of the packet */ outw( PTR_READ | PTR_RCV | PTR_AUTOINC, ioaddr + POINTER );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -