diff options
| -rw-r--r-- | drivers/mfd/ucb1x00-ts.c | 65 |
1 files changed, 17 insertions, 48 deletions
diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c index 52e0699eeb8b..a851d65c7cfe 100644 --- a/drivers/mfd/ucb1x00-ts.c +++ b/drivers/mfd/ucb1x00-ts.c | |||
| @@ -1,7 +1,8 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * linux/drivers/mfd/ucb1x00-ts.c | 2 | * Touchscreen driver for UCB1x00-based touchscreens |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2001 Russell King, All Rights Reserved. | 4 | * Copyright (C) 2001 Russell King, All Rights Reserved. |
| 5 | * Copyright (C) 2005 Pavel Machek | ||
| 5 | * | 6 | * |
| 6 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License version 2 as | 8 | * it under the terms of the GNU General Public License version 2 as |
| @@ -30,6 +31,7 @@ | |||
| 30 | #include <linux/device.h> | 31 | #include <linux/device.h> |
| 31 | #include <linux/suspend.h> | 32 | #include <linux/suspend.h> |
| 32 | #include <linux/slab.h> | 33 | #include <linux/slab.h> |
| 34 | #include <linux/kthread.h> | ||
| 33 | 35 | ||
| 34 | #include <asm/dma.h> | 36 | #include <asm/dma.h> |
| 35 | #include <asm/semaphore.h> | 37 | #include <asm/semaphore.h> |
| @@ -42,10 +44,7 @@ struct ucb1x00_ts { | |||
| 42 | struct ucb1x00 *ucb; | 44 | struct ucb1x00 *ucb; |
| 43 | 45 | ||
| 44 | wait_queue_head_t irq_wait; | 46 | wait_queue_head_t irq_wait; |
| 45 | struct semaphore sem; | ||
| 46 | struct completion init_exit; | ||
| 47 | struct task_struct *rtask; | 47 | struct task_struct *rtask; |
| 48 | int use_count; | ||
| 49 | u16 x_res; | 48 | u16 x_res; |
| 50 | u16 y_res; | 49 | u16 y_res; |
| 51 | 50 | ||
| @@ -176,12 +175,6 @@ static int ucb1x00_thread(void *_ts) | |||
| 176 | DECLARE_WAITQUEUE(wait, tsk); | 175 | DECLARE_WAITQUEUE(wait, tsk); |
| 177 | int valid; | 176 | int valid; |
| 178 | 177 | ||
| 179 | ts->rtask = tsk; | ||
| 180 | |||
| 181 | daemonize("ktsd"); | ||
| 182 | /* only want to receive SIGKILL */ | ||
| 183 | allow_signal(SIGKILL); | ||
| 184 | |||
| 185 | /* | 178 | /* |
| 186 | * We could run as a real-time thread. However, thus far | 179 | * We could run as a real-time thread. However, thus far |
| 187 | * this doesn't seem to be necessary. | 180 | * this doesn't seem to be necessary. |
| @@ -189,12 +182,10 @@ static int ucb1x00_thread(void *_ts) | |||
| 189 | // tsk->policy = SCHED_FIFO; | 182 | // tsk->policy = SCHED_FIFO; |
| 190 | // tsk->rt_priority = 1; | 183 | // tsk->rt_priority = 1; |
| 191 | 184 | ||
| 192 | complete(&ts->init_exit); | ||
| 193 | |||
| 194 | valid = 0; | 185 | valid = 0; |
| 195 | 186 | ||
| 196 | add_wait_queue(&ts->irq_wait, &wait); | 187 | add_wait_queue(&ts->irq_wait, &wait); |
| 197 | for (;;) { | 188 | while (!kthread_should_stop()) { |
| 198 | unsigned int x, y, p, val; | 189 | unsigned int x, y, p, val; |
| 199 | signed long timeout; | 190 | signed long timeout; |
| 200 | 191 | ||
| @@ -212,10 +203,7 @@ static int ucb1x00_thread(void *_ts) | |||
| 212 | ucb1x00_ts_mode_int(ts); | 203 | ucb1x00_ts_mode_int(ts); |
| 213 | ucb1x00_adc_disable(ts->ucb); | 204 | ucb1x00_adc_disable(ts->ucb); |
| 214 | 205 | ||
| 215 | set_task_state(tsk, TASK_UNINTERRUPTIBLE); | 206 | msleep(10); |
| 216 | schedule_timeout(HZ / 100); | ||
| 217 | if (signal_pending(tsk)) | ||
| 218 | break; | ||
| 219 | 207 | ||
| 220 | ucb1x00_enable(ts->ucb); | 208 | ucb1x00_enable(ts->ucb); |
| 221 | val = ucb1x00_reg_read(ts->ucb, UCB_TS_CR); | 209 | val = ucb1x00_reg_read(ts->ucb, UCB_TS_CR); |
| @@ -256,14 +244,12 @@ static int ucb1x00_thread(void *_ts) | |||
| 256 | try_to_freeze(); | 244 | try_to_freeze(); |
| 257 | 245 | ||
| 258 | schedule_timeout(timeout); | 246 | schedule_timeout(timeout); |
| 259 | if (signal_pending(tsk)) | ||
| 260 | break; | ||
| 261 | } | 247 | } |
| 262 | 248 | ||
| 263 | remove_wait_queue(&ts->irq_wait, &wait); | 249 | remove_wait_queue(&ts->irq_wait, &wait); |
| 264 | 250 | ||
| 265 | ts->rtask = NULL; | 251 | ts->rtask = NULL; |
| 266 | complete_and_exit(&ts->init_exit, 0); | 252 | return 0; |
| 267 | } | 253 | } |
| 268 | 254 | ||
| 269 | /* | 255 | /* |
| @@ -282,14 +268,7 @@ static int ucb1x00_ts_open(struct input_dev *idev) | |||
| 282 | struct ucb1x00_ts *ts = (struct ucb1x00_ts *)idev; | 268 | struct ucb1x00_ts *ts = (struct ucb1x00_ts *)idev; |
| 283 | int ret = 0; | 269 | int ret = 0; |
| 284 | 270 | ||
| 285 | if (down_interruptible(&ts->sem)) | 271 | BUG_ON(ts->rtask); |
| 286 | return -EINTR; | ||
| 287 | |||
| 288 | if (ts->use_count++ != 0) | ||
| 289 | goto out; | ||
| 290 | |||
| 291 | if (ts->rtask) | ||
| 292 | panic("ucb1x00: rtask running?"); | ||
| 293 | 272 | ||
| 294 | init_waitqueue_head(&ts->irq_wait); | 273 | init_waitqueue_head(&ts->irq_wait); |
| 295 | ret = ucb1x00_hook_irq(ts->ucb, UCB_IRQ_TSPX, ucb1x00_ts_irq, ts); | 274 | ret = ucb1x00_hook_irq(ts->ucb, UCB_IRQ_TSPX, ucb1x00_ts_irq, ts); |
| @@ -305,19 +284,16 @@ static int ucb1x00_ts_open(struct input_dev *idev) | |||
| 305 | ts->y_res = ucb1x00_ts_read_yres(ts); | 284 | ts->y_res = ucb1x00_ts_read_yres(ts); |
| 306 | ucb1x00_adc_disable(ts->ucb); | 285 | ucb1x00_adc_disable(ts->ucb); |
| 307 | 286 | ||
| 308 | init_completion(&ts->init_exit); | 287 | ts->rtask = kthread_run(ucb1x00_thread, ts, "ktsd"); |
| 309 | ret = kernel_thread(ucb1x00_thread, ts, CLONE_KERNEL); | 288 | if (!IS_ERR(ts->rtask)) { |
| 310 | if (ret >= 0) { | ||
| 311 | wait_for_completion(&ts->init_exit); | ||
| 312 | ret = 0; | 289 | ret = 0; |
| 313 | } else { | 290 | } else { |
| 314 | ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts); | 291 | ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts); |
| 292 | ts->rtask = NULL; | ||
| 293 | ret = -EFAULT; | ||
| 315 | } | 294 | } |
| 316 | 295 | ||
| 317 | out: | 296 | out: |
| 318 | if (ret) | ||
| 319 | ts->use_count--; | ||
| 320 | up(&ts->sem); | ||
| 321 | return ret; | 297 | return ret; |
| 322 | } | 298 | } |
| 323 | 299 | ||
| @@ -328,19 +304,13 @@ static void ucb1x00_ts_close(struct input_dev *idev) | |||
| 328 | { | 304 | { |
| 329 | struct ucb1x00_ts *ts = (struct ucb1x00_ts *)idev; | 305 | struct ucb1x00_ts *ts = (struct ucb1x00_ts *)idev; |
| 330 | 306 | ||
| 331 | down(&ts->sem); | 307 | if (ts->rtask) |
| 332 | if (--ts->use_count == 0) { | 308 | kthread_stop(ts->rtask); |
| 333 | if (ts->rtask) { | ||
| 334 | send_sig(SIGKILL, ts->rtask, 1); | ||
| 335 | wait_for_completion(&ts->init_exit); | ||
| 336 | } | ||
| 337 | 309 | ||
| 338 | ucb1x00_enable(ts->ucb); | 310 | ucb1x00_enable(ts->ucb); |
| 339 | ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts); | 311 | ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts); |
| 340 | ucb1x00_reg_write(ts->ucb, UCB_TS_CR, 0); | 312 | ucb1x00_reg_write(ts->ucb, UCB_TS_CR, 0); |
| 341 | ucb1x00_disable(ts->ucb); | 313 | ucb1x00_disable(ts->ucb); |
| 342 | } | ||
| 343 | up(&ts->sem); | ||
| 344 | } | 314 | } |
| 345 | 315 | ||
| 346 | #ifdef CONFIG_PM | 316 | #ifdef CONFIG_PM |
| @@ -379,7 +349,6 @@ static int ucb1x00_ts_add(struct ucb1x00_dev *dev) | |||
| 379 | 349 | ||
| 380 | ts->ucb = dev->ucb; | 350 | ts->ucb = dev->ucb; |
| 381 | ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC; | 351 | ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC; |
| 382 | init_MUTEX(&ts->sem); | ||
| 383 | 352 | ||
| 384 | ts->idev.name = "Touchscreen panel"; | 353 | ts->idev.name = "Touchscreen panel"; |
| 385 | ts->idev.id.product = ts->ucb->id; | 354 | ts->idev.id.product = ts->ucb->id; |
