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

📄 pegasus.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	struct sk_buff	*skb;	__u16 pkt_len;	if ( !pegasus || !(pegasus->flags & PEGASUS_RUNNING) )		return;	net = pegasus->net;	if ( !netif_device_present(net) )		return;	if ( pegasus->flags & PEGASUS_RX_BUSY ) {		pegasus->stats.rx_errors++;		dbg("pegasus Rx busy");		return;	}	pegasus->flags |= PEGASUS_RX_BUSY;	switch ( urb->status ) {		case USB_ST_NOERROR:			break;		case USB_ST_NORESPONSE:			dbg( "reset MAC" );			pegasus->flags &= ~PEGASUS_RX_BUSY;			break;		default:			dbg( "%s: RX status %d", net->name, urb->status );			goto goon;	}	if ( !count )		goto goon;	rx_status = *(int *)(pegasus->rx_buff + count - 4);	if ( rx_status & 0x000e0000 ) {		dbg("%s: RX packet error %x", net->name, rx_status & 0xe0000);		pegasus->stats.rx_errors++;		if ( rx_status & 0x060000 )			pegasus->stats.rx_length_errors++;		if ( rx_status & 0x080000 )			pegasus->stats.rx_crc_errors++;		if ( rx_status & 0x100000 )			pegasus->stats.rx_frame_errors++;		goto goon;	}	pkt_len = (rx_status & 0xfff) - 8;	if ( !(skb = dev_alloc_skb(pkt_len+2)) )		goto goon;	skb->dev = net;	skb_reserve(skb, 2);	eth_copy_and_sum(skb, pegasus->rx_buff, pkt_len, 0);	skb_put(skb, pkt_len);	skb->protocol = eth_type_trans(skb, net);	netif_rx(skb);	pegasus->stats.rx_packets++;	pegasus->stats.rx_bytes += pkt_len;goon:	FILL_BULK_URB( &pegasus->rx_urb, pegasus->usb,			usb_rcvbulkpipe(pegasus->usb, 1),			pegasus->rx_buff, PEGASUS_MAX_MTU, 			read_bulk_callback, pegasus );	if ( (res = usb_submit_urb(&pegasus->rx_urb)) )		warn( __FUNCTION__ " failed submint rx_urb %d", res);	pegasus->flags &= ~PEGASUS_RX_BUSY;}static void write_bulk_callback( struct urb *urb ){	pegasus_t *pegasus = urb->context;	if ( !pegasus || !(pegasus->flags & PEGASUS_RUNNING) )		return;	if ( !netif_device_present(pegasus->net) )		return;			if ( urb->status )		info("%s: TX status %d", pegasus->net->name, urb->status);	pegasus->net->trans_start = jiffies;	netif_wake_queue( pegasus->net );}#ifdef	PEGASUS_USE_INTRstatic void intr_callback( struct urb *urb ){	pegasus_t *pegasus = urb->context;	struct net_device *net;	__u8	*d;	if ( !pegasus )		return;			switch ( urb->status ) {		case USB_ST_NOERROR:			break;		case USB_ST_URB_KILLED:			return;		default:			info("intr status %d", urb->status);	}	d = urb->transfer_buffer;	net = pegasus->net;	if ( d[0] & 0xfc ) {		pegasus->stats.tx_errors++;		if ( d[0] & TX_UNDERRUN )			pegasus->stats.tx_fifo_errors++;		if ( d[0] & (EXCESSIVE_COL | JABBER_TIMEOUT) )			pegasus->stats.tx_aborted_errors++;		if ( d[0] & LATE_COL )			pegasus->stats.tx_window_errors++;		if ( d[0] & (NO_CARRIER | LOSS_CARRIER) )			pegasus->stats.tx_carrier_errors++;	}}#endif#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,48)static void pegasus_tx_timeout( struct net_device *net ){	pegasus_t *pegasus = net->priv;	if ( !pegasus )		return;			warn("%s: Tx timed out.", net->name);	pegasus->tx_urb.transfer_flags |= USB_ASYNC_UNLINK;	usb_unlink_urb( &pegasus->tx_urb );	pegasus->stats.tx_errors++;}#endifstatic int pegasus_start_xmit( struct sk_buff *skb, struct net_device *net ){	pegasus_t	*pegasus = net->priv;	int 	count = ((skb->len+2) & 0x3f) ? skb->len+2 : skb->len+3;	int 	res;	netif_stop_queue( net );			((__u16 *)pegasus->tx_buff)[0] = skb->len;	memcpy(pegasus->tx_buff+2, skb->data, skb->len);	FILL_BULK_URB( &pegasus->tx_urb, pegasus->usb,			usb_sndbulkpipe(pegasus->usb, 2),			pegasus->tx_buff, PEGASUS_MAX_MTU, 			write_bulk_callback, pegasus );	pegasus->tx_urb.transfer_buffer_length = count;	if ((res = usb_submit_urb(&pegasus->tx_urb))) {		warn("failed tx_urb %d", res);		pegasus->stats.tx_errors++;		netif_start_queue( net );	} else {		pegasus->stats.tx_packets++;		pegasus->stats.tx_bytes += skb->len;		net->trans_start = jiffies;	}	dev_kfree_skb(skb);	return 0;}static struct net_device_stats *pegasus_netdev_stats( struct net_device *dev ){	return &((pegasus_t *)dev->priv)->stats;}static inline void disable_net_traffic( pegasus_t *pegasus ){	int 	tmp=0;	set_registers( pegasus, EthCtrl0, 2, &tmp );}static inline void get_interrupt_interval( pegasus_t *pegasus ){	__u8	data[2];	read_eprom_word( pegasus, 4, (__u16 *)data );	if ( data[1] < 0x80 ) {		info( "intr interval will be changed from %ums to %ums",		     data[1], 0x80 );		data[1] = 0x80;#ifdef	PEGASUS_WRITE_EEPROM		write_eprom_word( pegasus, 4, *(__u16 *)data );#endif	}	pegasus->intr_interval = data[1];}static int pegasus_open(struct net_device *net){	pegasus_t *pegasus = (pegasus_t *)net->priv;	int	res;	MOD_INC_USE_COUNT;	if ( (res = enable_net_traffic(net, pegasus->usb)) ) {		err("can't enable_net_traffic() - %d", res);		MOD_DEC_USE_COUNT;		return -EIO;	}	FILL_BULK_URB( &pegasus->rx_urb, pegasus->usb,			usb_rcvbulkpipe(pegasus->usb, 1),			pegasus->rx_buff, PEGASUS_MAX_MTU, 			read_bulk_callback, pegasus );	if ( (res = usb_submit_urb(&pegasus->rx_urb)) )		warn( __FUNCTION__ " failed rx_urb %d", res );#ifdef	PEGASUS_USE_INTR	FILL_INT_URB( &pegasus->intr_urb, pegasus->usb,			usb_rcvintpipe(pegasus->usb, 3),			pegasus->intr_buff, sizeof(pegasus->intr_buff),			intr_callback, pegasus, pegasus->intr_interval );	if ( (res = usb_submit_urb(&pegasus->intr_urb)) )		warn( __FUNCTION__ " failed intr_urb %d", res);#endif	netif_start_queue( net );	pegasus->flags |= PEGASUS_RUNNING;	return 0;}static int pegasus_close( struct net_device *net ){	pegasus_t	*pegasus = net->priv;	pegasus->flags &= ~PEGASUS_RUNNING;	netif_stop_queue( net );	if ( !(pegasus->flags & PEGASUS_UNPLUG) )		disable_net_traffic( pegasus );	usb_unlink_urb( &pegasus->rx_urb );	usb_unlink_urb( &pegasus->tx_urb );	usb_unlink_urb( &pegasus->ctrl_urb );#ifdef	PEGASUS_USE_INTR	usb_unlink_urb( &pegasus->intr_urb );#endif	MOD_DEC_USE_COUNT;	return 0;}static int pegasus_ioctl( struct net_device *net, struct ifreq *rq, int cmd ){	__u16 *data = (__u16 *)&rq->ifr_data;	pegasus_t	*pegasus = net->priv;	switch(cmd) {		case SIOCDEVPRIVATE:			data[0] = pegasus->phy;		case SIOCDEVPRIVATE+1:			read_mii_word(pegasus, data[0], data[1]&0x1f, &data[3]);			return 0;		case SIOCDEVPRIVATE+2:			if ( !capable(CAP_NET_ADMIN) )				return -EPERM;			write_mii_word(pegasus, pegasus->phy, data[1] & 0x1f, data[2]);			return 0;		default:			return -EOPNOTSUPP;	}}static void pegasus_set_multicast( struct net_device *net ){	pegasus_t *pegasus = net->priv;	netif_stop_queue(net);	if (net->flags & IFF_PROMISC) {		pegasus->eth_regs[EthCtrl2] |= RX_PROMISCUOUS;		info("%s: Promiscuous mode enabled", net->name);	} else if ((net->mc_count > multicast_filter_limit) ||			(net->flags & IFF_ALLMULTI)) {		pegasus->eth_regs[EthCtrl0] |= RX_MULTICAST;		pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS;		info("%s set allmulti", net->name);	} else {		pegasus->eth_regs[EthCtrl0] &= ~RX_MULTICAST;		pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS;		info("%s: set Rx mode", net->name);	}	pegasus->flags |= ETH_REGS_CHANGE;	ctrl_callback( &pegasus->ctrl_urb );	netif_wake_queue(net);}static __u8 mii_phy_probe( pegasus_t *pegasus ){	int	i;	__u16	tmp;	for ( i=0; i < 32; i++ ) {		read_mii_word( pegasus, i, MII_BMSR, &tmp );		if ( tmp == 0 || tmp == 0xffff || (tmp & BMSR_MEDIA) == 0 )			continue;		else			return	i;	}	return	0xff;}static inline void setup_pegasus_II( pegasus_t *pegasus ){	set_register( pegasus, Reg1d, 0 );	set_register( pegasus, Reg7b, 2 );	if ( pegasus->features & HAS_HOME_PNA  && mii_mode )		set_register( pegasus, Reg81, 6 );	else		set_register( pegasus, Reg81, 2 );}static void * pegasus_probe( struct usb_device *dev, unsigned int ifnum,			     const struct usb_device_id *id){	struct net_device	*net;	pegasus_t		*pegasus;	int			dev_index = id - pegasus_ids;	if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) {		err("usb_set_configuration() failed");		return NULL;	}	if(!(pegasus = kmalloc(sizeof(struct pegasus), GFP_KERNEL))) {		err("out of memory allocating device structure");		return NULL;	}	usb_inc_dev_use( dev );	memset(pegasus, 0, sizeof(struct pegasus));	pegasus->dev_index = dev_index;	init_waitqueue_head( &pegasus->ctrl_wait );	net = init_etherdev( NULL, 0 );	if ( !net ) {		kfree( pegasus );		return	NULL;	}		pegasus->usb = dev;	pegasus->net = net;	net->priv = pegasus;	net->open = pegasus_open;	net->stop = pegasus_close;#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,48)	net->watchdog_timeo = PEGASUS_TX_TIMEOUT;	net->tx_timeout = pegasus_tx_timeout;#endif	net->do_ioctl = pegasus_ioctl;	net->hard_start_xmit = pegasus_start_xmit;	net->set_multicast_list = pegasus_set_multicast;	net->get_stats = pegasus_netdev_stats;	net->mtu = PEGASUS_MTU;	pegasus->features = usb_dev_id[dev_index].private;#ifdef	PEGASUS_USE_INTR	get_interrupt_interval( pegasus );#endif	if ( reset_mac(pegasus) ) {		err("can't reset MAC");		unregister_netdev( pegasus->net );		kfree(pegasus);		pegasus = NULL;		return NULL;	}	info( "%s: %s", net->name, usb_dev_id[dev_index].name );	set_ethernet_addr( pegasus );	if ( pegasus->features & PEGASUS_II ) {		info( "setup Pegasus II specific registers" );		setup_pegasus_II( pegasus );	}		pegasus->phy = mii_phy_probe( pegasus );	if ( pegasus->phy == 0xff ) {		warn( "can't locate MII phy, using default" );		pegasus->phy = 1;	}	return pegasus;}static void pegasus_disconnect( struct usb_device *dev, void *ptr ){	struct pegasus *pegasus = ptr;	if ( !pegasus ) {		warn("unregistering non-existant device");		return;	}	pegasus->flags |= PEGASUS_UNPLUG;	unregister_netdev( pegasus->net );	usb_dec_dev_use( dev );	kfree( pegasus );	pegasus = NULL;}static struct usb_driver pegasus_driver = {	name:		"pegasus",	probe:		pegasus_probe,	disconnect:	pegasus_disconnect,	id_table:	pegasus_ids,};int __init pegasus_init(void){	info( "%s", version );	return usb_register( &pegasus_driver );}void __exit pegasus_exit(void){	usb_deregister( &pegasus_driver );}module_init( pegasus_init );module_exit( pegasus_exit );

⌨️ 快捷键说明

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