aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorJohan Hovold <jhovold@gmail.com>2012-10-25 12:56:34 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-10-25 14:11:19 -0400
commit80c00750f0c9867a65b30a17880939b6bc660a77 (patch)
treeb8bc2072f4df67ad5889b95fc19957b4af466ee0 /drivers
parente681b66f2e19fadbe8a7e2a17900978cb6bc921f (diff)
USB: mos7840: fix port-data memory leak
Fix port-data memory leak by moving port data allocation and deallocation to port_probe and port_remove. Since commit 0998d0631001288 (device-core: Ensure drvdata = NULL when no driver is bound) the port private data is no longer freed at release as it is no longer accessible. Note that the indentation was kept intact using a do-while(0) in order to facilitate review. A follow-up patch will remove it. Compile-only tested. Signed-off-by: Johan Hovold <jhovold@gmail.com> Cc: stable <stable@vger.kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/serial/mos7840.c219
1 files changed, 89 insertions, 130 deletions
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 84f8c106e5e9..bc3df86134fe 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -2327,49 +2327,45 @@ static int mos7840_calc_num_ports(struct usb_serial *serial)
2327 return mos7840_num_ports; 2327 return mos7840_num_ports;
2328} 2328}
2329 2329
2330/**************************************************************************** 2330static int mos7840_port_probe(struct usb_serial_port *port)
2331 * mos7840_startup
2332 ****************************************************************************/
2333
2334static int mos7840_startup(struct usb_serial *serial)
2335{ 2331{
2332 struct usb_serial *serial = port->serial;
2336 struct moschip_port *mos7840_port; 2333 struct moschip_port *mos7840_port;
2337 struct usb_device *dev; 2334 int status;
2338 int i, status; 2335 int pnum;
2339 __u16 Data; 2336 __u16 Data;
2340 2337
2341 dev = serial->dev;
2342
2343 /* we set up the pointers to the endpoints in the mos7840_open * 2338 /* we set up the pointers to the endpoints in the mos7840_open *
2344 * function, as the structures aren't created yet. */ 2339 * function, as the structures aren't created yet. */
2345 2340
2346 /* set up port private structures */ 2341 pnum = port->number - serial->minor;
2347 for (i = 0; i < serial->num_ports; ++i) { 2342
2348 dev_dbg(&dev->dev, "mos7840_startup: configuring port %d............\n", i); 2343 /* FIXME: remove do-while(0) loop used to keep stable patch minimal.
2344 */
2345 do {
2346 dev_dbg(&port->dev, "mos7840_startup: configuring port %d............\n", pnum);
2349 mos7840_port = kzalloc(sizeof(struct moschip_port), GFP_KERNEL); 2347 mos7840_port = kzalloc(sizeof(struct moschip_port), GFP_KERNEL);
2350 if (mos7840_port == NULL) { 2348 if (mos7840_port == NULL) {
2351 dev_err(&dev->dev, "%s - Out of memory\n", __func__); 2349 dev_err(&port->dev, "%s - Out of memory\n", __func__);
2352 status = -ENOMEM; 2350 return -ENOMEM;
2353 i--; /* don't follow NULL pointer cleaning up */
2354 goto error;
2355 } 2351 }
2356 2352
2357 /* Initialize all port interrupt end point to port 0 int 2353 /* Initialize all port interrupt end point to port 0 int
2358 * endpoint. Our device has only one interrupt end point 2354 * endpoint. Our device has only one interrupt end point
2359 * common to all port */ 2355 * common to all port */
2360 2356
2361 mos7840_port->port = serial->port[i]; 2357 mos7840_port->port = port;
2362 mos7840_set_port_private(serial->port[i], mos7840_port); 2358 mos7840_set_port_private(port, mos7840_port);
2363 spin_lock_init(&mos7840_port->pool_lock); 2359 spin_lock_init(&mos7840_port->pool_lock);
2364 2360
2365 /* minor is not initialised until later by 2361 /* minor is not initialised until later by
2366 * usb-serial.c:get_free_serial() and cannot therefore be used 2362 * usb-serial.c:get_free_serial() and cannot therefore be used
2367 * to index device instances */ 2363 * to index device instances */
2368 mos7840_port->port_num = i + 1; 2364 mos7840_port->port_num = pnum + 1;
2369 dev_dbg(&dev->dev, "serial->port[i]->number = %d\n", serial->port[i]->number); 2365 dev_dbg(&port->dev, "port->number = %d\n", port->number);
2370 dev_dbg(&dev->dev, "serial->port[i]->serial->minor = %d\n", serial->port[i]->serial->minor); 2366 dev_dbg(&port->dev, "port->serial->minor = %d\n", port->serial->minor);
2371 dev_dbg(&dev->dev, "mos7840_port->port_num = %d\n", mos7840_port->port_num); 2367 dev_dbg(&port->dev, "mos7840_port->port_num = %d\n", mos7840_port->port_num);
2372 dev_dbg(&dev->dev, "serial->minor = %d\n", serial->minor); 2368 dev_dbg(&port->dev, "serial->minor = %d\n", serial->minor);
2373 2369
2374 if (mos7840_port->port_num == 1) { 2370 if (mos7840_port->port_num == 1) {
2375 mos7840_port->SpRegOffset = 0x0; 2371 mos7840_port->SpRegOffset = 0x0;
@@ -2396,115 +2392,115 @@ static int mos7840_startup(struct usb_serial *serial)
2396 mos7840_port->ControlRegOffset = 0xd; 2392 mos7840_port->ControlRegOffset = 0xd;
2397 mos7840_port->DcrRegOffset = 0x1c; 2393 mos7840_port->DcrRegOffset = 0x1c;
2398 } 2394 }
2399 mos7840_dump_serial_port(serial->port[i], mos7840_port); 2395 mos7840_dump_serial_port(port, mos7840_port);
2400 mos7840_set_port_private(serial->port[i], mos7840_port); 2396 mos7840_set_port_private(port, mos7840_port);
2401 2397
2402 /* enable rx_disable bit in control register */ 2398 /* enable rx_disable bit in control register */
2403 status = mos7840_get_reg_sync(serial->port[i], 2399 status = mos7840_get_reg_sync(port,
2404 mos7840_port->ControlRegOffset, &Data); 2400 mos7840_port->ControlRegOffset, &Data);
2405 if (status < 0) { 2401 if (status < 0) {
2406 dev_dbg(&dev->dev, "Reading ControlReg failed status-0x%x\n", status); 2402 dev_dbg(&port->dev, "Reading ControlReg failed status-0x%x\n", status);
2407 break; 2403 break;
2408 } else 2404 } else
2409 dev_dbg(&dev->dev, "ControlReg Reading success val is %x, status%d\n", Data, status); 2405 dev_dbg(&port->dev, "ControlReg Reading success val is %x, status%d\n", Data, status);
2410 Data |= 0x08; /* setting driver done bit */ 2406 Data |= 0x08; /* setting driver done bit */
2411 Data |= 0x04; /* sp1_bit to have cts change reflect in 2407 Data |= 0x04; /* sp1_bit to have cts change reflect in
2412 modem status reg */ 2408 modem status reg */
2413 2409
2414 /* Data |= 0x20; //rx_disable bit */ 2410 /* Data |= 0x20; //rx_disable bit */
2415 status = mos7840_set_reg_sync(serial->port[i], 2411 status = mos7840_set_reg_sync(port,
2416 mos7840_port->ControlRegOffset, Data); 2412 mos7840_port->ControlRegOffset, Data);
2417 if (status < 0) { 2413 if (status < 0) {
2418 dev_dbg(&dev->dev, "Writing ControlReg failed(rx_disable) status-0x%x\n", status); 2414 dev_dbg(&port->dev, "Writing ControlReg failed(rx_disable) status-0x%x\n", status);
2419 break; 2415 break;
2420 } else 2416 } else
2421 dev_dbg(&dev->dev, "ControlReg Writing success(rx_disable) status%d\n", status); 2417 dev_dbg(&port->dev, "ControlReg Writing success(rx_disable) status%d\n", status);
2422 2418
2423 /* Write default values in DCR (i.e 0x01 in DCR0, 0x05 in DCR2 2419 /* Write default values in DCR (i.e 0x01 in DCR0, 0x05 in DCR2
2424 and 0x24 in DCR3 */ 2420 and 0x24 in DCR3 */
2425 Data = 0x01; 2421 Data = 0x01;
2426 status = mos7840_set_reg_sync(serial->port[i], 2422 status = mos7840_set_reg_sync(port,
2427 (__u16) (mos7840_port->DcrRegOffset + 0), Data); 2423 (__u16) (mos7840_port->DcrRegOffset + 0), Data);
2428 if (status < 0) { 2424 if (status < 0) {
2429 dev_dbg(&dev->dev, "Writing DCR0 failed status-0x%x\n", status); 2425 dev_dbg(&port->dev, "Writing DCR0 failed status-0x%x\n", status);
2430 break; 2426 break;
2431 } else 2427 } else
2432 dev_dbg(&dev->dev, "DCR0 Writing success status%d\n", status); 2428 dev_dbg(&port->dev, "DCR0 Writing success status%d\n", status);
2433 2429
2434 Data = 0x05; 2430 Data = 0x05;
2435 status = mos7840_set_reg_sync(serial->port[i], 2431 status = mos7840_set_reg_sync(port,
2436 (__u16) (mos7840_port->DcrRegOffset + 1), Data); 2432 (__u16) (mos7840_port->DcrRegOffset + 1), Data);
2437 if (status < 0) { 2433 if (status < 0) {
2438 dev_dbg(&dev->dev, "Writing DCR1 failed status-0x%x\n", status); 2434 dev_dbg(&port->dev, "Writing DCR1 failed status-0x%x\n", status);
2439 break; 2435 break;
2440 } else 2436 } else
2441 dev_dbg(&dev->dev, "DCR1 Writing success status%d\n", status); 2437 dev_dbg(&port->dev, "DCR1 Writing success status%d\n", status);
2442 2438
2443 Data = 0x24; 2439 Data = 0x24;
2444 status = mos7840_set_reg_sync(serial->port[i], 2440 status = mos7840_set_reg_sync(port,
2445 (__u16) (mos7840_port->DcrRegOffset + 2), Data); 2441 (__u16) (mos7840_port->DcrRegOffset + 2), Data);
2446 if (status < 0) { 2442 if (status < 0) {
2447 dev_dbg(&dev->dev, "Writing DCR2 failed status-0x%x\n", status); 2443 dev_dbg(&port->dev, "Writing DCR2 failed status-0x%x\n", status);
2448 break; 2444 break;
2449 } else 2445 } else
2450 dev_dbg(&dev->dev, "DCR2 Writing success status%d\n", status); 2446 dev_dbg(&port->dev, "DCR2 Writing success status%d\n", status);
2451 2447
2452 /* write values in clkstart0x0 and clkmulti 0x20 */ 2448 /* write values in clkstart0x0 and clkmulti 0x20 */
2453 Data = 0x0; 2449 Data = 0x0;
2454 status = mos7840_set_reg_sync(serial->port[i], 2450 status = mos7840_set_reg_sync(port,
2455 CLK_START_VALUE_REGISTER, Data); 2451 CLK_START_VALUE_REGISTER, Data);
2456 if (status < 0) { 2452 if (status < 0) {
2457 dev_dbg(&dev->dev, "Writing CLK_START_VALUE_REGISTER failed status-0x%x\n", status); 2453 dev_dbg(&port->dev, "Writing CLK_START_VALUE_REGISTER failed status-0x%x\n", status);
2458 break; 2454 break;
2459 } else 2455 } else
2460 dev_dbg(&dev->dev, "CLK_START_VALUE_REGISTER Writing success status%d\n", status); 2456 dev_dbg(&port->dev, "CLK_START_VALUE_REGISTER Writing success status%d\n", status);
2461 2457
2462 Data = 0x20; 2458 Data = 0x20;
2463 status = mos7840_set_reg_sync(serial->port[i], 2459 status = mos7840_set_reg_sync(port,
2464 CLK_MULTI_REGISTER, Data); 2460 CLK_MULTI_REGISTER, Data);
2465 if (status < 0) { 2461 if (status < 0) {
2466 dev_dbg(&dev->dev, "Writing CLK_MULTI_REGISTER failed status-0x%x\n", status); 2462 dev_dbg(&port->dev, "Writing CLK_MULTI_REGISTER failed status-0x%x\n", status);
2467 goto error; 2463 goto error;
2468 } else 2464 } else
2469 dev_dbg(&dev->dev, "CLK_MULTI_REGISTER Writing success status%d\n", status); 2465 dev_dbg(&port->dev, "CLK_MULTI_REGISTER Writing success status%d\n", status);
2470 2466
2471 /* write value 0x0 to scratchpad register */ 2467 /* write value 0x0 to scratchpad register */
2472 Data = 0x00; 2468 Data = 0x00;
2473 status = mos7840_set_uart_reg(serial->port[i], 2469 status = mos7840_set_uart_reg(port,
2474 SCRATCH_PAD_REGISTER, Data); 2470 SCRATCH_PAD_REGISTER, Data);
2475 if (status < 0) { 2471 if (status < 0) {
2476 dev_dbg(&dev->dev, "Writing SCRATCH_PAD_REGISTER failed status-0x%x\n", status); 2472 dev_dbg(&port->dev, "Writing SCRATCH_PAD_REGISTER failed status-0x%x\n", status);
2477 break; 2473 break;
2478 } else 2474 } else
2479 dev_dbg(&dev->dev, "SCRATCH_PAD_REGISTER Writing success status%d\n", status); 2475 dev_dbg(&port->dev, "SCRATCH_PAD_REGISTER Writing success status%d\n", status);
2480 2476
2481 /* Zero Length flag register */ 2477 /* Zero Length flag register */
2482 if ((mos7840_port->port_num != 1) 2478 if ((mos7840_port->port_num != 1)
2483 && (serial->num_ports == 2)) { 2479 && (serial->num_ports == 2)) {
2484 2480
2485 Data = 0xff; 2481 Data = 0xff;
2486 status = mos7840_set_reg_sync(serial->port[i], 2482 status = mos7840_set_reg_sync(port,
2487 (__u16) (ZLP_REG1 + 2483 (__u16) (ZLP_REG1 +
2488 ((__u16)mos7840_port->port_num)), Data); 2484 ((__u16)mos7840_port->port_num)), Data);
2489 dev_dbg(&dev->dev, "ZLIP offset %x\n", 2485 dev_dbg(&port->dev, "ZLIP offset %x\n",
2490 (__u16)(ZLP_REG1 + ((__u16) mos7840_port->port_num))); 2486 (__u16)(ZLP_REG1 + ((__u16) mos7840_port->port_num)));
2491 if (status < 0) { 2487 if (status < 0) {
2492 dev_dbg(&dev->dev, "Writing ZLP_REG%d failed status-0x%x\n", i + 2, status); 2488 dev_dbg(&port->dev, "Writing ZLP_REG%d failed status-0x%x\n", pnum + 2, status);
2493 break; 2489 break;
2494 } else 2490 } else
2495 dev_dbg(&dev->dev, "ZLP_REG%d Writing success status%d\n", i + 2, status); 2491 dev_dbg(&port->dev, "ZLP_REG%d Writing success status%d\n", pnum + 2, status);
2496 } else { 2492 } else {
2497 Data = 0xff; 2493 Data = 0xff;
2498 status = mos7840_set_reg_sync(serial->port[i], 2494 status = mos7840_set_reg_sync(port,
2499 (__u16) (ZLP_REG1 + 2495 (__u16) (ZLP_REG1 +
2500 ((__u16)mos7840_port->port_num) - 0x1), Data); 2496 ((__u16)mos7840_port->port_num) - 0x1), Data);
2501 dev_dbg(&dev->dev, "ZLIP offset %x\n", 2497 dev_dbg(&port->dev, "ZLIP offset %x\n",
2502 (__u16)(ZLP_REG1 + ((__u16) mos7840_port->port_num) - 0x1)); 2498 (__u16)(ZLP_REG1 + ((__u16) mos7840_port->port_num) - 0x1));
2503 if (status < 0) { 2499 if (status < 0) {
2504 dev_dbg(&dev->dev, "Writing ZLP_REG%d failed status-0x%x\n", i + 1, status); 2500 dev_dbg(&port->dev, "Writing ZLP_REG%d failed status-0x%x\n", pnum + 1, status);
2505 break; 2501 break;
2506 } else 2502 } else
2507 dev_dbg(&dev->dev, "ZLP_REG%d Writing success status%d\n", i + 1, status); 2503 dev_dbg(&port->dev, "ZLP_REG%d Writing success status%d\n", pnum + 1, status);
2508 2504
2509 } 2505 }
2510 mos7840_port->control_urb = usb_alloc_urb(0, GFP_KERNEL); 2506 mos7840_port->control_urb = usb_alloc_urb(0, GFP_KERNEL);
@@ -2541,92 +2537,56 @@ static int mos7840_startup(struct usb_serial *serial)
2541 mos7840_port->led_flag = false; 2537 mos7840_port->led_flag = false;
2542 2538
2543 /* Turn off LED */ 2539 /* Turn off LED */
2544 mos7840_set_led_sync(serial->port[i], 2540 mos7840_set_led_sync(port,
2545 MODEM_CONTROL_REGISTER, 0x0300); 2541 MODEM_CONTROL_REGISTER, 0x0300);
2546 } 2542 }
2547 } 2543 } while (0);
2548 2544
2549 /* Zero Length flag enable */ 2545 if (pnum == serial->num_ports - 1) {
2550 Data = 0x0f; 2546 /* Zero Length flag enable */
2551 status = mos7840_set_reg_sync(serial->port[0], ZLP_REG5, Data); 2547 Data = 0x0f;
2552 if (status < 0) { 2548 status = mos7840_set_reg_sync(serial->port[0], ZLP_REG5, Data);
2553 dev_dbg(&dev->dev, "Writing ZLP_REG5 failed status-0x%x\n", status); 2549 if (status < 0) {
2554 goto error; 2550 dev_dbg(&port->dev, "Writing ZLP_REG5 failed status-0x%x\n", status);
2555 } else 2551 goto error;
2556 dev_dbg(&dev->dev, "ZLP_REG5 Writing success status%d\n", status); 2552 } else
2557 2553 dev_dbg(&port->dev, "ZLP_REG5 Writing success status%d\n", status);
2558 /* setting configuration feature to one */ 2554
2559 usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 2555 /* setting configuration feature to one */
2560 (__u8) 0x03, 0x00, 0x01, 0x00, NULL, 0x00, MOS_WDR_TIMEOUT); 2556 usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
2557 0x03, 0x00, 0x01, 0x00, NULL, 0x00,
2558 MOS_WDR_TIMEOUT);
2559 }
2561 return 0; 2560 return 0;
2562error: 2561error:
2563 for (/* nothing */; i >= 0; i--) { 2562 kfree(mos7840_port->dr);
2564 mos7840_port = mos7840_get_port_private(serial->port[i]); 2563 kfree(mos7840_port->ctrl_buf);
2564 usb_free_urb(mos7840_port->control_urb);
2565 kfree(mos7840_port);
2565 2566
2566 kfree(mos7840_port->dr);
2567 kfree(mos7840_port->ctrl_buf);
2568 usb_free_urb(mos7840_port->control_urb);
2569 kfree(mos7840_port);
2570 }
2571 return status; 2567 return status;
2572} 2568}
2573 2569
2574/**************************************************************************** 2570static int mos7840_port_remove(struct usb_serial_port *port)
2575 * mos7840_disconnect
2576 * This function is called whenever the device is removed from the usb bus.
2577 ****************************************************************************/
2578
2579static void mos7840_disconnect(struct usb_serial *serial)
2580{ 2571{
2581 int i;
2582 unsigned long flags;
2583 struct moschip_port *mos7840_port; 2572 struct moschip_port *mos7840_port;
2584 2573
2585 /* check for the ports to be closed,close the ports and disconnect */ 2574 mos7840_port = mos7840_get_port_private(port);
2586 2575
2587 /* free private structure allocated for serial port * 2576 if (mos7840_port->has_led) {
2588 * stop reads and writes on all ports */ 2577 /* Turn off LED */
2578 mos7840_set_led_sync(port, MODEM_CONTROL_REGISTER, 0x0300);
2589 2579
2590 for (i = 0; i < serial->num_ports; ++i) { 2580 del_timer_sync(&mos7840_port->led_timer1);
2591 mos7840_port = mos7840_get_port_private(serial->port[i]); 2581 del_timer_sync(&mos7840_port->led_timer2);
2592 if (mos7840_port) {
2593 usb_kill_urb(mos7840_port->control_urb);
2594 }
2595 } 2582 }
2596} 2583 usb_kill_urb(mos7840_port->control_urb);
2597 2584 usb_free_urb(mos7840_port->control_urb);
2598/**************************************************************************** 2585 kfree(mos7840_port->ctrl_buf);
2599 * mos7840_release 2586 kfree(mos7840_port->dr);
2600 * This function is called when the usb_serial structure is freed. 2587 kfree(mos7840_port);
2601 ****************************************************************************/
2602
2603static void mos7840_release(struct usb_serial *serial)
2604{
2605 int i;
2606 struct moschip_port *mos7840_port;
2607 2588
2608 /* check for the ports to be closed,close the ports and disconnect */ 2589 return 0;
2609
2610 /* free private structure allocated for serial port *
2611 * stop reads and writes on all ports */
2612
2613 for (i = 0; i < serial->num_ports; ++i) {
2614 mos7840_port = mos7840_get_port_private(serial->port[i]);
2615 if (mos7840_port) {
2616 if (mos7840_port->has_led) {
2617 /* Turn off LED */
2618 mos7840_set_led_sync(mos7840_port->port,
2619 MODEM_CONTROL_REGISTER, 0x0300);
2620
2621 del_timer_sync(&mos7840_port->led_timer1);
2622 del_timer_sync(&mos7840_port->led_timer2);
2623 }
2624 usb_free_urb(mos7840_port->control_urb);
2625 kfree(mos7840_port->ctrl_buf);
2626 kfree(mos7840_port->dr);
2627 kfree(mos7840_port);
2628 }
2629 }
2630} 2590}
2631 2591
2632static struct usb_serial_driver moschip7840_4port_device = { 2592static struct usb_serial_driver moschip7840_4port_device = {
@@ -2654,9 +2614,8 @@ static struct usb_serial_driver moschip7840_4port_device = {
2654 .tiocmget = mos7840_tiocmget, 2614 .tiocmget = mos7840_tiocmget,
2655 .tiocmset = mos7840_tiocmset, 2615 .tiocmset = mos7840_tiocmset,
2656 .get_icount = mos7840_get_icount, 2616 .get_icount = mos7840_get_icount,
2657 .attach = mos7840_startup, 2617 .port_probe = mos7840_port_probe,
2658 .disconnect = mos7840_disconnect, 2618 .port_remove = mos7840_port_remove,
2659 .release = mos7840_release,
2660 .read_bulk_callback = mos7840_bulk_in_callback, 2619 .read_bulk_callback = mos7840_bulk_in_callback,
2661 .read_int_callback = mos7840_interrupt_callback, 2620 .read_int_callback = mos7840_interrupt_callback,
2662}; 2621};