]>
Commit | Line | Data |
---|---|---|
4a62a5ab JW |
1 | /* |
2 | * LIRC base driver | |
3 | * | |
4 | * by Artur Lipowski <alipowski@interia.pl> | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License as published by | |
8 | * the Free Software Foundation; either version 2 of the License, or | |
9 | * (at your option) any later version. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
4a62a5ab JW |
16 | */ |
17 | ||
3fac0314 AS |
18 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
19 | ||
4a62a5ab | 20 | #include <linux/module.h> |
4a62a5ab | 21 | #include <linux/mutex.h> |
4a62a5ab | 22 | #include <linux/device.h> |
46c8f477 | 23 | #include <linux/idr.h> |
a6ddd4fe | 24 | #include <linux/poll.h> |
42e0442f SY |
25 | #include <linux/sched.h> |
26 | #include <linux/wait.h> | |
4a62a5ab | 27 | |
a60d64b1 | 28 | #include "rc-core-priv.h" |
aefb5e34 | 29 | #include <uapi/linux/lirc.h> |
4a62a5ab | 30 | |
42e0442f | 31 | #define LIRCBUF_SIZE 256 |
4a62a5ab JW |
32 | |
33 | static dev_t lirc_base_dev; | |
34 | ||
46c8f477 | 35 | /* Used to keep track of allocated lirc devices */ |
46c8f477 | 36 | static DEFINE_IDA(lirc_ida); |
4a62a5ab JW |
37 | |
38 | /* Only used for sysfs but defined to void otherwise */ | |
39 | static struct class *lirc_class; | |
40 | ||
42e0442f SY |
41 | /** |
42 | * ir_lirc_raw_event() - Send raw IR data to lirc to be relayed to userspace | |
43 | * | |
44 | * @dev: the struct rc_dev descriptor of the device | |
45 | * @ev: the struct ir_raw_event descriptor of the pulse/space | |
46 | */ | |
47 | void ir_lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev) | |
48 | { | |
7e45d660 SY |
49 | unsigned long flags; |
50 | struct lirc_fh *fh; | |
42e0442f SY |
51 | int sample; |
52 | ||
53 | /* Packet start */ | |
54 | if (ev.reset) { | |
55 | /* | |
56 | * Userspace expects a long space event before the start of | |
57 | * the signal to use as a sync. This may be done with repeat | |
58 | * packets and normal samples. But if a reset has been sent | |
59 | * then we assume that a long time has passed, so we send a | |
60 | * space with the maximum time value. | |
61 | */ | |
62 | sample = LIRC_SPACE(LIRC_VALUE_MASK); | |
63 | IR_dprintk(2, "delivering reset sync space to lirc_dev\n"); | |
64 | ||
65 | /* Carrier reports */ | |
66 | } else if (ev.carrier_report) { | |
67 | sample = LIRC_FREQUENCY(ev.carrier); | |
68 | IR_dprintk(2, "carrier report (freq: %d)\n", sample); | |
69 | ||
70 | /* Packet end */ | |
71 | } else if (ev.timeout) { | |
72 | if (dev->gap) | |
73 | return; | |
74 | ||
75 | dev->gap_start = ktime_get(); | |
76 | dev->gap = true; | |
77 | dev->gap_duration = ev.duration; | |
78 | ||
42e0442f SY |
79 | sample = LIRC_TIMEOUT(ev.duration / 1000); |
80 | IR_dprintk(2, "timeout report (duration: %d)\n", sample); | |
81 | ||
82 | /* Normal sample */ | |
83 | } else { | |
84 | if (dev->gap) { | |
85 | dev->gap_duration += ktime_to_ns(ktime_sub(ktime_get(), | |
86 | dev->gap_start)); | |
87 | ||
88 | /* Convert to ms and cap by LIRC_VALUE_MASK */ | |
89 | do_div(dev->gap_duration, 1000); | |
90 | dev->gap_duration = min_t(u64, dev->gap_duration, | |
91 | LIRC_VALUE_MASK); | |
92 | ||
7e45d660 SY |
93 | spin_lock_irqsave(&dev->lirc_fh_lock, flags); |
94 | list_for_each_entry(fh, &dev->lirc_fh, list) | |
95 | kfifo_put(&fh->rawir, | |
96 | LIRC_SPACE(dev->gap_duration)); | |
97 | spin_unlock_irqrestore(&dev->lirc_fh_lock, flags); | |
42e0442f SY |
98 | dev->gap = false; |
99 | } | |
100 | ||
101 | sample = ev.pulse ? LIRC_PULSE(ev.duration / 1000) : | |
102 | LIRC_SPACE(ev.duration / 1000); | |
103 | IR_dprintk(2, "delivering %uus %s to lirc_dev\n", | |
104 | TO_US(ev.duration), TO_STR(ev.pulse)); | |
105 | } | |
106 | ||
7e45d660 SY |
107 | spin_lock_irqsave(&dev->lirc_fh_lock, flags); |
108 | list_for_each_entry(fh, &dev->lirc_fh, list) { | |
109 | if (LIRC_IS_TIMEOUT(sample) && !fh->send_timeout_reports) | |
110 | continue; | |
111 | if (kfifo_put(&fh->rawir, sample)) | |
112 | wake_up_poll(&fh->wait_poll, POLLIN | POLLRDNORM); | |
113 | } | |
114 | spin_unlock_irqrestore(&dev->lirc_fh_lock, flags); | |
42e0442f SY |
115 | } |
116 | ||
117 | /** | |
118 | * ir_lirc_scancode_event() - Send scancode data to lirc to be relayed to | |
7e45d660 | 119 | * userspace. This can be called in atomic context. |
42e0442f SY |
120 | * @dev: the struct rc_dev descriptor of the device |
121 | * @lsc: the struct lirc_scancode describing the decoded scancode | |
122 | */ | |
123 | void ir_lirc_scancode_event(struct rc_dev *dev, struct lirc_scancode *lsc) | |
124 | { | |
7e45d660 SY |
125 | unsigned long flags; |
126 | struct lirc_fh *fh; | |
127 | ||
42e0442f SY |
128 | lsc->timestamp = ktime_get_ns(); |
129 | ||
7e45d660 SY |
130 | spin_lock_irqsave(&dev->lirc_fh_lock, flags); |
131 | list_for_each_entry(fh, &dev->lirc_fh, list) { | |
132 | if (kfifo_put(&fh->scancodes, *lsc)) | |
133 | wake_up_poll(&fh->wait_poll, POLLIN | POLLRDNORM); | |
134 | } | |
135 | spin_unlock_irqrestore(&dev->lirc_fh_lock, flags); | |
42e0442f SY |
136 | } |
137 | EXPORT_SYMBOL_GPL(ir_lirc_scancode_event); | |
138 | ||
139 | static int ir_lirc_open(struct inode *inode, struct file *file) | |
140 | { | |
141 | struct rc_dev *dev = container_of(inode->i_cdev, struct rc_dev, | |
142 | lirc_cdev); | |
7e45d660 SY |
143 | struct lirc_fh *fh = kzalloc(sizeof(*fh), GFP_KERNEL); |
144 | unsigned long flags; | |
42e0442f SY |
145 | int retval; |
146 | ||
7e45d660 SY |
147 | if (!fh) |
148 | return -ENOMEM; | |
42e0442f | 149 | |
7e45d660 | 150 | get_device(&dev->dev); |
42e0442f SY |
151 | |
152 | if (!dev->registered) { | |
153 | retval = -ENODEV; | |
7e45d660 | 154 | goto out_fh; |
42e0442f SY |
155 | } |
156 | ||
7e45d660 SY |
157 | if (dev->driver_type == RC_DRIVER_IR_RAW) { |
158 | if (kfifo_alloc(&fh->rawir, MAX_IR_EVENT_SIZE, GFP_KERNEL)) { | |
159 | retval = -ENOMEM; | |
160 | goto out_fh; | |
161 | } | |
42e0442f SY |
162 | } |
163 | ||
7e45d660 SY |
164 | if (dev->driver_type != RC_DRIVER_IR_RAW_TX) { |
165 | if (kfifo_alloc(&fh->scancodes, 32, GFP_KERNEL)) { | |
166 | retval = -ENOMEM; | |
167 | goto out_rawir; | |
168 | } | |
169 | } | |
170 | ||
171 | fh->send_mode = LIRC_MODE_PULSE; | |
172 | fh->rc = dev; | |
173 | fh->send_timeout_reports = true; | |
174 | ||
175 | if (dev->driver_type == RC_DRIVER_SCANCODE) | |
176 | fh->rec_mode = LIRC_MODE_SCANCODE; | |
177 | else | |
178 | fh->rec_mode = LIRC_MODE_MODE2; | |
179 | ||
180 | retval = rc_open(dev); | |
181 | if (retval) | |
182 | goto out_kfifo; | |
183 | ||
184 | init_waitqueue_head(&fh->wait_poll); | |
42e0442f | 185 | |
7e45d660 SY |
186 | file->private_data = fh; |
187 | spin_lock_irqsave(&dev->lirc_fh_lock, flags); | |
188 | list_add(&fh->list, &dev->lirc_fh); | |
189 | spin_unlock_irqrestore(&dev->lirc_fh_lock, flags); | |
42e0442f SY |
190 | |
191 | nonseekable_open(inode, file); | |
42e0442f SY |
192 | |
193 | return 0; | |
7e45d660 SY |
194 | out_kfifo: |
195 | if (dev->driver_type != RC_DRIVER_IR_RAW_TX) | |
196 | kfifo_free(&fh->scancodes); | |
197 | out_rawir: | |
198 | if (dev->driver_type == RC_DRIVER_IR_RAW) | |
199 | kfifo_free(&fh->rawir); | |
200 | out_fh: | |
201 | kfree(fh); | |
202 | put_device(&dev->dev); | |
42e0442f | 203 | |
42e0442f SY |
204 | return retval; |
205 | } | |
206 | ||
207 | static int ir_lirc_close(struct inode *inode, struct file *file) | |
208 | { | |
7e45d660 SY |
209 | struct lirc_fh *fh = file->private_data; |
210 | struct rc_dev *dev = fh->rc; | |
211 | unsigned long flags; | |
42e0442f | 212 | |
7e45d660 SY |
213 | spin_lock_irqsave(&dev->lirc_fh_lock, flags); |
214 | list_del(&fh->list); | |
215 | spin_unlock_irqrestore(&dev->lirc_fh_lock, flags); | |
216 | ||
217 | if (dev->driver_type == RC_DRIVER_IR_RAW) | |
218 | kfifo_free(&fh->rawir); | |
219 | if (dev->driver_type != RC_DRIVER_IR_RAW_TX) | |
220 | kfifo_free(&fh->scancodes); | |
221 | kfree(fh); | |
42e0442f SY |
222 | |
223 | rc_close(dev); | |
7e45d660 | 224 | put_device(&dev->dev); |
42e0442f SY |
225 | |
226 | return 0; | |
227 | } | |
228 | ||
229 | static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf, | |
230 | size_t n, loff_t *ppos) | |
231 | { | |
7e45d660 SY |
232 | struct lirc_fh *fh = file->private_data; |
233 | struct rc_dev *dev = fh->rc; | |
42e0442f SY |
234 | unsigned int *txbuf = NULL; |
235 | struct ir_raw_event *raw = NULL; | |
4957133f | 236 | ssize_t ret; |
42e0442f SY |
237 | size_t count; |
238 | ktime_t start; | |
239 | s64 towait; | |
240 | unsigned int duration = 0; /* signal duration in us */ | |
241 | int i; | |
242 | ||
4957133f SY |
243 | ret = mutex_lock_interruptible(&dev->lock); |
244 | if (ret) | |
245 | return ret; | |
246 | ||
247 | if (!dev->registered) { | |
248 | ret = -ENODEV; | |
249 | goto out; | |
250 | } | |
42e0442f SY |
251 | |
252 | start = ktime_get(); | |
253 | ||
254 | if (!dev->tx_ir) { | |
255 | ret = -EINVAL; | |
256 | goto out; | |
257 | } | |
258 | ||
7e45d660 | 259 | if (fh->send_mode == LIRC_MODE_SCANCODE) { |
42e0442f SY |
260 | struct lirc_scancode scan; |
261 | ||
4957133f SY |
262 | if (n != sizeof(scan)) { |
263 | ret = -EINVAL; | |
264 | goto out; | |
265 | } | |
42e0442f | 266 | |
4957133f SY |
267 | if (copy_from_user(&scan, buf, sizeof(scan))) { |
268 | ret = -EFAULT; | |
269 | goto out; | |
270 | } | |
42e0442f | 271 | |
4957133f SY |
272 | if (scan.flags || scan.keycode || scan.timestamp) { |
273 | ret = -EINVAL; | |
274 | goto out; | |
275 | } | |
42e0442f SY |
276 | |
277 | /* | |
278 | * The scancode field in lirc_scancode is 64-bit simply | |
279 | * to future-proof it, since there are IR protocols encode | |
280 | * use more than 32 bits. For now only 32-bit protocols | |
281 | * are supported. | |
282 | */ | |
283 | if (scan.scancode > U32_MAX || | |
4957133f SY |
284 | !rc_validate_scancode(scan.rc_proto, scan.scancode)) { |
285 | ret = -EINVAL; | |
286 | goto out; | |
287 | } | |
42e0442f SY |
288 | |
289 | raw = kmalloc_array(LIRCBUF_SIZE, sizeof(*raw), GFP_KERNEL); | |
4957133f SY |
290 | if (!raw) { |
291 | ret = -ENOMEM; | |
292 | goto out; | |
293 | } | |
42e0442f SY |
294 | |
295 | ret = ir_raw_encode_scancode(scan.rc_proto, scan.scancode, | |
296 | raw, LIRCBUF_SIZE); | |
297 | if (ret < 0) | |
298 | goto out; | |
299 | ||
300 | count = ret; | |
301 | ||
302 | txbuf = kmalloc_array(count, sizeof(unsigned int), GFP_KERNEL); | |
303 | if (!txbuf) { | |
304 | ret = -ENOMEM; | |
305 | goto out; | |
306 | } | |
307 | ||
308 | for (i = 0; i < count; i++) | |
309 | /* Convert from NS to US */ | |
310 | txbuf[i] = DIV_ROUND_UP(raw[i].duration, 1000); | |
311 | ||
312 | if (dev->s_tx_carrier) { | |
313 | int carrier = ir_raw_encode_carrier(scan.rc_proto); | |
314 | ||
315 | if (carrier > 0) | |
316 | dev->s_tx_carrier(dev, carrier); | |
317 | } | |
318 | } else { | |
4957133f SY |
319 | if (n < sizeof(unsigned int) || n % sizeof(unsigned int)) { |
320 | ret = -EINVAL; | |
321 | goto out; | |
322 | } | |
42e0442f SY |
323 | |
324 | count = n / sizeof(unsigned int); | |
4957133f SY |
325 | if (count > LIRCBUF_SIZE || count % 2 == 0) { |
326 | ret = -EINVAL; | |
327 | goto out; | |
328 | } | |
42e0442f SY |
329 | |
330 | txbuf = memdup_user(buf, n); | |
4957133f SY |
331 | if (IS_ERR(txbuf)) { |
332 | ret = PTR_ERR(txbuf); | |
333 | goto out; | |
334 | } | |
42e0442f SY |
335 | } |
336 | ||
337 | for (i = 0; i < count; i++) { | |
338 | if (txbuf[i] > IR_MAX_DURATION / 1000 - duration || !txbuf[i]) { | |
339 | ret = -EINVAL; | |
340 | goto out; | |
341 | } | |
342 | ||
343 | duration += txbuf[i]; | |
344 | } | |
345 | ||
346 | ret = dev->tx_ir(dev, txbuf, count); | |
347 | if (ret < 0) | |
348 | goto out; | |
349 | ||
7e45d660 | 350 | if (fh->send_mode == LIRC_MODE_SCANCODE) { |
42e0442f SY |
351 | ret = n; |
352 | } else { | |
353 | for (duration = i = 0; i < ret; i++) | |
354 | duration += txbuf[i]; | |
355 | ||
356 | ret *= sizeof(unsigned int); | |
357 | ||
358 | /* | |
359 | * The lircd gap calculation expects the write function to | |
360 | * wait for the actual IR signal to be transmitted before | |
361 | * returning. | |
362 | */ | |
363 | towait = ktime_us_delta(ktime_add_us(start, duration), | |
364 | ktime_get()); | |
365 | if (towait > 0) { | |
366 | set_current_state(TASK_INTERRUPTIBLE); | |
367 | schedule_timeout(usecs_to_jiffies(towait)); | |
368 | } | |
369 | } | |
370 | ||
371 | out: | |
4957133f | 372 | mutex_unlock(&dev->lock); |
42e0442f SY |
373 | kfree(txbuf); |
374 | kfree(raw); | |
375 | return ret; | |
376 | } | |
377 | ||
7e45d660 | 378 | static long ir_lirc_ioctl(struct file *file, unsigned int cmd, |
42e0442f SY |
379 | unsigned long arg) |
380 | { | |
7e45d660 SY |
381 | struct lirc_fh *fh = file->private_data; |
382 | struct rc_dev *dev = fh->rc; | |
42e0442f | 383 | u32 __user *argp = (u32 __user *)(arg); |
4957133f SY |
384 | u32 val = 0; |
385 | int ret; | |
42e0442f SY |
386 | |
387 | if (_IOC_DIR(cmd) & _IOC_WRITE) { | |
388 | ret = get_user(val, argp); | |
389 | if (ret) | |
390 | return ret; | |
391 | } | |
392 | ||
4957133f SY |
393 | ret = mutex_lock_interruptible(&dev->lock); |
394 | if (ret) | |
395 | return ret; | |
396 | ||
397 | if (!dev->registered) { | |
398 | ret = -ENODEV; | |
399 | goto out; | |
400 | } | |
42e0442f SY |
401 | |
402 | switch (cmd) { | |
403 | case LIRC_GET_FEATURES: | |
404 | if (dev->driver_type == RC_DRIVER_SCANCODE) | |
405 | val |= LIRC_CAN_REC_SCANCODE; | |
406 | ||
407 | if (dev->driver_type == RC_DRIVER_IR_RAW) { | |
408 | val |= LIRC_CAN_REC_MODE2 | LIRC_CAN_REC_SCANCODE; | |
409 | if (dev->rx_resolution) | |
410 | val |= LIRC_CAN_GET_REC_RESOLUTION; | |
411 | } | |
412 | ||
413 | if (dev->tx_ir) { | |
414 | val |= LIRC_CAN_SEND_PULSE | LIRC_CAN_SEND_SCANCODE; | |
415 | if (dev->s_tx_mask) | |
416 | val |= LIRC_CAN_SET_TRANSMITTER_MASK; | |
417 | if (dev->s_tx_carrier) | |
418 | val |= LIRC_CAN_SET_SEND_CARRIER; | |
419 | if (dev->s_tx_duty_cycle) | |
420 | val |= LIRC_CAN_SET_SEND_DUTY_CYCLE; | |
421 | } | |
422 | ||
423 | if (dev->s_rx_carrier_range) | |
424 | val |= LIRC_CAN_SET_REC_CARRIER | | |
425 | LIRC_CAN_SET_REC_CARRIER_RANGE; | |
426 | ||
427 | if (dev->s_learning_mode) | |
428 | val |= LIRC_CAN_USE_WIDEBAND_RECEIVER; | |
429 | ||
430 | if (dev->s_carrier_report) | |
431 | val |= LIRC_CAN_MEASURE_CARRIER; | |
432 | ||
433 | if (dev->max_timeout) | |
434 | val |= LIRC_CAN_SET_REC_TIMEOUT; | |
435 | ||
436 | break; | |
437 | ||
438 | /* mode support */ | |
439 | case LIRC_GET_REC_MODE: | |
440 | if (dev->driver_type == RC_DRIVER_IR_RAW_TX) | |
4957133f SY |
441 | ret = -ENOTTY; |
442 | else | |
443 | val = fh->rec_mode; | |
42e0442f SY |
444 | break; |
445 | ||
446 | case LIRC_SET_REC_MODE: | |
447 | switch (dev->driver_type) { | |
448 | case RC_DRIVER_IR_RAW_TX: | |
4957133f SY |
449 | ret = -ENOTTY; |
450 | break; | |
42e0442f SY |
451 | case RC_DRIVER_SCANCODE: |
452 | if (val != LIRC_MODE_SCANCODE) | |
4957133f | 453 | ret = -EINVAL; |
42e0442f SY |
454 | break; |
455 | case RC_DRIVER_IR_RAW: | |
456 | if (!(val == LIRC_MODE_MODE2 || | |
457 | val == LIRC_MODE_SCANCODE)) | |
4957133f | 458 | ret = -EINVAL; |
42e0442f SY |
459 | break; |
460 | } | |
461 | ||
4957133f SY |
462 | if (!ret) |
463 | fh->rec_mode = val; | |
464 | break; | |
42e0442f SY |
465 | |
466 | case LIRC_GET_SEND_MODE: | |
467 | if (!dev->tx_ir) | |
4957133f SY |
468 | ret = -ENOTTY; |
469 | else | |
470 | val = fh->send_mode; | |
42e0442f SY |
471 | break; |
472 | ||
473 | case LIRC_SET_SEND_MODE: | |
474 | if (!dev->tx_ir) | |
4957133f SY |
475 | ret = -ENOTTY; |
476 | else if (!(val == LIRC_MODE_PULSE || val == LIRC_MODE_SCANCODE)) | |
477 | ret = -EINVAL; | |
478 | else | |
479 | fh->send_mode = val; | |
480 | break; | |
42e0442f SY |
481 | |
482 | /* TX settings */ | |
483 | case LIRC_SET_TRANSMITTER_MASK: | |
484 | if (!dev->s_tx_mask) | |
4957133f SY |
485 | ret = -ENOTTY; |
486 | else | |
487 | ret = dev->s_tx_mask(dev, val); | |
488 | break; | |
42e0442f SY |
489 | |
490 | case LIRC_SET_SEND_CARRIER: | |
491 | if (!dev->s_tx_carrier) | |
4957133f SY |
492 | ret = -ENOTTY; |
493 | else | |
494 | ret = dev->s_tx_carrier(dev, val); | |
495 | break; | |
42e0442f SY |
496 | |
497 | case LIRC_SET_SEND_DUTY_CYCLE: | |
498 | if (!dev->s_tx_duty_cycle) | |
4957133f SY |
499 | ret = -ENOTTY; |
500 | else if (val <= 0 || val >= 100) | |
501 | ret = -EINVAL; | |
502 | else | |
503 | ret = dev->s_tx_duty_cycle(dev, val); | |
504 | break; | |
42e0442f SY |
505 | |
506 | /* RX settings */ | |
507 | case LIRC_SET_REC_CARRIER: | |
508 | if (!dev->s_rx_carrier_range) | |
4957133f SY |
509 | ret = -ENOTTY; |
510 | else if (val <= 0) | |
511 | ret = -EINVAL; | |
512 | else | |
513 | ret = dev->s_rx_carrier_range(dev, fh->carrier_low, | |
514 | val); | |
515 | break; | |
42e0442f SY |
516 | |
517 | case LIRC_SET_REC_CARRIER_RANGE: | |
518 | if (!dev->s_rx_carrier_range) | |
4957133f SY |
519 | ret = -ENOTTY; |
520 | else if (val <= 0) | |
521 | ret = -EINVAL; | |
522 | else | |
523 | fh->carrier_low = val; | |
524 | break; | |
42e0442f SY |
525 | |
526 | case LIRC_GET_REC_RESOLUTION: | |
527 | if (!dev->rx_resolution) | |
4957133f SY |
528 | ret = -ENOTTY; |
529 | else | |
530 | val = dev->rx_resolution / 1000; | |
42e0442f SY |
531 | break; |
532 | ||
533 | case LIRC_SET_WIDEBAND_RECEIVER: | |
534 | if (!dev->s_learning_mode) | |
4957133f SY |
535 | ret = -ENOTTY; |
536 | else | |
537 | ret = dev->s_learning_mode(dev, !!val); | |
538 | break; | |
42e0442f SY |
539 | |
540 | case LIRC_SET_MEASURE_CARRIER_MODE: | |
541 | if (!dev->s_carrier_report) | |
4957133f SY |
542 | ret = -ENOTTY; |
543 | else | |
544 | ret = dev->s_carrier_report(dev, !!val); | |
545 | break; | |
42e0442f SY |
546 | |
547 | /* Generic timeout support */ | |
548 | case LIRC_GET_MIN_TIMEOUT: | |
549 | if (!dev->max_timeout) | |
4957133f SY |
550 | ret = -ENOTTY; |
551 | else | |
552 | val = DIV_ROUND_UP(dev->min_timeout, 1000); | |
42e0442f SY |
553 | break; |
554 | ||
555 | case LIRC_GET_MAX_TIMEOUT: | |
556 | if (!dev->max_timeout) | |
4957133f SY |
557 | ret = -ENOTTY; |
558 | else | |
559 | val = dev->max_timeout / 1000; | |
42e0442f SY |
560 | break; |
561 | ||
562 | case LIRC_SET_REC_TIMEOUT: | |
4957133f SY |
563 | if (!dev->max_timeout) { |
564 | ret = -ENOTTY; | |
565 | } else if (val > U32_MAX / 1000) { | |
566 | /* Check for multiply overflow */ | |
567 | ret = -EINVAL; | |
568 | } else { | |
569 | u32 tmp = val * 1000; | |
570 | ||
571 | if (tmp < dev->min_timeout || tmp > dev->max_timeout) | |
572 | ret = -EINVAL; | |
573 | else if (dev->s_timeout) | |
574 | ret = dev->s_timeout(dev, tmp); | |
575 | else if (!ret) | |
576 | dev->timeout = tmp; | |
577 | } | |
42e0442f SY |
578 | break; |
579 | ||
580 | case LIRC_SET_REC_TIMEOUT_REPORTS: | |
581 | if (!dev->timeout) | |
4957133f SY |
582 | ret = -ENOTTY; |
583 | else | |
584 | fh->send_timeout_reports = !!val; | |
42e0442f SY |
585 | break; |
586 | ||
587 | default: | |
4957133f | 588 | ret = -ENOTTY; |
42e0442f SY |
589 | } |
590 | ||
4957133f | 591 | if (!ret && _IOC_DIR(cmd) & _IOC_READ) |
42e0442f SY |
592 | ret = put_user(val, argp); |
593 | ||
4957133f SY |
594 | out: |
595 | mutex_unlock(&dev->lock); | |
42e0442f SY |
596 | return ret; |
597 | } | |
598 | ||
599 | static unsigned int ir_lirc_poll(struct file *file, | |
600 | struct poll_table_struct *wait) | |
601 | { | |
7e45d660 SY |
602 | struct lirc_fh *fh = file->private_data; |
603 | struct rc_dev *rcdev = fh->rc; | |
42e0442f SY |
604 | unsigned int events = 0; |
605 | ||
7e45d660 | 606 | poll_wait(file, &fh->wait_poll, wait); |
42e0442f SY |
607 | |
608 | if (!rcdev->registered) { | |
609 | events = POLLHUP | POLLERR; | |
610 | } else if (rcdev->driver_type != RC_DRIVER_IR_RAW_TX) { | |
7e45d660 SY |
611 | if (fh->rec_mode == LIRC_MODE_SCANCODE && |
612 | !kfifo_is_empty(&fh->scancodes)) | |
42e0442f SY |
613 | events = POLLIN | POLLRDNORM; |
614 | ||
7e45d660 SY |
615 | if (fh->rec_mode == LIRC_MODE_MODE2 && |
616 | !kfifo_is_empty(&fh->rawir)) | |
42e0442f SY |
617 | events = POLLIN | POLLRDNORM; |
618 | } | |
619 | ||
620 | return events; | |
621 | } | |
622 | ||
623 | static ssize_t ir_lirc_read_mode2(struct file *file, char __user *buffer, | |
624 | size_t length) | |
625 | { | |
7e45d660 SY |
626 | struct lirc_fh *fh = file->private_data; |
627 | struct rc_dev *rcdev = fh->rc; | |
42e0442f SY |
628 | unsigned int copied; |
629 | int ret; | |
630 | ||
631 | if (length < sizeof(unsigned int) || length % sizeof(unsigned int)) | |
632 | return -EINVAL; | |
633 | ||
634 | do { | |
7e45d660 | 635 | if (kfifo_is_empty(&fh->rawir)) { |
42e0442f SY |
636 | if (file->f_flags & O_NONBLOCK) |
637 | return -EAGAIN; | |
638 | ||
7e45d660 SY |
639 | ret = wait_event_interruptible(fh->wait_poll, |
640 | !kfifo_is_empty(&fh->rawir) || | |
42e0442f SY |
641 | !rcdev->registered); |
642 | if (ret) | |
643 | return ret; | |
644 | } | |
645 | ||
646 | if (!rcdev->registered) | |
647 | return -ENODEV; | |
648 | ||
649 | ret = mutex_lock_interruptible(&rcdev->lock); | |
650 | if (ret) | |
651 | return ret; | |
7e45d660 | 652 | ret = kfifo_to_user(&fh->rawir, buffer, length, &copied); |
42e0442f SY |
653 | mutex_unlock(&rcdev->lock); |
654 | if (ret) | |
655 | return ret; | |
656 | } while (copied == 0); | |
657 | ||
658 | return copied; | |
659 | } | |
660 | ||
661 | static ssize_t ir_lirc_read_scancode(struct file *file, char __user *buffer, | |
662 | size_t length) | |
663 | { | |
7e45d660 SY |
664 | struct lirc_fh *fh = file->private_data; |
665 | struct rc_dev *rcdev = fh->rc; | |
42e0442f SY |
666 | unsigned int copied; |
667 | int ret; | |
668 | ||
669 | if (length < sizeof(struct lirc_scancode) || | |
670 | length % sizeof(struct lirc_scancode)) | |
671 | return -EINVAL; | |
672 | ||
673 | do { | |
7e45d660 | 674 | if (kfifo_is_empty(&fh->scancodes)) { |
42e0442f SY |
675 | if (file->f_flags & O_NONBLOCK) |
676 | return -EAGAIN; | |
677 | ||
7e45d660 SY |
678 | ret = wait_event_interruptible(fh->wait_poll, |
679 | !kfifo_is_empty(&fh->scancodes) || | |
42e0442f SY |
680 | !rcdev->registered); |
681 | if (ret) | |
682 | return ret; | |
683 | } | |
684 | ||
685 | if (!rcdev->registered) | |
686 | return -ENODEV; | |
687 | ||
688 | ret = mutex_lock_interruptible(&rcdev->lock); | |
689 | if (ret) | |
690 | return ret; | |
7e45d660 | 691 | ret = kfifo_to_user(&fh->scancodes, buffer, length, &copied); |
42e0442f SY |
692 | mutex_unlock(&rcdev->lock); |
693 | if (ret) | |
694 | return ret; | |
695 | } while (copied == 0); | |
696 | ||
697 | return copied; | |
698 | } | |
699 | ||
700 | static ssize_t ir_lirc_read(struct file *file, char __user *buffer, | |
701 | size_t length, loff_t *ppos) | |
702 | { | |
7e45d660 SY |
703 | struct lirc_fh *fh = file->private_data; |
704 | struct rc_dev *rcdev = fh->rc; | |
42e0442f SY |
705 | |
706 | if (rcdev->driver_type == RC_DRIVER_IR_RAW_TX) | |
707 | return -EINVAL; | |
708 | ||
709 | if (!rcdev->registered) | |
710 | return -ENODEV; | |
711 | ||
7e45d660 | 712 | if (fh->rec_mode == LIRC_MODE_MODE2) |
42e0442f SY |
713 | return ir_lirc_read_mode2(file, buffer, length); |
714 | else /* LIRC_MODE_SCANCODE */ | |
715 | return ir_lirc_read_scancode(file, buffer, length); | |
716 | } | |
717 | ||
718 | static const struct file_operations lirc_fops = { | |
719 | .owner = THIS_MODULE, | |
720 | .write = ir_lirc_transmit_ir, | |
721 | .unlocked_ioctl = ir_lirc_ioctl, | |
722 | #ifdef CONFIG_COMPAT | |
723 | .compat_ioctl = ir_lirc_ioctl, | |
724 | #endif | |
725 | .read = ir_lirc_read, | |
726 | .poll = ir_lirc_poll, | |
727 | .open = ir_lirc_open, | |
728 | .release = ir_lirc_close, | |
729 | .llseek = no_llseek, | |
730 | }; | |
731 | ||
b15e3937 | 732 | static void lirc_release_device(struct device *ld) |
4a62a5ab | 733 | { |
a6ddd4fe | 734 | struct rc_dev *rcdev = container_of(ld, struct rc_dev, lirc_dev); |
3381b779 | 735 | |
a6ddd4fe | 736 | put_device(&rcdev->dev); |
6ecccc37 | 737 | } |
6ecccc37 | 738 | |
a6ddd4fe | 739 | int ir_lirc_register(struct rc_dev *dev) |
6fa99e1a | 740 | { |
a6ddd4fe | 741 | int err, minor; |
4a62a5ab | 742 | |
a6ddd4fe | 743 | minor = ida_simple_get(&lirc_ida, 0, RC_DEV_MAX, GFP_KERNEL); |
7e45d660 SY |
744 | if (minor < 0) |
745 | return minor; | |
3381b779 | 746 | |
7e45d660 SY |
747 | device_initialize(&dev->lirc_dev); |
748 | dev->lirc_dev.class = lirc_class; | |
a6ddd4fe | 749 | dev->lirc_dev.parent = &dev->dev; |
7e45d660 | 750 | dev->lirc_dev.release = lirc_release_device; |
a6ddd4fe SY |
751 | dev->lirc_dev.devt = MKDEV(MAJOR(lirc_base_dev), minor); |
752 | dev_set_name(&dev->lirc_dev, "lirc%d", minor); | |
712551f0 | 753 | |
7e45d660 SY |
754 | INIT_LIST_HEAD(&dev->lirc_fh); |
755 | spin_lock_init(&dev->lirc_fh_lock); | |
756 | ||
a6ddd4fe | 757 | cdev_init(&dev->lirc_cdev, &lirc_fops); |
4a62a5ab | 758 | |
a6ddd4fe SY |
759 | err = cdev_device_add(&dev->lirc_cdev, &dev->lirc_dev); |
760 | if (err) | |
761 | goto out_ida; | |
74c839b2 | 762 | |
a6ddd4fe | 763 | get_device(&dev->dev); |
4a62a5ab | 764 | |
a6ddd4fe SY |
765 | dev_info(&dev->dev, "lirc_dev: driver %s registered at minor = %d", |
766 | dev->driver_name, minor); | |
56481f00 | 767 | |
c3c6dd75 | 768 | return 0; |
a6ddd4fe SY |
769 | |
770 | out_ida: | |
771 | ida_simple_remove(&lirc_ida, minor); | |
a6ddd4fe | 772 | return err; |
4a62a5ab | 773 | } |
4a62a5ab | 774 | |
a6ddd4fe | 775 | void ir_lirc_unregister(struct rc_dev *dev) |
4a62a5ab | 776 | { |
7e45d660 SY |
777 | unsigned long flags; |
778 | struct lirc_fh *fh; | |
779 | ||
a6ddd4fe SY |
780 | dev_dbg(&dev->dev, "lirc_dev: driver %s unregistered from minor = %d\n", |
781 | dev->driver_name, MINOR(dev->lirc_dev.devt)); | |
4a62a5ab | 782 | |
7e45d660 SY |
783 | spin_lock_irqsave(&dev->lirc_fh_lock, flags); |
784 | list_for_each_entry(fh, &dev->lirc_fh, list) | |
785 | wake_up_poll(&fh->wait_poll, POLLHUP | POLLERR); | |
786 | spin_unlock_irqrestore(&dev->lirc_fh_lock, flags); | |
4a62a5ab | 787 | |
a6ddd4fe SY |
788 | cdev_device_del(&dev->lirc_cdev, &dev->lirc_dev); |
789 | ida_simple_remove(&lirc_ida, MINOR(dev->lirc_dev.devt)); | |
4a62a5ab | 790 | } |
4a62a5ab | 791 | |
a60d64b1 | 792 | int __init lirc_dev_init(void) |
4a62a5ab JW |
793 | { |
794 | int retval; | |
795 | ||
796 | lirc_class = class_create(THIS_MODULE, "lirc"); | |
797 | if (IS_ERR(lirc_class)) { | |
3fac0314 | 798 | pr_err("class_create failed\n"); |
54fcecaf | 799 | return PTR_ERR(lirc_class); |
4a62a5ab JW |
800 | } |
801 | ||
a6ddd4fe | 802 | retval = alloc_chrdev_region(&lirc_base_dev, 0, RC_DEV_MAX, |
463015dd | 803 | "BaseRemoteCtl"); |
4a62a5ab JW |
804 | if (retval) { |
805 | class_destroy(lirc_class); | |
3fac0314 | 806 | pr_err("alloc_chrdev_region failed\n"); |
54fcecaf | 807 | return retval; |
4a62a5ab JW |
808 | } |
809 | ||
3fac0314 AS |
810 | pr_info("IR Remote Control driver registered, major %d\n", |
811 | MAJOR(lirc_base_dev)); | |
4a62a5ab | 812 | |
54fcecaf | 813 | return 0; |
4a62a5ab JW |
814 | } |
815 | ||
a60d64b1 | 816 | void __exit lirc_dev_exit(void) |
4a62a5ab JW |
817 | { |
818 | class_destroy(lirc_class); | |
a6ddd4fe | 819 | unregister_chrdev_region(lirc_base_dev, RC_DEV_MAX); |
4a62a5ab | 820 | } |