📄 rtl8150.c
字号:
/* * Copyright (c) 2002 Petko Manolov (petkan@users.sourceforge.net) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. */#include <linux/config.h>#include <linux/sched.h>#include <linux/signal.h>#include <linux/slab.h>#include <linux/module.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/mii.h>#include <linux/ethtool.h>#include <linux/devfs_fs_kernel.h>#include <linux/usb.h>#include <linux/init.h>#include <asm/uaccess.h>/* Version Information */#define DRIVER_VERSION "v0.4.3 (2002/12/31)"#define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"#define DRIVER_DESC "rtl8150 based usb-ethernet driver"#define IDR 0x0120#define MAR 0x0126#define CR 0x012e#define TCR 0x012f#define RCR 0x0130#define TSR 0x0132#define RSR 0x0133#define CON0 0x0135#define CON1 0x0136#define MSR 0x0137#define PHYADD 0x0138#define PHYDAT 0x0139#define PHYCNT 0x013b#define GPPC 0x013d#define BMCR 0x0140#define BMSR 0x0142#define ANAR 0x0144#define ANLP 0x0146#define AER 0x0148#define IDR_EEPROM 0x1202#define PHY_READ 0#define PHY_WRITE 0x20#define PHY_GO 0x40#define RTL8150_REQT_READ 0xc0#define RTL8150_REQT_WRITE 0x40#define RTL8150_REQ_GET_REGS 0x05#define RTL8150_REQ_SET_REGS 0x05#define RTL8150_MTU 1500#define RTL8150_MAX_MTU 1536#define RTL8150_TX_TIMEOUT (HZ)/* rtl8150 flags */#define RTL8150_FLAG_HWCRC 0#define RX_REG_SET 1#define RTL8150_UNPLUG 2/* Define these values to match your device */#define VENDOR_ID_REALTEK 0x0bda#define VENDOR_ID_MELCO 0x0411#define PRODUCT_ID_RTL8150 0x8150#define PRODUCT_ID_LUAKTX 0x0012#undef EEPROM_WRITE/* table of devices that work with this driver */static struct usb_device_id rtl8150_table[] = { {USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8150)}, {USB_DEVICE(VENDOR_ID_MELCO, PRODUCT_ID_LUAKTX)}, {}};MODULE_DEVICE_TABLE(usb, rtl8150_table);struct rtl8150 { unsigned int flags; struct usb_device *udev; struct usb_interface *interface; struct semaphore sem; struct net_device_stats stats; struct net_device *netdev; struct urb *rx_urb, *tx_urb, *intr_urb, *ctrl_urb; struct usb_ctrlrequest dr; int intr_interval; u16 rx_creg; u8 rx_buff[RTL8150_MAX_MTU]; u8 tx_buff[RTL8150_MAX_MTU]; u8 intr_buff[8]; u8 phy;};typedef struct rtl8150 rtl8150_t;/* the global usb devfs handle */extern devfs_handle_t usb_devfs_handle;unsigned long multicast_filter_limit = 32;static void rtl8150_disconnect(struct usb_device *dev, void *ptr);static void *rtl8150_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id);static struct usb_driver rtl8150_driver = { name: "rtl8150", probe: rtl8150_probe, disconnect: rtl8150_disconnect, id_table: rtl8150_table,};/***** device related part of the code***/static int get_registers(rtl8150_t * dev, u16 indx, u16 size, void *data){ return usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), RTL8150_REQ_GET_REGS, RTL8150_REQT_READ, indx, 0, data, size, HZ / 2);}static int set_registers(rtl8150_t * dev, u16 indx, u16 size, void *data){ return usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), RTL8150_REQ_SET_REGS, RTL8150_REQT_WRITE, indx, 0, data, size, HZ / 2);}static void ctrl_callback(struct urb *urb){ rtl8150_t *dev; switch (urb->status) { case 0: break; case -EINPROGRESS: break; case -ENOENT: break; default: warn("ctrl urb status %d", urb->status); } dev = urb->context; clear_bit(RX_REG_SET, &dev->flags);}static int async_set_registers(rtl8150_t * dev, u16 indx, u16 size, void *data){ int ret; if (test_bit(RX_REG_SET, &dev->flags)) return -EAGAIN; dev->dr.bRequestType = RTL8150_REQT_WRITE; dev->dr.bRequest = RTL8150_REQ_SET_REGS; dev->dr.wValue = cpu_to_le16(indx); dev->dr.wIndex = 0; dev->dr.wLength = cpu_to_le16(2); dev->ctrl_urb->transfer_buffer_length = 2; FILL_CONTROL_URB(dev->ctrl_urb, dev->udev, usb_sndctrlpipe(dev->udev, 0), (char *) &dev->dr, &dev->rx_creg, 2, ctrl_callback, dev); if ((ret = usb_submit_urb(dev->ctrl_urb))) err("control request submission failed: %d", ret); else set_bit(RX_REG_SET, &dev->flags); return ret;}static int read_mii_word(rtl8150_t * dev, u8 phy, __u8 indx, u16 * reg){ int i; u8 data[3], tmp; data[0] = phy; data[1] = data[2] = 0; tmp = indx | PHY_READ | PHY_GO; i = 0; set_registers(dev, PHYADD, sizeof(data), data); set_registers(dev, PHYCNT, 1, &tmp); do { get_registers(dev, PHYCNT, 1, data); } while ((data[0] & PHY_GO) && (i++ < HZ)); if (i < HZ) { get_registers(dev, PHYDAT, 2, data); *reg = le16_to_cpup((u16 *)data); return 0; } else return 1;}static int write_mii_word(rtl8150_t * dev, u8 phy, __u8 indx, u16 reg){ int i; u8 data[3], tmp; data[0] = phy; *(data + 1) = cpu_to_le16p(®); tmp = indx | PHY_WRITE | PHY_GO; i = 0; set_registers(dev, PHYADD, sizeof(data), data); set_registers(dev, PHYCNT, 1, &tmp); do { get_registers(dev, PHYCNT, 1, data); } while ((data[0] & PHY_GO) && (i++ < HZ)); if (i < HZ) return 0; else return 1;}static inline void set_ethernet_addr(rtl8150_t * dev){ u8 node_id[6]; get_registers(dev, IDR, sizeof(node_id), node_id); memcpy(dev->netdev->dev_addr, node_id, sizeof(node_id));}static int rtl8150_set_mac_address(struct net_device *netdev, void *p){ struct sockaddr *addr = p; rtl8150_t *dev; int i; if (netif_running(netdev)) return -EBUSY; dev = netdev->priv; if (dev == NULL) { return -ENODEV; } memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); dbg("%s: Setting MAC address to ", netdev->name); for (i = 0; i < 5; i++) printk("%02X:", netdev->dev_addr[i]); dbg("%02X\n", netdev->dev_addr[i]); /* Set the IDR registers. */ set_registers(dev, IDR, sizeof(netdev->dev_addr), netdev->dev_addr);#ifdef EEPROM_WRITE { u8 cr; /* Get the CR contents. */ get_registers(dev, CR, 1, &cr); /* Set the WEPROM bit (eeprom write enable). */ cr |= 0x20; set_registers(dev, CR, 1, &cr); /* Write the MAC address into eeprom. Eeprom writes must be word-sized, so we need to split them up. */ for (i = 0; i * 2 < netdev->addr_len; i++) { set_registers(dev, IDR_EEPROM + (i * 2), 2, netdev->dev_addr + (i * 2)); } /* Clear the WEPROM bit (preventing accidental eeprom writes). */ cr &= 0xdf; set_registers(dev, CR, 1, &cr); }#endif return 0;}static int rtl8150_reset(rtl8150_t * dev){ u8 data = 0x10; int i = HZ; set_registers(dev, CR, 1, &data); do { get_registers(dev, CR, 1, &data); } while ((data & 0x10) && --i); return (i > 0) ? 0 : -1;}static int alloc_all_urbs(rtl8150_t * dev){ dev->rx_urb = usb_alloc_urb(0); if (!dev->rx_urb) return 0; dev->tx_urb = usb_alloc_urb(0); if (!dev->tx_urb) { usb_free_urb(dev->rx_urb); return 0; } dev->intr_urb = usb_alloc_urb(0); if (!dev->intr_urb) { usb_free_urb(dev->rx_urb); usb_free_urb(dev->tx_urb); return 0; } dev->ctrl_urb = usb_alloc_urb(0); if (!dev->ctrl_urb) { usb_free_urb(dev->rx_urb); usb_free_urb(dev->tx_urb); usb_free_urb(dev->intr_urb); return 0; } return 1;}static void free_all_urbs(rtl8150_t * dev){ usb_free_urb(dev->rx_urb); usb_free_urb(dev->tx_urb); usb_free_urb(dev->intr_urb); usb_free_urb(dev->ctrl_urb);}static void unlink_all_urbs(rtl8150_t * dev){ usb_unlink_urb(dev->rx_urb); usb_unlink_urb(dev->tx_urb); usb_unlink_urb(dev->intr_urb); usb_unlink_urb(dev->ctrl_urb);}static void read_bulk_callback(struct urb *urb){ rtl8150_t *dev; int pkt_len, res; struct sk_buff *skb; struct net_device *netdev; u16 rx_stat; dev = urb->context; if (!dev) { warn("!dev"); return; } netdev = dev->netdev; if (!netif_device_present(netdev)) { warn("netdev is not present"); return; } switch (urb->status) { case 0: break; case -ENOENT: return; case -ETIMEDOUT: warn("need a device reset?.."); goto goon; default: warn("Rx status %d", urb->status); goto goon; } pkt_len = urb->actual_length - 4; rx_stat = le16_to_cpu(*(u16 *) (dev->rx_buff + pkt_len)); if (!(skb = dev_alloc_skb(pkt_len + 2))) goto goon; skb->dev = netdev; skb_reserve(skb, 2); eth_copy_and_sum(skb, dev->rx_buff, pkt_len, 0); skb_put(skb, pkt_len); skb->protocol = eth_type_trans(skb, netdev); netif_rx(skb); dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len;goon: 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 submission failed %d", netdev->name, res);}static void write_bulk_callback(struct urb *urb){ rtl8150_t *dev;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -