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 */