📄 rtl8150.c
字号:
} 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 + -