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
74*3c706829SNikita Zhandarovich /* USB endpoints */
75*3c706829SNikita Zhandarovich enum rtl8150_usb_ep {
76*3c706829SNikita Zhandarovich RTL8150_USB_EP_CONTROL = 0,
77*3c706829SNikita Zhandarovich RTL8150_USB_EP_BULK_IN = 1,
78*3c706829SNikita Zhandarovich RTL8150_USB_EP_BULK_OUT = 2,
79*3c706829SNikita Zhandarovich RTL8150_USB_EP_INT_IN = 3,
80*3c706829SNikita Zhandarovich };
81*3c706829SNikita Zhandarovich
825b2fc499SJeff Garzik /* Interrupt pipe data */
835b2fc499SJeff Garzik #define INT_TSR 0x00
845b2fc499SJeff Garzik #define INT_RSR 0x01
855b2fc499SJeff Garzik #define INT_MSR 0x02
865b2fc499SJeff Garzik #define INT_WAKSR 0x03
875b2fc499SJeff Garzik #define INT_TXOK_CNT 0x04
885b2fc499SJeff Garzik #define INT_RXLOST_CNT 0x05
895b2fc499SJeff Garzik #define INT_CRERR_CNT 0x06
905b2fc499SJeff Garzik #define INT_COL_CNT 0x07
915b2fc499SJeff Garzik
925b2fc499SJeff Garzik
935b2fc499SJeff Garzik #define RTL8150_MTU 1540
945b2fc499SJeff Garzik #define RTL8150_TX_TIMEOUT (HZ)
955b2fc499SJeff Garzik #define RX_SKB_POOL_SIZE 4
965b2fc499SJeff Garzik
975b2fc499SJeff Garzik /* rtl8150 flags */
985b2fc499SJeff Garzik #define RTL8150_HW_CRC 0
995b2fc499SJeff Garzik #define RX_REG_SET 1
1005b2fc499SJeff Garzik #define RTL8150_UNPLUG 2
1015b2fc499SJeff Garzik #define RX_URB_FAIL 3
1025b2fc499SJeff Garzik
1035b2fc499SJeff Garzik /* Define these values to match your device */
1045b2fc499SJeff Garzik #define VENDOR_ID_REALTEK 0x0bda
1055b2fc499SJeff Garzik #define VENDOR_ID_MELCO 0x0411
1065b2fc499SJeff Garzik #define VENDOR_ID_MICRONET 0x3980
1075b2fc499SJeff Garzik #define VENDOR_ID_LONGSHINE 0x07b8
1085b2fc499SJeff Garzik #define VENDOR_ID_OQO 0x1557
1095b2fc499SJeff Garzik #define VENDOR_ID_ZYXEL 0x0586
1105b2fc499SJeff Garzik
1115b2fc499SJeff Garzik #define PRODUCT_ID_RTL8150 0x8150
1125b2fc499SJeff Garzik #define PRODUCT_ID_LUAKTX 0x0012
1135b2fc499SJeff Garzik #define PRODUCT_ID_LCS8138TX 0x401a
1145b2fc499SJeff Garzik #define PRODUCT_ID_SP128AR 0x0003
1155b2fc499SJeff Garzik #define PRODUCT_ID_PRESTIGE 0x401a
1165b2fc499SJeff Garzik
1175b2fc499SJeff Garzik #undef EEPROM_WRITE
1185b2fc499SJeff Garzik
1195b2fc499SJeff Garzik /* table of devices that work with this driver */
120e1cb90f2SArvind Yadav static const struct usb_device_id rtl8150_table[] = {
1215b2fc499SJeff Garzik {USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8150)},
1225b2fc499SJeff Garzik {USB_DEVICE(VENDOR_ID_MELCO, PRODUCT_ID_LUAKTX)},
1235b2fc499SJeff Garzik {USB_DEVICE(VENDOR_ID_MICRONET, PRODUCT_ID_SP128AR)},
1245b2fc499SJeff Garzik {USB_DEVICE(VENDOR_ID_LONGSHINE, PRODUCT_ID_LCS8138TX)},
1255b2fc499SJeff Garzik {USB_DEVICE(VENDOR_ID_OQO, PRODUCT_ID_RTL8150)},
1265b2fc499SJeff Garzik {USB_DEVICE(VENDOR_ID_ZYXEL, PRODUCT_ID_PRESTIGE)},
1275b2fc499SJeff Garzik {}
1285b2fc499SJeff Garzik };
1295b2fc499SJeff Garzik
1305b2fc499SJeff Garzik MODULE_DEVICE_TABLE(usb, rtl8150_table);
1315b2fc499SJeff Garzik
1325b2fc499SJeff Garzik struct rtl8150 {
1335b2fc499SJeff Garzik unsigned long flags;
1345b2fc499SJeff Garzik struct usb_device *udev;
1355b2fc499SJeff Garzik struct tasklet_struct tl;
1365b2fc499SJeff Garzik struct net_device *netdev;
1374d12997aSPetko Manolov struct urb *rx_urb, *tx_urb, *intr_urb;
1385b2fc499SJeff Garzik struct sk_buff *tx_skb, *rx_skb;
1395b2fc499SJeff Garzik struct sk_buff *rx_skb_pool[RX_SKB_POOL_SIZE];
1405b2fc499SJeff Garzik spinlock_t rx_pool_lock;
1415b2fc499SJeff Garzik struct usb_ctrlrequest dr;
1425b2fc499SJeff Garzik int intr_interval;
1435b2fc499SJeff Garzik u8 *intr_buff;
1445b2fc499SJeff Garzik u8 phy;
1455b2fc499SJeff Garzik };
1465b2fc499SJeff Garzik
1475b2fc499SJeff Garzik typedef struct rtl8150 rtl8150_t;
1485b2fc499SJeff Garzik
1494d12997aSPetko Manolov struct async_req {
1504d12997aSPetko Manolov struct usb_ctrlrequest dr;
1514d12997aSPetko Manolov u16 rx_creg;
1524d12997aSPetko Manolov };
1534d12997aSPetko Manolov
1545b2fc499SJeff Garzik static const char driver_name [] = "rtl8150";
1555b2fc499SJeff Garzik
1565b2fc499SJeff Garzik /*
1575b2fc499SJeff Garzik **
1585b2fc499SJeff Garzik ** device related part of the code
1595b2fc499SJeff Garzik **
1605b2fc499SJeff Garzik */
get_registers(rtl8150_t * dev,u16 indx,u16 size,void * data)1615b2fc499SJeff Garzik static int get_registers(rtl8150_t * dev, u16 indx, u16 size, void *data)
1625b2fc499SJeff Garzik {
163b2a0f274SPetko Manolov return usb_control_msg_recv(dev->udev, 0, RTL8150_REQ_GET_REGS,
164b2a0f274SPetko Manolov RTL8150_REQT_READ, indx, 0, data, size,
165b2a0f274SPetko Manolov 1000, GFP_NOIO);
1665b2fc499SJeff Garzik }
1675b2fc499SJeff Garzik
set_registers(rtl8150_t * dev,u16 indx,u16 size,const void * data)1687926aff5SBen Hutchings static int set_registers(rtl8150_t * dev, u16 indx, u16 size, const void *data)
1695b2fc499SJeff Garzik {
170b2a0f274SPetko Manolov return usb_control_msg_send(dev->udev, 0, RTL8150_REQ_SET_REGS,
171b2a0f274SPetko Manolov RTL8150_REQT_WRITE, indx, 0, data, size,
172b2a0f274SPetko Manolov 1000, GFP_NOIO);
1735b2fc499SJeff Garzik }
1745b2fc499SJeff Garzik
async_set_reg_cb(struct urb * urb)1754d12997aSPetko Manolov static void async_set_reg_cb(struct urb *urb)
1765b2fc499SJeff Garzik {
1774d12997aSPetko Manolov struct async_req *req = (struct async_req *)urb->context;
178c94cb314SOliver Neukum int status = urb->status;
1795b2fc499SJeff Garzik
1804d12997aSPetko Manolov if (status < 0)
1814d12997aSPetko Manolov dev_dbg(&urb->dev->dev, "%s failed with %d", __func__, status);
1824d12997aSPetko Manolov kfree(req);
1834d12997aSPetko Manolov usb_free_urb(urb);
1845b2fc499SJeff Garzik }
1855b2fc499SJeff Garzik
async_set_registers(rtl8150_t * dev,u16 indx,u16 size,u16 reg)1864d12997aSPetko Manolov static int async_set_registers(rtl8150_t *dev, u16 indx, u16 size, u16 reg)
1875b2fc499SJeff Garzik {
1884d12997aSPetko Manolov int res = -ENOMEM;
1894d12997aSPetko Manolov struct urb *async_urb;
1904d12997aSPetko Manolov struct async_req *req;
1915b2fc499SJeff Garzik
1924d12997aSPetko Manolov req = kmalloc(sizeof(struct async_req), GFP_ATOMIC);
1934d12997aSPetko Manolov if (req == NULL)
1944d12997aSPetko Manolov return res;
1954d12997aSPetko Manolov async_urb = usb_alloc_urb(0, GFP_ATOMIC);
1964d12997aSPetko Manolov if (async_urb == NULL) {
1974d12997aSPetko Manolov kfree(req);
1984d12997aSPetko Manolov return res;
1994d12997aSPetko Manolov }
2004d12997aSPetko Manolov req->rx_creg = cpu_to_le16(reg);
2014d12997aSPetko Manolov req->dr.bRequestType = RTL8150_REQT_WRITE;
2024d12997aSPetko Manolov req->dr.bRequest = RTL8150_REQ_SET_REGS;
2034d12997aSPetko Manolov req->dr.wIndex = 0;
2044d12997aSPetko Manolov req->dr.wValue = cpu_to_le16(indx);
2054d12997aSPetko Manolov req->dr.wLength = cpu_to_le16(size);
2064d12997aSPetko Manolov usb_fill_control_urb(async_urb, dev->udev,
2074d12997aSPetko Manolov usb_sndctrlpipe(dev->udev, 0), (void *)&req->dr,
2084d12997aSPetko Manolov &req->rx_creg, size, async_set_reg_cb, req);
2094d12997aSPetko Manolov res = usb_submit_urb(async_urb, GFP_ATOMIC);
2104d12997aSPetko Manolov if (res) {
2114d12997aSPetko Manolov if (res == -ENODEV)
2125b2fc499SJeff Garzik netif_device_detach(dev->netdev);
2134d12997aSPetko Manolov dev_err(&dev->udev->dev, "%s failed with %d\n", __func__, res);
2144d12997aSPetko Manolov }
2154d12997aSPetko Manolov return res;
2165b2fc499SJeff Garzik }
2175b2fc499SJeff Garzik
read_mii_word(rtl8150_t * dev,u8 phy,__u8 indx,u16 * reg)2185b2fc499SJeff Garzik static int read_mii_word(rtl8150_t * dev, u8 phy, __u8 indx, u16 * reg)
2195b2fc499SJeff Garzik {
2205b2fc499SJeff Garzik int i;
2215b2fc499SJeff Garzik u8 data[3], tmp;
2225b2fc499SJeff Garzik
2235b2fc499SJeff Garzik data[0] = phy;
2245b2fc499SJeff Garzik data[1] = data[2] = 0;
2255b2fc499SJeff Garzik tmp = indx | PHY_READ | PHY_GO;
2265b2fc499SJeff Garzik i = 0;
2275b2fc499SJeff Garzik
2285b2fc499SJeff Garzik set_registers(dev, PHYADD, sizeof(data), data);
2295b2fc499SJeff Garzik set_registers(dev, PHYCNT, 1, &tmp);
2305b2fc499SJeff Garzik do {
2315b2fc499SJeff Garzik get_registers(dev, PHYCNT, 1, data);
2325b2fc499SJeff Garzik } while ((data[0] & PHY_GO) && (i++ < MII_TIMEOUT));
2335b2fc499SJeff Garzik
234c064efcaSroel kluin if (i <= MII_TIMEOUT) {
2355b2fc499SJeff Garzik get_registers(dev, PHYDAT, 2, data);
2365b2fc499SJeff Garzik *reg = data[0] | (data[1] << 8);
2375b2fc499SJeff Garzik return 0;
2385b2fc499SJeff Garzik } else
2395b2fc499SJeff Garzik return 1;
2405b2fc499SJeff Garzik }
2415b2fc499SJeff Garzik
write_mii_word(rtl8150_t * dev,u8 phy,__u8 indx,u16 reg)2425b2fc499SJeff Garzik static int write_mii_word(rtl8150_t * dev, u8 phy, __u8 indx, u16 reg)
2435b2fc499SJeff Garzik {
2445b2fc499SJeff Garzik int i;
2455b2fc499SJeff Garzik u8 data[3], tmp;
2465b2fc499SJeff Garzik
2475b2fc499SJeff Garzik data[0] = phy;
2485b2fc499SJeff Garzik data[1] = reg & 0xff;
2495b2fc499SJeff Garzik data[2] = (reg >> 8) & 0xff;
2505b2fc499SJeff Garzik tmp = indx | PHY_WRITE | PHY_GO;
2515b2fc499SJeff Garzik i = 0;
2525b2fc499SJeff Garzik
2535b2fc499SJeff Garzik set_registers(dev, PHYADD, sizeof(data), data);
2545b2fc499SJeff Garzik set_registers(dev, PHYCNT, 1, &tmp);
2555b2fc499SJeff Garzik do {
2565b2fc499SJeff Garzik get_registers(dev, PHYCNT, 1, data);
2575b2fc499SJeff Garzik } while ((data[0] & PHY_GO) && (i++ < MII_TIMEOUT));
2585b2fc499SJeff Garzik
259c064efcaSroel kluin if (i <= MII_TIMEOUT)
2605b2fc499SJeff Garzik return 0;
2615b2fc499SJeff Garzik else
2625b2fc499SJeff Garzik return 1;
2635b2fc499SJeff Garzik }
2645b2fc499SJeff Garzik
set_ethernet_addr(rtl8150_t * dev)265f45a4248SAnant Thazhemadam static void set_ethernet_addr(rtl8150_t *dev)
2665b2fc499SJeff Garzik {
267f45a4248SAnant Thazhemadam u8 node_id[ETH_ALEN];
268f45a4248SAnant Thazhemadam int ret;
2695b2fc499SJeff Garzik
270f45a4248SAnant Thazhemadam ret = get_registers(dev, IDR, sizeof(node_id), node_id);
271f45a4248SAnant Thazhemadam
27260f1626fSAnant Thazhemadam if (!ret) {
273af804e6dSJakub Kicinski eth_hw_addr_set(dev->netdev, node_id);
274f45a4248SAnant Thazhemadam } else {
275f45a4248SAnant Thazhemadam eth_hw_addr_random(dev->netdev);
276f45a4248SAnant Thazhemadam netdev_notice(dev->netdev, "Assigned a random MAC address: %pM\n",
277f45a4248SAnant Thazhemadam dev->netdev->dev_addr);
278f45a4248SAnant Thazhemadam }
2795b2fc499SJeff Garzik }
2805b2fc499SJeff Garzik
rtl8150_set_mac_address(struct net_device * netdev,void * p)2815b2fc499SJeff Garzik static int rtl8150_set_mac_address(struct net_device *netdev, void *p)
2825b2fc499SJeff Garzik {
2835b2fc499SJeff Garzik struct sockaddr *addr = p;
2845b2fc499SJeff Garzik rtl8150_t *dev = netdev_priv(netdev);
2855b2fc499SJeff Garzik
2865b2fc499SJeff Garzik if (netif_running(netdev))
2875b2fc499SJeff Garzik return -EBUSY;
2885b2fc499SJeff Garzik
28949ed8ddeSJakub Kicinski eth_hw_addr_set(netdev, addr->sa_data);
29049ae25b0SGreg Kroah-Hartman netdev_dbg(netdev, "Setting MAC address to %pM\n", netdev->dev_addr);
2915b2fc499SJeff Garzik /* Set the IDR registers. */
2926057912dSJulia Lawall set_registers(dev, IDR, netdev->addr_len, netdev->dev_addr);
2935b2fc499SJeff Garzik #ifdef EEPROM_WRITE
2945b2fc499SJeff Garzik {
295d649a284SH Hartley Sweeten int i;
2965b2fc499SJeff Garzik u8 cr;
2975b2fc499SJeff Garzik /* Get the CR contents. */
2985b2fc499SJeff Garzik get_registers(dev, CR, 1, &cr);
2995b2fc499SJeff Garzik /* Set the WEPROM bit (eeprom write enable). */
3005b2fc499SJeff Garzik cr |= 0x20;
3015b2fc499SJeff Garzik set_registers(dev, CR, 1, &cr);
3025b2fc499SJeff Garzik /* Write the MAC address into eeprom. Eeprom writes must be word-sized,
3035b2fc499SJeff Garzik so we need to split them up. */
3045b2fc499SJeff Garzik for (i = 0; i * 2 < netdev->addr_len; i++) {
3055b2fc499SJeff Garzik set_registers(dev, IDR_EEPROM + (i * 2), 2,
3065b2fc499SJeff Garzik netdev->dev_addr + (i * 2));
3075b2fc499SJeff Garzik }
3085b2fc499SJeff Garzik /* Clear the WEPROM bit (preventing accidental eeprom writes). */
3095b2fc499SJeff Garzik cr &= 0xdf;
3105b2fc499SJeff Garzik set_registers(dev, CR, 1, &cr);
3115b2fc499SJeff Garzik }
3125b2fc499SJeff Garzik #endif
3135b2fc499SJeff Garzik return 0;
3145b2fc499SJeff Garzik }
3155b2fc499SJeff Garzik
rtl8150_reset(rtl8150_t * dev)3165b2fc499SJeff Garzik static int rtl8150_reset(rtl8150_t * dev)
3175b2fc499SJeff Garzik {
3185b2fc499SJeff Garzik u8 data = 0x10;
3195b2fc499SJeff Garzik int i = HZ;
3205b2fc499SJeff Garzik
3215b2fc499SJeff Garzik set_registers(dev, CR, 1, &data);
3225b2fc499SJeff Garzik do {
3235b2fc499SJeff Garzik get_registers(dev, CR, 1, &data);
3245b2fc499SJeff Garzik } while ((data & 0x10) && --i);
3255b2fc499SJeff Garzik
3265b2fc499SJeff Garzik return (i > 0) ? 1 : 0;
3275b2fc499SJeff Garzik }
3285b2fc499SJeff Garzik
alloc_all_urbs(rtl8150_t * dev)3295b2fc499SJeff Garzik static int alloc_all_urbs(rtl8150_t * dev)
3305b2fc499SJeff Garzik {
3315b2fc499SJeff Garzik dev->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
3325b2fc499SJeff Garzik if (!dev->rx_urb)
3335b2fc499SJeff Garzik return 0;
3345b2fc499SJeff Garzik dev->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
3355b2fc499SJeff Garzik if (!dev->tx_urb) {
3365b2fc499SJeff Garzik usb_free_urb(dev->rx_urb);
3375b2fc499SJeff Garzik return 0;
3385b2fc499SJeff Garzik }
3395b2fc499SJeff Garzik dev->intr_urb = usb_alloc_urb(0, GFP_KERNEL);
3405b2fc499SJeff Garzik if (!dev->intr_urb) {
3415b2fc499SJeff Garzik usb_free_urb(dev->rx_urb);
3425b2fc499SJeff Garzik usb_free_urb(dev->tx_urb);
3435b2fc499SJeff Garzik return 0;
3445b2fc499SJeff Garzik }
3455b2fc499SJeff Garzik
3465b2fc499SJeff Garzik return 1;
3475b2fc499SJeff Garzik }
3485b2fc499SJeff Garzik
free_all_urbs(rtl8150_t * dev)3495b2fc499SJeff Garzik static void free_all_urbs(rtl8150_t * dev)
3505b2fc499SJeff Garzik {
3515b2fc499SJeff Garzik usb_free_urb(dev->rx_urb);
3525b2fc499SJeff Garzik usb_free_urb(dev->tx_urb);
3535b2fc499SJeff Garzik usb_free_urb(dev->intr_urb);
3545b2fc499SJeff Garzik }
3555b2fc499SJeff Garzik
unlink_all_urbs(rtl8150_t * dev)3565b2fc499SJeff Garzik static void unlink_all_urbs(rtl8150_t * dev)
3575b2fc499SJeff Garzik {
3585b2fc499SJeff Garzik usb_kill_urb(dev->rx_urb);
3595b2fc499SJeff Garzik usb_kill_urb(dev->tx_urb);
3605b2fc499SJeff Garzik usb_kill_urb(dev->intr_urb);
3615b2fc499SJeff Garzik }
3625b2fc499SJeff Garzik
pull_skb(rtl8150_t * dev)3635b2fc499SJeff Garzik static inline struct sk_buff *pull_skb(rtl8150_t *dev)
3645b2fc499SJeff Garzik {
3655b2fc499SJeff Garzik struct sk_buff *skb;
3665b2fc499SJeff Garzik int i;
3675b2fc499SJeff Garzik
3685b2fc499SJeff Garzik for (i = 0; i < RX_SKB_POOL_SIZE; i++) {
3695b2fc499SJeff Garzik if (dev->rx_skb_pool[i]) {
3705b2fc499SJeff Garzik skb = dev->rx_skb_pool[i];
3715b2fc499SJeff Garzik dev->rx_skb_pool[i] = NULL;
3725b2fc499SJeff Garzik return skb;
3735b2fc499SJeff Garzik }
3745b2fc499SJeff Garzik }
3755b2fc499SJeff Garzik return NULL;
3765b2fc499SJeff Garzik }
3775b2fc499SJeff Garzik
read_bulk_callback(struct urb * urb)3785b2fc499SJeff Garzik static void read_bulk_callback(struct urb *urb)
3795b2fc499SJeff Garzik {
3805b2fc499SJeff Garzik rtl8150_t *dev;
3815b2fc499SJeff Garzik unsigned pkt_len, res;
3825b2fc499SJeff Garzik struct sk_buff *skb;
3835b2fc499SJeff Garzik struct net_device *netdev;
384c94cb314SOliver Neukum int status = urb->status;
385c94cb314SOliver Neukum int result;
386feae641dSSebastian Andrzej Siewior unsigned long flags;
3875b2fc499SJeff Garzik
3885b2fc499SJeff Garzik dev = urb->context;
3895b2fc499SJeff Garzik if (!dev)
3905b2fc499SJeff Garzik return;
3915b2fc499SJeff Garzik if (test_bit(RTL8150_UNPLUG, &dev->flags))
3925b2fc499SJeff Garzik return;
3935b2fc499SJeff Garzik netdev = dev->netdev;
3945b2fc499SJeff Garzik if (!netif_device_present(netdev))
3955b2fc499SJeff Garzik return;
3965b2fc499SJeff Garzik
397c94cb314SOliver Neukum switch (status) {
3985b2fc499SJeff Garzik case 0:
3995b2fc499SJeff Garzik break;
4005b2fc499SJeff Garzik case -ENOENT:
4015b2fc499SJeff Garzik return; /* the urb is in unlink state */
4025b2fc499SJeff Garzik case -ETIME:
403342a437eSAndré Goddard Rosa if (printk_ratelimit())
4044dc89948SGreg Kroah-Hartman dev_warn(&urb->dev->dev, "may be reset is needed?..\n");
4055b2fc499SJeff Garzik goto goon;
4065b2fc499SJeff Garzik default:
407342a437eSAndré Goddard Rosa if (printk_ratelimit())
408c94cb314SOliver Neukum dev_warn(&urb->dev->dev, "Rx status %d\n", status);
4095b2fc499SJeff Garzik goto goon;
4105b2fc499SJeff Garzik }
4115b2fc499SJeff Garzik
4125b2fc499SJeff Garzik if (!dev->rx_skb)
4135b2fc499SJeff Garzik goto resched;
4145b2fc499SJeff Garzik /* protect against short packets (tell me why we got some?!?) */
4155b2fc499SJeff Garzik if (urb->actual_length < 4)
4165b2fc499SJeff Garzik goto goon;
4175b2fc499SJeff Garzik
4185b2fc499SJeff Garzik res = urb->actual_length;
4195b2fc499SJeff Garzik pkt_len = res - 4;
4205b2fc499SJeff Garzik
4215b2fc499SJeff Garzik skb_put(dev->rx_skb, pkt_len);
4225b2fc499SJeff Garzik dev->rx_skb->protocol = eth_type_trans(dev->rx_skb, netdev);
4235b2fc499SJeff Garzik netif_rx(dev->rx_skb);
424b7e41e23SStephen Hemminger netdev->stats.rx_packets++;
425b7e41e23SStephen Hemminger netdev->stats.rx_bytes += pkt_len;
4265b2fc499SJeff Garzik
427feae641dSSebastian Andrzej Siewior spin_lock_irqsave(&dev->rx_pool_lock, flags);
4285b2fc499SJeff Garzik skb = pull_skb(dev);
429feae641dSSebastian Andrzej Siewior spin_unlock_irqrestore(&dev->rx_pool_lock, flags);
4305b2fc499SJeff Garzik if (!skb)
4315b2fc499SJeff Garzik goto resched;
4325b2fc499SJeff Garzik
4335b2fc499SJeff Garzik dev->rx_skb = skb;
4345b2fc499SJeff Garzik goon:
4355b2fc499SJeff Garzik usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
4365b2fc499SJeff Garzik dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev);
437c94cb314SOliver Neukum result = usb_submit_urb(dev->rx_urb, GFP_ATOMIC);
438c94cb314SOliver Neukum if (result == -ENODEV)
4395b2fc499SJeff Garzik netif_device_detach(dev->netdev);
440c94cb314SOliver Neukum else if (result) {
4415b2fc499SJeff Garzik set_bit(RX_URB_FAIL, &dev->flags);
4425b2fc499SJeff Garzik goto resched;
4435b2fc499SJeff Garzik } else {
4445b2fc499SJeff Garzik clear_bit(RX_URB_FAIL, &dev->flags);
4455b2fc499SJeff Garzik }
4465b2fc499SJeff Garzik
4475b2fc499SJeff Garzik return;
4485b2fc499SJeff Garzik resched:
4495b2fc499SJeff Garzik tasklet_schedule(&dev->tl);
4505b2fc499SJeff Garzik }
4515b2fc499SJeff Garzik
write_bulk_callback(struct urb * urb)4525b2fc499SJeff Garzik static void write_bulk_callback(struct urb *urb)
4535b2fc499SJeff Garzik {
4545b2fc499SJeff Garzik rtl8150_t *dev;
455c94cb314SOliver Neukum int status = urb->status;
4565b2fc499SJeff Garzik
4575b2fc499SJeff Garzik dev = urb->context;
4585b2fc499SJeff Garzik if (!dev)
4595b2fc499SJeff Garzik return;
4605b2fc499SJeff Garzik dev_kfree_skb_irq(dev->tx_skb);
4615b2fc499SJeff Garzik if (!netif_device_present(dev->netdev))
4625b2fc499SJeff Garzik return;
463c94cb314SOliver Neukum if (status)
464880c9c66SGreg Kroah-Hartman dev_info(&urb->dev->dev, "%s: Tx status %d\n",
465c94cb314SOliver Neukum dev->netdev->name, status);
466860e9538SFlorian Westphal netif_trans_update(dev->netdev);
4675b2fc499SJeff Garzik netif_wake_queue(dev->netdev);
4685b2fc499SJeff Garzik }
4695b2fc499SJeff Garzik
intr_callback(struct urb * urb)4705b2fc499SJeff Garzik static void intr_callback(struct urb *urb)
4715b2fc499SJeff Garzik {
4725b2fc499SJeff Garzik rtl8150_t *dev;
4735b2fc499SJeff Garzik __u8 *d;
474c94cb314SOliver Neukum int status = urb->status;
475c94cb314SOliver Neukum int res;
4765b2fc499SJeff Garzik
4775b2fc499SJeff Garzik dev = urb->context;
4785b2fc499SJeff Garzik if (!dev)
4795b2fc499SJeff Garzik return;
480c94cb314SOliver Neukum switch (status) {
4815b2fc499SJeff Garzik case 0: /* success */
4825b2fc499SJeff Garzik break;
4835b2fc499SJeff Garzik case -ECONNRESET: /* unlink */
4845b2fc499SJeff Garzik case -ENOENT:
4855b2fc499SJeff Garzik case -ESHUTDOWN:
4865b2fc499SJeff Garzik return;
4875b2fc499SJeff Garzik /* -EPIPE: should clear the halt */
4885b2fc499SJeff Garzik default:
489880c9c66SGreg Kroah-Hartman dev_info(&urb->dev->dev, "%s: intr status %d\n",
490c94cb314SOliver Neukum dev->netdev->name, status);
4915b2fc499SJeff Garzik goto resubmit;
4925b2fc499SJeff Garzik }
4935b2fc499SJeff Garzik
4945b2fc499SJeff Garzik d = urb->transfer_buffer;
4955b2fc499SJeff Garzik if (d[0] & TSR_ERRORS) {
496b7e41e23SStephen Hemminger dev->netdev->stats.tx_errors++;
4975b2fc499SJeff Garzik if (d[INT_TSR] & (TSR_ECOL | TSR_JBR))
498b7e41e23SStephen Hemminger dev->netdev->stats.tx_aborted_errors++;
4995b2fc499SJeff Garzik if (d[INT_TSR] & TSR_LCOL)
500b7e41e23SStephen Hemminger dev->netdev->stats.tx_window_errors++;
5015b2fc499SJeff Garzik if (d[INT_TSR] & TSR_LOSS_CRS)
502b7e41e23SStephen Hemminger dev->netdev->stats.tx_carrier_errors++;
5035b2fc499SJeff Garzik }
5045b2fc499SJeff Garzik /* Report link status changes to the network stack */
5055b2fc499SJeff Garzik if ((d[INT_MSR] & MSR_LINK) == 0) {
5065b2fc499SJeff Garzik if (netif_carrier_ok(dev->netdev)) {
5075b2fc499SJeff Garzik netif_carrier_off(dev->netdev);
50849ae25b0SGreg Kroah-Hartman netdev_dbg(dev->netdev, "%s: LINK LOST\n", __func__);
5095b2fc499SJeff Garzik }
5105b2fc499SJeff Garzik } else {
5115b2fc499SJeff Garzik if (!netif_carrier_ok(dev->netdev)) {
5125b2fc499SJeff Garzik netif_carrier_on(dev->netdev);
51349ae25b0SGreg Kroah-Hartman netdev_dbg(dev->netdev, "%s: LINK CAME BACK\n", __func__);
5145b2fc499SJeff Garzik }
5155b2fc499SJeff Garzik }
5165b2fc499SJeff Garzik
5175b2fc499SJeff Garzik resubmit:
518c94cb314SOliver Neukum res = usb_submit_urb (urb, GFP_ATOMIC);
519c94cb314SOliver Neukum if (res == -ENODEV)
5205b2fc499SJeff Garzik netif_device_detach(dev->netdev);
521c94cb314SOliver Neukum else if (res)
52221f52432SGreg Kroah-Hartman dev_err(&dev->udev->dev,
52321f52432SGreg Kroah-Hartman "can't resubmit intr, %s-%s/input0, status %d\n",
52421f52432SGreg Kroah-Hartman dev->udev->bus->bus_name, dev->udev->devpath, res);
5255b2fc499SJeff Garzik }
5265b2fc499SJeff Garzik
rtl8150_suspend(struct usb_interface * intf,pm_message_t message)5275b2fc499SJeff Garzik static int rtl8150_suspend(struct usb_interface *intf, pm_message_t message)
5285b2fc499SJeff Garzik {
5295b2fc499SJeff Garzik rtl8150_t *dev = usb_get_intfdata(intf);
5305b2fc499SJeff Garzik
5315b2fc499SJeff Garzik netif_device_detach(dev->netdev);
5325b2fc499SJeff Garzik
5335b2fc499SJeff Garzik if (netif_running(dev->netdev)) {
5345b2fc499SJeff Garzik usb_kill_urb(dev->rx_urb);
5355b2fc499SJeff Garzik usb_kill_urb(dev->intr_urb);
5365b2fc499SJeff Garzik }
5375b2fc499SJeff Garzik return 0;
5385b2fc499SJeff Garzik }
5395b2fc499SJeff Garzik
rtl8150_resume(struct usb_interface * intf)5405b2fc499SJeff Garzik static int rtl8150_resume(struct usb_interface *intf)
5415b2fc499SJeff Garzik {
5425b2fc499SJeff Garzik rtl8150_t *dev = usb_get_intfdata(intf);
5435b2fc499SJeff Garzik
5445b2fc499SJeff Garzik netif_device_attach(dev->netdev);
5455b2fc499SJeff Garzik if (netif_running(dev->netdev)) {
5465b2fc499SJeff Garzik dev->rx_urb->status = 0;
5475b2fc499SJeff Garzik dev->rx_urb->actual_length = 0;
5485b2fc499SJeff Garzik read_bulk_callback(dev->rx_urb);
5495b2fc499SJeff Garzik
5505b2fc499SJeff Garzik dev->intr_urb->status = 0;
5515b2fc499SJeff Garzik dev->intr_urb->actual_length = 0;
5525b2fc499SJeff Garzik intr_callback(dev->intr_urb);
5535b2fc499SJeff Garzik }
5545b2fc499SJeff Garzik return 0;
5555b2fc499SJeff Garzik }
5565b2fc499SJeff Garzik
5575b2fc499SJeff Garzik /*
5585b2fc499SJeff Garzik **
5595b2fc499SJeff Garzik ** network related part of the code
5605b2fc499SJeff Garzik **
5615b2fc499SJeff Garzik */
5625b2fc499SJeff Garzik
fill_skb_pool(rtl8150_t * dev)5635b2fc499SJeff Garzik static void fill_skb_pool(rtl8150_t *dev)
5645b2fc499SJeff Garzik {
5655b2fc499SJeff Garzik struct sk_buff *skb;
5665b2fc499SJeff Garzik int i;
5675b2fc499SJeff Garzik
5685b2fc499SJeff Garzik for (i = 0; i < RX_SKB_POOL_SIZE; i++) {
5695b2fc499SJeff Garzik if (dev->rx_skb_pool[i])
5705b2fc499SJeff Garzik continue;
5715b2fc499SJeff Garzik skb = dev_alloc_skb(RTL8150_MTU + 2);
5725b2fc499SJeff Garzik if (!skb) {
5735b2fc499SJeff Garzik return;
5745b2fc499SJeff Garzik }
5755b2fc499SJeff Garzik skb_reserve(skb, 2);
5765b2fc499SJeff Garzik dev->rx_skb_pool[i] = skb;
5775b2fc499SJeff Garzik }
5785b2fc499SJeff Garzik }
5795b2fc499SJeff Garzik
free_skb_pool(rtl8150_t * dev)5805b2fc499SJeff Garzik static void free_skb_pool(rtl8150_t *dev)
5815b2fc499SJeff Garzik {
5825b2fc499SJeff Garzik int i;
5835b2fc499SJeff Garzik
5845b2fc499SJeff Garzik for (i = 0; i < RX_SKB_POOL_SIZE; i++)
5855b2fc499SJeff Garzik dev_kfree_skb(dev->rx_skb_pool[i]);
5865b2fc499SJeff Garzik }
5875b2fc499SJeff Garzik
rx_fixup(struct tasklet_struct * t)5881999ad32SEmil Renner Berthing static void rx_fixup(struct tasklet_struct *t)
589141b9e66Sfrançois romieu {
5901999ad32SEmil Renner Berthing struct rtl8150 *dev = from_tasklet(dev, t, tl);
591141b9e66Sfrançois romieu struct sk_buff *skb;
592141b9e66Sfrançois romieu int status;
593141b9e66Sfrançois romieu
594141b9e66Sfrançois romieu spin_lock_irq(&dev->rx_pool_lock);
595141b9e66Sfrançois romieu fill_skb_pool(dev);
596141b9e66Sfrançois romieu spin_unlock_irq(&dev->rx_pool_lock);
597141b9e66Sfrançois romieu if (test_bit(RX_URB_FAIL, &dev->flags))
598141b9e66Sfrançois romieu if (dev->rx_skb)
599141b9e66Sfrançois romieu goto try_again;
600141b9e66Sfrançois romieu spin_lock_irq(&dev->rx_pool_lock);
601141b9e66Sfrançois romieu skb = pull_skb(dev);
602141b9e66Sfrançois romieu spin_unlock_irq(&dev->rx_pool_lock);
603141b9e66Sfrançois romieu if (skb == NULL)
604141b9e66Sfrançois romieu goto tlsched;
605141b9e66Sfrançois romieu dev->rx_skb = skb;
606141b9e66Sfrançois romieu usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
607141b9e66Sfrançois romieu dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev);
608141b9e66Sfrançois romieu try_again:
609141b9e66Sfrançois romieu status = usb_submit_urb(dev->rx_urb, GFP_ATOMIC);
610141b9e66Sfrançois romieu if (status == -ENODEV) {
611141b9e66Sfrançois romieu netif_device_detach(dev->netdev);
612141b9e66Sfrançois romieu } else if (status) {
613141b9e66Sfrançois romieu set_bit(RX_URB_FAIL, &dev->flags);
614141b9e66Sfrançois romieu goto tlsched;
615141b9e66Sfrançois romieu } else {
616141b9e66Sfrançois romieu clear_bit(RX_URB_FAIL, &dev->flags);
617141b9e66Sfrançois romieu }
618141b9e66Sfrançois romieu
619141b9e66Sfrançois romieu return;
620141b9e66Sfrançois romieu tlsched:
621141b9e66Sfrançois romieu tasklet_schedule(&dev->tl);
622141b9e66Sfrançois romieu }
623141b9e66Sfrançois romieu
enable_net_traffic(rtl8150_t * dev)6245b2fc499SJeff Garzik static int enable_net_traffic(rtl8150_t * dev)
6255b2fc499SJeff Garzik {
6265b2fc499SJeff Garzik u8 cr, tcr, rcr, msr;
6275b2fc499SJeff Garzik
6285b2fc499SJeff Garzik if (!rtl8150_reset(dev)) {
6294dc89948SGreg Kroah-Hartman dev_warn(&dev->udev->dev, "device reset failed\n");
6305b2fc499SJeff Garzik }
6315b2fc499SJeff Garzik /* RCR bit7=1 attach Rx info at the end; =0 HW CRC (which is broken) */
6325b2fc499SJeff Garzik rcr = 0x9e;
6335b2fc499SJeff Garzik tcr = 0xd8;
6345b2fc499SJeff Garzik cr = 0x0c;
6355b2fc499SJeff Garzik if (!(rcr & 0x80))
6365b2fc499SJeff Garzik set_bit(RTL8150_HW_CRC, &dev->flags);
6375b2fc499SJeff Garzik set_registers(dev, RCR, 1, &rcr);
6385b2fc499SJeff Garzik set_registers(dev, TCR, 1, &tcr);
6395b2fc499SJeff Garzik set_registers(dev, CR, 1, &cr);
6405b2fc499SJeff Garzik get_registers(dev, MSR, 1, &msr);
6415b2fc499SJeff Garzik
6425b2fc499SJeff Garzik return 0;
6435b2fc499SJeff Garzik }
6445b2fc499SJeff Garzik
disable_net_traffic(rtl8150_t * dev)6455b2fc499SJeff Garzik static void disable_net_traffic(rtl8150_t * dev)
6465b2fc499SJeff Garzik {
6475b2fc499SJeff Garzik u8 cr;
6485b2fc499SJeff Garzik
6495b2fc499SJeff Garzik get_registers(dev, CR, 1, &cr);
6505b2fc499SJeff Garzik cr &= 0xf3;
6515b2fc499SJeff Garzik set_registers(dev, CR, 1, &cr);
6525b2fc499SJeff Garzik }
6535b2fc499SJeff Garzik
rtl8150_tx_timeout(struct net_device * netdev,unsigned int txqueue)6540290bd29SMichael S. Tsirkin static void rtl8150_tx_timeout(struct net_device *netdev, unsigned int txqueue)
6555b2fc499SJeff Garzik {
6565b2fc499SJeff Garzik rtl8150_t *dev = netdev_priv(netdev);
6574dc89948SGreg Kroah-Hartman dev_warn(&netdev->dev, "Tx timeout.\n");
6585b2fc499SJeff Garzik usb_unlink_urb(dev->tx_urb);
659b7e41e23SStephen Hemminger netdev->stats.tx_errors++;
6605b2fc499SJeff Garzik }
6615b2fc499SJeff Garzik
rtl8150_set_multicast(struct net_device * netdev)6625b2fc499SJeff Garzik static void rtl8150_set_multicast(struct net_device *netdev)
6635b2fc499SJeff Garzik {
6645b2fc499SJeff Garzik rtl8150_t *dev = netdev_priv(netdev);
6654d12997aSPetko Manolov u16 rx_creg = 0x9e;
6664d12997aSPetko Manolov
6675b2fc499SJeff Garzik netif_stop_queue(netdev);
6685b2fc499SJeff Garzik if (netdev->flags & IFF_PROMISC) {
6694d12997aSPetko Manolov rx_creg |= 0x0001;
670880c9c66SGreg Kroah-Hartman dev_info(&netdev->dev, "%s: promiscuous mode\n", netdev->name);
6714cd24eafSJiri Pirko } else if (!netdev_mc_empty(netdev) ||
6725b2fc499SJeff Garzik (netdev->flags & IFF_ALLMULTI)) {
6734d12997aSPetko Manolov rx_creg &= 0xfffe;
6744d12997aSPetko Manolov rx_creg |= 0x0002;
6753a9b0455SDavid Lechner dev_dbg(&netdev->dev, "%s: allmulti set\n", netdev->name);
6765b2fc499SJeff Garzik } else {
6775b2fc499SJeff Garzik /* ~RX_MULTICAST, ~RX_PROMISCUOUS */
6784d12997aSPetko Manolov rx_creg &= 0x00fc;
6795b2fc499SJeff Garzik }
6804d12997aSPetko Manolov async_set_registers(dev, RCR, sizeof(rx_creg), rx_creg);
6815b2fc499SJeff Garzik netif_wake_queue(netdev);
6825b2fc499SJeff Garzik }
6835b2fc499SJeff Garzik
rtl8150_start_xmit(struct sk_buff * skb,struct net_device * netdev)68425a79c41SStephen Hemminger static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb,
68525a79c41SStephen Hemminger struct net_device *netdev)
6865b2fc499SJeff Garzik {
6875b2fc499SJeff Garzik rtl8150_t *dev = netdev_priv(netdev);
6885b2fc499SJeff Garzik int count, res;
6895b2fc499SJeff Garzik
6905b2fc499SJeff Garzik netif_stop_queue(netdev);
6915b2fc499SJeff Garzik count = (skb->len < 60) ? 60 : skb->len;
6925b2fc499SJeff Garzik count = (count & 0x3f) ? count : count + 1;
6935b2fc499SJeff Garzik dev->tx_skb = skb;
6945b2fc499SJeff Garzik usb_fill_bulk_urb(dev->tx_urb, dev->udev, usb_sndbulkpipe(dev->udev, 2),
6955b2fc499SJeff Garzik skb->data, count, write_bulk_callback, dev);
6965b2fc499SJeff Garzik if ((res = usb_submit_urb(dev->tx_urb, GFP_ATOMIC))) {
6975b2fc499SJeff Garzik /* Can we get/handle EPIPE here? */
6985b2fc499SJeff Garzik if (res == -ENODEV)
6995b2fc499SJeff Garzik netif_device_detach(dev->netdev);
7005b2fc499SJeff Garzik else {
7014dc89948SGreg Kroah-Hartman dev_warn(&netdev->dev, "failed tx_urb %d\n", res);
702b7e41e23SStephen Hemminger netdev->stats.tx_errors++;
7035b2fc499SJeff Garzik netif_start_queue(netdev);
7045b2fc499SJeff Garzik }
7055b2fc499SJeff Garzik } else {
706b7e41e23SStephen Hemminger netdev->stats.tx_packets++;
707b7e41e23SStephen Hemminger netdev->stats.tx_bytes += skb->len;
708860e9538SFlorian Westphal netif_trans_update(netdev);
7095b2fc499SJeff Garzik }
7105b2fc499SJeff Garzik
7116ed10654SPatrick McHardy return NETDEV_TX_OK;
7125b2fc499SJeff Garzik }
7135b2fc499SJeff Garzik
7145b2fc499SJeff Garzik
set_carrier(struct net_device * netdev)7155b2fc499SJeff Garzik static void set_carrier(struct net_device *netdev)
7165b2fc499SJeff Garzik {
7175b2fc499SJeff Garzik rtl8150_t *dev = netdev_priv(netdev);
7185b2fc499SJeff Garzik short tmp;
7195b2fc499SJeff Garzik
7205b2fc499SJeff Garzik get_registers(dev, CSCR, 2, &tmp);
7215b2fc499SJeff Garzik if (tmp & CSCR_LINK_STATUS)
7225b2fc499SJeff Garzik netif_carrier_on(netdev);
7235b2fc499SJeff Garzik else
7245b2fc499SJeff Garzik netif_carrier_off(netdev);
7255b2fc499SJeff Garzik }
7265b2fc499SJeff Garzik
rtl8150_open(struct net_device * netdev)7275b2fc499SJeff Garzik static int rtl8150_open(struct net_device *netdev)
7285b2fc499SJeff Garzik {
7295b2fc499SJeff Garzik rtl8150_t *dev = netdev_priv(netdev);
7305b2fc499SJeff Garzik int res;
7315b2fc499SJeff Garzik
7325b2fc499SJeff Garzik if (dev->rx_skb == NULL)
7335b2fc499SJeff Garzik dev->rx_skb = pull_skb(dev);
7345b2fc499SJeff Garzik if (!dev->rx_skb)
7355b2fc499SJeff Garzik return -ENOMEM;
7365b2fc499SJeff Garzik
7375b2fc499SJeff Garzik set_registers(dev, IDR, 6, netdev->dev_addr);
7385b2fc499SJeff Garzik
7395b2fc499SJeff Garzik usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
7405b2fc499SJeff Garzik dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev);
7415b2fc499SJeff Garzik if ((res = usb_submit_urb(dev->rx_urb, GFP_KERNEL))) {
7425b2fc499SJeff Garzik if (res == -ENODEV)
7435b2fc499SJeff Garzik netif_device_detach(dev->netdev);
7444dc89948SGreg Kroah-Hartman dev_warn(&netdev->dev, "rx_urb submit failed: %d\n", res);
7455b2fc499SJeff Garzik return res;
7465b2fc499SJeff Garzik }
7475b2fc499SJeff Garzik usb_fill_int_urb(dev->intr_urb, dev->udev, usb_rcvintpipe(dev->udev, 3),
7485b2fc499SJeff Garzik dev->intr_buff, INTBUFSIZE, intr_callback,
7495b2fc499SJeff Garzik dev, dev->intr_interval);
7505b2fc499SJeff Garzik if ((res = usb_submit_urb(dev->intr_urb, GFP_KERNEL))) {
7515b2fc499SJeff Garzik if (res == -ENODEV)
7525b2fc499SJeff Garzik netif_device_detach(dev->netdev);
7534dc89948SGreg Kroah-Hartman dev_warn(&netdev->dev, "intr_urb submit failed: %d\n", res);
7545b2fc499SJeff Garzik usb_kill_urb(dev->rx_urb);
7555b2fc499SJeff Garzik return res;
7565b2fc499SJeff Garzik }
7575b2fc499SJeff Garzik enable_net_traffic(dev);
7585b2fc499SJeff Garzik set_carrier(netdev);
7595b2fc499SJeff Garzik netif_start_queue(netdev);
7605b2fc499SJeff Garzik
7615b2fc499SJeff Garzik return res;
7625b2fc499SJeff Garzik }
7635b2fc499SJeff Garzik
rtl8150_close(struct net_device * netdev)7645b2fc499SJeff Garzik static int rtl8150_close(struct net_device *netdev)
7655b2fc499SJeff Garzik {
7665b2fc499SJeff Garzik rtl8150_t *dev = netdev_priv(netdev);
7675b2fc499SJeff Garzik
7685b2fc499SJeff Garzik netif_stop_queue(netdev);
7695b2fc499SJeff Garzik if (!test_bit(RTL8150_UNPLUG, &dev->flags))
7705b2fc499SJeff Garzik disable_net_traffic(dev);
7715b2fc499SJeff Garzik unlink_all_urbs(dev);
7725b2fc499SJeff Garzik
7731abe7cd9SSudip Mukherjee return 0;
7745b2fc499SJeff Garzik }
7755b2fc499SJeff Garzik
rtl8150_get_drvinfo(struct net_device * netdev,struct ethtool_drvinfo * info)7765b2fc499SJeff Garzik static void rtl8150_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *info)
7775b2fc499SJeff Garzik {
7785b2fc499SJeff Garzik rtl8150_t *dev = netdev_priv(netdev);
7795b2fc499SJeff Garzik
780fb3ceec1SWolfram Sang strscpy(info->driver, driver_name, sizeof(info->driver));
781fb3ceec1SWolfram Sang strscpy(info->version, DRIVER_VERSION, sizeof(info->version));
7827826d43fSJiri Pirko usb_make_path(dev->udev, info->bus_info, sizeof(info->bus_info));
7835b2fc499SJeff Garzik }
7845b2fc499SJeff Garzik
rtl8150_get_link_ksettings(struct net_device * netdev,struct ethtool_link_ksettings * ecmd)785b66239b6SPhilippe Reynes static int rtl8150_get_link_ksettings(struct net_device *netdev,
786b66239b6SPhilippe Reynes struct ethtool_link_ksettings *ecmd)
7875b2fc499SJeff Garzik {
7885b2fc499SJeff Garzik rtl8150_t *dev = netdev_priv(netdev);
7897bcca710SOliver Neukum short lpa = 0;
7907bcca710SOliver Neukum short bmcr = 0;
791b66239b6SPhilippe Reynes u32 supported;
7925b2fc499SJeff Garzik
793b66239b6SPhilippe Reynes supported = (SUPPORTED_10baseT_Half |
7945b2fc499SJeff Garzik SUPPORTED_10baseT_Full |
7955b2fc499SJeff Garzik SUPPORTED_100baseT_Half |
7965b2fc499SJeff Garzik SUPPORTED_100baseT_Full |
7975b2fc499SJeff Garzik SUPPORTED_Autoneg |
7985b2fc499SJeff Garzik SUPPORTED_TP | SUPPORTED_MII);
799b66239b6SPhilippe Reynes ecmd->base.port = PORT_TP;
800b66239b6SPhilippe Reynes ecmd->base.phy_address = dev->phy;
8015b2fc499SJeff Garzik get_registers(dev, BMCR, 2, &bmcr);
8025b2fc499SJeff Garzik get_registers(dev, ANLP, 2, &lpa);
8035b2fc499SJeff Garzik if (bmcr & BMCR_ANENABLE) {
80470739497SDavid Decotigny u32 speed = ((lpa & (LPA_100HALF | LPA_100FULL)) ?
80570739497SDavid Decotigny SPEED_100 : SPEED_10);
806b66239b6SPhilippe Reynes ecmd->base.speed = speed;
807b66239b6SPhilippe Reynes ecmd->base.autoneg = AUTONEG_ENABLE;
80870739497SDavid Decotigny if (speed == SPEED_100)
809b66239b6SPhilippe Reynes ecmd->base.duplex = (lpa & LPA_100FULL) ?
8105b2fc499SJeff Garzik DUPLEX_FULL : DUPLEX_HALF;
8115b2fc499SJeff Garzik else
812b66239b6SPhilippe Reynes ecmd->base.duplex = (lpa & LPA_10FULL) ?
8135b2fc499SJeff Garzik DUPLEX_FULL : DUPLEX_HALF;
8145b2fc499SJeff Garzik } else {
815b66239b6SPhilippe Reynes ecmd->base.autoneg = AUTONEG_DISABLE;
816b66239b6SPhilippe Reynes ecmd->base.speed = ((bmcr & BMCR_SPEED100) ?
817b66239b6SPhilippe Reynes SPEED_100 : SPEED_10);
818b66239b6SPhilippe Reynes ecmd->base.duplex = (bmcr & BMCR_FULLDPLX) ?
8195b2fc499SJeff Garzik DUPLEX_FULL : DUPLEX_HALF;
8205b2fc499SJeff Garzik }
821b66239b6SPhilippe Reynes
822b66239b6SPhilippe Reynes ethtool_convert_legacy_u32_to_link_mode(ecmd->link_modes.supported,
823b66239b6SPhilippe Reynes supported);
824b66239b6SPhilippe Reynes
8255b2fc499SJeff Garzik return 0;
8265b2fc499SJeff Garzik }
8275b2fc499SJeff Garzik
8280fc0b732SStephen Hemminger static const struct ethtool_ops ops = {
8295b2fc499SJeff Garzik .get_drvinfo = rtl8150_get_drvinfo,
830b66239b6SPhilippe Reynes .get_link = ethtool_op_get_link,
831b66239b6SPhilippe Reynes .get_link_ksettings = rtl8150_get_link_ksettings,
8325b2fc499SJeff Garzik };
8335b2fc499SJeff Garzik
rtl8150_siocdevprivate(struct net_device * netdev,struct ifreq * rq,void __user * udata,int cmd)834ef1b5b0cSArnd Bergmann static int rtl8150_siocdevprivate(struct net_device *netdev, struct ifreq *rq,
835ef1b5b0cSArnd Bergmann void __user *udata, int cmd)
8365b2fc499SJeff Garzik {
8375b2fc499SJeff Garzik rtl8150_t *dev = netdev_priv(netdev);
8385b2fc499SJeff Garzik u16 *data = (u16 *) & rq->ifr_ifru;
8395b2fc499SJeff Garzik int res = 0;
8405b2fc499SJeff Garzik
8415b2fc499SJeff Garzik switch (cmd) {
8425b2fc499SJeff Garzik case SIOCDEVPRIVATE:
8435b2fc499SJeff Garzik data[0] = dev->phy;
844df561f66SGustavo A. R. Silva fallthrough;
8455b2fc499SJeff Garzik case SIOCDEVPRIVATE + 1:
8465b2fc499SJeff Garzik read_mii_word(dev, dev->phy, (data[1] & 0x1f), &data[3]);
8475b2fc499SJeff Garzik break;
8485b2fc499SJeff Garzik case SIOCDEVPRIVATE + 2:
8495b2fc499SJeff Garzik if (!capable(CAP_NET_ADMIN))
8505b2fc499SJeff Garzik return -EPERM;
8515b2fc499SJeff Garzik write_mii_word(dev, dev->phy, (data[1] & 0x1f), data[2]);
8525b2fc499SJeff Garzik break;
8535b2fc499SJeff Garzik default:
8545b2fc499SJeff Garzik res = -EOPNOTSUPP;
8555b2fc499SJeff Garzik }
8565b2fc499SJeff Garzik
8575b2fc499SJeff Garzik return res;
8585b2fc499SJeff Garzik }
8595b2fc499SJeff Garzik
860d79f7ef4SStephen Hemminger static const struct net_device_ops rtl8150_netdev_ops = {
861d79f7ef4SStephen Hemminger .ndo_open = rtl8150_open,
862d79f7ef4SStephen Hemminger .ndo_stop = rtl8150_close,
863ef1b5b0cSArnd Bergmann .ndo_siocdevprivate = rtl8150_siocdevprivate,
864d79f7ef4SStephen Hemminger .ndo_start_xmit = rtl8150_start_xmit,
865d79f7ef4SStephen Hemminger .ndo_tx_timeout = rtl8150_tx_timeout,
866afc4b13dSJiri Pirko .ndo_set_rx_mode = rtl8150_set_multicast,
867d79f7ef4SStephen Hemminger .ndo_set_mac_address = rtl8150_set_mac_address,
868d79f7ef4SStephen Hemminger
869d79f7ef4SStephen Hemminger .ndo_validate_addr = eth_validate_addr,
870d79f7ef4SStephen Hemminger };
871d79f7ef4SStephen Hemminger
rtl8150_probe(struct usb_interface * intf,const struct usb_device_id * id)8725b2fc499SJeff Garzik static int rtl8150_probe(struct usb_interface *intf,
8735b2fc499SJeff Garzik const struct usb_device_id *id)
8745b2fc499SJeff Garzik {
8755b2fc499SJeff Garzik struct usb_device *udev = interface_to_usbdev(intf);
8765b2fc499SJeff Garzik rtl8150_t *dev;
8775b2fc499SJeff Garzik struct net_device *netdev;
878*3c706829SNikita Zhandarovich static const u8 bulk_ep_addr[] = {
879*3c706829SNikita Zhandarovich RTL8150_USB_EP_BULK_IN | USB_DIR_IN,
880*3c706829SNikita Zhandarovich RTL8150_USB_EP_BULK_OUT | USB_DIR_OUT,
881*3c706829SNikita Zhandarovich 0};
882*3c706829SNikita Zhandarovich static const u8 int_ep_addr[] = {
883*3c706829SNikita Zhandarovich RTL8150_USB_EP_INT_IN | USB_DIR_IN,
884*3c706829SNikita Zhandarovich 0};
8855b2fc499SJeff Garzik
8865b2fc499SJeff Garzik netdev = alloc_etherdev(sizeof(rtl8150_t));
88741de8d4cSJoe Perches if (!netdev)
8885b2fc499SJeff Garzik return -ENOMEM;
8895b2fc499SJeff Garzik
8905b2fc499SJeff Garzik dev = netdev_priv(netdev);
8915b2fc499SJeff Garzik
8925b2fc499SJeff Garzik dev->intr_buff = kmalloc(INTBUFSIZE, GFP_KERNEL);
8935b2fc499SJeff Garzik if (!dev->intr_buff) {
8945b2fc499SJeff Garzik free_netdev(netdev);
8955b2fc499SJeff Garzik return -ENOMEM;
8965b2fc499SJeff Garzik }
8975b2fc499SJeff Garzik
898*3c706829SNikita Zhandarovich /* Verify that all required endpoints are present */
899*3c706829SNikita Zhandarovich if (!usb_check_bulk_endpoints(intf, bulk_ep_addr) ||
900*3c706829SNikita Zhandarovich !usb_check_int_endpoints(intf, int_ep_addr)) {
901*3c706829SNikita Zhandarovich dev_err(&intf->dev, "couldn't find required endpoints\n");
902*3c706829SNikita Zhandarovich goto out;
903*3c706829SNikita Zhandarovich }
904*3c706829SNikita Zhandarovich
9051999ad32SEmil Renner Berthing tasklet_setup(&dev->tl, rx_fixup);
9065b2fc499SJeff Garzik spin_lock_init(&dev->rx_pool_lock);
9075b2fc499SJeff Garzik
9085b2fc499SJeff Garzik dev->udev = udev;
9095b2fc499SJeff Garzik dev->netdev = netdev;
910d79f7ef4SStephen Hemminger netdev->netdev_ops = &rtl8150_netdev_ops;
9115b2fc499SJeff Garzik netdev->watchdog_timeo = RTL8150_TX_TIMEOUT;
9127ad24ea4SWilfried Klaebe netdev->ethtool_ops = &ops;
9135b2fc499SJeff Garzik dev->intr_interval = 100; /* 100ms */
9145b2fc499SJeff Garzik
9155b2fc499SJeff Garzik if (!alloc_all_urbs(dev)) {
91621f52432SGreg Kroah-Hartman dev_err(&intf->dev, "out of memory\n");
9175b2fc499SJeff Garzik goto out;
9185b2fc499SJeff Garzik }
9195b2fc499SJeff Garzik if (!rtl8150_reset(dev)) {
92021f52432SGreg Kroah-Hartman dev_err(&intf->dev, "couldn't reset the device\n");
9215b2fc499SJeff Garzik goto out1;
9225b2fc499SJeff Garzik }
9235b2fc499SJeff Garzik fill_skb_pool(dev);
9245b2fc499SJeff Garzik set_ethernet_addr(dev);
9255b2fc499SJeff Garzik
9265b2fc499SJeff Garzik usb_set_intfdata(intf, dev);
9275b2fc499SJeff Garzik SET_NETDEV_DEV(netdev, &intf->dev);
9285b2fc499SJeff Garzik if (register_netdev(netdev) != 0) {
92921f52432SGreg Kroah-Hartman dev_err(&intf->dev, "couldn't register the device\n");
9305b2fc499SJeff Garzik goto out2;
9315b2fc499SJeff Garzik }
9325b2fc499SJeff Garzik
933880c9c66SGreg Kroah-Hartman dev_info(&intf->dev, "%s: rtl8150 is detected\n", netdev->name);
9345b2fc499SJeff Garzik
9355b2fc499SJeff Garzik return 0;
9365b2fc499SJeff Garzik
9375b2fc499SJeff Garzik out2:
9385b2fc499SJeff Garzik usb_set_intfdata(intf, NULL);
9395b2fc499SJeff Garzik free_skb_pool(dev);
9405b2fc499SJeff Garzik out1:
9415b2fc499SJeff Garzik free_all_urbs(dev);
9425b2fc499SJeff Garzik out:
9435b2fc499SJeff Garzik kfree(dev->intr_buff);
9445b2fc499SJeff Garzik free_netdev(netdev);
9455b2fc499SJeff Garzik return -EIO;
9465b2fc499SJeff Garzik }
9475b2fc499SJeff Garzik
rtl8150_disconnect(struct usb_interface * intf)9485b2fc499SJeff Garzik static void rtl8150_disconnect(struct usb_interface *intf)
9495b2fc499SJeff Garzik {
9505b2fc499SJeff Garzik rtl8150_t *dev = usb_get_intfdata(intf);
9515b2fc499SJeff Garzik
9525b2fc499SJeff Garzik usb_set_intfdata(intf, NULL);
9535b2fc499SJeff Garzik if (dev) {
9545b2fc499SJeff Garzik set_bit(RTL8150_UNPLUG, &dev->flags);
9555b2fc499SJeff Garzik tasklet_kill(&dev->tl);
9565b2fc499SJeff Garzik unregister_netdev(dev->netdev);
9575b2fc499SJeff Garzik unlink_all_urbs(dev);
9585b2fc499SJeff Garzik free_all_urbs(dev);
9595b2fc499SJeff Garzik free_skb_pool(dev);
9605b2fc499SJeff Garzik dev_kfree_skb(dev->rx_skb);
9615b2fc499SJeff Garzik kfree(dev->intr_buff);
9625b2fc499SJeff Garzik free_netdev(dev->netdev);
9635b2fc499SJeff Garzik }
9645b2fc499SJeff Garzik }
9655b2fc499SJeff Garzik
966141b9e66Sfrançois romieu static struct usb_driver rtl8150_driver = {
967141b9e66Sfrançois romieu .name = driver_name,
968141b9e66Sfrançois romieu .probe = rtl8150_probe,
969141b9e66Sfrançois romieu .disconnect = rtl8150_disconnect,
970141b9e66Sfrançois romieu .id_table = rtl8150_table,
971141b9e66Sfrançois romieu .suspend = rtl8150_suspend,
972e1f12eb6SSarah Sharp .resume = rtl8150_resume,
973e1f12eb6SSarah Sharp .disable_hub_initiated_lpm = 1,
974141b9e66Sfrançois romieu };
975141b9e66Sfrançois romieu
976d632eb1bSGreg Kroah-Hartman module_usb_driver(rtl8150_driver);
9775b2fc499SJeff Garzik
9785b2fc499SJeff Garzik MODULE_AUTHOR(DRIVER_AUTHOR);
9795b2fc499SJeff Garzik MODULE_DESCRIPTION(DRIVER_DESC);
9805b2fc499SJeff Garzik MODULE_LICENSE("GPL");
981