📄 smc_probe.c
字号:
static int smc_probe()
{
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 );
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);
/* 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
/* => 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 = inw( ioaddr + REV_REG );
lp = (struct smc_local *)dev->priv;
lp->ChipID = (revision_register >> 4) & 0xF;
lp->ChipRev = revision_register & 0xF;
return 0;
err_out:
release_region (ioaddr, SMC_IO_EXTENT);
return retval;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -