⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 asix.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * ASIX AX8817X based USB 2.0 Ethernet Devices * Copyright (C) 2003-2006 David Hollis <dhollis@davehollis.com> * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net> * Copyright (C) 2006 James Painter <jamie.painter@iname.com> * Copyright (c) 2002-2003 TiVo Inc. * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */// #define	DEBUG			// error path messages, extra info// #define	VERBOSE			// more; success messages#include <linux/module.h>#include <linux/kmod.h>#include <linux/init.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/ethtool.h>#include <linux/workqueue.h>#include <linux/mii.h>#include <linux/usb.h>#include <linux/crc32.h>#include "usbnet.h"#define DRIVER_VERSION "14-Jun-2006"static const char driver_name [] = "asix";/* ASIX AX8817X based USB 2.0 Ethernet Devices */#define AX_CMD_SET_SW_MII		0x06#define AX_CMD_READ_MII_REG		0x07#define AX_CMD_WRITE_MII_REG		0x08#define AX_CMD_SET_HW_MII		0x0a#define AX_CMD_READ_EEPROM		0x0b#define AX_CMD_WRITE_EEPROM		0x0c#define AX_CMD_WRITE_ENABLE		0x0d#define AX_CMD_WRITE_DISABLE		0x0e#define AX_CMD_READ_RX_CTL		0x0f#define AX_CMD_WRITE_RX_CTL		0x10#define AX_CMD_READ_IPG012		0x11#define AX_CMD_WRITE_IPG0		0x12#define AX_CMD_WRITE_IPG1		0x13#define AX_CMD_READ_NODE_ID		0x13#define AX_CMD_WRITE_IPG2		0x14#define AX_CMD_WRITE_MULTI_FILTER	0x16#define AX88172_CMD_READ_NODE_ID	0x17#define AX_CMD_READ_PHY_ID		0x19#define AX_CMD_READ_MEDIUM_STATUS	0x1a#define AX_CMD_WRITE_MEDIUM_MODE	0x1b#define AX_CMD_READ_MONITOR_MODE	0x1c#define AX_CMD_WRITE_MONITOR_MODE	0x1d#define AX_CMD_READ_GPIOS		0x1e#define AX_CMD_WRITE_GPIOS		0x1f#define AX_CMD_SW_RESET			0x20#define AX_CMD_SW_PHY_STATUS		0x21#define AX_CMD_SW_PHY_SELECT		0x22#define AX_MONITOR_MODE			0x01#define AX_MONITOR_LINK			0x02#define AX_MONITOR_MAGIC		0x04#define AX_MONITOR_HSFS			0x10/* AX88172 Medium Status Register values */#define AX88172_MEDIUM_FD		0x02#define AX88172_MEDIUM_TX		0x04#define AX88172_MEDIUM_FC		0x10#define AX88172_MEDIUM_DEFAULT \		( AX88172_MEDIUM_FD | AX88172_MEDIUM_TX | AX88172_MEDIUM_FC )#define AX_MCAST_FILTER_SIZE		8#define AX_MAX_MCAST			64#define AX_SWRESET_CLEAR		0x00#define AX_SWRESET_RR			0x01#define AX_SWRESET_RT			0x02#define AX_SWRESET_PRTE			0x04#define AX_SWRESET_PRL			0x08#define AX_SWRESET_BZ			0x10#define AX_SWRESET_IPRL			0x20#define AX_SWRESET_IPPD			0x40#define AX88772_IPG0_DEFAULT		0x15#define AX88772_IPG1_DEFAULT		0x0c#define AX88772_IPG2_DEFAULT		0x12/* AX88772 & AX88178 Medium Mode Register */#define AX_MEDIUM_PF		0x0080#define AX_MEDIUM_JFE		0x0040#define AX_MEDIUM_TFC		0x0020#define AX_MEDIUM_RFC		0x0010#define AX_MEDIUM_ENCK		0x0008#define AX_MEDIUM_AC		0x0004#define AX_MEDIUM_FD		0x0002#define AX_MEDIUM_GM		0x0001#define AX_MEDIUM_SM		0x1000#define AX_MEDIUM_SBP		0x0800#define AX_MEDIUM_PS		0x0200#define AX_MEDIUM_RE		0x0100#define AX88178_MEDIUM_DEFAULT	\	(AX_MEDIUM_PS | AX_MEDIUM_FD | AX_MEDIUM_AC | \	 AX_MEDIUM_RFC | AX_MEDIUM_TFC | AX_MEDIUM_JFE | \	 AX_MEDIUM_RE )#define AX88772_MEDIUM_DEFAULT	\	(AX_MEDIUM_FD | AX_MEDIUM_RFC | \	 AX_MEDIUM_TFC | AX_MEDIUM_PS | \	 AX_MEDIUM_AC | AX_MEDIUM_RE )/* AX88772 & AX88178 RX_CTL values */#define AX_RX_CTL_SO			0x0080#define AX_RX_CTL_AP			0x0020#define AX_RX_CTL_AM			0x0010#define AX_RX_CTL_AB			0x0008#define AX_RX_CTL_SEP			0x0004#define AX_RX_CTL_AMALL			0x0002#define AX_RX_CTL_PRO			0x0001#define AX_RX_CTL_MFB_2048		0x0000#define AX_RX_CTL_MFB_4096		0x0100#define AX_RX_CTL_MFB_8192		0x0200#define AX_RX_CTL_MFB_16384		0x0300#define AX_DEFAULT_RX_CTL	\	(AX_RX_CTL_SO | AX_RX_CTL_AB )/* GPIO 0 .. 2 toggles */#define AX_GPIO_GPO0EN		0x01	/* GPIO0 Output enable */#define AX_GPIO_GPO_0		0x02	/* GPIO0 Output value */#define AX_GPIO_GPO1EN		0x04	/* GPIO1 Output enable */#define AX_GPIO_GPO_1		0x08	/* GPIO1 Output value */#define AX_GPIO_GPO2EN		0x10	/* GPIO2 Output enable */#define AX_GPIO_GPO_2		0x20	/* GPIO2 Output value */#define AX_GPIO_RESERVED	0x40	/* Reserved */#define AX_GPIO_RSE		0x80	/* Reload serial EEPROM */#define AX_EEPROM_MAGIC		0xdeadbeef#define AX88172_EEPROM_LEN	0x40#define AX88772_EEPROM_LEN	0xff#define PHY_MODE_MARVELL	0x0000#define MII_MARVELL_LED_CTRL	0x0018#define MII_MARVELL_STATUS	0x001b#define MII_MARVELL_CTRL	0x0014#define MARVELL_LED_MANUAL	0x0019#define MARVELL_STATUS_HWCFG	0x0004#define MARVELL_CTRL_TXDELAY	0x0002#define MARVELL_CTRL_RXDELAY	0x0080/* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */struct asix_data {	u8 multi_filter[AX_MCAST_FILTER_SIZE];	u8 phymode;	u8 ledmode;	u8 eeprom_len;};struct ax88172_int_data {	__le16 res1;	u8 link;	__le16 res2;	u8 status;	__le16 res3;} __attribute__ ((packed));static int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,			    u16 size, void *data){	void *buf;	int err = -ENOMEM;	devdbg(dev,"asix_read_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d",		cmd, value, index, size);	buf = kmalloc(size, GFP_KERNEL);	if (!buf)		goto out;	err = usb_control_msg(		dev->udev,		usb_rcvctrlpipe(dev->udev, 0),		cmd,		USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,		value,		index,		buf,		size,		USB_CTRL_GET_TIMEOUT);	if (err == size)		memcpy(data, buf, size);	else if (err >= 0)		err = -EINVAL;	kfree(buf);out:	return err;}static int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,			     u16 size, void *data){	void *buf = NULL;	int err = -ENOMEM;	devdbg(dev,"asix_write_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d",		cmd, value, index, size);	if (data) {		buf = kmalloc(size, GFP_KERNEL);		if (!buf)			goto out;		memcpy(buf, data, size);	}	err = usb_control_msg(		dev->udev,		usb_sndctrlpipe(dev->udev, 0),		cmd,		USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,		value,		index,		buf,		size,		USB_CTRL_SET_TIMEOUT);	kfree(buf);out:	return err;}static void asix_async_cmd_callback(struct urb *urb){	struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context;	if (urb->status < 0)		printk(KERN_DEBUG "asix_async_cmd_callback() failed with %d",			urb->status);	kfree(req);	usb_free_urb(urb);}static voidasix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index,				    u16 size, void *data){	struct usb_ctrlrequest *req;	int status;	struct urb *urb;	devdbg(dev,"asix_write_cmd_async() cmd=0x%02x value=0x%04x index=0x%04x size=%d",		cmd, value, index, size);	if ((urb = usb_alloc_urb(0, GFP_ATOMIC)) == NULL) {		deverr(dev, "Error allocating URB in write_cmd_async!");		return;	}	if ((req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC)) == NULL) {		deverr(dev, "Failed to allocate memory for control request");		usb_free_urb(urb);		return;	}	req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE;	req->bRequest = cmd;	req->wValue = cpu_to_le16(value);	req->wIndex = cpu_to_le16(index);	req->wLength = cpu_to_le16(size);	usb_fill_control_urb(urb, dev->udev,			     usb_sndctrlpipe(dev->udev, 0),			     (void *)req, data, size,			     asix_async_cmd_callback, req);	if((status = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {		deverr(dev, "Error submitting the control message: status=%d",				status);		kfree(req);		usb_free_urb(urb);	}}static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb){	u8  *head;	u32  header;	char *packet;	struct sk_buff *ax_skb;	u16 size;	head = (u8 *) skb->data;	memcpy(&header, head, sizeof(header));	le32_to_cpus(&header);	packet = head + sizeof(header);	skb_pull(skb, 4);	while (skb->len > 0) {		if ((short)(header & 0x0000ffff) !=		    ~((short)((header & 0xffff0000) >> 16))) {			deverr(dev,"asix_rx_fixup() Bad Header Length");		}		/* get the packet length */		size = (u16) (header & 0x0000ffff);		if ((skb->len) - ((size + 1) & 0xfffe) == 0)			return 2;		if (size > ETH_FRAME_LEN) {			deverr(dev,"asix_rx_fixup() Bad RX Length %d", size);			return 0;		}		ax_skb = skb_clone(skb, GFP_ATOMIC);		if (ax_skb) {			ax_skb->len = size;			ax_skb->data = packet;			skb_set_tail_pointer(ax_skb, size);			usbnet_skb_return(dev, ax_skb);		} else {			return 0;		}		skb_pull(skb, (size + 1) & 0xfffe);		if (skb->len == 0)			break;		head = (u8 *) skb->data;		memcpy(&header, head, sizeof(header));		le32_to_cpus(&header);		packet = head + sizeof(header);		skb_pull(skb, 4);	}	if (skb->len < 0) {		deverr(dev,"asix_rx_fixup() Bad SKB Length %d", skb->len);		return 0;	}	return 1;}static struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb,					gfp_t flags){	int padlen;	int headroom = skb_headroom(skb);	int tailroom = skb_tailroom(skb);	u32 packet_len;	u32 padbytes = 0xffff0000;	padlen = ((skb->len + 4) % 512) ? 0 : 4;	if ((!skb_cloned(skb))	    && ((headroom + tailroom) >= (4 + padlen))) {		if ((headroom < 4) || (tailroom < padlen)) {			skb->data = memmove(skb->head + 4, skb->data, skb->len);			skb_set_tail_pointer(skb, skb->len);		}	} else {		struct sk_buff *skb2;		skb2 = skb_copy_expand(skb, 4, padlen, flags);		dev_kfree_skb_any(skb);		skb = skb2;		if (!skb)			return NULL;	}	skb_push(skb, 4);	packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4);	cpu_to_le32s(&packet_len);	skb_copy_to_linear_data(skb, &packet_len, sizeof(packet_len));	if ((skb->len % 512) == 0) {		cpu_to_le32s(&padbytes);		memcpy(skb_tail_pointer(skb), &padbytes, sizeof(padbytes));		skb_put(skb, sizeof(padbytes));	}	return skb;}static void asix_status(struct usbnet *dev, struct urb *urb){	struct ax88172_int_data *event;	int link;	if (urb->actual_length < 8)		return;	event = urb->transfer_buffer;	link = event->link & 0x01;	if (netif_carrier_ok(dev->net) != link) {		if (link) {			netif_carrier_on(dev->net);			usbnet_defer_kevent (dev, EVENT_LINK_RESET );		} else			netif_carrier_off(dev->net);		devdbg(dev, "Link Status is: %d", link);	}}static inline int asix_set_sw_mii(struct usbnet *dev){	int ret;	ret = asix_write_cmd(dev, AX_CMD_SET_SW_MII, 0x0000, 0, 0, NULL);	if (ret < 0)		deverr(dev, "Failed to enable software MII access");	return ret;}static inline int asix_set_hw_mii(struct usbnet *dev){	int ret;	ret = asix_write_cmd(dev, AX_CMD_SET_HW_MII, 0x0000, 0, 0, NULL);	if (ret < 0)		deverr(dev, "Failed to enable hardware MII access");	return ret;}static inline int asix_get_phy_addr(struct usbnet *dev){	u8 buf[2];	int ret = asix_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf);	devdbg(dev, "asix_get_phy_addr()");	if (ret < 0) {		deverr(dev, "Error reading PHYID register: %02x", ret);		goto out;	}	devdbg(dev, "asix_get_phy_addr() returning 0x%04x", *((__le16 *)buf));	ret = buf[1];out:	return ret;}static int asix_sw_reset(struct usbnet *dev, u8 flags){	int ret;        ret = asix_write_cmd(dev, AX_CMD_SW_RESET, flags, 0, 0, NULL);	if (ret < 0)		deverr(dev,"Failed to send software reset: %02x", ret);	return ret;}static u16 asix_read_rx_ctl(struct usbnet *dev){	__le16 v;	int ret = asix_read_cmd(dev, AX_CMD_READ_RX_CTL, 0, 0, 2, &v);	if (ret < 0) {		deverr(dev, "Error reading RX_CTL register: %02x", ret);		goto out;	}	ret = le16_to_cpu(v);out:	return ret;}static int asix_write_rx_ctl(struct usbnet *dev, u16 mode){	int ret;	devdbg(dev,"asix_write_rx_ctl() - mode = 0x%04x", mode);	ret = asix_write_cmd(dev, AX_CMD_WRITE_RX_CTL, mode, 0, 0, NULL);	if (ret < 0)		deverr(dev, "Failed to write RX_CTL mode to 0x%04x: %02x",		       mode, ret);	return ret;}static u16 asix_read_medium_status(struct usbnet *dev){

⌨️ 快捷键说明

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