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

📄 pegasus.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
				ret = set_register(pegasus, Gpio1, 0x26);			ret = set_register(pegasus, Gpio0, pegasus->features);			ret = set_register(pegasus, Gpio0, DEFAULT_GPIO_SET);			break;		}	}	if (i == REG_TIMEOUT)		return 1;	if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS ||	    usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK) {		ret = set_register(pegasus, Gpio0, 0x24);		ret = set_register(pegasus, Gpio0, 0x26);	}	if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_ELCON) {		__u16 auxmode;		read_mii_word(pegasus, 3, 0x1b, &auxmode);		write_mii_word(pegasus, 3, 0x1b, auxmode | 4);	}	return 0;}static int enable_net_traffic(struct net_device *dev, struct usb_device *usb){	__u16 linkpart;	__u8 data[4];	pegasus_t *pegasus = netdev_priv(dev);	int ret;	read_mii_word(pegasus, pegasus->phy, MII_LPA, &linkpart);	data[0] = 0xc9;	data[1] = 0;	if (linkpart & (ADVERTISE_100FULL | ADVERTISE_10FULL))		data[1] |= 0x20;	/* set full duplex */	if (linkpart & (ADVERTISE_100FULL | ADVERTISE_100HALF))		data[1] |= 0x10;	/* set 100 Mbps */	if (mii_mode)		data[1] = 0;	data[2] = (loopback & 1) ? 0x09 : 0x01;	memcpy(pegasus->eth_regs, data, sizeof (data));	ret = set_registers(pegasus, EthCtrl0, 3, data);	if (usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS ||	    usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK) {		u16 auxmode;		read_mii_word(pegasus, 0, 0x1b, &auxmode);		write_mii_word(pegasus, 0, 0x1b, auxmode | 4);	}	return 0;}static void fill_skb_pool(pegasus_t * pegasus){	int i;	for (i = 0; i < RX_SKBS; i++) {		if (pegasus->rx_pool[i])			continue;		pegasus->rx_pool[i] = dev_alloc_skb(PEGASUS_MTU + 2);		/*		 ** we give up if the allocation fail. the tasklet will be		 ** rescheduled again anyway...		 */		if (pegasus->rx_pool[i] == NULL)			return;		pegasus->rx_pool[i]->dev = pegasus->net;		skb_reserve(pegasus->rx_pool[i], 2);	}}static void free_skb_pool(pegasus_t * pegasus){	int i;	for (i = 0; i < RX_SKBS; i++) {		if (pegasus->rx_pool[i]) {			dev_kfree_skb(pegasus->rx_pool[i]);			pegasus->rx_pool[i] = NULL;		}	}}static inline struct sk_buff *pull_skb(pegasus_t * pegasus){	int i;	struct sk_buff *skb;	for (i = 0; i < RX_SKBS; i++) {		if (likely(pegasus->rx_pool[i] != NULL)) {			skb = pegasus->rx_pool[i];			pegasus->rx_pool[i] = NULL;			return skb;		}	}	return NULL;}static void read_bulk_callback(struct urb *urb, struct pt_regs *regs){	pegasus_t *pegasus = urb->context;	struct net_device *net;	int rx_status, count = urb->actual_length;	u8 *buf = urb->transfer_buffer;	__u16 pkt_len;	if (!pegasus)		return;	net = pegasus->net;	if (!netif_device_present(net) || !netif_running(net))		return;	switch (urb->status) {	case 0:		break;	case -ETIMEDOUT:		if (netif_msg_rx_err(pegasus))			pr_debug("%s: reset MAC\n", net->name);		pegasus->flags &= ~PEGASUS_RX_BUSY;		break;	case -EPIPE:		/* stall, or disconnect from TT */		/* FIXME schedule work to clear the halt */		if (netif_msg_rx_err(pegasus))			printk(KERN_WARNING "%s: no rx stall recovery\n",					net->name);		return;	case -ENOENT:	case -ECONNRESET:	case -ESHUTDOWN:		if (netif_msg_ifdown(pegasus))			pr_debug("%s: rx unlink, %d\n", net->name, urb->status);		return;	default:		if (netif_msg_rx_err(pegasus))			pr_debug("%s: RX status %d\n", net->name, urb->status);		goto goon;	}	if (!count || count < 4)		goto goon;	rx_status = buf[count - 2];	if (rx_status & 0x1e) {		if (netif_msg_rx_err(pegasus))			pr_debug("%s: RX packet error %x\n",					net->name, rx_status);		pegasus->stats.rx_errors++;		if (rx_status & 0x06)	// long or runt			pegasus->stats.rx_length_errors++;		if (rx_status & 0x08)			pegasus->stats.rx_crc_errors++;		if (rx_status & 0x10)	// extra bits			pegasus->stats.rx_frame_errors++;		goto goon;	}	if (pegasus->chip == 0x8513) {		pkt_len = le32_to_cpu(*(__le32 *)urb->transfer_buffer);		pkt_len &= 0x0fff;		pegasus->rx_skb->data += 2;	} else {		pkt_len = buf[count - 3] << 8;		pkt_len += buf[count - 4];		pkt_len &= 0xfff;		pkt_len -= 8;	}	/*	 * If the packet is unreasonably long, quietly drop it rather than	 * kernel panicing by calling skb_put.	 */	if (pkt_len > PEGASUS_MTU)		goto goon;	/*	 * at this point we are sure pegasus->rx_skb != NULL	 * so we go ahead and pass up the packet.	 */	skb_put(pegasus->rx_skb, pkt_len);	pegasus->rx_skb->protocol = eth_type_trans(pegasus->rx_skb, net);	netif_rx(pegasus->rx_skb);	pegasus->stats.rx_packets++;	pegasus->stats.rx_bytes += pkt_len;	if (pegasus->flags & PEGASUS_UNPLUG)		return;	spin_lock(&pegasus->rx_pool_lock);	pegasus->rx_skb = pull_skb(pegasus);	spin_unlock(&pegasus->rx_pool_lock);	if (pegasus->rx_skb == NULL)		goto tl_sched;goon:	usb_fill_bulk_urb(pegasus->rx_urb, pegasus->usb,			  usb_rcvbulkpipe(pegasus->usb, 1),			  pegasus->rx_skb->data, PEGASUS_MTU + 8,			  read_bulk_callback, pegasus);	if (usb_submit_urb(pegasus->rx_urb, GFP_ATOMIC)) {		pegasus->flags |= PEGASUS_RX_URB_FAIL;		goto tl_sched;	} else {		pegasus->flags &= ~PEGASUS_RX_URB_FAIL;	}	return;tl_sched:	tasklet_schedule(&pegasus->rx_tl);}static void rx_fixup(unsigned long data){	pegasus_t *pegasus;	unsigned long flags;	pegasus = (pegasus_t *) data;	if (pegasus->flags & PEGASUS_UNPLUG)		return;	spin_lock_irqsave(&pegasus->rx_pool_lock, flags);	fill_skb_pool(pegasus);	if (pegasus->flags & PEGASUS_RX_URB_FAIL)		if (pegasus->rx_skb)			goto try_again;	if (pegasus->rx_skb == NULL) {		pegasus->rx_skb = pull_skb(pegasus);	}	if (pegasus->rx_skb == NULL) {		if (netif_msg_rx_err(pegasus))			printk(KERN_WARNING "%s: low on memory\n",					pegasus->net->name);		tasklet_schedule(&pegasus->rx_tl);		goto done;	}	usb_fill_bulk_urb(pegasus->rx_urb, pegasus->usb,			  usb_rcvbulkpipe(pegasus->usb, 1),			  pegasus->rx_skb->data, PEGASUS_MTU + 8,			  read_bulk_callback, pegasus);try_again:	if (usb_submit_urb(pegasus->rx_urb, GFP_ATOMIC)) {		pegasus->flags |= PEGASUS_RX_URB_FAIL;		tasklet_schedule(&pegasus->rx_tl);	} else {		pegasus->flags &= ~PEGASUS_RX_URB_FAIL;	}done:	spin_unlock_irqrestore(&pegasus->rx_pool_lock, flags);}static void write_bulk_callback(struct urb *urb, struct pt_regs *regs){	pegasus_t *pegasus = urb->context;	struct net_device *net = pegasus->net;	if (!pegasus)		return;	if (!netif_device_present(net) || !netif_running(net))		return;	switch (urb->status) {	case -EPIPE:		/* FIXME schedule_work() to clear the tx halt */		netif_stop_queue(net);		if (netif_msg_tx_err(pegasus))			printk(KERN_WARNING "%s: no tx stall recovery\n",					net->name);		return;	case -ENOENT:	case -ECONNRESET:	case -ESHUTDOWN:		if (netif_msg_ifdown(pegasus))			pr_debug("%s: tx unlink, %d\n", net->name, urb->status);		return;	default:		if (netif_msg_tx_err(pegasus))			pr_info("%s: TX status %d\n", net->name, urb->status);		/* FALL THROUGH */	case 0:		break;	}	net->trans_start = jiffies;	netif_wake_queue(net);}static void intr_callback(struct urb *urb, struct pt_regs *regs){	pegasus_t *pegasus = urb->context;	struct net_device *net;	int status;	if (!pegasus)		return;	net = pegasus->net;	switch (urb->status) {	case 0:		break;	case -ECONNRESET:	/* unlink */	case -ENOENT:	case -ESHUTDOWN:		return;	default:		/* some Pegasus-I products report LOTS of data		 * toggle errors... avoid log spamming		 */		if (netif_msg_timer(pegasus))			pr_debug("%s: intr status %d\n", net->name,					urb->status);	}	if (urb->actual_length >= 6) {		u8	* d = urb->transfer_buffer;		/* byte 0 == tx_status1, reg 2B */		if (d[0] & (TX_UNDERRUN|EXCESSIVE_COL					|LATE_COL|JABBER_TIMEOUT)) {			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++;		}		/* d[5].LINK_STATUS lies on some adapters.		 * d[0].NO_CARRIER kicks in only with failed TX.		 * ... so monitoring with MII may be safest.		 */		if (d[0] & NO_CARRIER)			netif_carrier_off(net);			else			netif_carrier_on(net);		/* bytes 3-4 == rx_lostpkt, reg 2E/2F */		pegasus->stats.rx_missed_errors += ((d[3] & 0x7f) << 8) | d[4];	}	status = usb_submit_urb(urb, SLAB_ATOMIC);	if (status && netif_msg_timer(pegasus))		printk(KERN_ERR "%s: can't resubmit interrupt urb, %d\n",				net->name, status);}static void pegasus_tx_timeout(struct net_device *net){	pegasus_t *pegasus = netdev_priv(net);	if (netif_msg_timer(pegasus))		printk(KERN_WARNING "%s: tx timeout\n", net->name);	usb_unlink_urb(pegasus->tx_urb);	pegasus->stats.tx_errors++;}static int pegasus_start_xmit(struct sk_buff *skb, struct net_device *net){	pegasus_t *pegasus = netdev_priv(net);	int count = ((skb->len + 2) & 0x3f) ? skb->len + 2 : skb->len + 3;	int res;	__u16 l16 = skb->len;	netif_stop_queue(net);	((__le16 *) pegasus->tx_buff)[0] = cpu_to_le16(l16);	memcpy(pegasus->tx_buff + 2, skb->data, skb->len);	usb_fill_bulk_urb(pegasus->tx_urb, pegasus->usb,			  usb_sndbulkpipe(pegasus->usb, 2),			  pegasus->tx_buff, count,			  write_bulk_callback, pegasus);	if ((res = usb_submit_urb(pegasus->tx_urb, GFP_ATOMIC))) {		if (netif_msg_tx_err(pegasus))			printk(KERN_WARNING "%s: fail tx, %d\n",					net->name, res);		switch (res) {		case -EPIPE:		/* stall, or disconnect from TT */			/* cleanup should already have been scheduled */			break;		case -ENODEV:		/* disconnect() upcoming */			break;		default:			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 *) netdev_priv(dev))->stats;}static inline void disable_net_traffic(pegasus_t * pegasus){	int tmp = 0;	int ret;	ret = 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 (pegasus->usb->speed != USB_SPEED_HIGH) {		if (data[1] < 0x80) {			if (netif_msg_timer(pegasus))				dev_info(&pegasus->intf->dev, "intr interval "					"changed from %ums to %ums\n",					data[1], 0x80);			data[1] = 0x80;#ifdef PEGASUS_WRITE_EEPROM			write_eprom_word(pegasus, 4, *(__u16 *) data);#endif		}	}	pegasus->intr_interval = data[1];}static void set_carrier(struct net_device *net){	pegasus_t *pegasus = netdev_priv(net);	u16 tmp;	if (!read_mii_word(pegasus, pegasus->phy, MII_BMSR, &tmp))		return;	if (tmp & BMSR_LSTATUS)		netif_carrier_on(net);	else		netif_carrier_off(net);}static void free_all_urbs(pegasus_t * pegasus){	usb_free_urb(pegasus->intr_urb);	usb_free_urb(pegasus->tx_urb);	usb_free_urb(pegasus->rx_urb);	usb_free_urb(pegasus->ctrl_urb);}static void unlink_all_urbs(pegasus_t * pegasus){	usb_kill_urb(pegasus->intr_urb);	usb_kill_urb(pegasus->tx_urb);	usb_kill_urb(pegasus->rx_urb);	usb_kill_urb(pegasus->ctrl_urb);}static int alloc_urbs(pegasus_t * pegasus){	pegasus->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL);	if (!pegasus->ctrl_urb) {		return 0;	}	pegasus->rx_urb = usb_alloc_urb(0, GFP_KERNEL);	if (!pegasus->rx_urb) {		usb_free_urb(pegasus->ctrl_urb);		return 0;	}	pegasus->tx_urb = usb_alloc_urb(0, GFP_KERNEL);	if (!pegasus->tx_urb) {		usb_free_urb(pegasus->rx_urb);		usb_free_urb(pegasus->ctrl_urb);		return 0;	}	pegasus->intr_urb = usb_alloc_urb(0, GFP_KERNEL);

⌨️ 快捷键说明

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