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

📄 smc9194.c

📁 powerpc内核mpc8241linux系统下net驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
		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 ) {		return -ENODEV;	}	/* 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. */		return -ENODEV;	}	/*  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 );		return -ENODEV;	}	/* 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. */	return 0;}/*--------------------------------------------------------------- . 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 .-----------------------------------------------------------------*/__initfunc(static int  smc_initcard(struct device *dev, int ioaddr)){	int i;	static unsigned version_printed = 0;	/* registers */	word	revision_register;	word	configuration_register;	word  	memory_info_register;	word 	memory_cfg_register;	const char *	version_string;	const char *	if_string;	int	memory;	int   irqval;	/* see if I need to initialize the ethernet card structure */	if (dev == NULL) {#ifdef SUPPORT_OLD_KERNEL#ifndef MODULE/* note: the old module interface does not support this call */		dev = init_etherdev( 0, sizeof( struct smc_local ), 0 );#endif#else		dev = init_etherdev(0, 0);#endif		if (dev == NULL)			return -ENOMEM;	}	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.... */		return -ENODEV;	}	/* 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!!!! 	 .	*/#ifndef NO_AUTOPROBE	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");		return -ENODEV;	}#else	if (dev->irq == 0 ) {		printk(CARDNAME		": Autoprobing IRQs is not supported for old kernels.\n");		return -ENODEV;	}#endif	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(CARDNAME ": %s(r:%d) at %#3x IRQ:%d INTF:%s MEM:%db ",		version_string, revision_register & 0xF, ioaddr, dev->irq,		if_string, memory );	/*	 . 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)			return -ENOMEM;	}	/* 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 */      	irqval = request_irq(dev->irq, &smc_interrupt, 0, CARDNAME, dev);      	if (irqval) {       	  printk(CARDNAME": unable to get IRQ %d (irqval=%d).\n",		dev->irq, irqval);       	  return -EAGAIN;      	}	/* Grab the region so that no one else tries to probe our ioports. */	request_region(ioaddr, SMC_IO_EXTENT, CARDNAME);	dev->open		        = smc_open;	dev->stop		        = smc_close;	dev->hard_start_xmit    	= smc_send_packet;	dev->get_stats			= smc_query_statistics;#ifdef	HAVE_MULTICAST	dev->set_multicast_list 	= &smc_set_multicast_list;#endif	return 0;}#if SMC_DEBUG > 2static void print_packet( byte * buf, int length ){#if 0	int i;	int remainder;	int lines;	printk("Packet of length %d \n", length );	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/* * Open and Initialize the board * * Set up everything, reset the card, etc .. * */static int smc_open(struct device *dev){	int	ioaddr = dev->base_addr;	int	i;	/* used to set hw ethernet address */	/* clear out all the junk that was put here before... */	memset(dev->priv, 0, sizeof(struct smc_local));	dev->tbusy 	= 0;	dev->interrupt  = 0;	dev->start 	= 1;#ifdef MODULE	MOD_INC_USE_COUNT;#endif	/* reset the hardware */	smc_reset( ioaddr );	smc_enable( ioaddr );	/* Select which interface to use */	SMC_SELECT_BANK( 1 );	if ( dev->if_port == 1 ) {		outw( inw( ioaddr + CONFIG ) & ~CFG_AUI_SELECT,			ioaddr + CONFIG );	}	else if ( dev->if_port == 2 ) {		outw( inw( ioaddr + CONFIG ) | CFG_AUI_SELECT,			ioaddr + CONFIG );	}	/*  		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 + i );	}	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 int smc_send_packet(struct sk_buff *skb, struct device *dev){	if (dev->tbusy) {		/* If we get here, some higher level has decided we are broken.		   There should really be a "kick me" function call instead. */		int tickssofar = jiffies - dev->trans_start;		if (tickssofar < 5)			return 1;		printk(KERN_WARNING CARDNAME": transmit timed out, %s?\n",			tx_done(dev) ? "IRQ conflict" :			"network cable problem");		/* "kick" the adaptor */		smc_reset( dev->base_addr );		smc_enable( dev->base_addr );		dev->tbusy = 0;		dev->trans_start = jiffies;		/* clear anything saved */		((struct smc_local *)dev->priv)->saved_skb = NULL;	}	/* Block a timer-based transmit from overlapping.  This could better be	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {		printk(KERN_WARNING CARDNAME": Transmitter access conflict.\n");		dev_kfree_skb (skb);	} else {		/* Well, I want to send the packet.. but I don't know		   if I can send it right now...  */		return smc_wait_to_send_packet( skb, dev );	}	return 0;}/*-------------------------------------------------------------------- . . This is the main routine of the driver, to handle the 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. . ---------------------------------------------------------------------*/#ifdef REALLY_NEW_KERNELstatic void smc_interrupt(int irq, void * dev_id,  struct pt_regs * regs)#elsestatic void smc_interrupt(int irq, struct pt_regs * regs)#endif{	struct 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((CARDNAME": SMC interrupt started \n"));	if (dev == NULL) {		printk(KERN_WARNING  CARDNAME": irq %d for unknown device.\n",			irq);		return;	}/* will Linux let this happen ??  If not, this costs some speed */	if ( dev->interrupt ) {		printk(KERN_WARNING CARDNAME": interrupt inside interrupt.\n");		return;	}	dev->interrupt = 1;	saved_bank = inw( ioaddr + BANK_SELECT );	SMC_SELECT_BANK(2);	saved_pointer = inw( ioaddr + POINTER );	mask = inb( ioaddr + INT_MASK );	/* clear all interrupts */	outb( 0, ioaddr + INT_MASK );	/* set a timeout value, so I don't stay here forever */	timeout = 4;	PRINTK2((KERN_WARNING CARDNAME ": MASK IS %x \n", mask ));	do {		/* read the status flag, and mask it */		status = inb( ioaddr + INTERRUPT ) & mask;		if (!status )			break;		PRINTK3((KERN_WARNING CARDNAME			": Handling interrupt status %x \n", status ));		if (status & IM_RCV_INT) {			/* Got a packet(s). */			PRINTK2((KERN_WARNING CARDNAME				": Receive Interrupt\n"));			smc_rcv(dev);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -