netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH-SR9700] Merge USB 1.1 Ethernet Adapter SR9700 Device Driver into the Linux Kernel
@ 2013-08-20 10:50 liujunliang_ljl
  2013-08-20 13:36 ` Ben Hutchings
  2013-08-21 10:02 ` Re: [PATCH-SR9700] Merge USB 1.1 Ethernet Adapter SR9700 DeviceDriver " liujunliang_ljl
  0 siblings, 2 replies; 9+ messages in thread
From: liujunliang_ljl @ 2013-08-20 10:50 UTC (permalink / raw)
  To: gregkh; +Cc: linux-usb, netdev, linux-kernel, sunhecheng

Dear Gregkh & all :

		I am the software engineer Liu Junliang from ShenZhen CoreChips high technology company, on the market of SR9700 chip is designed and owned by us. 
        SR9700 is a type of USB to Ethernet Converter and is compatible with USB 1.1 protocol, We want to merge SR9700 device driver into the Linux Kernel. The following is the Linux 3.10.7 version patch for SR9700, Please give us the assessment and support.
        Thanks a lot.

[PATCH] :                             
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index 287cc62..a94b196 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -272,6 +272,14 @@ config USB_NET_DM9601
 	  This option adds support for Davicom DM9601 based USB 1.1
 	  10/100 Ethernet adapters.
 
+config USB_NET_SR9700
+	tristate "CoreChip-sz SR9700 based USB 1.1 10/100 ethernet devices"
+	depends on USB_USBNET
+	select CRC32
+	help
+	  This option adds support for CoreChip-sz SR9700 based USB 1.1
+	  10/100 Ethernet adapters.
+
 config USB_NET_SMSC75XX
 	tristate "SMSC LAN75XX based USB 2.0 gigabit ethernet devices"
 	depends on USB_USBNET
diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile
index 9ab5c9d..bba87a2 100644
--- a/drivers/net/usb/Makefile
+++ b/drivers/net/usb/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_USB_NET_AX88179_178A)      += ax88179_178a.o
 obj-$(CONFIG_USB_NET_CDCETHER)	+= cdc_ether.o
 obj-$(CONFIG_USB_NET_CDC_EEM)	+= cdc_eem.o
 obj-$(CONFIG_USB_NET_DM9601)	+= dm9601.o
+obj-$(CONFIG_USB_NET_SR9700)	+= sr9700.o
 obj-$(CONFIG_USB_NET_SMSC75XX)	+= smsc75xx.o
 obj-$(CONFIG_USB_NET_SMSC95XX)	+= smsc95xx.o
 obj-$(CONFIG_USB_NET_GL620A)	+= gl620a.o
diff --git a/drivers/net/usb/sr9700.c b/drivers/net/usb/sr9700.c
new file mode 100644
index 0000000..6a6429a
--- /dev/null
+++ b/drivers/net/usb/sr9700.c
@@ -0,0 +1,557 @@
+/*
+ * CoreChip-sz SR9700 one chip USB 1.1 Ethernet Devices
+ *
+ * Author : liujl <liujunliang_ljl@163.com>
+ *
+ * Based on dm9601.c
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+//#define DEBUG
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/usb.h>
+#include <linux/crc32.h>
+#include <linux/usb/usbnet.h>
+
+#include "sr9700.h"
+
+static int sr_read(struct usbnet *dev, u8 reg, u16 length, void *data)
+{
+	int err;
+
+	err = usbnet_read_cmd(dev, SR_RD_REGS, SR_REQ_RD_REG,
+					0, reg, data, length);
+	if(err != length && err >= 0)
+		err = -EINVAL;
+	return err;
+}
+
+static int sr_write(struct usbnet *dev, u8 reg, u16 length, void *data)
+{
+	int err;
+
+	err = usbnet_write_cmd(dev, SR_WR_REGS, SR_REQ_WR_REG,
+					0, reg, data, length);
+	if (err >= 0 && err < length)
+		err = -EINVAL;
+	
+	return err;
+}
+
+static int sr_read_reg(struct usbnet *dev, u8 reg, u8 *value)
+{
+	return sr_read(dev, reg, 1, value);
+}
+
+static int sr_write_reg(struct usbnet *dev, u8 reg, u8 value)
+{
+	return usbnet_write_cmd(dev, SR_WR_REGS, SR_REQ_WR_REG,
+			       value, reg, NULL, 0);
+}
+
+static void sr_write_async(struct usbnet *dev, u8 reg, u16 length, void *data)
+{
+	usbnet_write_cmd_async(dev, SR_WR_REGS, SR_REQ_WR_REG,
+					0, reg, data, length);
+}
+
+static void sr_write_reg_async(struct usbnet *dev, u8 reg, u8 value)
+{
+	usbnet_write_cmd_async(dev, SR_WR_REGS, SR_REQ_WR_REG,
+					value, reg, NULL, 0);
+}
+
+static int sr_share_read_word(struct usbnet *dev, int phy, u8 reg, __le16 *value)
+{
+	int ret, i;
+
+	mutex_lock(&dev->phy_mutex);
+
+	sr_write_reg(dev, EPAR, phy ? (reg | 0x40) : reg);
+	sr_write_reg(dev, EPCR, phy ? 0xc : 0x4);
+
+	for (i = 0; i < SR_SHARE_TIMEOUT; i++) {
+		u8 tmp = 0;
+
+		udelay(1);
+		ret = sr_read_reg(dev, EPCR, &tmp);
+		if (ret < 0)
+			goto out;
+
+		/* ready */
+		if ((tmp & 1) == 0)
+			break;
+	}
+
+	if (i >= SR_SHARE_TIMEOUT) {
+		netdev_err(dev->net, "%s read timed out!", phy ? "phy" : "eeprom");
+		ret = -EIO;
+		goto out;
+	}
+
+	sr_write_reg(dev, EPCR, 0x0);
+	ret = sr_read(dev, EPDR, 2, value);
+
+	netdev_dbg(dev->net, "read shared %d 0x%02x returned 0x%04x, %d",
+	       phy, reg, *value, ret);
+
+ out:
+	mutex_unlock(&dev->phy_mutex);
+	return ret;
+}
+
+static int sr_share_write_word(struct usbnet *dev, int phy, u8 reg, __le16 value)
+{
+	int ret, i;
+
+	mutex_lock(&dev->phy_mutex);
+
+	ret = sr_write(dev, EPDR, 2, &value);
+	if (ret < 0)
+		goto out;
+
+	sr_write_reg(dev, EPAR, phy ? (reg | 0x40) : reg);
+	sr_write_reg(dev, EPCR, phy ? 0x1a : 0x12);
+
+	for (i = 0; i < SR_SHARE_TIMEOUT; i++) {
+		u8 tmp = 0;
+
+		udelay(1);
+		ret = sr_read_reg(dev, EPCR, &tmp);
+		if (ret < 0)
+			goto out;
+
+		/* ready */
+		if ((tmp & 1) == 0)
+			break;
+	}
+
+	if (i >= SR_SHARE_TIMEOUT) {
+		netdev_err(dev->net, "%s write timed out!", phy ? "phy" : "eeprom");
+		ret = -EIO;
+		goto out;
+	}
+
+	sr_write_reg(dev, EPCR, 0x0);
+
+out:
+	mutex_unlock(&dev->phy_mutex);
+	return ret;
+}
+
+static int sr_read_eeprom_word(struct usbnet *dev, u8 offset, void *value)
+{
+	return sr_share_read_word(dev, 0, offset, value);
+}
+
+
+static int sr9700_get_eeprom_len(struct net_device *dev)
+{
+	return SR_EEPROM_LEN;
+}
+
+static int sr9700_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, u8 * data)
+{
+	struct usbnet *dev = netdev_priv(net);
+	__le16 *ebuf = (__le16 *) data;
+	int i;
+
+	/* access is 16bit */
+	if ((eeprom->offset % 2) || (eeprom->len % 2))
+		return -EINVAL;
+
+	for (i = 0; i < eeprom->len / 2; i++) {
+		if (sr_read_eeprom_word(dev, eeprom->offset / 2 + i, &ebuf[i]) < 0)
+			return -EINVAL;
+	}
+	return 0;
+}
+
+static int sr_mdio_read(struct net_device *netdev, int phy_id, int loc)
+{
+	struct usbnet *dev = netdev_priv(netdev);
+
+	__le16 res;
+	int rc = 0;
+
+	if (phy_id) {
+		netdev_dbg(dev->net, "Only internal phy supported");
+		return 0;
+	}
+
+	/* Access NSR_LINKST bit for link status instead of MII_BMSR */
+	if(loc == MII_BMSR){
+			u8 value;
+			sr_read_reg(dev, NSR, &value);
+			if(value & NSR_LINKST) {
+				rc = 1;
+			}
+	}
+	sr_share_read_word(dev, 1, loc, &res);
+	if(rc == 1)
+			return (le16_to_cpu(res) | BMSR_LSTATUS);
+	else
+			return (le16_to_cpu(res) & ~BMSR_LSTATUS);
+
+	netdev_dbg(dev->net,
+	       "sr_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x",
+	       phy_id, loc, le16_to_cpu(res));
+
+	return le16_to_cpu(res);
+}
+
+static void sr_mdio_write(struct net_device *netdev, int phy_id, int loc, int val)
+{
+	struct usbnet *dev = netdev_priv(netdev);
+	__le16 res = cpu_to_le16(val);
+
+	if (phy_id) {
+		netdev_dbg(dev->net, "Only internal phy supported");
+		return;
+	}
+
+	netdev_dbg(dev->net,"sr_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x",
+	       phy_id, loc, val);
+
+	sr_share_write_word(dev, 1, loc, res);
+}
+
+/*-------------------------------------------------------------------------------------------*/
+
+static void sr9700_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info)
+{
+	/* Inherit standard device info */
+	usbnet_get_drvinfo(net, info);
+	info->eedump_len = SR_EEPROM_LEN;
+}
+
+static u32 sr9700_get_link(struct net_device *net)
+{
+	struct usbnet *dev = netdev_priv(net);
+	int rc = 0;
+	u8 value = 0;
+
+	/* Get the Link Status directly */
+	sr_read_reg(dev, NSR, &value);
+	if(value & NSR_LINKST) {
+		rc = 1;
+	}
+
+	return rc;
+}
+
+static int sr9700_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
+{
+	struct usbnet *dev = netdev_priv(net);
+
+	return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
+}
+
+static const struct ethtool_ops sr9700_ethtool_ops = {
+	.get_drvinfo	= sr9700_get_drvinfo,
+	.get_link	= sr9700_get_link,
+	.get_msglevel	= usbnet_get_msglevel,
+	.set_msglevel	= usbnet_set_msglevel,
+	.get_eeprom_len	= sr9700_get_eeprom_len,
+	.get_eeprom	= sr9700_get_eeprom,
+	.get_settings	= usbnet_get_settings,
+	.set_settings	= usbnet_set_settings,
+	.nway_reset	= usbnet_nway_reset,
+};
+
+static void sr9700_set_multicast(struct net_device *net)
+{
+	struct usbnet *dev = netdev_priv(net);
+	/* We use the 20 byte dev->data for our 8 byte filter buffer
+	 * to avoid allocating memory that is tricky to free later */
+	u8 *hashes = (u8 *) & dev->data;
+	u8 rx_ctl = 0x31;	// enable, disable_long, disable_crc
+
+	memset(hashes, 0x00, SR_MCAST_SIZE);
+	hashes[SR_MCAST_SIZE - 1] |= 0x80;	/* broadcast address */
+
+        if (net->flags & IFF_PROMISC) {
+                rx_ctl |= 0x02;
+        } else if (net->flags & IFF_ALLMULTI ||
+                   netdev_mc_count(net) > SR_MCAST_MAX) {
+                rx_ctl |= 0x04;
+        } else if (!netdev_mc_empty(net)) {
+                struct netdev_hw_addr *ha;
+ 
+                netdev_for_each_mc_addr(ha, net) {
+                        u32 crc = ether_crc(ETH_ALEN, ha->addr) >> 26;
+                        hashes[crc >> 3] |= 1 << (crc & 0x7);
+                }
+        }
+
+	sr_write_async(dev, MAR, SR_MCAST_SIZE, hashes);
+	sr_write_reg_async(dev, RCR, rx_ctl);
+}
+
+static int sr9700_set_mac_address(struct net_device *net, void *p)
+{
+	struct sockaddr *addr = p;
+	struct usbnet *dev = netdev_priv(net);
+
+	if (!is_valid_ether_addr(addr->sa_data)) {
+		dev_err(&net->dev, "not setting invalid mac address %pM\n",
+								addr->sa_data);
+		return -EINVAL;
+	}
+
+	memcpy(net->dev_addr, addr->sa_data, net->addr_len);
+	sr_write_async(dev, PAR, 6, dev->net->dev_addr);
+
+	return 0;
+}
+
+static const struct net_device_ops sr9700_netdev_ops = {
+	.ndo_open		= usbnet_open,
+	.ndo_stop		= usbnet_stop,
+	.ndo_start_xmit		= usbnet_start_xmit,
+	.ndo_tx_timeout		= usbnet_tx_timeout,
+	.ndo_change_mtu		= usbnet_change_mtu,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_do_ioctl 		= sr9700_ioctl,
+	.ndo_set_rx_mode	= sr9700_set_multicast,
+	.ndo_set_mac_address	= sr9700_set_mac_address,
+};
+
+static int sr9700_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+	int ret;
+
+	ret = usbnet_get_endpoints(dev, intf);
+	if (ret)
+		goto out;
+
+	dev->net->netdev_ops = &sr9700_netdev_ops;
+	dev->net->ethtool_ops = &sr9700_ethtool_ops;
+	dev->net->hard_header_len += SR_TX_OVERHEAD;
+	dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
+	dev->rx_urb_size = 3072;	// bulkin buffer is preferably not less than 3K
+
+	dev->mii.dev = dev->net;
+	dev->mii.mdio_read = sr_mdio_read;
+	dev->mii.mdio_write = sr_mdio_write;
+	dev->mii.phy_id_mask = 0x1f;
+	dev->mii.reg_num_mask = 0x1f;
+
+	/* reset the sr9700 */
+	sr_write_reg(dev, NCR, 1);
+	udelay(20);
+
+	/* read MAC */
+	if (sr_read(dev, PAR, ETH_ALEN, dev->net->dev_addr) < 0) {
+		printk(KERN_ERR "Error reading MAC address\n");
+		ret = -ENODEV;
+		goto out;
+	}
+
+	/* power up and reset phy */
+	sr_write_reg(dev, PRR, 1);
+	mdelay(20);		// at least 10ms, here 20ms for safe
+	sr_write_reg(dev, PRR, 0);
+	udelay(2 * 1000);	// at least 1ms, here 2ms for reading right register
+
+	/* receive broadcast packets */
+	sr9700_set_multicast(dev->net);
+
+	sr_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
+	sr_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
+	mii_nway_restart(&dev->mii);
+
+out:
+	return ret;
+}
+
+static int sr9700_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+{
+	int len;
+	struct sk_buff *sr_skb;
+
+	/* format:
+	   b0: rx status
+	   b1: packet length (incl crc) low
+	   b2: packet length (incl crc) high
+	   b3..n-4: packet data
+	   bn-3..bn: ethernet crc
+	 */
+
+	if (unlikely(skb->len < SR_RX_OVERHEAD)) {
+		dev_err(&dev->udev->dev, "unexpected tiny rx frame\n");
+		return 0;
+	}
+
+	/*
+	 * Each packet contains multiple skbs
+	 */
+	while (skb->len > SR_RX_OVERHEAD)
+	{
+		if (skb->data[0] != 0x40)
+		{
+			return 0;
+		}
+
+		/* ignore the CRC length */
+		len = (skb->data[1] | (skb->data[2] << 8)) - 4;
+
+		if (len > ETH_FRAME_LEN)
+		{
+			return 0;
+		}
+
+		/* the last skb of current packet */
+		if (skb->len == (len + SR_RX_OVERHEAD))
+		{
+			skb_pull( skb, 3 );
+			skb->len = len;
+			skb->tail = skb->data + len;
+			skb->truesize = len + sizeof(struct sk_buff);
+			return 2;
+		}
+
+		/* skb_clone is used for address align */
+		sr_skb = skb_clone(skb, GFP_ATOMIC);
+		if (sr_skb) 
+		{
+			sr_skb->len = len;
+			sr_skb->data = skb->data + 3;
+			sr_skb->tail = skb->data + len;
+			sr_skb->truesize = len + sizeof(struct sk_buff);
+			usbnet_skb_return(dev, sr_skb);	
+		}
+		else
+		{
+			return 0;
+		}
+
+		skb_pull( skb, len + SR_RX_OVERHEAD );
+	};
+	
+	return 0;
+}
+
+static struct sk_buff *sr9700_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
+{
+	int len;
+
+	/* format:
+	   b0: packet length low
+	   b1: packet length high
+	   b3..n: packet data
+	*/
+
+	len = skb->len;
+
+	if (skb_headroom(skb) < SR_TX_OVERHEAD) {
+		struct sk_buff *skb2;
+
+		skb2 = skb_copy_expand(skb, SR_TX_OVERHEAD, 0, flags);
+		dev_kfree_skb_any(skb);
+		skb = skb2;
+		if (!skb)
+			return NULL;
+	}
+
+	__skb_push(skb, SR_TX_OVERHEAD);
+
+	/* usbnet adds padding if length is a multiple of packet size
+	   if so, adjust length value in header */
+	if ((skb->len % dev->maxpacket) == 0)
+		len++;
+
+	skb->data[0] = len;
+	skb->data[1] = len >> 8;
+
+	return skb;
+}
+
+static void sr9700_status(struct usbnet *dev, struct urb *urb)
+{
+	int link;
+	u8 *buf;
+
+	/* format:
+	   b0: net status
+	   b1: tx status 1
+	   b2: tx status 2
+	   b3: rx status
+	   b4: rx overflow
+	   b5: rx count
+	   b6: tx count
+	   b7: gpr
+	*/
+
+	if (urb->actual_length < 8)
+		return;
+
+	buf = urb->transfer_buffer;
+
+	link = !!(buf[0] & 0x40);
+	if (netif_carrier_ok(dev->net) != link) {
+		usbnet_link_change(dev, link, 1);
+		netdev_dbg(dev->net, "Link Status is: %d", link);
+	}
+}
+
+static int sr9700_link_reset(struct usbnet *dev)
+{
+	struct ethtool_cmd ecmd;
+
+	mii_check_media(&dev->mii, 1, 1);
+	mii_ethtool_gset(&dev->mii, &ecmd);
+
+	netdev_dbg(dev->net, "link_reset() speed: %d duplex: %d",
+	       ecmd.speed, ecmd.duplex);
+
+	return 0;
+}
+
+static const struct driver_info sr9700_driver_info = {
+	.description	= "CoreChip SR9700 USB Ethernet",
+	.flags		= FLAG_ETHER,
+	.bind		= sr9700_bind,
+	.rx_fixup	= sr9700_rx_fixup,
+	.tx_fixup	= sr9700_tx_fixup,
+	.status		= sr9700_status,
+	.link_reset	= sr9700_link_reset,
+	.reset		= sr9700_link_reset,
+};
+
+static const struct usb_device_id products[] = {
+	{
+	 USB_DEVICE(0x0fe6, 0x9700),	/* SR9700 device */
+	 .driver_info = (unsigned long)&sr9700_driver_info,
+	 },
+	{},			// END
+};
+
+MODULE_DEVICE_TABLE(usb, products);
+
+static struct usb_driver sr9700_usb_driver = {
+	.name = "sr9700",
+	.id_table = products,
+	.probe = usbnet_probe,
+	.disconnect = usbnet_disconnect,
+	.suspend = usbnet_suspend,
+	.resume = usbnet_resume,
+	.disable_hub_initiated_lpm = 1,
+};
+
+module_usb_driver(sr9700_usb_driver);
+
+MODULE_AUTHOR("liujl <liujunliang_ljl@163.com>");
+MODULE_DESCRIPTION("SR9700 one chip USB 1.1 USB to Ethernet device from http://www.corechip-sz.com/");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/usb/sr9700.h b/drivers/net/usb/sr9700.h
new file mode 100644
index 0000000..d9fe82d
--- /dev/null
+++ b/drivers/net/usb/sr9700.h
@@ -0,0 +1,152 @@
+/*
+ * CoreChip-sz SR9700 one chip USB 1.1 Ethernet Devices
+ *
+ * Author : liujl <liujunliang_ljl@163.com>
+ *
+ * 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.
+ */
+
+/* sr9700 spec. register table on android platform */
+/* Registers */
+#define	NCR			0x00
+#define	NSR			0x01
+#define	TCR			0x02
+#define	TSR1		0x03
+#define	TSR2		0x04
+#define	RCR			0x05
+#define	RSR			0x06
+#define	ROCR		0x07
+#define	BPTR		0x08
+#define	FCTR		0x09
+#define	FCR			0x0A
+#define	EPCR		0x0B
+#define	EPAR		0x0C
+#define	EPDR		0x0D	// 0x0D ~ 0x0E
+#define	WCR			0x0F
+#define	PAR			0x10
+#define	MAR			0x16
+#define	PRR			0x1F
+#define	TWPAL		0x20
+#define	TWPAH		0x21
+#define	TRPAL		0x22
+#define	TRPAH		0x23
+#define	RWPAL		0x24
+#define	RWPAH		0x25
+#define	RRPAL		0x26
+#define	RRPAH		0x27
+#define	VID			0x28
+#define	PID			0x2A
+#define	CHIPR		0x2C
+#define	USBDA		0xF0
+#define	RXC			0xF1
+#define	TXC_USBS	0xF2
+#define	USBC		0xF4
+
+/* Bit definition for registers */
+// Network Control Reg
+#define	NCR_RST			(1 << 0)
+#define	NCR_LBK			(3 << 1)
+#define	NCR_FDX			(1 << 3)
+#define	NCR_WAKEEN		(1 << 6)
+// Network Status Reg
+#define	NSR_RXRDY	(1 << 0)
+#define	NSR_RXOV	(1 << 1)
+#define	NSR_TX1END	(1 << 2)
+#define	NSR_TX2END	(1 << 3)
+#define	NSR_TXFULL	(1 << 4)
+#define	NSR_WAKEST	(1 << 5)
+#define	NSR_LINKST	(1 << 6)
+#define	NSR_SPEED	(1 << 7)
+// Tx Control Reg
+#define	TCR_CRC_DIS		(1 << 1)
+#define	TCR_PAD_DIS		(1 << 2)
+#define	TCR_LC_CARE		(1 << 3)
+#define	TCR_CRS_CARE	(1 << 4)
+#define	TCR_EXCECM		(1 << 5)
+#define	TCR_LF_EN		(1 << 6)
+// Tx Status Reg for Packet 1
+#define	TSR1_EC		(1 << 2)
+#define	TSR1_COL	(1 << 3)
+#define	TSR1_LC		(1 << 4)
+#define	TSR1_NC		(1 << 5)
+#define	TSR1_LOC		(1 << 6)
+#define	TSR1_TLF	(1 << 7)
+// Tx Status Reg for Packet 2
+#define	TSR2_EC		(1 << 2)
+#define	TSR2_COL	(1 << 3)
+#define	TSR2_LC		(1 << 4)
+#define	TSR2_NC		(1 << 5)
+#define	TSR2_LOC		(1 << 6)
+#define	TSR2_TLF	(1 << 7)
+// Rx Control Reg
+#define	RCR_RXEN		(1 << 0)
+#define	RCR_PRMSC		(1 << 1)
+#define	RCR_RUNT		(1 << 2)
+#define	RCR_ALL			(1 << 3)
+#define	RCR_DIS_CRC		(1 << 4)
+#define	RCR_DIS_LONG	(1 << 5)
+// Rx Status Reg
+#define	RSR_AE		(1 << 2)
+#define	RSR_MF		(1 << 6)
+#define	RSR_RF		(1 << 7)
+// Recv Overflow Counter Reg
+#define	ROCR_ROC		(0x7F << 0)
+#define	ROCR_RXFU		(1 << 7)
+// Back Pressure Threshold Reg
+#define	BPTR_JPT	(0x0F << 0)
+#define	BPTR_BPHW	(0x0F << 4)
+// Flow Control Threshold Reg
+#define	FCTR_LWOT		(0x0F << 0)
+#define	FCTR_HWOT		(0x0F << 4)
+// rx/tx Flow Control Reg
+#define	FCR_FLCE	(1 << 0)
+#define	FCR_BKPA	(1 << 4)
+#define	FCR_TXPEN	(1 << 5)
+#define	FCR_TXPF	(1 << 6)
+#define	FCR_TXP0	(1 << 7)
+// EEPROM & PHY Control Reg
+#define	EPCR_ERRE		(1 << 0)
+#define	EPCR_ERPRW		(1 << 1)
+#define	EPCR_ERPRR		(1 << 2)
+#define	EPCR_EPOS		(1 << 3)
+#define	EPCR_WEP		(1 << 4)
+// EEPROM & PHY Address Reg
+#define	EPAR_EROA		(0x3F << 0)
+#define	EPAR_PHY_ADR	(0x03 << 6)
+// Wakeup Control Reg
+#define	WCR_MAGICST		(1 << 0)
+#define	WCR_LINKST		(1 << 2)
+#define	WCR_MAGICEN		(1 << 3)
+#define	WCR_LINKEN		(1 << 5)
+// Phy Reset Reg
+#define	PRR_PHY_RST		(1 << 0)
+// USB Device Address Reg
+#define	USBDA_USBFA	(0x7F << 0)
+// TX packet Counter & USB Status Reg
+#define	TXC_USBS_TXC0	(1 << 0)
+#define	TXC_USBS_TXC1	(1 << 1)
+#define	TXC_USBS_TXC2	(1 << 2)
+#define	TXC_USBS_EP1RDY	(1 << 5)
+#define	TXC_USBS_SUSFLAG	(1 << 6)
+#define	TXC_USBS_RXFAULT	(1 << 7)
+// USB Control Reg
+#define	USBC_EP3NAK	(1 << 4)
+#define	USBC_EP3ACK	(1 << 5)
+
+/* Variables */
+#define	SR_RD_REGS		0x00
+#define	SR_WR_REGS		0x01
+#define	SR_WR_REG		0x03
+#define	SR_REQ_RD_REG	(USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
+#define	SR_REQ_WR_REG	(USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
+
+#define	SR_SHARE_TIMEOUT	1000
+#define	SR_EEPROM_LEN		256
+#define	SR_MCAST_SIZE		8
+#define	SR_MCAST_MAX		64
+#define	SR_TX_OVERHEAD		2	// 2bytes header
+#define	SR_RX_OVERHEAD		7	// 3bytes header + 4crc tail
+
+/*----------------------------------------------------------------------------------------------*/


