⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 smc9194.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		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 + -