# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
#	           ChangeSet	1.600.1.10 -> 1.600.1.11
#	drivers/usb/host/ohci-hcd.c	1.24    -> 1.25   
#	drivers/usb/core/hcd.c	1.32    -> 1.33   
#	drivers/usb/host/ohci-dbg.c	1.10    -> 1.11   
#	drivers/usb/host/uhci-hcd.c	1.12    -> 1.13   
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/09/04	rmk@arm.linux.org.uk	1.600.1.11
# [PATCH] 2.5.32-usb
# 
# This patch appears not to be in 2.5.32, but applies cleanly.
# 
# The following patch fixes 3 problems in USB:
# 
# 1. Don't pci_map buffers when we know we're not going to pass them
#    to a device.
# 
#    This was first noticed on ARM (no surprises here); the root hub
#    code, rh_call_control(), placed data into the buffer and then
#    called usb_hcd_giveback_urb().  This function called
#    pci_unmap_single() on this region which promptly destroyed the
#    data that rh_call_control() had placed there.  This lead to a
#    corrupted device descriptor and the "too many configurations"
#    message.
# 
# 2. If controller->hcca is NULL, don't try to dereference it.
# 
# 3. If we free the root hub (in ohci-hcd.c or uhci-hcd.c), don't
#    leave a dangling pointer around to trip us up in usb_disconnect().
#    EHCI appears to get this right.
# --------------------------------------------
#
diff -Nru a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
--- a/drivers/usb/core/hcd.c	Thu Sep  5 08:51:07 2002
+++ b/drivers/usb/core/hcd.c	Thu Sep  5 08:51:07 2002
@@ -1020,6 +1020,16 @@
 	if (status)
 		return status;
 
+	/* increment urb's reference count as part of giving it to the HCD
+	 * (which now controls it).  HCD guarantees that it either returns
+	 * an error or calls giveback(), but not both.
+	 */
+	urb = usb_get_urb (urb);
+	if (urb->dev == hcd->self.root_hub) {
+		urb->transfer_flags |= URB_NO_DMA_MAP;
+		return rh_urb_enqueue (hcd, urb);
+	}
+
 	/* lower level hcd code should use *_dma exclusively */
 	if (!(urb->transfer_flags & URB_NO_DMA_MAP)) {
 		if (usb_pipecontrol (urb->pipe))
@@ -1038,16 +1048,7 @@
 					    : PCI_DMA_TODEVICE);
 	}
 
-	/* increment urb's reference count as part of giving it to the HCD
-	 * (which now controls it).  HCD guarantees that it either returns
-	 * an error or calls giveback(), but not both.
-	 */
-	urb = usb_get_urb (urb);
-	if (urb->dev == hcd->self.root_hub)
-		status = rh_urb_enqueue (hcd, urb);
-	else
-		status = hcd->driver->urb_enqueue (hcd, urb, mem_flags);
-	return status;
+	return hcd->driver->urb_enqueue (hcd, urb, mem_flags);
 }
 
 /*-------------------------------------------------------------------------*/
diff -Nru a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c
--- a/drivers/usb/host/ohci-dbg.c	Thu Sep  5 08:51:07 2002
+++ b/drivers/usb/host/ohci-dbg.c	Thu Sep  5 08:51:07 2002
@@ -208,7 +208,8 @@
 	if (verbose)
 		ohci_dump_periodic (controller, "hcca");
 #endif
-	dbg ("hcca frame #%04x", controller->hcca->frame_no);
+	if (controller->hcca)
+		dbg ("hcca frame #%04x", controller->hcca->frame_no);
 	ohci_dump_roothub (controller, 1);
 }
 
diff -Nru a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
--- a/drivers/usb/host/ohci-hcd.c	Thu Sep  5 08:51:07 2002
+++ b/drivers/usb/host/ohci-hcd.c	Thu Sep  5 08:51:07 2002
@@ -519,7 +519,8 @@
 	usb_connect (udev);
 	udev->speed = USB_SPEED_FULL;
 	if (usb_register_root_hub (udev, ohci->parent_dev) != 0) {
-		usb_free_dev (udev); 
+		usb_free_dev (udev);
+		ohci->hcd.self.root_hub = NULL;
 		disable (ohci);
 		ohci->hc_control &= ~OHCI_CTRL_HCFS;
 		writel (ohci->hc_control, &ohci->regs->control);
diff -Nru a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
--- a/drivers/usb/host/uhci-hcd.c	Thu Sep  5 08:51:07 2002
+++ b/drivers/usb/host/uhci-hcd.c	Thu Sep  5 08:51:07 2002
@@ -2329,6 +2329,7 @@
 
 err_alloc_skeltd:
 	usb_free_dev(udev);
+	hcd->self.root_hub = NULL;
 
 err_alloc_root_hub:
 	pci_pool_destroy(uhci->qh_pool);
