📄 smc91111.c
字号:
} PRINTK2("%s: smc_probe\n", dev->name); PRINTK("Trying to request region for base addr %x\n", ioaddr); /* Grab the region so that no one else tries to probe our ioports. */ if (!request_region(ioaddr, SMC_IO_EXTENT, dev->name)) return -EBUSY; PRINTK("request_region successful, try to read data from chip:\n"); /* First, see if the high byte is 0x33 */ bank = SMC_inw(ioaddr, BANK_SELECT); PRINTK("bank got %x from SMC_inw\n", bank); if ((bank & 0xFF00) != 0x3300) return -ENODEV; /* The above MIGHT indicate a device, but I need to write to further test this. */ SMC_outw(0x0, ioaddr, BANK_SELECT); bank = SMC_inw(ioaddr, BANK_SELECT); if ((bank & 0xFF00) != 0x3300) { retval = -ENODEV; goto err_out; } /* 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 = SMC_inw(ioaddr, BASE_REG); PRINTK("base_address_register = %x\n",base_address_register); /* go check those pesky isa io addresses >:( */ if ((ioaddr&0x0fff) != (base_address_register >> 3 & 0x3E0)) { printk("%s: ioaddr %x doesn't match configuration (%x)." "Probably not a SMC chip\n", CARDNAME, (ioaddr&0x0fff), 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; } /* 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, REV_REG); if (!chip_ids[(revision_register >> 4) & 0xF]) { /* I don't recognize this chip, so... */ printk ("%s: IO %x: Unrecognized revision register: %x, Contact author. \n", dev->name, ioaddr, revision_register); retval = -ENODEV; goto err_out; } PRINTK("revision_register = %x\n",revision_register); /* 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. */ /* Note also that ChipID's for smc91c110 and 91c111 are * both '9'. ????? [jws] */ 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 ) Some folks don't use the . eeprom, or use it in different ways, so we need a platform specific . mac address initializer: */ smc_init_mac_addr( dev, ioaddr, interface); if (!is_valid_ether_addr(dev->dev_addr)) { if (!is_valid_ether_addr(fallback_mac)) printk("%s: Invalid ethernet MAC address. Please set using " "ifconfig\n", dev->name); else { printk("%s: Unitialized MAC address detected -- using a dummy one\n", dev->name); for (i = 0; i < 6; i++) dev->dev_addr[i] = fallback_mac[i]; /* support for multiple chips */ dev->dev_addr[5] = (ioaddr >> 8) & 0xff; } } /* get the memory information */ SMC_SELECT_BANK(0); memory_info_register = SMC_inw(ioaddr, MIR_REG); memory = memory_info_register & (u16) 0x00ff; memory *= LAN91C111_MEMORY_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 = SMC_inw(ioaddr, REV_REG); 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; } /* now, reset the chip, and put it into a known state */ smc_reset(dev);#if 0 /* . 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(dev); } } if (dev->irq == 0) { printk("%s: Couldn't autodetect your IRQ. Use irq=xx.\n", dev->name); retval = -ENODEV; goto err_out; } /* can't assume this for non-PC architectures, folks */ 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; }#endif /* Initialize the private structure. */ if (dev->priv == NULL) { dev->priv = kmalloc(sizeof (struct smc_local), GFP_KERNEL); if (dev->priv == NULL) { retval = -ENOMEM; goto err_out; } } /* set the private data to zero by default */ memset(dev->priv, 0, sizeof (struct smc_local)); lp = (struct smc_local *) dev->priv; /* Fill in the fields of the device structure with ethernet values. */ ether_setup(dev); /* get extra config data for interface */ lp->dev_dma_phys = smc_config[interface].dma_addr; lp->use_32bit = smc_config[interface].use_32bit;#if 0 GPDR(IRQ_TO_GPIO_2_80(dev->irq)) &= ~GPIO_bit(IRQ_TO_GPIO_2_80(dev->irq)); set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(dev->irq), IRQT_RISING); /* treat a dma addr of zero as no dma */ if( lp->dev_dma_phys) { #if 0 retval = pxa_request_dma(dev->name, DMA_PRIO_LOW, smc_dma_irq, (void *) lp); if (retval < 0) { printk("%s: unable to acquire a DMA channel.\n", dev->name); kfree(dev->priv); dev->priv = NULL; goto err_out; } dev->dma = retval; PRINTK("%s: got dma channel number %d for smc rx\n", __FUNCTION__, dev->dma); PRINTK("%s: using %0#10lx for phys addr for smc device number %d\n", __FUNCTION__, lp->dev_dma_phys, i); #endif }#endif /* Grab the IRQ */ retval = request_irq(IRQ_EINT2, &smc_interrupt, 0, dev->name, dev); if (retval) { printk("%s: unable to get IRQ %d (irqval=%d).\n", dev->name, IRQ_EINT2, retval);#if 0 /*modified by syx*/ if( lp->dev_dma_phys) pxa_free_dma(dev->dma); #endif kfree(dev->priv); dev->priv = NULL; 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->get_stats = smc_query_statistics;#ifdef HAVE_MULTICAST dev->set_multicast_list = &smc_set_multicast_list;#endif /* => Store the ChipRevision and ChipID, to be used in resolving the Odd-Byte * issue in RevB of LAN91C111; Pramod */ SMC_SELECT_BANK(3); revision_register = SMC_inw(ioaddr, REV_REG); lp->ChipID = (revision_register >> 4) & 0xF; lp->ChipRev = revision_register & 0xF; /* now, print out the card info, in a short format.. */ printk("%s: %s(rev:%d) at %#3x IRQ:%d DMA:%d (%s) MEM:%db NOWAIT:%d ", dev->name, version_string, revision_register & 0xF, ioaddr, dev->irq, dev->dma, lp->use_32bit?"32-bit":"16-bit", memory, wait_mode[(int)(dev->name[3]) - 48]); /* . 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]); PRINTK("ChipID: %x, ChipRev: %x, stored in dev->priv at %p\n", lp->ChipID, lp->ChipRev, lp); return 0; err_out: release_region(ioaddr, SMC_IO_EXTENT); return retval;}#if SMC_DEBUG > 2static voidprint_packet(unsigned char *buf, int length){ int i; int remainder; int lines; printk("Packet of length %d \n", length);#if SMC_DEBUG > 3 lines = length / 16; remainder = length % 16; for (i = 0; i < lines; i++) { int cur; for (cur = 0; cur < 8; cur++) { u8 a, b; a = *(buf++); b = *(buf++); printk("%02x%02x ", a, b); } printk("\n"); } for (i = 0; i < remainder / 2; i++) { u8 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 intsmc_open(struct net_device *dev){ struct smc_local *lp = (struct smc_local *) dev->priv; unsigned int ioaddr = dev->base_addr; int i; /* used to set hw ethernet address */ u16 phy_status; u8 phyaddr = lp->phyaddr; PRINTK2("%s:smc_open\n", dev->name); /* in spite of checks earlier, someone may set a bogus mac addr via some other * mechanism. We *really* need to prevent invalid addresses, particularly * 0:0:0:0:0:0 and ff:ff:ff:ff:ff:ff, from hitting the wire, as this wreaks * havoc with some switches. */ if (!is_valid_ether_addr(dev->dev_addr)) { printk(KERN_INFO "%s: Invalid network MAC address for %s encountered.\n", __FUNCTION__,dev->name); return -EINVAL; } // Setup the default Register Modes lp->tcr_cur_mode = TCR_DEFAULT; lp->rcr_cur_mode = RCR_DEFAULT; lp->rpc_cur_mode = RPC_DEFAULT; // Set default parameters (files)#ifdef CONFIG_SYSCTL lp->ctl_swfdup = 0; lp->ctl_ephloop = 0; lp->ctl_miiop = 0; lp->ctl_autoneg = 1; lp->ctl_rfduplx = 1; lp->ctl_rspeed = 100; lp->ctl_afduplx = 0; lp->ctl_aspeed = 100; lp->ctl_lnkfail = 1; lp->ctl_forcol = 0; lp->ctl_filtcar = 0;#endif spin_lock_init(&lp->mmu_lock); /* reset the hardware */ smc_reset(dev); smc_enable(dev); /* Configure the PHY */ smc_phy_configure(dev); /* jws: read status of phy */ phy_status = smc_read_phy_register(ioaddr, phyaddr, PHY_STAT_REG); if ((phy_status & PHY_STAT_REM_FLT) || !(phy_status & PHY_STAT_LINK)) { printk("%s: ERROR: remote fault or cable not connected.\n", __FUNCTION__); return -ENOLINK; } /* 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) { u16 address; address = dev->dev_addr[i + 1] << 8; address |= dev->dev_addr[i]; SMC_outw(address, ioaddr, ADDR0_REG + i); }#ifdef MODULE MOD_INC_USE_COUNT;#endif#ifdef CONFIG_SYSCTL smc_sysctl_register(dev);#endif 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 int smc_get_reg(int bank, unsigned int ioaddr, int reg);static inline void smc_dump_registers( unsigned int ioaddr){ int oldbank = inw( ioaddr + BANK_SELECT); printk("-----smc_dump-----\n"); printk("-----BANK0-----\n"); printk("TCR = %04x\n", smc_get_reg(0, ioaddr, TCR_REG)); printk("EPH = %04x\n", smc_get_reg(0, ioaddr, EPH_STATUS_REG)); printk("RCR = %04x\n", smc_get_reg(0, ioaddr, RCR_REG)); printk("CNT = %04x\n", smc_get_reg(0, ioaddr, COUNTER_REG)); printk("MIR = %04x\n", smc_get_reg(0, ioaddr, MIR_REG)); printk("RPC = %04x\n", smc_get_reg(0, ioaddr, RPC_REG)); printk("-----BANK1-----\n"); printk("CFG = %04x\n", smc_get_reg(1, ioaddr, CONFIG_REG)); printk("BAS = %04x\n", smc_get_reg(1, ioaddr, BASE_REG)); printk("GPR = %04x\n", smc_get_reg(1, ioaddr, GP_REG)); printk("CTL = %04x\n", smc_get_reg(1, ioaddr, CTL_REG)); printk("-----BANK2-----\n"); printk("ARPN= %04x\n", smc_get_reg(2, ioaddr, PN_REG)); printk("RXTX= %04x\n", smc_get_reg(2, ioaddr, RXFIFO_REG)); printk("PTR = %04x\n", smc_get_reg(2, ioaddr, PTR_REG)); printk("ISR = %04x\n", smc_get_reg(2, ioaddr, INT_REG)); printk("-----BANK3-----\n"); printk("REV = %04x\n", smc_get_reg(3, ioaddr, REV_REG)); printk("ERX = %04x\n", smc_get_reg(3, ioaddr, ERCV_REG)); outw( oldbank, ioaddr + BANK_SELECT );}static voidsmc_timeout(struct net_device *dev){ PRINTK3("%s:smc_send_packet\n", dev->name); /* If we get here, some higher level has decided we are broken. There should really be a "kick me" function call instead. */ printk(KERN_INFO "%s: transmit timed out, %s?\n", dev->name, tx_done(dev) ? "IRQ conflict" : "network cable problem"); smc_dump_registers( dev->base_addr);#if 0 /* "kick" the adaptor */ smc_reset(dev); smc_enable(dev); /* Reconfigure the PHY */ smc_phy_configure(dev);#endif ((struct smc_local *) dev->priv)->saved_skb = NULL; netif_wake_queue(dev); dev->trans_start = jiffies; /* clear anything saved */// netif_wake_queue(dev);}/*-------------------------------------------------------------------- . . This is the main routine of the driver, to handle the net_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. . ---------------------------------------------------------------------*/static voidsmc_interrupt(int irq, void *dev_id, struct pt_regs *regs){ struct net_device *dev = dev_id;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -