diff options
Diffstat (limited to 'drivers/media/IR/ir-raw-event.c')
-rw-r--r-- | drivers/media/IR/ir-raw-event.c | 73 |
1 files changed, 37 insertions, 36 deletions
diff --git a/drivers/media/IR/ir-raw-event.c b/drivers/media/IR/ir-raw-event.c index fb3336c37191..5f98ab823057 100644 --- a/drivers/media/IR/ir-raw-event.c +++ b/drivers/media/IR/ir-raw-event.c | |||
@@ -20,36 +20,14 @@ | |||
20 | /* Define the max number of pulse/space transitions to buffer */ | 20 | /* Define the max number of pulse/space transitions to buffer */ |
21 | #define MAX_IR_EVENT_SIZE 512 | 21 | #define MAX_IR_EVENT_SIZE 512 |
22 | 22 | ||
23 | /* Used to keep track of IR raw clients, protected by ir_raw_handler_lock */ | ||
24 | static LIST_HEAD(ir_raw_client_list); | ||
25 | |||
23 | /* Used to handle IR raw handler extensions */ | 26 | /* Used to handle IR raw handler extensions */ |
24 | static DEFINE_SPINLOCK(ir_raw_handler_lock); | 27 | static DEFINE_SPINLOCK(ir_raw_handler_lock); |
25 | static LIST_HEAD(ir_raw_handler_list); | 28 | static LIST_HEAD(ir_raw_handler_list); |
26 | static u64 available_protocols; | 29 | static u64 available_protocols; |
27 | 30 | ||
28 | /** | ||
29 | * RUN_DECODER() - runs an operation on all IR decoders | ||
30 | * @ops: IR raw handler operation to be called | ||
31 | * @arg: arguments to be passed to the callback | ||
32 | * | ||
33 | * Calls ir_raw_handler::ops for all registered IR handlers. It prevents | ||
34 | * new decode addition/removal while running, by locking ir_raw_handler_lock | ||
35 | * mutex. If an error occurs, we keep going, as in the decode case, each | ||
36 | * decoder must have a crack at decoding the data. We return a sum of the | ||
37 | * return codes, which will be either 0 or negative for current callers. | ||
38 | */ | ||
39 | #define RUN_DECODER(ops, ...) ({ \ | ||
40 | struct ir_raw_handler *_ir_raw_handler; \ | ||
41 | int _sumrc = 0, _rc; \ | ||
42 | spin_lock(&ir_raw_handler_lock); \ | ||
43 | list_for_each_entry(_ir_raw_handler, &ir_raw_handler_list, list) { \ | ||
44 | if (_ir_raw_handler->ops) { \ | ||
45 | _rc = _ir_raw_handler->ops(__VA_ARGS__); \ | ||
46 | _sumrc += _rc; \ | ||
47 | } \ | ||
48 | } \ | ||
49 | spin_unlock(&ir_raw_handler_lock); \ | ||
50 | _sumrc; \ | ||
51 | }) | ||
52 | |||
53 | #ifdef MODULE | 31 | #ifdef MODULE |
54 | /* Used to load the decoders */ | 32 | /* Used to load the decoders */ |
55 | static struct work_struct wq_load; | 33 | static struct work_struct wq_load; |
@@ -58,11 +36,17 @@ static struct work_struct wq_load; | |||
58 | static void ir_raw_event_work(struct work_struct *work) | 36 | static void ir_raw_event_work(struct work_struct *work) |
59 | { | 37 | { |
60 | struct ir_raw_event ev; | 38 | struct ir_raw_event ev; |
39 | struct ir_raw_handler *handler; | ||
61 | struct ir_raw_event_ctrl *raw = | 40 | struct ir_raw_event_ctrl *raw = |
62 | container_of(work, struct ir_raw_event_ctrl, rx_work); | 41 | container_of(work, struct ir_raw_event_ctrl, rx_work); |
63 | 42 | ||
64 | while (kfifo_out(&raw->kfifo, &ev, sizeof(ev)) == sizeof(ev)) | 43 | while (kfifo_out(&raw->kfifo, &ev, sizeof(ev)) == sizeof(ev)) { |
65 | RUN_DECODER(decode, raw->input_dev, ev); | 44 | spin_lock(&ir_raw_handler_lock); |
45 | list_for_each_entry(handler, &ir_raw_handler_list, list) | ||
46 | handler->decode(raw->input_dev, ev); | ||
47 | spin_unlock(&ir_raw_handler_lock); | ||
48 | raw->prev_ev = ev; | ||
49 | } | ||
66 | } | 50 | } |
67 | 51 | ||
68 | /** | 52 | /** |
@@ -176,6 +160,7 @@ int ir_raw_event_register(struct input_dev *input_dev) | |||
176 | { | 160 | { |
177 | struct ir_input_dev *ir = input_get_drvdata(input_dev); | 161 | struct ir_input_dev *ir = input_get_drvdata(input_dev); |
178 | int rc; | 162 | int rc; |
163 | struct ir_raw_handler *handler; | ||
179 | 164 | ||
180 | ir->raw = kzalloc(sizeof(*ir->raw), GFP_KERNEL); | 165 | ir->raw = kzalloc(sizeof(*ir->raw), GFP_KERNEL); |
181 | if (!ir->raw) | 166 | if (!ir->raw) |
@@ -192,26 +177,32 @@ int ir_raw_event_register(struct input_dev *input_dev) | |||
192 | return rc; | 177 | return rc; |
193 | } | 178 | } |
194 | 179 | ||
195 | rc = RUN_DECODER(raw_register, input_dev); | 180 | spin_lock(&ir_raw_handler_lock); |
196 | if (rc < 0) { | 181 | list_add_tail(&ir->raw->list, &ir_raw_client_list); |
197 | kfifo_free(&ir->raw->kfifo); | 182 | list_for_each_entry(handler, &ir_raw_handler_list, list) |
198 | kfree(ir->raw); | 183 | if (handler->raw_register) |
199 | ir->raw = NULL; | 184 | handler->raw_register(ir->raw->input_dev); |
200 | return rc; | 185 | spin_unlock(&ir_raw_handler_lock); |
201 | } | ||
202 | 186 | ||
203 | return rc; | 187 | return 0; |
204 | } | 188 | } |
205 | 189 | ||
206 | void ir_raw_event_unregister(struct input_dev *input_dev) | 190 | void ir_raw_event_unregister(struct input_dev *input_dev) |
207 | { | 191 | { |
208 | struct ir_input_dev *ir = input_get_drvdata(input_dev); | 192 | struct ir_input_dev *ir = input_get_drvdata(input_dev); |
193 | struct ir_raw_handler *handler; | ||
209 | 194 | ||
210 | if (!ir->raw) | 195 | if (!ir->raw) |
211 | return; | 196 | return; |
212 | 197 | ||
213 | cancel_work_sync(&ir->raw->rx_work); | 198 | cancel_work_sync(&ir->raw->rx_work); |
214 | RUN_DECODER(raw_unregister, input_dev); | 199 | |
200 | spin_lock(&ir_raw_handler_lock); | ||
201 | list_del(&ir->raw->list); | ||
202 | list_for_each_entry(handler, &ir_raw_handler_list, list) | ||
203 | if (handler->raw_unregister) | ||
204 | handler->raw_unregister(ir->raw->input_dev); | ||
205 | spin_unlock(&ir_raw_handler_lock); | ||
215 | 206 | ||
216 | kfifo_free(&ir->raw->kfifo); | 207 | kfifo_free(&ir->raw->kfifo); |
217 | kfree(ir->raw); | 208 | kfree(ir->raw); |
@@ -224,8 +215,13 @@ void ir_raw_event_unregister(struct input_dev *input_dev) | |||
224 | 215 | ||
225 | int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler) | 216 | int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler) |
226 | { | 217 | { |
218 | struct ir_raw_event_ctrl *raw; | ||
219 | |||
227 | spin_lock(&ir_raw_handler_lock); | 220 | spin_lock(&ir_raw_handler_lock); |
228 | list_add_tail(&ir_raw_handler->list, &ir_raw_handler_list); | 221 | list_add_tail(&ir_raw_handler->list, &ir_raw_handler_list); |
222 | if (ir_raw_handler->raw_register) | ||
223 | list_for_each_entry(raw, &ir_raw_client_list, list) | ||
224 | ir_raw_handler->raw_register(raw->input_dev); | ||
229 | available_protocols |= ir_raw_handler->protocols; | 225 | available_protocols |= ir_raw_handler->protocols; |
230 | spin_unlock(&ir_raw_handler_lock); | 226 | spin_unlock(&ir_raw_handler_lock); |
231 | 227 | ||
@@ -235,8 +231,13 @@ EXPORT_SYMBOL(ir_raw_handler_register); | |||
235 | 231 | ||
236 | void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler) | 232 | void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler) |
237 | { | 233 | { |
234 | struct ir_raw_event_ctrl *raw; | ||
235 | |||
238 | spin_lock(&ir_raw_handler_lock); | 236 | spin_lock(&ir_raw_handler_lock); |
239 | list_del(&ir_raw_handler->list); | 237 | list_del(&ir_raw_handler->list); |
238 | if (ir_raw_handler->raw_unregister) | ||
239 | list_for_each_entry(raw, &ir_raw_client_list, list) | ||
240 | ir_raw_handler->raw_unregister(raw->input_dev); | ||
240 | available_protocols &= ~ir_raw_handler->protocols; | 241 | available_protocols &= ~ir_raw_handler->protocols; |
241 | spin_unlock(&ir_raw_handler_lock); | 242 | spin_unlock(&ir_raw_handler_lock); |
242 | } | 243 | } |