- don't try chiprev 0100 erratum 0114 workaround on newer chips; and (mostly) revert it when clearing endpoint halt feature. (bugfix)
- add missing define for the "force crc error" bit; I guess those #defines were generated from old chip specs! potentially useful with test software.
- sysfs register dump includes chiprev and decodes some of the more interesting endpoint response bits.
- makes a sysfs "gadget" node, representing the gadget itself. (decided against the class_device or bus_type approaches, until their value outweighs their costs.)
Please merge.
- Dave
--- linux-2.6/drivers/usb/gadget/net2280.h 2003-08-08 16:35:17.000000000 -0700
+++ gadget-2.6/drivers/usb/gadget/net2280.h 2003-08-24 19:35:26.000000000 -0700
@@ -389,6 +389,7 @@
u32 ep_rsp;
#define SET_NAK_OUT_PACKETS 15
#define SET_EP_HIDE_STATUS_PHASE 14
+#define SET_EP_FORCE_CRC_ERROR 13
#define SET_INTERRUPT_MODE 12
#define SET_CONTROL_STATUS_PHASE_HANDSHAKE 11
#define SET_NAK_OUT_PACKETS_MODE 10
@@ -396,6 +397,7 @@
#define SET_ENDPOINT_HALT 8
#define CLEAR_NAK_OUT_PACKETS 7
#define CLEAR_EP_HIDE_STATUS_PHASE 6
+#define CLEAR_EP_FORCE_CRC_ERROR 5
#define CLEAR_INTERRUPT_MODE 4
#define CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE 3
#define CLEAR_NAK_OUT_PACKETS_MODE 2
@@ -476,6 +478,9 @@
#define REG_CHIPREV 0x03 /* in bcd */
#define REG_HS_NAK_RATE 0x0a /* NAK per N uframes */
+#define CHIPREV_1 0x0100
+#define CHIPREV_1A 0x0110
+
#ifdef __KERNEL__
/* ep a-f highspeed and fullspeed maxpacket, addresses
@@ -529,24 +534,6 @@
ep->stopped = 1;
}
-static inline void set_halt (struct net2280_ep *ep)
-{
- /* ep0 and bulk/intr endpoints */
- writel ( (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE)
- /* set NAK_OUT for erratum 0114 */
- | (1 << SET_NAK_OUT_PACKETS)
- | (1 << SET_ENDPOINT_HALT)
- , &ep->regs->ep_rsp);
-}
-
-static inline void clear_halt (struct net2280_ep *ep)
-{
- /* bulk/intr endpoints */
- writel ( (1 << CLEAR_ENDPOINT_HALT)
- | (1 << CLEAR_ENDPOINT_TOGGLE)
- , &ep->regs->ep_rsp);
-}
-
/* count (<= 4) bytes in the next fifo write will be valid */
static inline void set_fifo_bytecount (struct net2280_ep *ep, unsigned count)
{
@@ -589,6 +576,28 @@
// statistics...
};
+static inline void set_halt (struct net2280_ep *ep)
+{
+ /* ep0 and bulk/intr endpoints */
+ writel ( (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE)
+ /* set NAK_OUT for erratum 0114 */
+ | ((ep->dev->chiprev == CHIPREV_1) << SET_NAK_OUT_PACKETS)
+ | (1 << SET_ENDPOINT_HALT)
+ , &ep->regs->ep_rsp);
+}
+
+static inline void clear_halt (struct net2280_ep *ep)
+{
+ /* ep0 and bulk/intr endpoints */
+ writel ( (1 << CLEAR_ENDPOINT_HALT)
+ | (1 << CLEAR_ENDPOINT_TOGGLE)
+ /* unless the gadget driver left a short packet in the
+ * fifo, this reverses the erratum 0114 workaround.
+ */
+ | ((ep->dev->chiprev == CHIPREV_1) << CLEAR_NAK_OUT_PACKETS)
+ , &ep->regs->ep_rsp);
+}
+
#ifdef USE_RDK_LEDS
static inline void net2280_led_init (struct net2280 *dev)
--- linux-2.6/drivers/usb/gadget/net2280.c 2003-08-09 07:42:10.000000000 -0700
+++ gadget-2.6/drivers/usb/gadget/net2280.c 2003-08-24 19:35:26.000000000 -0700
@@ -30,6 +30,7 @@
/*
* Copyright (C) 2003 David Brownell
+ * Copyright (C) 2003 NetChip Technologies
*
* 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
@@ -76,7 +77,7 @@
#define DRIVER_DESC "NetChip 2280 USB Peripheral Controller"
-#define DRIVER_VERSION "May Day 2003"
+#define DRIVER_VERSION "Bastille Day 2003"
#define DMA_ADDR_INVALID (~(dma_addr_t)0)
#define EP_DONTUSE 13 /* nonzero */
@@ -1344,11 +1345,12 @@
s = "(none)";
/* Main Control Registers */
- t = snprintf (next, size, "%s " DRIVER_VERSION "\n"
+ t = snprintf (next, size, "%s version " DRIVER_VERSION
+ ", chiprev %04x\n"
"devinit %03x fifoctl %08x gadget '%s'\n"
"pci irqenb0 %02x irqenb1 %08x "
"irqstat0 %04x irqstat1 %08x\n",
- driver_name,
+ driver_name, dev->chiprev,
readl (&dev->regs->devinit),
readl (&dev->regs->fifoctl),
s,
@@ -1393,16 +1395,33 @@
continue;
t1 = readl (&ep->regs->ep_cfg);
+ t2 = readl (&ep->regs->ep_rsp) & 0xff;
t = snprintf (next, size,
- "%s\tcfg %05x rsp %02x enb %02x ",
- ep->ep.name, t1,
- readl (&ep->regs->ep_rsp) & 0xff,
+ "%s\tcfg %05x rsp (%02x) %s%s%s%s%s%s%s%s"
+ "irqenb %02x\n",
+ ep->ep.name, t1, t2,
+ (t2 & (1 << CLEAR_NAK_OUT_PACKETS))
+ ? "NAK " : "",
+ (t2 & (1 << CLEAR_EP_HIDE_STATUS_PHASE))
+ ? "hide " : "",
+ (t2 & (1 << CLEAR_EP_FORCE_CRC_ERROR))
+ ? "CRC " : "",
+ (t2 & (1 << CLEAR_INTERRUPT_MODE))
+ ? "interrupt " : "",
+ (t2 & (1<<CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE))
+ ? "status " : "",
+ (t2 & (1 << CLEAR_NAK_OUT_PACKETS_MODE))
+ ? "NAKmode " : "",
+ (t2 & (1 << CLEAR_ENDPOINT_TOGGLE))
+ ? "DATA1 " : "DATA0 ",
+ (t2 & (1 << CLEAR_ENDPOINT_HALT))
+ ? "HALT " : "",
readl (&ep->regs->ep_irqenb));
size -= t;
next += t;
t = snprintf (next, size,
- "stat %08x avail %04x "
+ "\tstat %08x avail %04x "
"(ep%d%s-%s)%s\n",
readl (&ep->regs->ep_stat),
readl (&ep->regs->ep_avail),
@@ -1796,6 +1815,7 @@
dev->ep [i].irqs = 0;
/* hook up the driver ... */
+ driver->driver.bus = 0;
dev->driver = driver;
dev->gadget.dev.driver = &driver->driver;
retval = driver->bind (&dev->gadget);
@@ -1807,10 +1827,6 @@
return retval;
}
- // FIXME
- // driver_register (&driver->driver);
- // device_register (&dev->gadget.dev);
-
device_create_file (&dev->pdev->dev, &dev_attr_function);
device_create_file (&dev->pdev->dev, &dev_attr_queues);
@@ -1877,10 +1893,6 @@
device_remove_file (&dev->pdev->dev, &dev_attr_function);
device_remove_file (&dev->pdev->dev, &dev_attr_queues);
- // FIXME
- // device_unregister()
- // driver_unregister (&driver->driver);
-
DEBUG (dev, "unregistered driver '%s'\n", driver->driver.name);
return 0;
}
@@ -2049,9 +2061,9 @@
/* maybe advance queue to next request */
if (ep->num == 0) {
- /* FIXME need mechanism (request flag?) so control OUT
- * can decide to stall ep0 after that done() returns,
- * from non-irq context
+ /* NOTE: net2280 could let gadget driver start the
+ * status stage later. since not all controllers let
+ * them control that, the api doesn't (yet) allow it.
*/
if (!ep->stopped)
allow_status (ep);
@@ -2174,6 +2186,8 @@
/* watch control traffic at the token level, and force
* synchronization before letting the status stage happen.
+ * FIXME ignore tokens we'll NAK, until driver responds.
+ * that'll mean a lot less irqs for some drivers.
*/
ep->is_in = (u.r.bRequestType & USB_DIR_IN) != 0;
if (ep->is_in)
@@ -2458,6 +2472,13 @@
/*-------------------------------------------------------------------------*/
+static void gadget_release (struct device *_dev)
+{
+ struct net2280 *dev = dev_get_drvdata (_dev);
+
+ kfree (dev);
+}
+
/* tear down the binding between this driver and the pci device */
static void net2280_remove (struct pci_dev *pdev)
@@ -2493,12 +2514,12 @@
pci_resource_len (pdev, 0));
if (dev->enabled)
pci_disable_device (pdev);
+ device_unregister (&dev->gadget.dev);
device_remove_file (&pdev->dev, &dev_attr_registers);
pci_set_drvdata (pdev, 0);
- INFO (dev, "unbind from pci %s\n", pci_name(pdev));
+ INFO (dev, "unbind\n");
- kfree (dev);
the_controller = 0;
}
@@ -2518,7 +2539,7 @@
* usb_gadget_driver_{register,unregister}() must change.
*/
if (the_controller) {
- WARN (the_controller, "ignoring %s\n", pci_name(pdev));
+ dev_warn (&pdev->dev, "ignoring\n");
return -EBUSY;
}
@@ -2534,9 +2555,11 @@
dev->pdev = pdev;
dev->gadget.ops = &net2280_ops;
- strcpy (dev->gadget.dev.bus_id, pci_name(pdev));
+ /* the "gadget" abstracts/virtualizes the controller */
+ strcpy (dev->gadget.dev.bus_id, "gadget");
dev->gadget.dev.parent = &pdev->dev;
dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
+ dev->gadget.dev.release = gadget_release;
dev->gadget.name = driver_name;
/* now all the pci goodies ... */
@@ -2650,6 +2673,7 @@
INFO (dev, "version: %s\n", bufp);
the_controller = dev;
+ device_register (&dev->gadget.dev);
device_create_file (&pdev->dev, &dev_attr_registers);
return 0;
