ChangeSet 1.1276.1.52, 2003/08/27 17:31:43-07:00, david-b@pacbell.net

[PATCH] USB: net2280 fixes: ep halt, sysfs

Small updates:

  - 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.)


 drivers/usb/gadget/net2280.c |   68 +++++++++++++++++++++++++++++--------------
 drivers/usb/gadget/net2280.h |   45 +++++++++++++++++-----------
 2 files changed, 73 insertions(+), 40 deletions(-)


diff -Nru a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
--- a/drivers/usb/gadget/net2280.c	Tue Sep  2 12:43:19 2003
+++ b/drivers/usb/gadget/net2280.c	Tue Sep  2 12:43:19 2003
@@ -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
@@ -77,7 +78,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 */
@@ -1345,11 +1346,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,
@@ -1394,16 +1396,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),
@@ -1797,6 +1816,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);
@@ -1808,10 +1828,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);
 
@@ -1878,10 +1894,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;
 }
@@ -2050,9 +2062,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);
@@ -2175,6 +2187,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)
@@ -2459,6 +2473,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)
@@ -2494,12 +2515,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;
 }
 
@@ -2519,7 +2540,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;
 	}
 
@@ -2535,9 +2556,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 ... */
@@ -2651,6 +2674,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;
diff -Nru a/drivers/usb/gadget/net2280.h b/drivers/usb/gadget/net2280.h
--- a/drivers/usb/gadget/net2280.h	Tue Sep  2 12:43:19 2003
+++ b/drivers/usb/gadget/net2280.h	Tue Sep  2 12:43:19 2003
@@ -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)
 {
@@ -588,6 +575,28 @@
 	struct pci_pool			*requests;
 	// 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
 
