rtl8150.c 18.3 KB
Newer Older
Petko Manolov's avatar
USB  
Petko Manolov committed
1
/*
Petko Manolov's avatar
Petko Manolov committed
2
 *  Copyright (c) 2002 Petko Manolov (petkan@users.sourceforge.net)
Petko Manolov's avatar
USB  
Petko Manolov committed
3
 *
Petko Manolov's avatar
Petko Manolov committed
4 5 6
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * version 2 as published by the Free Software Foundation.
Petko Manolov's avatar
USB  
Petko Manolov committed
7 8 9 10
 */

#include <linux/config.h>
#include <linux/sched.h>
Petko Manolov's avatar
Petko Manolov committed
11
#include <linux/init.h>
Petko Manolov's avatar
USB  
Petko Manolov committed
12 13 14 15 16 17 18 19 20 21 22 23
#include <linux/signal.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/usb.h>
#include <asm/uaccess.h>

/* Version Information */
24
#define DRIVER_VERSION "v0.5.4 (2002/04/11)"
Petko Manolov's avatar
USB  
Petko Manolov committed
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
#define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"
#define DRIVER_DESC "rtl8150 based usb-ethernet driver"

#define	IRD			0x0120
#define	MAR			0x0126
#define	CR			0x012e
#define	TCR			0x012f
#define	RCR			0x0130
#define	TSR			0x0132
#define	RSR			0x0133
#define	CON0			0x0135
#define	CON1			0x0136
#define	MSR			0x0137
#define	PHYADD			0x0138
#define	PHYDAT			0x0139
#define	PHYCNT			0x013b
#define	GPPC			0x013d
#define	BMCR			0x0140
#define	BMSR			0x0142
#define	ANAR			0x0144
#define	ANLP			0x0146
#define	AER			0x0148

#define	PHY_READ		0
#define	PHY_WRITE		0x20
#define	PHY_GO			0x40

Petko Manolov's avatar
Petko Manolov committed
52 53
#define	MII_TIMEOUT		10

Petko Manolov's avatar
USB  
Petko Manolov committed
54 55 56 57 58
#define	RTL8150_REQT_READ	0xc0
#define	RTL8150_REQT_WRITE	0x40
#define	RTL8150_REQ_GET_REGS	0x05
#define	RTL8150_REQ_SET_REGS	0x05

Petko Manolov's avatar
Petko Manolov committed
59
#define	RTL8150_MTU		1540
Petko Manolov's avatar
USB  
Petko Manolov committed
60
#define	RTL8150_TX_TIMEOUT	(HZ)
Petko Manolov's avatar
Petko Manolov committed
61
#define	RX_SKB_POOL_SIZE	4
Petko Manolov's avatar
USB  
Petko Manolov committed
62 63

/* rtl8150 flags */
Petko Manolov's avatar
Petko Manolov committed
64
#define	RTL8150_HW_CRC		0
Petko Manolov's avatar
USB  
Petko Manolov committed
65
#define	RX_REG_SET		1
Petko Manolov's avatar
Petko Manolov committed
66
#define	RTL8150_UNPLUG		2
67
#define	RX_URB_FAIL		3
Petko Manolov's avatar
USB  
Petko Manolov committed
68 69 70 71 72 73

/* Define these values to match your device */
#define VENDOR_ID_REALTEK		0x0bda
#define PRODUCT_ID_RTL8150		0x8150

/* table of devices that work with this driver */
Petko Manolov's avatar
Petko Manolov committed
74 75 76
static struct usb_device_id rtl8150_table[] = {
	{USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8150)},
	{}
Petko Manolov's avatar
USB  
Petko Manolov committed
77 78
};

Petko Manolov's avatar
Petko Manolov committed
79
MODULE_DEVICE_TABLE(usb, rtl8150_table);
Petko Manolov's avatar
USB  
Petko Manolov committed
80 81

struct rtl8150 {
Petko Manolov's avatar
Petko Manolov committed
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
	unsigned long flags;
	struct usb_device *udev;
	struct semaphore sem;
	struct tasklet_struct tl;
	struct net_device_stats stats;
	struct net_device *netdev;
	struct urb *rx_urb, *tx_urb, *intr_urb, *ctrl_urb;
	struct sk_buff *tx_skb, *rx_skb;
	struct sk_buff *rx_skb_pool[RX_SKB_POOL_SIZE];
	spinlock_t rx_pool_lock;
	struct usb_ctrlrequest dr;
	int intr_interval;
	u16 rx_creg;
	u8 intr_buff[8];
	u8 phy;
Petko Manolov's avatar
USB  
Petko Manolov committed
97 98
};

Petko Manolov's avatar
Petko Manolov committed
99
typedef struct rtl8150 rtl8150_t;
Petko Manolov's avatar
USB  
Petko Manolov committed
100 101 102 103 104

/* the global usb devfs handle */
extern devfs_handle_t usb_devfs_handle;
unsigned long multicast_filter_limit = 32;

Petko Manolov's avatar
Petko Manolov committed
105 106
static void fill_skb_pool(rtl8150_t *);
static void free_skb_pool(rtl8150_t *);
Petko Manolov's avatar
Petko Manolov committed
107
static inline struct sk_buff *pull_skb(rtl8150_t *);
Petko Manolov's avatar
USB  
Petko Manolov committed
108
static void rtl8150_disconnect(struct usb_device *dev, void *ptr);
Petko Manolov's avatar
Petko Manolov committed
109 110
static void *rtl8150_probe(struct usb_device *dev, unsigned int ifnum,
			   const struct usb_device_id *id);
Petko Manolov's avatar
USB  
Petko Manolov committed
111 112 113 114 115 116 117 118 119 120 121 122 123

