📄 smc9194.c
字号:
* Force byte mode. */ writel(readl(addr + ECSR) | ECSR_IOIS8, addr + ECSR); local_irq_restore(flags); iounmap(addr); /* * Wait for the chip to wake up. */ mdelay(1); /* * Map the real registers. */ addr = ioremap(0x18000000, 8 * 1024); if (!addr) return -ENOMEM; ret = smc_probe(dev, (int)addr); if (ret) iounmap(addr); }#elif defined(CONFIG_SA1100_GRAPHICSCLIENT) || defined(CONFIG_SA1100_GRAPHICSMASTER) if (machine_is_graphicsclient() || machine_is_graphicsmaster()) { int base_addr = ADS_ETHERNET; // Max recovery timing MSC1 &= ~0xFFFF; MSC1 |= 0x8649; ret = smc_probe(dev, base_addr); }#elif defined(CONFIG_SA1100_FLEXANET) if (machine_is_flexanet()) { volatile unsigned *attaddr; int ioaddr; unsigned flags; /* Get the I/O and attribute base addresses * declared in flexanet.h */ ioaddr = FHH_ETH_IOBASE; attaddr = (unsigned *) FHH_ETH_MMBASE; /* Ethernet IRQ setup (GPIO is input, falling edge) */ GPDR &= ~(GPIO_ETH_IRQ); set_GPIO_IRQ_edge( GPIO_ETH_IRQ, GPIO_FALLING_EDGE ); dev->irq = IRQ_GPIO_ETH; local_irq_save(flags); /* first reset, then enable the device. Sequence is critical */ attaddr[ECOR] |= ECOR_RESET; udelay(100); attaddr[ECOR] &= ~ECOR_RESET; attaddr[ECOR] |= ECOR_ENABLE; local_irq_restore(flags); /* force 16-bit mode */ attaddr[ECSR] &= ~ECSR_IOIS8; ret = smc_probe(dev, ioaddr); }#elif defined(CONFIG_ARCH_LUBBOCK) || defined(CONFIG_ARCH_PXA_IDP) if (machine_is_lubbock() || machine_is_pxa_idp()) { int ioaddr = machine_is_lubbock() ? LUBBOCK_ETH_BASE : IDP_ETH_BASE; volatile unsigned *attaddr = (unsigned *) (ioaddr + 0x100000); unsigned flags; /* first reset, then enable the device. Sequence is critical */ local_irq_save(flags); attaddr[ECOR] |= ECOR_RESET; udelay(100); attaddr[ECOR] &= ~ECOR_RESET; attaddr[ECOR] |= ECOR_ENABLE; /* force 16-bit mode */ attaddr[ECSR] &= ~ECSR_IOIS8; mdelay(1); local_irq_restore(flags); dev->irq = LUBBOCK_ETH_IRQ; ret = smc_probe(dev, ioaddr); }#elif defined(CONFIG_ISA) int i; int base_addr = dev->base_addr; SET_MODULE_OWNER(dev); /* try a specific location */ if (base_addr > 0x1ff) return smc_probe(dev, base_addr); else if (base_addr != 0) return -ENXIO; /* check every ethernet address */ for (i = 0; smc_portlist[i]; i++) if (smc_probe(dev, smc_portlist[i]) == 0) return 0; /* couldn't find anything */#endif return ret;}/*---------------------------------------------------------------------- . smc_findirq . . This routine has a simple purpose -- make the SMC chip generate an . interrupt, so an auto-detect routine can detect it, and find the IRQ, ------------------------------------------------------------------------*/int __init smc_findirq(struct net_device *dev){ int timeout = 20; unsigned long cookie; u_int ioaddr = dev->base_addr; /* I have to do a STI() here, because this is called from a routine that does an CLI during this process, making it rather difficult to get interrupts for auto detection */ sti(); cookie = probe_irq_on(); /* * What I try to do here is trigger an ALLOC_INT. This is done * by allocating a small chunk of memory, which will give an interrupt * when done. */ /* enable ALLOCation interrupts ONLY. */ SMC_SELECT_BANK(2); SMC_SET_INT(IM_ALLOC_INT); /* . 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 */ SMC_SET_INT(0); /* 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);}static int __init smc_probe_chip(struct net_device *dev, int ioaddr){ unsigned int temp; /* First, see if the high byte is 0x33 */ temp = smc_inw(ioaddr, BANK_SELECT); if ((temp & 0xFF00) != 0x3300) return -ENODEV; /* The above MIGHT indicate a device, but I need to write to further test this. */ smc_outw(0, ioaddr, BANK_SELECT); temp = smc_inw(ioaddr, BANK_SELECT); if ((temp & 0xFF00) != 0x3300) return -ENODEV;#ifdef CONFIG_ISA /* 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); temp = smc_inw(ioaddr, BASE); if (ioaddr != (temp >> 3 & 0x3E0)) { printk("%s: IOADDR %x doesn't match configuration (%x)." "Probably not a SMC chip\n", dev->name, 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; }#endif return 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!!!! .*/static int __init smc_probe_irq(struct net_device *dev){ if (dev->irq < 2) { int trials; trials = 3; while (trials--) { dev->irq = smc_findirq(dev); 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); return -ENODEV; } /* * Some machines (eg, PCs) need to cannonicalize their IRQs. */ dev->irq = irq_cannonicalize(dev->irq); return 0;}/*---------------------------------------------------------------------- . Function: smc_probe(struct net_device *dev, 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){ struct smc_local *smc; int i, memory, retval; static unsigned version_printed; const char *version_string; /* registers */ word revision_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, dev->name)) return -EBUSY; /* * Do the basic probes. */ retval = smc_probe_chip(dev, ioaddr); if (retval) 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, REVISION); version_string = chip_ids[(revision_register >> 4) & 15]; if (!version_string) { /* 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; } /* 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(KERN_INFO "%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; } if (dev->dev_addr[0] != 0) { /* * Possibly a multicast MAC which is not good. * Some people apparently defined it backwards in the eprom. */ for (i = 0; i < 3; i++) { unsigned char tmp = dev->dev_addr[i]; dev->dev_addr[i] = dev->dev_addr[5-i]; dev->dev_addr[5-i] = tmp; } } if (!is_valid_ether_addr(dev->dev_addr)) printk("%s: Invalid ethernet MAC address. Please set using " "ifconfig\n", dev->name); /* 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); /* now, reset the chip, and put it into a known state */ smc_reset(dev); /* * Ok, now that we have everything in a * sane state, probe for the interrupt. */ retval = smc_probe_irq(dev); if (retval) goto err_out; /* 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; } } smc = dev->priv; /* set the private data to zero by default */ memset(smc, 0, sizeof(struct smc_local)); /* * Get the interface characteristics. * is it using AUI or 10BaseT ? */ switch (dev->if_port) { case IF_PORT_10BASET: smc->port = PORT_TP; break; case IF_PORT_AUI: smc->port = PORT_AUI; break; default: SMC_SELECT_BANK(1); configuration_register = smc_inw(ioaddr, CONFIG); if (configuration_register & CFG_AUI_SELECT) { dev->if_port = IF_PORT_AUI; smc->port = PORT_AUI; } else { dev->if_port = IF_PORT_10BASET; smc->port = PORT_TP; } break; } /* all interfaces are half-duplex by default */ smc->duplex = DUPLEX_HALF; /* now, print out the card info, in a short format.. */ printk("%s: %s (rev %d) at %#3x IRQ:%d INTF:%s MEM:%db ", dev->name, version_string, revision_register & 15, ioaddr, dev->irq, interfaces[smc->port], 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]); /* Fill in the fields of the device structure with ethernet values. */ ether_setup(dev); /* Grab the IRQ */ retval = request_irq(dev->irq, &smc_interrupt, 0, dev->name, dev); if (retval) { printk("%s: unable to get IRQ %d (irqval=%d).\n", dev->name, dev->irq, retval); 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->watchdog_timeo = HZ/20; dev->get_stats = smc_query_statistics; dev->set_multicast_list = smc_set_multicast_list; dev->do_ioctl = smc_ioctl; return 0;err_out: release_region(ioaddr, SMC_IO_EXTENT); return retval;}/* * This is responsible for setting the chip appropriately * for the interface type. This should only be called while * the interface is up and running. */static void smc_set_port(struct net_device *dev){ struct smc_local *smc = dev->priv; u_int ioaddr = dev->base_addr; u_int val; SMC_SELECT_BANK(1); val = smc_inw(ioaddr, CONFIG); switch (smc->port) { case PORT_TP: val &= ~CFG_AUI_SELECT; break; case PORT_AUI: val |= CFG_AUI_SELECT; break; } smc_outw(val, ioaddr, CONFIG); SMC_SELECT_BANK(0); val = smc_inw(ioaddr, TCR); switch (smc->duplex) { case DUPLEX_HALF: val &= ~TCR_FDSE; break; case DUPLEX_FULL: val |= TCR_FDSE; break; } smc_outw(val, ioaddr, TCR);}/* * Open and Initialize the board * * Set up everything, reset the card, etc .. * */static int smc_open(struct net_device *dev){ struct smc_local *smc = dev->priv; u_int ioaddr = dev->base_addr; int i; /* * Check that the address is valid. If its not, refuse * to bring the device up. The user must specify an * address using ifconfig eth0 hw ether xx:xx:xx:xx:xx:xx */ if (!is_valid_ether_addr(dev->dev_addr)) return -EINVAL; /* clear out all the junk that was put here before... */ smc->saved_skb = NULL; smc->packets_waiting = 0; /* reset the hardware */ smc_reset(dev); smc_enable(dev); /* Select which interface to use */ smc_set_port(dev); /* 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]; smc_outw(address, ioaddr, ADDR0 + i); } netif_start_queue(dev); return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -