1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
25b2fc499SJeff Garzik /*
35b2fc499SJeff Garzik * Copyright (c) 2002 Petko Manolov (petkan@users.sourceforge.net)
45b2fc499SJeff Garzik */
55b2fc499SJeff Garzik
65b2fc499SJeff Garzik #include <linux/signal.h>
75b2fc499SJeff Garzik #include <linux/slab.h>
85b2fc499SJeff Garzik #include <linux/module.h>
95b2fc499SJeff Garzik #include <linux/netdevice.h>
105b2fc499SJeff Garzik #include <linux/etherdevice.h>
115b2fc499SJeff Garzik #include <linux/mii.h>
125b2fc499SJeff Garzik #include <linux/ethtool.h>
135b2fc499SJeff Garzik #include <linux/usb.h>
147c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
155b2fc499SJeff Garzik
165b2fc499SJeff Garzik /* Version Information */
175b2fc499SJeff Garzik #define DRIVER_VERSION "v0.6.2 (2004/08/27)"
185b2fc499SJeff Garzik #define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"
195b2fc499SJeff Garzik #define DRIVER_DESC "rtl8150 based usb-ethernet driver"
205b2fc499SJeff Garzik
215b2fc499SJeff Garzik #define IDR 0x0120
225b2fc499SJeff Garzik #define MAR 0x0126
235b2fc499SJeff Garzik #define CR 0x012e
245b2fc499SJeff Garzik #define TCR 0x012f
255b2fc499SJeff Garzik #define RCR 0x0130
265b2fc499SJeff Garzik #define TSR 0x0132
275b2fc499SJeff Garzik #define RSR 0x0133
285b2fc499SJeff Garzik #define CON0 0x0135
295b2fc499SJeff Garzik #define CON1 0x0136
305b2fc499SJeff Garzik #define MSR 0x0137
315b2fc499SJeff Garzik #define PHYADD 0x0138
325b2fc499SJeff Garzik #define PHYDAT 0x0139
335b2fc499SJeff Garzik #define PHYCNT 0x013b
345b2fc499SJeff Garzik #define GPPC 0x013d
355b2fc499SJeff Garzik #define BMCR 0x0140
365b2fc499SJeff Garzik #define BMSR 0x0142
375b2fc499SJeff Garzik #define ANAR 0x0144
385b2fc499SJeff Garzik #define ANLP 0x0146
395b2fc499SJeff Garzik #define AER 0x0148
405b2fc499SJeff Garzik #define CSCR 0x014C /* This one has the link status */
415b2fc499SJeff Garzik #define CSCR_LINK_STATUS (1 << 3)
425b2fc499SJeff Garzik
435b2fc499SJeff Garzik #define IDR_EEPROM 0x1202
445b2fc499SJeff Garzik
455b2fc499SJeff Garzik #define PHY_READ 0
465b2fc499SJeff Garzik #define PHY_WRITE 0x20
475b2fc499SJeff Garzik #define PHY_GO 0x40
485b2fc499SJeff Garzik
495b2fc499SJeff Garzik #define MII_TIMEOUT 10
505b2fc499SJeff Garzik #define INTBUFSIZE 8
515b2fc499SJeff Garzik
525b2fc499SJeff Garzik #define RTL8150_REQT_READ 0xc0
535b2fc499SJeff Garzik #define RTL8150_REQT_WRITE 0x40
545b2fc499SJeff Garzik #define RTL8150_REQ_GET_REGS 0x05
555b2fc499SJeff Garzik #define RTL8150_REQ_SET_REGS 0x05
565b2fc499SJeff Garzik
575b2fc499SJeff Garzik
585b2fc499SJeff Garzik /* Transmit status register errors */
595b2fc499SJeff Garzik #define TSR_ECOL (1<<5)
605b2fc499SJeff Garzik #define TSR_LCOL (1<<4)
615b2fc499SJeff Garzik #define TSR_LOSS_CRS (1<<3)
625b2fc499SJeff Garzik #define TSR_JBR (1<<2)
635b2fc499SJeff Garzik #define TSR_ERRORS (TSR_ECOL | TSR_LCOL | TSR_LOSS_CRS | TSR_JBR)
645b2fc499SJeff Garzik /* Receive status register errors */
655b2fc499SJeff Garzik #define RSR_CRC (1<<2)
665b2fc499SJeff Garzik #define RSR_FAE (1<<1)
675b2fc499SJeff Garzik #define RSR_ERRORS (RSR_CRC | RSR_FAE)
685b2fc499SJeff Garzik
695b2fc499SJeff Garzik /* Media status register definitions */
705b2fc499SJeff Garzik #define MSR_DUPLEX (1<<4)
715b2fc499SJeff Garzik #define MSR_SPEED (1<<3)
725b2fc499SJeff Garzik #define MSR_LINK (1<<2)
735b2fc499SJeff Garzik
745b2fc499SJeff Garzik /* Interrupt pipe data */
755b2fc499SJeff Garzik #define INT_TSR 0x00
765b2fc499SJeff Garzik #define INT_RSR 0x01
775b2fc499SJeff Garzik #define INT_MSR 0x02
785b2fc499SJeff Garzik #define INT_WAKSR 0x03
795b2fc499SJeff Garzik #define INT_TXOK_CNT 0x04
805b2fc499SJeff Garzik #define INT_RXLOST_CNT 0x05
815b2fc499SJeff Garzik #define INT_CRERR_CNT 0x06
825b2fc499SJeff Garzik #define INT_COL_CNT 0x07
835b2fc499SJeff Garzik
845b2fc499SJeff Garzik
855b2fc499SJeff Garzik #define RTL8150_MTU 1540
865b2fc499SJeff Garzik #define RTL8150_TX_TIMEOUT (HZ)
875b2fc499SJeff Garzik #define RX_SKB_POOL_SIZE 4
885b2fc499SJeff Garzik
895b2fc499SJeff Garzik /* rtl8150 flags */
905b2fc499SJeff Garzik #define RTL8150_HW_CRC 0
915b2fc499SJeff Garzik #define RX_REG_SET 1
925b2fc499SJeff Garzik #define RTL8150_UNPLUG 2
935b2fc499SJeff Garzik #define RX_URB_FAIL 3
945b2fc499SJeff Garzik
955b2fc499SJeff Garzik /* Define these values to match your device */
965b2fc499SJeff Garzik #define VENDOR_ID_REALTEK 0x0bda
975b2fc499SJeff Garzik #define VENDOR_ID_MELCO 0x0411
985b2fc499SJeff Garzik #define VENDOR_ID_MICRONET 0x3980
995b2fc499SJeff Garzik #define VENDOR_ID_LONGSHINE 0x07b8
1005b2fc499SJeff Garzik #define VENDOR_ID_OQO 0x1557
1015b2fc499SJeff Garzik #define VENDOR_ID_ZYXEL 0x0586
1025b2fc499SJeff Garzik
1035b2fc499SJeff Garzik #define PRODUCT_ID_RTL8150 0x8150
1045b2fc499SJeff Garzik #define PRODUCT_ID_LUAKTX 0x0012
1055b2fc499SJeff Garzik #define PRODUCT_ID_LCS8138TX 0x401a
1065b2fc499SJeff Garzik #define PRODUCT_ID_SP128AR 0x0003
1075b2fc499SJeff Garzik #define PRODUCT_ID_PRESTIGE 0x401a
1085b2fc499SJeff Garzik
1095b2fc499SJeff Garzik #undef EEPROM_WRITE
1105b2fc499SJeff Garzik
1115b2fc499SJeff Garzik /* table of devices that work with this driver */
112e1cb90f2SArvind Yadav static const struct usb_device_id rtl8150_table[] = {
1135b2fc499SJeff Garzik {USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8150)},
1145b2fc499SJeff Garzik {USB_DEVICE(VENDOR_ID_MELCO, PRODUCT_ID_LUAKTX)},
1155b2fc499SJeff Garzik {USB_DEVICE(VENDOR_ID_MICRONET, PRODUCT_ID_SP128AR)},
1165b2fc499SJeff Garzik {USB_DEVICE(VENDOR_ID_LONGSHINE, PRODUCT_ID_LCS8138TX)},
1175b2fc499SJeff Garzik {USB_DEVICE(VENDOR_ID_OQO, PRODUCT_ID_RTL8150)},
1185b2fc499SJeff Garzik {USB_DEVICE(VENDOR_ID_ZYXEL, PRODUCT_ID_PRESTIGE)},
1195b2fc499SJeff Garzik {}
1205b2fc499SJeff Garzik };
1215b2fc499SJeff Garzik
1225b2fc499SJeff Garzik MODULE_DEVICE_TABLE(usb, rtl8150_table);
1235b2fc499SJeff Garzik
1245b2fc499SJeff Garzik struct rtl8150 {
1255b2fc499SJeff Garzik unsigned long flags;
1265b2fc499SJeff Garzik struct usb_device *udev;
1275b2fc499SJeff Garzik struct tasklet_struct tl;
1285b2fc499SJeff Garzik struct net_device *netdev;
1294d12997aSPetko Manolov struct urb *rx_urb, *tx_urb, *intr_urb;
1305b2fc499SJeff Garzik struct sk_buff *tx_skb, *rx_skb;
1315b2fc499SJeff Garzik struct sk_buff *rx_skb_pool[RX_SKB_POOL_SIZE];
1325b2fc499SJeff Garzik spinlock_t rx_pool_lock;
1335b2fc499SJeff Garzik struct usb_ctrlrequest dr;
1345b2fc499SJeff Garzik int intr_interval;
1355b2fc499SJeff Garzik u8 *intr_buff;
1365b2fc499SJeff Garzik u8 phy;
1375b2fc499SJeff Garzik };
1385b2fc499SJeff Garzik
1395b2fc499SJeff Garzik typedef struct rtl8150 rtl8150_t;
1405b2fc499SJeff Garzik
1414d12997aSPetko Manolov struct async_req {
1424d12997aSPetko Manolov struct usb_ctrlrequest dr;
1434d12997aSPetko Manolov u16 rx_creg;
1444d12997aSPetko Manolov };
1454d12997aSPetko Manolov
1465b2fc499SJeff Garzik static const char driver_name [] = "rtl8150";
1475b2fc499SJeff Garzik
1485b2fc499SJeff Garzik /*
1495b2fc499SJeff Garzik **
1505b2fc499SJeff Garzik ** device related part of the code
1515b2fc499SJeff Garzik **
1525b2fc499SJeff Garzik */
get_registers(rtl8150_t * dev,u16 indx,u16 size,void * data)1535b2fc499SJeff Garzik static int get_registers(rtl8150_t * dev, u16 indx, u16 size, void *data)
1545b2fc499SJeff Garzik {
155b2a0f274SPetko Manolov return usb_control_msg_recv(dev->udev, 0, RTL8150_REQ_GET_REGS,
156b2a0f274SPetko Manolov RTL8150_REQT_READ, indx, 0, data, size,
157b2a0f274SPetko Manolov 1000, GFP_NOIO);
1585b2fc499SJeff Garzik }
1595b2fc499SJeff Garzik
set_registers(rtl8150_t * dev,u16 indx,u16 size,const void * data)1607926aff5SBen Hutchings static int set_registers(rtl8150_t * dev, u16 indx, u16 size, const void *data)
1615b2fc499SJeff Garzik {
162b2a0f274SPetko Manolov return usb_control_msg_send(dev->udev, 0, RTL8150_REQ_SET_REGS,
163b2a0f274SPetko Manolov RTL8150_REQT_WRITE, indx, 0, data, size,
164b2a0f274SPetko Manolov 1000, GFP_NOIO);
1655b2fc499SJeff Garzik }
1665b2fc499SJeff Garzik
async_set_reg_cb(struct urb * urb)1674d12997aSPetko Manolov static void async_set_reg_cb(struct urb *urb)
1685b2fc499SJeff Garzik {
1694d12997aSPetko Manolov struct async_req *req = (struct async_req *)urb->context;
170c94cb314SOliver Neukum int status = urb->status;
1715b2fc499SJeff Garzik
1724d12997aSPetko Manolov if (status < 0)
1734d12997aSPetko Manolov dev_dbg(&urb->dev->dev, "%s failed with %d", __func__, status);
1744d12997aSPetko Manolov kfree(req);
1754d12997aSPetko Manolov usb_free_urb(urb);
1765b2fc499SJeff Garzik }
1775b2fc499SJeff Garzik
async_set_registers(rtl8150_t * dev,u16 indx,u16 size,u16 reg)1784d12997aSPetko Manolov static int async_set_registers(rtl8150_t *dev, u16 indx, u16 size, u16 reg)
1795b2fc499SJeff Garzik {
1804d12997aSPetko Manolov int res = -ENOMEM;
1814d12997aSPetko Manolov struct urb *async_urb;
1824d12997aSPetko Manolov struct async_req *req;
1835b2fc499SJeff Garzik
1844d12997aSPetko Manolov req = kmalloc(sizeof(struct async_req), GFP_ATOMIC);
1854d12997aSPetko Manolov if (req == NULL)
1864d12997aSPetko Manolov return res;
1874d12997aSPetko Manolov async_urb = usb_alloc_urb(0, GFP_ATOMIC);
1884d12997aSPetko Manolov if (async_urb == NULL) {
1894d12997aSPetko Manolov kfree(req);
1904d12997aSPetko Manolov return res;
1914d12997aSPetko Manolov }
1924d12997aSPetko Manolov req->rx_creg = cpu_to_le16(reg);
1934d12997aSPetko Manolov req->dr.bRequestType = RTL8150_REQT_WRITE;
1944d12997aSPetko Manolov req->dr.bRequest = RTL8150_REQ_SET_REGS;
1954d12997aSPetko Manolov req->dr.wIndex = 0;
1964d12997aSPetko Manolov req->dr.wValue = cpu_to_le16(indx);
1974d12997aSPetko Manolov req->dr.wLength = cpu_to_le16(size);
1984d12997aSPetko Manolov usb_fill_control_urb(async_urb, dev->udev,
1994d12997aSPetko Manolov usb_sndctrlpipe(dev->udev, 0), (void *)&req->dr,
2004d12997aSPetko Manolov &req->rx_creg, size, async_set_reg_cb, req);
2014d12997aSPetko Manolov res = usb_submit_urb(async_urb, GFP_ATOMIC);
2024d12997aSPetko Manolov if (res) {
2034d12997aSPetko Manolov if (res == -ENODEV)
2045b2fc499SJeff Garzik netif_device_detach(dev->netdev);
2054d12997aSPetko Manolov dev_err(&dev->udev->dev, "%s failed with %d\n", __func__, res);
2064d12997aSPetko Manolov }
2074d12997aSPetko Manolov return res;
2085b2fc499SJeff Garzik }
2095b2fc499SJeff Garzik
read_mii_word(rtl8150_t * dev,u8 phy,__u8 indx,u16 * reg)2105b2fc499SJeff Garzik static int read_mii_word(rtl8150_t * dev, u8 phy, __u8 indx, u16 * reg)
2115b2fc499SJeff Garzik {
2125b2fc499SJeff Garzik int i;
2135b2fc499SJeff Garzik u8 data[3], tmp;
2145b2fc499SJeff Garzik
2155b2fc499SJeff Garzik data[0] = phy;
2165b2fc499SJeff Garzik data[1] = data[2] = 0;
2175b2fc499SJeff Garzik tmp = indx | PHY_READ | PHY_GO;
2185b2fc499SJeff Garzik i = 0;
2195b2fc499SJeff Garzik
2205b2fc499SJeff Garzik set_registers(dev, PHYADD, sizeof(data), data);
2215b2fc499SJeff Garzik set_registers(dev, PHYCNT, 1, &tmp);
2225b2fc499SJeff Garzik do {
2235b2fc499SJeff Garzik get_registers(dev, PHYCNT, 1, data);
2245b2fc499SJeff Garzik } while ((data[0] & PHY_GO) && (i++ < MII_TIMEOUT));
2255b2fc499SJeff Garzik
226c064efcaSroel kluin if (i <= MII_TIMEOUT) {
2275b2fc499SJeff Garzik get_registers(dev, PHYDAT, 2, data);
2285b2fc499SJeff Garzik *reg = data[0] | (data[1] << 8);
2295b2fc499SJeff Garzik return 0;
2305b2fc499SJeff Garzik } else
2315b2fc499SJeff Garzik return 1;
2325b2fc499SJeff Garzik }
2335b2fc499SJeff Garzik
write_mii_word(rtl8150_t * dev,u8 phy,__u8 indx,u16 reg)2345b2fc499SJeff Garzik static int write_mii_word(rtl8150_t * dev, u8 phy, __u8 indx, u16 reg)
2355b2fc499SJeff Garzik {
2365b2fc499SJeff Garzik int i;
2375b2fc499SJeff Garzik u8 data[3], tmp;
2385b2fc499SJeff Garzik
2395b2fc499SJeff Garzik data[0] = phy;
2405b2fc499SJeff Garzik data[1] = reg & 0xff;
2415b2fc499SJeff Garzik data[2] = (reg >> 8) & 0xff;
2425b2fc499SJeff Garzik tmp = indx | PHY_WRITE | PHY_GO;
2435b2fc499SJeff Garzik i = 0;
2445b2fc499SJeff Garzik
2455b2fc499SJeff Garzik set_registers(dev, PHYADD, sizeof(data), data);
2465b2fc499SJeff Garzik set_registers(dev, PHYCNT, 1, &tmp);
2475b2fc499SJeff Garzik do {
2485b2fc499SJeff Garzik get_registers(dev, PHYCNT, 1, data);
2495b2fc499SJeff Garzik } while ((data[0] & PHY_GO) && (i++ < MII_TIMEOUT));
2505b2fc499SJeff Garzik
251c064efcaSroel kluin if (i <= MII_TIMEOUT)
2525b2fc499SJeff Garzik return 0;
2535b2fc499SJeff Garzik else
2545b2fc499SJeff Garzik return 1;
2555b2fc499SJeff Garzik }
2565b2fc499SJeff Garzik
set_ethernet_addr(rtl8150_t * dev)257f45a4248SAnant Thazhemadam static void set_ethernet_addr(rtl8150_t *dev)
2585b2fc499SJeff Garzik {
259f45a4248SAnant Thazhemadam u8 node_id[ETH_ALEN];
260f45a4248SAnant Thazhemadam int ret;
2615b2fc499SJeff Garzik
262f45a4248SAnant Thazhemadam ret = get_registers(dev, IDR, sizeof(node_id), node_id);
263f45a4248SAnant Thazhemadam
26460f1626fSAnant Thazhemadam if (!ret) {
265af804e6dSJakub Kicinski eth_hw_addr_set(dev->netdev, node_id);
266f45a4248SAnant Thazhemadam } else {
267f45a4248SAnant Thazhemadam eth_hw_addr_random(dev->netdev);
268f45a4248SAnant Thazhemadam netdev_notice(dev->netdev, "Assigned a random MAC address: %pM\n",
269f45a4248SAnant Thazhemadam dev->netdev->dev_addr);
270f45a4248SAnant Thazhemadam }
2715b2fc499SJeff Garzik }
2725b2fc499SJeff Garzik
rtl8150_set_mac_address(struct net_device * netdev,void * p)2735b2fc499SJeff Garzik static int rtl8150_set_mac_address(struct net_device *netdev, void *p)
2745b2fc499SJeff Garzik {
2755b2fc499SJeff Garzik struct sockaddr *addr = p;
2765b2fc499SJeff Garzik rtl8150_t *dev = netdev_priv(netdev);
2775b2fc499SJeff Garzik
2785b2fc499SJeff Garzik if (netif_running(netdev))
2795b2fc499SJeff Garzik return -EBUSY;
2805b2fc499SJeff Garzik
28149ed8ddeSJakub Kicinski eth_hw_addr_set(netdev, addr->sa_data);
28249ae25b0SGreg Kroah-Hartman netdev_dbg(netdev, "Setting MAC address to %pM\n", netdev->dev_addr);
2835b2fc499SJeff Garzik /* Set the IDR registers. */
2846057912dSJulia Lawall set_registers(dev, IDR, netdev->addr_len, netdev->dev_addr);
2855b2fc499SJeff Garzik #ifdef EEPROM_WRITE
2865b2fc499SJeff Garzik {
287d649a284SH Hartley Sweeten int i;
2885b2fc499SJeff Garzik u8 cr;
2895b2fc499SJeff Garzik /* Get the CR contents. */
2905b2fc499SJeff Garzik get_registers(dev, CR, 1, &cr);
2915b2fc499SJeff Garzik /* Set the WEPROM bit (eeprom write enable). */
2925b2fc499SJeff Garzik cr |= 0x20;
2935b2fc499SJeff Garzik set_registers(dev, CR, 1, &cr);
2945b2fc499SJeff Garzik /* Write the MAC address into eeprom. Eeprom writes must be word-sized,
2955b2fc499SJeff Garzik so we need to split them up. */
2965b2fc499SJeff Garzik for (i = 0; i * 2 < netdev->addr_len; i++) {
2975b2fc499SJeff Garzik set_registers(dev, IDR_EEPROM + (i * 2), 2,
2985b2fc499SJeff Garzik netdev->dev_addr + (i * 2));
2995b2fc499SJeff Garzik }
3005b2fc499SJeff Garzik /* Clear the WEPROM bit (preventing accidental eeprom writes). */
3015b2fc499SJeff Garzik cr &= 0xdf;
3025b2fc499SJeff Garzik set_registers(dev, CR, 1, &cr);
3035b2fc499SJeff Garzik }
3045b2fc499SJeff Garzik #endif
3055b2fc499SJeff Garzik return 0;
3065b2fc499SJeff Garzik }
3075b2fc499SJeff Garzik
rtl8150_reset(rtl8150_t * dev)3085b2fc499SJeff Garzik static int rtl8150_reset(rtl8150_t * dev)
3095b2fc499SJeff Garzik {
3105b2fc499SJeff Garzik u8 data = 0x10;
3115b2fc499SJeff Garzik int i = HZ;
3125b2fc499SJeff Garzik
3135b2fc499SJeff Garzik set_registers(dev, CR, 1, &data);
3145b2fc499SJeff Garzik do {
3155b2fc499SJeff Garzik get_registers(dev, CR, 1, &data);
3165b2fc499SJeff Garzik } while ((data & 0x10) && --i);
3175b2fc499SJeff Garzik
3185b2fc499SJeff Garzik return (i > 0) ? 1 : 0;
3195b2fc499SJeff Garzik }
3205b2fc499SJeff Garzik
alloc_all_urbs(rtl8150_t * dev)3215b2fc499SJeff Garzik static int alloc_all_urbs(rtl8150_t * dev)
3225b2fc499SJeff Garzik {
3235b2fc499SJeff Garzik dev->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
3245b2fc499SJeff Garzik if (!dev->rx_urb)
3255b2fc499SJeff Garzik return 0;
3265b2fc499SJeff Garzik dev->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
3275b2fc499SJeff Garzik if (!dev->tx_urb) {
3285b2fc499SJeff Garzik usb_free_urb(dev->rx_urb);
3295b2fc499SJeff Garzik return 0;
3305b2fc499SJeff Garzik }
3315b2fc499SJeff Garzik dev->intr_urb = usb_alloc_urb(0, GFP_KERNEL);
3325b2fc499SJeff Garzik if (!dev->intr_urb) {
3335b2fc499SJeff Garzik usb_free_urb(dev->rx_urb);
3345b2fc499SJeff Garzik usb_free_urb(dev->tx_urb);
3355b2fc499SJeff Garzik return 0;
3365b2fc499SJeff Garzik }
3375b2fc499SJeff Garzik
3385b2fc499SJeff Garzik return 1;
3395b2fc499SJeff Garzik }
3405b2fc499SJeff Garzik
free_all_urbs(rtl8150_t * dev)3415b2fc499SJeff Garzik static void free_all_urbs(rtl8150_t * dev)
3425b2fc499SJeff Garzik {
3435b2fc499SJeff Garzik usb_free_urb(dev->rx_urb);
3445b2fc499SJeff Garzik usb_free_urb(dev->tx_urb);
3455b2fc499SJeff Garzik usb_free_urb(dev->intr_urb);
3465b2fc499SJeff Garzik }
3475b2fc499SJeff Garzik
unlink_all_urbs(rtl8150_t * dev)3485b2fc499SJeff Garzik static void unlink_all_urbs(rtl8150_t * dev)
3495b2fc499SJeff Garzik {
3505b2fc499SJeff Garzik usb_kill_urb(dev->rx_urb);
3515b2fc499SJeff Garzik usb_kill_urb(dev->tx_urb);
3525b2fc499SJeff Garzik usb_kill_urb(dev->intr_urb);
3535b2fc499SJeff Garzik }
3545b2fc499SJeff Garzik
pull_skb(rtl8150_t * dev)3555b2fc499SJeff Garzik static inline struct sk_buff *pull_skb(rtl8150_t *dev)
3565b2fc499SJeff Garzik {
3575b2fc499SJeff Garzik struct sk_buff *skb;
3585b2fc499SJeff Garzik int i;
3595b2fc499SJeff Garzik
3605b2fc499SJeff Garzik for (i = 0; i < RX_SKB_POOL_SIZE; i++) {
3615b2fc499SJeff Garzik if (dev->rx_skb_pool[i]) {
3625b2fc499SJeff Garzik skb = dev->rx_skb_pool[i];
3635b2fc499SJeff Garzik dev->rx_skb_pool[i] = NULL;
3645b2fc499SJeff Garzik return skb;
3655b2fc499SJeff Garzik }
3665b2fc499SJeff Garzik }
3675b2fc499SJeff Garzik return NULL;
3685b2fc499SJeff Garzik }
3695b2fc499SJeff Garzik
read_bulk_callback(struct urb * urb)3705b2fc499SJeff Garzik static void read_bulk_callback(struct urb *urb)
3715b2fc499SJeff Garzik {
3725b2fc499SJeff Garzik rtl8150_t *dev;
3735b2fc499SJeff Garzik unsigned pkt_len, res;
3745b2fc499SJeff Garzik struct sk_buff *skb;
3755b2fc499SJeff Garzik struct net_device *netdev;
376c94cb314SOliver Neukum int status = urb->status;
377c94cb314SOliver Neukum int result;
378feae641dSSebastian Andrzej Siewior unsigned long flags;
3795b2fc499SJeff Garzik
3805b2fc499SJeff Garzik dev = urb->context;
3815b2fc499SJeff Garzik if (!dev)
3825b2fc499SJeff Garzik return;
3835b2fc499SJeff Garzik if (test_bit(RTL8150_UNPLUG, &dev->flags))
3845b2fc499SJeff Garzik return;
3855b2fc499SJeff Garzik netdev = dev->netdev;
3865b2fc499SJeff Garzik if (!netif_device_present(netdev))
3875b2fc499SJeff Garzik return;
3885b2fc499SJeff Garzik
389c94cb314SOliver Neukum switch (status) {
3905b2fc499SJeff Garzik case 0:
3915b2fc499SJeff Garzik break;
3925b2fc499SJeff Garzik case -ENOENT:
3935b2fc499SJeff Garzik return; /* the urb is in unlink state */
3945b2fc499SJeff Garzik case -ETIME:
395342a437eSAndré Goddard Rosa if (printk_ratelimit())
3964dc89948SGreg Kroah-Hartman dev_warn(&urb->dev->dev, "may be reset is needed?..\n");
3975b2fc499SJeff Garzik goto goon;
3985b2fc499SJeff Garzik default:
399342a437eSAndré Goddard Rosa if (printk_ratelimit())
400c94cb314SOliver Neukum dev_warn(&urb->dev->dev, "Rx status %d\n", status);
4015b2fc499SJeff Garzik goto goon;
4025b2fc499SJeff Garzik }
4035b2fc499SJeff Garzik
4045b2fc499SJeff Garzik if (!dev->rx_skb)
4055b2fc499SJeff Garzik goto resched;
4065b2fc499SJeff Garzik /* protect against short packets (tell me why we got some?!?) */
4075b2fc499SJeff Garzik if (urb->actual_length < 4)
4085b2fc499SJeff Garzik goto goon;
4095b2fc499SJeff Garzik
4105b2fc499SJeff Garzik res = urb->actual_length;
4115b2fc499SJeff Garzik pkt_len = res - 4;
4125b2fc499SJeff Garzik
4135b2fc499SJeff Garzik skb_put(dev->rx_skb, pkt_len);
4145b2fc499SJeff Garzik dev->rx_skb->protocol = eth_type_trans(dev->rx_skb, netdev);
4155b2fc499SJeff Garzik netif_rx(dev->rx_skb);
416b7e41e23SStephen Hemminger netdev->stats.rx_packets++;
417b7e41e23SStephen Hemminger netdev->stats.rx_bytes += pkt_len;
4185b2fc499SJeff Garzik
419feae641dSSebastian Andrzej Siewior spin_lock_irqsave(&dev->rx_pool_lock, flags);
4205b2fc499SJeff Garzik skb = pull_skb(dev);
421feae641dSSebastian Andrzej Siewior spin_unlock_irqrestore(&dev->rx_pool_lock, flags);
4225b2fc499SJeff Garzik if (!skb)
4235b2fc499SJeff Garzik goto resched;
4245b2fc499SJeff Garzik
4255b2fc499SJeff Garzik dev->rx_skb = skb;
4265b2fc499SJeff Garzik goon:
4275b2fc499SJeff Garzik usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
4285b2fc499SJeff Garzik dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev);
429c94cb314SOliver Neukum result = usb_submit_urb(dev->rx_urb, GFP_ATOMIC);
430c94cb314SOliver Neukum if (result == -ENODEV)
4315b2fc499SJeff Garzik netif_device_detach(dev->netdev);
432c94cb314SOliver Neukum else if (result) {
4335b2fc499SJeff Garzik set_bit(RX_URB_FAIL, &dev->flags);
4345b2fc499SJeff Garzik goto resched;
4355b2fc499SJeff Garzik } else {
4365b2fc499SJeff Garzik clear_bit(RX_URB_FAIL, &dev->flags);
4375b2fc499SJeff Garzik }
4385b2fc499SJeff Garzik
4395b2fc499SJeff Garzik return;
4405b2fc499SJeff Garzik resched:
4415b2fc499SJeff Garzik tasklet_schedule(&dev->tl);
4425b2fc499SJeff Garzik }
4435b2fc499SJeff Garzik
write_bulk_callback(struct urb * urb)4445b2fc499SJeff Garzik static void write_bulk_callback(struct urb *urb)
4455b2fc499SJeff Garzik {
4465b2fc499SJeff Garzik rtl8150_t *dev;
447c94cb314SOliver Neukum int status = urb->status;
4485b2fc499SJeff Garzik
4495b2fc499SJeff Garzik dev = urb->context;
4505b2fc499SJeff Garzik if (!dev)
4515b2fc499SJeff Garzik return;
4525b2fc499SJeff Garzik dev_kfree_skb_irq(dev->tx_skb);
4535b2fc499SJeff Garzik if (!netif_device_present(dev->netdev))
4545b2fc499SJeff Garzik return;
455c94cb314SOliver Neukum if (status)
456880c9c66SGreg Kroah-Hartman dev_info(&urb->dev->dev, "%s: Tx status %d\n",
457c94cb314SOliver Neukum dev->netdev->name, status);
458860e9538SFlorian Westphal netif_trans_update(dev->netdev);
4595b2fc499SJeff Garzik netif_wake_queue(dev->netdev);
4605b2fc499SJeff Garzik }
4615b2fc499SJeff Garzik
intr_callback(struct urb * urb)4625b2fc499SJeff Garzik static void intr_callback(struct urb *urb)
4635b2fc499SJeff Garzik {
4645b2fc499SJeff Garzik rtl8150_t *dev;
4655b2fc499SJeff Garzik __u8 *d;
466c94cb314SOliver Neukum int status = urb->status;
467c94cb314SOliver Neukum int res;
4685b2fc499SJeff Garzik
4695b2fc499SJeff Garzik dev = urb->context;
4705b2fc499SJeff Garzik if (!dev)
4715b2fc499SJeff Garzik return;
472c94cb314SOliver Neukum switch (status) {
4735b2fc499SJeff Garzik case 0: /* success */
4745b2fc499SJeff Garzik break;
4755b2fc499SJeff Garzik case -ECONNRESET: /* unlink */
4765b2fc499SJeff Garzik case -ENOENT:
4775b2fc499SJeff Garzik case -ESHUTDOWN:
4785b2fc499SJeff Garzik return;
4795b2fc499SJeff Garzik /* -EPIPE: should clear the halt */
4805b2fc499SJeff Garzik default:
481880c9c66SGreg Kroah-Hartman dev_info(&urb->dev->dev, "%s: intr status %d\n",
482c94cb314SOliver Neukum dev->netdev->name, status);
4835b2fc499SJeff Garzik goto resubmit;
4845b2fc499SJeff Garzik }
4855b2fc499SJeff Garzik
4865b2fc499SJeff Garzik d = urb->transfer_buffer;
4875b2fc499SJeff Garzik if (d[0] & TSR_ERRORS) {
488b7e41e23SStephen Hemminger dev->netdev->stats.tx_errors++;
4895b2fc499SJeff Garzik if (d[INT_TSR] & (TSR_ECOL | TSR_JBR))
490b7e41e23SStephen Hemminger dev->netdev->stats.tx_aborted_errors++;
4915b2fc499SJeff Garzik if (d[INT_TSR] & TSR_LCOL)
492b7e41e23SStephen Hemminger dev->netdev->stats.tx_window_errors++;
4935b2fc499SJeff Garzik if (d[INT_TSR] & TSR_LOSS_CRS)
494b7e41e23SStephen Hemminger dev->netdev->stats.tx_carrier_errors++;
4955b2fc499SJeff Garzik }
4965b2fc499SJeff Garzik /* Report link status changes to the network stack */
4975b2fc499SJeff Garzik if ((d[INT_MSR] & MSR_LINK) == 0) {
4985b2fc499SJeff Garzik if (netif_carrier_ok(dev->netdev)) {
4995b2fc499SJeff Garzik netif_carrier_off(dev->netdev);
50049ae25b0SGreg Kroah-Hartman netdev_dbg(dev->netdev, "%s: LINK LOST\n", __func__);
5015b2fc499SJeff Garzik }
5025b2fc499SJeff Garzik } else {
5035b2fc499SJeff Garzik if (!netif_carrier_ok(dev->netdev)) {
5045b2fc499SJeff Garzik netif_carrier_on(dev->netdev);
50549ae25b0SGreg Kroah-Hartman netdev_dbg(dev->netdev, "%s: LINK CAME BACK\n", __func__);
5065b2fc499SJeff Garzik }
5075b2fc499SJeff Garzik }
5085b2fc499SJeff Garzik
5095b2fc499SJeff Garzik resubmit:
510c94cb314SOliver Neukum res = usb_submit_urb (urb, GFP_ATOMIC);
511c94cb314SOliver Neukum if (res == -ENODEV)
5125b2fc499SJeff Garzik netif_device_detach(dev->netdev);
513c94cb314SOliver Neukum else if (res)
51421f52432SGreg Kroah-Hartman dev_err(&dev->udev->dev,
51521f52432SGreg Kroah-Hartman "can't resubmit intr, %s-%s/input0, status %d\n",
51621f52432SGreg Kroah-Hartman dev->udev->bus->bus_name, dev->udev->devpath, res);
5175b2fc499SJeff Garzik }
5185b2fc499SJeff Garzik
rtl8150_suspend(struct usb_interface * intf,pm_message_t message)5195b2fc499SJeff Garzik static int rtl8150_suspend(struct usb_interface *intf, pm_message_t message)
5205b2fc499SJeff Garzik {
5215b2fc499SJeff Garzik rtl8150_t *dev = usb_get_intfdata(intf);
5225b2fc499SJeff Garzik
5235b2fc499SJeff Garzik netif_device_detach(dev->netdev);
5245b2fc499SJeff Garzik
5255b2fc499SJeff Garzik if (netif_running(dev->netdev)) {
5265b2fc499SJeff Garzik usb_kill_urb(dev->rx_urb);
5275b2fc499SJeff Garzik usb_kill_urb(dev->intr_urb);
5285b2fc499SJeff Garzik }
5295b2fc499SJeff Garzik return 0;
5305b2fc499SJeff Garzik }
5315b2fc499SJeff Garzik
rtl8150_resume(struct usb_interface * intf)5325b2fc499SJeff Garzik static int rtl8150_resume(struct usb_interface *intf)
5335b2fc499SJeff Garzik {
5345b2fc499SJeff Garzik rtl8150_t *dev = usb_get_intfdata(intf);
5355b2fc499SJeff Garzik
5365b2fc499SJeff Garzik netif_device_attach(dev->netdev);
5375b2fc499SJeff Garzik if (netif_running(dev->netdev)) {
5385b2fc499SJeff Garzik dev->rx_urb->status = 0;
5395b2fc499SJeff Garzik dev->rx_urb->actual_length = 0;
5405b2fc499SJeff Garzik read_bulk_callback(dev->rx_urb);
5415b2fc499SJeff Garzik
5425b2fc499SJeff Garzik dev->intr_urb->status = 0;
5435b2fc499SJeff Garzik dev->intr_urb->actual_length = 0;
5445b2fc499SJeff Garzik intr_callback(dev->intr_urb);
5455b2fc499SJeff Garzik }
5465b2fc499SJeff Garzik return 0;
5475b2fc499SJeff Garzik }
5485b2fc499SJeff Garzik
5495b2fc499SJeff Garzik /*
5505b2fc499SJeff Garzik **
5515b2fc499SJeff Garzik ** network related part of the code
5525b2fc499SJeff Garzik **
5535b2fc499SJeff Garzik */
5545b2fc499SJeff Garzik
fill_skb_pool(rtl8150_t * dev)5555b2fc499SJeff Garzik static void fill_skb_pool(rtl8150_t *dev)
5565b2fc499SJeff Garzik {
5575b2fc499SJeff Garzik struct sk_buff *skb;
5585b2fc499SJeff Garzik int i;
5595b2fc499SJeff Garzik
5605b2fc499SJeff Garzik for (i = 0; i < RX_SKB_POOL_SIZE; i++) {
5615b2fc499SJeff Garzik if (dev->rx_skb_pool[i])
5625b2fc499SJeff Garzik continue;
5635b2fc499SJeff Garzik skb = dev_alloc_skb(RTL8150_MTU + 2);
5645b2fc499SJeff Garzik if (!skb) {
5655b2fc499SJeff Garzik return;
5665b2fc499SJeff Garzik }
5675b2fc499SJeff Garzik skb_reserve(skb, 2);
5685b2fc499SJeff Garzik dev->rx_skb_pool[i] = skb;
5695b2fc499SJeff Garzik }
5705b2fc499SJeff Garzik }
5715b2fc499SJeff Garzik
free_skb_pool(rtl8150_t * dev)5725b2fc499SJeff Garzik static void free_skb_pool(rtl8150_t *dev)
5735b2fc499SJeff Garzik {
5745b2fc499SJeff Garzik int i;
5755b2fc499SJeff Garzik
5765b2fc499SJeff Garzik for (i = 0; i < RX_SKB_POOL_SIZE; i++)
5775b2fc499SJeff Garzik dev_kfree_skb(dev->rx_skb_pool[i]);
5785b2fc499SJeff Garzik }
5795b2fc499SJeff Garzik
rx_fixup(struct tasklet_struct * t)5801999ad32SEmil Renner Berthing static void rx_fixup(struct tasklet_struct *t)
581141b9e66Sfrançois romieu {
5821999ad32SEmil Renner Berthing struct rtl8150 *dev = from_tasklet(dev, t, tl);
583141b9e66Sfrançois romieu struct sk_buff *skb;
584141b9e66Sfrançois romieu int status;
585141b9e66Sfrançois romieu
586141b9e66Sfrançois romieu spin_lock_irq(&dev->rx_pool_lock);
587141b9e66Sfrançois romieu fill_skb_pool(dev);
588141b9e66Sfrançois romieu spin_unlock_irq(&dev->rx_pool_lock);
589141b9e66Sfrançois romieu if (test_bit(RX_URB_FAIL, &dev->flags))
590141b9e66Sfrançois romieu if (dev->rx_skb)
591141b9e66Sfrançois romieu goto try_again;
592141b9e66Sfrançois romieu spin_lock_irq(&dev->rx_pool_lock);
593141b9e66Sfrançois romieu skb = pull_skb(dev);
594141b9e66Sfrançois romieu spin_unlock_irq(&dev->rx_pool_lock);
595141b9e66Sfrançois romieu if (skb == NULL)
596141b9e66Sfrançois romieu goto tlsched;
597141b9e66Sfrançois romieu dev->rx_skb = skb;
598141b9e66Sfrançois romieu usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
599141b9e66Sfrançois romieu dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev);
600141b9e66Sfrançois romieu try_again:
601141b9e66Sfrançois romieu status = usb_submit_urb(dev->rx_urb, GFP_ATOMIC);
602141b9e66Sfrançois romieu if (status == -ENODEV) {
603141b9e66Sfrançois romieu netif_device_detach(dev->netdev);
604141b9e66Sfrançois romieu } else if (status) {
605141b9e66Sfrançois romieu set_bit(RX_URB_FAIL, &dev->flags);
606141b9e66Sfrançois romieu goto tlsched;
607141b9e66Sfrançois romieu } else {
608141b9e66Sfrançois romieu clear_bit(RX_URB_FAIL, &dev->flags);
609141b9e66Sfrançois romieu }
610141b9e66Sfrançois romieu
611141b9e66Sfrançois romieu return;
612141b9e66Sfrançois romieu tlsched:
613141b9e66Sfrançois romieu tasklet_schedule(&dev->tl);
614141b9e66Sfrançois romieu }
615141b9e66Sfrançois romieu
enable_net_traffic(rtl8150_t * dev)6165b2fc499SJeff Garzik static int enable_net_traffic(rtl8150_t * dev)
6175b2fc499SJeff Garzik {
6185b2fc499SJeff Garzik u8 cr, tcr, rcr, msr;
6195b2fc499SJeff Garzik
6205b2fc499SJeff Garzik if (!rtl8150_reset(dev)) {
6214dc89948SGreg Kroah-Hartman dev_warn(&dev->udev->dev, "device reset failed\n");
6225b2fc499SJeff Garzik }
6235b2fc499SJeff Garzik /* RCR bit7=1 attach Rx info at the end; =0 HW CRC (which is broken) */
6245b2fc499SJeff Garzik rcr = 0x9e;
6255b2fc499SJeff Garzik tcr = 0xd8;
6265b2fc499SJeff Garzik cr = 0x0c;
6275b2fc499SJeff Garzik if (!(rcr & 0x80))
6285b2fc499SJeff Garzik set_bit(RTL8150_HW_CRC, &dev->flags);
6295b2fc499SJeff Garzik set_registers(dev, RCR, 1, &rcr);
6305b2fc499SJeff Garzik set_registers(dev, TCR, 1, &tcr);
6315b2fc499SJeff Garzik set_registers(dev, CR, 1, &cr);
6325b2fc499SJeff Garzik get_registers(dev, MSR, 1, &msr);
6335b2fc499SJeff Garzik
6345b2fc499SJeff Garzik return 0;
6355b2fc499SJeff Garzik }
6365b2fc499SJeff Garzik
disable_net_traffic(rtl8150_t * dev)6375b2fc499SJeff Garzik static void disable_net_traffic(rtl8150_t * dev)
6385b2fc499SJeff Garzik {
6395b2fc499SJeff Garzik u8 cr;
6405b2fc499SJeff Garzik
6415b2fc499SJeff Garzik get_registers(dev, CR, 1, &cr);
6425b2fc499SJeff Garzik cr &= 0xf3;
6435b2fc499SJeff Garzik set_registers(dev, CR, 1, &cr);
6445b2fc499SJeff Garzik }
6455b2fc499SJeff Garzik
rtl8150_tx_timeout(struct net_device * netdev,unsigned int txqueue)6460290bd29SMichael S. Tsirkin static void rtl8150_tx_timeout(struct net_device *netdev, unsigned int txqueue)
6475b2fc499SJeff Garzik {
6485b2fc499SJeff Garzik rtl8150_t *dev = netdev_priv(netdev);
6494dc89948SGreg Kroah-Hartman dev_warn(&netdev->dev, "Tx timeout.\n");
6505b2fc499SJeff Garzik usb_unlink_urb(dev->tx_urb);
651b7e41e23SStephen Hemminger netdev->stats.tx_errors++;
6525b2fc499SJeff Garzik }
6535b2fc499SJeff Garzik
rtl8150_set_multicast(struct net_device * netdev)6545b2fc499SJeff Garzik static void rtl8150_set_multicast(struct net_device *netdev)
6555b2fc499SJeff Garzik {
6565b2fc499SJeff Garzik rtl8150_t *dev = netdev_priv(netdev);
6574d12997aSPetko Manolov u16 rx_creg = 0x9e;
6584d12997aSPetko Manolov
6595b2fc499SJeff Garzik netif_stop_queue(netdev);
6605b2fc499SJeff Garzik if (netdev->flags & IFF_PROMISC) {
6614d12997aSPetko Manolov rx_creg |= 0x0001;
662880c9c66SGreg Kroah-Hartman dev_info(&netdev->dev, "%s: promiscuous mode\n", netdev->name);
6634cd24eafSJiri Pirko } else if (!netdev_mc_empty(netdev) ||
6645b2fc499SJeff Garzik (netdev->flags & IFF_ALLMULTI)) {
6654d12997aSPetko Manolov rx_creg &= 0xfffe;
6664d12997aSPetko Manolov rx_creg |= 0x0002;
6673a9b0455SDavid Lechner dev_dbg(&netdev->dev, "%s: allmulti set\n", netdev->name);
6685b2fc499SJeff Garzik } else {
6695b2fc499SJeff Garzik /* ~RX_MULTICAST, ~RX_PROMISCUOUS */
6704d12997aSPetko Manolov rx_creg &= 0x00fc;
6715b2fc499SJeff Garzik }
6724d12997aSPetko Manolov async_set_registers(dev, RCR, sizeof(rx_creg), rx_creg);
6735b2fc499SJeff Garzik netif_wake_queue(netdev);
6745b2fc499SJeff Garzik }
6755b2fc499SJeff Garzik
rtl8150_start_xmit(struct sk_buff * skb,struct net_device * netdev)67625a79c41SStephen Hemminger static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb,
67725a79c41SStephen Hemminger struct net_device *netdev)
6785b2fc499SJeff Garzik {
6795b2fc499SJeff Garzik rtl8150_t *dev = netdev_priv(netdev);
6805b2fc499SJeff Garzik int count, res;
6815b2fc499SJeff Garzik
6825b2fc499SJeff Garzik netif_stop_queue(netdev);
6835b2fc499SJeff Garzik count = (skb->len < 60) ? 60 : skb->len;
6845b2fc499SJeff Garzik count = (count & 0x3f) ? count : count + 1;
6855b2fc499SJeff Garzik dev->tx_skb = skb;
6865b2fc499SJeff Garzik usb_fill_bulk_urb(dev->tx_urb, dev->udev, usb_sndbulkpipe(dev->udev, 2),
6875b2fc499SJeff Garzik skb->data, count, write_bulk_callback, dev);
6885b2fc499SJeff Garzik if ((res = usb_submit_urb(dev->tx_urb, GFP_ATOMIC))) {
6895b2fc499SJeff Garzik /* Can we get/handle EPIPE here? */
6905b2fc499SJeff Garzik if (res == -ENODEV)
6915b2fc499SJeff Garzik netif_device_detach(dev->netdev);
6925b2fc499SJeff Garzik else {
6934dc89948SGreg Kroah-Hartman dev_warn(&netdev->dev, "failed tx_urb %d\n", res);
694b7e41e23SStephen Hemminger netdev->stats.tx_errors++;
6955b2fc499SJeff Garzik netif_start_queue(netdev);
6965b2fc499SJeff Garzik }
6975b2fc499SJeff Garzik } else {
698b7e41e23SStephen Hemminger netdev->stats.tx_packets++;
699b7e41e23SStephen Hemminger netdev->stats.tx_bytes += skb->len;
700860e9538SFlorian Westphal netif_trans_update(netdev);
7015b2fc499SJeff Garzik }
7025b2fc499SJeff Garzik
7036ed10654SPatrick McHardy return NETDEV_TX_OK;
7045b2fc499SJeff Garzik }
7055b2fc499SJeff Garzik
7065b2fc499SJeff Garzik
set_carrier(struct net_device * netdev)7075b2fc499SJeff Garzik static void set_carrier(struct net_device *netdev)
7085b2fc499SJeff Garzik {
7095b2fc499SJeff Garzik rtl8150_t *dev = netdev_priv(netdev);
7105b2fc499SJeff Garzik short tmp;
7115b2fc499SJeff Garzik
7125b2fc499SJeff Garzik get_registers(dev, CSCR, 2, &tmp);
7135b2fc499SJeff Garzik if (tmp & CSCR_LINK_STATUS)
7145b2fc499SJeff Garzik netif_carrier_on(netdev);
7155b2fc499SJeff Garzik else
7165b2fc499SJeff Garzik netif_carrier_off(netdev);
7175b2fc499SJeff Garzik }
7185b2fc499SJeff Garzik
rtl8150_open(struct net_device * netdev)7195b2fc499SJeff Garzik static int rtl8150_open(struct net_device *netdev)
7205b2fc499SJeff Garzik {
7215b2fc499SJeff Garzik rtl8150_t *dev = netdev_priv(netdev);
7225b2fc499SJeff Garzik int res;
7235b2fc499SJeff Garzik
7245b2fc499SJeff Garzik if (dev->rx_skb == NULL)
7255b2fc499SJeff Garzik dev->rx_skb = pull_skb(dev);
7265b2fc499SJeff Garzik if (!dev->rx_skb)
7275b2fc499SJeff Garzik return -ENOMEM;
7285b2fc499SJeff Garzik
7295b2fc499SJeff Garzik set_registers(dev, IDR, 6, netdev->dev_addr);
7305b2fc499SJeff Garzik
7315b2fc499SJeff Garzik usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
7325b2fc499SJeff Garzik dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev);
7335b2fc499SJeff Garzik if ((res = usb_submit_urb(dev->rx_urb, GFP_KERNEL))) {
7345b2fc499SJeff Garzik if (res == -ENODEV)
7355b2fc499SJeff Garzik netif_device_detach(dev->netdev);
7364dc89948SGreg Kroah-Hartman dev_warn(&netdev->dev, "rx_urb submit failed: %d\n", res);
7375b2fc499SJeff Garzik return res;
7385b2fc499SJeff Garzik }
7395b2fc499SJeff Garzik usb_fill_int_urb(dev->intr_urb, dev->udev, usb_rcvintpipe(dev->udev, 3),
7405b2fc499SJeff Garzik dev->intr_buff, INTBUFSIZE, intr_callback,
7415b2fc499SJeff Garzik dev, dev->intr_interval);
7425b2fc499SJeff Garzik if ((res = usb_submit_urb(dev->intr_urb, GFP_KERNEL))) {
7435b2fc499SJeff Garzik if (res == -ENODEV)
7445b2fc499SJeff Garzik netif_device_detach(dev->netdev);
7454dc89948SGreg Kroah-Hartman dev_warn(&netdev->dev, "intr_urb submit failed: %d\n", res);
7465b2fc499SJeff Garzik usb_kill_urb(dev->rx_urb);
7475b2fc499SJeff Garzik return res;
7485b2fc499SJeff Garzik }
7495b2fc499SJeff Garzik enable_net_traffic(dev);
7505b2fc499SJeff Garzik set_carrier(netdev);
7515b2fc499SJeff Garzik netif_start_queue(netdev);
7525b2fc499SJeff Garzik
7535b2fc499SJeff Garzik return res;
7545b2fc499SJeff Garzik }
7555b2fc499SJeff Garzik
rtl8150_close(struct net_device * netdev)7565b2fc499SJeff Garzik static int rtl8150_close(struct net_device *netdev)
7575b2fc499SJeff Garzik {
7585b2fc499SJeff Garzik rtl8150_t *dev = netdev_priv(netdev);
7595b2fc499SJeff Garzik
7605b2fc499SJeff Garzik netif_stop_queue(netdev);
7615b2fc499SJeff Garzik if (!test_bit(RTL8150_UNPLUG, &dev->flags))
7625b2fc499SJeff Garzik disable_net_traffic(dev);
7635b2fc499SJeff Garzik unlink_all_urbs(dev);
7645b2fc499SJeff Garzik
7651abe7cd9SSudip Mukherjee return 0;
7665b2fc499SJeff Garzik }
7675b2fc499SJeff Garzik
rtl8150_get_drvinfo(struct net_device * netdev,struct ethtool_drvinfo * info)7685b2fc499SJeff Garzik static void rtl8150_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *info)
7695b2fc499SJeff Garzik {
7705b2fc499SJeff Garzik rtl8150_t *dev = netdev_priv(netdev);
7715b2fc499SJeff Garzik
772fb3ceec1SWolfram Sang strscpy(info->driver, driver_name, sizeof(info->driver));
773fb3ceec1SWolfram Sang strscpy(info->version, DRIVER_VERSION, sizeof(info->version));
7747826d43fSJiri Pirko usb_make_path(dev->udev, info->bus_info, sizeof(info->bus_info));
7755b2fc499SJeff Garzik }
7765b2fc499SJeff Garzik
rtl8150_get_link_ksettings(struct net_device * netdev,struct ethtool_link_ksettings * ecmd)777b66239b6SPhilippe Reynes static int rtl8150_get_link_ksettings(struct net_device *netdev,
778b66239b6SPhilippe Reynes struct ethtool_link_ksettings *ecmd)
7795b2fc499SJeff Garzik {
7805b2fc499SJeff Garzik rtl8150_t *dev = netdev_priv(netdev);
781*7bcca710SOliver Neukum short lpa = 0;
782*7bcca710SOliver Neukum short bmcr = 0;
783b66239b6SPhilippe Reynes u32 supported;
7845b2fc499SJeff Garzik
785b66239b6SPhilippe Reynes supported = (SUPPORTED_10baseT_Half |
7865b2fc499SJeff Garzik SUPPORTED_10baseT_Full |
7875b2fc499SJeff Garzik SUPPORTED_100baseT_Half |
7885b2fc499SJeff Garzik SUPPORTED_100baseT_Full |
7895b2fc499SJeff Garzik SUPPORTED_Autoneg |
7905b2fc499SJeff Garzik SUPPORTED_TP | SUPPORTED_MII);
791b66239b6SPhilippe Reynes ecmd->base.port = PORT_TP;
792b66239b6SPhilippe Reynes ecmd->base.phy_address = dev->phy;
7935b2fc499SJeff Garzik get_registers(dev, BMCR, 2, &bmcr);
7945b2fc499SJeff Garzik get_registers(dev, ANLP, 2, &lpa);
7955b2fc499SJeff Garzik if (bmcr & BMCR_ANENABLE) {
79670739497SDavid Decotigny u32 speed = ((lpa & (LPA_100HALF | LPA_100FULL)) ?
79770739497SDavid Decotigny SPEED_100 : SPEED_10);
798b66239b6SPhilippe Reynes ecmd->base.speed = speed;
799b66239b6SPhilippe Reynes ecmd->base.autoneg = AUTONEG_ENABLE;
80070739497SDavid Decotigny if (speed == SPEED_100)
801b66239b6SPhilippe Reynes ecmd->base.duplex = (lpa & LPA_100FULL) ?
8025b2fc499SJeff Garzik DUPLEX_FULL : DUPLEX_HALF;
8035b2fc499SJeff Garzik else
804b66239b6SPhilippe Reynes ecmd->base.duplex = (lpa & LPA_10FULL) ?
8055b2fc499SJeff Garzik DUPLEX_FULL : DUPLEX_HALF;
8065b2fc499SJeff Garzik } else {
807b66239b6SPhilippe Reynes ecmd->base.autoneg = AUTONEG_DISABLE;
808b66239b6SPhilippe Reynes ecmd->base.speed = ((bmcr & BMCR_SPEED100) ?
809b66239b6SPhilippe Reynes SPEED_100 : SPEED_10);
810b66239b6SPhilippe Reynes ecmd->base.duplex = (bmcr & BMCR_FULLDPLX) ?
8115b2fc499SJeff Garzik DUPLEX_FULL : DUPLEX_HALF;
8125b2fc499SJeff Garzik }
813b66239b6SPhilippe Reynes
814b66239b6SPhilippe Reynes ethtool_convert_legacy_u32_to_link_mode(ecmd->link_modes.supported,
815b66239b6SPhilippe Reynes supported);
816b66239b6SPhilippe Reynes
8175b2fc499SJeff Garzik return 0;
8185b2fc499SJeff Garzik }
8195b2fc499SJeff Garzik
8200fc0b732SStephen Hemminger static const struct ethtool_ops ops = {
8215b2fc499SJeff Garzik .get_drvinfo = rtl8150_get_drvinfo,
822b66239b6SPhilippe Reynes .get_link = ethtool_op_get_link,
823b66239b6SPhilippe Reynes .get_link_ksettings = rtl8150_get_link_ksettings,
8245b2fc499SJeff Garzik };
8255b2fc499SJeff Garzik
rtl8150_siocdevprivate(struct net_device * netdev,struct ifreq * rq,void __user * udata,int cmd)826ef1b5b0cSArnd Bergmann static int rtl8150_siocdevprivate(struct net_device *netdev, struct ifreq *rq,
827ef1b5b0cSArnd Bergmann void __user *udata, int cmd)
8285b2fc499SJeff Garzik {
8295b2fc499SJeff Garzik rtl8150_t *dev = netdev_priv(netdev);
8305b2fc499SJeff Garzik u16 *data = (u16 *) & rq->ifr_ifru;
8315b2fc499SJeff Garzik int res = 0;
8325b2fc499SJeff Garzik
8335b2fc499SJeff Garzik switch (cmd) {
8345b2fc499SJeff Garzik case SIOCDEVPRIVATE:
8355b2fc499SJeff Garzik data[0] = dev->phy;
836df561f66SGustavo A. R. Silva fallthrough;
8375b2fc499SJeff Garzik case SIOCDEVPRIVATE + 1:
8385b2fc499SJeff Garzik read_mii_word(dev, dev->phy, (data[1] & 0x1f), &data[3]);
8395b2fc499SJeff Garzik break;
8405b2fc499SJeff Garzik case SIOCDEVPRIVATE + 2:
8415b2fc499SJeff Garzik if (!capable(CAP_NET_ADMIN))
8425b2fc499SJeff Garzik return -EPERM;
8435b2fc499SJeff Garzik write_mii_word(dev, dev->phy, (data[1] & 0x1f), data[2]);
8445b2fc499SJeff Garzik break;
8455b2fc499SJeff Garzik default:
8465b2fc499SJeff Garzik res = -EOPNOTSUPP;
8475b2fc499SJeff Garzik }
8485b2fc499SJeff Garzik
8495b2fc499SJeff Garzik return res;
8505b2fc499SJeff Garzik }
8515b2fc499SJeff Garzik
852d79f7ef4SStephen Hemminger static const struct net_device_ops rtl8150_netdev_ops = {
853d79f7ef4SStephen Hemminger .ndo_open = rtl8150_open,
854d79f7ef4SStephen Hemminger .ndo_stop = rtl8150_close,
855ef1b5b0cSArnd Bergmann .ndo_siocdevprivate = rtl8150_siocdevprivate,
856d79f7ef4SStephen Hemminger .ndo_start_xmit = rtl8150_start_xmit,
857d79f7ef4SStephen Hemminger .ndo_tx_timeout = rtl8150_tx_timeout,
858afc4b13dSJiri Pirko .ndo_set_rx_mode = rtl8150_set_multicast,
859d79f7ef4SStephen Hemminger .ndo_set_mac_address = rtl8150_set_mac_address,
860d79f7ef4SStephen Hemminger
861d79f7ef4SStephen Hemminger .ndo_validate_addr = eth_validate_addr,
862d79f7ef4SStephen Hemminger };
863d79f7ef4SStephen Hemminger
rtl8150_probe(struct usb_interface * intf,const struct usb_device_id * id)8645b2fc499SJeff Garzik static int rtl8150_probe(struct usb_interface *intf,
8655b2fc499SJeff Garzik const struct usb_device_id *id)
8665b2fc499SJeff Garzik {
8675b2fc499SJeff Garzik struct usb_device *udev = interface_to_usbdev(intf);
8685b2fc499SJeff Garzik rtl8150_t *dev;
8695b2fc499SJeff Garzik struct net_device *netdev;
8705b2fc499SJeff Garzik
8715b2fc499SJeff Garzik netdev = alloc_etherdev(sizeof(rtl8150_t));
87241de8d4cSJoe Perches if (!netdev)
8735b2fc499SJeff Garzik return -ENOMEM;
8745b2fc499SJeff Garzik
8755b2fc499SJeff Garzik dev = netdev_priv(netdev);
8765b2fc499SJeff Garzik
8775b2fc499SJeff Garzik dev->intr_buff = kmalloc(INTBUFSIZE, GFP_KERNEL);
8785b2fc499SJeff Garzik if (!dev->intr_buff) {
8795b2fc499SJeff Garzik free_netdev(netdev);
8805b2fc499SJeff Garzik return -ENOMEM;
8815b2fc499SJeff Garzik }
8825b2fc499SJeff Garzik
8831999ad32SEmil Renner Berthing tasklet_setup(&dev->tl, rx_fixup);
8845b2fc499SJeff Garzik spin_lock_init(&dev->rx_pool_lock);
8855b2fc499SJeff Garzik
8865b2fc499SJeff Garzik dev->udev = udev;
8875b2fc499SJeff Garzik dev->netdev = netdev;
888d79f7ef4SStephen Hemminger netdev->netdev_ops = &rtl8150_netdev_ops;
8895b2fc499SJeff Garzik netdev->watchdog_timeo = RTL8150_TX_TIMEOUT;
8907ad24ea4SWilfried Klaebe netdev->ethtool_ops = &ops;
8915b2fc499SJeff Garzik dev->intr_interval = 100; /* 100ms */
8925b2fc499SJeff Garzik
8935b2fc499SJeff Garzik if (!alloc_all_urbs(dev)) {
89421f52432SGreg Kroah-Hartman dev_err(&intf->dev, "out of memory\n");
8955b2fc499SJeff Garzik goto out;
8965b2fc499SJeff Garzik }
8975b2fc499SJeff Garzik if (!rtl8150_reset(dev)) {
89821f52432SGreg Kroah-Hartman dev_err(&intf->dev, "couldn't reset the device\n");
8995b2fc499SJeff Garzik goto out1;
9005b2fc499SJeff Garzik }
9015b2fc499SJeff Garzik fill_skb_pool(dev);
9025b2fc499SJeff Garzik set_ethernet_addr(dev);
9035b2fc499SJeff Garzik
9045b2fc499SJeff Garzik usb_set_intfdata(intf, dev);
9055b2fc499SJeff Garzik SET_NETDEV_DEV(netdev, &intf->dev);
9065b2fc499SJeff Garzik if (register_netdev(netdev) != 0) {
90721f52432SGreg Kroah-Hartman dev_err(&intf->dev, "couldn't register the device\n");
9085b2fc499SJeff Garzik goto out2;
9095b2fc499SJeff Garzik }
9105b2fc499SJeff Garzik
911880c9c66SGreg Kroah-Hartman dev_info(&intf->dev, "%s: rtl8150 is detected\n", netdev->name);
9125b2fc499SJeff Garzik
9135b2fc499SJeff Garzik return 0;
9145b2fc499SJeff Garzik
9155b2fc499SJeff Garzik out2:
9165b2fc499SJeff Garzik usb_set_intfdata(intf, NULL);
9175b2fc499SJeff Garzik free_skb_pool(dev);
9185b2fc499SJeff Garzik out1:
9195b2fc499SJeff Garzik free_all_urbs(dev);
9205b2fc499SJeff Garzik out:
9215b2fc499SJeff Garzik kfree(dev->intr_buff);
9225b2fc499SJeff Garzik free_netdev(netdev);
9235b2fc499SJeff Garzik return -EIO;
9245b2fc499SJeff Garzik }
9255b2fc499SJeff Garzik
rtl8150_disconnect(struct usb_interface * intf)9265b2fc499SJeff Garzik static void rtl8150_disconnect(struct usb_interface *intf)
9275b2fc499SJeff Garzik {
9285b2fc499SJeff Garzik rtl8150_t *dev = usb_get_intfdata(intf);
9295b2fc499SJeff Garzik
9305b2fc499SJeff Garzik usb_set_intfdata(intf, NULL);
9315b2fc499SJeff Garzik if (dev) {
9325b2fc499SJeff Garzik set_bit(RTL8150_UNPLUG, &dev->flags);
9335b2fc499SJeff Garzik tasklet_kill(&dev->tl);
9345b2fc499SJeff Garzik unregister_netdev(dev->netdev);
9355b2fc499SJeff Garzik unlink_all_urbs(dev);
9365b2fc499SJeff Garzik free_all_urbs(dev);
9375b2fc499SJeff Garzik free_skb_pool(dev);
9385b2fc499SJeff Garzik dev_kfree_skb(dev->rx_skb);
9395b2fc499SJeff Garzik kfree(dev->intr_buff);
9405b2fc499SJeff Garzik free_netdev(dev->netdev);
9415b2fc499SJeff Garzik }
9425b2fc499SJeff Garzik }
9435b2fc499SJeff Garzik
944141b9e66Sfrançois romieu static struct usb_driver rtl8150_driver = {
945141b9e66Sfrançois romieu .name = driver_name,
946141b9e66Sfrançois romieu .probe = rtl8150_probe,
947141b9e66Sfrançois romieu .disconnect = rtl8150_disconnect,
948141b9e66Sfrançois romieu .id_table = rtl8150_table,
949141b9e66Sfrançois romieu .suspend = rtl8150_suspend,
950e1f12eb6SSarah Sharp .resume = rtl8150_resume,
951e1f12eb6SSarah Sharp .disable_hub_initiated_lpm = 1,
952141b9e66Sfrançois romieu };
953141b9e66Sfrançois romieu
954d632eb1bSGreg Kroah-Hartman module_usb_driver(rtl8150_driver);
9555b2fc499SJeff Garzik
9565b2fc499SJeff Garzik MODULE_AUTHOR(DRIVER_AUTHOR);
9575b2fc499SJeff Garzik MODULE_DESCRIPTION(DRIVER_DESC);
9585b2fc499SJeff Garzik MODULE_LICENSE("GPL");
959