static struct usb_driver rtl8150_driver = {
	name:		"rtl8150",
	probe:		rtl8150_probe,
	disconnect:	rtl8150_disconnect,
	id_table:	rtl8150_table,
};

/*
**
**	device related part of the code
**
*/
Petko Manolov's avatar
Petko Manolov committed
124
static int get_registers(rtl8150_t * dev, u16 indx, u16 size, void *data)
Petko Manolov's avatar
USB  
Petko Manolov committed
125
{
Petko Manolov's avatar
Petko Manolov committed
126 127 128
	return usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
			       RTL8150_REQ_GET_REGS, RTL8150_REQT_READ,
			       indx, 0, data, size, HZ / 2);
Petko Manolov's avatar
USB  
Petko Manolov committed
129 130
}

Petko Manolov's avatar
Petko Manolov committed
131
static int set_registers(rtl8150_t * dev, u16 indx, u16 size, void *data)
Petko Manolov's avatar
USB  
Petko Manolov committed
132
{
Petko Manolov's avatar
Petko Manolov committed
133 134 135
	return usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
			       RTL8150_REQ_SET_REGS, RTL8150_REQT_WRITE,
			       indx, 0, data, size, HZ / 2);
Petko Manolov's avatar
USB  
Petko Manolov committed
136 137 138 139
}

static void ctrl_callback(struct urb *urb)
{
Petko Manolov's avatar
Petko Manolov committed
140 141
	rtl8150_t *dev;

Petko Manolov's avatar
USB  
Petko Manolov committed
142 143 144 145 146 147 148 149 150 151 152 153 154 155
	switch (urb->status) {
	case 0:
		break;
	case -EINPROGRESS:
		break;
	case -ENOENT:
		break;
	default:
		warn("ctrl urb status %d", urb->status);
	}
	dev = urb->context;
	clear_bit(RX_REG_SET, &dev->flags);
}

Petko Manolov's avatar
Petko Manolov committed
156
static int async_set_registers(rtl8150_t * dev, u16 indx, u16 size, void *data)
Petko Manolov's avatar
USB  
Petko Manolov committed
157
{
Petko Manolov's avatar
Petko Manolov committed
158
	int ret;
Petko Manolov's avatar
USB  
Petko Manolov committed
159

Petko Manolov's avatar
Petko Manolov committed
160
	if (test_bit(RX_REG_SET, &dev->flags))
Petko Manolov's avatar
USB  
Petko Manolov committed
161
		return -EAGAIN;
Petko Manolov's avatar
Petko Manolov committed
162

Petko Manolov's avatar
USB  
Petko Manolov committed
163 164 165 166 167 168
	dev->dr.bRequestType = RTL8150_REQT_WRITE;
	dev->dr.bRequest = RTL8150_REQ_SET_REGS;
	dev->dr.wValue = cpu_to_le16(indx);
	dev->dr.wIndex = 0;
	dev->dr.wLength = cpu_to_le16(size);
	dev->ctrl_urb->transfer_buffer_length = size;
Petko Manolov's avatar
Petko Manolov committed
169 170 171
	FILL_CONTROL_URB(dev->ctrl_urb, dev->udev,
			 usb_sndctrlpipe(dev->udev, 0), (char *) &dev->dr,
			 &dev->rx_creg, size, ctrl_callback, dev);
Petko Manolov's avatar
USB  
Petko Manolov committed
172 173 174 175 176 177 178 179
	if ((ret = usb_submit_urb(dev->ctrl_urb, GFP_ATOMIC)))
		err("control request submission failed: %d", ret);
	else
		set_bit(RX_REG_SET, &dev->flags);

	return ret;
}

Petko Manolov's avatar
Petko Manolov committed
180
static int read_mii_word(rtl8150_t * dev, u8 phy, __u8 indx, u16 * reg)
Petko Manolov's avatar
USB  
Petko Manolov committed
181
{
Petko Manolov's avatar
Petko Manolov committed
182 183
	int i;
	u8 data[3], tmp;
Petko Manolov's avatar
USB  
Petko Manolov committed
184 185 186 187 188 189 190 191 192 193

	data[0] = phy;
	data[1] = data[2] = 0;
	tmp = indx | PHY_READ | PHY_GO;
	i = 0;

	set_registers(dev, PHYADD, sizeof(data), data);
	set_registers(dev, PHYCNT, 1, &tmp);
	do {
		get_registers(dev, PHYCNT, 1, data);
Petko Manolov's avatar
Petko Manolov committed
194
	} while ((data[0] & PHY_GO) && (i++ < MII_TIMEOUT));
Petko Manolov's avatar
USB  
Petko Manolov committed
195

Petko Manolov's avatar
Petko Manolov committed
196
	if (i < MII_TIMEOUT) {
Petko Manolov's avatar
USB  
Petko Manolov committed
197 198 199 200 201 202 203
		get_registers(dev, PHYDAT, 2, data);
		*reg = le16_to_cpup(data);
		return 0;
	} else
		return 1;
}

Petko Manolov's avatar
Petko Manolov committed
204
static int write_mii_word(rtl8150_t * dev, u8 phy, __u8 indx, u16 reg)
Petko Manolov's avatar
USB  
Petko Manolov committed
205
{
Petko Manolov's avatar
Petko Manolov committed
206 207
	int i;
	u8 data[3], tmp;
Petko Manolov's avatar
USB  
Petko Manolov committed
208 209 210 211 212 213 214 215 216 217

	data[0] = phy;
	*(data + 1) = cpu_to_le16p(&reg);
	tmp = indx | PHY_WRITE | PHY_GO;
	i = 0;

	set_registers(dev, PHYADD, sizeof(data), data);
	set_registers(dev, PHYCNT, 1, &tmp);
	do {
		get_registers(dev, PHYCNT, 1, data);
Petko Manolov's avatar
Petko Manolov committed
218
	} while ((data[0] & PHY_GO) && (i++ < MII_TIMEOUT));
Petko Manolov's avatar
USB  
Petko Manolov committed
219

Petko Manolov's avatar
Petko Manolov committed
220
	if (i < MII_TIMEOUT)
Petko Manolov's avatar
USB  
Petko Manolov committed
221 222 223 224 225
		return 0;
	else
		return 1;
}

