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

📄 rtl8150.c

📁 linux的网卡实用驱动及应用源码rtl8150
💻 C
📖 第 1 页 / 共 3 页
字号:
		return;
	
	usb_unlink_urb( &rtl8150->tx_urb );
	warn("%s: Tx timed out.", net->name);
	rtl8150->stats.tx_errors++;
	net->trans_start = jiffies;

	netif_wake_queue( net );
	info( "-rtl8150_tx_timeout() <=====" );
}



static int rtl8150_start_xmit( struct sk_buff *skb, struct net_device *net )
{
	rtl8150_t	*rtl8150 = net->priv;
	int 	count = ((skb->len) & 0x3f) ? skb->len : skb->len+1;
		/// increase 64n-length packet by one, because the host controller sometimes doesn't send
		/// 0-length usb packet to end the 64n-length packet.
	int 	res;

	//info( "+rtl8150_start_xmit() =====>" );

	netif_stop_queue( net );
		
	memcpy( rtl8150->tx_buff, skb->data, skb->len );
	
	if(count < RTL8150_MIN_PACKET_LENGTH)
		count = RTL8150_MIN_PACKET_LENGTH;
	FILL_BULK_URB( &rtl8150->tx_urb, rtl8150->usb,
			usb_sndbulkpipe(rtl8150->usb, 2),
			rtl8150->tx_buff, RTL8150_MAX_MTU, 
			write_bulk_callback, rtl8150 );
	rtl8150->tx_urb.transfer_buffer_length = count;

	//info( " rtl8150_start_xmit: packet length = 0x%x", count);	
	//info( " rtl8150_start_xmit: packet = %x %x %x %x %x %x %x %x %x %x %x %x", rtl8150->tx_buff[0], rtl8150->tx_buff[1],
	//	rtl8150->tx_buff[2], rtl8150->tx_buff[3], rtl8150->tx_buff[4], rtl8150->tx_buff[5],
	//	rtl8150->tx_buff[6], rtl8150->tx_buff[7], rtl8150->tx_buff[8], rtl8150->tx_buff[9],
	//	rtl8150->tx_buff[10], rtl8150->tx_buff[11]);
	rtl8150->tx_urb.transfer_flags |= USB_ASYNC_UNLINK;
	if ((res = usb_submit_urb(&rtl8150->tx_urb))) 
	{
		warn("failed tx_urb %d", res);
		rtl8150->stats.tx_errors++;
		netif_start_queue( net );
	}
	else 
	{
		rtl8150->stats.tx_packets++;
		rtl8150->stats.tx_bytes += skb->len;
		net->trans_start = jiffies;	/// record the time stamp
	}

	dev_kfree_skb(skb);
	
	//info( "-rtl8150_start_xmit() <=====" );	
	return 0;
}


/// this function is called when "ifconfig ethx" or "netstat"
static struct net_device_stats *rtl8150_netdev_stats( struct net_device *dev )
{
	//info( "+rtl8150_netdev_stats() =====>" );
	return &((rtl8150_t *)dev->priv)->stats;
	//info( "-rtl8150_netdev_stats() <=====" );
}



static inline void disable_net_traffic( rtl8150_t *rtl8150 )
{
	__u8	tmp = 0;

	info( "+disable_net_traffic() =====>" );
	set_registers( rtl8150, Command, 1, &tmp );
	info( "-disable_net_traffic() <=====" );
}



static inline void get_interrupt_interval( rtl8150_t *rtl8150 )
{
	__u8	data;

	info( "+get_interrupt_interval() =====>" );

	read_eprom_byte( rtl8150, EPROM_Interv, &data );
	rtl8150->intr_interval = data;
	info( "-get_interrupt_interval() <=====" );
}


