[PATCH] USB: net2282 and net2280 software compatibility

Below is a patch to gadgets/net2280.[ch] which adds support for the
net2282 controller. The original code was kindly provided by PLX
Technology, I just merged it with the current net2280 driver in the
kernel. Tested on 2.6.15.6, but only with 2282. I did the merge, so
that the behaviour for the 2280 is unaffected (except for short delays
for extra checks).

Signed-off-by: G. Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

Support for net2282 in net2280 driver.
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index d80f718..363b2ad 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -69,11 +69,11 @@
 	   often need board-specific hooks.
 
 config USB_GADGET_NET2280
-	boolean "NetChip 2280"
+	boolean "NetChip 228x"
 	depends on PCI
 	select USB_GADGET_DUALSPEED
 	help
-	   NetChip 2280 is a PCI based USB peripheral controller which
+	   NetChip 2280 / 2282 is a PCI based USB peripheral controller which
 	   supports both full and high speed USB 2.0 data transfers.  
 	   
 	   It has six configurable endpoints, as well as endpoint zero
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
index fb73dc1..7682c07 100644
--- a/drivers/usb/gadget/net2280.c
+++ b/drivers/usb/gadget/net2280.c
@@ -26,6 +26,8 @@
  * Copyright (C) 2003 David Brownell
  * Copyright (C) 2003-2005 PLX Technology, Inc.
  *
+ * Modified Seth Levy 2005 PLX Technology, Inc. to provide compatibility with 2282 chip
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -71,8 +73,8 @@
 #include <asm/unaligned.h>
 
 
-#define	DRIVER_DESC		"PLX NET2280 USB Peripheral Controller"
-#define	DRIVER_VERSION		"2005 Feb 03"
+#define	DRIVER_DESC		"PLX NET228x USB Peripheral Controller"
+#define	DRIVER_VERSION		"2005 Sept 27"
 
 #define	DMA_ADDR_INVALID	(~(dma_addr_t)0)
 #define	EP_DONTUSE		13	/* nonzero */
@@ -118,7 +120,7 @@
 /* enable_suspend -- When enabled, the driver will respond to
  * USB suspend requests by powering down the NET2280.  Otherwise,
  * USB suspend requests will be ignored.  This is acceptible for
- * self-powered devices, and helps avoid some quirks.
+ * self-powered devices
  */
 static int enable_suspend = 0;
 
@@ -223,6 +225,11 @@
 	ep->is_in = (tmp & USB_DIR_IN) != 0;
 	if (!ep->is_in)
 		writel ((1 << SET_NAK_OUT_PACKETS), &ep->regs->ep_rsp);
+	else if (dev->pdev->device != 0x2280) {
+		/* Added for 2282, Don't use nak packets on an in endpoint, this was ignored on 2280 */
+		writel ((1 << CLEAR_NAK_OUT_PACKETS)
+			| (1 << CLEAR_NAK_OUT_PACKETS_MODE), &ep->regs->ep_rsp);
+	}
 
 	writel (tmp, &ep->regs->ep_cfg);
 
@@ -232,8 +239,9 @@
 		writel (tmp, &dev->regs->pciirqenb0);
 
 		tmp = (1 << DATA_PACKET_RECEIVED_INTERRUPT_ENABLE)
-			| (1 << DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE)
-			| readl (&ep->regs->ep_irqenb);
+			| (1 << DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE);
+		if (dev->pdev->device == 0x2280)
+			tmp |= readl (&ep->regs->ep_irqenb);
 		writel (tmp, &ep->regs->ep_irqenb);
 	} else {				/* dma, per-request */
 		tmp = (1 << (8 + ep->num));	/* completion */
@@ -314,10 +322,18 @@
 	/* init to our chosen defaults, notably so that we NAK OUT
 	 * packets until the driver queues a read (+note erratum 0112)
 	 */
-	tmp = (1 << SET_NAK_OUT_PACKETS_MODE)
+	if (!ep->is_in || ep->dev->pdev->device == 0x2280) {
+		tmp = (1 << SET_NAK_OUT_PACKETS_MODE)
 		| (1 << SET_NAK_OUT_PACKETS)
 		| (1 << CLEAR_EP_HIDE_STATUS_PHASE)
 		| (1 << CLEAR_INTERRUPT_MODE);
+	} else {
+		/* added for 2282 */
+		tmp = (1 << CLEAR_NAK_OUT_PACKETS_MODE)
+		| (1 << CLEAR_NAK_OUT_PACKETS)
+		| (1 << CLEAR_EP_HIDE_STATUS_PHASE)
+		| (1 << CLEAR_INTERRUPT_MODE);
+	}
 
 	if (ep->num != 0) {
 		tmp |= (1 << CLEAR_ENDPOINT_TOGGLE)
@@ -326,14 +342,18 @@
 	writel (tmp, &ep->regs->ep_rsp);
 
 	/* scrub most status bits, and flush any fifo state */
-	writel (  (1 << TIMEOUT)
+	if (ep->dev->pdev->device == 0x2280)
+		tmp = (1 << FIFO_OVERFLOW)
+			| (1 << FIFO_UNDERFLOW);
+	else
+		tmp = 0;
+
+	writel (tmp | (1 << TIMEOUT)
 		| (1 << USB_STALL_SENT)
 		| (1 << USB_IN_NAK_SENT)
 		| (1 << USB_IN_ACK_RCVD)
 		| (1 << USB_OUT_PING_NAK_SENT)
 		| (1 << USB_OUT_ACK_SENT)
-		| (1 << FIFO_OVERFLOW)
-		| (1 << FIFO_UNDERFLOW)
 		| (1 << FIFO_FLUSH)
 		| (1 << SHORT_PACKET_OUT_DONE_INTERRUPT)
 		| (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)
@@ -718,7 +738,7 @@
 	 */
 	if (ep->is_in)
 		dmacount |= (1 << DMA_DIRECTION);
-	else if ((dmacount % ep->ep.maxpacket) != 0)
+	if ((!ep->is_in && (dmacount % ep->ep.maxpacket) != 0) || ep->dev->pdev->device != 0x2280)
 		dmacount |= (1 << END_OF_CHAIN);
 
 	req->valid = valid;
@@ -760,9 +780,12 @@
 static void start_queue (struct net2280_ep *ep, u32 dmactl, u32 td_dma)
 {
 	struct net2280_dma_regs	__iomem *dma = ep->dma;
+	unsigned int tmp = (1 << VALID_BIT) | (ep->is_in << DMA_DIRECTION);
 
-	writel ((1 << VALID_BIT) | (ep->is_in << DMA_DIRECTION),
-			&dma->dmacount);
+	if (ep->dev->pdev->device != 0x2280)
+		tmp |= (1 << END_OF_CHAIN);
+
+	writel (tmp, &dma->dmacount);
 	writel (readl (&dma->dmastat), &dma->dmastat);
 
 	writel (td_dma, &dma->dmadesc);
@@ -2110,7 +2133,11 @@
 	VDEBUG (ep->dev, "%s ack ep_stat %08x, req %p\n",
 			ep->ep.name, t, req ? &req->req : 0);
 #endif
-	writel (t & ~(1 << NAK_OUT_PACKETS), &ep->regs->ep_stat);
+	if (!ep->is_in || ep->dev->pdev->device == 0x2280)
+		writel (t & ~(1 << NAK_OUT_PACKETS), &ep->regs->ep_stat);
+	else
+		/* Added for 2282 */
+		writel (t, &ep->regs->ep_stat);
 
 	/* for ep0, monitor token irqs to catch data stage length errors
 	 * and to synchronize on status.
@@ -2337,7 +2364,7 @@
 			u32			raw [2];
 			struct usb_ctrlrequest	r;
 		} u;
-		int				tmp = 0;
+		int				tmp;
 		struct net2280_request		*req;
 
 		if (dev->gadget.speed == USB_SPEED_UNKNOWN) {
@@ -2364,14 +2391,19 @@
 		}
 		ep->stopped = 0;
 		dev->protocol_stall = 0;
-		writel (  (1 << TIMEOUT)
+
+		if (ep->dev->pdev->device == 0x2280)
+			tmp = (1 << FIFO_OVERFLOW)
+				| (1 << FIFO_UNDERFLOW);
+		else
+			tmp = 0;
+
+		writel (tmp | (1 << TIMEOUT)
 			| (1 << USB_STALL_SENT)
 			| (1 << USB_IN_NAK_SENT)
 			| (1 << USB_IN_ACK_RCVD)
 			| (1 << USB_OUT_PING_NAK_SENT)
 			| (1 << USB_OUT_ACK_SENT)
-			| (1 << FIFO_OVERFLOW)
-			| (1 << FIFO_UNDERFLOW)
 			| (1 << SHORT_PACKET_OUT_DONE_INTERRUPT)
 			| (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)
 			| (1 << DATA_PACKET_RECEIVED_INTERRUPT)
@@ -2385,6 +2417,8 @@
 		cpu_to_le32s (&u.raw [0]);
 		cpu_to_le32s (&u.raw [1]);
 
+		tmp = 0;
+
 #define	w_value		le16_to_cpup (&u.r.wValue)
 #define	w_index		le16_to_cpup (&u.r.wIndex)
 #define	w_length	le16_to_cpup (&u.r.wLength)
@@ -2594,10 +2628,17 @@
 		writel (stat, &dev->regs->irqstat1);
 
 	/* some status we can just ignore */
-	stat &= ~((1 << CONTROL_STATUS_INTERRUPT)
-			| (1 << SUSPEND_REQUEST_INTERRUPT)
-			| (1 << RESUME_INTERRUPT)
-			| (1 << SOF_INTERRUPT));
+	if (dev->pdev->device == 0x2280)
+		stat &= ~((1 << CONTROL_STATUS_INTERRUPT)
+			  | (1 << SUSPEND_REQUEST_INTERRUPT)
+			  | (1 << RESUME_INTERRUPT)
+			  | (1 << SOF_INTERRUPT));
+	else
+		stat &= ~((1 << CONTROL_STATUS_INTERRUPT)
+			  | (1 << RESUME_INTERRUPT)
+			  | (1 << SOF_DOWN_INTERRUPT)
+			  | (1 << SOF_INTERRUPT));
+
 	if (!stat)
 		return;
 	// DEBUG (dev, "irqstat1 %08x\n", stat);
@@ -2939,6 +2980,13 @@
 	.device =	0x2280,
 	.subvendor =	PCI_ANY_ID,
 	.subdevice =	PCI_ANY_ID,
+}, {
+	.class = 	((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
+	.class_mask = 	~0,
+	.vendor =	0x17cc,
+	.device =	0x2282,
+	.subvendor =	PCI_ANY_ID,
+	.subdevice =	PCI_ANY_ID,
 
 }, { /* end: all zeroes */ }
 };
diff --git a/drivers/usb/gadget/net2280.h b/drivers/usb/gadget/net2280.h
index fff4509..e195abe 100644
--- a/drivers/usb/gadget/net2280.h
+++ b/drivers/usb/gadget/net2280.h
@@ -179,6 +179,7 @@
 #define     PCI_TARGET_ABORT_RECEIVED_INTERRUPT                 19
 #define     PCI_RETRY_ABORT_INTERRUPT                           17
 #define     PCI_MASTER_CYCLE_DONE_INTERRUPT                     16
+#define     SOF_DOWN_INTERRUPT                                  14
 #define     GPIO_INTERRUPT                                      13
 #define     DMA_D_INTERRUPT                                     12
 #define     DMA_C_INTERRUPT                                     11
@@ -346,6 +347,7 @@
 #define     DMA_ENABLE                                          1
 #define     DMA_ADDRESS_HOLD                                    0
 	u32		dmastat;
+#define     DMA_ABORT_DONE_INTERRUPT                            27
 #define     DMA_SCATTER_GATHER_DONE_INTERRUPT                   25
 #define     DMA_TRANSACTION_DONE_INTERRUPT                      24
 #define     DMA_ABORT                                           1