Petko Manolov's avatar
Petko Manolov committed
226
static inline void set_ethernet_addr(rtl8150_t * dev)
Petko Manolov's avatar
USB  
Petko Manolov committed
227
{
Petko Manolov's avatar
Petko Manolov committed
228
	u8 node_id[6];
Petko Manolov's avatar
USB  
Petko Manolov committed
229 230 231 232 233

	get_registers(dev, IRD, sizeof(node_id), node_id);
	memcpy(dev->netdev->dev_addr, node_id, sizeof(node_id));
}

Petko Manolov's avatar
Petko Manolov committed
234
static int rtl8150_reset(rtl8150_t * dev)
Petko Manolov's avatar
USB  
Petko Manolov committed
235
{
Petko Manolov's avatar
Petko Manolov committed
236 237
	u8 data = 0x10;
	int i = HZ;
Petko Manolov's avatar
USB  
Petko Manolov committed
238 239 240 241 242 243

	set_registers(dev, CR, 1, &data);
	do {
		get_registers(dev, CR, 1, &data);
	} while ((data & 0x10) && --i);

Petko Manolov's avatar
Petko Manolov committed
244 245
	return (i > 0) ? 1 : 0;
}
Petko Manolov's avatar
USB  
Petko Manolov committed
246

Petko Manolov's avatar
Petko Manolov committed
247
static int alloc_all_urbs(rtl8150_t * dev)
Petko Manolov's avatar
USB  
Petko Manolov committed
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
{
	dev->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
	if (!dev->rx_urb)
		return 0;
	dev->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
	if (!dev->tx_urb) {
		usb_free_urb(dev->rx_urb);
		return 0;
	}
	dev->intr_urb = usb_alloc_urb(0, GFP_KERNEL);
	if (!dev->intr_urb) {
		usb_free_urb(dev->rx_urb);
		usb_free_urb(dev->tx_urb);
		return 0;
	}
	dev->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL);
	if (!dev->intr_urb) {
		usb_free_urb(dev->rx_urb);
		usb_free_urb(dev->tx_urb);
		usb_free_urb(dev->intr_urb);
		return 0;
	}

	return 1;
}

Petko Manolov's avatar
Petko Manolov committed
274
static void free_all_urbs(rtl8150_t * dev)
Petko Manolov's avatar
USB  
Petko Manolov committed
275 276 277 278 279 280 281
{
	usb_free_urb(dev->rx_urb);
	usb_free_urb(dev->tx_urb);
	usb_free_urb(dev->intr_urb);
	usb_free_urb(dev->ctrl_urb);
}

Petko Manolov's avatar
Petko Manolov committed
282
static void unlink_all_urbs(rtl8150_t * dev)
Petko Manolov's avatar
USB  
Petko Manolov committed
283 284 285 286 287 288 289 290 291
{
	usb_unlink_urb(dev->rx_urb);
	usb_unlink_urb(dev->tx_urb);
	usb_unlink_urb(dev->intr_urb);
	usb_unlink_urb(dev->ctrl_urb);
}

static void read_bulk_callback(struct urb *urb)
{
Petko Manolov's avatar
Petko Manolov committed
292 293 294
	rtl8150_t *dev;
	unsigned pkt_len, res;
	struct sk_buff *skb;
Petko Manolov's avatar
USB  
Petko Manolov committed
295
	struct net_device *netdev;
Petko Manolov's avatar
Petko Manolov committed
296
	u16 rx_stat;
Petko Manolov's avatar
USB  
Petko Manolov committed
297 298

	dev = urb->context;
299 300 301
	if (!dev)
		return;
	if (test_bit(RTL8150_UNPLUG, &dev->flags))
Petko Manolov's avatar
USB  
Petko Manolov committed
302 303
		return;
	netdev = dev->netdev;
304
	if (!netif_device_present(netdev))
Petko Manolov's avatar
USB  
Petko Manolov committed
305
		return;
306

Petko Manolov's avatar
USB  
Petko Manolov committed
307 308 309 310
	switch (urb->status) {
	case 0:
		break;
	case -ENOENT:
Petko Manolov's avatar
Petko Manolov committed
311
		return;	/* the urb is in unlink state */
Petko Manolov's avatar
USB  
Petko Manolov committed
312
	case -ETIMEDOUT:
Petko Manolov's avatar
Petko Manolov committed
313
		warn("may be reset is needed?..");
Petko Manolov's avatar
Petko Manolov committed
314
		goto goon;
Petko Manolov's avatar
USB  
Petko Manolov committed
315 316 317 318 319
	default:
		warn("Rx status %d", urb->status);
		goto goon;
	}

Petko Manolov's avatar
Petko Manolov committed
320 321
	if (!dev->rx_skb)
		goto resched;
Petko Manolov's avatar
Petko Manolov committed
322

Petko Manolov's avatar
Petko Manolov committed
323
	res = urb->actual_length;
Petko Manolov's avatar
Petko Manolov committed
324
	rx_stat = le16_to_cpu(*(short *)(urb->transfer_buffer + res - 4));
Petko Manolov's avatar
Petko Manolov committed
325 326
	pkt_len = res - 4;

Petko Manolov's avatar
Petko Manolov committed
327 328 329
	skb_put(dev->rx_skb, pkt_len);
	dev->rx_skb->protocol = eth_type_trans(dev->rx_skb, netdev);
	netif_rx(dev->rx_skb);
Petko Manolov's avatar
USB  
Petko Manolov committed
330 331
	dev->stats.rx_packets++;
	dev->stats.rx_bytes += pkt_len;
Petko Manolov's avatar
Petko Manolov committed
332 333

	spin_lock(&dev->rx_pool_lock);
Petko Manolov's avatar
Petko Manolov committed
334
	skb = pull_skb(dev);
Petko Manolov's avatar
Petko Manolov committed
335
	spin_unlock(&dev->rx_pool_lock);
Petko Manolov's avatar
Petko Manolov committed
336 337
	if (!skb)
		goto resched;
Petko Manolov's avatar
Petko Manolov committed
338 339

	dev->rx_skb = skb;
Petko Manolov's avatar
USB  
Petko Manolov committed
340
goon:
Petko Manolov's avatar
Petko Manolov committed
341 342
	FILL_BULK_URB(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
		      dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev);
Petko Manolov's avatar
Petko Manolov committed
343
	if (usb_submit_urb(dev->rx_urb, GFP_ATOMIC)) {
344
		set_bit(RX_URB_FAIL, &dev->flags);
Petko Manolov's avatar
Petko Manolov committed
345 346
		goto resched;
	} else {
347
		clear_bit(RX_URB_FAIL, &dev->flags);
Petko Manolov's avatar
Petko Manolov committed
348 349 350 351 352
	}

	return;
resched:
	tasklet_schedule(&dev->tl);
Petko Manolov's avatar
USB  
Petko Manolov committed
353 354
}

Petko Manolov's avatar
Petko Manolov committed
355 356 357 358 359 360
static void rx_fixup(unsigned long data)
{
	rtl8150_t *dev;
	struct sk_buff *skb;

	dev = (rtl8150_t *)data;
361

Petko Manolov's avatar
Petko Manolov committed
362
	spin_lock_irq(&dev->rx_pool_lock);
Petko Manolov's avatar
Petko Manolov committed
363
	fill_skb_pool(dev);
Petko Manolov's avatar
Petko Manolov committed
364
	spin_unlock_irq(&dev->rx_pool_lock);
365
	if (test_bit(RX_URB_FAIL, &dev->flags))
Petko Manolov's avatar
Petko Manolov committed
366 367
		if (dev->rx_skb)
			goto try_again;
Petko Manolov's avatar
Petko Manolov committed
368 369 370 371
	spin_lock_irq(&dev->rx_pool_lock);
	skb = pull_skb(dev);
	spin_unlock_irq(&dev->rx_pool_lock);
	if (skb == NULL)
Petko Manolov's avatar
Petko Manolov committed
372
		goto tlsched;
Petko Manolov's avatar
Petko Manolov committed
373 374 375
	dev->rx_skb = skb;
	FILL_BULK_URB(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
		      dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev);
376 377 378
try_again:
	if (usb_submit_urb(dev->rx_urb, GFP_ATOMIC)) {
		set_bit(RX_URB_FAIL, &dev->flags);
Petko Manolov's avatar
Petko Manolov committed
379 380
		goto tlsched;
	 } else {
381
		clear_bit(RX_URB_FAIL, &dev->flags);
Petko Manolov's avatar
Petko Manolov committed
382 383 384 385 386
	}

	return;
tlsched:
	tasklet_schedule(&dev->tl);
Petko Manolov's avatar
Petko Manolov committed
387
}
Petko Manolov's avatar
USB  
Petko Manolov committed
388 389 390

static void write_bulk_callback(struct urb *urb)
{
Petko Manolov's avatar
Petko Manolov committed
391
	rtl8150_t *dev;
Petko Manolov's avatar
USB  
Petko Manolov committed
392 393 394 395

	dev = urb->context;
	if (!dev)
		return;
Petko Manolov's avatar
Petko Manolov committed
396
	dev_kfree_skb_irq(dev->tx_skb);
Petko Manolov's avatar
USB  
Petko Manolov committed
397 398 399 400 401 402 403 404 405 406
	if (!netif_device_present(dev->netdev))
		return;
	if (urb->status)
		info("%s: Tx status %d", dev->netdev->name, urb->status);
	dev->netdev->trans_start = jiffies;
	netif_wake_queue(dev->netdev);
}

void intr_callback(struct urb *urb)
{
Petko Manolov's avatar
Petko Manolov committed
407
	rtl8150_t *dev;
Petko Manolov's avatar
USB  
Petko Manolov committed
408 409 410 411 412

	dev = urb->context;
	if (!dev)
		return;
	switch (urb->status) {
Petko Manolov's avatar
Petko Manolov committed
413 414 415 416 417 418
	case 0:
		break;
	case -ENOENT:
		return;
	default:
		info("%s: intr status %d", dev->netdev->name, urb->status);
Petko Manolov's avatar
USB  
Petko Manolov committed
419 420 421 422 423 424 425 426 427
	}
}

/*
**
**	network related part of the code
**
*/

Petko Manolov's avatar
Petko Manolov committed
428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454
static void fill_skb_pool(rtl8150_t *dev)
{
	struct sk_buff *skb;
	int i;

	for (i = 0; i < RX_SKB_POOL_SIZE; i++) {
		if (dev->rx_skb_pool[i])
			continue;
		skb = dev_alloc_skb(RTL8150_MTU + 2);
		if (!skb) {
			return;
		}
		skb->dev = dev->netdev;
		skb_reserve(skb, 2);
		dev->rx_skb_pool[i] = skb;
	}
}

static void free_skb_pool(rtl8150_t *dev)
{
	int i;

	for (i = 0; i < RX_SKB_POOL_SIZE; i++)
		if (dev->rx_skb_pool[i])
			dev_kfree_skb(dev->rx_skb_pool[i]);
}

Petko Manolov's avatar
Petko Manolov committed
455
static inline struct sk_buff *pull_skb(rtl8150_t *dev)
Petko Manolov's avatar
Petko Manolov committed
456 457 458 459 460 461 462 463 464 465 466 467 468
{
	struct sk_buff *skb;
	int i;

	for (i = 0; i < RX_SKB_POOL_SIZE; i++) {
		if (dev->rx_skb_pool[i]) {
			skb = dev->rx_skb_pool[i];
			dev->rx_skb_pool[i] = NULL;
			return skb;
		}
	}
	return NULL;
}
Petko Manolov's avatar
USB  
Petko Manolov committed
469

Petko Manolov's avatar
Petko Manolov committed
470
static int enable_net_traffic(rtl8150_t * dev)
Petko Manolov's avatar
USB  
Petko Manolov committed
471
{
Petko Manolov's avatar
Petko Manolov committed
472
	u8 cr, tcr, rcr, msr;
Petko Manolov's avatar
USB  
Petko Manolov committed
473

Petko Manolov's avatar
Petko Manolov committed
474
	if (!rtl8150_reset(dev)) {
Petko Manolov's avatar
USB  
Petko Manolov committed
475 476
		warn("%s - device reset failed", __FUNCTION__);
	}
Petko Manolov's avatar
Petko Manolov committed
477 478 479
	/* RCR bit7=1 attach Rx info at the end;  =0 HW CRC (which is broken) */
	dev->rx_creg = rcr = 0x9e;
	tcr = 0xd8;
Petko Manolov's avatar
USB  
Petko Manolov committed
480
	cr = 0x0c;
Petko Manolov's avatar
Petko Manolov committed
481 482
	if (!(rcr & 0x80))
		set_bit(RTL8150_HW_CRC, &dev->flags);
Petko Manolov's avatar
USB  
Petko Manolov committed
483 484 485 486 487 488 489 490
	set_registers(dev, RCR, 1, &rcr);
	set_registers(dev, TCR, 1, &tcr);
	set_registers(dev, CR, 1, &cr);
	get_registers(dev, MSR, 1, &msr);

	return 0;
}

Petko Manolov's avatar
Petko Manolov committed
491
static void disable_net_traffic(rtl8150_t * dev)
Petko Manolov's avatar
USB  
Petko Manolov committed
492
{
Petko Manolov's avatar
Petko Manolov committed
493
	u8 cr;
Petko Manolov's avatar
USB  
Petko Manolov committed
494 495 496 497 498 499 500 501

	get_registers(dev, CR, 1, &cr);
	cr &= 0xf3;
	set_registers(dev, CR, 1, &cr);
}

static struct net_device_stats *rtl8150_netdev_stats(struct net_device *dev)
{
Petko Manolov's avatar
Petko Manolov committed
502
	return &((rtl8150_t *) dev->priv)->stats;
Petko Manolov's avatar
USB  
Petko Manolov committed
503 504 505 506
}

static void rtl8150_tx_timeout(struct net_device *netdev)
{
Petko Manolov's avatar
Petko Manolov committed
507
	rtl8150_t *dev;
Petko Manolov's avatar
USB  
Petko Manolov committed
508 509 510 511

	dev = netdev->priv;
	if (!dev)
		return;
Petko Manolov's avatar
Petko Manolov committed
512
	warn("%s: Tx timeout.", netdev->name);
Petko Manolov's avatar
USB  
Petko Manolov committed
513 514 515 516 517 518 519
	dev->tx_urb->transfer_flags |= USB_ASYNC_UNLINK;
	usb_unlink_urb(dev->tx_urb);
	dev->stats.tx_errors++;
}

static void rtl8150_set_multicast(struct net_device *netdev)
{
Petko Manolov's avatar
Petko Manolov committed
520
	rtl8150_t *dev;
Petko Manolov's avatar
USB  
Petko Manolov committed
521 522 523 524 525 526 527

	dev = netdev->priv;
	netif_stop_queue(netdev);
	if (netdev->flags & IFF_PROMISC) {
		dev->rx_creg |= 0x0001;
		info("%s: promiscuous mode", netdev->name);
	} else if ((netdev->mc_count > multicast_filter_limit) ||
Petko Manolov's avatar
Petko Manolov committed
528
		   (netdev->flags & IFF_ALLMULTI)) {
Petko Manolov's avatar
USB  
Petko Manolov committed
529 530 531 532 533 534 535 536 537 538 539 540 541
		dev->rx_creg &= 0xfffe;
		dev->rx_creg |= 0x0002;
		info("%s: allmulti set", netdev->name);
	} else {
		/* ~RX_MULTICAST, ~RX_PROMISCUOUS */
		dev->rx_creg &= 0x00fc;
	}
	async_set_registers(dev, RCR, 2, &dev->rx_creg);
	netif_wake_queue(netdev);
}

