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

📄 dm9601.c

📁 DM9601 USB网卡linux驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
		dbi->stats.tx_errors++;		if ( (d[0] | d[1]) & 0x84) 	/* EXEC & JABBER */			dbi->stats.tx_aborted_errors++;		if ( (d[0] | d[1]) & 0x10 )	/* LATE COL */			dbi->stats.tx_window_errors++;		if ( (d[0] | d[1]) & 0x60 )	/* NO or LOST CARRIER */			dbi->stats.tx_carrier_errors++;	}}#endifstatic void dm9601_tx_timeout( struct net_device *net ){	dm9601_board_info_t *dbi = net->priv;	if ( !dbi )		return;			warn("%s: Tx timed out.", net->name);	dbi->tx_urb.transfer_flags |= URB_NO_FSBR;//USB_ASYNC_UNLINK;	usb_unlink_urb( &dbi->tx_urb );	dbi->stats.tx_errors++;}static int dm9601_start_xmit( struct sk_buff *skb, struct net_device *net ){	dm9601_board_info_t	*dbi = net->priv;	int 	count = skb->len + 2;	int 	res;	__u16 l16 = skb->len;		netif_stop_queue( net );	if (!(count & 0x3f)) { count++; l16++; }	((__u16 *)dbi->tx_buff)[0] = cpu_to_le16(l16);	memcpy(dbi->tx_buff + 2, skb->data, skb->len);	usb_fill_bulk_urb( &dbi->tx_urb, dbi->usb,			usb_sndbulkpipe(dbi->usb, 2),			dbi->tx_buff, count, 			write_bulk_callback, dbi);	if ((res = usb_submit_urb(&dbi->tx_urb,GFP_KERNEL))) {		warn("failed tx_urb %d", res);		dbi->stats.tx_errors++;		netif_start_queue( net );	} else {		dbi->stats.tx_packets++;		dbi->stats.tx_bytes += skb->len;		net->trans_start = jiffies;	}	dev_kfree_skb(skb);	return 0;}static struct net_device_stats *dm9601_netdev_stats( struct net_device *dev ){	return &((dm9601_board_info_t *)dev->priv)->stats;}static inline void disable_net_traffic( dm9601_board_info_t *dbi ){	__u8 reg5;	write_mii_word(dbi, 1, 0, 0x8000);	/* RESET PHY */	get_registers(dbi, RxControl, 1, &reg5);	reg5 &= 0xfe;	set_register(dbi, RxControl, reg5);	/* RX disable */	set_register(dbi, GeneralPurpose, 0x01);/* PHY power down */}static void set_phy_mode(dm9601_board_info_t *dbi){	__u16	phy_reg0 = 0x1000, phy_reg4 = 0x01e1;	/* PHY media mode setting */	if ( !(dbi->op_mode & DM9601_AUTO) ) {			switch(dbi->op_mode) {			case DM9601_10MHF:  				phy_reg4 = 0x0021; break;			case DM9601_10MFD:  				phy_reg4 = 0x0041; break;			case DM9601_100MHF: 				phy_reg4 = 0x0081; break;			case DM9601_100MFD: 				phy_reg4 = 0x0101; break;			default: 				phy_reg0 = 0x8000; break;		}		write_mii_word(dbi, 1, 4, phy_reg4); /* Set PHY capability */		write_mii_word(dbi, 1, 0, phy_reg0);	}	/* Active PHY */	set_register( dbi, GeneralPurposeCtrl, 0x01 );	/* Let GPIO0 output */	set_register( dbi, GeneralPurpose, 0x00 );	/* Power_on PHY */}/*	Init HomeRun DM9801*/static void program_dm9801(dm9601_board_info_t *dbi, u16 HPNA_rev){	__u16 reg16, reg17, reg24, reg25;	if ( !nfloor ) nfloor = DM9801_NOISE_FLOOR;	read_mii_word(dbi, 1, 16, &reg16);	read_mii_word(dbi, 1, 17, &reg17);	read_mii_word(dbi, 1, 24, &reg24);	read_mii_word(dbi, 1, 25, &reg25);	switch(HPNA_rev) {	case 0xb900: /* DM9801 E3 */		reg16 |= 0x1000;		reg25 = ( (reg24 + nfloor) & 0x00ff) | 0xf000;		break;	case 0xb901: /* DM9801 E4 */		reg25 = ( (reg24 + nfloor) & 0x00ff) | 0xc200;		reg17 = (reg17 & 0xfff0) + nfloor + 3;		break;	case 0xb902: /* DM9801 E5 */	case 0xb903: /* DM9801 E6 */	default:		reg16 |= 0x1000;		reg25 = ( (reg24 + nfloor - 3) & 0x00ff) | 0xc200;		reg17 = (reg17 & 0xfff0) + nfloor;		break;	}	write_mii_word(dbi, 1, 16, reg16);	write_mii_word(dbi, 1, 17, reg17);	write_mii_word(dbi, 1, 25, reg25);}/*	Init LongRun DM9802*/static void program_dm9802(dm9601_board_info_t *dbi){	__u16 reg25;	if ( !nfloor ) nfloor = DM9802_NOISE_FLOOR;	read_mii_word(dbi, 1, 25, &reg25);	reg25 = (reg25 & 0xff00) + nfloor;	write_mii_word(dbi, 1, 25, reg25);}/*	Identify NIC type*/static void identify_nic(dm9601_board_info_t* dbi){	__u16	phy_tmp;	/* Select EXT_MII */	dbi->net_ctrl_reg |= 0x80;	set_register(dbi, NetworkCtrl, dbi->net_ctrl_reg);	/* EXT-MII */	read_mii_word(dbi, 1, 3, &phy_tmp);	switch(phy_tmp & 0xfff0) {	case 0xb900:		read_mii_word(dbi, 1, 31, &phy_tmp);		if (phy_tmp == 0x4404) { 			dbi->nic_type =  HOMERUN_NIC;			program_dm9801(dbi, phy_tmp);		} else {			dbi->nic_type = LONGRUN_NIC;			program_dm9802(dbi);		}		break;	default:		dbi->nic_type = FASTETHER_NIC;	}	/* Select INT_MII */	dbi->net_ctrl_reg &= ~0x80;	set_register(dbi, NetworkCtrl, dbi->net_ctrl_reg);}static void init_dm9601(struct net_device *net){	dm9601_board_info_t *dbi = (dm9601_board_info_t *)net->priv;	/* User passed argument */	dbi->rx_ctrl_reg = reg5 | 0x01;	dbi->net_ctrl_reg = 0x00;	dbi->reg08 = reg8;	dbi->reg09 = reg9;	dbi->reg0a = rega;	/* RESET device */	set_register(dbi, NetworkCtrl, 0x01);	/* Reset */	udelay(100);	/* NIC type: FASTETHER, HOMERUN, LONGRUN */	identify_nic(dbi);	/* Set PHY */	dbi->op_mode = dm9601_mode;	set_phy_mode(dbi);	/* MII selection */	if ( 	(dbi->nic_type != FASTETHER_NIC) && 		(dbi->op_mode == DM9601_1M_HPNA) 	)		dbi->net_ctrl_reg |= 0x80;	/* Program operating register */	set_register(dbi, NetworkCtrl, dbi->net_ctrl_reg);	set_register(dbi, BackPressureThresh, dbi->reg08);	set_register(dbi, FlowControlThresh, dbi->reg09);	set_register(dbi, RxFlowControl, dbi->reg0a);	set_register(dbi, USBControl, 0x26);	/* Reset EP1/EP2, INT always return */	set_registers(dbi, PhysicalAddr, 0x06, net->dev_addr); /*  MAC addr */	dbi->hash_table[3] = 0x8000;	/* Broadcast Address */	set_registers(dbi, MulticastAddr, 0x08, dbi->hash_table); /*  Hash Table */	set_register(dbi, RxControl, dbi->rx_ctrl_reg); /* Active RX */}static int dm9601_open(struct net_device *net){	dm9601_board_info_t *dbi = (dm9601_board_info_t *)net->priv;	int	res;	int owner;	down(&dbi->ctrl_sem);	owner = try_module_get(net->class_dev.class->owner); 	usb_fill_bulk_urb( &dbi->rx_urb, dbi->usb,			usb_rcvbulkpipe(dbi->usb, 1),			dbi->rx_buff, DM9601_MAX_MTU, 			read_bulk_callback, dbi );	if ( (res = usb_submit_urb(&dbi->rx_urb,GFP_ATOMIC)) )		warn("%s: failed rx_urb %d",__FUNCTION__,res);	dbi->rx_buf_flag = 1;#ifdef	DM9601_USE_INTR	usb_fill_int_urb( &dbi->intr_urb, dbi->usb,			usb_rcvintpipe(dbi->usb, 3),			dbi->intr_buff, sizeof(dbi->intr_buff),			intr_callback, dbi, dbi->intr_interval );	if ( (res = usb_submit_urb(&dbi->intr_urb,GFP_ATOMIC)) )		warn("%s: failed intr_urb %d",__FUNCTION__,res);#endif	init_dm9601(net);	netif_start_queue( net );	dbi->flags |= DM9601_RUNNING;	up(&dbi->ctrl_sem);	return 0;}static int dm9601_close( struct net_device *net ){	dm9601_board_info_t	*dbi = net->priv;	dbi->flags &= ~DM9601_RUNNING;	netif_stop_queue(net);	if ( !(dbi->flags & DM9601_UNPLUG) )		disable_net_traffic(dbi);	usb_unlink_urb(&dbi->rx_urb);	usb_unlink_urb(&dbi->tx_urb);	usb_unlink_urb(&dbi->ctrl_urb);#ifdef	DM9601_USE_INTR	usb_unlink_urb(&dbi->intr_urb);#endif	module_put(net->class_dev.class->owner); #ifdef STS_DBUG	printk("<DM9601> rx errors: %lx \n", dbi->stats.rx_errors);	printk("<DM9601> fifo over errors: %lx \n", dbi->stats.rx_fifo_errors);	printk("<DM9601> crc errors: %lx \n", dbi->stats.rx_crc_errors);	printk("<DM9601> alignment errors: %lx \n", dbi->stats.rx_frame_errors);	printk("<DM9601> physical layer errors: %lx \n", dbi->rx_ple_errors);	printk("<DM9601> watchdog errors: %lx \n", dbi->rx_wdt_errors);	printk("<DM9601> late collision errors: %lx \n", dbi->rx_lc_errors);	printk("<DM9601> runt frame errors: %lx \n", dbi->rx_runtf_errors);	printk("<DM9601> long frame errors: %lx \n", dbi->rx_longf_errors);#endif	return 0;}static int dm9601_ioctl( struct net_device *net, struct ifreq *rq, int cmd ){	__u16 *data = (__u16 *)&rq->ifr_data;	dm9601_board_info_t	*dbi = net->priv;	switch(cmd) {		case SIOCDEVPRIVATE:			data[0] = dbi->phy;		case SIOCDEVPRIVATE+1:			read_mii_word(dbi, data[0], data[1]&0x1f, &data[3]);			return 0;		case SIOCDEVPRIVATE+2:			if ( !capable(CAP_NET_ADMIN) )				return -EPERM;			write_mii_word(dbi, dbi->phy, data[1] & 0x1f, data[2]);			return 0;		default:			return -EOPNOTSUPP;	}}/*  Calculate the CRC valude of the Rx packet  flag = 1 : return the reverse CRC (for the received packet CRC)         0 : return the normal CRC (for Hash Table index)*/static unsigned long cal_CRC(unsigned char * Data, unsigned int Len, u8 flag){   u32 crc = ether_crc_le(Len, Data);      if (flag) 	   return ~crc;      return crc;}static void dm9601_set_multicast( struct net_device *net ){	dm9601_board_info_t *dbi = net->priv;	struct dev_mc_list *mcptr = net->mc_list;	int count = net->mc_count, i, hash_val;	netif_stop_queue(net);	if (net->flags & IFF_PROMISC) {		dbi->rx_ctrl_reg |= RX_PROMISCUOUS;		info("%s: Promiscuous mode enabled", net->name);	} else if (net->flags & IFF_ALLMULTI) {		dbi->rx_ctrl_reg |= RX_PASS_MULTICAST;		dbi->rx_ctrl_reg &= ~RX_PROMISCUOUS;		info("%s set allmulti", net->name);	} else {		dbi->rx_ctrl_reg &= ~RX_PASS_MULTICAST;		dbi->rx_ctrl_reg &= ~RX_PROMISCUOUS;		/* Clear Hash Table */		for (i = 0; i < 4; i++) dbi->hash_table[i] = 0;		/* Set Broadcast Address */		dbi->hash_table[3] = 0x8000;		/* the multicast address in Hash Table : 64 bits */		for (i = 0; i < count; i++, mcptr = mcptr->next) {			hash_val = cal_CRC((char *)mcptr->dmi_addr, 6, 0) & 0x3f; 			dbi->hash_table[hash_val / 16] |= (u16) 1 << (hash_val % 16);		}		info("%s: set Rx mode", net->name);	}	dbi->flags |= HASH_REGS_CHANGE | RX_CTRL_CHANGE;	ctrl_callback(&dbi->ctrl_urb, NULL);	netif_wake_queue(net);}static int dm9601_probe( struct usb_interface *udev, const struct usb_device_id *id){	struct net_device	*net;	dm9601_board_info_t	*dbi;	int dev_index = id - dm9601_ids;	struct usb_device *dev = interface_to_usbdev (udev);		int status;		if(!(dbi = kmalloc(sizeof(dm9601_board_info_t), GFP_KERNEL))) {		err("out of memory allocating device structure");		return -ENOMEM;	}//	printk("dev_index %d dbi %x\n",dev_index,dbi);	usb_get_dev(dev);	memset(dbi, 0, sizeof(dm9601_board_info_t));	// initialize dbi struct	usb_init_urb(&dbi->ctrl_urb);	usb_init_urb(&dbi->rx_urb);	usb_init_urb(&dbi->tx_urb);	usb_init_urb(&dbi->intr_urb);	usb_init_urb(&dbi->dump_urb);	dbi->dev_index = dev_index;	init_waitqueue_head( &dbi->ctrl_wait );	net = alloc_etherdev(0);	if ( !net ) {		kfree( dbi );		return	-ENOMEM;	}		init_MUTEX(&dbi->ctrl_sem);	down(&dbi->ctrl_sem);	dbi->usb = dev;	dbi->net = net;	net->priv = dbi;	net->open = dm9601_open;	net->stop = dm9601_close;	net->watchdog_timeo = DM9601_TX_TIMEOUT;	net->tx_timeout = dm9601_tx_timeout;	net->do_ioctl = dm9601_ioctl;	net->hard_start_xmit = dm9601_start_xmit;	net->set_multicast_list = dm9601_set_multicast;	net->get_stats = dm9601_netdev_stats;	net->mtu = DM9601_MTU;	dbi->intr_interval = 0xff;	/* Default is 0x80 */	/* Get Node Address */	read_eprom_word(dbi, 0, (__u16 *)net->dev_addr);	read_eprom_word(dbi, 1, (__u16 *)(net->dev_addr + 2));	read_eprom_word(dbi, 2, (__u16 *)(net->dev_addr + 4));	dbi->features = usb_dev_id[dev_index].private;	info( "%s: %s", net->name, usb_dev_id[dev_index].name );		usb_set_intfdata (udev, dbi);	SET_NETDEV_DEV(net, &udev->dev);	status = register_netdev (net);	up(&dbi->ctrl_sem);	if (status)		return status;	// start as if the link is up	netif_device_attach (net);			return 0;	}static void dm9601_disconnect( struct usb_interface *intf){	dm9601_board_info_t *dbi;	struct usb_device *dev;	dev = interface_to_usbdev (intf);	dbi = usb_get_intfdata(intf);	if ( !dbi ) {		warn("unregistering non-existant device");		return;	}	dbi->flags |= DM9601_UNPLUG;	unregister_netdev( dbi->net );	usb_put_dev(dev);	kfree( dbi );	dbi = NULL;}static struct usb_driver dm9601_driver = {	name:		"dm9601",	probe:		dm9601_probe,	disconnect:	dm9601_disconnect,	id_table:	dm9601_ids,};int __init dm9601_init(void){	info( "%s", version ); 	switch(mode) {   		case DM9601_10MHF:		case DM9601_100MHF:		case DM9601_10MFD:		case DM9601_100MFD:		case DM9601_1M_HPNA:			dm9601_mode = mode;			break;		default:			dm9601_mode = DM9601_AUTO;	}	nfloor = (nfloor > 15) ? 0:nfloor;	return usb_register( &dm9601_driver );}void __exit dm9601_exit(void){	usb_deregister( &dm9601_driver );}module_init( dm9601_init );module_exit( dm9601_exit );

⌨️ 快捷键说明

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