Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Input: synaptics_i2c - switch to using __cancel_delayed_work()

cancel_delayed_work() may spin and therefore should not be used in
interrupt contexts.

Acked-by: Mike Rapoport <mike@compulab.co.il>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

+32 -19
+32 -19
drivers/input/mouse/synaptics_i2c.c
··· 203 203 * and the irq configuration should be set to Falling Edge Trigger 204 204 */ 205 205 /* Control IRQ / Polling option */ 206 - static int polling_req; 206 + static bool polling_req; 207 207 module_param(polling_req, bool, 0444); 208 208 MODULE_PARM_DESC(polling_req, "Request Polling. Default = 0 (use irq)"); 209 209 ··· 217 217 struct i2c_client *client; 218 218 struct input_dev *input; 219 219 struct delayed_work dwork; 220 + spinlock_t lock; 220 221 int no_data_count; 221 222 int no_decel_param; 222 223 int reduce_report_param; ··· 367 366 return xy_delta || gesture; 368 367 } 369 368 369 + static void synaptics_i2c_reschedule_work(struct synaptics_i2c *touch, 370 + unsigned long delay) 371 + { 372 + unsigned long flags; 373 + 374 + spin_lock_irqsave(&touch->lock, flags); 375 + 376 + /* 377 + * If work is already scheduled then subsequent schedules will not 378 + * change the scheduled time that's why we have to cancel it first. 379 + */ 380 + __cancel_delayed_work(&touch->dwork); 381 + schedule_delayed_work(&touch->dwork, delay); 382 + 383 + spin_unlock_irqrestore(&touch->lock, flags); 384 + } 385 + 370 386 static irqreturn_t synaptics_i2c_irq(int irq, void *dev_id) 371 387 { 372 388 struct synaptics_i2c *touch = dev_id; 373 389 374 - /* 375 - * We want to have the work run immediately but it might have 376 - * already been scheduled with a delay, that's why we have to 377 - * cancel it first. 378 - */ 379 - cancel_delayed_work(&touch->dwork); 380 - schedule_delayed_work(&touch->dwork, 0); 390 + synaptics_i2c_reschedule_work(touch, 0); 381 391 382 392 return IRQ_HANDLED; 383 393 } ··· 464 452 * We poll the device once in THREAD_IRQ_SLEEP_SECS and 465 453 * if error is detected, we try to reset and reconfigure the touchpad. 466 454 */ 467 - schedule_delayed_work(&touch->dwork, delay); 455 + synaptics_i2c_reschedule_work(touch, delay); 468 456 } 469 457 470 458 static int synaptics_i2c_open(struct input_dev *input) ··· 477 465 return ret; 478 466 479 467 if (polling_req) 480 - schedule_delayed_work(&touch->dwork, 481 - msecs_to_jiffies(NO_DATA_SLEEP_MSECS)); 468 + synaptics_i2c_reschedule_work(touch, 469 + msecs_to_jiffies(NO_DATA_SLEEP_MSECS)); 482 470 483 471 return 0; 484 472 } ··· 533 521 touch->scan_rate_param = scan_rate; 534 522 set_scan_rate(touch, scan_rate); 535 523 INIT_DELAYED_WORK(&touch->dwork, synaptics_i2c_work_handler); 524 + spin_lock_init(&touch->lock); 536 525 537 526 return touch; 538 527 } ··· 548 535 if (!touch) 549 536 return -ENOMEM; 550 537 551 - i2c_set_clientdata(client, touch); 552 - 553 538 ret = synaptics_i2c_reset_config(client); 554 539 if (ret) 555 540 goto err_mem_free; 556 541 557 542 if (client->irq < 1) 558 - polling_req = 1; 543 + polling_req = true; 559 544 560 545 touch->input = input_allocate_device(); 561 546 if (!touch->input) { ··· 574 563 dev_warn(&touch->client->dev, 575 564 "IRQ request failed: %d, " 576 565 "falling back to polling\n", ret); 577 - polling_req = 1; 566 + polling_req = true; 578 567 synaptics_i2c_reg_set(touch->client, 579 568 INTERRUPT_EN_REG, 0); 580 569 } ··· 591 580 "Input device register failed: %d\n", ret); 592 581 goto err_input_free; 593 582 } 583 + 584 + i2c_set_clientdata(client, touch); 585 + 594 586 return 0; 595 587 596 588 err_input_free: 597 589 input_free_device(touch->input); 598 590 err_mem_free: 599 - i2c_set_clientdata(client, NULL); 600 591 kfree(touch); 601 592 602 593 return ret; ··· 609 596 struct synaptics_i2c *touch = i2c_get_clientdata(client); 610 597 611 598 if (!polling_req) 612 - free_irq(touch->client->irq, touch); 599 + free_irq(client->irq, touch); 613 600 614 601 input_unregister_device(touch->input); 615 602 i2c_set_clientdata(client, NULL); ··· 640 627 if (ret) 641 628 return ret; 642 629 643 - schedule_delayed_work(&touch->dwork, 644 - msecs_to_jiffies(NO_DATA_SLEEP_MSECS)); 630 + synaptics_i2c_reschedule_work(touch, 631 + msecs_to_jiffies(NO_DATA_SLEEP_MSECS)); 645 632 646 633 return 0; 647 634 }