static int rtl8150_start_xmit(struct sk_buff *skb, struct net_device *netdev)
{
Petko Manolov's avatar
Petko Manolov committed
542 543
	rtl8150_t *dev;
	int count, res;
Petko Manolov's avatar
USB  
Petko Manolov committed
544 545 546

	netif_stop_queue(netdev);
	dev = netdev->priv;
Petko Manolov's avatar
Petko Manolov committed
547 548
	count = (skb->len < 60) ? 60 : skb->len;
	count = (count & 0x3f) ? count : count + 1;
Petko Manolov's avatar
Petko Manolov committed
549 550 551
	dev->tx_skb = skb;
	FILL_BULK_URB(dev->tx_urb, dev->udev, usb_sndbulkpipe(dev->udev, 2),
		      skb->data, count, write_bulk_callback, dev);
552
	if ((res = usb_submit_urb(dev->tx_urb, GFP_ATOMIC))) {
Petko Manolov's avatar
USB  
Petko Manolov committed
553 554 555 556 557 558 559 560 561 562 563 564 565 566
		warn("failed tx_urb %d\n", res);
		dev->stats.tx_errors++;
		netif_start_queue(netdev);
	} else {
		dev->stats.tx_packets++;
		dev->stats.tx_bytes += skb->len;
		netdev->trans_start = jiffies;
	}

	return 0;
}

static int rtl8150_open(struct net_device *netdev)
{
Petko Manolov's avatar
Petko Manolov committed
567 568 569
	rtl8150_t *dev;
	int res;

Petko Manolov's avatar
USB  
Petko Manolov committed
570 571 572 573
	dev = netdev->priv;
	if (dev == NULL) {
		return -ENODEV;
	}
Petko Manolov's avatar
Petko Manolov committed
574 575
	if (dev->rx_skb == NULL)
		dev->rx_skb = pull_skb(dev);
Petko Manolov's avatar
Petko Manolov committed
576 577 578
	if (!dev->rx_skb)
		return -ENOMEM;

Petko Manolov's avatar
Petko Manolov committed
579
	down(&dev->sem);
Petko Manolov's avatar
Petko Manolov committed
580 581 582
	FILL_BULK_URB(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
		      dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev);
	if ((res = usb_submit_urb(dev->rx_urb, GFP_KERNEL)))
Petko Manolov's avatar
USB  
Petko Manolov committed
583
		warn("%s: rx_urb submit failed: %d", __FUNCTION__, res);
Petko Manolov's avatar
Petko Manolov committed
584 585 586 587
	FILL_INT_URB(dev->intr_urb, dev->udev, usb_rcvintpipe(dev->udev, 3),
		     dev->intr_buff, sizeof(dev->intr_buff), intr_callback,
		     dev, dev->intr_interval);
	if ((res = usb_submit_urb(dev->intr_urb, GFP_KERNEL)))
Petko Manolov's avatar
USB  
Petko Manolov committed
588 589 590
		warn("%s: intr_urb submit failed: %d", __FUNCTION__, res);
	netif_start_queue(netdev);
	enable_net_traffic(dev);
Petko Manolov's avatar
Petko Manolov committed
591
	up(&dev->sem);
Petko Manolov's avatar
USB  
Petko Manolov committed
592 593 594 595 596 597 598 599 600 601 602 603 604

	return res;
}

static int rtl8150_close(struct net_device *netdev)
{
	rtl8150_t *dev;
	int res = 0;

	dev = netdev->priv;
	if (!dev)
		return -ENODEV;

Petko Manolov's avatar
Petko Manolov committed
605
	down(&dev->sem);
606
	netif_stop_queue(netdev);
Petko Manolov's avatar
Petko Manolov committed
607 608
	if (!test_bit(RTL8150_UNPLUG, &dev->flags))
		disable_net_traffic(dev);
Petko Manolov's avatar
USB  
Petko Manolov committed
609
	unlink_all_urbs(dev);
Petko Manolov's avatar
Petko Manolov committed
610
	up(&dev->sem);
Petko Manolov's avatar
USB  
Petko Manolov committed
611 612 613 614 615 616

	return res;
}

