xref: /openbmc/linux/drivers/net/usb/rtl8150.c (revision 7bcca710)
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