diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-03-25 20:13:43 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-05-17 23:53:00 -0400 |
commit | 93c312ff21b0a53e701a45741887208297646a1a (patch) | |
tree | cc17d43e5b1926228daacb4ea61d7be43f1c0c24 /drivers/media/IR/ir-raw-event.c | |
parent | 995187bed30c0545e8da88372e9807da0a85911e (diff) |
V4L/DVB: ir-core: prepare to add more operations for ir decoders
Some decoders and a lirc_dev interface may need some other operations to work.
For example: IR device register/unregister and ir_keydown events may need to
be tracked.
As some operations can occur in interrupt time, and a lock is needed to prevent
un-registering a decode while decoding a key, the lock needed to be convert
into a spin lock.
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/IR/ir-raw-event.c')
-rw-r--r-- | drivers/media/IR/ir-raw-event.c | 71 |
1 files changed, 58 insertions, 13 deletions
diff --git a/drivers/media/IR/ir-raw-event.c b/drivers/media/IR/ir-raw-event.c index 3eae128400ea..11f23f4491b2 100644 --- a/drivers/media/IR/ir-raw-event.c +++ b/drivers/media/IR/ir-raw-event.c | |||
@@ -14,13 +14,41 @@ | |||
14 | 14 | ||
15 | #include <media/ir-core.h> | 15 | #include <media/ir-core.h> |
16 | #include <linux/workqueue.h> | 16 | #include <linux/workqueue.h> |
17 | #include <linux/spinlock.h> | ||
17 | 18 | ||
18 | /* Define the max number of bit transitions per IR keycode */ | 19 | /* Define the max number of bit transitions per IR keycode */ |
19 | #define MAX_IR_EVENT_SIZE 256 | 20 | #define MAX_IR_EVENT_SIZE 256 |
20 | 21 | ||
21 | /* Used to handle IR raw handler extensions */ | 22 | /* Used to handle IR raw handler extensions */ |
22 | static LIST_HEAD(ir_raw_handler_list); | 23 | static LIST_HEAD(ir_raw_handler_list); |
23 | static DEFINE_MUTEX(ir_raw_handler_lock); | 24 | static spinlock_t ir_raw_handler_lock; |
25 | |||
26 | /** | ||
27 | * RUN_DECODER() - runs an operation on all IR decoders | ||
28 | * @ops: IR raw handler operation to be called | ||
29 | * @arg: arguments to be passed to the callback | ||
30 | * | ||
31 | * Calls ir_raw_handler::ops for all registered IR handlers. It prevents | ||
32 | * new decode addition/removal while running, by locking ir_raw_handler_lock | ||
33 | * mutex. If an error occurs, it stops the ops. Otherwise, it returns a sum | ||
34 | * of the return codes. | ||
35 | */ | ||
36 | #define RUN_DECODER(ops, ...) ({ \ | ||
37 | struct ir_raw_handler *_ir_raw_handler; \ | ||
38 | int _sumrc = 0, _rc; \ | ||
39 | spin_lock(&ir_raw_handler_lock); \ | ||
40 | list_for_each_entry(_ir_raw_handler, &ir_raw_handler_list, list) { \ | ||
41 | if (_ir_raw_handler->ops) { \ | ||
42 | _rc = _ir_raw_handler->ops(__VA_ARGS__); \ | ||
43 | if (_rc < 0) \ | ||
44 | break; \ | ||
45 | _sumrc += _rc; \ | ||
46 | } \ | ||
47 | } \ | ||
48 | spin_unlock(&ir_raw_handler_lock); \ | ||
49 | _sumrc; \ | ||
50 | }) | ||
51 | |||
24 | 52 | ||
25 | /* Used to load the decoders */ | 53 | /* Used to load the decoders */ |
26 | static struct work_struct wq_load; | 54 | static struct work_struct wq_load; |
@@ -38,6 +66,8 @@ int ir_raw_event_register(struct input_dev *input_dev) | |||
38 | int rc, size; | 66 | int rc, size; |
39 | 67 | ||
40 | ir->raw = kzalloc(sizeof(*ir->raw), GFP_KERNEL); | 68 | ir->raw = kzalloc(sizeof(*ir->raw), GFP_KERNEL); |
69 | if (!ir->raw) | ||
70 | return -ENOMEM; | ||
41 | 71 | ||
42 | size = sizeof(struct ir_raw_event) * MAX_IR_EVENT_SIZE * 2; | 72 | size = sizeof(struct ir_raw_event) * MAX_IR_EVENT_SIZE * 2; |
43 | size = roundup_pow_of_two(size); | 73 | size = roundup_pow_of_two(size); |
@@ -48,6 +78,19 @@ int ir_raw_event_register(struct input_dev *input_dev) | |||
48 | set_bit(EV_REP, input_dev->evbit); | 78 | set_bit(EV_REP, input_dev->evbit); |
49 | 79 | ||
50 | rc = kfifo_alloc(&ir->raw->kfifo, size, GFP_KERNEL); | 80 | rc = kfifo_alloc(&ir->raw->kfifo, size, GFP_KERNEL); |
81 | if (rc < 0) { | ||
82 | kfree(ir->raw); | ||
83 | ir->raw = NULL; | ||
84 | return rc; | ||
85 | } | ||
86 | |||
87 | rc = RUN_DECODER(raw_register, input_dev); | ||
88 | if (rc < 0) { | ||
89 | kfifo_free(&ir->raw->kfifo); | ||
90 | kfree(ir->raw); | ||
91 | ir->raw = NULL; | ||
92 | return rc; | ||
93 | } | ||
51 | 94 | ||
52 | return rc; | 95 | return rc; |
53 | } | 96 | } |
@@ -62,6 +105,8 @@ void ir_raw_event_unregister(struct input_dev *input_dev) | |||
62 | 105 | ||
63 | del_timer_sync(&ir->raw->timer_keyup); | 106 | del_timer_sync(&ir->raw->timer_keyup); |
64 | 107 | ||
108 | RUN_DECODER(raw_unregister, input_dev); | ||
109 | |||
65 | kfifo_free(&ir->raw->kfifo); | 110 | kfifo_free(&ir->raw->kfifo); |
66 | kfree(ir->raw); | 111 | kfree(ir->raw); |
67 | ir->raw = NULL; | 112 | ir->raw = NULL; |
@@ -109,7 +154,6 @@ int ir_raw_event_handle(struct input_dev *input_dev) | |||
109 | int rc; | 154 | int rc; |
110 | struct ir_raw_event *evs; | 155 | struct ir_raw_event *evs; |
111 | int len, i; | 156 | int len, i; |
112 | struct ir_raw_handler *ir_raw_handler; | ||
113 | 157 | ||
114 | /* | 158 | /* |
115 | * Store the events into a temporary buffer. This allows calling more than | 159 | * Store the events into a temporary buffer. This allows calling more than |
@@ -133,13 +177,10 @@ int ir_raw_event_handle(struct input_dev *input_dev) | |||
133 | 177 | ||
134 | /* | 178 | /* |
135 | * Call all ir decoders. This allows decoding the same event with | 179 | * Call all ir decoders. This allows decoding the same event with |
136 | * more than one protocol handler. | 180 | * more than one protocol handler. It returns the number of keystrokes |
137 | * FIXME: better handle the returned code: does it make sense to use | 181 | * sent to the event interface |
138 | * other decoders, if the first one already handled the IR? | ||
139 | */ | 182 | */ |
140 | list_for_each_entry(ir_raw_handler, &ir_raw_handler_list, list) { | 183 | rc = RUN_DECODER(decode, input_dev, evs, len); |
141 | rc = ir_raw_handler->decode(input_dev, evs, len); | ||
142 | } | ||
143 | 184 | ||
144 | kfree(evs); | 185 | kfree(evs); |
145 | 186 | ||
@@ -153,18 +194,18 @@ EXPORT_SYMBOL_GPL(ir_raw_event_handle); | |||
153 | 194 | ||
154 | int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler) | 195 | int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler) |
155 | { | 196 | { |
156 | mutex_lock(&ir_raw_handler_lock); | 197 | spin_lock(&ir_raw_handler_lock); |
157 | list_add_tail(&ir_raw_handler->list, &ir_raw_handler_list); | 198 | list_add_tail(&ir_raw_handler->list, &ir_raw_handler_list); |
158 | mutex_unlock(&ir_raw_handler_lock); | 199 | spin_unlock(&ir_raw_handler_lock); |
159 | return 0; | 200 | return 0; |
160 | } | 201 | } |
161 | EXPORT_SYMBOL(ir_raw_handler_register); | 202 | EXPORT_SYMBOL(ir_raw_handler_register); |
162 | 203 | ||
163 | void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler) | 204 | void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler) |
164 | { | 205 | { |
165 | mutex_lock(&ir_raw_handler_lock); | 206 | spin_lock(&ir_raw_handler_lock); |
166 | list_del(&ir_raw_handler->list); | 207 | list_del(&ir_raw_handler->list); |
167 | mutex_unlock(&ir_raw_handler_lock); | 208 | spin_unlock(&ir_raw_handler_lock); |
168 | } | 209 | } |
169 | EXPORT_SYMBOL(ir_raw_handler_unregister); | 210 | EXPORT_SYMBOL(ir_raw_handler_unregister); |
170 | 211 | ||
@@ -181,6 +222,10 @@ static void init_decoders(struct work_struct *work) | |||
181 | 222 | ||
182 | void ir_raw_init(void) | 223 | void ir_raw_init(void) |
183 | { | 224 | { |
225 | spin_lock_init(&ir_raw_handler_lock); | ||
226 | |||
227 | #ifdef MODULE | ||
184 | INIT_WORK(&wq_load, init_decoders); | 228 | INIT_WORK(&wq_load, init_decoders); |
185 | schedule_work(&wq_load); | 229 | schedule_work(&wq_load); |
186 | } \ No newline at end of file | 230 | #endif |
231 | } | ||