diff options
Diffstat (limited to 'drivers/input/serio/hil_mlc.c')
| -rw-r--r-- | drivers/input/serio/hil_mlc.c | 56 |
1 files changed, 33 insertions, 23 deletions
diff --git a/drivers/input/serio/hil_mlc.c b/drivers/input/serio/hil_mlc.c index 65605e4ef3cf..3fedfc5abc73 100644 --- a/drivers/input/serio/hil_mlc.c +++ b/drivers/input/serio/hil_mlc.c @@ -54,6 +54,7 @@ #include <linux/hil_mlc.h> #include <linux/errno.h> +#include <linux/export.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> @@ -74,10 +75,10 @@ EXPORT_SYMBOL(hil_mlc_unregister); static LIST_HEAD(hil_mlcs); static DEFINE_RWLOCK(hil_mlcs_lock); static struct timer_list hil_mlcs_kicker; -static int hil_mlcs_probe; +static int hil_mlcs_probe, hil_mlc_stop; static void hil_mlcs_process(unsigned long unused); -static DECLARE_TASKLET_DISABLED(hil_mlcs_tasklet, hil_mlcs_process, 0); +static DECLARE_TASKLET_DISABLED_OLD(hil_mlcs_tasklet, hil_mlcs_process); /* #define HIL_MLC_DEBUG */ @@ -274,14 +275,12 @@ static int hilse_match(hil_mlc *mlc, int unused) /* An LCV used to prevent runaway loops, forces 5 second sleep when reset. */ static int hilse_init_lcv(hil_mlc *mlc, int unused) { - struct timeval tv; + time64_t now = ktime_get_seconds(); - do_gettimeofday(&tv); - - if (mlc->lcv && (tv.tv_sec - mlc->lcv_tv.tv_sec) < 5) + if (mlc->lcv && (now - mlc->lcv_time) < 5) return -1; - mlc->lcv_tv = tv; + mlc->lcv_time = now; mlc->lcv = 0; return 0; @@ -604,8 +603,8 @@ static inline void hilse_setup_input(hil_mlc *mlc, const struct hilse_node *node BUG(); } mlc->istarted = 1; - mlc->intimeout = node->arg; - do_gettimeofday(&(mlc->instart)); + mlc->intimeout = usecs_to_jiffies(node->arg); + mlc->instart = jiffies; mlc->icount = 15; memset(mlc->ipacket, 0, 16 * sizeof(hil_packet)); BUG_ON(down_trylock(&mlc->isem)); @@ -704,21 +703,30 @@ static int hilse_donode(hil_mlc *mlc) if (!mlc->ostarted) { mlc->ostarted = 1; mlc->opacket = pack; - mlc->out(mlc); + rc = mlc->out(mlc); nextidx = HILSEN_DOZE; write_unlock_irqrestore(&mlc->lock, flags); + if (rc) { + hil_mlc_stop = 1; + return 1; + } break; } mlc->ostarted = 0; - do_gettimeofday(&(mlc->instart)); + mlc->instart = jiffies; write_unlock_irqrestore(&mlc->lock, flags); nextidx = HILSEN_NEXT; break; case HILSE_CTS: write_lock_irqsave(&mlc->lock, flags); - nextidx = mlc->cts(mlc) ? node->bad : node->good; + rc = mlc->cts(mlc); + nextidx = rc ? node->bad : node->good; write_unlock_irqrestore(&mlc->lock, flags); + if (rc) { + hil_mlc_stop = 1; + return 1; + } break; default: @@ -731,18 +739,14 @@ static int hilse_donode(hil_mlc *mlc) #endif while (nextidx & HILSEN_SCHED) { - struct timeval tv; + unsigned long now = jiffies; if (!sched_long) goto sched; - do_gettimeofday(&tv); - tv.tv_usec += USEC_PER_SEC * (tv.tv_sec - mlc->instart.tv_sec); - tv.tv_usec -= mlc->instart.tv_usec; - if (tv.tv_usec >= mlc->intimeout) goto sched; - tv.tv_usec = (mlc->intimeout - tv.tv_usec) * HZ / USEC_PER_SEC; - if (!tv.tv_usec) goto sched; - mod_timer(&hil_mlcs_kicker, jiffies + tv.tv_usec); + if (time_after(now, mlc->instart + mlc->intimeout)) + goto sched; + mod_timer(&hil_mlcs_kicker, mlc->instart + mlc->intimeout); break; sched: tasklet_schedule(&hil_mlcs_tasklet); @@ -784,8 +788,14 @@ static void hil_mlcs_process(unsigned long unused) /************************* Keepalive timer task *********************/ -static void hil_mlcs_timer(unsigned long data) +static void hil_mlcs_timer(struct timer_list *unused) { + if (hil_mlc_stop) { + /* could not send packet - stop immediately. */ + pr_warn(PREFIX "HIL seems stuck - Disabling HIL MLC.\n"); + return; + } + hil_mlcs_probe = 1; tasklet_schedule(&hil_mlcs_tasklet); /* Re-insert the periodic task. */ @@ -998,7 +1008,7 @@ int hil_mlc_unregister(hil_mlc *mlc) static int __init hil_mlc_init(void) { - setup_timer(&hil_mlcs_kicker, &hil_mlcs_timer, 0); + timer_setup(&hil_mlcs_kicker, &hil_mlcs_timer, 0); mod_timer(&hil_mlcs_kicker, jiffies + HZ); tasklet_enable(&hil_mlcs_tasklet); @@ -1008,7 +1018,7 @@ static int __init hil_mlc_init(void) static void __exit hil_mlc_exit(void) { - del_timer_sync(&hil_mlcs_kicker); + timer_delete_sync(&hil_mlcs_kicker); tasklet_kill(&hil_mlcs_tasklet); } |
