📄 smc91111.c
字号:
/* send the packet length ( +6 for status words, length, and ctl*/
outb( (length+6) & 0xFF,ioaddr + DATA_REG );
outb( (length+6) >> 8 , ioaddr + DATA_REG );
#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
outsl(ioaddr + DATA_REG, buf, length >> 2 );
if ( length & 0x2 )
outw(*((word *)(buf + (length & 0xFFFFFFFC))),ioaddr +DATA_REG);
#else
outsw(ioaddr + DATA_REG , buf, (length ) >> 1);
#endif // USE_32_BIT
/* Send the last byte, if there is one. */
if ( (length & 1) == 0 ) {
outw( 0, ioaddr + DATA_REG );
} else {
outb( buf[length -1 ], ioaddr + DATA_REG );
outb( 0x20, ioaddr + DATA_REG); // Set odd bit in CONTROL BYTE
}
/* 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_REG );
PRINTK2("%s: Sent packet of length %d \n", dev->name, 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( struct device * dev )
| 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:
| 0 --> there is a device
| anything else, error
|
---------------------------------------------------------------------------
*/
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);
/* 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");
}
#ifndef NO_AUTOPROBE
/*----------------------------------------------------------------------
. 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 )
{
int timeout = 20;
unsigned long cookie;
PRINTK2("CARDNAME:smc_findirq\n");
/* 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.
*/
SMC_SELECT_BANK(2);
/* enable ALLOCation interrupts ONLY */
outb( IM_ALLOC_INT, ioaddr + IM_REG );
/*
. 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_REG );
/*
. Wait until positive that the interrupt has been generated
*/
while ( timeout ) {
byte int_status;
int_status = inb( ioaddr + INT_REG );
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.
*/
mdelay(10);
/* and disable all interrupts again */
outb( 0, ioaddr + IM_REG );
/* 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);
}
#endif
/*----------------------------------------------------------------------
. Function: smc_probe( int ioaddr )
.
. Purpose:
. Tests to see if a given ioaddr points to an SMC91111 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;
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 );
if ( (bank & 0xFF00) != 0x3300 ) 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 )
{
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 );
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;
}
/* 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 );
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_REG + 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_REG );
memory = memory_info_register & (word)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 = 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 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;
}
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("%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);
/*
. 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) {
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);
dev->change_mtu = eth_change_mtu;
/* 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->get_stats = smc_query_statistics;
#ifdef HAVE_MULTICAST
dev->set_multicast_list = &smc_set_multicast_list;
#endif
return 0;
err_out:
release_region (ioaddr, SMC_IO_EXTENT);
return retval;
}
#if SMC_DEBUG > 2
static 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -