📄 smc9194.c
字号:
lp->saved_skb = NULL; /* this IS an error, but, i don't want the skb saved */ netif_wake_queue(dev); return 0; } /* either way, a packet is waiting now */ lp->packets_waiting++; /* now, try to allocate the memory */ SMC_SELECT_BANK( 2 ); outw( MC_ALLOC | numPages, ioaddr + MMU_CMD ); /* . Performance Hack . . wait a short amount of time.. if I can send a packet now, I send . it now. Otherwise, I enable an interrupt and wait for one to be . available. . . I could have handled this a slightly different way, by checking to . see if any memory was available in the FREE MEMORY register. However, . either way, I need to generate an allocation, and the allocation works . no matter what, so I saw no point in checking free memory. */ time_out = MEMORY_WAIT_TIME; do { word status; status = inb( ioaddr + INTERRUPT ); if ( status & IM_ALLOC_INT ) { /* acknowledge the interrupt */ outb( IM_ALLOC_INT, ioaddr + INTERRUPT ); break; } } while ( -- time_out ); if ( !time_out ) { /* oh well, wait until the chip finds memory later */ SMC_ENABLE_INT( IM_ALLOC_INT ); PRINTK2((CARDNAME": memory allocation deferred. \n")); /* it's deferred, but I'll handle it later */ return 0; } /* or YES! I can send the packet now.. */ smc_hardware_send_packet(dev); netif_wake_queue(dev); return 0;}/* . Function: smc_hardware_send_packet(struct net_device * ) . Purpose: . This sends the actual packet to the SMC9xxx chip. . . Algorithm: . First, see if a saved_skb is available. . ( this should NOT be called if there is no 'saved_skb' . Now, find the packet number that the chip allocated . Point the data pointers at it in memory . Set the length word in the chip's memory . Dump the packet to chip memory . Check if a last byte is needed ( odd length packet ) . if so, set the control flag right . Tell the card to send it . Enable the transmit interrupt, so I know if it failed . Free the kernel data if I actually sent it.*/static void smc_hardware_send_packet( struct net_device * dev ){ struct smc_local *lp = netdev_priv(dev); byte packet_no; struct sk_buff * skb = lp->saved_skb; word length; unsigned int ioaddr; byte * buf; ioaddr = dev->base_addr; if ( !skb ) { PRINTK((CARDNAME": In XMIT with no packet to send \n")); return; } length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; buf = skb->data; /* If I get here, I _know_ there is a packet slot waiting for me */ packet_no = inb( ioaddr + PNR_ARR + 1 ); if ( packet_no & 0x80 ) { /* or isn't there? BAD CHIP! */ printk(KERN_DEBUG CARDNAME": Memory allocation failed. \n"); dev_kfree_skb_any(skb); lp->saved_skb = NULL; netif_wake_queue(dev); return; } /* we have a packet address, so tell the card to use it */ outb( packet_no, ioaddr + PNR_ARR ); /* point to the beginning of the packet */ outw( PTR_AUTOINC , ioaddr + POINTER ); PRINTK3((CARDNAME": Trying to xmit packet of length %x\n", length ));#if SMC_DEBUG > 2 print_packet( buf, length );#endif /* send the packet length ( +6 for status, length and ctl byte ) and the status word ( set to zeros ) */#ifdef USE_32_BIT outl( (length +6 ) << 16 , ioaddr + DATA_1 );#else outw( 0, ioaddr + DATA_1 ); /* send the packet length ( +6 for status words, length, and ctl*/ outb( (length+6) & 0xFF,ioaddr + DATA_1 ); outb( (length+6) >> 8 , ioaddr + DATA_1 );#endif /* send the actual data . I _think_ it's faster to send the longs first, and then . mop up by sending the last word. It depends heavily . on alignment, at least on the 486. Maybe it would be . a good idea to check which is optimal? But that could take . almost as much time as is saved? */#ifdef USE_32_BIT if ( length & 0x2 ) { outsl(ioaddr + DATA_1, buf, length >> 2 );#if !defined(__H8300H__) && !defined(__H8300S__) outw( *((word *)(buf + (length & 0xFFFFFFFC))),ioaddr +DATA_1);#else ctrl_outw( *((word *)(buf + (length & 0xFFFFFFFC))),ioaddr +DATA_1);#endif } else outsl(ioaddr + DATA_1, buf, length >> 2 );#else outsw(ioaddr + DATA_1 , buf, (length ) >> 1);#endif /* Send the last byte, if there is one. */ if ( (length & 1) == 0 ) { outw( 0, ioaddr + DATA_1 ); } else { outb( buf[length -1 ], ioaddr + DATA_1 ); outb( 0x20, ioaddr + DATA_1); } /* enable the interrupts */ SMC_ENABLE_INT( (IM_TX_INT | IM_TX_EMPTY_INT) ); /* and let the chipset deal with it */ outw( MC_ENQUEUE , ioaddr + MMU_CMD ); PRINTK2((CARDNAME": Sent packet of length %d \n",length)); lp->saved_skb = NULL; dev_kfree_skb_any (skb); dev->trans_start = jiffies; /* we can send another packet */ netif_wake_queue(dev); return;}/*------------------------------------------------------------------------- | | smc_init(int unit) | Input parameters: | dev->base_addr == 0, try to find all possible locations | dev->base_addr == 1, return failure code | dev->base_addr == 2, always allocate space, and return success | dev->base_addr == <anything else> this is the address to check | | Output: | pointer to net_device or ERR_PTR(error) | ---------------------------------------------------------------------------*/static int io;static int irq;static int ifport;struct net_device * __init smc_init(int unit){ struct net_device *dev = alloc_etherdev(sizeof(struct smc_local)); struct devlist *smcdev = smc_devlist; int err = 0; if (!dev) return ERR_PTR(-ENODEV); if (unit >= 0) { sprintf(dev->name, "eth%d", unit); netdev_boot_setup_check(dev); io = dev->base_addr; irq = dev->irq; } if (io > 0x1ff) { /* Check a single specified location. */ err = smc_probe(dev, io); } else if (io != 0) { /* Don't probe at all. */ err = -ENXIO; } else { for (;smcdev->port; smcdev++) { if (smc_probe(dev, smcdev->port) == 0) break; } if (!smcdev->port) err = -ENODEV; } if (err) goto out; err = register_netdev(dev); if (err) goto out1; return dev;out1: free_irq(dev->irq, dev); release_region(dev->base_addr, SMC_IO_EXTENT);out: free_netdev(dev); return ERR_PTR(err);}/*---------------------------------------------------------------------- . 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( int ioaddr ){#ifndef NO_AUTOPROBE int timeout = 20; unsigned long cookie; 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. */ 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 */ outw( MC_ALLOC | 1, ioaddr + MMU_CMD ); /* . Wait until positive that the interrupt has been generated */ while ( timeout ) { byte int_status; int_status = 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 probe_irq_off 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 probe_irq_off fails to report anything. This should fix probe_irq_* problems. */ SMC_DELAY(); SMC_DELAY(); /* and disable all interrupts again */ outb( 0, ioaddr + INT_MASK ); /* 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; DECLARE_MAC_BUF(mac); /* Grab the region so that no one else tries to probe our ioports. */ if (!request_region(ioaddr, SMC_IO_EXTENT, DRV_NAME)) return -EBUSY; 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 = 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 = 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.... */ 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: %s\n", print_mac(mac, dev->dev_addr)); /* 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->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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -