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

📄 smc91111.c

📁 smc9111网卡芯片的linux驱动程序
💻 C
📖 第 1 页 / 共 5 页
字号:
{	int offset;	offset = (base + reg) & 0x3;	return inl((base + reg) & ~3) >> 8 * offset;}static inline u16SMC_inw(u_int base, u_int reg){	int offset;	offset = (base + reg) & 0x3;	if (offset % 2)		printk(KERN_CRIT "%s: read not word aligned!\n", __FUNCTION__);	return inl((base + reg) & ~3) >> 8 * offset;}static inline u32SMC_inl(u_int base, u_int reg){	if ((base + reg) & 3)		printk(KERN_CRIT "%s: read not dword aligned!\n", __FUNCTION__);	return inl(base + reg);}/* Only one release command at a time, please */static inline void smc_wait_mmu_release_complete( unsigned int ioaddr){    int count = 0;    /* assume bank 2 selected */    while ( SMC_inw( ioaddr, MMU_CMD_REG ) & MC_BUSY )    {        udelay(1); // Wait until not busy        if( ++count > 200) break;    }}/* Only one allocate command at a time, please */static inline void smc_check_mmu_allocate_complete( unsigned int ioaddr){    if ( SMC_inb( ioaddr , AR_REG) & AR_FAILED)    {        printk("Memory alloc result: FAILED. \n");    }}static inline voidSMC_dma_inl(struct net_device *dev, unsigned char *data, u_int len){#if 0	struct smc_local *lp = (struct smc_local *) dev->priv;	dma_addr_t dma_handle;	unsigned int dcmd_width = DCMD_WIDTH2;	if( lp->use_32bit) dcmd_width = DCMD_WIDTH4;	//get sk_buff phys addr for dma engine:	dma_handle =	    pci_map_single(NULL, data, (size_t) len, PCI_DMA_FROMDEVICE);	if (dma_handle == 0) {		printk(KERN_CRIT		       "%s: Couldn't acquire phys addr of dma target buffer!\n",		       __FUNCTION__);		return;	}	PRINTK("%s: using %0#10x for phys addr for target buffer\n",	       __FUNCTION__, dma_handle);	PRINTK("%s: using %0#10lx for phys addr of smc rx buffer\n",	       __FUNCTION__, lp->dev_dma_phys);	PRINTK("%s: using dma channel %d\n", __FUNCTION__, dev->dma);	PRINTK("%s: attempting to xfer %d bytes of data...\n", __FUNCTION__,	       len);	DCSR(dev->dma) = DCSR_NODESC;	DTADR(dev->dma) = dma_handle;	DSADR(dev->dma) = lp->dev_dma_phys;	DCMD(dev->dma) =	    DCMD_INCTRGADDR | DCMD_BURST32 | dcmd_width | (DCMD_LENGTH & len);	DCSR(dev->dma) = DCSR_NODESC | DCSR_RUN;	/* Interrupt context, folks- no sleeping allowed... */	while (!(DCSR(dev->dma) & DCSR_STOPSTATE));	DCSR(dev->dma) = 0;	pci_unmap_single(NULL, dma_handle, (size_t) len, PCI_DMA_FROMDEVICE);#endif}static inline voidSMC_ins(u_int base, u_int reg, unsigned char *data, u_int len,	struct net_device *dev){	struct smc_local *lp = (struct smc_local *) dev->priv;	if( lp->dev_dma_phys)	{		SMC_dma_inl(dev, data, len);	}	else	{		u_int port = base + reg;		if( lp->use_32bit)		{			int i;			unsigned char *tail;			unsigned long leftover;			PRINTK ("SMC_ins: got %x for base, %x for reg, %p for data, %d for len\n",				 base, reg, data, len);			PRINTK(" Reading %d dwords (and %d bytes) \n", len >> 2, len & 3);			insl(port, data, len >> 2);			/* read the left over bytes (this is where things go bad			 * on PXA.  Don't even THINK of using insb... */			if (len & 3) {				tail = data + (len & ~3);				leftover = SMC_inl(base, reg);				for (i = 0; i < (len & 3); i++)					*tail++ = (char) (leftover >> (8 * i)) & 0xff;				PRINTK("Leftover (last) fifo read: %0#10lx saving to %p\n",						leftover, tail);			}		}		else		{			PRINTK(" Reading %d words and %d byte(s) \n", len >> 1, len & 1);			insw(port, data, len >> 1);			if (len & 1) {				data += len & ~1;				*data = inb(port);			}		}	}}void lan91c111Delay()
{
        int i;

        for(i=0; i<80; i++); 
}/* byte, word writes function normally on PXA */static inline voidSMC_outb(u8 val, u_int base, u_int reg){	outb(val, base + reg);	lan91c111Delay();}static inline voidSMC_outw(u16 val, u_int base, u_int reg){	outw(val, base + reg);	lan91c111Delay();}static inline voidSMC_outl(u32 val, u_int base, u_int reg){	u_int port = base + reg;	outl(val, port);	lan91c111Delay();}/*static inline voidSMC_outb(u8 val, u_int base, u_int reg){	int offset;	u32 offset2=val;	offset = (base + reg) & 0x3;	outl((offset2<< 8 * offset),((base + reg) & ~3)) ;	}static inline voidSMC_outw(u16 val, u_int base, u_int reg){	int offset;        u32 offset2=val;	offset = (base + reg) & 0x3;	if (offset % 2)		printk(KERN_CRIT "%s: read not word aligned!\n", __FUNCTION__);	outl((offset2<< 8 * offset),((base + reg) & ~3)) ;}static inline voidSMC_outl(u32 val, u_int base, u_int reg){	u_int port = base + reg;	outl(val, port);}*/static inline voidSMC_outsl(u_int base, u_int reg, unsigned char *data, u_int len){	u_int port = base + reg;	outsl(port, data, len >> 2);	lan91c111Delay();}static inline voidSMC_outsw(u_int base, u_int reg, unsigned char *data, u_int len){	u_int port = base + reg;	outsw(port, data, len >> 1);	lan91c111Delay();}/*------------------------------------------------------------------------- .  I define some macros to make it easier to do somewhat common . or slightly complicated, repeated tasks.  --------------------------------------------------------------------------*//* select a register bank, 0 to 3  */#define SMC_SELECT_BANK(x)				\	{						\		SMC_outw(x, ioaddr, BANK_SELECT);	\			}/* define a small delay for the reset */#define SMC_DELAY()					\	{						\		SMC_inw(ioaddr, RCR);			\		SMC_inw(ioaddr, RCR);			\		SMC_inw(ioaddr, RCR);			\	}/* this enables an interrupt in the interrupt mask register */#define SMC_ENABLE_INT(x)				\	{						\		u8 mask;				\		SMC_SELECT_BANK(2)			\		mask = SMC_inb(ioaddr, IM_REG);	\		mask |= (x);				\		SMC_outb(mask, ioaddr, IM_REG);	\	}/* this disables an interrupt from the interrupt mask register */#define SMC_DISABLE_INT(x) {				\		u8 mask;				\		SMC_SELECT_BANK(2);			\		mask = SMC_inb( ioaddr, IM_REG );		\		mask &= ~(x);				\		SMC_outb( mask, ioaddr, IM_REG ); 		\}#endif/* CONFIG_ARCH_S3C2410*//* . Function: smc_reset( struct device* dev ) . Purpose: .  	This sets the SMC91111 chip to its normal state, hopefully from whatever . 	mess that any other DOS driver has put it in. . . Maybe I should reset more registers to defaults in here?  SOFTRST  should . do that for me. . . Method: .	1.  send a SOFT RESET .	2.  wait for it to finish .	3.  enable autorelease mode .	4.  reset the memory management unit .	5.  clear all interrupts .*/static voidsmc_reset(struct net_device *dev){	//struct smc_local *lp  = (struct smc_local *)dev->priv;	unsigned int ioaddr = dev->base_addr;	PRINTK2("%s:smc_reset\n", dev->name);	/* This resets the registers mostly to defaults, but doesn't	   affect EEPROM.  That seems unnecessary */	SMC_SELECT_BANK(0);	SMC_outw(RCR_SOFTRST, ioaddr, RCR_REG);	/* Setup the Configuration Register */	/* This is necessary because the CONFIG_REG is not affected */	/* by a soft reset */	SMC_SELECT_BANK(1);	SMC_outw(CONFIG_DEFAULT, ioaddr, CONFIG_REG);	/* Setup for fast accesses if requested */	/* If the card/system can't handle it then there will */	/* be no recovery except for a hard reset or power cycle */	if (wait_mode[(int)(dev->name[3] - 48)]) //an ascii digit, don't forget		SMC_outw(((SMC_inw(ioaddr, CONFIG_REG)) | CONFIG_NO_WAIT),			 ioaddr, CONFIG_REG);#ifdef SMC_POWER_DOWN	/* Release from possible power-down state */	/* Configuration register is not affected by Soft Reset */	SMC_SELECT_BANK(1);	SMC_outw((SMC_inw(ioaddr, CONFIG_REG) | CONFIG_EPH_POWER_EN),		 ioaddr, CONFIG_REG);#endif	SMC_SELECT_BANK(0);	/* this should pause enough for the chip to be happy */	mdelay(10);	/* Disable transmit and receive functionality */	SMC_outw(RCR_CLEAR, ioaddr, RCR_REG);	SMC_outw(TCR_CLEAR, ioaddr, TCR_REG);	/* set the control register to automatically	   release successfully transmitted packets, to make the best	   use out of our limited memory */	SMC_SELECT_BANK(1);#ifdef USE_AUTO_RELEASE	SMC_outw((SMC_inw(ioaddr, CTL_REG) | CTL_AUTO_RELEASE), ioaddr,		 CTL_REG);#else	SMC_outw((SMC_inw(ioaddr, CTL_REG) & ~CTL_AUTO_RELEASE), ioaddr,		 CTL_REG);#endif	/* Reset the MMU */	SMC_SELECT_BANK(2);	SMC_outw(MC_RESET, ioaddr, MMU_CMD_REG);	/* Note:  It doesn't seem that waiting for the MMU busy is needed here,	   but this is a place where future chipsets _COULD_ break.  Be wary	   of issuing another MMU command right after this */	/* Well, then, how about doing this? [jws] */	while (SMC_inw(ioaddr, MMU_CMD_REG) & MC_BUSY)		udelay(1);	// Wait until not busy	/* Disable all interrupts */	SMC_outb(0, ioaddr, IM_REG);}/* . Function: smc_enable . Purpose: let the chip talk to the outside work . Method: .	1.  Enable the transmitter .	2.  Enable the receiver .	3.  Enable interrupts*/static voidsmc_enable(struct net_device *dev){	unsigned int ioaddr = dev->base_addr;	struct smc_local *lp = (struct smc_local *) dev->priv;	PRINTK2("%s:smc_enable\n", dev->name);	SMC_SELECT_BANK(0);	/* see the header file for options in TCR/RCR DEFAULT */	SMC_outw(lp->tcr_cur_mode, ioaddr, TCR_REG);	SMC_outw(lp->rcr_cur_mode, ioaddr, RCR_REG);	/* now, enable interrupts */	SMC_SELECT_BANK(2);	SMC_outb(SMC_INTERRUPT_MASK, ioaddr, IM_REG);}/* . Function: smc_shutdown . Purpose:  closes down the SMC91xxx chip. . Method: .	1. zero the interrupt mask .	2. clear the enable receive flag .	3. clear the enable xmit flags . . TODO: .   (1) maybe utilize power down mode. .	Why not yet?  Because while the chip will go into power down mode, .	the manual says that it will wake up in response to any I/O requests .	in the register space.   Empirical results do not show this working.*/static voidsmc_shutdown(unsigned int ioaddr){	PRINTK2("%s:smc_shutdown\n", CARDNAME);	/* no more interrupts for me */	SMC_SELECT_BANK(2);	SMC_outb(0, ioaddr, IM_REG);	/* and tell the card to stay away from that nasty outside world */	SMC_SELECT_BANK(0);	SMC_outb(RCR_CLEAR, ioaddr, RCR_REG);	SMC_outb(TCR_CLEAR, ioaddr, TCR_REG);#ifdef SMC_POWER_DOWN	/* finally, shut the chip down */	SMC_SELECT_BANK(1);	SMC_outw(SMC_inw(ioaddr, CONFIG_REG) & ~CONFIG_EPH_POWER_EN,		 ioaddr, CONFIG_REG);#endif}/* . Function: smc_setmulticast( int ioaddr, int count, dev_mc_list * adds ) . Purpose: .    This sets the internal hardware table to filter out unwanted multicast .    packets before they take up memory. . .    The SMC chip uses a hash table where the high 6 bits of the CRC of .    address are the offset into the table.  If that bit is 1, then the .    multicast packet is accepted.  Otherwise, it's dropped silently. . .    To use the 6 bits as an offset into the table, the high 3 bits are the .    number of the 8 bit register, while the low 3 bits are the bit within .    that register. . . This routine is based very heavily on the one provided by Peter Cammaert.*/static voidsmc_setmulticast(unsigned int ioaddr, int count, struct dev_mc_list *addrs){	int i;	unsigned char multicast_table[8];	struct dev_mc_list *cur_addr;	/* table for flipping the order of 3 bits */	unsigned char invert3[] = { 0, 4, 2, 6, 1, 5, 3, 7 };	PRINTK2("%s:smc_setmulticast\n", CARDNAME);	/* start with a table of all zeros: reject all */	memset(multicast_table, 0, sizeof (multicast_table));	cur_addr = addrs;	for (i = 0; i < count; i++, cur_addr = cur_addr->next) {		int position;		/* do we have a pointer here? */		if (!cur_addr)			break;		/* make sure this is a multicast address - shouldn't this		   be a given if we have it here ? */		if (!(*cur_addr->dmi_addr & 1))			continue;		/* only use the low order bits */		position = crc32(cur_addr->dmi_addr, 6) & 0x3f;		/* do some messy swapping to put the bit in the right spot */		multicast_table[invert3[position & 7]] |=		    (1 << invert3[(position >> 3) & 7]);	}	/* now, the table can be loaded into the chipset */	SMC_SELECT_BANK(3);	for (i = 0; i < 8; i++) {		SMC_outb(multicast_table[i], ioaddr, MCAST_REG1 + i);	}}/*  Finds the CRC32 of a set of bytes.  Again, from Peter Cammaert's code.*/

⌨️ 快捷键说明

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