static int rtl8150_ethtool_ioctl(struct net_device *netdev, void *uaddr)
{
Petko Manolov's avatar
Petko Manolov committed
617 618
	rtl8150_t *dev;
	int cmd;
Petko Manolov's avatar
USB  
Petko Manolov committed
619 620

	dev = netdev->priv;
Petko Manolov's avatar
Petko Manolov committed
621
	if (get_user(cmd, (int *) uaddr))
Petko Manolov's avatar
USB  
Petko Manolov committed
622 623 624
		return -EFAULT;

	switch (cmd) {
Petko Manolov's avatar
Petko Manolov committed
625 626 627
	case ETHTOOL_GDRVINFO:{
		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };

Petko Manolov's avatar
USB  
Petko Manolov committed
628 629
		strncpy(info.driver, DRIVER_DESC, ETHTOOL_BUSINFO_LEN);
		strncpy(info.version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN);
Petko Manolov's avatar
Petko Manolov committed
630
		usb_make_path(dev->udev, info.bus_info, sizeof info.bus_info);
Petko Manolov's avatar
USB  
Petko Manolov committed
631 632 633
		if (copy_to_user(uaddr, &info, sizeof(info)))
			return -EFAULT;
		return 0;
Petko Manolov's avatar
Petko Manolov committed
634 635
		}
	case ETHTOOL_GSET:{
Petko Manolov's avatar
USB  
Petko Manolov committed
636
		struct ethtool_cmd ecmd;
Petko Manolov's avatar
Petko Manolov committed
637
		short lpa, bmcr;
Petko Manolov's avatar
USB  
Petko Manolov committed
638 639 640 641

		if (copy_from_user(&ecmd, uaddr, sizeof(ecmd)))
			return -EFAULT;
		ecmd.supported = (SUPPORTED_10baseT_Half |
Petko Manolov's avatar
Petko Manolov committed
642 643 644 645 646
				  SUPPORTED_10baseT_Full |
				  SUPPORTED_100baseT_Half |
				  SUPPORTED_100baseT_Full |
				  SUPPORTED_Autoneg |
				  SUPPORTED_TP | SUPPORTED_MII);
Petko Manolov's avatar
USB  
Petko Manolov committed
647 648 649 650 651 652 653 654 655 656 657
		ecmd.port = PORT_TP;
		ecmd.transceiver = XCVR_INTERNAL;
		ecmd.phy_address = dev->phy;
		get_registers(dev, BMCR, 2, &bmcr);
		get_registers(dev, ANLP, 2, &lpa);
		if (bmcr & BMCR_ANENABLE) {
			ecmd.autoneg = AUTONEG_ENABLE;
			ecmd.speed = (lpa & (LPA_100HALF | LPA_100FULL)) ?
			             SPEED_100 : SPEED_10;
			if (ecmd.speed == SPEED_100)
				ecmd.duplex = (lpa & LPA_100FULL) ?
Petko Manolov's avatar
Petko Manolov committed
658
				    DUPLEX_FULL : DUPLEX_HALF;
Petko Manolov's avatar
USB  
Petko Manolov committed
659 660
			else
				ecmd.duplex = (lpa & LPA_10FULL) ?
Petko Manolov's avatar
Petko Manolov committed
661
				    DUPLEX_FULL : DUPLEX_HALF;
Petko Manolov's avatar
USB  
Petko Manolov committed
662 663 664
		} else {
			ecmd.autoneg = AUTONEG_DISABLE;
			ecmd.speed = (bmcr & BMCR_SPEED100) ?
Petko Manolov's avatar
Petko Manolov committed
665
			    SPEED_100 : SPEED_10;
Petko Manolov's avatar
USB  
Petko Manolov committed
666
			ecmd.duplex = (bmcr & BMCR_FULLDPLX) ?
Petko Manolov's avatar
Petko Manolov committed
667
			    DUPLEX_FULL : DUPLEX_HALF;
Petko Manolov's avatar
USB  
Petko Manolov committed
668 669 670 671
		}
		if (copy_to_user(uaddr, &ecmd, sizeof(ecmd)))
			return -EFAULT;
		return 0;
Petko Manolov's avatar
Petko Manolov committed
672
		}
Petko Manolov's avatar
USB  
Petko Manolov committed
673 674
	case ETHTOOL_SSET:
		return -ENOTSUPP;
Petko Manolov's avatar
Petko Manolov committed
675 676
	case ETHTOOL_GLINK:{
		struct ethtool_value edata = { ETHTOOL_GLINK };
Petko Manolov's avatar
USB  
Petko Manolov committed
677 678 679 680 681

		edata.data = netif_carrier_ok(netdev);
		if (copy_to_user(uaddr, &edata, sizeof(edata)))
			return -EFAULT;
		return 0;
Petko Manolov's avatar
Petko Manolov committed
682
		}
Petko Manolov's avatar
USB  
Petko Manolov committed
683 684 685 686 687
	default:
		return -EOPNOTSUPP;
	}
}

Petko Manolov's avatar
Petko Manolov committed
688
static int rtl8150_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
Petko Manolov's avatar
USB  
Petko Manolov committed
689 690
{
	rtl8150_t *dev;
Petko Manolov's avatar
Petko Manolov committed
691 692
	u16 *data;
	int res;
Petko Manolov's avatar
USB  
Petko Manolov committed
693 694

	dev = netdev->priv;
Petko Manolov's avatar
Petko Manolov committed
695
	data = (u16 *) & rq->ifr_data;
Petko Manolov's avatar
Petko Manolov committed
696
	res = 0;
Petko Manolov's avatar
USB  
Petko Manolov committed
697

Petko Manolov's avatar
Petko Manolov committed
698
	down(&dev->sem);
Petko Manolov's avatar
USB  
Petko Manolov committed
699 700
	switch (cmd) {
	case SIOCETHTOOL:
Petko Manolov's avatar
Petko Manolov committed
701 702
		res = rtl8150_ethtool_ioctl(netdev, rq->ifr_data);
		break;
Petko Manolov's avatar
USB  
Petko Manolov committed
703 704
	case SIOCDEVPRIVATE:
		data[0] = dev->phy;
Petko Manolov's avatar
Petko Manolov committed
705
	case SIOCDEVPRIVATE + 1:
Petko Manolov's avatar
USB  
Petko Manolov committed
706
		read_mii_word(dev, dev->phy, (data[1] & 0x1f), &data[3]);
Petko Manolov's avatar
Petko Manolov committed
707
		break;
Petko Manolov's avatar
Petko Manolov committed
708
	case SIOCDEVPRIVATE + 2:
Petko Manolov's avatar
Petko Manolov committed
709 710
		if (!capable(CAP_NET_ADMIN)) {
			up(&dev->sem);
Petko Manolov's avatar
USB  
Petko Manolov committed
711
			return -EPERM;
Petko Manolov's avatar
Petko Manolov committed
712
		}
Petko Manolov's avatar
USB  
Petko Manolov committed
713
		write_mii_word(dev, dev->phy, (data[1] & 0x1f), data[2]);
Petko Manolov's avatar
Petko Manolov committed
714
		break;
Petko Manolov's avatar
USB  
Petko Manolov committed
715
	default:
Petko Manolov's avatar
Petko Manolov committed
716
		res = -EOPNOTSUPP;
Petko Manolov's avatar
USB  
Petko Manolov committed
717
	}
Petko Manolov's avatar
Petko Manolov committed
718 719
	up(&dev->sem);
	return res;
Petko Manolov's avatar
USB  
Petko Manolov committed
720 721
}

