diff options
Diffstat (limited to 'drivers/mfd')
-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; |