diff options
author | Paul Mackerras <paulus@samba.org> | 2007-12-12 23:11:22 -0500 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2007-12-18 23:22:02 -0500 |
commit | c61dace9a10a4bc54c764f9f490994a9d7852859 (patch) | |
tree | 2a67ac64a47d37f52cb5031365c3fdaf9b73194b /drivers | |
parent | 33f6e7940691b1c92b276148c48a9551ac07f11d (diff) |
[POWERPC] Convert adb.c to use kthread API and not spin on ADB requests
This converts adb.c to use the kthread API.
It also changes adb_request so that if the ADBREQ_SYNC flag is
specified, we now sleep waiting for the request to finish using an
on-stack completion rather than spinning. To implement this, we now
require that if the ADBREQ_SYNC flag is set, the `done' parameter must
be NULL. All of the existing callers of adb_request that pass
ADBREQ_SYNC appear to be in process context and have done == NULL.
Doing this allows us to get rid of an awful hack in adb_request()
where we used to test whether the request was coming from the adb
probe task and use a completion if it was, and otherwise spin.
This also gets rid of a static request block that was used if the req
parameter to adb_request was NULL. None of the callers do that any
more, so the static request block is no longer necessary.
Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/macintosh/adb.c | 78 |
1 files changed, 21 insertions, 57 deletions
diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c index 7b892f4a8e8c..5ae28f076d25 100644 --- a/drivers/macintosh/adb.c +++ b/drivers/macintosh/adb.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/spinlock.h> | 35 | #include <linux/spinlock.h> |
36 | #include <linux/completion.h> | 36 | #include <linux/completion.h> |
37 | #include <linux/device.h> | 37 | #include <linux/device.h> |
38 | #include <linux/kthread.h> | ||
38 | 39 | ||
39 | #include <asm/uaccess.h> | 40 | #include <asm/uaccess.h> |
40 | #include <asm/semaphore.h> | 41 | #include <asm/semaphore.h> |
@@ -82,9 +83,7 @@ struct adb_driver *adb_controller; | |||
82 | BLOCKING_NOTIFIER_HEAD(adb_client_list); | 83 | BLOCKING_NOTIFIER_HEAD(adb_client_list); |
83 | static int adb_got_sleep; | 84 | static int adb_got_sleep; |
84 | static int adb_inited; | 85 | static int adb_inited; |
85 | static pid_t adb_probe_task_pid; | ||
86 | static DECLARE_MUTEX(adb_probe_mutex); | 86 | static DECLARE_MUTEX(adb_probe_mutex); |
87 | static struct completion adb_probe_task_comp; | ||
88 | static int sleepy_trackpad; | 87 | static int sleepy_trackpad; |
89 | static int autopoll_devs; | 88 | static int autopoll_devs; |
90 | int __adb_probe_sync; | 89 | int __adb_probe_sync; |
@@ -126,16 +125,6 @@ static void printADBreply(struct adb_request *req) | |||
126 | } | 125 | } |
127 | #endif | 126 | #endif |
128 | 127 | ||
129 | |||
130 | static __inline__ void adb_wait_ms(unsigned int ms) | ||
131 | { | ||
132 | if (current->pid && adb_probe_task_pid && | ||
133 | adb_probe_task_pid == current->pid) | ||
134 | msleep(ms); | ||
135 | else | ||
136 | mdelay(ms); | ||
137 | } | ||
138 | |||
139 | static int adb_scan_bus(void) | 128 | static int adb_scan_bus(void) |
140 | { | 129 | { |
141 | int i, highFree=0, noMovement; | 130 | int i, highFree=0, noMovement; |
@@ -240,13 +229,10 @@ static int adb_scan_bus(void) | |||
240 | static int | 229 | static int |
241 | adb_probe_task(void *x) | 230 | adb_probe_task(void *x) |
242 | { | 231 | { |
243 | strcpy(current->comm, "kadbprobe"); | ||
244 | |||
245 | printk(KERN_INFO "adb: starting probe task...\n"); | 232 | printk(KERN_INFO "adb: starting probe task...\n"); |
246 | do_adb_reset_bus(); | 233 | do_adb_reset_bus(); |
247 | printk(KERN_INFO "adb: finished probe task...\n"); | 234 | printk(KERN_INFO "adb: finished probe task...\n"); |
248 | 235 | ||
249 | adb_probe_task_pid = 0; | ||
250 | up(&adb_probe_mutex); | 236 | up(&adb_probe_mutex); |
251 | 237 | ||
252 | return 0; | 238 | return 0; |
@@ -255,7 +241,7 @@ adb_probe_task(void *x) | |||
255 | static void | 241 | static void |
256 | __adb_probe_task(struct work_struct *bullshit) | 242 | __adb_probe_task(struct work_struct *bullshit) |
257 | { | 243 | { |
258 | adb_probe_task_pid = kernel_thread(adb_probe_task, NULL, SIGCHLD | CLONE_KERNEL); | 244 | kthread_run(adb_probe_task, NULL, "kadbprobe"); |
259 | } | 245 | } |
260 | 246 | ||
261 | static DECLARE_WORK(adb_reset_work, __adb_probe_task); | 247 | static DECLARE_WORK(adb_reset_work, __adb_probe_task); |
@@ -341,7 +327,6 @@ int __init adb_init(void) | |||
341 | sleepy_trackpad = 1; | 327 | sleepy_trackpad = 1; |
342 | #endif /* CONFIG_PPC */ | 328 | #endif /* CONFIG_PPC */ |
343 | 329 | ||
344 | init_completion(&adb_probe_task_comp); | ||
345 | adbdev_init(); | 330 | adbdev_init(); |
346 | adb_reset_bus(); | 331 | adb_reset_bus(); |
347 | } | 332 | } |
@@ -366,7 +351,7 @@ do_adb_reset_bus(void) | |||
366 | 351 | ||
367 | if (sleepy_trackpad) { | 352 | if (sleepy_trackpad) { |
368 | /* Let the trackpad settle down */ | 353 | /* Let the trackpad settle down */ |
369 | adb_wait_ms(500); | 354 | msleep(500); |
370 | } | 355 | } |
371 | 356 | ||
372 | down(&adb_handler_sem); | 357 | down(&adb_handler_sem); |
@@ -382,7 +367,7 @@ do_adb_reset_bus(void) | |||
382 | 367 | ||
383 | if (sleepy_trackpad) { | 368 | if (sleepy_trackpad) { |
384 | /* Let the trackpad settle down */ | 369 | /* Let the trackpad settle down */ |
385 | adb_wait_ms(1500); | 370 | msleep(1500); |
386 | } | 371 | } |
387 | 372 | ||
388 | if (!ret) { | 373 | if (!ret) { |
@@ -406,41 +391,27 @@ adb_poll(void) | |||
406 | adb_controller->poll(); | 391 | adb_controller->poll(); |
407 | } | 392 | } |
408 | 393 | ||
409 | static void | 394 | static void adb_sync_req_done(struct adb_request *req) |
410 | adb_probe_wakeup(struct adb_request *req) | ||
411 | { | 395 | { |
412 | complete(&adb_probe_task_comp); | 396 | struct completion *comp = req->arg; |
413 | } | ||
414 | 397 | ||
415 | /* Static request used during probe */ | 398 | complete(comp); |
416 | static struct adb_request adb_sreq; | 399 | } |
417 | static unsigned long adb_sreq_lock; // Use semaphore ! */ | ||
418 | 400 | ||
419 | int | 401 | int |
420 | adb_request(struct adb_request *req, void (*done)(struct adb_request *), | 402 | adb_request(struct adb_request *req, void (*done)(struct adb_request *), |
421 | int flags, int nbytes, ...) | 403 | int flags, int nbytes, ...) |
422 | { | 404 | { |
423 | va_list list; | 405 | va_list list; |
424 | int i, use_sreq; | 406 | int i; |
425 | int rc; | 407 | int rc; |
408 | struct completion comp; | ||
426 | 409 | ||
427 | if ((adb_controller == NULL) || (adb_controller->send_request == NULL)) | 410 | if ((adb_controller == NULL) || (adb_controller->send_request == NULL)) |
428 | return -ENXIO; | 411 | return -ENXIO; |
429 | if (nbytes < 1) | 412 | if (nbytes < 1) |
430 | return -EINVAL; | 413 | return -EINVAL; |
431 | if (req == NULL && (flags & ADBREQ_NOSEND)) | 414 | |
432 | return -EINVAL; | ||
433 | |||
434 | if (req == NULL) { | ||
435 | if (test_and_set_bit(0,&adb_sreq_lock)) { | ||
436 | printk("adb.c: Warning: contention on static request !\n"); | ||
437 | return -EPERM; | ||
438 | } | ||
439 | req = &adb_sreq; | ||
440 | flags |= ADBREQ_SYNC; | ||
441 | use_sreq = 1; | ||
442 | } else | ||
443 | use_sreq = 0; | ||
444 | req->nbytes = nbytes+1; | 415 | req->nbytes = nbytes+1; |
445 | req->done = done; | 416 | req->done = done; |
446 | req->reply_expected = flags & ADBREQ_REPLY; | 417 | req->reply_expected = flags & ADBREQ_REPLY; |
@@ -453,25 +424,18 @@ adb_request(struct adb_request *req, void (*done)(struct adb_request *), | |||
453 | if (flags & ADBREQ_NOSEND) | 424 | if (flags & ADBREQ_NOSEND) |
454 | return 0; | 425 | return 0; |
455 | 426 | ||
456 | /* Synchronous requests send from the probe thread cause it to | 427 | /* Synchronous requests block using an on-stack completion */ |
457 | * block. Beware that the "done" callback will be overriden ! | 428 | if (flags & ADBREQ_SYNC) { |
458 | */ | 429 | WARN_ON(done); |
459 | if ((flags & ADBREQ_SYNC) && | 430 | req->done = adb_sync_req_done; |
460 | (current->pid && adb_probe_task_pid && | 431 | req->arg = ∁ |
461 | adb_probe_task_pid == current->pid)) { | 432 | init_completion(&comp); |
462 | req->done = adb_probe_wakeup; | ||
463 | rc = adb_controller->send_request(req, 0); | ||
464 | if (rc || req->complete) | ||
465 | goto bail; | ||
466 | wait_for_completion(&adb_probe_task_comp); | ||
467 | rc = 0; | ||
468 | goto bail; | ||
469 | } | 433 | } |
470 | 434 | ||
471 | rc = adb_controller->send_request(req, flags & ADBREQ_SYNC); | 435 | rc = adb_controller->send_request(req, 0); |
472 | bail: | 436 | |
473 | if (use_sreq) | 437 | if ((flags & ADBREQ_SYNC) && !rc && !req->complete) |
474 | clear_bit(0, &adb_sreq_lock); | 438 | wait_for_completion(&comp); |
475 | 439 | ||
476 | return rc; | 440 | return rc; |
477 | } | 441 | } |