Petko Manolov's avatar
Petko Manolov committed
722 723
static void *rtl8150_probe(struct usb_device *udev, unsigned int ifnum,
			   const struct usb_device_id *id)
Petko Manolov's avatar
USB  
Petko Manolov committed
724 725 726 727 728 729 730 731 732 733
{
	rtl8150_t *dev;
	struct net_device *netdev;

	if (usb_set_configuration(udev, udev->config[0].bConfigurationValue)) {
		err("usb_set_configuration() failed");
		return NULL;
	}
	if ((udev->descriptor.idVendor != VENDOR_ID_REALTEK) ||
	    (udev->descriptor.idProduct != PRODUCT_ID_RTL8150)) {
Petko Manolov's avatar
Petko Manolov committed
734
		err("Not the one we are interested about");
Petko Manolov's avatar
USB  
Petko Manolov committed
735 736 737 738
		return NULL;
	}
	dev = kmalloc(sizeof(rtl8150_t), GFP_KERNEL);
	if (!dev) {
Petko Manolov's avatar
Petko Manolov committed
739 740
		err("Out of memory");
		return NULL;
Petko Manolov's avatar
USB  
Petko Manolov committed
741 742 743 744 745 746 747
	} else
		memset(dev, 0, sizeof(rtl8150_t));

	netdev = init_etherdev(NULL, 0);
	if (!netdev) {
		kfree(dev);
		err("Oh boy, out of memory again?!?");
Petko Manolov's avatar
Petko Manolov committed
748
		return NULL;
Petko Manolov's avatar
USB  
Petko Manolov committed
749
	}
Petko Manolov's avatar
Petko Manolov committed
750

Petko Manolov's avatar
USB  
Petko Manolov committed
751
	init_MUTEX(&dev->sem);
Petko Manolov's avatar
Petko Manolov committed
752 753 754 755
	tasklet_init(&dev->tl, rx_fixup, (unsigned long)dev);
	spin_lock_init(&dev->rx_pool_lock);
	
	down(&dev->sem);
Petko Manolov's avatar
USB  
Petko Manolov committed
756 757 758 759 760 761 762 763 764 765 766 767 768 769 770
	dev->udev = udev;
	dev->netdev = netdev;
	SET_MODULE_OWNER(netdev);
	netdev->priv = dev;
	netdev->open = rtl8150_open;
	netdev->stop = rtl8150_close;
	netdev->do_ioctl = rtl8150_ioctl;
	netdev->watchdog_timeo = RTL8150_TX_TIMEOUT;
	netdev->tx_timeout = rtl8150_tx_timeout;
	netdev->hard_start_xmit = rtl8150_start_xmit;
	netdev->set_multicast_list = rtl8150_set_multicast;
	netdev->get_stats = rtl8150_netdev_stats;
	netdev->mtu = RTL8150_MTU;
	dev->intr_interval = 100;	/* 100ms */

Petko Manolov's avatar
Petko Manolov committed
771 772 773 774 775
	if (!alloc_all_urbs(dev)) {
		err("out of memory");
		goto err;
	}
	if (!rtl8150_reset(dev)) {
Petko Manolov's avatar
USB  
Petko Manolov committed
776 777
		err("couldn't reset the device");
		free_all_urbs(dev);
Petko Manolov's avatar
Petko Manolov committed
778
		goto err;
Petko Manolov's avatar
USB  
Petko Manolov committed
779
	}
Petko Manolov's avatar
Petko Manolov committed
780
	fill_skb_pool(dev);
Petko Manolov's avatar
USB  
Petko Manolov committed
781
	set_ethernet_addr(dev);
Petko Manolov's avatar
Petko Manolov committed
782
	info("%s: rtl8150 is detected", netdev->name);
Petko Manolov's avatar
Petko Manolov committed
783 784
	
	up(&dev->sem);
Petko Manolov's avatar
USB  
Petko Manolov committed
785
	return dev;
Petko Manolov's avatar
Petko Manolov committed
786 787 788 789 790 791
err:
	unregister_netdev(dev->netdev);
	up(&dev->sem);
	kfree(netdev);
	kfree(dev);
	return NULL;
Petko Manolov's avatar
USB  
Petko Manolov committed
792 793 794 795 796 797 798
}

static void rtl8150_disconnect(struct usb_device *udev, void *ptr)
{
	rtl8150_t *dev;

	dev = ptr;
Petko Manolov's avatar
Petko Manolov committed
799
	set_bit(RTL8150_UNPLUG, &dev->flags);
Petko Manolov's avatar
USB  
Petko Manolov committed
800 801 802
	unregister_netdev(dev->netdev);
	unlink_all_urbs(dev);
	free_all_urbs(dev);
Petko Manolov's avatar
Petko Manolov committed
803 804 805
	free_skb_pool(dev);
	if (dev->rx_skb)
		dev_kfree_skb(dev->rx_skb);
Petko Manolov's avatar
USB  
Petko Manolov committed
806 807 808 809 810 811
	kfree(dev->netdev);
	kfree(dev);
	dev->netdev = NULL;
	dev = NULL;
}

Petko Manolov's avatar
Petko Manolov committed
812
int __init usb_rtl8150_init(void)
Petko Manolov's avatar
USB  
Petko Manolov committed
813 814 815 816 817
{
	info(DRIVER_DESC " " DRIVER_VERSION);
	return usb_register(&rtl8150_driver);
}

Petko Manolov's avatar
Petko Manolov committed
818
void __exit usb_rtl8150_exit(void)
Petko Manolov's avatar
USB  
Petko Manolov committed
819 820 821 822 823 824 825 826 827 828
{
	usb_deregister(&rtl8150_driver);
}

module_init(usb_rtl8150_init);
module_exit(usb_rtl8150_exit);

MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");