/// this function is called when "ifconfig ethx xxx ....."
static int rtl8150_open(struct net_device *net)
{
	rtl8150_t *rtl8150 = (rtl8150_t *)net->priv;
	int	res;

	info( "+rtl8150_open() =====>" );

	MOD_INC_USE_COUNT;
	
	///info( " rtl8150_open: before enable_net_traffic()" );
	if ( (res = enable_net_traffic(net, rtl8150->usb)) ) 
	{
		info(" rtl8150_open: enable_net_traffic failed");
		err("can't enable_net_traffic() - %d", res);
		MOD_DEC_USE_COUNT;
		return -EIO;
	}

	/// initiate the rx operation
	info( " rtl8150_open: initiate the rx operation" );
	FILL_BULK_URB( &rtl8150->rx_urb, rtl8150->usb,
			usb_rcvbulkpipe(rtl8150->usb, 1),
			rtl8150->rx_buff, RTL8150_MAX_MTU, 
			read_bulk_callback, rtl8150 );
	if ( (res = usb_submit_urb(&rtl8150->rx_urb)) )
	{
		info(" rtl8150_open: usb_submit_urb failed" );
		warn( __FUNCTION__ " failed rx_urb %d", res );
	}

	/*
	/// initiate the interrupt operation
#ifdef	RTL8150_USE_INTR
	get_interrupt_interval( rtl8150 );
	FILL_INT_URB( &rtl8150->intr_urb, rtl8150->usb,
			usb_rcvintpipe(rtl8150->usb, 3),
			rtl8150->intr_buff, sizeof(rtl8150->intr_buff),
			intr_callback, rtl8150, rtl8150->intr_interval );
	if ( (res = usb_submit_urb(&rtl8150->intr_urb)) )
		warn( __FUNCTION__ " failed intr_urb %d", res);
#endif
	*/
	netif_start_queue( net );
	rtl8150->flags |= RTL8150_RUNNING;

	info( "-rt8150_open() <=====" );
	
	return 0;
}



/// this funciton is called when "ifconfig ethx down"
static int rtl8150_close( struct net_device *net )
{
	rtl8150_t	*rtl8150 = net->priv;

	info( "+rtl8150_close() =====>" );

	rtl8150->flags &= ~RTL8150_RUNNING;
	netif_stop_queue( net );
	if ( !(rtl8150->flags & RTL8150_UNPLUG) )
		disable_net_traffic( rtl8150 );

	usb_unlink_urb( &rtl8150->rx_urb );
	usb_unlink_urb( &rtl8150->tx_urb );
	usb_unlink_urb( &rtl8150->ctrl_urb );
	usb_unlink_urb( &rtl8150->intr_urb );

	MOD_DEC_USE_COUNT;

	info( "-rtl8150_close() <=====" );
	return 0;
}



static int rtl8150_ioctl( struct net_device *net, struct ifreq *rq, int cmd )
{
	__u16 *data = (__u16 *)&rq->ifr_data;
	rtl8150_t	*rtl8150 = net->priv;

	info( "+rtl8150_ioctl() =====> return -EOPNOTSUPP directly" );

	return -EOPNOTSUPP;

	switch(cmd) {
		case SIOCDEVPRIVATE:
			data[0] = rtl8150->phy;
		case SIOCDEVPRIVATE+1:
			read_phy_word(rtl8150, data[0], data[1]&0x1f, &data[3]);
			return 0;
		case SIOCDEVPRIVATE+2:
			if ( !capable(CAP_NET_ADMIN) )
				return -EPERM;
			write_phy_word(rtl8150, rtl8150->phy, data[1] & 0x1f, data[2]);
			return 0;
		default:
			return -EOPNOTSUPP;
	}
}