--------------------------------------------------
2013-08-20 
liujunliang_ljl 
www.corechip-sz.com

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH-SR9700] Merge USB 1.1 Ethernet Adapter SR9700 Device Driver into the Linux Kernel
  2013-08-20 10:50 [PATCH-SR9700] Merge USB 1.1 Ethernet Adapter SR9700 Device Driver into the Linux Kernel liujunliang_ljl
@ 2013-08-20 13:36 ` Ben Hutchings
  2013-08-21 10:02 ` Re: [PATCH-SR9700] Merge USB 1.1 Ethernet Adapter SR9700 DeviceDriver " liujunliang_ljl
  1 sibling, 0 replies; 9+ messages in thread
From: Ben Hutchings @ 2013-08-20 13:36 UTC (permalink / raw)
  To: liujunliang_ljl; +Cc: gregkh, linux-usb, netdev, linux-kernel, sunhecheng

On Tue, 2013-08-20 at 18:50 +0800, liujunliang_ljl wrote:
> Dear Gregkh & all :
> 
> 		I am the software engineer Liu Junliang from ShenZhen CoreChips high technology company, on the market of SR9700 chip is designed and owned by us. 
>         SR9700 is a type of USB to Ethernet Converter and is compatible with USB 1.1 protocol, We want to merge SR9700 device driver into the Linux Kernel. The following is the Linux 3.10.7 version patch for SR9700, Please give us the assessment and support.
>         Thanks a lot.

As this is a net driver, the relevant maintainer is David Miller and not
Greg.

There are some style errors here which can be found using
scripts/checkpatch.pl.  You'll need to fix those and re-submit.  I'll
point out some more problems inline.

> --- /dev/null
> +++ b/drivers/net/usb/sr9700.c
[...]
> +static int sr9700_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, u8 * data)
> +{
> +	struct usbnet *dev = netdev_priv(net);
> +	__le16 *ebuf = (__le16 *) data;
> +	int i;
> +
> +	/* access is 16bit */
> +	if ((eeprom->offset % 2) || (eeprom->len % 2))
> +		return -EINVAL;

You're really supposed to handle these cases by shifting as necessary.

> +	for (i = 0; i < eeprom->len / 2; i++) {
> +		if (sr_read_eeprom_word(dev, eeprom->offset / 2 + i, &ebuf[i]) < 0)
> +			return -EINVAL;

You should pass up the error code, not substitute -EINVAL.

[...]
> +static void sr9700_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info)
> +{
> +	/* Inherit standard device info */
> +	usbnet_get_drvinfo(net, info);
> +	info->eedump_len = SR_EEPROM_LEN;

You don't need to set eedump_len; the ethtool core will set it after
calling sr9700_get_eeprom_len().  So you don't need your own
implementation of get_drvinfo at all.

[...]
> +static int sr9700_bind(struct usbnet *dev, struct usb_interface *intf)
> +{
[...]
> +	/* read MAC */
> +	if (sr_read(dev, PAR, ETH_ALEN, dev->net->dev_addr) < 0) {
> +		printk(KERN_ERR "Error reading MAC address\n");
> +		ret = -ENODEV;
> +		goto out;
> +	}
[...]

I think this should read the MAC address from EEPROM and copy it to both
dev_addr to perm_addr.  MAC address changes should not persist if the
driver is reloaded.

Ben.

-- 
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Re: [PATCH-SR9700] Merge USB 1.1 Ethernet Adapter SR9700 DeviceDriver into the Linux Kernel
  2013-08-20 10:50 [PATCH-SR9700] Merge USB 1.1 Ethernet Adapter SR9700 Device Driver into the Linux Kernel liujunliang_ljl
  2013-08-20 13:36 ` Ben Hutchings
@ 2013-08-21 10:02 ` liujunliang_ljl
  2013-08-22  8:45   ` Simon Horman
  1 sibling, 1 reply; 9+ messages in thread
From: liujunliang_ljl @ 2013-08-21 10:02 UTC (permalink / raw)
  To: Ben Hutchings; +Cc: gregkh, linux-usb, netdev, linux-kernel, sunhecheng

Dear Ben :

		1,  please give me email address of David Miller, and Thanks a lot.

		2,  please check the new sr9700 device driver which is checked by the script tools
			
				scripts/checkpatch.pl 
			and the attachment file is the result of scripts/checkpatch.pl patch-commit-20130821

			I'm sorry that I'm still finding the way to signed-off

		3, Thanks again for your correct suggestion and Please check the new device driver patch.
		
[PATCH] :  
  
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index 287cc62..a94b196 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -272,6 +272,14 @@ config USB_NET_DM9601
 	  This option adds support for Davicom DM9601 based USB 1.1
 	  10/100 Ethernet adapters.
 
+config USB_NET_SR9700
+	tristate "CoreChip-sz SR9700 based USB 1.1 10/100 ethernet devices"
+	depends on USB_USBNET
+	select CRC32
+	help
+	  This option adds support for CoreChip-sz SR9700 based USB 1.1
+	  10/100 Ethernet adapters.
+
 config USB_NET_SMSC75XX
 	tristate "SMSC LAN75XX based USB 2.0 gigabit ethernet devices"
 	depends on USB_USBNET
diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile
index 9ab5c9d..bba87a2 100644
--- a/drivers/net/usb/Makefile
+++ b/drivers/net/usb/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_USB_NET_AX88179_178A)      += ax88179_178a.o
 obj-$(CONFIG_USB_NET_CDCETHER)	+= cdc_ether.o
 obj-$(CONFIG_USB_NET_CDC_EEM)	+= cdc_eem.o
 obj-$(CONFIG_USB_NET_DM9601)	+= dm9601.o
+obj-$(CONFIG_USB_NET_SR9700)	+= sr9700.o
 obj-$(CONFIG_USB_NET_SMSC75XX)	+= smsc75xx.o
 obj-$(CONFIG_USB_NET_SMSC95XX)	+= smsc95xx.o
 obj-$(CONFIG_USB_NET_GL620A)	+= gl620a.o
diff --git a/drivers/net/usb/sr9700.c b/drivers/net/usb/sr9700.c
new file mode 100644
index 0000000..9c8f167
--- /dev/null
+++ b/drivers/net/usb/sr9700.c
@@ -0,0 +1,536 @@
+/*
+ * CoreChip-sz SR9700 one chip USB 1.1 Ethernet Devices
+ *
+ * Author : liujl <liujunliang_ljl@163.com>
+ *
+ * Based on dm9601.c
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/usb.h>
+#include <linux/crc32.h>
+#include <linux/usb/usbnet.h>
+
+#include "sr9700.h"
+
+static int sr_read(struct usbnet *dev, u8 reg, u16 length, void *data)
+{
+	int err;
+
+	err = usbnet_read_cmd(dev, SR_RD_REGS, SR_REQ_RD_REG,
+					0, reg, data, length);
+	if ((err != length) && (err >= 0))
+		err = -EINVAL;
+	return err;
+}
+
+static int sr_write(struct usbnet *dev, u8 reg, u16 length, void *data)
+{
+	int err;
+
+	err = usbnet_write_cmd(dev, SR_WR_REGS, SR_REQ_WR_REG,
+					0, reg, data, length);
+	if ((err >= 0) && (err < length))
+		err = -EINVAL;
+	return err;
+}
+
+static int sr_read_reg(struct usbnet *dev, u8 reg, u8 *value)
+{
+	return sr_read(dev, reg, 1, value);
+}
+
+static int sr_write_reg(struct usbnet *dev, u8 reg, u8 value)
+{
+	return usbnet_write_cmd(dev, SR_WR_REGS, SR_REQ_WR_REG,
+					value, reg, NULL, 0);
+}
+
+static void sr_write_async(struct usbnet *dev, u8 reg, u16 length, void *data)
+{
+	usbnet_write_cmd_async(dev, SR_WR_REGS, SR_REQ_WR_REG,
+					0, reg, data, length);
+}
+
+static void sr_write_reg_async(struct usbnet *dev, u8 reg, u8 value)
+{
+	usbnet_write_cmd_async(dev, SR_WR_REGS, SR_REQ_WR_REG,
+					value, reg, NULL, 0);
+}
+
+static int sr_share_read_word(struct usbnet *dev, int phy, u8 reg, __le16 *value)
+{
+	int ret, i;
+
+	mutex_lock(&dev->phy_mutex);
+
+	sr_write_reg(dev, EPAR, phy ? (reg | 0x40) : reg);
+	sr_write_reg(dev, EPCR, phy ? 0xc : 0x4);
+
+	for (i = 0; i < SR_SHARE_TIMEOUT; i++) {
+		u8 tmp = 0;
+
+		udelay(1);
+		ret = sr_read_reg(dev, EPCR, &tmp);
+		if (ret < 0)
+			goto out_unlock;
+
+		/* ready */
+		if ((tmp & EPCR_ERRE) == 0)
+			break;
+	}
+
+	if (i >= SR_SHARE_TIMEOUT) {
+		netdev_err(dev->net, "%s read timed out!\n", phy ? "phy" : "eeprom");
+		ret = -EIO;
+		goto out_unlock;
+	}
+
+	sr_write_reg(dev, EPCR, 0x0);
+	ret = sr_read(dev, EPDR, 2, value);
+
+	netdev_dbg(dev->net, "read shared %d 0x%02x returned 0x%04x, %d\n",
+	       phy, reg, *value, ret);
+
+ out_unlock:
+	mutex_unlock(&dev->phy_mutex);
+	return ret;
+}
+
+static int sr_share_write_word(struct usbnet *dev, int phy, u8 reg, __le16 value)
+{
+	int ret, i;
+
+	mutex_lock(&dev->phy_mutex);
+
+	ret = sr_write(dev, EPDR, 2, &value);
+	if (ret < 0)
+		goto out_unlock;
+
+	sr_write_reg(dev, EPAR, phy ? (reg | 0x40) : reg);
+	sr_write_reg(dev, EPCR, phy ? 0x1a : 0x12);
+
+	for (i = 0; i < SR_SHARE_TIMEOUT; i++) {
+		u8 tmp = 0;
+
+		udelay(1);
+		ret = sr_read_reg(dev, EPCR, &tmp);
+		if (ret < 0)
+			goto out_unlock;
+
+		/* ready */
+		if ((tmp & EPCR_ERRE) == 0)
+			break;
+	}
+
+	if (i >= SR_SHARE_TIMEOUT) {
+		netdev_err(dev->net, "%s write timed out!\n", phy ? "phy" : "eeprom");
+		ret = -EIO;
+		goto out_unlock;
+	}
+
+	sr_write_reg(dev, EPCR, 0x0);
+
+out_unlock:
+	mutex_unlock(&dev->phy_mutex);
+	return ret;
+}
+
+static int sr_read_eeprom_word(struct usbnet *dev, u8 offset, void *value)
+{
+	return sr_share_read_word(dev, 0, offset, value);
+}
+
+static int sr9700_get_eeprom_len(struct net_device *dev)
+{
+	return SR_EEPROM_LEN;
+}
+
+static int sr9700_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, u8 *data)
+{
+	struct usbnet *dev = netdev_priv(net);
+	__le16 *ebuf = (__le16 *) data;
+	int ret = 0;
+	int i;
+
+	/* access is 16bit */
+	if ((eeprom->offset % 2) || (eeprom->len % 2))
+		return -EINVAL;
+
+	for (i = 0; i < eeprom->len / 2; i++)
+			ret = sr_read_eeprom_word(dev, eeprom->offset / 2 + i, &ebuf[i]);
+
+	return ret;
+}
+
+static int sr_mdio_read(struct net_device *netdev, int phy_id, int loc)
+{
+	struct usbnet *dev = netdev_priv(netdev);
+	__le16 res;
+	int rc = 0;
+
+	if (phy_id) {
+		netdev_dbg(dev->net, "Only internal phy supported\n");
+		return 0;
+	}
+
+	/* Access NSR_LINKST bit for link status instead of MII_BMSR */
+	if (loc == MII_BMSR) {
+			u8 value;
+
+			sr_read_reg(dev, NSR, &value);
+			if (value & NSR_LINKST)
+					rc = 1;
+	}
+	sr_share_read_word(dev, 1, loc, &res);
+	if (rc == 1)
+			return le16_to_cpu(res) | BMSR_LSTATUS;
+	else
+			return le16_to_cpu(res) & ~BMSR_LSTATUS;
+
+	netdev_dbg(dev->net,
+	       "sr_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n",
+	       phy_id, loc, le16_to_cpu(res));
+
+	return le16_to_cpu(res);
+}
+
+static void sr_mdio_write(struct net_device *netdev, int phy_id, int loc, int val)
+{
+	struct usbnet *dev = netdev_priv(netdev);
+	__le16 res = cpu_to_le16(val);
+
+	if (phy_id) {
+		netdev_dbg(dev->net, "Only internal phy supported\n");
+		return;
+	}
+
+	netdev_dbg(dev->net, "sr_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n",
+	       phy_id, loc, val);
+
+	sr_share_write_word(dev, 1, loc, res);
+}
+
+static u32 sr9700_get_link(struct net_device *net)
+{
+	struct usbnet *dev = netdev_priv(net);
+	int rc = 0;
+	u8 value = 0;
+
+	/* Get the Link Status directly */
+	sr_read_reg(dev, NSR, &value);
+	if (value & NSR_LINKST)
+		rc = 1;
+
+	return rc;
+}
+
+static int sr9700_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
+{
+	struct usbnet *dev = netdev_priv(net);
+
+	return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
+}
+
+static const struct ethtool_ops sr9700_ethtool_ops = {
+	.get_drvinfo	= usbnet_get_drvinfo,
+	.get_link		= sr9700_get_link,
+	.get_msglevel	= usbnet_get_msglevel,
+	.set_msglevel	= usbnet_set_msglevel,
+	.get_eeprom_len	= sr9700_get_eeprom_len,
+	.get_eeprom		= sr9700_get_eeprom,
+	.get_settings	= usbnet_get_settings,
+	.set_settings	= usbnet_set_settings,
+	.nway_reset		= usbnet_nway_reset,
+};
+
+static void sr9700_set_multicast(struct net_device *net)
+{
+	struct usbnet *dev = netdev_priv(net);
+	/* We use the 20 byte dev->data for our 8 byte filter buffer
+	 * to avoid allocating memory that is tricky to free later
+	 */
+	u8 *hashes = (u8 *) &dev->data;
+	/* rx_ctl setting : enable, disable_long, disable_crc */
+	u8 rx_ctl = RCR_RXEN | RCR_DIS_CRC | RCR_DIS_LONG;
+
+	memset(hashes, 0x00, SR_MCAST_SIZE);
+	hashes[SR_MCAST_SIZE - 1] |= SR_MCAST_ADDR_FLAG;	/* broadcast address */
+
+	if (net->flags & IFF_PROMISC) {
+			rx_ctl |= RCR_PRMSC;
+	} else if (net->flags & IFF_ALLMULTI ||
+					netdev_mc_count(net) > SR_MCAST_MAX) {
+			rx_ctl |= RCR_RUNT;
+	} else if (!netdev_mc_empty(net)) {
+			struct netdev_hw_addr *ha;
+			netdev_for_each_mc_addr(ha, net) {
+					u32 crc = ether_crc(ETH_ALEN, ha->addr) >> 26;
+					hashes[crc >> 3] |= 1 << (crc & 0x7);
+			}
+	}
+
+	sr_write_async(dev, MAR, SR_MCAST_SIZE, hashes);
+	sr_write_reg_async(dev, RCR, rx_ctl);
+}
+
+static int sr9700_set_mac_address(struct net_device *net, void *p)
+{
+	struct sockaddr *addr = p;
+	struct usbnet *dev = netdev_priv(net);
+
+	if (!is_valid_ether_addr(addr->sa_data)) {
+		netdev_err(net, "not setting invalid mac address %pM\n",
+						addr->sa_data);
+		return -EINVAL;
+	}
+
+	memcpy(net->dev_addr, addr->sa_data, net->addr_len);
+	sr_write_async(dev, PAR, 6, dev->net->dev_addr);
+
+	return 0;
+}
+
+static const struct net_device_ops sr9700_netdev_ops = {
+	.ndo_open			= usbnet_open,
+	.ndo_stop			= usbnet_stop,
+	.ndo_start_xmit		= usbnet_start_xmit,
+	.ndo_tx_timeout		= usbnet_tx_timeout,
+	.ndo_change_mtu		= usbnet_change_mtu,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_do_ioctl		= sr9700_ioctl,
+	.ndo_set_rx_mode	= sr9700_set_multicast,
+	.ndo_set_mac_address	= sr9700_set_mac_address,
+};
+
+static int sr9700_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+	int ret;
+
+	ret = usbnet_get_endpoints(dev, intf);
+	if (ret)
+		goto out;
+
+	dev->net->netdev_ops = &sr9700_netdev_ops;
+	dev->net->ethtool_ops = &sr9700_ethtool_ops;
+	dev->net->hard_header_len += SR_TX_OVERHEAD;
+	dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
+	dev->rx_urb_size = 3072;	/* bulkin buffer is preferably not less than 3K */
+
+	dev->mii.dev = dev->net;
+	dev->mii.mdio_read = sr_mdio_read;
+	dev->mii.mdio_write = sr_mdio_write;
+	dev->mii.phy_id_mask = 0x1f;
+	dev->mii.reg_num_mask = 0x1f;
+
+	/* reset the sr9700 */
+	sr_write_reg(dev, NCR, 1);
+	udelay(20);
+
+	/* read MAC
+	 * After Chip Power on, the Chip will reload the MAC from EEPROM automatically to PAR
+	 * In case there is no EEPROM externally, a default MAC address is stored in PAR for making chip work properly
+	 */
+	if (sr_read(dev, PAR, ETH_ALEN, dev->net->dev_addr) < 0) {
+		netdev_err(dev->net, "Error reading MAC address\n");
+		ret = -ENODEV;
+		goto out;
+	}
+
+	/* power up and reset phy */
+	sr_write_reg(dev, PRR, 1);
+	mdelay(20);		/* at least 10ms, here 20ms for safe */
+	sr_write_reg(dev, PRR, 0);
+	udelay(2 * 1000);	/* at least 1ms, here 2ms for reading right register */
+
+	/* receive broadcast packets */
+	sr9700_set_multicast(dev->net);
+
+	sr_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
+	sr_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
+	mii_nway_restart(&dev->mii);
+
+out:
+	return ret;
+}
+
+static int sr9700_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+{
+	int len;
+	struct sk_buff *sr_skb;
+
+	/* format:
+	   b0: rx status
+	   b1: packet length (incl crc) low
+	   b2: packet length (incl crc) high
+	   b3..n-4: packet data
+	   bn-3..bn: ethernet crc
+	 */
+
+	if (unlikely(skb->len < SR_RX_OVERHEAD)) {
+		netdev_err(dev->net, "unexpected tiny rx frame\n");
+		return 0;
+	}
+
+	/* Each packet contains multiple skbs */
+	while (skb->len > SR_RX_OVERHEAD) {
+		if (skb->data[0] != 0x40)
+			return 0;
+
+		/* ignore the CRC length */
+		len = (skb->data[1] | (skb->data[2] << 8)) - 4;
+
+		if (len > ETH_FRAME_LEN)
+			return 0;
+
+		/* the last skb of current packet */
+		if (skb->len == (len + SR_RX_OVERHEAD))	{
+			skb_pull(skb, 3);
+			skb->len = len;
+			skb->tail = skb->data + len;
+			skb->truesize = len + sizeof(struct sk_buff);
+			return 2;
+		}
+
+		/* skb_clone is used for address align */
+		sr_skb = skb_clone(skb, GFP_ATOMIC);
+		if (sr_skb) {
+			sr_skb->len = len;
+			sr_skb->data = skb->data + 3;
+			sr_skb->tail = skb->data + len;
+			sr_skb->truesize = len + sizeof(struct sk_buff);
+			usbnet_skb_return(dev, sr_skb);
+		} else {
+			return 0;
+		}
+
+		skb_pull(skb, len + SR_RX_OVERHEAD);
+	};
+
+	return 0;
+}
+
+static struct sk_buff *sr9700_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
+{
+	int len;
+
+	/* format:
+	   b0: packet length low
+	   b1: packet length high
+	   b3..n: packet data
+	*/
+
+	len = skb->len;
+
+	if (skb_headroom(skb) < SR_TX_OVERHEAD) {
+		struct sk_buff *skb2;
+
+		skb2 = skb_copy_expand(skb, SR_TX_OVERHEAD, 0, flags);
+		dev_kfree_skb_any(skb);
+		skb = skb2;
+		if (!skb)
+			return NULL;
+	}
+
+	__skb_push(skb, SR_TX_OVERHEAD);
+
+	/* usbnet adds padding if length is a multiple of packet size
+	 * if so, adjust length value in header
+	 */
+	if ((skb->len % dev->maxpacket) == 0)
+		len++;
+
+	skb->data[0] = len;
+	skb->data[1] = len >> 8;
+
+	return skb;
+}
+
+static void sr9700_status(struct usbnet *dev, struct urb *urb)
+{
+	int link;
+	u8 *buf;
+
+	/* format:
+	   b0: net status
+	   b1: tx status 1
+	   b2: tx status 2
+	   b3: rx status
+	   b4: rx overflow
+	   b5: rx count
+	   b6: tx count
+	   b7: gpr
+	*/
+
+	if (urb->actual_length < 8)
+		return;
+
+	buf = urb->transfer_buffer;
+
+	link = !!(buf[0] & 0x40);
+	if (netif_carrier_ok(dev->net) != link) {
+		usbnet_link_change(dev, link, 1);
+		netdev_dbg(dev->net, "Link Status is: %d\n", link);
+	}
+}
+
+static int sr9700_link_reset(struct usbnet *dev)
+{
+	struct ethtool_cmd ecmd;
+
+	mii_check_media(&dev->mii, 1, 1);
+	mii_ethtool_gset(&dev->mii, &ecmd);
+
+	netdev_dbg(dev->net, "link_reset() speed: %d duplex: %d\n",
+	       ecmd.speed, ecmd.duplex);
+
+	return 0;
+}
+
+static const struct driver_info sr9700_driver_info = {
+	.description	= "CoreChip SR9700 USB Ethernet",
+	.flags		= FLAG_ETHER,
+	.bind		= sr9700_bind,
+	.rx_fixup	= sr9700_rx_fixup,
+	.tx_fixup	= sr9700_tx_fixup,
+	.status		= sr9700_status,
+	.link_reset	= sr9700_link_reset,
+	.reset		= sr9700_link_reset,
+};
+
+static const struct usb_device_id products[] = {
+	{
+	 USB_DEVICE(0x0fe6, 0x9700),	/* SR9700 device */
+	 .driver_info = (unsigned long)&sr9700_driver_info,
+	 },
+	{},			/* END */
+};
+
+MODULE_DEVICE_TABLE(usb, products);
+
+static struct usb_driver sr9700_usb_driver = {
+	.name = "sr9700",
+	.id_table = products,
+	.probe = usbnet_probe,
+	.disconnect = usbnet_disconnect,
+	.suspend = usbnet_suspend,
+	.resume = usbnet_resume,
+	.disable_hub_initiated_lpm = 1,
+};
+
+module_usb_driver(sr9700_usb_driver);
+
+MODULE_AUTHOR("liujl <liujunliang_ljl@163.com>");
+MODULE_DESCRIPTION("SR9700 one chip USB 1.1 USB to Ethernet device from http://www.corechip-sz.com/");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/usb/sr9700.h b/drivers/net/usb/sr9700.h
new file mode 100644
index 0000000..f1968ae
--- /dev/null
+++ b/drivers/net/usb/sr9700.h
@@ -0,0 +1,172 @@
+/*
+ * CoreChip-sz SR9700 one chip USB 1.1 Ethernet Devices
+ *
+ * Author : liujl <liujunliang_ljl@163.com>
+ *
+ * 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.
+ */
+
+#ifndef _SR9700_H
+#define	_SR9700_H
+
+/* sr9700 spec. register table on Linux platform */
+
+/* Network Control Reg */
+#define	NCR			0x00
+#define		NCR_RST			(1 << 0)
+#define		NCR_LBK			(3 << 1)
+#define		NCR_FDX			(1 << 3)
+#define		NCR_WAKEEN		(1 << 6)
+/* Network Status Reg */
+#define	NSR			0x01
+#define		NSR_RXRDY		(1 << 0)
+#define		NSR_RXOV		(1 << 1)
+#define		NSR_TX1END		(1 << 2)
+#define		NSR_TX2END		(1 << 3)
+#define		NSR_TXFULL		(1 << 4)
+#define		NSR_WAKEST		(1 << 5)
+#define		NSR_LINKST		(1 << 6)
+#define		NSR_SPEED		(1 << 7)
+/* Tx Control Reg */
+#define	TCR			0x02
+#define		TCR_CRC_DIS		(1 << 1)
+#define		TCR_PAD_DIS		(1 << 2)
+#define		TCR_LC_CARE		(1 << 3)
+#define		TCR_CRS_CARE	(1 << 4)
+#define		TCR_EXCECM		(1 << 5)
+#define		TCR_LF_EN		(1 << 6)
+/* Tx Status Reg for Packet Index 1 */
+#define	TSR1		0x03
+#define		TSR1_EC			(1 << 2)
+#define		TSR1_COL		(1 << 3)
+#define		TSR1_LC			(1 << 4)
+#define		TSR1_NC			(1 << 5)
+#define		TSR1_LOC		(1 << 6)
+#define		TSR1_TLF		(1 << 7)
+/* Tx Status Reg for Packet Index 2 */
+#define	TSR2		0x04
+#define		TSR2_EC			(1 << 2)
+#define		TSR2_COL		(1 << 3)
+#define		TSR2_LC			(1 << 4)
+#define		TSR2_NC			(1 << 5)
+#define		TSR2_LOC		(1 << 6)
+#define		TSR2_TLF		(1 << 7)
+/* Rx Control Reg*/
+#define	RCR			0x05
+#define		RCR_RXEN		(1 << 0)
+#define		RCR_PRMSC		(1 << 1)
+#define		RCR_RUNT		(1 << 2)
+#define		RCR_ALL			(1 << 3)
+#define		RCR_DIS_CRC		(1 << 4)
+#define		RCR_DIS_LONG	(1 << 5)
+/* Rx Status Reg */
+#define	RSR			0x06
+#define		RSR_AE			(1 << 2)
+#define		RSR_MF			(1 << 6)
+#define		RSR_RF			(1 << 7)
+/* Rx Overflow Counter Reg */
+#define	ROCR		0x07
+#define		ROCR_ROC		(0x7F << 0)
+#define		ROCR_RXFU		(1 << 7)
+/* Back Pressure Threshold Reg */
+#define	BPTR		0x08
+#define		BPTR_JPT		(0x0F << 0)
+#define		BPTR_BPHW		(0x0F << 4)
+/* Flow Control Threshold Reg */
+#define	FCTR		0x09
+#define		FCTR_LWOT		(0x0F << 0)
+#define		FCTR_HWOT		(0x0F << 4)
+/* rx/tx Flow Control Reg */
+#define	FCR			0x0A
+#define		FCR_FLCE		(1 << 0)
+#define		FCR_BKPA		(1 << 4)
+#define		FCR_TXPEN		(1 << 5)
+#define		FCR_TXPF		(1 << 6)
+#define		FCR_TXP0		(1 << 7)
+/* Eeprom & Phy Control Reg */
+#define	EPCR		0x0B
+#define		EPCR_ERRE		(1 << 0)
+#define		EPCR_ERPRW		(1 << 1)
+#define		EPCR_ERPRR		(1 << 2)
+#define		EPCR_EPOS		(1 << 3)
+#define		EPCR_WEP		(1 << 4)
+/* Eeprom & Phy Address Reg */
+#define	EPAR		0x0C
+#define		EPAR_EROA		(0x3F << 0)
+#define		EPAR_PHY_ADR	(0x03 << 6)
+/* Eeprom &	Phy Data Reg */
+#define	EPDR		0x0D	/* 0x0D ~ 0x0E for Data Reg Low & High */
+/* Wakeup Control Reg */
+#define	WCR			0x0F
+#define		WCR_MAGICST		(1 << 0)
+#define		WCR_LINKST		(1 << 2)
+#define		WCR_MAGICEN		(1 << 3)
+#define		WCR_LINKEN		(1 << 5)
+/* Physical Address Reg */
+#define	PAR			0x10	/* 0x10 ~ 0x15 6 bytes for PAR */
+/* Multicast Address Reg */
+#define	MAR			0x16	/* 0x16 ~ 0x1D 8 bytes for MAR */
+/* 0x1e unused */
+/* Phy Reset Reg */
+#define	PRR			0x1F
+#define		PRR_PHY_RST		(1 << 0)
+/* Tx sdram Write Pointer Address Low */
+#define	TWPAL		0x20
+/* Tx sdram Write Pointer Address High */
+#define	TWPAH		0x21
+/* Tx sdram Read Pointer Address Low */
+#define	TRPAL		0x22
+/* Tx sdram Read Pointer Address High */
+#define	TRPAH		0x23
+/* Rx sdram Write Pointer Address Low */
+#define	RWPAL		0x24
+/* Rx sdram Write Pointer Address High */
+#define	RWPAH		0x25
+/* Rx sdram Read Pointer Address Low */
+#define	RRPAL		0x26
+/* Rx sdram Read Pointer Address High */
+#define	RRPAH		0x27
+/* Vendor ID register */
+#define	VID			0x28	/* 0x28 ~ 0x29 2 bytes for VID */
+/* Product ID register */
+#define	PID			0x2A	/* 0x2A ~ 0x2B 2 bytes for PID */
+/* CHIP Revision register */
+#define	CHIPR		0x2C
+/* 0x2D --> 0xEF unused */
+/* USB Device Address */
+#define	USBDA		0xF0
+#define		USBDA_USBFA		(0x7F << 0)
+/* RX packet Counter Reg */
+#define	RXC			0xF1
+/* Tx packet Counter & USB Status Reg */
+#define	TXC_USBS	0xF2
+#define		TXC_USBS_TXC0		(1 << 0)
+#define		TXC_USBS_TXC1		(1 << 1)
+#define		TXC_USBS_TXC2		(1 << 2)
+#define		TXC_USBS_EP1RDY		(1 << 5)
+#define		TXC_USBS_SUSFLAG	(1 << 6)
+#define		TXC_USBS_RXFAULT	(1 << 7)
+/* USB Control register */
+#define	USBC		0xF4
+#define		USBC_EP3NAK		(1 << 4)
+#define		USBC_EP3ACK		(1 << 5)
+
+/* Register access commands and flags */
+#define	SR_RD_REGS		0x00
+#define	SR_WR_REGS		0x01
+#define	SR_WR_REG		0x03
+#define	SR_REQ_RD_REG	(USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
+#define	SR_REQ_WR_REG	(USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
+
+/* parameters */
+#define	SR_SHARE_TIMEOUT	1000
+#define	SR_EEPROM_LEN		256
+#define	SR_MCAST_SIZE		8
+#define	SR_MCAST_ADDR_FLAG	0x80
+#define	SR_MCAST_MAX		64
+#define	SR_TX_OVERHEAD		2	/* 2bytes header */
+#define	SR_RX_OVERHEAD		7	/* 3bytes header + 4crc tail */
+
+#endif	/* _SR9700_H */




2013-08-21 



liujunliang_ljl 



发件人: Ben Hutchings 
发送时间: 2013-08-20  21:36:50 
收件人: liujunliang_ljl 
抄送: gregkh; linux-usb; netdev; linux-kernel; sunhecheng 
主题: Re: [PATCH-SR9700] Merge USB 1.1 Ethernet Adapter SR9700 DeviceDriver into the Linux Kernel 
 
On Tue, 2013-08-20 at 18:50 +0800, liujunliang_ljl wrote:
> Dear Gregkh & all :
> 
>  I am the software engineer Liu Junliang from ShenZhen CoreChips high technology company, on the market of SR9700 chip is designed and owned by us. 
>         SR9700 is a type of USB to Ethernet Converter and is compatible with USB 1.1 protocol, We want to merge SR9700 device driver into the Linux Kernel. The following is the Linux 3.10.7 version patch for SR9700, Please give us the assessment and support.
>         Thanks a lot.
As this is a net driver, the relevant maintainer is David Miller and not
Greg.
There are some style errors here which can be found using
scripts/checkpatch.pl.  You'll need to fix those and re-submit.  I'll
point out some more problems inline.
> --- /dev/null
> +++ b/drivers/net/usb/sr9700.c
[...]
> +static int sr9700_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, u8 * data)
> +{
> + struct usbnet *dev = netdev_priv(net);
> + __le16 *ebuf = (__le16 *) data;
> + int i;
> +
> + /* access is 16bit */
> + if ((eeprom->offset % 2) || (eeprom->len % 2))
> + return -EINVAL;
You're really supposed to handle these cases by shifting as necessary.
> + for (i = 0; i < eeprom->len / 2; i++) {
> + if (sr_read_eeprom_word(dev, eeprom->offset / 2 + i, &ebuf[i]) < 0)
> + return -EINVAL;
You should pass up the error code, not substitute -EINVAL.
[...]
> +static void sr9700_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info)
> +{
> + /* Inherit standard device info */
> + usbnet_get_drvinfo(net, info);
> + info->eedump_len = SR_EEPROM_LEN;
You don't need to set eedump_len; the ethtool core will set it after
calling sr9700_get_eeprom_len().  So you don't need your own
implementation of get_drvinfo at all.
[...]
> +static int sr9700_bind(struct usbnet *dev, struct usb_interface *intf)
> +{
[...]
> + /* read MAC */
> + if (sr_read(dev, PAR, ETH_ALEN, dev->net->dev_addr) < 0) {
> + printk(KERN_ERR "Error reading MAC address\n");
> + ret = -ENODEV;
> + goto out;
> + }
[...]
I think this should read the MAC address from EEPROM and copy it to both
dev_addr to perm_addr.  MAC address changes should not persist if the
driver is reloaded.
Ben.
-- 
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: Re: [PATCH-SR9700] Merge USB 1.1 Ethernet Adapter SR9700 DeviceDriver into the Linux Kernel
  2013-08-21 10:02 ` Re: [PATCH-SR9700] Merge USB 1.1 Ethernet Adapter SR9700 DeviceDriver " liujunliang_ljl
@ 2013-08-22  8:45   ` Simon Horman
  0 siblings, 0 replies; 9+ messages in thread
From: Simon Horman @ 2013-08-22  8:45 UTC (permalink / raw)
  To: liujunliang_ljl
  Cc: Ben Hutchings, gregkh, linux-usb, netdev, linux-kernel, sunhecheng

On Wed, Aug 21, 2013 at 06:02:45PM +0800, liujunliang_ljl wrote:
> Dear Ben :
> 
> 		1,  please give me email address of David Miller, and Thanks a lot.

You can find him in the MAINTAINERS file.
He should also show up if you use scripts/get_maintainer.pl

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Re: [PATCH-SR9700] Merge USB 1.1 Ethernet Adapter SR9700 DeviceDriver into the Linux Kernel
  2013-08-21 10:06   ` liujunliang_ljl
  2013-08-21 16:20     ` Greg KH
@ 2013-08-21 20:33     ` Francois Romieu
  1 sibling, 0 replies; 9+ messages in thread
From: Francois Romieu @ 2013-08-21 20:33 UTC (permalink / raw)
  To: liujunliang_ljl; +Cc: gregkh, sunhecheng, linux-usb, netdev, linux-kernel

liujunliang_ljl <liujunliang_ljl@163.com> :
[...]
> diff --git a/drivers/net/usb/sr9700.c b/drivers/net/usb/sr9700.c
> new file mode 100644
> index 0000000..9c8f167
> --- /dev/null
> +++ b/drivers/net/usb/sr9700.c
[...]
> +static int sr_read(struct usbnet *dev, u8 reg, u16 length, void *data)
> +{
> +	int err;
> +
> +	err = usbnet_read_cmd(dev, SR_RD_REGS, SR_REQ_RD_REG,
> +					0, reg, data, length);

	err = usbnet_read_cmd(dev, SR_RD_REGS, SR_REQ_RD_REG, 0, reg, data,
			      length);

(I already outlined it in my first review)

> +	if ((err != length) && (err >= 0))
> +		err = -EINVAL;
> +	return err;
> +}
> +
> +static int sr_write(struct usbnet *dev, u8 reg, u16 length, void *data)
> +{
> +	int err;
> +
> +	err = usbnet_write_cmd(dev, SR_WR_REGS, SR_REQ_WR_REG,
> +					0, reg, data, length);

See my first review as well.

> +	if ((err >= 0) && (err < length))
> +		err = -EINVAL;
> +	return err;
> +}
> +
> +static int sr_read_reg(struct usbnet *dev, u8 reg, u8 *value)
> +{
> +	return sr_read(dev, reg, 1, value);
> +}
> +
> +static int sr_write_reg(struct usbnet *dev, u8 reg, u8 value)
> +{
> +	return usbnet_write_cmd(dev, SR_WR_REGS, SR_REQ_WR_REG,
> +					value, reg, NULL, 0);

See my first review as well.

> +}
> +
> +static void sr_write_async(struct usbnet *dev, u8 reg, u16 length, void *data)
> +{
> +	usbnet_write_cmd_async(dev, SR_WR_REGS, SR_REQ_WR_REG,
> +					0, reg, data, length);

See my first review as well.

> +}
> +
> +static void sr_write_reg_async(struct usbnet *dev, u8 reg, u8 value)
> +{
> +	usbnet_write_cmd_async(dev, SR_WR_REGS, SR_REQ_WR_REG,
> +					value, reg, NULL, 0);

See my first review as well.

> +}
> +
> +static int sr_share_read_word(struct usbnet *dev, int phy, u8 reg, __le16 *value)
> +{
> +	int ret, i;
> +
> +	mutex_lock(&dev->phy_mutex);
> +
> +	sr_write_reg(dev, EPAR, phy ? (reg | 0x40) : reg);
> +	sr_write_reg(dev, EPCR, phy ? 0xc : 0x4);
> +
> +	for (i = 0; i < SR_SHARE_TIMEOUT; i++) {
> +		u8 tmp = 0;
> +
> +		udelay(1);
> +		ret = sr_read_reg(dev, EPCR, &tmp);
> +		if (ret < 0)
> +			goto out_unlock;
> +
> +		/* ready */
> +		if ((tmp & EPCR_ERRE) == 0)
> +			break;
> +	}
> +
> +	if (i >= SR_SHARE_TIMEOUT) {
> +		netdev_err(dev->net, "%s read timed out!\n", phy ? "phy" : "eeprom");
> +		ret = -EIO;
> +		goto out_unlock;
> +	}
> +
> +	sr_write_reg(dev, EPCR, 0x0);
> +	ret = sr_read(dev, EPDR, 2, value);
> +
> +	netdev_dbg(dev->net, "read shared %d 0x%02x returned 0x%04x, %d\n",
> +	       phy, reg, *value, ret);
> +
> + out_unlock:
   ^ please remove space.

(you renamed it but the "no space before label" part has been ignored)

> +	mutex_unlock(&dev->phy_mutex);
> +	return ret;
> +}
> +
> +static int sr_share_write_word(struct usbnet *dev, int phy, u8 reg, __le16 value)
> +{
> +	int ret, i;
> +
> +	mutex_lock(&dev->phy_mutex);
> +
> +	ret = sr_write(dev, EPDR, 2, &value);
> +	if (ret < 0)
> +		goto out_unlock;
> +
> +	sr_write_reg(dev, EPAR, phy ? (reg | 0x40) : reg);
> +	sr_write_reg(dev, EPCR, phy ? 0x1a : 0x12);
> +
> +	for (i = 0; i < SR_SHARE_TIMEOUT; i++) {
> +		u8 tmp = 0;
> +
> +		udelay(1);
> +		ret = sr_read_reg(dev, EPCR, &tmp);
> +		if (ret < 0)
> +			goto out_unlock;
> +
> +		/* ready */
> +		if ((tmp & EPCR_ERRE) == 0)
> +			break;
> +	}

I made a remark about the 11 lines above in my first review. May I politely
ask you to read it again ?

[...]
> +static const struct ethtool_ops sr9700_ethtool_ops = {
> +	.get_drvinfo	= usbnet_get_drvinfo,
> +	.get_link		= sr9700_get_link,
> +	.get_msglevel	= usbnet_get_msglevel,
> +	.set_msglevel	= usbnet_set_msglevel,
> +	.get_eeprom_len	= sr9700_get_eeprom_len,
> +	.get_eeprom		= sr9700_get_eeprom,
> +	.get_settings	= usbnet_get_settings,
> +	.set_settings	= usbnet_set_settings,
> +	.nway_reset		= usbnet_nway_reset,

The fields above line up nicely with a 4 spaces tabulation but the
standard kernel one is 8 spaces wide.

[...]
> +static const struct net_device_ops sr9700_netdev_ops = {
> +	.ndo_open			= usbnet_open,
> +	.ndo_stop			= usbnet_stop,
> +	.ndo_start_xmit		= usbnet_start_xmit,
> +	.ndo_tx_timeout		= usbnet_tx_timeout,
> +	.ndo_change_mtu		= usbnet_change_mtu,
> +	.ndo_validate_addr	= eth_validate_addr,
> +	.ndo_do_ioctl		= sr9700_ioctl,
> +	.ndo_set_rx_mode	= sr9700_set_multicast,
> +	.ndo_set_mac_address	= sr9700_set_mac_address,

Same 4 vs 8 spaces tabs problem as above.

[...]
> +static int sr9700_bind(struct usbnet *dev, struct usb_interface *intf)
> +{
> +	int ret;
> +
> +	ret = usbnet_get_endpoints(dev, intf);
> +	if (ret)
> +		goto out;
> +
> +	dev->net->netdev_ops = &sr9700_netdev_ops;
> +	dev->net->ethtool_ops = &sr9700_ethtool_ops;
> +	dev->net->hard_header_len += SR_TX_OVERHEAD;
> +	dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
> +	dev->rx_urb_size = 3072;	/* bulkin buffer is preferably not less than 3K */
> +
> +	dev->mii.dev = dev->net;
> +	dev->mii.mdio_read = sr_mdio_read;
> +	dev->mii.mdio_write = sr_mdio_write;
> +	dev->mii.phy_id_mask = 0x1f;
> +	dev->mii.reg_num_mask = 0x1f;

Please add local dev->net and dev->mii variables.

[...]
> +	/* power up and reset phy */
> +	sr_write_reg(dev, PRR, 1);

Please replace '1' with appropriate #define.

> +	mdelay(20);		/* at least 10ms, here 20ms for safe */
> +	sr_write_reg(dev, PRR, 0);

Please replace '0' with appropriate #define.

[...]
> +static int sr9700_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
> +{
> +	int len;
> +	struct sk_buff *sr_skb;

	struct sk_buff *sr_skb;
	int len;

(long lines first)

[...]
> +	/* Each packet contains multiple skbs */
> +	while (skb->len > SR_RX_OVERHEAD) {
> +		if (skb->data[0] != 0x40)
> +			return 0;
> +
> +		/* ignore the CRC length */
> +		len = (skb->data[1] | (skb->data[2] << 8)) - 4;
> +
> +		if (len > ETH_FRAME_LEN)
> +			return 0;
> +
> +		/* the last skb of current packet */
> +		if (skb->len == (len + SR_RX_OVERHEAD))	{
> +			skb_pull(skb, 3);
> +			skb->len = len;
> +			skb->tail = skb->data + len;
> +			skb->truesize = len + sizeof(struct sk_buff);
> +			return 2;
> +		}
> +
> +		/* skb_clone is used for address align */
> +		sr_skb = skb_clone(skb, GFP_ATOMIC);
> +		if (sr_skb) {

		if (!sr_skb)
			return 0;

> +			sr_skb->len = len;
> +			sr_skb->data = skb->data + 3;
> +			sr_skb->tail = skb->data + len;
> +			sr_skb->truesize = len + sizeof(struct sk_buff);
> +			usbnet_skb_return(dev, sr_skb);
> +		} else {
> +			return 0;
> +		}
> +
> +		skb_pull(skb, len + SR_RX_OVERHEAD);
> +	};
> +
> +	return 0;
> +}
[...]
> +static struct usb_driver sr9700_usb_driver = {
> +	.name = "sr9700",
> +	.id_table = products,
> +	.probe = usbnet_probe,
> +	.disconnect = usbnet_disconnect,
> +	.suspend = usbnet_suspend,
> +	.resume = usbnet_resume,
> +	.disable_hub_initiated_lpm = 1,
> +};

Please line things up (see my first review).

[...]
> ???????? Francois Romieu 
> ?????????? 2013-08-21  04:46:12 
> ???????? liujunliang_ljl 
> ?????? gregkh; sunhecheng; linux-usb; netdev; linux-kernel 
> ?????? Re: [PATCH-SR9700] Merge USB 1.1 Ethernet Adapter SR9700 DeviceDriver into the Linux Kernel 

Please avoid full quote and top posting.

-- 
Ueimor

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Re: [PATCH-SR9700] Merge USB 1.1 Ethernet Adapter SR9700 DeviceDriver into the Linux Kernel
  2013-08-21 10:06   ` liujunliang_ljl
@ 2013-08-21 16:20     ` Greg KH
  2013-08-21 20:33     ` Francois Romieu
  1 sibling, 0 replies; 9+ messages in thread
From: Greg KH @ 2013-08-21 16:20 UTC (permalink / raw)
  To: liujunliang_ljl
  Cc: Francois Romieu, sunhecheng, linux-usb, netdev, linux-kernel

On Wed, Aug 21, 2013 at 06:06:02PM +0800, liujunliang_ljl wrote:
> Dear Francois Romieu :
> 
> 	1, all the format problems have been fixed
> 	
> 	2, sr9700.h registers definition is re-written
> 
> 	3, Thanks for your detail checking and I have beed scripts/checkpatch.pl the patch and please check it.
> 
> [PATCH] :

You still aren't sending the patch in a format in which we can apply it
in.  Please read the file, Documentation/SubmittingPatches, specifically
the part about the "Signed-off-by:" line, and provding a proper body of
the patch for the changelog.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Re: [PATCH-SR9700] Merge USB 1.1 Ethernet Adapter SR9700 DeviceDriver into the Linux Kernel
  2013-08-21 10:07     ` Re: [PATCH-SR9700] Merge USB 1.1 Ethernet Adapter SR9700 DeviceDriver " liujunliang_ljl
@ 2013-08-21 11:34       ` Joe Perches
  0 siblings, 0 replies; 9+ messages in thread
From: Joe Perches @ 2013-08-21 11:34 UTC (permalink / raw)
  To: liujunliang_ljl
  Cc: Francois Romieu, gregkh, sunhecheng, linux-usb, netdev, linux-kernel

On Wed, 2013-08-21 at 18:07 +0800, liujunliang_ljl wrote:
> 		Thanks a lot and I have been fixed all the problems mentioned above. please check the following patch and thanks again. 

Just trivial comments below:

> diff --git a/drivers/net/usb/sr9700.c b/drivers/net/usb/sr9700.c
[]
> +static void sr_write_reg_async(struct usbnet *dev, u8 reg, u8 value)
> +{
> +	usbnet_write_cmd_async(dev, SR_WR_REGS, SR_REQ_WR_REG,
> +					value, reg, NULL, 0);
> +}
> +
> +static int sr_share_read_word(struct usbnet *dev, int phy, u8 reg, __le16 *value)
> +{
[]
> +	netdev_dbg(dev->net, "read shared %d 0x%02x returned 0x%04x, %d\n",
> +	       phy, reg, *value, ret);

You have a lot of code that uses inconsistent
indentation.  Code in drivers/net and drivers/usb/net
generally prefers to use alignment to parenthesis for
multi-line statements

The first could use

	usbnet_write_cmd_async(dev, SR_WR_REGS, SR_REQ_WR_REG,
			       value, reg, NULL, 0);

and the second

	netdev_dbg(dev->net, "read shared %d 0x%02x returned 0x%04x, %d\n",
		   phy, reg, *value, ret);

Maximal use of 8 space indentation tabs followed by
minimal spaces.

There are many of these above.

> +static int sr9700_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, u8 *data)
[]
> +	for (i = 0; i < eeprom->len / 2; i++)
> +			ret = sr_read_eeprom_word(dev, eeprom->offset / 2 + i, &ebuf[i]);

One too many tabs for the second line, a few of these...

[]

> +static int sr_mdio_read(struct net_device *netdev, int phy_id, int loc)
[]
> +	if (rc == 1)
> +			return le16_to_cpu(res) | BMSR_LSTATUS;
> +	else
> +			return le16_to_cpu(res) & ~BMSR_LSTATUS;

The code below the returns here is unreachable.

> +
> +	netdev_dbg(dev->net,
> +	       "sr_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n",
> +	       phy_id, loc, le16_to_cpu(res));
> +
> +	return le16_to_cpu(res);
> +}

You might try to use scripts/checkpatch.pl --strict if you
care about these.  It should flag most of these coding
style inconsistencies.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Re: [PATCH-SR9700] Merge USB 1.1 Ethernet Adapter SR9700 DeviceDriver into the Linux Kernel
  2013-08-20 20:58   ` Joe Perches
@ 2013-08-21 10:07     ` liujunliang_ljl
  2013-08-21 11:34       ` Joe Perches
  0 siblings, 1 reply; 9+ messages in thread
From: liujunliang_ljl @ 2013-08-21 10:07 UTC (permalink / raw)
  To: Joe Perches, Francois Romieu
  Cc: gregkh, sunhecheng, linux-usb, netdev, linux-kernel

Dear Joe :

		Thanks a lot and I have been fixed all the problems mentioned above. please check the following patch and thanks again. 

[PATCH] :
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index 287cc62..a94b196 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -272,6 +272,14 @@ config USB_NET_DM9601
 	  This option adds support for Davicom DM9601 based USB 1.1
 	  10/100 Ethernet adapters.
 
+config USB_NET_SR9700
+	tristate "CoreChip-sz SR9700 based USB 1.1 10/100 ethernet devices"
+	depends on USB_USBNET
+	select CRC32
+	help
+	  This option adds support for CoreChip-sz SR9700 based USB 1.1
+	  10/100 Ethernet adapters.
+
 config USB_NET_SMSC75XX
 	tristate "SMSC LAN75XX based USB 2.0 gigabit ethernet devices"
 	depends on USB_USBNET
diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile
index 9ab5c9d..bba87a2 100644
--- a/drivers/net/usb/Makefile
+++ b/drivers/net/usb/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_USB_NET_AX88179_178A)      += ax88179_178a.o
 obj-$(CONFIG_USB_NET_CDCETHER)	+= cdc_ether.o
 obj-$(CONFIG_USB_NET_CDC_EEM)	+= cdc_eem.o
 obj-$(CONFIG_USB_NET_DM9601)	+= dm9601.o
+obj-$(CONFIG_USB_NET_SR9700)	+= sr9700.o
 obj-$(CONFIG_USB_NET_SMSC75XX)	+= smsc75xx.o
 obj-$(CONFIG_USB_NET_SMSC95XX)	+= smsc95xx.o
 obj-$(CONFIG_USB_NET_GL620A)	+= gl620a.o
diff --git a/drivers/net/usb/sr9700.c b/drivers/net/usb/sr9700.c
new file mode 100644
index 0000000..9c8f167
--- /dev/null
+++ b/drivers/net/usb/sr9700.c
@@ -0,0 +1,536 @@
+/*
+ * CoreChip-sz SR9700 one chip USB 1.1 Ethernet Devices
+ *
+ * Author : liujl <liujunliang_ljl@163.com>
+ *
+ * Based on dm9601.c
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/usb.h>
+#include <linux/crc32.h>
+#include <linux/usb/usbnet.h>
+
+#include "sr9700.h"
+
+static int sr_read(struct usbnet *dev, u8 reg, u16 length, void *data)
+{
+	int err;
+
+	err = usbnet_read_cmd(dev, SR_RD_REGS, SR_REQ_RD_REG,
+					0, reg, data, length);
+	if ((err != length) && (err >= 0))
+		err = -EINVAL;
+	return err;
+}
+
+static int sr_write(struct usbnet *dev, u8 reg, u16 length, void *data)
+{
+	int err;
+
+	err = usbnet_write_cmd(dev, SR_WR_REGS, SR_REQ_WR_REG,
+					0, reg, data, length);
+	if ((err >= 0) && (err < length))
+		err = -EINVAL;
+	return err;
+}
+
+static int sr_read_reg(struct usbnet *dev, u8 reg, u8 *value)
+{
+	return sr_read(dev, reg, 1, value);
+}
+
+static int sr_write_reg(struct usbnet *dev, u8 reg, u8 value)
+{
+	return usbnet_write_cmd(dev, SR_WR_REGS, SR_REQ_WR_REG,
+					value, reg, NULL, 0);
+}
+
+static void sr_write_async(struct usbnet *dev, u8 reg, u16 length, void *data)
+{
+	usbnet_write_cmd_async(dev, SR_WR_REGS, SR_REQ_WR_REG,
+					0, reg, data, length);
+}
+
+static void sr_write_reg_async(struct usbnet *dev, u8 reg, u8 value)
+{
+	usbnet_write_cmd_async(dev, SR_WR_REGS, SR_REQ_WR_REG,
+					value, reg, NULL, 0);
+}
+
+static int sr_share_read_word(struct usbnet *dev, int phy, u8 reg, __le16 *value)
+{
+	int ret, i;
+
+	mutex_lock(&dev->phy_mutex);
+
+	sr_write_reg(dev, EPAR, phy ? (reg | 0x40) : reg);
+	sr_write_reg(dev, EPCR, phy ? 0xc : 0x4);
+
+	for (i = 0; i < SR_SHARE_TIMEOUT; i++) {
+		u8 tmp = 0;
+
+		udelay(1);
+		ret = sr_read_reg(dev, EPCR, &tmp);
+		if (ret < 0)
+			goto out_unlock;
+
+		/* ready */
+		if ((tmp & EPCR_ERRE) == 0)
+			break;
+	}
+
+	if (i >= SR_SHARE_TIMEOUT) {
+		netdev_err(dev->net, "%s read timed out!\n", phy ? "phy" : "eeprom");
+		ret = -EIO;
+		goto out_unlock;
+	}
+
+	sr_write_reg(dev, EPCR, 0x0);
+	ret = sr_read(dev, EPDR, 2, value);
+
+	netdev_dbg(dev->net, "read shared %d 0x%02x returned 0x%04x, %d\n",
+	       phy, reg, *value, ret);
+
+ out_unlock:
+	mutex_unlock(&dev->phy_mutex);
+	return ret;
+}
+
+static int sr_share_write_word(struct usbnet *dev, int phy, u8 reg, __le16 value)
+{
+	int ret, i;
+
+	mutex_lock(&dev->phy_mutex);
+
+	ret = sr_write(dev, EPDR, 2, &value);
+	if (ret < 0)
+		goto out_unlock;
+
+	sr_write_reg(dev, EPAR, phy ? (reg | 0x40) : reg);
+	sr_write_reg(dev, EPCR, phy ? 0x1a : 0x12);
+
+	for (i = 0; i < SR_SHARE_TIMEOUT; i++) {
+		u8 tmp = 0;
+
+		udelay(1);
+		ret = sr_read_reg(dev, EPCR, &tmp);
+		if (ret < 0)
+			goto out_unlock;
+
+		/* ready */
+		if ((tmp & EPCR_ERRE) == 0)
+			break;
+	}
+
+	if (i >= SR_SHARE_TIMEOUT) {
+		netdev_err(dev->net, "%s write timed out!\n", phy ? "phy" : "eeprom");
+		ret = -EIO;
+		goto out_unlock;
+	}
+
+	sr_write_reg(dev, EPCR, 0x0);
+
+out_unlock:
+	mutex_unlock(&dev->phy_mutex);
+	return ret;
+}
+
+static int sr_read_eeprom_word(struct usbnet *dev, u8 offset, void *value)
+{
+	return sr_share_read_word(dev, 0, offset, value);
+}
+
+static int sr9700_get_eeprom_len(struct net_device *dev)
+{
+	return SR_EEPROM_LEN;
+}
+
+static int sr9700_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, u8 *data)
+{
+	struct usbnet *dev = netdev_priv(net);
+	__le16 *ebuf = (__le16 *) data;
+	int ret = 0;
+	int i;
+
+	/* access is 16bit */
+	if ((eeprom->offset % 2) || (eeprom->len % 2))
+		return -EINVAL;
+
+	for (i = 0; i < eeprom->len / 2; i++)
+			ret = sr_read_eeprom_word(dev, eeprom->offset / 2 + i, &ebuf[i]);
+
+	return ret;
+}
+
+static int sr_mdio_read(struct net_device *netdev, int phy_id, int loc)
+{
+	struct usbnet *dev = netdev_priv(netdev);
+	__le16 res;
+	int rc = 0;
+
+	if (phy_id) {
+		netdev_dbg(dev->net, "Only internal phy supported\n");
+		return 0;
+	}
+
+	/* Access NSR_LINKST bit for link status instead of MII_BMSR */
+	if (loc == MII_BMSR) {
+			u8 value;
+
+			sr_read_reg(dev, NSR, &value);
+			if (value & NSR_LINKST)
+					rc = 1;
+	}
+	sr_share_read_word(dev, 1, loc, &res);
+	if (rc == 1)
+			return le16_to_cpu(res) | BMSR_LSTATUS;
+	else
+			return le16_to_cpu(res) & ~BMSR_LSTATUS;
+
+	netdev_dbg(dev->net,
+	       "sr_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n",
+	       phy_id, loc, le16_to_cpu(res));
+
+	return le16_to_cpu(res);
+}
+
+static void sr_mdio_write(struct net_device *netdev, int phy_id, int loc, int val)
+{
+	struct usbnet *dev = netdev_priv(netdev);
+	__le16 res = cpu_to_le16(val);
+
+	if (phy_id) {
+		netdev_dbg(dev->net, "Only internal phy supported\n");
+		return;
+	}
+
+	netdev_dbg(dev->net, "sr_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n",
+	       phy_id, loc, val);
+
+	sr_share_write_word(dev, 1, loc, res);
+}
+
+static u32 sr9700_get_link(struct net_device *net)
+{
+	struct usbnet *dev = netdev_priv(net);
+	int rc = 0;
+	u8 value = 0;
+
+	/* Get the Link Status directly */
+	sr_read_reg(dev, NSR, &value);
+	if (value & NSR_LINKST)
+		rc = 1;
+
+	return rc;
+}
+
+static int sr9700_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
+{
+	struct usbnet *dev = netdev_priv(net);
+
+	return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
+}
+
+static const struct ethtool_ops sr9700_ethtool_ops = {
+	.get_drvinfo	= usbnet_get_drvinfo,
+	.get_link		= sr9700_get_link,
+	.get_msglevel	= usbnet_get_msglevel,
+	.set_msglevel	= usbnet_set_msglevel,
+	.get_eeprom_len	= sr9700_get_eeprom_len,
+	.get_eeprom		= sr9700_get_eeprom,
+	.get_settings	= usbnet_get_settings,
+	.set_settings	= usbnet_set_settings,
+	.nway_reset		= usbnet_nway_reset,
+};
+
+static void sr9700_set_multicast(struct net_device *net)
+{
+	struct usbnet *dev = netdev_priv(net);
+	/* We use the 20 byte dev->data for our 8 byte filter buffer
+	 * to avoid allocating memory that is tricky to free later
+	 */
+	u8 *hashes = (u8 *) &dev->data;
+	/* rx_ctl setting : enable, disable_long, disable_crc */
+	u8 rx_ctl = RCR_RXEN | RCR_DIS_CRC | RCR_DIS_LONG;
+
+	memset(hashes, 0x00, SR_MCAST_SIZE);
+	hashes[SR_MCAST_SIZE - 1] |= SR_MCAST_ADDR_FLAG;	/* broadcast address */
+
+	if (net->flags & IFF_PROMISC) {
+			rx_ctl |= RCR_PRMSC;
+	} else if (net->flags & IFF_ALLMULTI ||
+					netdev_mc_count(net) > SR_MCAST_MAX) {
+			rx_ctl |= RCR_RUNT;
+	} else if (!netdev_mc_empty(net)) {
+			struct netdev_hw_addr *ha;
+			netdev_for_each_mc_addr(ha, net) {
+					u32 crc = ether_crc(ETH_ALEN, ha->addr) >> 26;
+					hashes[crc >> 3] |= 1 << (crc & 0x7);
+			}
+	}
+
+	sr_write_async(dev, MAR, SR_MCAST_SIZE, hashes);
+	sr_write_reg_async(dev, RCR, rx_ctl);
+}
+
+static int sr9700_set_mac_address(struct net_device *net, void *p)
+{
+	struct sockaddr *addr = p;
+	struct usbnet *dev = netdev_priv(net);
+
+	if (!is_valid_ether_addr(addr->sa_data)) {
+		netdev_err(net, "not setting invalid mac address %pM\n",
+						addr->sa_data);
+		return -EINVAL;
+	}
+
+	memcpy(net->dev_addr, addr->sa_data, net->addr_len);
+	sr_write_async(dev, PAR, 6, dev->net->dev_addr);
+
+	return 0;
+}
+
+static const struct net_device_ops sr9700_netdev_ops = {
+	.ndo_open			= usbnet_open,
+	.ndo_stop			= usbnet_stop,
+	.ndo_start_xmit		= usbnet_start_xmit,
+	.ndo_tx_timeout		= usbnet_tx_timeout,
+	.ndo_change_mtu		= usbnet_change_mtu,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_do_ioctl		= sr9700_ioctl,
+	.ndo_set_rx_mode	= sr9700_set_multicast,
+	.ndo_set_mac_address	= sr9700_set_mac_address,
+};
+
+static int sr9700_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+	int ret;
+
+	ret = usbnet_get_endpoints(dev, intf);
+	if (ret)
+		goto out;
+
+	dev->net->netdev_ops = &sr9700_netdev_ops;
+	dev->net->ethtool_ops = &sr9700_ethtool_ops;
+	dev->net->hard_header_len += SR_TX_OVERHEAD;
+	dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
+	dev->rx_urb_size = 3072;	/* bulkin buffer is preferably not less than 3K */
+
+	dev->mii.dev = dev->net;
+	dev->mii.mdio_read = sr_mdio_read;
+	dev->mii.mdio_write = sr_mdio_write;
+	dev->mii.phy_id_mask = 0x1f;
+	dev->mii.reg_num_mask = 0x1f;
+
+	/* reset the sr9700 */
+	sr_write_reg(dev, NCR, 1);
+	udelay(20);
+
+	/* read MAC
+	 * After Chip Power on, the Chip will reload the MAC from EEPROM automatically to PAR
+	 * In case there is no EEPROM externally, a default MAC address is stored in PAR for making chip work properly
+	 */
+	if (sr_read(dev, PAR, ETH_ALEN, dev->net->dev_addr) < 0) {
+		netdev_err(dev->net, "Error reading MAC address\n");
+		ret = -ENODEV;
+		goto out;
+	}
+
+	/* power up and reset phy */
+	sr_write_reg(dev, PRR, 1);
+	mdelay(20);		/* at least 10ms, here 20ms for safe */
+	sr_write_reg(dev, PRR, 0);
+	udelay(2 * 1000);	/* at least 1ms, here 2ms for reading right register */
+
+	/* receive broadcast packets */
+	sr9700_set_multicast(dev->net);
+
+	sr_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
+	sr_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
+	mii_nway_restart(&dev->mii);
+
+out:
+	return ret;
+}
+
+static int sr9700_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+{
+	int len;
+	struct sk_buff *sr_skb;
+
+	/* format:
+	   b0: rx status
+	   b1: packet length (incl crc) low
+	   b2: packet length (incl crc) high
+	   b3..n-4: packet data
+	   bn-3..bn: ethernet crc
+	 */
+
+	if (unlikely(skb->len < SR_RX_OVERHEAD)) {
+		netdev_err(dev->net, "unexpected tiny rx frame\n");
+		return 0;
+	}
+
+	/* Each packet contains multiple skbs */
+	while (skb->len > SR_RX_OVERHEAD) {
+		if (skb->data[0] != 0x40)
+			return 0;
+
+		/* ignore the CRC length */
+		len = (skb->data[1] | (skb->data[2] << 8)) - 4;
+
+		if (len > ETH_FRAME_LEN)
+			return 0;
+
+		/* the last skb of current packet */
+		if (skb->len == (len + SR_RX_OVERHEAD))	{
+			skb_pull(skb, 3);
+			skb->len = len;
+			skb->tail = skb->data + len;
+			skb->truesize = len + sizeof(struct sk_buff);
+			return 2;
+		}
+
+		/* skb_clone is used for address align */
+		sr_skb = skb_clone(skb, GFP_ATOMIC);
+		if (sr_skb) {
+			sr_skb->len = len;
+			sr_skb->data = skb->data + 3;
+			sr_skb->tail = skb->data + len;
+			sr_skb->truesize = len + sizeof(struct sk_buff);
+			usbnet_skb_return(dev, sr_skb);
+		} else {
+			return 0;
+		}
+
+		skb_pull(skb, len + SR_RX_OVERHEAD);
+	};
+
+	return 0;
+}
+
+static struct sk_buff *sr9700_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
+{
+	int len;
+
+	/* format:
+	   b0: packet length low
+	   b1: packet length high
+	   b3..n: packet data
+	*/
+
+	len = skb->len;
+
+	if (skb_headroom(skb) < SR_TX_OVERHEAD) {
+		struct sk_buff *skb2;
+
+		skb2 = skb_copy_expand(skb, SR_TX_OVERHEAD, 0, flags);
+		dev_kfree_skb_any(skb);
+		skb = skb2;
+		if (!skb)
+			return NULL;
+	}
+
+	__skb_push(skb, SR_TX_OVERHEAD);
+
+	/* usbnet adds padding if length is a multiple of packet size
+	 * if so, adjust length value in header
+	 */
+	if ((skb->len % dev->maxpacket) == 0)
+		len++;
+
+	skb->data[0] = len;
+	skb->data[1] = len >> 8;
+
+	return skb;
+}
+
+static void sr9700_status(struct usbnet *dev, struct urb *urb)
+{
+	int link;
+	u8 *buf;
+
+	/* format:
+	   b0: net status
+	   b1: tx status 1
+	   b2: tx status 2
+	   b3: rx status
+	   b4: rx overflow
+	   b5: rx count
+	   b6: tx count
+	   b7: gpr
+	*/
+
+	if (urb->actual_length < 8)
+		return;
+
+	buf = urb->transfer_buffer;
+
+	link = !!(buf[0] & 0x40);
+	if (netif_carrier_ok(dev->net) != link) {
+		usbnet_link_change(dev, link, 1);
+		netdev_dbg(dev->net, "Link Status is: %d\n", link);
+	}
+}
+
+static int sr9700_link_reset(struct usbnet *dev)
+{
+	struct ethtool_cmd ecmd;
+
+	mii_check_media(&dev->mii, 1, 1);
+	mii_ethtool_gset(&dev->mii, &ecmd);
+
+	netdev_dbg(dev->net, "link_reset() speed: %d duplex: %d\n",
+	       ecmd.speed, ecmd.duplex);
+
+	return 0;
+}
+
+static const struct driver_info sr9700_driver_info = {
+	.description	= "CoreChip SR9700 USB Ethernet",
+	.flags		= FLAG_ETHER,
+	.bind		= sr9700_bind,
+	.rx_fixup	= sr9700_rx_fixup,
+	.tx_fixup	= sr9700_tx_fixup,
+	.status		= sr9700_status,
+	.link_reset	= sr9700_link_reset,
+	.reset		= sr9700_link_reset,
+};
+
+static const struct usb_device_id products[] = {
+	{
+	 USB_DEVICE(0x0fe6, 0x9700),	/* SR9700 device */
+	 .driver_info = (unsigned long)&sr9700_driver_info,
+	 },
+	{},			/* END */
+};
+
+MODULE_DEVICE_TABLE(usb, products);
+
+static struct usb_driver sr9700_usb_driver = {
+	.name = "sr9700",
+	.id_table = products,
+	.probe = usbnet_probe,
+	.disconnect = usbnet_disconnect,
+	.suspend = usbnet_suspend,
+	.resume = usbnet_resume,
+	.disable_hub_initiated_lpm = 1,
+};
+
+module_usb_driver(sr9700_usb_driver);
+
+MODULE_AUTHOR("liujl <liujunliang_ljl@163.com>");
+MODULE_DESCRIPTION("SR9700 one chip USB 1.1 USB to Ethernet device from http://www.corechip-sz.com/");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/usb/sr9700.h b/drivers/net/usb/sr9700.h
new file mode 100644
index 0000000..f1968ae
--- /dev/null
+++ b/drivers/net/usb/sr9700.h
@@ -0,0 +1,172 @@
+/*
+ * CoreChip-sz SR9700 one chip USB 1.1 Ethernet Devices
+ *
+ * Author : liujl <liujunliang_ljl@163.com>
+ *
+ * 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.
+ */
+
+#ifndef _SR9700_H
+#define	_SR9700_H
+
+/* sr9700 spec. register table on Linux platform */
+
+/* Network Control Reg */
+#define	NCR			0x00
+#define		NCR_RST			(1 << 0)
+#define		NCR_LBK			(3 << 1)
+#define		NCR_FDX			(1 << 3)
+#define		NCR_WAKEEN		(1 << 6)
+/* Network Status Reg */
+#define	NSR			0x01
+#define		NSR_RXRDY		(1 << 0)
+#define		NSR_RXOV		(1 << 1)
+#define		NSR_TX1END		(1 << 2)
+#define		NSR_TX2END		(1 << 3)
+#define		NSR_TXFULL		(1 << 4)
+#define		NSR_WAKEST		(1 << 5)
+#define		NSR_LINKST		(1 << 6)
+#define		NSR_SPEED		(1 << 7)
+/* Tx Control Reg */
+#define	TCR			0x02
+#define		TCR_CRC_DIS		(1 << 1)
+#define		TCR_PAD_DIS		(1 << 2)
+#define		TCR_LC_CARE		(1 << 3)
+#define		TCR_CRS_CARE	(1 << 4)
+#define		TCR_EXCECM		(1 << 5)
+#define		TCR_LF_EN		(1 << 6)
+/* Tx Status Reg for Packet Index 1 */
+#define	TSR1		0x03
+#define		TSR1_EC			(1 << 2)
+#define		TSR1_COL		(1 << 3)
+#define		TSR1_LC			(1 << 4)
+#define		TSR1_NC			(1 << 5)
+#define		TSR1_LOC		(1 << 6)
+#define		TSR1_TLF		(1 << 7)
+/* Tx Status Reg for Packet Index 2 */
+#define	TSR2		0x04
+#define		TSR2_EC			(1 << 2)
+#define		TSR2_COL		(1 << 3)
+#define		TSR2_LC			(1 << 4)
+#define		TSR2_NC			(1 << 5)
+#define		TSR2_LOC		(1 << 6)
+#define		TSR2_TLF		(1 << 7)
+/* Rx Control Reg*/
+#define	RCR			0x05
+#define		RCR_RXEN		(1 << 0)
+#define		RCR_PRMSC		(1 << 1)
+#define		RCR_RUNT		(1 << 2)
+#define		RCR_ALL			(1 << 3)
+#define		RCR_DIS_CRC		(1 << 4)
+#define		RCR_DIS_LONG	(1 << 5)
+/* Rx Status Reg */
+#define	RSR			0x06
+#define		RSR_AE			(1 << 2)
+#define		RSR_MF			(1 << 6)
+#define		RSR_RF			(1 << 7)
+/* Rx Overflow Counter Reg */
+#define	ROCR		0x07
+#define		ROCR_ROC		(0x7F << 0)
+#define		ROCR_RXFU		(1 << 7)
+/* Back Pressure Threshold Reg */
+#define	BPTR		0x08
+#define		BPTR_JPT		(0x0F << 0)
+#define		BPTR_BPHW		(0x0F << 4)
+/* Flow Control Threshold Reg */
+#define	FCTR		0x09
+#define		FCTR_LWOT		(0x0F << 0)
+#define		FCTR_HWOT		(0x0F << 4)
+/* rx/tx Flow Control Reg */
+#define	FCR			0x0A
+#define		FCR_FLCE		(1 << 0)
+#define		FCR_BKPA		(1 << 4)
+#define		FCR_TXPEN		(1 << 5)
+#define		FCR_TXPF		(1 << 6)
+#define		FCR_TXP0		(1 << 7)
+/* Eeprom & Phy Control Reg */
+#define	EPCR		0x0B
+#define		EPCR_ERRE		(1 << 0)
+#define		EPCR_ERPRW		(1 << 1)
+#define		EPCR_ERPRR		(1 << 2)
+#define		EPCR_EPOS		(1 << 3)
+#define		EPCR_WEP		(1 << 4)
+/* Eeprom & Phy Address Reg */
+#define	EPAR		0x0C
+#define		EPAR_EROA		(0x3F << 0)
+#define		EPAR_PHY_ADR	(0x03 << 6)
+/* Eeprom &	Phy Data Reg */
+#define	EPDR		0x0D	/* 0x0D ~ 0x0E for Data Reg Low & High */
+/* Wakeup Control Reg */
+#define	WCR			0x0F
+#define		WCR_MAGICST		(1 << 0)
+#define		WCR_LINKST		(1 << 2)
+#define		WCR_MAGICEN		(1 << 3)
+#define		WCR_LINKEN		(1 << 5)
+/* Physical Address Reg */
+#define	PAR			0x10	/* 0x10 ~ 0x15 6 bytes for PAR */
+/* Multicast Address Reg */
+#define	MAR			0x16	/* 0x16 ~ 0x1D 8 bytes for MAR */
+/* 0x1e unused */
+/* Phy Reset Reg */
+#define	PRR			0x1F
+#define		PRR_PHY_RST		(1 << 0)
+/* Tx sdram Write Pointer Address Low */
+#define	TWPAL		0x20
+/* Tx sdram Write Pointer Address High */
+#define	TWPAH		0x21
+/* Tx sdram Read Pointer Address Low */
+#define	TRPAL		0x22
+/* Tx sdram Read Pointer Address High */
+#define	TRPAH		0x23
+/* Rx sdram Write Pointer Address Low */
+#define	RWPAL		0x24
+/* Rx sdram Write Pointer Address High */
+#define	RWPAH		0x25
+/* Rx sdram Read Pointer Address Low */
+#define	RRPAL		0x26
+/* Rx sdram Read Pointer Address High */
+#define	RRPAH		0x27
+/* Vendor ID register */
+#define	VID			0x28	/* 0x28 ~ 0x29 2 bytes for VID */
+/* Product ID register */
+#define	PID			0x2A	/* 0x2A ~ 0x2B 2 bytes for PID */
+/* CHIP Revision register */
+#define	CHIPR		0x2C
+/* 0x2D --> 0xEF unused */
+/* USB Device Address */
+#define	USBDA		0xF0
+#define		USBDA_USBFA		(0x7F << 0)
+/* RX packet Counter Reg */
+#define	RXC			0xF1
+/* Tx packet Counter & USB Status Reg */
+#define	TXC_USBS	0xF2
+#define		TXC_USBS_TXC0		(1 << 0)
+#define		TXC_USBS_TXC1		(1 << 1)
+#define		TXC_USBS_TXC2		(1 << 2)
+#define		TXC_USBS_EP1RDY		(1 << 5)
+#define		TXC_USBS_SUSFLAG	(1 << 6)
+#define		TXC_USBS_RXFAULT	(1 << 7)
+/* USB Control register */
+#define	USBC		0xF4
+#define		USBC_EP3NAK		(1 << 4)
+#define		USBC_EP3ACK		(1 << 5)
+
+/* Register access commands and flags */
+#define	SR_RD_REGS		0x00
+#define	SR_WR_REGS		0x01
+#define	SR_WR_REG		0x03
+#define	SR_REQ_RD_REG	(USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
+#define	SR_REQ_WR_REG	(USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
+
+/* parameters */
+#define	SR_SHARE_TIMEOUT	1000
+#define	SR_EEPROM_LEN		256
+#define	SR_MCAST_SIZE		8
+#define	SR_MCAST_ADDR_FLAG	0x80
+#define	SR_MCAST_MAX		64
+#define	SR_TX_OVERHEAD		2	/* 2bytes header */
+#define	SR_RX_OVERHEAD		7	/* 3bytes header + 4crc tail */
+
+#endif	/* _SR9700_H */





2013-08-21 



liujunliang_ljl 



发件人: Joe Perches 
发送时间: 2013-08-21  04:58:27 
收件人: Francois Romieu 
抄送: liujunliang_ljl; gregkh; sunhecheng; linux-usb; netdev; linux-kernel 
主题: Re: [PATCH-SR9700] Merge USB 1.1 Ethernet Adapter SR9700 DeviceDriver into the Linux Kernel 
 
On Tue, 2013-08-20 at 22:46 +0200, Francois Romieu wrote:
> liujunliang_ljl <liujunliang_ljl@163.com> :
> > + if (i >= SR_SHARE_TIMEOUT) {
> > + netdev_err(dev->net, "%s read timed out!", phy ? "phy" : "eeprom");
netdev_<level>, like almost all other printk
messages needs a terminating "\n" newline to
avoid any possible message interleaving by other
printks.
> > + if (!is_valid_ether_addr(addr->sa_data)) {
> > + dev_err(&net->dev, "not setting invalid mac address %pM\n",
> > + addr->sa_data);
> 
>  dev_err(&net->dev, "not setting invalid mac address %pM\n",
>  addr->sa_data);
prefer netdev_<level> to dev_<level> where possible.

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: Re: [PATCH-SR9700] Merge USB 1.1 Ethernet Adapter SR9700 DeviceDriver into the Linux Kernel
  2013-08-20 20:46 ` Francois Romieu
  2013-08-20 20:58   ` Joe Perches
@ 2013-08-21 10:06   ` liujunliang_ljl
  2013-08-21 16:20     ` Greg KH
  2013-08-21 20:33     ` Francois Romieu
  1 sibling, 2 replies; 9+ messages in thread
From: liujunliang_ljl @ 2013-08-21 10:06 UTC (permalink / raw)
  To: Francois Romieu; +Cc: gregkh, sunhecheng, linux-usb, netdev, linux-kernel

Dear Francois Romieu :

	1, all the format problems have been fixed
	
	2, sr9700.h registers definition is re-written

	3, Thanks for your detail checking and I have beed scripts/checkpatch.pl the patch and please check it.

[PATCH] :
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index 287cc62..a94b196 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -272,6 +272,14 @@ config USB_NET_DM9601
 	  This option adds support for Davicom DM9601 based USB 1.1
 	  10/100 Ethernet adapters.
 
+config USB_NET_SR9700
+	tristate "CoreChip-sz SR9700 based USB 1.1 10/100 ethernet devices"
+	depends on USB_USBNET
+	select CRC32
+	help
+	  This option adds support for CoreChip-sz SR9700 based USB 1.1
+	  10/100 Ethernet adapters.
+
 config USB_NET_SMSC75XX
 	tristate "SMSC LAN75XX based USB 2.0 gigabit ethernet devices"
 	depends on USB_USBNET
diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile
index 9ab5c9d..bba87a2 100644
--- a/drivers/net/usb/Makefile
+++ b/drivers/net/usb/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_USB_NET_AX88179_178A)      += ax88179_178a.o
 obj-$(CONFIG_USB_NET_CDCETHER)	+= cdc_ether.o
 obj-$(CONFIG_USB_NET_CDC_EEM)	+= cdc_eem.o
 obj-$(CONFIG_USB_NET_DM9601)	+= dm9601.o
+obj-$(CONFIG_USB_NET_SR9700)	+= sr9700.o
 obj-$(CONFIG_USB_NET_SMSC75XX)	+= smsc75xx.o
 obj-$(CONFIG_USB_NET_SMSC95XX)	+= smsc95xx.o
 obj-$(CONFIG_USB_NET_GL620A)	+= gl620a.o
diff --git a/drivers/net/usb/sr9700.c b/drivers/net/usb/sr9700.c
new file mode 100644
index 0000000..9c8f167
--- /dev/null
+++ b/drivers/net/usb/sr9700.c
@@ -0,0 +1,536 @@
+/*
+ * CoreChip-sz SR9700 one chip USB 1.1 Ethernet Devices
+ *
+ * Author : liujl <liujunliang_ljl@163.com>
+ *
+ * Based on dm9601.c
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/usb.h>
+#include <linux/crc32.h>
+#include <linux/usb/usbnet.h>
+
+#include "sr9700.h"
+
+static int sr_read(struct usbnet *dev, u8 reg, u16 length, void *data)
+{
+	int err;
+
+	err = usbnet_read_cmd(dev, SR_RD_REGS, SR_REQ_RD_REG,
+					0, reg, data, length);
+	if ((err != length) && (err >= 0))
+		err = -EINVAL;
+	return err;
+}
+
+static int sr_write(struct usbnet *dev, u8 reg, u16 length, void *data)
+{
+	int err;
+
+	err = usbnet_write_cmd(dev, SR_WR_REGS, SR_REQ_WR_REG,
+					0, reg, data, length);
+	if ((err >= 0) && (err < length))
+		err = -EINVAL;
+	return err;
+}
+
+static int sr_read_reg(struct usbnet *dev, u8 reg, u8 *value)
+{
+	return sr_read(dev, reg, 1, value);
+}
+
+static int sr_write_reg(struct usbnet *dev, u8 reg, u8 value)
+{
+	return usbnet_write_cmd(dev, SR_WR_REGS, SR_REQ_WR_REG,
+					value, reg, NULL, 0);
+}
+
+static void sr_write_async(struct usbnet *dev, u8 reg, u16 length, void *data)
+{
+	usbnet_write_cmd_async(dev, SR_WR_REGS, SR_REQ_WR_REG,
+					0, reg, data, length);
+}
+
+static void sr_write_reg_async(struct usbnet *dev, u8 reg, u8 value)
+{
+	usbnet_write_cmd_async(dev, SR_WR_REGS, SR_REQ_WR_REG,
+					value, reg, NULL, 0);
+}
+
+static int sr_share_read_word(struct usbnet *dev, int phy, u8 reg, __le16 *value)
+{
+	int ret, i;
+
+	mutex_lock(&dev->phy_mutex);
+
+	sr_write_reg(dev, EPAR, phy ? (reg | 0x40) : reg);
+	sr_write_reg(dev, EPCR, phy ? 0xc : 0x4);
+
+	for (i = 0; i < SR_SHARE_TIMEOUT; i++) {
+		u8 tmp = 0;
+
+		udelay(1);
+		ret = sr_read_reg(dev, EPCR, &tmp);
+		if (ret < 0)
+			goto out_unlock;
+
+		/* ready */
+		if ((tmp & EPCR_ERRE) == 0)
+			break;
+	}
+
+	if (i >= SR_SHARE_TIMEOUT) {
+		netdev_err(dev->net, "%s read timed out!\n", phy ? "phy" : "eeprom");
+		ret = -EIO;
+		goto out_unlock;
+	}
+
+	sr_write_reg(dev, EPCR, 0x0);
+	ret = sr_read(dev, EPDR, 2, value);
+
+	netdev_dbg(dev->net, "read shared %d 0x%02x returned 0x%04x, %d\n",
+	       phy, reg, *value, ret);
+
+ out_unlock:
+	mutex_unlock(&dev->phy_mutex);
+	return ret;
+}
+
+static int sr_share_write_word(struct usbnet *dev, int phy, u8 reg, __le16 value)
+{
+	int ret, i;
+
+	mutex_lock(&dev->phy_mutex);
+
+	ret = sr_write(dev, EPDR, 2, &value);
+	if (ret < 0)
+		goto out_unlock;
+
+	sr_write_reg(dev, EPAR, phy ? (reg | 0x40) : reg);
+	sr_write_reg(dev, EPCR, phy ? 0x1a : 0x12);
+
+	for (i = 0; i < SR_SHARE_TIMEOUT; i++) {
+		u8 tmp = 0;
+
+		udelay(1);
+		ret = sr_read_reg(dev, EPCR, &tmp);
+		if (ret < 0)
+			goto out_unlock;
+
+		/* ready */
+		if ((tmp & EPCR_ERRE) == 0)
+			break;
+	}
+
+	if (i >= SR_SHARE_TIMEOUT) {
+		netdev_err(dev->net, "%s write timed out!\n", phy ? "phy" : "eeprom");
+		ret = -EIO;
+		goto out_unlock;
+	}
+
+	sr_write_reg(dev, EPCR, 0x0);
+
+out_unlock:
+	mutex_unlock(&dev->phy_mutex);
+	return ret;
+}
+
+static int sr_read_eeprom_word(struct usbnet *dev, u8 offset, void *value)
+{
+	return sr_share_read_word(dev, 0, offset, value);
+}
+
+static int sr9700_get_eeprom_len(struct net_device *dev)
+{
+	return SR_EEPROM_LEN;
+}
+
+static int sr9700_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, u8 *data)
+{
+	struct usbnet *dev = netdev_priv(net);
+	__le16 *ebuf = (__le16 *) data;
+	int ret = 0;
+	int i;
+
+	/* access is 16bit */
+	if ((eeprom->offset % 2) || (eeprom->len % 2))
+		return -EINVAL;
+
+	for (i = 0; i < eeprom->len / 2; i++)
+			ret = sr_read_eeprom_word(dev, eeprom->offset / 2 + i, &ebuf[i]);
+
+	return ret;
+}
+
+static int sr_mdio_read(struct net_device *netdev, int phy_id, int loc)
+{
+	struct usbnet *dev = netdev_priv(netdev);
+	__le16 res;
+	int rc = 0;
+
+	if (phy_id) {
+		netdev_dbg(dev->net, "Only internal phy supported\n");
+		return 0;
+	}
+
+	/* Access NSR_LINKST bit for link status instead of MII_BMSR */
+	if (loc == MII_BMSR) {
+			u8 value;
+
+			sr_read_reg(dev, NSR, &value);
+			if (value & NSR_LINKST)
+					rc = 1;
+	}
+	sr_share_read_word(dev, 1, loc, &res);
+	if (rc == 1)
+			return le16_to_cpu(res) | BMSR_LSTATUS;
+	else
+			return le16_to_cpu(res) & ~BMSR_LSTATUS;
+
+	netdev_dbg(dev->net,
+	       "sr_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n",
+	       phy_id, loc, le16_to_cpu(res));
+
+	return le16_to_cpu(res);
+}
+
+static void sr_mdio_write(struct net_device *netdev, int phy_id, int loc, int val)
+{
+	struct usbnet *dev = netdev_priv(netdev);
+	__le16 res = cpu_to_le16(val);
+
+	if (phy_id) {
+		netdev_dbg(dev->net, "Only internal phy supported\n");
+		return;
+	}
+
+	netdev_dbg(dev->net, "sr_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n",
+	       phy_id, loc, val);
+
+	sr_share_write_word(dev, 1, loc, res);
+}
+
+static u32 sr9700_get_link(struct net_device *net)
+{
+	struct usbnet *dev = netdev_priv(net);
+	int rc = 0;
+	u8 value = 0;
+
+	/* Get the Link Status directly */
+	sr_read_reg(dev, NSR, &value);
+	if (value & NSR_LINKST)
+		rc = 1;
+
+	return rc;
+}
+
+static int sr9700_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
+{
+	struct usbnet *dev = netdev_priv(net);
+
+	return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
+}
+
+static const struct ethtool_ops sr9700_ethtool_ops = {
+	.get_drvinfo	= usbnet_get_drvinfo,
+	.get_link		= sr9700_get_link,
+	.get_msglevel	= usbnet_get_msglevel,
+	.set_msglevel	= usbnet_set_msglevel,
+	.get_eeprom_len	= sr9700_get_eeprom_len,
+	.get_eeprom		= sr9700_get_eeprom,
+	.get_settings	= usbnet_get_settings,
+	.set_settings	= usbnet_set_settings,
+	.nway_reset		= usbnet_nway_reset,
+};
+
+static void sr9700_set_multicast(struct net_device *net)
+{
+	struct usbnet *dev = netdev_priv(net);
+	/* We use the 20 byte dev->data for our 8 byte filter buffer
+	 * to avoid allocating memory that is tricky to free later
+	 */
+	u8 *hashes = (u8 *) &dev->data;
+	/* rx_ctl setting : enable, disable_long, disable_crc */
+	u8 rx_ctl = RCR_RXEN | RCR_DIS_CRC | RCR_DIS_LONG;
+
+	memset(hashes, 0x00, SR_MCAST_SIZE);
+	hashes[SR_MCAST_SIZE - 1] |= SR_MCAST_ADDR_FLAG;	/* broadcast address */
+
+	if (net->flags & IFF_PROMISC) {
+			rx_ctl |= RCR_PRMSC;
+	} else if (net->flags & IFF_ALLMULTI ||
+					netdev_mc_count(net) > SR_MCAST_MAX) {
+			rx_ctl |= RCR_RUNT;
+	} else if (!netdev_mc_empty(net)) {
+			struct netdev_hw_addr *ha;
+			netdev_for_each_mc_addr(ha, net) {
+					u32 crc = ether_crc(ETH_ALEN, ha->addr) >> 26;
+					hashes[crc >> 3] |= 1 << (crc & 0x7);
+			}
+	}
+
+	sr_write_async(dev, MAR, SR_MCAST_SIZE, hashes);
+	sr_write_reg_async(dev, RCR, rx_ctl);
+}
+
+static int sr9700_set_mac_address(struct net_device *net, void *p)
+{
+	struct sockaddr *addr = p;
+	struct usbnet *dev = netdev_priv(net);
+
+	if (!is_valid_ether_addr(addr->sa_data)) {
+		netdev_err(net, "not setting invalid mac address %pM\n",
+						addr->sa_data);
+		return -EINVAL;
+	}
+
+	memcpy(net->dev_addr, addr->sa_data, net->addr_len);
+	sr_write_async(dev, PAR, 6, dev->net->dev_addr);
+
+	return 0;
+}
+
+static const struct net_device_ops sr9700_netdev_ops = {
+	.ndo_open			= usbnet_open,
+	.ndo_stop			= usbnet_stop,
+	.ndo_start_xmit		= usbnet_start_xmit,
+	.ndo_tx_timeout		= usbnet_tx_timeout,
+	.ndo_change_mtu		= usbnet_change_mtu,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_do_ioctl		= sr9700_ioctl,
+	.ndo_set_rx_mode	= sr9700_set_multicast,
+	.ndo_set_mac_address	= sr9700_set_mac_address,
+};
+
+static int sr9700_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+	int ret;
+
+	ret = usbnet_get_endpoints(dev, intf);
+	if (ret)
+		goto out;
+
+	dev->net->netdev_ops = &sr9700_netdev_ops;
+	dev->net->ethtool_ops = &sr9700_ethtool_ops;
+	dev->net->hard_header_len += SR_TX_OVERHEAD;
+	dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
+	dev->rx_urb_size = 3072;	/* bulkin buffer is preferably not less than 3K */
+
+	dev->mii.dev = dev->net;
+	dev->mii.mdio_read = sr_mdio_read;
+	dev->mii.mdio_write = sr_mdio_write;
+	dev->mii.phy_id_mask = 0x1f;
+	dev->mii.reg_num_mask = 0x1f;
+
+	/* reset the sr9700 */
+	sr_write_reg(dev, NCR, 1);
+	udelay(20);
+
+	/* read MAC
+	 * After Chip Power on, the Chip will reload the MAC from EEPROM automatically to PAR
+	 * In case there is no EEPROM externally, a default MAC address is stored in PAR for making chip work properly
+	 */
+	if (sr_read(dev, PAR, ETH_ALEN, dev->net->dev_addr) < 0) {
+		netdev_err(dev->net, "Error reading MAC address\n");
+		ret = -ENODEV;
+		goto out;
+	}
+
+	/* power up and reset phy */
+	sr_write_reg(dev, PRR, 1);
+	mdelay(20);		/* at least 10ms, here 20ms for safe */
+	sr_write_reg(dev, PRR, 0);
+	udelay(2 * 1000);	/* at least 1ms, here 2ms for reading right register */
+
+	/* receive broadcast packets */
+	sr9700_set_multicast(dev->net);
+
+	sr_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
+	sr_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
+	mii_nway_restart(&dev->mii);
+
+out:
+	return ret;
+}
+
+static int sr9700_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+{
+	int len;
+	struct sk_buff *sr_skb;
+
+	/* format:
+	   b0: rx status
+	   b1: packet length (incl crc) low
+	   b2: packet length (incl crc) high
+	   b3..n-4: packet data
+	   bn-3..bn: ethernet crc
+	 */
+
+	if (unlikely(skb->len < SR_RX_OVERHEAD)) {
+		netdev_err(dev->net, "unexpected tiny rx frame\n");
+		return 0;
+	}
+
+	/* Each packet contains multiple skbs */
+	while (skb->len > SR_RX_OVERHEAD) {
+		if (skb->data[0] != 0x40)
+			return 0;
+
+		/* ignore the CRC length */
+		len = (skb->data[1] | (skb->data[2] << 8)) - 4;
+
+		if (len > ETH_FRAME_LEN)
+			return 0;
+
+		/* the last skb of current packet */
+		if (skb->len == (len + SR_RX_OVERHEAD))	{
+			skb_pull(skb, 3);
+			skb->len = len;
+			skb->tail = skb->data + len;
+			skb->truesize = len + sizeof(struct sk_buff);
+			return 2;
+		}
+
+		/* skb_clone is used for address align */
+		sr_skb = skb_clone(skb, GFP_ATOMIC);
+		if (sr_skb) {
+			sr_skb->len = len;
+			sr_skb->data = skb->data + 3;
+			sr_skb->tail = skb->data + len;
+			sr_skb->truesize = len + sizeof(struct sk_buff);
+			usbnet_skb_return(dev, sr_skb);
+		} else {
+			return 0;
+		}
+
+		skb_pull(skb, len + SR_RX_OVERHEAD);
+	};
+
+	return 0;
+}
+
+static struct sk_buff *sr9700_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
+{
+	int len;
+
+	/* format:
+	   b0: packet length low
+	   b1: packet length high
+	   b3..n: packet data
+	*/
+
+	len = skb->len;
+
+	if (skb_headroom(skb) < SR_TX_OVERHEAD) {
+		struct sk_buff *skb2;
+
+		skb2 = skb_copy_expand(skb, SR_TX_OVERHEAD, 0, flags);
+		dev_kfree_skb_any(skb);
+		skb = skb2;
+		if (!skb)
+			return NULL;
+	}
+
+	__skb_push(skb, SR_TX_OVERHEAD);
+
+	/* usbnet adds padding if length is a multiple of packet size
+	 * if so, adjust length value in header
+	 */
+	if ((skb->len % dev->maxpacket) == 0)
+		len++;
+
+	skb->data[0] = len;
+	skb->data[1] = len >> 8;
+
+	return skb;
+}
+
+static void sr9700_status(struct usbnet *dev, struct urb *urb)
+{
+	int link;
+	u8 *buf;
+
+	/* format:
+	   b0: net status
+	   b1: tx status 1
+	   b2: tx status 2
+	   b3: rx status
+	   b4: rx overflow
+	   b5: rx count
+	   b6: tx count
+	   b7: gpr
+	*/
+
+	if (urb->actual_length < 8)
+		return;
+
+	buf = urb->transfer_buffer;
+
+	link = !!(buf[0] & 0x40);
+	if (netif_carrier_ok(dev->net) != link) {
+		usbnet_link_change(dev, link, 1);
+		netdev_dbg(dev->net, "Link Status is: %d\n", link);
+	}
+}
+
+static int sr9700_link_reset(struct usbnet *dev)
+{
+	struct ethtool_cmd ecmd;
+
+	mii_check_media(&dev->mii, 1, 1);
+	mii_ethtool_gset(&dev->mii, &ecmd);
+
+	netdev_dbg(dev->net, "link_reset() speed: %d duplex: %d\n",
+	       ecmd.speed, ecmd.duplex);
+
+	return 0;
+}
+
+static const struct driver_info sr9700_driver_info = {
+	.description	= "CoreChip SR9700 USB Ethernet",
+	.flags		= FLAG_ETHER,
+	.bind		= sr9700_bind,
+	.rx_fixup	= sr9700_rx_fixup,
+	.tx_fixup	= sr9700_tx_fixup,
+	.status		= sr9700_status,
+	.link_reset	= sr9700_link_reset,
+	.reset		= sr9700_link_reset,
+};
+
+static const struct usb_device_id products[] = {
+	{
+	 USB_DEVICE(0x0fe6, 0x9700),	/* SR9700 device */
+	 .driver_info = (unsigned long)&sr9700_driver_info,
+	 },
+	{},			/* END */
+};
+
+MODULE_DEVICE_TABLE(usb, products);
+
+static struct usb_driver sr9700_usb_driver = {
+	.name = "sr9700",
+	.id_table = products,
+	.probe = usbnet_probe,
+	.disconnect = usbnet_disconnect,
+	.suspend = usbnet_suspend,
+	.resume = usbnet_resume,
+	.disable_hub_initiated_lpm = 1,
+};
+
+module_usb_driver(sr9700_usb_driver);
+
+MODULE_AUTHOR("liujl <liujunliang_ljl@163.com>");
+MODULE_DESCRIPTION("SR9700 one chip USB 1.1 USB to Ethernet device from http://www.corechip-sz.com/");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/usb/sr9700.h b/drivers/net/usb/sr9700.h
new file mode 100644
index 0000000..f1968ae
--- /dev/null
+++ b/drivers/net/usb/sr9700.h
@@ -0,0 +1,172 @@
+/*
+ * CoreChip-sz SR9700 one chip USB 1.1 Ethernet Devices
+ *
+ * Author : liujl <liujunliang_ljl@163.com>
+ *
+ * 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.
+ */
+
+#ifndef _SR9700_H
+#define	_SR9700_H
+
+/* sr9700 spec. register table on Linux platform */
+
+/* Network Control Reg */
+#define	NCR			0x00
+#define		NCR_RST			(1 << 0)
+#define		NCR_LBK			(3 << 1)
+#define		NCR_FDX			(1 << 3)
+#define		NCR_WAKEEN		(1 << 6)
+/* Network Status Reg */
+#define	NSR			0x01
+#define		NSR_RXRDY		(1 << 0)
+#define		NSR_RXOV		(1 << 1)
+#define		NSR_TX1END		(1 << 2)
+#define		NSR_TX2END		(1 << 3)
+#define		NSR_TXFULL		(1 << 4)
+#define		NSR_WAKEST		(1 << 5)
+#define		NSR_LINKST		(1 << 6)
+#define		NSR_SPEED		(1 << 7)
+/* Tx Control Reg */
+#define	TCR			0x02
+#define		TCR_CRC_DIS		(1 << 1)
+#define		TCR_PAD_DIS		(1 << 2)
+#define		TCR_LC_CARE		(1 << 3)
+#define		TCR_CRS_CARE	(1 << 4)
+#define		TCR_EXCECM		(1 << 5)
+#define		TCR_LF_EN		(1 << 6)
+/* Tx Status Reg for Packet Index 1 */
+#define	TSR1		0x03
+#define		TSR1_EC			(1 << 2)
+#define		TSR1_COL		(1 << 3)
+#define		TSR1_LC			(1 << 4)
+#define		TSR1_NC			(1 << 5)
+#define		TSR1_LOC		(1 << 6)
+#define		TSR1_TLF		(1 << 7)
+/* Tx Status Reg for Packet Index 2 */
+#define	TSR2		0x04
+#define		TSR2_EC			(1 << 2)
+#define		TSR2_COL		(1 << 3)
+#define		TSR2_LC			(1 << 4)
+#define		TSR2_NC			(1 << 5)
+#define		TSR2_LOC		(1 << 6)
+#define		TSR2_TLF		(1 << 7)
+/* Rx Control Reg*/
+#define	RCR			0x05
+#define		RCR_RXEN		(1 << 0)
+#define		RCR_PRMSC		(1 << 1)
+#define		RCR_RUNT		(1 << 2)
+#define		RCR_ALL			(1 << 3)
+#define		RCR_DIS_CRC		(1 << 4)
+#define		RCR_DIS_LONG	(1 << 5)
+/* Rx Status Reg */
+#define	RSR			0x06
+#define		RSR_AE			(1 << 2)
+#define		RSR_MF			(1 << 6)
+#define		RSR_RF			(1 << 7)
+/* Rx Overflow Counter Reg */
+#define	ROCR		0x07
+#define		ROCR_ROC		(0x7F << 0)
+#define		ROCR_RXFU		(1 << 7)
+/* Back Pressure Threshold Reg */
+#define	BPTR		0x08
+#define		BPTR_JPT		(0x0F << 0)
+#define		BPTR_BPHW		(0x0F << 4)
+/* Flow Control Threshold Reg */
+#define	FCTR		0x09
+#define		FCTR_LWOT		(0x0F << 0)
+#define		FCTR_HWOT		(0x0F << 4)
+/* rx/tx Flow Control Reg */
+#define	FCR			0x0A
+#define		FCR_FLCE		(1 << 0)
+#define		FCR_BKPA		(1 << 4)
+#define		FCR_TXPEN		(1 << 5)
+#define		FCR_TXPF		(1 << 6)
+#define		FCR_TXP0		(1 << 7)
+/* Eeprom & Phy Control Reg */
+#define	EPCR		0x0B
+#define		EPCR_ERRE		(1 << 0)
+#define		EPCR_ERPRW		(1 << 1)
+#define		EPCR_ERPRR		(1 << 2)
+#define		EPCR_EPOS		(1 << 3)
+#define		EPCR_WEP		(1 << 4)
+/* Eeprom & Phy Address Reg */
+#define	EPAR		0x0C
+#define		EPAR_EROA		(0x3F << 0)
+#define		EPAR_PHY_ADR	(0x03 << 6)
+/* Eeprom &	Phy Data Reg */
+#define	EPDR		0x0D	/* 0x0D ~ 0x0E for Data Reg Low & High */
+/* Wakeup Control Reg */
+#define	WCR			0x0F
+#define		WCR_MAGICST		(1 << 0)
+#define		WCR_LINKST		(1 << 2)
+#define		WCR_MAGICEN		(1 << 3)
+#define		WCR_LINKEN		(1 << 5)
+/* Physical Address Reg */
+#define	PAR			0x10	/* 0x10 ~ 0x15 6 bytes for PAR */
+/* Multicast Address Reg */
+#define	MAR			0x16	/* 0x16 ~ 0x1D 8 bytes for MAR */
+/* 0x1e unused */
+/* Phy Reset Reg */
+#define	PRR			0x1F
+#define		PRR_PHY_RST		(1 << 0)
+/* Tx sdram Write Pointer Address Low */
+#define	TWPAL		0x20
+/* Tx sdram Write Pointer Address High */
+#define	TWPAH		0x21
+/* Tx sdram Read Pointer Address Low */
+#define	TRPAL		0x22
+/* Tx sdram Read Pointer Address High */
+#define	TRPAH		0x23
+/* Rx sdram Write Pointer Address Low */
+#define	RWPAL		0x24
+/* Rx sdram Write Pointer Address High */
+#define	RWPAH		0x25
+/* Rx sdram Read Pointer Address Low */
+#define	RRPAL		0x26
+/* Rx sdram Read Pointer Address High */
+#define	RRPAH		0x27
+/* Vendor ID register */
+#define	VID			0x28	/* 0x28 ~ 0x29 2 bytes for VID */
+/* Product ID register */
+#define	PID			0x2A	/* 0x2A ~ 0x2B 2 bytes for PID */
+/* CHIP Revision register */
+#define	CHIPR		0x2C
+/* 0x2D --> 0xEF unused */
+/* USB Device Address */
+#define	USBDA		0xF0
+#define		USBDA_USBFA		(0x7F << 0)
+/* RX packet Counter Reg */
+#define	RXC			0xF1
+/* Tx packet Counter & USB Status Reg */
+#define	TXC_USBS	0xF2
+#define		TXC_USBS_TXC0		(1 << 0)
+#define		TXC_USBS_TXC1		(1 << 1)
+#define		TXC_USBS_TXC2		(1 << 2)
+#define		TXC_USBS_EP1RDY		(1 << 5)
+#define		TXC_USBS_SUSFLAG	(1 << 6)
+#define		TXC_USBS_RXFAULT	(1 << 7)
+/* USB Control register */
+#define	USBC		0xF4
+#define		USBC_EP3NAK		(1 << 4)
+#define		USBC_EP3ACK		(1 << 5)
+
+/* Register access commands and flags */
+#define	SR_RD_REGS		0x00
+#define	SR_WR_REGS		0x01
+#define	SR_WR_REG		0x03
+#define	SR_REQ_RD_REG	(USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
+#define	SR_REQ_WR_REG	(USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
+
+/* parameters */
+#define	SR_SHARE_TIMEOUT	1000
+#define	SR_EEPROM_LEN		256
+#define	SR_MCAST_SIZE		8
+#define	SR_MCAST_ADDR_FLAG	0x80
+#define	SR_MCAST_MAX		64
+#define	SR_TX_OVERHEAD		2	/* 2bytes header */
+#define	SR_RX_OVERHEAD		7	/* 3bytes header + 4crc tail */
+
+#endif	/* _SR9700_H */



2013-08-21 



liujunliang_ljl 



发件人: Francois Romieu 
发送时间: 2013-08-21  04:46:12 
收件人: liujunliang_ljl 
抄送: gregkh; sunhecheng; linux-usb; netdev; linux-kernel 
主题: Re: [PATCH-SR9700] Merge USB 1.1 Ethernet Adapter SR9700 DeviceDriver into the Linux Kernel 
 
liujunliang_ljl <liujunliang_ljl@163.com> :
[...]
> We want to merge SR9700 device driver into the Linux Kernel. The following
> is the Linux 3.10.7 version patch for SR9700, Please give us the assessment
> and support.
Welcome. Go ahead.
[...]
> diff --git a/drivers/net/usb/sr9700.c b/drivers/net/usb/sr9700.c
> new file mode 100644
> index 0000000..6a6429a
> --- /dev/null
> +++ b/drivers/net/usb/sr9700.c
[...]
> +static int sr_read(struct usbnet *dev, u8 reg, u16 length, void *data)
> +{
> + int err;
> +
> + err = usbnet_read_cmd(dev, SR_RD_REGS, SR_REQ_RD_REG,
> + 0, reg, data, length);
err = usbnet_read_cmd(dev, SR_RD_REGS, SR_REQ_RD_REG, 0, reg, data,
      length);
> + if(err != length && err >= 0)
         ^^ missing space
> + err = -EINVAL;
> + return err;
> +}
> +
> +static int sr_write(struct usbnet *dev, u8 reg, u16 length, void *data)
> +{
> + int err;
> +
> + err = usbnet_write_cmd(dev, SR_WR_REGS, SR_REQ_WR_REG,
> + 0, reg, data, length);
See above.
> + if (err >= 0 && err < length)
> + err = -EINVAL;
> + 
> + return err;
> +}
> +
> +static int sr_read_reg(struct usbnet *dev, u8 reg, u8 *value)
> +{
> + return sr_read(dev, reg, 1, value);
> +}
> +
> +static int sr_write_reg(struct usbnet *dev, u8 reg, u8 value)
> +{
> + return usbnet_write_cmd(dev, SR_WR_REGS, SR_REQ_WR_REG,
> +        value, reg, NULL, 0);
Sic.
> +}
> +
> +static void sr_write_async(struct usbnet *dev, u8 reg, u16 length, void *data)
> +{
> + usbnet_write_cmd_async(dev, SR_WR_REGS, SR_REQ_WR_REG,
> + 0, reg, data, length);
Sic.
> +}
> +
> +static void sr_write_reg_async(struct usbnet *dev, u8 reg, u8 value)
> +{
> + usbnet_write_cmd_async(dev, SR_WR_REGS, SR_REQ_WR_REG,
> + value, reg, NULL, 0);
Sic.
> +}
> +
> +static int sr_share_read_word(struct usbnet *dev, int phy, u8 reg, __le16 *value)
> +{
> + int ret, i;
> +
> + mutex_lock(&dev->phy_mutex);
> +
> + sr_write_reg(dev, EPAR, phy ? (reg | 0x40) : reg);
> + sr_write_reg(dev, EPCR, phy ? 0xc : 0x4);
> +
> + for (i = 0; i < SR_SHARE_TIMEOUT; i++) {
> + u8 tmp = 0;
> +
> + udelay(1);
> + ret = sr_read_reg(dev, EPCR, &tmp);
> + if (ret < 0)
> + goto out;
goto out_unlock;
> +
> + /* ready */
> + if ((tmp & 1) == 0)
if ((tmp & EPCR_ERRE) == 0)
> + break;
> + }
> +
> + if (i >= SR_SHARE_TIMEOUT) {
> + netdev_err(dev->net, "%s read timed out!", phy ? "phy" : "eeprom");
> + ret = -EIO;
> + goto out;
> + }
> +
> + sr_write_reg(dev, EPCR, 0x0);
> + ret = sr_read(dev, EPDR, 2, value);
> +
> + netdev_dbg(dev->net, "read shared %d 0x%02x returned 0x%04x, %d",
> +        phy, reg, *value, ret);
> +
> + out:
   ^ please remove space.
> + mutex_unlock(&dev->phy_mutex);
> + return ret;
> +}
> +
> +static int sr_share_write_word(struct usbnet *dev, int phy, u8 reg, __le16 value)
> +{
> + int ret, i;
> +
> + mutex_lock(&dev->phy_mutex);
> +
> + ret = sr_write(dev, EPDR, 2, &value);
> + if (ret < 0)
> + goto out;
> +
> + sr_write_reg(dev, EPAR, phy ? (reg | 0x40) : reg);
> + sr_write_reg(dev, EPCR, phy ? 0x1a : 0x12);
> +
> + for (i = 0; i < SR_SHARE_TIMEOUT; i++) {
> + u8 tmp = 0;
> +
> + udelay(1);
> + ret = sr_read_reg(dev, EPCR, &tmp);
> + if (ret < 0)
> + goto out;
> +
> + /* ready */
> + if ((tmp & 1) == 0)
> + break;
> + }
The 11 lines above are identical in sr_share_read_word. Please refactor.
[...]
> +static int sr_mdio_read(struct net_device *netdev, int phy_id, int loc)
> +{
> + struct usbnet *dev = netdev_priv(netdev);
> +
> + __le16 res;
Excess empty line.
> + int rc = 0;
> +
> + if (phy_id) {
> + netdev_dbg(dev->net, "Only internal phy supported");
> + return 0;
> + }
> +
> + /* Access NSR_LINKST bit for link status instead of MII_BMSR */
> + if(loc == MII_BMSR){
         ^^               ^^
Missing spaces.
> + u8 value;
Excess tabs and missing empty line.
> + sr_read_reg(dev, NSR, &value);
> + if(value & NSR_LINKST) {
Excess tabs, missing spaces, useless "{".
> + rc = 1;
> + }
> + }
> + sr_share_read_word(dev, 1, loc, &res);
> + if(rc == 1)
> + return (le16_to_cpu(res) | BMSR_LSTATUS);
> + else
> + return (le16_to_cpu(res) & ~BMSR_LSTATUS);
Excess "(" (aka "return is not a function").
[...]
> +/*-------------------------------------------------------------------------------------------*/
Just say no.
[...]
> +static void sr9700_set_multicast(struct net_device *net)
> +{
> + struct usbnet *dev = netdev_priv(net);
> + /* We use the 20 byte dev->data for our 8 byte filter buffer
> +  * to avoid allocating memory that is tricky to free later */
> + u8 *hashes = (u8 *) & dev->data;
                             ^extraneous space
> + u8 rx_ctl = 0x31; // enable, disable_long, disable_crc
u8 rx_ctl = RCR_ALL | RCR_DIS_CRC | RCR_DIS_LONG;
> +
> + memset(hashes, 0x00, SR_MCAST_SIZE);
> + hashes[SR_MCAST_SIZE - 1] |= 0x80; /* broadcast address */
Use #define.
> +
> +        if (net->flags & IFF_PROMISC) {
   ^^^^^^^^ should use tab, not space
> +                rx_ctl |= 0x02;
   ^^^... sic
> +        } else if (net->flags & IFF_ALLMULTI ||
> +                   netdev_mc_count(net) > SR_MCAST_MAX) {
> +                rx_ctl |= 0x04;
> +        } else if (!netdev_mc_empty(net)) {
> +                struct netdev_hw_addr *ha;
> + 
> +                netdev_for_each_mc_addr(ha, net) {
> +                        u32 crc = ether_crc(ETH_ALEN, ha->addr) >> 26;
> +                        hashes[crc >> 3] |= 1 << (crc & 0x7);
> +                }
> +        }
   ^^^... etc.
> +
> + sr_write_async(dev, MAR, SR_MCAST_SIZE, hashes);
> + sr_write_reg_async(dev, RCR, rx_ctl);
> +}
> +
> +static int sr9700_set_mac_address(struct net_device *net, void *p)
> +{
> + struct sockaddr *addr = p;
> + struct usbnet *dev = netdev_priv(net);
Long declaration lines first please.
> +
> + if (!is_valid_ether_addr(addr->sa_data)) {
> + dev_err(&net->dev, "not setting invalid mac address %pM\n",
> + addr->sa_data);
dev_err(&net->dev, "not setting invalid mac address %pM\n",
addr->sa_data);
[...]
> +static int sr9700_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
> +{
> + int len;
> + struct sk_buff *sr_skb;
> +
> + /* format:
> +    b0: rx status
> +    b1: packet length (incl crc) low
> +    b2: packet length (incl crc) high
> +    b3..n-4: packet data
> +    bn-3..bn: ethernet crc
> +  */
> +
> + if (unlikely(skb->len < SR_RX_OVERHEAD)) {
> + dev_err(&dev->udev->dev, "unexpected tiny rx frame\n");
> + return 0;
> + }
> +
> + /*
> +  * Each packet contains multiple skbs
> +  */
> + while (skb->len > SR_RX_OVERHEAD)
> + {
K&R please.
[...]
> +static struct usb_driver sr9700_usb_driver = {
> + .name = "sr9700",
> + .id_table = products,
> + .probe = usbnet_probe,
> + .disconnect = usbnet_disconnect,
> + .suspend = usbnet_suspend,
> + .resume = usbnet_resume,
> + .disable_hub_initiated_lpm = 1,
Use <tab>=.
[...]
> diff --git a/drivers/net/usb/sr9700.h b/drivers/net/usb/sr9700.h
> new file mode 100644
> index 0000000..d9fe82d
> --- /dev/null
> +++ b/drivers/net/usb/sr9700.h
> @@ -0,0 +1,152 @@
> +/*
> + * CoreChip-sz SR9700 one chip USB 1.1 Ethernet Devices
> + *
> + * Author : liujl <liujunliang_ljl@163.com>
> + *
> + * 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.
> + */
> +
> +/* sr9700 spec. register table on android platform */
> +/* Registers */
> +#define NCR 0x00
> +#define NSR 0x01
[...]
> +/* Bit definition for registers */
> +// Network Control Reg
> +#define NCR_RST (1 << 0)
> +#define NCR_LBK (3 << 1)
> +#define NCR_FDX (1 << 3)
> +#define NCR_WAKEEN (1 << 6)
You may group these with the register declarations above. Use an
offset to improve readability and separate registers from fields.
See drivers/net/ethernet/broadcom/tg3.h for instance.
-- 
Ueimor

^ permalink raw reply related	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2013-08-22  8:45 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-08-20 10:50 [PATCH-SR9700] Merge USB 1.1 Ethernet Adapter SR9700 Device Driver into the Linux Kernel liujunliang_ljl
2013-08-20 13:36 ` Ben Hutchings
2013-08-21 10:02 ` Re: [PATCH-SR9700] Merge USB 1.1 Ethernet Adapter SR9700 DeviceDriver " liujunliang_ljl
2013-08-22  8:45   ` Simon Horman
  -- strict thread matches above, loose matches on Subject: below --
2013-08-20 10:41 [PATCH-SR9700] Merge USB 1.1 Ethernet Adapter SR9700 Device Driver " liujunliang_ljl
2013-08-20 20:46 ` Francois Romieu
2013-08-20 20:58   ` Joe Perches
2013-08-21 10:07     ` Re: [PATCH-SR9700] Merge USB 1.1 Ethernet Adapter SR9700 DeviceDriver " liujunliang_ljl
2013-08-21 11:34       ` Joe Perches
2013-08-21 10:06   ` liujunliang_ljl
2013-08-21 16:20     ` Greg KH
2013-08-21 20:33     ` Francois Romieu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).