Commit abea87bc authored by Alan Stern's avatar Alan Stern Committed by Linus Torvalds

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

 Allocate hub status input buffers separately and not on the stack.
parent cd83bdb4
...@@ -103,21 +103,23 @@ static int usb_set_port_feature(struct usb_device *dev, int port, int feature) ...@@ -103,21 +103,23 @@ static int usb_set_port_feature(struct usb_device *dev, int port, int feature)
/* /*
* USB 2.0 spec Section 11.24.2.6 * 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), return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_HUB, 0, 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 * 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), return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port, 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 */ /* completion function, fires on port status changes and various faults */
...@@ -272,16 +274,48 @@ static void usb_hub_power_on(struct usb_hub *hub) ...@@ -272,16 +274,48 @@ static void usb_hub_power_on(struct usb_hub *hub)
wait_ms(hub->descriptor->bPwrOn2PwrGood * 2); 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, static int usb_hub_configure(struct usb_hub *hub,
struct usb_endpoint_descriptor *endpoint) struct usb_endpoint_descriptor *endpoint)
{ {
struct usb_device *dev = interface_to_usbdev (hub->intf); struct usb_device *dev = interface_to_usbdev (hub->intf);
struct device *hub_dev; struct device *hub_dev;
struct usb_hub_status hubstatus; u16 hubstatus, hubchange;
unsigned int pipe; unsigned int pipe;
int maxp, ret; int maxp, ret;
char *message; 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); hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL);
if (!hub->descriptor) { if (!hub->descriptor) {
message = "can't kmalloc hub descriptor"; message = "can't kmalloc hub descriptor";
...@@ -396,27 +430,25 @@ static int usb_hub_configure(struct usb_hub *hub, ...@@ -396,27 +430,25 @@ static int usb_hub_configure(struct usb_hub *hub,
dev_dbg(hub_dev, "hub controller current requirement: %dmA\n", dev_dbg(hub_dev, "hub controller current requirement: %dmA\n",
hub->descriptor->bHubContrCurrent); hub->descriptor->bHubContrCurrent);
ret = usb_get_hub_status(dev, &hubstatus); ret = usb_hub_hub_status(hub, &hubstatus, &hubchange);
if (ret < 0) { if (ret < 0) {
message = "can't get hub status"; message = "can't get hub status";
goto fail; goto fail;
} }
le16_to_cpus(&hubstatus.wHubStatus);
dev_dbg(hub_dev, "local power source is %s\n", dev_dbg(hub_dev, "local power source is %s\n",
(hubstatus.wHubStatus & HUB_STATUS_LOCAL_POWER) (hubstatus & HUB_STATUS_LOCAL_POWER)
? "lost (inactive)" : "good"); ? "lost (inactive)" : "good");
dev_dbg(hub_dev, "%sover-current condition exists\n", dev_dbg(hub_dev, "%sover-current condition exists\n",
(hubstatus.wHubStatus & HUB_STATUS_OVERCURRENT) ? "" : "no "); (hubstatus & HUB_STATUS_OVERCURRENT) ? "" : "no ");
/* Start the interrupt endpoint */ /* Start the interrupt endpoint */
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
if (maxp > sizeof(hub->buffer)) if (maxp > sizeof(*hub->buffer))
maxp = sizeof(hub->buffer); maxp = sizeof(*hub->buffer);
hub->urb = usb_alloc_urb(0, GFP_KERNEL); hub->urb = usb_alloc_urb(0, GFP_KERNEL);
if (!hub->urb) { if (!hub->urb) {
...@@ -425,7 +457,7 @@ static int usb_hub_configure(struct usb_hub *hub, ...@@ -425,7 +457,7 @@ static int usb_hub_configure(struct usb_hub *hub,
goto fail; 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); hub, endpoint->bInterval);
ret = usb_submit_urb(hub->urb, GFP_KERNEL); ret = usb_submit_urb(hub->urb, GFP_KERNEL);
if (ret) { if (ret) {
...@@ -484,6 +516,16 @@ static void hub_disconnect(struct usb_interface *intf) ...@@ -484,6 +516,16 @@ static void hub_disconnect(struct usb_interface *intf)
hub->descriptor = NULL; hub->descriptor = NULL;
} }
if (hub->status) {
kfree(hub->status);
hub->status = NULL;
}
if (hub->buffer) {
kfree(hub->buffer);
hub->buffer = NULL;
}
/* Free the memory */ /* Free the memory */
kfree(hub); kfree(hub);
} }
...@@ -641,25 +683,20 @@ static void usb_hub_disconnect(struct usb_device *dev) ...@@ -641,25 +683,20 @@ static void usb_hub_disconnect(struct usb_device *dev)
err("cannot disconnect hub %s", dev->devpath); 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) u16 *status, u16 *change)
{ {
struct usb_port_status *portsts; struct usb_hub *hub = usb_get_intfdata (dev->actconfig->interface);
int ret = -ENOMEM; int ret;
portsts = kmalloc(sizeof(*portsts), GFP_NOIO); ret = usb_get_port_status(dev, port + 1, &hub->status->port);
if (portsts) { if (ret < 0)
ret = usb_get_port_status(hub, port + 1, portsts); dev_err (hubdev (dev),
if (ret < 0) "%s failed (err = %d)\n", __FUNCTION__, ret);
dev_err (hubdev (hub), else {
"%s failed (err = %d)\n", __FUNCTION__, *status = le16_to_cpu(hub->status->port.wPortStatus);
ret); *change = le16_to_cpu(hub->status->port.wPortChange);
else { ret = 0;
*status = le16_to_cpu(portsts->wPortStatus);
*change = le16_to_cpu(portsts->wPortChange);
ret = 0;
}
kfree(portsts);
} }
return ret; return ret;
} }
...@@ -955,7 +992,6 @@ static void usb_hub_events(void) ...@@ -955,7 +992,6 @@ static void usb_hub_events(void)
struct list_head *tmp; struct list_head *tmp;
struct usb_device *dev; struct usb_device *dev;
struct usb_hub *hub; struct usb_hub *hub;
struct usb_hub_status hubsts;
u16 hubstatus; u16 hubstatus;
u16 hubchange; u16 hubchange;
u16 portstatus; u16 portstatus;
...@@ -1064,11 +1100,9 @@ static void usb_hub_events(void) ...@@ -1064,11 +1100,9 @@ static void usb_hub_events(void)
} /* end for i */ } /* end for i */
/* deal with hub status changes */ /* 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"); dev_err (&hub->intf->dev, "get_hub_status failed\n");
else { else {
hubstatus = le16_to_cpup(&hubsts.wHubStatus);
hubchange = le16_to_cpup(&hubsts.wHubChange);
if (hubchange & HUB_CHANGE_LOCAL_POWER) { if (hubchange & HUB_CHANGE_LOCAL_POWER) {
dev_dbg (&hub->intf->dev, "power change\n"); dev_dbg (&hub->intf->dev, "power change\n");
usb_clear_hub_feature(dev, C_HUB_LOCAL_POWER); usb_clear_hub_feature(dev, C_HUB_LOCAL_POWER);
......
...@@ -174,7 +174,11 @@ struct usb_hub { ...@@ -174,7 +174,11 @@ struct usb_hub {
struct urb *urb; /* for interrupt polling pipe */ struct urb *urb; /* for interrupt polling pipe */
/* buffer for urb ... 1 bit each for hub and children, rounded up */ /* 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 error; /* last reported error */
int nerrors; /* track consecutive errors */ int nerrors; /* track consecutive errors */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment