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

📄 sbni.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
	if( nl->state & FL_SLAVE )		spin_unlock( &((struct net_local *) nl->master->priv)->lock );#endif}/* * Routine returns 1 if it need to acknoweledge received frame. * Empty frame received without errors won't be acknoweledged. */static intrecv_frame( struct net_device  *dev ){	struct net_local  *nl   = (struct net_local *) dev->priv;	unsigned long  ioaddr	= dev->base_addr;	u32  crc = CRC32_INITIAL;	unsigned  framelen, frameno, ack;	unsigned  is_first, frame_ok;	if( check_fhdr( ioaddr, &framelen, &frameno, &ack, &is_first, &crc ) ) {		frame_ok = framelen > 4			?  upload_data( dev, framelen, frameno, is_first, crc )			:  skip_tail( ioaddr, framelen, crc );		if( frame_ok )			interpret_ack( dev, ack );	} else		frame_ok = 0;	outb( inb( ioaddr + CSR0 ) ^ CT_ZER, ioaddr + CSR0 );	if( frame_ok ) {		nl->state |= FL_PREV_OK;		if( framelen > 4 )			nl->in_stats.all_rx_number++;	} else		nl->state &= ~FL_PREV_OK,		change_level( dev ),		nl->in_stats.all_rx_number++,		nl->in_stats.bad_rx_number++;	return  !frame_ok  ||  framelen > 4;}static voidsend_frame( struct net_device  *dev ){	struct net_local  *nl    = (struct net_local *) dev->priv;	u32  crc = CRC32_INITIAL;	if( nl->state & FL_NEED_RESEND ) {		/* if frame was sended but not ACK'ed - resend it */		if( nl->trans_errors ) {			--nl->trans_errors;			if( nl->framelen != 0 )				nl->in_stats.resend_tx_number++;		} else {			/* cannot xmit with many attempts */#ifdef CONFIG_SBNI_MULTILINE			if( (nl->state & FL_SLAVE)  ||  nl->link )#endif			nl->state |= FL_LINE_DOWN;			drop_xmit_queue( dev );			goto  do_send;		}	} else		nl->trans_errors = TR_ERROR_COUNT;	send_frame_header( dev, &crc );	nl->state |= FL_NEED_RESEND;	/*	 * FL_NEED_RESEND will be cleared after ACK, but if empty	 * frame sended then in prepare_to_send next frame	 */	if( nl->framelen ) {		download_data( dev, &crc );		nl->in_stats.all_tx_number++;		nl->state |= FL_WAIT_ACK;	}	outsb( dev->base_addr + DAT, (u8 *)&crc, sizeof crc );do_send:	outb( inb( dev->base_addr + CSR0 ) & ~TR_REQ, dev->base_addr + CSR0 );	if( nl->tx_frameno )		/* next frame exists - we request card to send it */		outb( inb( dev->base_addr + CSR0 ) | TR_REQ,		      dev->base_addr + CSR0 );}/* * Write the frame data into adapter's buffer memory, and calculate CRC. * Do padding if necessary. */static voiddownload_data( struct net_device  *dev,  u32  *crc_p ){	struct net_local  *nl    = (struct net_local *) dev->priv;	struct sk_buff    *skb	 = nl->tx_buf_p;	unsigned  len = min_t(unsigned int, skb->len - nl->outpos, nl->framelen);	outsb( dev->base_addr + DAT, skb->data + nl->outpos, len );	*crc_p = calc_crc32( *crc_p, skb->data + nl->outpos, len );	/* if packet too short we should write some more bytes to pad */	for( len = nl->framelen - len;  len--; )		outb( 0, dev->base_addr + DAT ),		*crc_p = CRC32( 0, *crc_p );}static intupload_data( struct net_device  *dev,  unsigned  framelen,  unsigned  frameno,	     unsigned  is_first,  u32  crc ){	struct net_local  *nl = (struct net_local *) dev->priv;	int  frame_ok;	if( is_first )		nl->wait_frameno = frameno,		nl->inppos = 0;	if( nl->wait_frameno == frameno ) {		if( nl->inppos + framelen  <=  ETHER_MAX_LEN )			frame_ok = append_frame_to_pkt( dev, framelen, crc );		/*		 * if CRC is right but framelen incorrect then transmitter		 * error was occurred... drop entire packet		 */		else if( (frame_ok = skip_tail( dev->base_addr, framelen, crc ))			 != 0 )			nl->wait_frameno = 0,			nl->inppos = 0,#ifdef CONFIG_SBNI_MULTILINE			((struct net_local *) nl->master->priv)				->stats.rx_errors++,			((struct net_local *) nl->master->priv)				->stats.rx_missed_errors++;#else			nl->stats.rx_errors++,			nl->stats.rx_missed_errors++;#endif			/* now skip all frames until is_first != 0 */	} else		frame_ok = skip_tail( dev->base_addr, framelen, crc );	if( is_first  &&  !frame_ok )		/*		 * Frame has been broken, but we had already stored		 * is_first... Drop entire packet.		 */		nl->wait_frameno = 0,#ifdef CONFIG_SBNI_MULTILINE		((struct net_local *) nl->master->priv)->stats.rx_errors++,		((struct net_local *) nl->master->priv)->stats.rx_crc_errors++;#else		nl->stats.rx_errors++,		nl->stats.rx_crc_errors++;#endif	return  frame_ok;}static __inline voidsend_complete( struct net_local  *nl ){#ifdef CONFIG_SBNI_MULTILINE	((struct net_local *) nl->master->priv)->stats.tx_packets++;	((struct net_local *) nl->master->priv)->stats.tx_bytes		+= nl->tx_buf_p->len;#else	nl->stats.tx_packets++;	nl->stats.tx_bytes += nl->tx_buf_p->len;#endif	dev_kfree_skb_irq( nl->tx_buf_p );	nl->tx_buf_p = NULL;	nl->outpos = 0;	nl->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND);	nl->framelen   = 0;}static voidinterpret_ack( struct net_device  *dev,  unsigned  ack ){	struct net_local  *nl = (struct net_local *) dev->priv;	if( ack == FRAME_SENT_OK ) {		nl->state &= ~FL_NEED_RESEND;		if( nl->state & FL_WAIT_ACK ) {			nl->outpos += nl->framelen;			if( --nl->tx_frameno )				nl->framelen = min_t(unsigned int,						   nl->maxframe,						   nl->tx_buf_p->len - nl->outpos);			else				send_complete( nl ),#ifdef CONFIG_SBNI_MULTILINE				netif_wake_queue( nl->master );#else				netif_wake_queue( dev );#endif		}	}	nl->state &= ~FL_WAIT_ACK;}/* * Glue received frame with previous fragments of packet. * Indicate packet when last frame would be accepted. */static intappend_frame_to_pkt( struct net_device  *dev,  unsigned  framelen,  u32  crc ){	struct net_local  *nl = (struct net_local *) dev->priv;	u8  *p;	if( nl->inppos + framelen  >  ETHER_MAX_LEN )		return  0;	if( !nl->rx_buf_p  &&  !(nl->rx_buf_p = get_rx_buf( dev )) )		return  0;	p = nl->rx_buf_p->data + nl->inppos;	insb( dev->base_addr + DAT, p, framelen );	if( calc_crc32( crc, p, framelen ) != CRC32_REMAINDER )		return  0;	nl->inppos += framelen - 4;	if( --nl->wait_frameno == 0 )		/* last frame received */		indicate_pkt( dev );	return  1;}/* * Prepare to start output on adapter. * Transmitter will be actually activated when marker is accepted. */static voidprepare_to_send( struct sk_buff  *skb,  struct net_device  *dev ){	struct net_local  *nl = (struct net_local *) dev->priv;	unsigned int  len;	/* nl->tx_buf_p == NULL here! */	if( nl->tx_buf_p )		printk( KERN_ERR "%s: memory leak!\n", dev->name );	nl->outpos = 0;	nl->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND);	len = skb->len;	if( len < SBNI_MIN_LEN )		len = SBNI_MIN_LEN;	nl->tx_buf_p	= skb;	nl->tx_frameno	= (len + nl->maxframe - 1) / nl->maxframe;	nl->framelen	= len < nl->maxframe  ?  len  :  nl->maxframe;	outb( inb( dev->base_addr + CSR0 ) | TR_REQ,  dev->base_addr + CSR0 );#ifdef CONFIG_SBNI_MULTILINE	nl->master->trans_start = jiffies;#else	dev->trans_start = jiffies;#endif}static voiddrop_xmit_queue( struct net_device  *dev ){	struct net_local  *nl = (struct net_local *) dev->priv;	if( nl->tx_buf_p )		dev_kfree_skb_any( nl->tx_buf_p ),		nl->tx_buf_p = NULL,#ifdef CONFIG_SBNI_MULTILINE		((struct net_local *) nl->master->priv)			->stats.tx_errors++,		((struct net_local *) nl->master->priv)			->stats.tx_carrier_errors++;#else		nl->stats.tx_errors++,		nl->stats.tx_carrier_errors++;#endif	nl->tx_frameno	= 0;	nl->framelen	= 0;	nl->outpos	= 0;	nl->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND);#ifdef CONFIG_SBNI_MULTILINE	netif_start_queue( nl->master );	nl->master->trans_start = jiffies;#else	netif_start_queue( dev );	dev->trans_start = jiffies;#endif}static voidsend_frame_header( struct net_device  *dev,  u32  *crc_p ){	struct net_local  *nl  = (struct net_local *) dev->priv;	u32  crc = *crc_p;	u32  len_field = nl->framelen + 6;	/* CRC + frameno + reserved */	u8   value;	if( nl->state & FL_NEED_RESEND )		len_field |= FRAME_RETRY;	/* non-first attempt... */	if( nl->outpos == 0 )		len_field |= FRAME_FIRST;	len_field |= (nl->state & FL_PREV_OK) ? FRAME_SENT_OK : FRAME_SENT_BAD;	outb( SBNI_SIG, dev->base_addr + DAT );	value = (u8) len_field;	outb( value, dev->base_addr + DAT );	crc = CRC32( value, crc );	value = (u8) (len_field >> 8);	outb( value, dev->base_addr + DAT );	crc = CRC32( value, crc );	outb( nl->tx_frameno, dev->base_addr + DAT );	crc = CRC32( nl->tx_frameno, crc );	outb( 0, dev->base_addr + DAT );	crc = CRC32( 0, crc );	*crc_p = crc;}/* * if frame tail not needed (incorrect number or received twice), * it won't store, but CRC will be calculated */static intskip_tail( unsigned int  ioaddr,  unsigned int  tail_len,  u32 crc ){	while( tail_len-- )		crc = CRC32( inb( ioaddr + DAT ), crc );	return  crc == CRC32_REMAINDER;}/* * Preliminary checks if frame header is correct, calculates its CRC * and split it to simple fields */static intcheck_fhdr( u32  ioaddr,  u32  *framelen,  u32  *frameno,  u32  *ack,	    u32  *is_first,  u32  *crc_p ){	u32  crc = *crc_p;	u8   value;	if( inb( ioaddr + DAT ) != SBNI_SIG )		return  0;	value = inb( ioaddr + DAT );	*framelen = (u32)value;	crc = CRC32( value, crc );	value = inb( ioaddr + DAT );	*framelen |= ((u32)value) << 8;	crc = CRC32( value, crc );	*ack = *framelen & FRAME_ACK_MASK;	*is_first = (*framelen & FRAME_FIRST) != 0;	if( (*framelen &= FRAME_LEN_MASK) < 6	    ||  *framelen > SBNI_MAX_FRAME - 3 )		return  0;	value = inb( ioaddr + DAT );	*frameno = (u32)value;	crc = CRC32( value, crc );	crc = CRC32( inb( ioaddr + DAT ), crc );	/* reserved byte */	*framelen -= 2;	*crc_p = crc;	return  1;}static struct sk_buff *get_rx_buf( struct net_device  *dev ){	/* +2 is to compensate for the alignment fixup below */	struct sk_buff  *skb = dev_alloc_skb( ETHER_MAX_LEN + 2 );	if( !skb )		return  NULL;#ifdef CONFIG_SBNI_MULTILINE	skb->dev = ((struct net_local *) dev->priv)->master;#else	skb->dev = dev;#endif	skb_reserve( skb, 2 );		/* Align IP on longword boundaries */	return  skb;}static voidindicate_pkt( struct net_device  *dev ){	struct net_local  *nl  = (struct net_local *) dev->priv;	struct sk_buff    *skb = nl->rx_buf_p;	skb_put( skb, nl->inppos );#ifdef CONFIG_SBNI_MULTILINE	skb->protocol = eth_type_trans( skb, nl->master );	netif_rx( skb );	dev->last_rx = jiffies;	++((struct net_local *) nl->master->priv)->stats.rx_packets;	((struct net_local *) nl->master->priv)->stats.rx_bytes += nl->inppos;#else	skb->protocol = eth_type_trans( skb, dev );	netif_rx( skb );	dev->last_rx = jiffies;	++nl->stats.rx_packets;	nl->stats.rx_bytes += nl->inppos;#endif	nl->rx_buf_p = NULL;	/* protocol driver will clear this sk_buff */}/* -------------------------------------------------------------------------- *//* * Routine checks periodically wire activity and regenerates marker if * connect was inactive for a long time. */static voidsbni_watchdog( unsigned long  arg ){	struct net_device  *dev = (struct net_device *) arg;	struct net_local   *nl  = (struct net_local *) dev->priv;	struct timer_list  *w   = &nl->watchdog; 	unsigned long	   flags;	unsigned char	   csr0;	spin_lock_irqsave( &nl->lock, flags );	csr0 = inb( dev->base_addr + CSR0 );	if( csr0 & RC_CHK ) {		if( nl->timer_ticks ) {			if( csr0 & (RC_RDY | BU_EMP) )				/* receiving not active */				nl->timer_ticks--;		} else {			nl->in_stats.timeout_number++;			if( nl->delta_rxl )				timeout_change_level( dev );			outb( *(u_char *)&nl->csr1 | PR_RES,			      dev->base_addr + CSR1 );			csr0 = inb( dev->base_addr + CSR0 );		}	} else		nl->state &= ~FL_LINE_DOWN;	outb( csr0 | RC_CHK, dev->base_addr + CSR0 ); 	init_timer( w );	w->expires	= jiffies + SBNI_TIMEOUT;	w->data		= arg;	w->function	= sbni_watchdog;	add_timer( w );	spin_unlock_irqrestore( &nl->lock, flags );}static unsigned char  rxl_tab[] = {	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08,	0x0a, 0x0c, 0x0f, 0x16, 0x18, 0x1a, 0x1c, 0x1f};#define SIZE_OF_TIMEOUT_RXL_TAB 4static unsigned char  timeout_rxl_tab[] = {	0x03, 0x05, 0x08, 0x0b};/* -------------------------------------------------------------------------- */static voidcard_start( struct net_device  *dev ){	struct net_local  *nl = (struct net_local *) dev->priv;	nl->timer_ticks = CHANGE_LEVEL_START_TICKS;	nl->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND);	nl->state |= FL_PREV_OK;	nl->inppos = nl->outpos = 0;	nl->wait_frameno = 0;	nl->tx_frameno	 = 0;	nl->framelen	 = 0;	outb( *(u_char *)&nl->csr1 | PR_RES, dev->base_addr + CSR1 );	outb( EN_INT, dev->base_addr + CSR0 );}/* -------------------------------------------------------------------------- *//* Receive level auto-selection */static voidchange_level( struct net_device  *dev ){	struct net_local  *nl = (struct net_local *) dev->priv;	if( nl->delta_rxl == 0 )	/* do not auto-negotiate RxL */		return;	if( nl->cur_rxl_index == 0 )		nl->delta_rxl = 1;	else if( nl->cur_rxl_index == 15 )		nl->delta_rxl = -1;	else if( nl->cur_rxl_rcvd < nl->prev_rxl_rcvd )		nl->delta_rxl = -nl->delta_rxl;	nl->csr1.rxl = rxl_tab[ nl->cur_rxl_index += nl->delta_rxl ];	inb( dev->base_addr + CSR0 );	/* needs for PCI cards */	outb( *(u8 *)&nl->csr1, dev->base_addr + CSR1 );	nl->prev_rxl_rcvd = nl->cur_rxl_rcvd;	nl->cur_rxl_rcvd  = 0;}static voidtimeout_change_level( struct net_device  *dev ){	struct net_local  *nl = (struct net_local *) dev->priv;	nl->cur_rxl_index = timeout_rxl_tab[ nl->timeout_rxl ];	if( ++nl->timeout_rxl >= 4 )		nl->timeout_rxl = 0;	nl->csr1.rxl = rxl_tab[ nl->cur_rxl_index ];	inb( dev->base_addr + CSR0 );	outb( *(unsigned char *)&nl->csr1, dev->base_addr + CSR1 );	nl->prev_rxl_rcvd = nl->cur_rxl_rcvd;

⌨️ 快捷键说明

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