static void rtl8150_set_multicast( struct net_device *net )
{
	__u16	rcr_content;
	rtl8150_t *rtl8150 = net->priv;

	info( "+rtl8150_set_multicast() =====>" );

	netif_stop_queue(net);

	while( rtl8150->get_registers_flag == 1 )
		;
	rtl8150->get_registers_flag = 1;
	get_registers( rtl8150, RxConfig, 2, &rcr_content );
	while( rtl8150->get_registers_flag == 1 )
		;

	if (net->flags & IFF_PROMISC) 
	{
		rcr_content |= AAP;
		info(" %s: Promiscuous mode enabled", net->name);
	} 
	else if( (net->mc_count > multicast_filter_limit) || (net->flags & IFF_ALLMULTI) ) 
	{
		rcr_content |= AAM;
		rcr_content &= ~AAP;
		info(" %s set allmulti", net->name);
	} 
	else 
	{
		rcr_content &= ~AAM;
		rcr_content &= ~AAP;
		info(" %s: No Promiscuous and All Multicast", net->name);
		/// added by Owen, please refer to 14.14.2 of Linux Device Drivers
		/// if( net->mc_count==0 )
		/// 	ff_get_only_own_packets();
		/// else
		/// {
		///	struct dev_mc_list	*mcptr;
		/// 	ff_clear_mc_list();
		///	for( mc_ptr = net->mc_list; mc_ptr; mc_ptr = mc_ptr->next )
		///		ff_store_mc_address( mc_ptr->dmi_addr );
		//	ff_get_packets_in_multicast_list();
		/// }
	}

	while( rtl8150->set_registers_flag == 1 )
		;
	rtl8150->set_registers_flag = 1;
	set_registers( rtl8150, RxConfig, 2, &rcr_content );
	while( rtl8150->set_registers_flag == 1 )
		;
	
	netif_wake_queue(net);	
	info( "-rtl8150_set_multicast() <=====" );	
}


static int check_device_ids( __u16 vendor, __u16 product )
{
	int i=0;

	info( "+check_device_ids() =====>" );
	info( " check_device_ids: vendor id = 0x%x", vendor );
	info( " check_device_ids: device id = 0x%x", product );
	
	while ( usb_dev_id[i].name ) {
		if ( (usb_dev_id[i].vendor == vendor) && (usb_dev_id[i].device == product) )
		{
		 	info( " check_device_ids: BINGO!" );
		 	info( "-check_device_ids() <=====" );
			return i;
		}
		i++;
	}
	
	info( " check_device_ids: not our device");
	info( "-check_device_ids() <=====" );
	return	-1;
}


static void mii_HPNA_phy_probe( rtl8150_t *rtl8150 )
{
	int	i;
	__u16	tmp;

        /*
	for ( i=0; i < 32; i++ ) 
	{
		read_phy_word( rtl8150, i, MII_PHY_ID2, &tmp );
		tmp = tmp & 0xfff0;
		if( tmp == AMD_PHY_ID ) 
		{
			rtl8150->hpna_phy = AMD_PHY;
			rtl8150->phy = i;
			return;
		}
		else if( tmp == NS_PHY_ID )
		{
			rtl8150->hpna_phy = NS_PHY;
			rtl8150->phy = i;
			return;
		}
		else
			continue;	
	}

	rtl8150->phy = 0;
	rtl8150->hpna_phy = UNKNOWN_PHY;
	*/
}



static void * rtl8150_probe( struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id)
{
	struct net_device *net;
	rtl8150_t *rtl8150;
	int	dev_indx;

	info( "+rtl8150_probe() =====>" );

	///info( " rtl8150_probe: before check_deice_ids()" );
	if ( (dev_indx = check_device_ids(dev->descriptor.idVendor, dev->descriptor.idProduct)) == -1 ) 
	{
		info( " rtl8150_pbobe: this is not my device!" );
		return NULL;
	}
	///info( " rtl8150_probe: after check_device_ids()" );
	

	///info( " rtl8150_probe: before usb_set_configuration()" );
	/// the following is for fixing the bug of 1st-cut, and must be removed in 2nd-cut
	dev->config[0].bConfigurationValue = 1;
	////////////////////////////////////////////////
	if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) 
	{
		err("usb_set_configuration() failed");
		info( " rtl8150_probe: usb_set_configuration() failed" );
		return NULL;
	}
	///info( " rtl8150_probe: after usb_set_configuration()" );

	if(!(rtl8150 = kmalloc(sizeof(struct rtl8150), GFP_KERNEL))) 
	{
		err("out of memory allocating device structure");
		info( " rtl8150_probe: out of memory allocating device structure" );
		return NULL;
	}
	
	/// added by Owen on 01/11/2000
	rtl8150->get_registers_flag = 0;
	rtl8150->set_registers_flag = 0;

	///info( " rtl8150_probe: before usb_inc_dev_use()" );
	usb_inc_dev_use( dev );
	memset(rtl8150, 0, sizeof(struct rtl8150));
	///info( " rtl8150_probe: after usb_inc_dev_use()" );
	
	///info( " rtl8150_probe: before init_MUTEX()" );
	init_MUTEX( &rtl8150-> ctrl_sem );
	///info( " rtl8150_probe: after init_MUTEX()" );
	
	///info( " rtl8150_probe: before init_waitqueue_head()" );
	init_waitqueue_head( &rtl8150->ctrl_wait );
	///info( " rtl8150_probe: after init_waitqueue_head()" );

	///info( " rtl8150_probe: before init_etherdev()" );
	net = init_etherdev( NULL, 0 );
	if ( !net ) 
	{
		kfree( rtl8150 );
		info( " rtl8150_probe: init_etherdev() failed" );
		return	NULL;
	}
	///info( " rtl8150_probe: after init_etherdev()" );
	
	rtl8150->usb = dev;
	rtl8150->net = net;
	net->priv = rtl8150;
	net->open = rtl8150_open;
	net->stop = rtl8150_close;
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,48)
	net->watchdog_timeo = RTL8150_TX_TIMEOUT;
	net->tx_timeout = rtl8150_tx_timeout;
