ChangeSet 1.1243.50.5, 2003/06/06 15:03:07-07:00, stern@rowland.harvard.edu

[PATCH] USB: Don't allocate transfer buffers on the stack in hub.c

 Allocate hub status input buffers separately and not on the stack.


 drivers/usb/core/hub.c |  100 ++++++++++++++++++++++++++++++++-----------------
 drivers/usb/core/hub.h |    6 ++
 2 files changed, 72 insertions(+), 34 deletions(-)


diff -Nru a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
--- a/drivers/usb/core/hub.c	Tue Jun 10 17:11:57 2003
+++ b/drivers/usb/core/hub.c	Tue Jun 10 17:11:57 2003
@@ -103,21 +103,23 @@
 /*
  * USB 2.0 spec Section 11.24.2.6
  */
-static int usb_get_hub_status(struct usb_device *dev, void *data)
+static int usb_get_hub_status(struct usb_device *dev,
+		struct usb_hub_status *data)
 {
 	return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
 		USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_HUB, 0, 0,
-		data, sizeof(struct usb_hub_status), HZ);
+		data, sizeof(*data), HZ);
 }
 
 /*
  * USB 2.0 spec Section 11.24.2.7
  */
-static int usb_get_port_status(struct usb_device *dev, int port, void *data)
+static int usb_get_port_status(struct usb_device *dev, int port,
+		struct usb_port_status *data)
 {
 	return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
 		USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port,
-		data, sizeof(struct usb_hub_status), HZ);
+		data, sizeof(*data), HZ);
 }
 
 /* completion function, fires on port status changes and various faults */
@@ -272,16 +274,48 @@
 	wait_ms(hub->descriptor->bPwrOn2PwrGood * 2);
 }
 
+static int usb_hub_hub_status(struct usb_hub *hub,
+		u16 *status, u16 *change)
+{
+	struct usb_device *dev = interface_to_usbdev (hub->intf);
+	int ret;
+
+	ret = usb_get_hub_status(dev, &hub->status->hub);
+	if (ret < 0)
+		dev_err (hubdev (dev),
+			"%s failed (err = %d)\n", __FUNCTION__, ret);
+	else {
+		*status = le16_to_cpu(hub->status->hub.wHubStatus);
+		*change = le16_to_cpu(hub->status->hub.wHubChange); 
+		ret = 0;
+	}
+	return ret;
+}
+
 static int usb_hub_configure(struct usb_hub *hub,
 	struct usb_endpoint_descriptor *endpoint)
 {
 	struct usb_device *dev = interface_to_usbdev (hub->intf);
 	struct device *hub_dev;
-	struct usb_hub_status hubstatus;
+	u16 hubstatus, hubchange;
 	unsigned int pipe;
 	int maxp, ret;
 	char *message;
 
+	hub->buffer = kmalloc(sizeof(*hub->buffer), GFP_KERNEL);
+	if (!hub->buffer) {
+		message = "can't kmalloc hub irq buffer";
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	hub->status = kmalloc(sizeof(*hub->status), GFP_KERNEL);
+	if (!hub->status) {
+		message = "can't kmalloc hub status buffer";
+		ret = -ENOMEM;
+		goto fail;
+	}
+
 	hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL);
 	if (!hub->descriptor) {
 		message = "can't kmalloc hub descriptor";
@@ -396,27 +430,25 @@
 	dev_dbg(hub_dev, "hub controller current requirement: %dmA\n",
 		hub->descriptor->bHubContrCurrent);
 
-	ret = usb_get_hub_status(dev, &hubstatus);
+	ret = usb_hub_hub_status(hub, &hubstatus, &hubchange);
 	if (ret < 0) {
 		message = "can't get hub status";
 		goto fail;
 	}
 
-	le16_to_cpus(&hubstatus.wHubStatus);
-
 	dev_dbg(hub_dev, "local power source is %s\n",
-		(hubstatus.wHubStatus & HUB_STATUS_LOCAL_POWER)
+		(hubstatus & HUB_STATUS_LOCAL_POWER)
 		? "lost (inactive)" : "good");
 
 	dev_dbg(hub_dev, "%sover-current condition exists\n",
-		(hubstatus.wHubStatus & HUB_STATUS_OVERCURRENT) ? "" : "no ");
+		(hubstatus & HUB_STATUS_OVERCURRENT) ? "" : "no ");
 
 	/* Start the interrupt endpoint */
 	pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
 	maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
 
-	if (maxp > sizeof(hub->buffer))
-		maxp = sizeof(hub->buffer);
+	if (maxp > sizeof(*hub->buffer))
+		maxp = sizeof(*hub->buffer);
 
 	hub->urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!hub->urb) {
@@ -425,7 +457,7 @@
 		goto fail;
 	}
 
-	usb_fill_int_urb(hub->urb, dev, pipe, hub->buffer, maxp, hub_irq,
+	usb_fill_int_urb(hub->urb, dev, pipe, *hub->buffer, maxp, hub_irq,
 		hub, endpoint->bInterval);
 	ret = usb_submit_urb(hub->urb, GFP_KERNEL);
 	if (ret) {
@@ -484,6 +516,16 @@
 		hub->descriptor = NULL;
 	}
 
+	if (hub->status) {
+		kfree(hub->status);
+		hub->status = NULL;
+	}
+
+	if (hub->buffer) {
+		kfree(hub->buffer);
+		hub->buffer = NULL;
+	}
+
 	/* Free the memory */
 	kfree(hub);
 }
@@ -641,25 +683,20 @@
 	err("cannot disconnect hub %s", dev->devpath);
 }
 
-static int usb_hub_port_status(struct usb_device *hub, int port,
+static int usb_hub_port_status(struct usb_device *dev, int port,
 			       u16 *status, u16 *change)
 {
-	struct usb_port_status *portsts;
-	int ret = -ENOMEM;
+	struct usb_hub *hub = usb_get_intfdata (dev->actconfig->interface);
+	int ret;
 
-	portsts = kmalloc(sizeof(*portsts), GFP_NOIO);
-	if (portsts) {
-		ret = usb_get_port_status(hub, port + 1, portsts);
-		if (ret < 0)
-			dev_err (hubdev (hub),
-				"%s failed (err = %d)\n", __FUNCTION__,
-				ret);
-		else {
-			*status = le16_to_cpu(portsts->wPortStatus);
-			*change = le16_to_cpu(portsts->wPortChange); 
-			ret = 0;
-		}
-		kfree(portsts);
+	ret = usb_get_port_status(dev, port + 1, &hub->status->port);
+	if (ret < 0)
+		dev_err (hubdev (dev),
+			"%s failed (err = %d)\n", __FUNCTION__, ret);
+	else {
+		*status = le16_to_cpu(hub->status->port.wPortStatus);
+		*change = le16_to_cpu(hub->status->port.wPortChange); 
+		ret = 0;
 	}
 	return ret;
 }
@@ -955,7 +992,6 @@
 	struct list_head *tmp;
 	struct usb_device *dev;
 	struct usb_hub *hub;
-	struct usb_hub_status hubsts;
 	u16 hubstatus;
 	u16 hubchange;
 	u16 portstatus;
@@ -1064,11 +1100,9 @@
 		} /* end for i */
 
 		/* deal with hub status changes */
-		if (usb_get_hub_status(dev, &hubsts) < 0)
+		if (usb_hub_hub_status(hub, &hubstatus, &hubchange) < 0)
 			dev_err (&hub->intf->dev, "get_hub_status failed\n");
 		else {
-			hubstatus = le16_to_cpup(&hubsts.wHubStatus);
-			hubchange = le16_to_cpup(&hubsts.wHubChange);
 			if (hubchange & HUB_CHANGE_LOCAL_POWER) {
 				dev_dbg (&hub->intf->dev, "power change\n");
 				usb_clear_hub_feature(dev, C_HUB_LOCAL_POWER);
diff -Nru a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h
--- a/drivers/usb/core/hub.h	Tue Jun 10 17:11:57 2003
+++ b/drivers/usb/core/hub.h	Tue Jun 10 17:11:57 2003
@@ -174,7 +174,11 @@
 	struct urb		*urb;		/* for interrupt polling pipe */
 
 	/* buffer for urb ... 1 bit each for hub and children, rounded up */
-	char			buffer[(USB_MAXCHILDREN + 1 + 7) / 8];
+	char			(*buffer)[(USB_MAXCHILDREN + 1 + 7) / 8];
+	union {
+		struct usb_hub_status	hub;
+		struct usb_port_status	port;
+	}			*status;	/* buffer for status reports */
 
 	int			error;		/* last reported error */
 	int			nerrors;	/* track consecutive errors */
