diff options
| author | Johan Hovold <jhovold@gmail.com> | 2013-08-13 07:27:37 -0400 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-08-14 16:51:02 -0400 |
| commit | bad41a5bf1775cdf6026d5a1b233bdc4853f27ca (patch) | |
| tree | f3e75a02337bad3cd38ddfbf8d1fa37290dd9cb7 /drivers/usb/serial | |
| parent | 2fcd1c9b327c23414a5215a0fa53df9d75871a46 (diff) | |
USB: keyspan: fix port DMA-buffer allocations
Make sure port DMA-buffers are allocated separately from containing
structure to prevent potential memory corruption on non-cache-coherent
systems.
Signed-off-by: Johan Hovold <jhovold@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/serial')
| -rw-r--r-- | drivers/usb/serial/keyspan.c | 64 |
1 files changed, 56 insertions, 8 deletions
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index 3d2ce56e1009..e731bbc166a0 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c | |||
| @@ -50,6 +50,10 @@ | |||
| 50 | #define INSTAT_BUFLEN 32 | 50 | #define INSTAT_BUFLEN 32 |
| 51 | #define GLOCONT_BUFLEN 64 | 51 | #define GLOCONT_BUFLEN 64 |
| 52 | #define INDAT49W_BUFLEN 512 | 52 | #define INDAT49W_BUFLEN 512 |
| 53 | #define IN_BUFLEN 64 | ||
| 54 | #define OUT_BUFLEN 64 | ||
| 55 | #define INACK_BUFLEN 1 | ||
| 56 | #define OUTCONT_BUFLEN 64 | ||
| 53 | 57 | ||
| 54 | /* Per device and per port private data */ | 58 | /* Per device and per port private data */ |
| 55 | struct keyspan_serial_private { | 59 | struct keyspan_serial_private { |
| @@ -81,18 +85,18 @@ struct keyspan_port_private { | |||
| 81 | 85 | ||
| 82 | /* Input endpoints and buffer for this port */ | 86 | /* Input endpoints and buffer for this port */ |
| 83 | struct urb *in_urbs[2]; | 87 | struct urb *in_urbs[2]; |
| 84 | char in_buffer[2][64]; | 88 | char *in_buffer[2]; |
| 85 | /* Output endpoints and buffer for this port */ | 89 | /* Output endpoints and buffer for this port */ |
| 86 | struct urb *out_urbs[2]; | 90 | struct urb *out_urbs[2]; |
| 87 | char out_buffer[2][64]; | 91 | char *out_buffer[2]; |
| 88 | 92 | ||
| 89 | /* Input ack endpoint */ | 93 | /* Input ack endpoint */ |
| 90 | struct urb *inack_urb; | 94 | struct urb *inack_urb; |
| 91 | char inack_buffer[1]; | 95 | char *inack_buffer; |
| 92 | 96 | ||
| 93 | /* Output control endpoint */ | 97 | /* Output control endpoint */ |
| 94 | struct urb *outcont_urb; | 98 | struct urb *outcont_urb; |
| 95 | char outcont_buffer[64]; | 99 | char *outcont_buffer; |
| 96 | 100 | ||
| 97 | /* Settings for the port */ | 101 | /* Settings for the port */ |
| 98 | int baud; | 102 | int baud; |
| @@ -2406,6 +2410,26 @@ static int keyspan_port_probe(struct usb_serial_port *port) | |||
| 2406 | if (!p_priv) | 2410 | if (!p_priv) |
| 2407 | return -ENOMEM; | 2411 | return -ENOMEM; |
| 2408 | 2412 | ||
| 2413 | for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i) { | ||
| 2414 | p_priv->in_buffer[i] = kzalloc(IN_BUFLEN, GFP_KERNEL); | ||
| 2415 | if (!p_priv->in_buffer[i]) | ||
| 2416 | goto err_in_buffer; | ||
| 2417 | } | ||
| 2418 | |||
| 2419 | for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i) { | ||
| 2420 | p_priv->out_buffer[i] = kzalloc(OUT_BUFLEN, GFP_KERNEL); | ||
| 2421 | if (!p_priv->out_buffer[i]) | ||
| 2422 | goto err_out_buffer; | ||
| 2423 | } | ||
| 2424 | |||
| 2425 | p_priv->inack_buffer = kzalloc(INACK_BUFLEN, GFP_KERNEL); | ||
| 2426 | if (!p_priv->inack_buffer) | ||
| 2427 | goto err_inack_buffer; | ||
| 2428 | |||
| 2429 | p_priv->outcont_buffer = kzalloc(OUTCONT_BUFLEN, GFP_KERNEL); | ||
| 2430 | if (!p_priv->outcont_buffer) | ||
| 2431 | goto err_outcont_buffer; | ||
| 2432 | |||
| 2409 | p_priv->device_details = d_details; | 2433 | p_priv->device_details = d_details; |
| 2410 | 2434 | ||
| 2411 | /* Setup values for the various callback routines */ | 2435 | /* Setup values for the various callback routines */ |
| @@ -2418,7 +2442,8 @@ static int keyspan_port_probe(struct usb_serial_port *port) | |||
| 2418 | for (i = 0; i <= d_details->indat_endp_flip; ++i, ++endp) { | 2442 | for (i = 0; i <= d_details->indat_endp_flip; ++i, ++endp) { |
| 2419 | p_priv->in_urbs[i] = keyspan_setup_urb(serial, endp, | 2443 | p_priv->in_urbs[i] = keyspan_setup_urb(serial, endp, |
| 2420 | USB_DIR_IN, port, | 2444 | USB_DIR_IN, port, |
| 2421 | p_priv->in_buffer[i], 64, | 2445 | p_priv->in_buffer[i], |
| 2446 | IN_BUFLEN, | ||
| 2422 | cback->indat_callback); | 2447 | cback->indat_callback); |
| 2423 | } | 2448 | } |
| 2424 | /* outdat endpoints also have flip */ | 2449 | /* outdat endpoints also have flip */ |
| @@ -2426,25 +2451,41 @@ static int keyspan_port_probe(struct usb_serial_port *port) | |||
| 2426 | for (i = 0; i <= d_details->outdat_endp_flip; ++i, ++endp) { | 2451 | for (i = 0; i <= d_details->outdat_endp_flip; ++i, ++endp) { |
| 2427 | p_priv->out_urbs[i] = keyspan_setup_urb(serial, endp, | 2452 | p_priv->out_urbs[i] = keyspan_setup_urb(serial, endp, |
| 2428 | USB_DIR_OUT, port, | 2453 | USB_DIR_OUT, port, |
| 2429 | p_priv->out_buffer[i], 64, | 2454 | p_priv->out_buffer[i], |
| 2455 | OUT_BUFLEN, | ||
| 2430 | cback->outdat_callback); | 2456 | cback->outdat_callback); |
| 2431 | } | 2457 | } |
| 2432 | /* inack endpoint */ | 2458 | /* inack endpoint */ |
| 2433 | p_priv->inack_urb = keyspan_setup_urb(serial, | 2459 | p_priv->inack_urb = keyspan_setup_urb(serial, |
| 2434 | d_details->inack_endpoints[port_num], | 2460 | d_details->inack_endpoints[port_num], |
| 2435 | USB_DIR_IN, port, | 2461 | USB_DIR_IN, port, |
| 2436 | p_priv->inack_buffer, 1, | 2462 | p_priv->inack_buffer, |
| 2463 | INACK_BUFLEN, | ||
| 2437 | cback->inack_callback); | 2464 | cback->inack_callback); |
| 2438 | /* outcont endpoint */ | 2465 | /* outcont endpoint */ |
| 2439 | p_priv->outcont_urb = keyspan_setup_urb(serial, | 2466 | p_priv->outcont_urb = keyspan_setup_urb(serial, |
| 2440 | d_details->outcont_endpoints[port_num], | 2467 | d_details->outcont_endpoints[port_num], |
| 2441 | USB_DIR_OUT, port, | 2468 | USB_DIR_OUT, port, |
| 2442 | p_priv->outcont_buffer, 64, | 2469 | p_priv->outcont_buffer, |
| 2470 | OUTCONT_BUFLEN, | ||
| 2443 | cback->outcont_callback); | 2471 | cback->outcont_callback); |
| 2444 | 2472 | ||
| 2445 | usb_set_serial_port_data(port, p_priv); | 2473 | usb_set_serial_port_data(port, p_priv); |
| 2446 | 2474 | ||
| 2447 | return 0; | 2475 | return 0; |
| 2476 | |||
| 2477 | err_outcont_buffer: | ||
| 2478 | kfree(p_priv->inack_buffer); | ||
| 2479 | err_inack_buffer: | ||
| 2480 | for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i) | ||
| 2481 | kfree(p_priv->out_buffer[i]); | ||
| 2482 | err_out_buffer: | ||
| 2483 | for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i) | ||
| 2484 | kfree(p_priv->in_buffer[i]); | ||
| 2485 | err_in_buffer: | ||
| 2486 | kfree(p_priv); | ||
| 2487 | |||
| 2488 | return -ENOMEM; | ||
| 2448 | } | 2489 | } |
| 2449 | 2490 | ||
| 2450 | static int keyspan_port_remove(struct usb_serial_port *port) | 2491 | static int keyspan_port_remove(struct usb_serial_port *port) |
| @@ -2468,6 +2509,13 @@ static int keyspan_port_remove(struct usb_serial_port *port) | |||
| 2468 | usb_free_urb(p_priv->out_urbs[i]); | 2509 | usb_free_urb(p_priv->out_urbs[i]); |
| 2469 | } | 2510 | } |
| 2470 | 2511 | ||
| 2512 | kfree(p_priv->outcont_buffer); | ||
| 2513 | kfree(p_priv->inack_buffer); | ||
| 2514 | for (i = 0; i < ARRAY_SIZE(p_priv->out_buffer); ++i) | ||
| 2515 | kfree(p_priv->out_buffer[i]); | ||
| 2516 | for (i = 0; i < ARRAY_SIZE(p_priv->in_buffer); ++i) | ||
| 2517 | kfree(p_priv->in_buffer[i]); | ||
| 2518 | |||
| 2471 | kfree(p_priv); | 2519 | kfree(p_priv); |
| 2472 | 2520 | ||
| 2473 | return 0; | 2521 | return 0; |