#endif
	net->do_ioctl = rtl8150_ioctl;
	net->hard_start_xmit = rtl8150_start_xmit;
	net->set_multicast_list = rtl8150_set_multicast;
	net->get_stats = rtl8150_netdev_stats;
	net->mtu = RTL8150_MTU;     //  1500

	rtl8150->features = usb_dev_id[dev_indx].private;
	
	///info( " rtl8150_probe: before reset_mac()" );
	if ( reset_mac(rtl8150) ) 
	{
		err("can't reset MAC");
		info( " rtl8150_probe: reset_mac() failed" );
		unregister_netdev( rtl8150->net );
		kfree(rtl8150);
		rtl8150 = NULL;
		return NULL;
	}
	///info( " rtl8150_probe: after reset_mac()" );

	///info( " rtl8150_probe: before set_ethernet_addr()" );
	set_ethernet_addr( rtl8150 );
	///info( " rtl8150_probe: after set_ethernet_addr()" );
	
	if( rtl8150->features & FEATURE_HAS_HOME_PNA )
		mii_HPNA_phy_probe( rtl8150 );
	
	info( "%s: %s", net->name, usb_dev_id[dev_indx].name );

	info( "-rtl8150_probe() <=====" );
	return rtl8150;
}


static void rtl8150_disconnect( struct usb_device *dev, void *ptr )
{
	struct rtl8150 *rtl8150 = ptr;

	info( "+rtl8150_disconnect() =====>" );

	if ( !rtl8150 ) {
		info( " rtl8150_disconnect: unregister non-existant device" );
		warn("unregistering non-existant device");
		return;
	}

	rtl8150->flags |= RTL8150_UNPLUG;
	unregister_netdev( rtl8150->net );
	usb_dec_dev_use( dev );
	kfree( rtl8150 );
	rtl8150 = NULL;
	info( "-rtl8150_disconnect() <=====" );
}


static struct usb_driver rtl8150_driver = {
	name:		"RTL8150",
	probe:		rtl8150_probe,
	disconnect:	rtl8150_disconnect,
};


/// this function is called when "insmod rtl8150.o"
int __init rtl8150_init(void)
{
	int	registerResult;
	
	info( "+rtl8150_init() =====>" );
	info( "%s", version );
        registerResult = usb_register( &rtl8150_driver );
	info( "-rtl8150_init() <=====" );

	return registerResult;
}


/// this funciton is called when "rmmod rtl8150"
void __exit rtl8150_exit(void)
{
	info( "+rtl8150_exit() =====>" );
	usb_deregister( &rtl8150_driver );
	info( "-rtl8150_exit() <=====" );
}

module_init( rtl8150_init );

module_exit( rtl8150_exit );

⌨️ 快捷键说明

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