aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mfd/ucb1x00-ts.c65
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;