📄 smc91113.c
字号:
int __init smc_init(struct net_device *dev){ int i; int base_addr = dev ? dev->base_addr : 0; PRINTK2("CARDNAME:smc_init\n"); SET_MODULE_OWNER (dev); smc_cpu_init(); /* try a specific location */ if (base_addr > 0x1ff) return smc_probe(dev, base_addr); else if ( 0 != base_addr ) 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 */ return -ENODEV;}/*------------------------------------------------------------------------- | | smc_destructor( struct device * dev ) | Input parameters: | dev, pointer to the device structure | | Output: | None. | ---------------------------------------------------------------------------*/void smc_destructor(struct net_device *dev){ PRINTK2("CARDNAME:smc_destructor\n");}/*---------------------------------------------------------------------- . Function: smc_probe( int ioaddr ) . . Purpose: . Tests to see if a given ioaddr points to an SMC91113 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 = 0; unsigned int bank; const char *version_string; /*registers */ word revision_register; word base_address_register; word memory_info_register; /*=> Pramod */ struct smc_local *lp; /*<= Pramod */ PRINTK2("CARDNAME:smc_probe\n"); /* Grab the region so that no one else tries to probe our ioports. */ if (!request_region(ioaddr, SMC_IO_EXTENT, dev->name)) return -EBUSY; /* First, see if the high byte is 0x33 */ bank = inw( ioaddr + BANK_SELECT ); /* Qinwei say, high byte will always be 0x33*/ 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 ); /* Qinwei say , switch to bank 0 and test again!*/ bank = 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 = inw( ioaddr + BASE_REG ); /* Qinwei : should get 0x1801 in EV44b0*/ if ( (ioaddr - CONFIG_SMC91113_CS) != ( 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; } /* 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 + REV_REG ); /* Qinwei: must get 0x3391 on EV44b0II*/ 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 ); /*Read the value from Chip, when reset,chip maybe read from eeprom.*/ if (iic_mac(&(dev->dev_addr[0]))) { /* for ( i = 0; i < 6; i += 2 )
{
word address;
address = inw( ioaddr + ADDR0_REG + i );
dev->dev_addr[ i + 1] = address >> 8;
dev->dev_addr[ i ] = address & 0xFF;
}*/
} else { // set default MAC address // Qinwei, can read the MAC from EEprom on reset dev->dev_addr[0] = 0x00; dev->dev_addr[1] = 0x0B; dev->dev_addr[2] = 0x51; dev->dev_addr[3] = 0x00; dev->dev_addr[4] = 0x0F; dev->dev_addr[5] = 0xFF; } for ( i = 0; i < 6; i += 2 ) { word address; address = dev->dev_addr[ i ]; address += dev->dev_addr[ i + 1] << 8; outw( address, ioaddr + ADDR0_REG + i ); } /* Qinwei:get the memory information from chip, as 91c113, should 04*/ SMC_SELECT_BANK( 0 ); memory_info_register = inw( ioaddr + MIR_REG ); memory = memory_info_register & (word)0x00ff; memory *= LAN91C113_MEMORY_MULTIPLIER; /*Qinwei: now we have 8K*/ /* 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 + 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; } /* Qinwei: reset the chip, and put it into a known state */ smc_reset( dev ); /* Qinwei: every thing seems OK, print out the card info, in a short format.. */ printk("%s: %s(rev:%d) at %#3x IRQ:%d MEMSIZE:%db NOWAIT:%d ", dev->name, version_string, revision_register & 0xF, ioaddr, dev->irq, memory, dev->dma); /* Qinwei: Print the Ethernet address */ printk("\n Deafult MAC ADDR: "); for (i = 0; i < 5; i++) printk("%2.2x:", dev->dev_addr[i] ); printk("%2.2x \n", dev->dev_addr[5] ); /* Create 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)); /* Fill in the fields of the device structure with ethernet values. */ ether_setup(dev); /* Grab the IRQ */ disable_irq(dev->irq); /* Qinwei : Disable the interrupt first.*/ retval = request_irq(dev->irq, &smc_interrupt, SA_INTERRUPT, "ether Rx/Tx", 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->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 LAN91C113; Pramod */ SMC_SELECT_BANK(3); revision_register = inw( ioaddr + REV_REG ); lp = (struct smc_local *)dev->priv; lp->ChipID = (revision_register >> 4) & 0xF; lp->ChipRev = revision_register & 0xF; /* Qinwei: for config the PHY on kernel, remove the initial PHY on smc_open */ lp->rpc_cur_mode = RPC_DEFAULT; lp->tcr_cur_mode = TCR_DEFAULT; lp->rcr_cur_mode = RCR_DEFAULT; smc_enable( dev ); smc_phy_configure(dev); return 0;err_out: release_region (ioaddr, SMC_IO_EXTENT); return retval;}#if SMC_DEBUG > 2static void print_packet( byte * buf, int length ){#if 1 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 ++ ) { 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}#endif/* * Open and Initialize the board * * Set up everything, reset the card, etc .. * */static int smc_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 */ PRINTK2("%s:smc_open\n", dev->name); /* clear out all the junk that was put here before... */ /* Qinwei: we already clear it on SMC_probe, and fill some infomation, so mark following line.*/ // memset(dev->priv, 0, sizeof(struct smc_local)); /* Qinwei: Start the transmit queue*/ netif_start_queue(dev); // Setup the default Register Modes lp->tcr_cur_mode = TCR_DEFAULT; lp->rcr_cur_mode = RCR_DEFAULT;#ifdef CONFIG_SYSCTL // Set default parameters (files) 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 = 1; lp->ctl_aspeed = 100; lp->ctl_lnkfail = 1; lp->ctl_forcol = 0; lp->ctl_filtcar = 0;#endif// CONFIG_SYSCTL /* reset the hardware */ /* Qinwei: we already do it on SMC_probe,so can mark following line.*/ // smc_reset( dev ); smc_enable( dev ); /* Configure the PHY *//* lp->rpc_cur_mode = RPC_DEFAULT; smc_phy_configure(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 ]; outw( address, ioaddr + ADDR0_REG + i ); }#ifdef CONFIG_SYSCTL smc_sysctl_register(dev);#endif /* CONFIG_SYSCTL */ netif_start_queue(dev); enable_irq(dev->irq); /* Qinwei; now open the interrupt*/ 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){ 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_WARNING "%s: transmit timed out, %s?\n",dev->name, tx_done(dev) ? "IRQ conflict" :"network cable problem"); /* "kick" the adaptor */ smc_reset( dev ); smc_enable( dev ); /* Reconfigure the PHY */ smc_phy_configure(dev); netif_wake_queue(dev); dev->trans_start = jiffies; /* clear anything saved */ ((struct smc_local *)dev->priv)->saved_skb = NULL; enable_irq(dev->irq); /* Qinwei; now open the interrupt*/}/*-------------------------------------------------------------------- . . 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 void smc_interrupt(int irq, void * dev_id, struct pt_regs * regs){ struct net_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("%s: SMC interrupt started \n", dev->name); if (dev == NULL) { printk(KERN_WARNING "%s: irq %d for unknown device.\n", dev->name, irq); return; }/* will Linux let this happen ?? If not, this costs some speed if ( dev->interrupt ) { printk(KERN_WARNING "%s: interrupt inside interrupt.\n", dev->name); return; } dev->interrupt = 1; */ saved_bank = inw( ioaddr + BANK_SELECT ); SMC_SELECT_BANK(2); saved_pointer = inw( ioaddr + PTR_REG ); /* read the interrupt status register */ mask = inb( ioaddr + IM_REG ); /* disable all interrupts */ outb( 0, ioaddr + IM_REG ); /* set a timeout value, so I don't stay here forever */ timeout = 4; PRINTK2(KERN_WARNING "%s: MASK IS %x \n", dev->name, mask); do { /* read the status flag, and mask it */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -