[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.
This commit is contained in:
parent
f043ca43c1
commit
950ee4c8f0
|
@ -69,11 +69,11 @@ choice
|
|||
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
|
||||
|
|
|
@ -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 @@ module_param (fifo_mode, ushort, 0644);
|
|||
/* 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 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
|
|||
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 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
|
|||
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 @@ static void ep_reset (struct net2280_regs __iomem *regs, struct net2280_ep *ep)
|
|||
/* 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 @@ static void ep_reset (struct net2280_regs __iomem *regs, struct net2280_ep *ep)
|
|||
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 @@ fill_dma_desc (struct net2280_ep *ep, struct net2280_request *req, int valid)
|
|||
*/
|
||||
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 inline void stop_dma (struct net2280_dma_regs __iomem *dma)
|
|||
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 @@ static void handle_ep_small (struct net2280_ep *ep)
|
|||
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 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
|
|||
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 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
|
|||
}
|
||||
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 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
|
|||
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 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat)
|
|||
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 @@ static struct pci_device_id pci_ids [] = { {
|
|||
.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 */ }
|
||||
};
|
||||
|
|
|
@ -179,6 +179,7 @@ struct net2280_regs {
|
|||
#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 @@ struct net2280_dma_regs { /* [11.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
|
||||
|
|
Loading…
Reference in New Issue