rtl8150.c

来自「是关于linux2.5.1的完全源码」· C语言 代码 · 共 835 行 · 第 1/2 页

C
835
字号
/* * Copyright (c) 2002 Petko Manolov (petkan@users.sourceforge.net) * *	This program is free software; you can redistribute it and/or *	modify it under the terms of the GNU General Public License as *	published by the Free Software Foundation; either version 2 of *	the License, or (at your option) any later version. * */#include <linux/config.h>#include <linux/sched.h>#include <linux/signal.h>#include <linux/slab.h>#include <linux/module.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/mii.h>#include <linux/ethtool.h>#include <linux/devfs_fs_kernel.h>#include <linux/usb.h>#include <asm/uaccess.h>/* Version Information */#define DRIVER_VERSION "v0.5.4 (2002/04/11)"#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#define	MII_TIMEOUT		10#define	RTL8150_REQT_READ	0xc0#define	RTL8150_REQT_WRITE	0x40#define	RTL8150_REQ_GET_REGS	0x05#define	RTL8150_REQ_SET_REGS	0x05#define	RTL8150_MTU		1540#define	RTL8150_TX_TIMEOUT	(HZ)#define	RX_SKB_POOL_SIZE	4/* rtl8150 flags */#define	RTL8150_HW_CRC		0#define	RX_REG_SET		1#define	RTL8150_UNPLUG		2#define	RX_URB_FAIL		3/* 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 */static struct usb_device_id rtl8150_table[] = {	{USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8150)},	{}};MODULE_DEVICE_TABLE(usb, rtl8150_table);struct rtl8150 {	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;};typedef struct rtl8150 rtl8150_t;/* the global usb devfs handle */extern devfs_handle_t usb_devfs_handle;unsigned long multicast_filter_limit = 32;static void fill_skb_pool(rtl8150_t *);static void free_skb_pool(rtl8150_t *);static struct sk_buff *pull_skb(rtl8150_t *);static void rtl8150_disconnect(struct usb_device *dev, void *ptr);static void *rtl8150_probe(struct usb_device *dev, unsigned int ifnum,			   const struct usb_device_id *id);static struct usb_driver rtl8150_driver = {	name:		"rtl8150",	probe:		rtl8150_probe,	disconnect:	rtl8150_disconnect,	id_table:	rtl8150_table,};/*****	device related part of the code***/static int get_registers(rtl8150_t * dev, u16 indx, u16 size, void *data){	return usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),			       RTL8150_REQ_GET_REGS, RTL8150_REQT_READ,			       indx, 0, data, size, HZ / 2);}static int set_registers(rtl8150_t * dev, u16 indx, u16 size, void *data){	return usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),			       RTL8150_REQ_SET_REGS, RTL8150_REQT_WRITE,			       indx, 0, data, size, HZ / 2);}static void ctrl_callback(struct urb *urb){	rtl8150_t *dev;	switch (urb->status) {	case 0:		break;	case -EINPROGRESS:		break;	case -ENOENT:		break;	default:		warn("ctrl urb status %d", urb->status);	}	dev = urb->context;	clear_bit(RX_REG_SET, &dev->flags);}static int async_set_registers(rtl8150_t * dev, u16 indx, u16 size, void *data){	int ret;	if (test_bit(RX_REG_SET, &dev->flags))		return -EAGAIN;	dev->dr.bRequestType = RTL8150_REQT_WRITE;	dev->dr.bRequest = RTL8150_REQ_SET_REGS;	dev->dr.wValue = cpu_to_le16(indx);	dev->dr.wIndex = 0;	dev->dr.wLength = cpu_to_le16(size);	dev->ctrl_urb->transfer_buffer_length = size;	FILL_CONTROL_URB(dev->ctrl_urb, dev->udev,			 usb_sndctrlpipe(dev->udev, 0), (char *) &dev->dr,			 &dev->rx_creg, size, ctrl_callback, dev);	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;}static int read_mii_word(rtl8150_t * dev, u8 phy, __u8 indx, u16 * reg){	int i;	u8 data[3], tmp;	data[0] = phy;	data[1] = data[2] = 0;	tmp = indx | PHY_READ | PHY_GO;	i = 0;	set_registers(dev, PHYADD, sizeof(data), data);	set_registers(dev, PHYCNT, 1, &tmp);	do {		get_registers(dev, PHYCNT, 1, data);	} while ((data[0] & PHY_GO) && (i++ < MII_TIMEOUT));	if (i < MII_TIMEOUT) {		get_registers(dev, PHYDAT, 2, data);		*reg = le16_to_cpup(data);		return 0;	} else		return 1;}static int write_mii_word(rtl8150_t * dev, u8 phy, __u8 indx, u16 reg){	int i;	u8 data[3], tmp;	data[0] = phy;	*(data + 1) = cpu_to_le16p(&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);	} while ((data[0] & PHY_GO) && (i++ < MII_TIMEOUT));	if (i < MII_TIMEOUT)		return 0;	else		return 1;}static inline void set_ethernet_addr(rtl8150_t * dev){	u8 node_id[6];	get_registers(dev, IRD, sizeof(node_id), node_id);	memcpy(dev->netdev->dev_addr, node_id, sizeof(node_id));}static int rtl8150_reset(rtl8150_t * dev){	u8 data = 0x10;	int i = HZ;	set_registers(dev, CR, 1, &data);	do {		get_registers(dev, CR, 1, &data);	} while ((data & 0x10) && --i);	return (i > 0) ? 1 : 0;}static int alloc_all_urbs(rtl8150_t * dev){	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;}static void free_all_urbs(rtl8150_t * dev){	usb_free_urb(dev->rx_urb);	usb_free_urb(dev->tx_urb);	usb_free_urb(dev->intr_urb);	usb_free_urb(dev->ctrl_urb);}static void unlink_all_urbs(rtl8150_t * dev){	usb_unlink_urb(dev->rx_urb);	usb_unlink_urb(dev->tx_urb);	usb_unlink_urb(dev->intr_urb);	usb_unlink_urb(dev->ctrl_urb);}static void read_bulk_callback(struct urb *urb){	rtl8150_t *dev;	unsigned pkt_len, res;	struct sk_buff *skb;	struct net_device *netdev;	u16 rx_stat;	dev = urb->context;	if (!dev)		return;	if (test_bit(RTL8150_UNPLUG, &dev->flags))		return;	netdev = dev->netdev;	if (!netif_device_present(netdev))		return;	switch (urb->status) {	case 0:		break;	case -ENOENT:		return;	/* the urb is in unlink state */	case -ETIMEDOUT:		warn("reset needed may be?..");		goto goon;	default:		warn("Rx status %d", urb->status);		goto goon;	}	if (!dev->rx_skb)		goto resched;	res = urb->actual_length;	rx_stat = le16_to_cpu(*(short *)(urb->transfer_buffer + res - 4));	pkt_len = res - 4;	skb_put(dev->rx_skb, pkt_len);	dev->rx_skb->protocol = eth_type_trans(dev->rx_skb, netdev);	netif_rx(dev->rx_skb);	dev->stats.rx_packets++;	dev->stats.rx_bytes += pkt_len;		skb = pull_skb(dev);	if (!skb)		goto resched;	skb->dev = netdev;	skb_reserve(skb, 2);	dev->rx_skb = skb;goon:	FILL_BULK_URB(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),		      dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev);	if (usb_submit_urb(dev->rx_urb, GFP_ATOMIC)) {		set_bit(RX_URB_FAIL, &dev->flags);		goto resched;	} else {		clear_bit(RX_URB_FAIL, &dev->flags);	}	return;resched:	tasklet_schedule(&dev->tl);}static void rx_fixup(unsigned long data){	rtl8150_t *dev;	struct sk_buff *skb;	dev = (rtl8150_t *)data;	fill_skb_pool(dev);	if (test_bit(RX_URB_FAIL, &dev->flags))		if (dev->rx_skb)			goto try_again;	if (!(skb = pull_skb(dev)))		goto tlsched;	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);try_again:	if (usb_submit_urb(dev->rx_urb, GFP_ATOMIC)) {		set_bit(RX_URB_FAIL, &dev->flags);		goto tlsched;	 } else {		clear_bit(RX_URB_FAIL, &dev->flags);	}	return;tlsched:	tasklet_schedule(&dev->tl);}static void write_bulk_callback(struct urb *urb){	rtl8150_t *dev;	dev = urb->context;	if (!dev)		return;	dev_kfree_skb_irq(dev->tx_skb);	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){	rtl8150_t *dev;	dev = urb->context;	if (!dev)		return;	switch (urb->status) {	case 0:		break;	case -ENOENT:		return;	default:		info("%s: intr status %d", dev->netdev->name, urb->status);	}}/*

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?