📄 rtl8150.c
字号:
dev = urb->context; if (!dev) return; 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);}void intr_callback(struct urb *urb){ rtl8150_t *dev; dev = urb->context; if (!dev) return; switch (urb->status) { case 0: break; case -ENOENT: return; default: info("%s: intr status %d", dev->netdev->name, urb->status); }}/***** network related part of the code***/static int enable_net_traffic(rtl8150_t * dev){ u8 cr, tcr, rcr, msr; if (rtl8150_reset(dev)) { warn("%s - device reset failed", __FUNCTION__); } dev->rx_creg = rcr = 0x9e; /* bit7=1 attach Rx info at the end */ tcr = 0xd8; cr = 0x0c; 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 *) dev->priv)->stats;}static void rtl8150_tx_timeout(struct net_device *netdev){ rtl8150_t *dev; dev = netdev->priv; if (!dev) return; warn("%s: Tx timeout.", netdev->name); dev->tx_urb->transfer_flags |= USB_ASYNC_UNLINK; usb_unlink_urb(dev->tx_urb); dev->stats.tx_errors++;}static void rtl8150_set_multicast(struct net_device *netdev){ rtl8150_t *dev; dev = netdev->priv; netif_stop_queue(netdev); if (netdev->flags & IFF_PROMISC) { dev->rx_creg |= 0x0001; info("%s: promiscuous mode", netdev->name); } else if ((netdev->mc_count > multicast_filter_limit) || (netdev->flags & IFF_ALLMULTI)) { dev->rx_creg &= 0xfffe; dev->rx_creg |= 0x0002; info("%s: allmulti set", netdev->name); } else { /* ~RX_MULTICAST, ~RX_PROMISCUOUS */ dev->rx_creg &= 0x00fc; } async_set_registers(dev, RCR, 2, &dev->rx_creg); netif_wake_queue(netdev);}static int rtl8150_start_xmit(struct sk_buff *skb, struct net_device *netdev){ rtl8150_t *dev; int count, res; netif_stop_queue(netdev); dev = netdev->priv; count = (skb->len < 60) ? 60 : skb->len; count = (count & 0x3f) ? count : count + 1; memcpy(dev->tx_buff, skb->data, skb->len); FILL_BULK_URB(dev->tx_urb, dev->udev, usb_sndbulkpipe(dev->udev, 2), dev->tx_buff, count, write_bulk_callback, dev); dev->tx_urb->transfer_buffer_length = count; if ((res = usb_submit_urb(dev->tx_urb))) { 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; } dev_kfree_skb(skb); return 0;}static int rtl8150_open(struct net_device *netdev){ rtl8150_t *dev; int res; dev = netdev->priv; if (dev == NULL) { return -ENODEV; } down(&dev->sem); set_registers(dev, IDR, 6, netdev->dev_addr); FILL_BULK_URB(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1), dev->rx_buff, RTL8150_MAX_MTU, read_bulk_callback, dev); if ((res = usb_submit_urb(dev->rx_urb))) warn("%s: rx_urb submit failed: %d", __FUNCTION__, res); FILL_INT_URB(dev->intr_urb, dev->udev, usb_rcvintpipe(dev->udev, 3), dev->intr_buff, sizeof(dev->intr_buff), intr_callback, dev, dev->intr_interval); if ((res = usb_submit_urb(dev->intr_urb))) warn("%s: intr_urb submit failed: %d", __FUNCTION__, res); netif_start_queue(netdev); enable_net_traffic(dev); up(&dev->sem); return res;}static int rtl8150_close(struct net_device *netdev){ rtl8150_t *dev; int res = 0; dev = netdev->priv; if (!dev) return -ENODEV; down(&dev->sem); if (!test_bit(RTL8150_UNPLUG, &dev->flags)) disable_net_traffic(dev); unlink_all_urbs(dev); netif_stop_queue(netdev); up(&dev->sem); return res;}static int rtl8150_ethtool_ioctl(struct net_device *netdev, void *uaddr){ rtl8150_t *dev; int cmd; char tmp[128]; dev = netdev->priv; if (get_user(cmd, (int *) uaddr)) return -EFAULT; switch (cmd) { case ETHTOOL_GDRVINFO:{ struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; strncpy(info.driver, DRIVER_DESC, ETHTOOL_BUSINFO_LEN); strncpy(info.version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN); sprintf(tmp, "usb%d:%d", dev->udev->bus->busnum, dev->udev->devnum); strncpy(info.bus_info, tmp, ETHTOOL_BUSINFO_LEN); if (copy_to_user(uaddr, &info, sizeof(info))) return -EFAULT; return 0; } case ETHTOOL_GSET:{ struct ethtool_cmd ecmd; short lpa, bmcr; if (copy_from_user(&ecmd, uaddr, sizeof(ecmd))) return -EFAULT; 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; } if (copy_to_user(uaddr, &ecmd, sizeof(ecmd))) return -EFAULT; return 0; } case ETHTOOL_SSET: return -ENOTSUPP; case ETHTOOL_GLINK:{ struct ethtool_value edata = { ETHTOOL_GLINK }; edata.data = netif_carrier_ok(netdev); if (copy_to_user(uaddr, &edata, sizeof(edata))) return -EFAULT; return 0; } default: return -EOPNOTSUPP; }}static int rtl8150_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd){ rtl8150_t *dev; u16 *data; int res; dev = netdev->priv; data = (u16 *) & rq->ifr_data; res = 0; down(&dev->sem); switch (cmd) { case SIOCETHTOOL: res = rtl8150_ethtool_ioctl(netdev, rq->ifr_data); break; 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)) { up(&dev->sem); return -EPERM; } write_mii_word(dev, dev->phy, (data[1] & 0x1f), data[2]); break; default: res = -EOPNOTSUPP; } up(&dev->sem); return res;}static void *rtl8150_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id){ rtl8150_t *dev; struct net_device *netdev; udev->config[0].bConfigurationValue = 1; if (usb_set_configuration(udev, udev->config[0].bConfigurationValue)) { err("usb_set_configuration() failed"); return NULL; } dev = kmalloc(sizeof(rtl8150_t), GFP_KERNEL); if (!dev) { err("Out of memory"); goto exit; } else memset(dev, 0, sizeof(rtl8150_t)); netdev = init_etherdev(NULL, 0); if (!netdev) { kfree(dev); err("Oh boy, out of memory again?!?"); dev = NULL; goto exit; } init_MUTEX(&dev->sem); dev->udev = udev; dev->netdev = netdev; SET_MODULE_OWNER(netdev); netdev->priv = dev; 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; dev->intr_interval = 100; /* 100ms */ if (rtl8150_reset(dev) || !alloc_all_urbs(dev)) { err("couldn't reset the device"); free_all_urbs(dev); unregister_netdev(dev->netdev); kfree(netdev); kfree(dev); dev = NULL; goto exit; } set_ethernet_addr(dev); /* let's not be very nasty :-) */ info("%s: rtl8150 is detected", netdev->name);exit: return dev;}static void rtl8150_disconnect(struct usb_device *udev, void *ptr){ rtl8150_t *dev; dev = ptr; set_bit(RTL8150_UNPLUG, &dev->flags); unregister_netdev(dev->netdev); unlink_all_urbs(dev); free_all_urbs(dev); kfree(dev->netdev); kfree(dev); dev->netdev = NULL; dev = NULL;}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 + -