📄 smc9194.c
字号:
return -ENODEV; } /* 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 ) { return -ENODEV; } /* 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. */ return -ENODEV; } /* 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 = 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 ); return -ENODEV; } /* 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. */ return 0;}/*--------------------------------------------------------------- . 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 .-----------------------------------------------------------------*/__initfunc(static int smc_initcard(struct device *dev, int ioaddr)){ int i; static unsigned version_printed = 0; /* registers */ word revision_register; word configuration_register; word memory_info_register; word memory_cfg_register; const char * version_string; const char * if_string; int memory; int irqval; /* see if I need to initialize the ethernet card structure */ if (dev == NULL) {#ifdef SUPPORT_OLD_KERNEL#ifndef MODULE/* note: the old module interface does not support this call */ dev = init_etherdev( 0, sizeof( struct smc_local ), 0 );#endif#else dev = init_etherdev(0, 0);#endif if (dev == NULL) return -ENOMEM; } 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 = 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 = inw( ioaddr + MIR ); memory_cfg_register = inw( ioaddr + MCR ); memory = ( memory_cfg_register >> 9 ) & 0x7; /* multiplier */ memory *= 256 * ( memory_info_register & 0xFF ); /* 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.... */ return -ENODEV; } /* 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!!!! . */#ifndef NO_AUTOPROBE 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"); return -ENODEV; }#else if (dev->irq == 0 ) { printk(CARDNAME ": Autoprobing IRQs is not supported for old kernels.\n"); return -ENODEV; }#endif if (dev->irq == 2) { /* Fixup for users that don't know that IRQ 2 is really IRQ 9, * or don't know which one to set. */ dev->irq = 9; } /* now, print out the card info, in a short format.. */ printk(CARDNAME ": %s(r:%d) at %#3x IRQ:%d INTF:%s MEM:%db ", 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] ); /* Initialize the private structure. */ if (dev->priv == NULL) { dev->priv = kmalloc(sizeof(struct smc_local), GFP_KERNEL); if (dev->priv == NULL) return -ENOMEM; } /* set the private data to zero by default */ memset(dev->priv, 0, sizeof(struct smc_local)); /* Fill in the fields of the device structure with ethernet values. */ ether_setup(dev); /* Grab the IRQ */ irqval = request_irq(dev->irq, &smc_interrupt, 0, CARDNAME, dev); if (irqval) { printk(CARDNAME": unable to get IRQ %d (irqval=%d).\n", dev->irq, irqval); return -EAGAIN; } /* Grab the region so that no one else tries to probe our ioports. */ request_region(ioaddr, SMC_IO_EXTENT, CARDNAME); dev->open = smc_open; dev->stop = smc_close; dev->hard_start_xmit = smc_send_packet; dev->get_stats = smc_query_statistics;#ifdef HAVE_MULTICAST dev->set_multicast_list = &smc_set_multicast_list;#endif return 0;}#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 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)); dev->tbusy = 0; dev->interrupt = 0; dev->start = 1;#ifdef MODULE MOD_INC_USE_COUNT;#endif /* 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... */ SMC_SELECT_BANK( 1 ); for ( i = 0; i < 6; i += 2 ) { word address; address = dev->dev_addr[ i + 1 ] << 8 ; address |= dev->dev_addr[ i ]; outw( address, ioaddr + ADDR0 + i ); } 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 int smc_send_packet(struct sk_buff *skb, struct device *dev){ if (dev->tbusy) { /* If we get here, some higher level has decided we are broken. There should really be a "kick me" function call instead. */ int tickssofar = jiffies - dev->trans_start; if (tickssofar < 5) return 1; 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->tbusy = 0; dev->trans_start = jiffies; /* clear anything saved */ ((struct smc_local *)dev->priv)->saved_skb = NULL; } /* 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) { printk(KERN_WARNING CARDNAME": Transmitter access conflict.\n"); dev_kfree_skb (skb); } else { /* Well, I want to send the packet.. but I don't know if I can send it right now... */ return smc_wait_to_send_packet( skb, dev ); } return 0;}/*-------------------------------------------------------------------- . . This is the main routine of the driver, to handle the device when . it needs some attention. . . So: . first, save state of the chipset . branch off into routines to handle each case, and acknowledge . each to the interrupt register . and finally restore state. . ---------------------------------------------------------------------*/#ifdef REALLY_NEW_KERNELstatic void smc_interrupt(int irq, void * dev_id, struct pt_regs * regs)#elsestatic void smc_interrupt(int irq, struct pt_regs * regs)#endif{ struct device *dev = dev_id; int ioaddr = dev->base_addr; struct smc_local *lp = (struct smc_local *)dev->priv; byte status; word card_stats; byte mask; int timeout; /* state registers */ word saved_bank; word saved_pointer; PRINTK3((CARDNAME": SMC interrupt started \n")); if (dev == NULL) { printk(KERN_WARNING CARDNAME": irq %d for unknown device.\n", irq); return; }/* will Linux let this happen ?? If not, this costs some speed */ if ( dev->interrupt ) { printk(KERN_WARNING CARDNAME": interrupt inside interrupt.\n"); return; } dev->interrupt = 1; saved_bank = inw( ioaddr + BANK_SELECT ); SMC_SELECT_BANK(2); saved_pointer = inw( ioaddr + POINTER ); mask = inb( ioaddr + INT_MASK ); /* clear all interrupts */ outb( 0, ioaddr + INT_MASK ); /* set a timeout value, so I don't stay here forever */ timeout = 4; PRINTK2((KERN_WARNING CARDNAME ": MASK IS %x \n", mask )); do { /* read the status flag, and mask it */ status = inb( ioaddr + INTERRUPT ) & mask; if (!status ) break; PRINTK3((KERN_WARNING CARDNAME ": Handling interrupt status %x \n", status )); if (status & IM_RCV_INT) { /* Got a packet(s). */ PRINTK2((KERN_WARNING CARDNAME ": Receive Interrupt\n")); smc_rcv(dev);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -