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

📄 rtl8150.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
	}	return;resched:	tasklet_schedule(&dev->tl);}static void rx_fixup(unsigned long data){	rtl8150_t *dev;	struct sk_buff *skb;	dev = (rtl8150_t *)data;	spin_lock_irq(&dev->rx_pool_lock);	fill_skb_pool(dev);	spin_unlock_irq(&dev->rx_pool_lock);	if (test_bit(RX_URB_FAIL, &dev->flags))		if (dev->rx_skb)			goto try_again;	spin_lock_irq(&dev->rx_pool_lock);	skb = pull_skb(dev);	spin_unlock_irq(&dev->rx_pool_lock);	if (skb == NULL)		goto tlsched;	dev->rx_skb = skb;	usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),		      dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev);try_again:	if (usb_submit_urb(dev->rx_urb, GFP_ATOMIC)) {		set_bit(RX_URB_FAIL, &dev->flags);		goto tlsched;	 } else {		clear_bit(RX_URB_FAIL, &dev->flags);	}	return;tlsched:	tasklet_schedule(&dev->tl);}static void write_bulk_callback(struct urb *urb, struct pt_regs *regs){	rtl8150_t *dev;	dev = urb->context;	if (!dev)		return;	dev_kfree_skb_irq(dev->tx_skb);	if (!netif_device_present(dev->netdev))		return;	if (urb->status)		info("%s: Tx status %d", dev->netdev->name, urb->status);	dev->netdev->trans_start = jiffies;	netif_wake_queue(dev->netdev);}static void intr_callback(struct urb *urb, struct pt_regs *regs){	rtl8150_t *dev;	__u8 *d;	int status;	dev = urb->context;	if (!dev)		return;	switch (urb->status) {	case 0:			/* success */		break;	case -ECONNRESET:	/* unlink */	case -ENOENT:	case -ESHUTDOWN:		return;	/* -EPIPE:  should clear the halt */	default:		info("%s: intr status %d", dev->netdev->name, urb->status);		goto resubmit;	}	d = urb->transfer_buffer;	if (d[0] & TSR_ERRORS) {		dev->stats.tx_errors++;		if (d[INT_TSR] & (TSR_ECOL | TSR_JBR))			dev->stats.tx_aborted_errors++;		if (d[INT_TSR] & TSR_LCOL)			dev->stats.tx_window_errors++;		if (d[INT_TSR] & TSR_LOSS_CRS)			dev->stats.tx_carrier_errors++;	}	/* Report link status changes to the network stack */	if ((d[INT_MSR] & MSR_LINK) == 0) {		if (netif_carrier_ok(dev->netdev)) {			netif_carrier_off(dev->netdev);			dbg("%s: LINK LOST\n", __func__);		}	} else {		if (!netif_carrier_ok(dev->netdev)) {			netif_carrier_on(dev->netdev);			dbg("%s: LINK CAME BACK\n", __func__);		}	}resubmit:	status = usb_submit_urb (urb, SLAB_ATOMIC);	if (status)		err ("can't resubmit intr, %s-%s/input0, status %d",				dev->udev->bus->bus_name,				dev->udev->devpath, status);}/*****	network related part of the code***/static void fill_skb_pool(rtl8150_t *dev){	struct sk_buff *skb;	int i;	for (i = 0; i < RX_SKB_POOL_SIZE; i++) {		if (dev->rx_skb_pool[i])			continue;		skb = dev_alloc_skb(RTL8150_MTU + 2);		if (!skb) {			return;		}		skb->dev = dev->netdev;		skb_reserve(skb, 2);		dev->rx_skb_pool[i] = skb;	}}static void free_skb_pool(rtl8150_t *dev){	int i;	for (i = 0; i < RX_SKB_POOL_SIZE; i++)		if (dev->rx_skb_pool[i])			dev_kfree_skb(dev->rx_skb_pool[i]);}static int enable_net_traffic(rtl8150_t * dev){	u8 cr, tcr, rcr, msr;	if (!rtl8150_reset(dev)) {		warn("%s - device reset failed", __FUNCTION__);	}	/* RCR bit7=1 attach Rx info at the end;  =0 HW CRC (which is broken) */	rcr = 0x9e;	dev->rx_creg = cpu_to_le16(rcr);	tcr = 0xd8;	cr = 0x0c;	if (!(rcr & 0x80))		set_bit(RTL8150_HW_CRC, &dev->flags);	set_registers(dev, RCR, 1, &rcr);	set_registers(dev, TCR, 1, &tcr);	set_registers(dev, CR, 1, &cr);	get_registers(dev, MSR, 1, &msr);	return 0;}static void disable_net_traffic(rtl8150_t * dev){	u8 cr;	get_registers(dev, CR, 1, &cr);	cr &= 0xf3;	set_registers(dev, CR, 1, &cr);}static struct net_device_stats *rtl8150_netdev_stats(struct net_device *dev){	return &((rtl8150_t *)netdev_priv(dev))->stats;}static void rtl8150_tx_timeout(struct net_device *netdev){	rtl8150_t *dev = netdev_priv(netdev);	warn("%s: Tx timeout.", netdev->name);	usb_unlink_urb(dev->tx_urb);	dev->stats.tx_errors++;}static void rtl8150_set_multicast(struct net_device *netdev){	rtl8150_t *dev = netdev_priv(netdev);	netif_stop_queue(netdev);	if (netdev->flags & IFF_PROMISC) {		dev->rx_creg |= cpu_to_le16(0x0001);		info("%s: promiscuous mode", netdev->name);	} else if (netdev->mc_count ||		   (netdev->flags & IFF_ALLMULTI)) {		dev->rx_creg &= cpu_to_le16(0xfffe);		dev->rx_creg |= cpu_to_le16(0x0002);		info("%s: allmulti set", netdev->name);	} else {		/* ~RX_MULTICAST, ~RX_PROMISCUOUS */		dev->rx_creg &= cpu_to_le16(0x00fc);	}	async_set_registers(dev, RCR, 2);	netif_wake_queue(netdev);}static int rtl8150_start_xmit(struct sk_buff *skb, struct net_device *netdev){	rtl8150_t *dev = netdev_priv(netdev);	int count, res;	netif_stop_queue(netdev);	count = (skb->len < 60) ? 60 : skb->len;	count = (count & 0x3f) ? count : count + 1;	dev->tx_skb = skb;	usb_fill_bulk_urb(dev->tx_urb, dev->udev, usb_sndbulkpipe(dev->udev, 2),		      skb->data, count, write_bulk_callback, dev);	if ((res = usb_submit_urb(dev->tx_urb, GFP_ATOMIC))) {		warn("failed tx_urb %d\n", res);		dev->stats.tx_errors++;		netif_start_queue(netdev);	} else {		dev->stats.tx_packets++;		dev->stats.tx_bytes += skb->len;		netdev->trans_start = jiffies;	}	return 0;}static void set_carrier(struct net_device *netdev){	rtl8150_t *dev = netdev_priv(netdev);	short tmp;	get_registers(dev, CSCR, 2, &tmp);	if (tmp & CSCR_LINK_STATUS)		netif_carrier_on(netdev);	else		netif_carrier_off(netdev);}static int rtl8150_open(struct net_device *netdev){	rtl8150_t *dev = netdev_priv(netdev);	int res;	if (dev->rx_skb == NULL)		dev->rx_skb = pull_skb(dev);	if (!dev->rx_skb)		return -ENOMEM;	set_registers(dev, IDR, 6, netdev->dev_addr);		usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),		      dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev);	if ((res = usb_submit_urb(dev->rx_urb, GFP_KERNEL)))		warn("%s: rx_urb submit failed: %d", __FUNCTION__, res);	usb_fill_int_urb(dev->intr_urb, dev->udev, usb_rcvintpipe(dev->udev, 3),		     dev->intr_buff, INTBUFSIZE, intr_callback,		     dev, dev->intr_interval);	if ((res = usb_submit_urb(dev->intr_urb, GFP_KERNEL)))		warn("%s: intr_urb submit failed: %d", __FUNCTION__, res);	netif_start_queue(netdev);	enable_net_traffic(dev);	set_carrier(netdev);	return res;}static int rtl8150_close(struct net_device *netdev){	rtl8150_t *dev = netdev_priv(netdev);	int res = 0;	netif_stop_queue(netdev);	if (!test_bit(RTL8150_UNPLUG, &dev->flags))		disable_net_traffic(dev);	unlink_all_urbs(dev);	return res;}static void rtl8150_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *info){	rtl8150_t *dev = netdev_priv(netdev);	strncpy(info->driver, driver_name, ETHTOOL_BUSINFO_LEN);	strncpy(info->version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN);	usb_make_path(dev->udev, info->bus_info, sizeof info->bus_info);}static int rtl8150_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd){	rtl8150_t *dev = netdev_priv(netdev);	short lpa, bmcr;	ecmd->supported = (SUPPORTED_10baseT_Half |			  SUPPORTED_10baseT_Full |			  SUPPORTED_100baseT_Half |			  SUPPORTED_100baseT_Full |			  SUPPORTED_Autoneg |			  SUPPORTED_TP | SUPPORTED_MII);	ecmd->port = PORT_TP;	ecmd->transceiver = XCVR_INTERNAL;	ecmd->phy_address = dev->phy;	get_registers(dev, BMCR, 2, &bmcr);	get_registers(dev, ANLP, 2, &lpa);	if (bmcr & BMCR_ANENABLE) {		ecmd->autoneg = AUTONEG_ENABLE;		ecmd->speed = (lpa & (LPA_100HALF | LPA_100FULL)) ?			     SPEED_100 : SPEED_10;		if (ecmd->speed == SPEED_100)			ecmd->duplex = (lpa & LPA_100FULL) ?			    DUPLEX_FULL : DUPLEX_HALF;		else			ecmd->duplex = (lpa & LPA_10FULL) ?			    DUPLEX_FULL : DUPLEX_HALF;	} else {		ecmd->autoneg = AUTONEG_DISABLE;		ecmd->speed = (bmcr & BMCR_SPEED100) ?		    SPEED_100 : SPEED_10;		ecmd->duplex = (bmcr & BMCR_FULLDPLX) ?		    DUPLEX_FULL : DUPLEX_HALF;	}	return 0;}static struct ethtool_ops ops = {	.get_drvinfo = rtl8150_get_drvinfo,	.get_settings = rtl8150_get_settings,	.get_link = ethtool_op_get_link};static int rtl8150_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd){	rtl8150_t *dev = netdev_priv(netdev);	u16 *data = (u16 *) & rq->ifr_ifru;	int res = 0;	switch (cmd) {	case SIOCDEVPRIVATE:		data[0] = dev->phy;	case SIOCDEVPRIVATE + 1:		read_mii_word(dev, dev->phy, (data[1] & 0x1f), &data[3]);		break;	case SIOCDEVPRIVATE + 2:		if (!capable(CAP_NET_ADMIN))			return -EPERM;		write_mii_word(dev, dev->phy, (data[1] & 0x1f), data[2]);		break;	default:		res = -EOPNOTSUPP;	}	return res;}static int rtl8150_probe(struct usb_interface *intf,			 const struct usb_device_id *id){	struct usb_device *udev = interface_to_usbdev(intf);	rtl8150_t *dev;	struct net_device *netdev;	netdev = alloc_etherdev(sizeof(rtl8150_t));	if (!netdev) {		err("Out of memory");		return -ENOMEM;	}	dev = netdev_priv(netdev);	memset(dev, 0, sizeof(rtl8150_t));	dev->intr_buff = kmalloc(INTBUFSIZE, GFP_KERNEL);	if (!dev->intr_buff) {		free_netdev(netdev);		return -ENOMEM;	}	tasklet_init(&dev->tl, rx_fixup, (unsigned long)dev);	spin_lock_init(&dev->rx_pool_lock);		dev->udev = udev;	dev->netdev = netdev;	SET_MODULE_OWNER(netdev);	netdev->open = rtl8150_open;	netdev->stop = rtl8150_close;	netdev->do_ioctl = rtl8150_ioctl;	netdev->watchdog_timeo = RTL8150_TX_TIMEOUT;	netdev->tx_timeout = rtl8150_tx_timeout;	netdev->hard_start_xmit = rtl8150_start_xmit;	netdev->set_multicast_list = rtl8150_set_multicast;	netdev->set_mac_address = rtl8150_set_mac_address;	netdev->get_stats = rtl8150_netdev_stats;	netdev->mtu = RTL8150_MTU;	SET_ETHTOOL_OPS(netdev, &ops);	dev->intr_interval = 100;	/* 100ms */	if (!alloc_all_urbs(dev)) {		err("out of memory");		goto out;	}	if (!rtl8150_reset(dev)) {		err("couldn't reset the device");		goto out1;	}	fill_skb_pool(dev);	set_ethernet_addr(dev);	info("%s: rtl8150 is detected", netdev->name);		usb_set_intfdata(intf, dev);	SET_NETDEV_DEV(netdev, &intf->dev);	if (register_netdev(netdev) != 0) {		err("couldn't register the device");		goto out2;	}	return 0;out2:	usb_set_intfdata(intf, NULL);	free_skb_pool(dev);out1:	free_all_urbs(dev);out:	kfree(dev->intr_buff);	free_netdev(netdev);	return -EIO;}static void rtl8150_disconnect(struct usb_interface *intf){	rtl8150_t *dev = usb_get_intfdata(intf);	usb_set_intfdata(intf, NULL);	if (dev) {		set_bit(RTL8150_UNPLUG, &dev->flags);		tasklet_disable(&dev->tl);		unregister_netdev(dev->netdev);		unlink_all_urbs(dev);		free_all_urbs(dev);		free_skb_pool(dev);		if (dev->rx_skb)			dev_kfree_skb(dev->rx_skb);		kfree(dev->intr_buff);		free_netdev(dev->netdev);	}}static int __init usb_rtl8150_init(void){	info(DRIVER_DESC " " DRIVER_VERSION);	return usb_register(&rtl8150_driver);}static void __exit usb_rtl8150_exit(void){	usb_deregister(&rtl8150_driver);}module_init(usb_rtl8150_init);module_exit(usb_rtl8150_exit);MODULE_AUTHOR(DRIVER_AUTHOR);MODULE_DESCRIPTION(DRIVER_DESC);MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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