]>
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; | |
a74b2bff | 234 | unsigned int *txbuf; |
42e0442f | 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; | |
a74b2bff | 249 | goto out_unlock; |
4957133f | 250 | } |
42e0442f SY |
251 | |
252 | start = ktime_get(); | |
253 | ||
254 | if (!dev->tx_ir) { | |
255 | ret = -EINVAL; | |
a74b2bff | 256 | goto out_unlock; |
42e0442f SY |
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; | |
a74b2bff | 264 | goto out_unlock; |
4957133f | 265 | } |
42e0442f | 266 | |
4957133f SY |
267 | if (copy_from_user(&scan, buf, sizeof(scan))) { |
268 | ret = -EFAULT; | |
a74b2bff | 269 | goto out_unlock; |
4957133f | 270 | } |
42e0442f | 271 | |
4957133f SY |
272 | if (scan.flags || scan.keycode || scan.timestamp) { |
273 | ret = -EINVAL; | |
a74b2bff | 274 | goto out_unlock; |
4957133f | 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; | |
a74b2bff | 286 | goto out_unlock; |
4957133f | 287 | } |
42e0442f SY |
288 | |
289 | raw = kmalloc_array(LIRCBUF_SIZE, sizeof(*raw), GFP_KERNEL); | |
4957133f SY |
290 | if (!raw) { |
291 | ret = -ENOMEM; | |
a74b2bff | 292 | goto out_unlock; |
4957133f | 293 | } |
42e0442f SY |
294 | |
295 | ret = ir_raw_encode_scancode(scan.rc_proto, scan.scancode, | |
296 | raw, LIRCBUF_SIZE); | |
297 | if (ret < 0) | |
a74b2bff | 298 | goto out_kfree; |
42e0442f SY |
299 | |
300 | count = ret; | |
301 | ||
302 | txbuf = kmalloc_array(count, sizeof(unsigned int), GFP_KERNEL); | |
303 | if (!txbuf) { | |
304 | ret = -ENOMEM; | |
a74b2bff | 305 | goto out_kfree; |
42e0442f SY |
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; | |
a74b2bff | 321 | goto out_unlock; |
4957133f | 322 | } |
42e0442f SY |
323 | |
324 | count = n / sizeof(unsigned int); | |
4957133f SY |
325 | if (count > LIRCBUF_SIZE || count % 2 == 0) { |
326 | ret = -EINVAL; | |
a74b2bff | 327 | goto out_unlock; |
4957133f | 328 | } |
42e0442f SY |
329 | |
330 | txbuf = memdup_user(buf, n); | |
4957133f SY |
331 | if (IS_ERR(txbuf)) { |
332 | ret = PTR_ERR(txbuf); | |
a74b2bff | 333 | goto out_unlock; |
4957133f | 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; | |
a74b2bff | 340 | goto out_kfree; |
42e0442f SY |
341 | } |
342 | ||
343 | duration += txbuf[i]; | |
344 | } | |
345 | ||
346 | ret = dev->tx_ir(dev, txbuf, count); | |
347 | if (ret < 0) | |
a74b2bff | 348 | goto out_kfree; |
42e0442f | 349 | |
f81a8158 SY |
350 | kfree(txbuf); |
351 | kfree(raw); | |
352 | mutex_unlock(&dev->lock); | |
353 | ||
dde7edff SY |
354 | /* |
355 | * The lircd gap calculation expects the write function to | |
356 | * wait for the actual IR signal to be transmitted before | |
357 | * returning. | |
358 | */ | |
359 | towait = ktime_us_delta(ktime_add_us(start, duration), | |
360 | ktime_get()); | |
361 | if (towait > 0) { | |
362 | set_current_state(TASK_INTERRUPTIBLE); | |
363 | schedule_timeout(usecs_to_jiffies(towait)); | |
42e0442f SY |
364 | } |
365 | ||
f81a8158 | 366 | return n; |
a74b2bff | 367 | out_kfree: |
42e0442f SY |
368 | kfree(txbuf); |
369 | kfree(raw); | |
a74b2bff SY |
370 | out_unlock: |
371 | mutex_unlock(&dev->lock); | |
42e0442f SY |
372 | return ret; |
373 | } | |
374 | ||
7e45d660 | 375 | static long ir_lirc_ioctl(struct file *file, unsigned int cmd, |
42e0442f SY |
376 | unsigned long arg) |
377 | { | |
7e45d660 SY |
378 | struct lirc_fh *fh = file->private_data; |
379 | struct rc_dev *dev = fh->rc; | |
42e0442f | 380 | u32 __user *argp = (u32 __user *)(arg); |
4957133f SY |
381 | u32 val = 0; |
382 | int ret; | |
42e0442f SY |
383 | |
384 | if (_IOC_DIR(cmd) & _IOC_WRITE) { | |
385 | ret = get_user(val, argp); | |
386 | if (ret) | |
387 | return ret; | |
388 | } | |
389 | ||
4957133f SY |
390 | ret = mutex_lock_interruptible(&dev->lock); |
391 | if (ret) | |
392 | return ret; | |
393 | ||
394 | if (!dev->registered) { | |
395 | ret = -ENODEV; | |
396 | goto out; | |
397 | } | |
42e0442f SY |
398 | |
399 | switch (cmd) { | |
400 | case LIRC_GET_FEATURES: | |
401 | if (dev->driver_type == RC_DRIVER_SCANCODE) | |
402 | val |= LIRC_CAN_REC_SCANCODE; | |
403 | ||
404 | if (dev->driver_type == RC_DRIVER_IR_RAW) { | |
405 | val |= LIRC_CAN_REC_MODE2 | LIRC_CAN_REC_SCANCODE; | |
406 | if (dev->rx_resolution) | |
407 | val |= LIRC_CAN_GET_REC_RESOLUTION; | |
408 | } | |
409 | ||
410 | if (dev->tx_ir) { | |
411 | val |= LIRC_CAN_SEND_PULSE | LIRC_CAN_SEND_SCANCODE; | |
412 | if (dev->s_tx_mask) | |
413 | val |= LIRC_CAN_SET_TRANSMITTER_MASK; | |
414 | if (dev->s_tx_carrier) | |
415 | val |= LIRC_CAN_SET_SEND_CARRIER; | |
416 | if (dev->s_tx_duty_cycle) | |
417 | val |= LIRC_CAN_SET_SEND_DUTY_CYCLE; | |
418 | } | |
419 | ||
420 | if (dev->s_rx_carrier_range) | |
421 | val |= LIRC_CAN_SET_REC_CARRIER | | |
422 | LIRC_CAN_SET_REC_CARRIER_RANGE; | |
423 | ||
424 | if (dev->s_learning_mode) | |
425 | val |= LIRC_CAN_USE_WIDEBAND_RECEIVER; | |
426 | ||
427 | if (dev->s_carrier_report) | |
428 | val |= LIRC_CAN_MEASURE_CARRIER; | |
429 | ||
430 | if (dev->max_timeout) | |
431 | val |= LIRC_CAN_SET_REC_TIMEOUT; | |
432 | ||
433 | break; | |
434 | ||
435 | /* mode support */ | |
436 | case LIRC_GET_REC_MODE: | |
437 | if (dev->driver_type == RC_DRIVER_IR_RAW_TX) | |
4957133f SY |
438 | ret = -ENOTTY; |
439 | else | |
440 | val = fh->rec_mode; | |
42e0442f SY |
441 | break; |
442 | ||
443 | case LIRC_SET_REC_MODE: | |
444 | switch (dev->driver_type) { | |
445 | case RC_DRIVER_IR_RAW_TX: | |
4957133f SY |
446 | ret = -ENOTTY; |
447 | break; | |
42e0442f SY |
448 | case RC_DRIVER_SCANCODE: |
449 | if (val != LIRC_MODE_SCANCODE) | |
4957133f | 450 | ret = -EINVAL; |
42e0442f SY |
451 | break; |
452 | case RC_DRIVER_IR_RAW: | |
453 | if (!(val == LIRC_MODE_MODE2 || | |
454 | val == LIRC_MODE_SCANCODE)) | |
4957133f | 455 | ret = -EINVAL; |
42e0442f SY |
456 | break; |
457 | } | |
458 | ||
4957133f SY |
459 | if (!ret) |
460 | fh->rec_mode = val; | |
461 | break; | |
42e0442f SY |
462 | |
463 | case LIRC_GET_SEND_MODE: | |
464 | if (!dev->tx_ir) | |
4957133f SY |
465 | ret = -ENOTTY; |
466 | else | |
467 | val = fh->send_mode; | |
42e0442f SY |
468 | break; |
469 | ||
470 | case LIRC_SET_SEND_MODE: | |
471 | if (!dev->tx_ir) | |
4957133f SY |
472 | ret = -ENOTTY; |
473 | else if (!(val == LIRC_MODE_PULSE || val == LIRC_MODE_SCANCODE)) | |
474 | ret = -EINVAL; | |
475 | else | |
476 | fh->send_mode = val; | |
477 | break; | |
42e0442f SY |
478 | |
479 | /* TX settings */ | |
480 | case LIRC_SET_TRANSMITTER_MASK: | |
481 | if (!dev->s_tx_mask) | |
4957133f SY |
482 | ret = -ENOTTY; |
483 | else | |
484 | ret = dev->s_tx_mask(dev, val); | |
485 | break; | |
42e0442f SY |
486 | |
487 | case LIRC_SET_SEND_CARRIER: | |
488 | if (!dev->s_tx_carrier) | |
4957133f SY |
489 | ret = -ENOTTY; |
490 | else | |
491 | ret = dev->s_tx_carrier(dev, val); | |
492 | break; | |
42e0442f SY |
493 | |
494 | case LIRC_SET_SEND_DUTY_CYCLE: | |
495 | if (!dev->s_tx_duty_cycle) | |
4957133f SY |
496 | ret = -ENOTTY; |
497 | else if (val <= 0 || val >= 100) | |
498 | ret = -EINVAL; | |
499 | else | |
500 | ret = dev->s_tx_duty_cycle(dev, val); | |
501 | break; | |
42e0442f SY |
502 | |
503 | /* RX settings */ | |
504 | case LIRC_SET_REC_CARRIER: | |
505 | if (!dev->s_rx_carrier_range) | |
4957133f SY |
506 | ret = -ENOTTY; |
507 | else if (val <= 0) | |
508 | ret = -EINVAL; | |
509 | else | |
510 | ret = dev->s_rx_carrier_range(dev, fh->carrier_low, | |
511 | val); | |
512 | break; | |
42e0442f SY |
513 | |
514 | case LIRC_SET_REC_CARRIER_RANGE: | |
515 | if (!dev->s_rx_carrier_range) | |
4957133f SY |
516 | ret = -ENOTTY; |
517 | else if (val <= 0) | |
518 | ret = -EINVAL; | |
519 | else | |
520 | fh->carrier_low = val; | |
521 | break; | |
42e0442f SY |
522 | |
523 | case LIRC_GET_REC_RESOLUTION: | |
524 | if (!dev->rx_resolution) | |
4957133f SY |
525 | ret = -ENOTTY; |
526 | else | |
527 | val = dev->rx_resolution / 1000; | |
42e0442f SY |
528 | break; |
529 | ||
530 | case LIRC_SET_WIDEBAND_RECEIVER: | |
531 | if (!dev->s_learning_mode) | |
4957133f SY |
532 | ret = -ENOTTY; |
533 | else | |
534 | ret = dev->s_learning_mode(dev, !!val); | |
535 | break; | |
42e0442f SY |
536 | |
537 | case LIRC_SET_MEASURE_CARRIER_MODE: | |
538 | if (!dev->s_carrier_report) | |
4957133f SY |
539 | ret = -ENOTTY; |
540 | else | |
541 | ret = dev->s_carrier_report(dev, !!val); | |
542 | break; | |
42e0442f SY |
543 | |
544 | /* Generic timeout support */ | |
545 | case LIRC_GET_MIN_TIMEOUT: | |
546 | if (!dev->max_timeout) | |
4957133f SY |
547 | ret = -ENOTTY; |
548 | else | |
549 | val = DIV_ROUND_UP(dev->min_timeout, 1000); | |
42e0442f SY |
550 | break; |
551 | ||
552 | case LIRC_GET_MAX_TIMEOUT: | |
553 | if (!dev->max_timeout) | |
4957133f SY |
554 | ret = -ENOTTY; |
555 | else | |
556 | val = dev->max_timeout / 1000; | |
42e0442f SY |
557 | break; |
558 | ||
559 | case LIRC_SET_REC_TIMEOUT: | |
4957133f SY |
560 | if (!dev->max_timeout) { |
561 | ret = -ENOTTY; | |
562 | } else if (val > U32_MAX / 1000) { | |
563 | /* Check for multiply overflow */ | |
564 | ret = -EINVAL; | |
565 | } else { | |
566 | u32 tmp = val * 1000; | |
567 | ||
568 | if (tmp < dev->min_timeout || tmp > dev->max_timeout) | |
569 | ret = -EINVAL; | |
570 | else if (dev->s_timeout) | |
571 | ret = dev->s_timeout(dev, tmp); | |
572 | else if (!ret) | |
573 | dev->timeout = tmp; | |
574 | } | |
42e0442f SY |
575 | break; |
576 | ||
577 | case LIRC_SET_REC_TIMEOUT_REPORTS: | |
578 | if (!dev->timeout) | |
4957133f SY |
579 | ret = -ENOTTY; |
580 | else | |
581 | fh->send_timeout_reports = !!val; | |
42e0442f SY |
582 | break; |
583 | ||
584 | default: | |
4957133f | 585 | ret = -ENOTTY; |
42e0442f SY |
586 | } |
587 | ||
4957133f | 588 | if (!ret && _IOC_DIR(cmd) & _IOC_READ) |
42e0442f SY |
589 | ret = put_user(val, argp); |
590 | ||
4957133f SY |
591 | out: |
592 | mutex_unlock(&dev->lock); | |
42e0442f SY |
593 | return ret; |
594 | } | |
595 | ||
596 | static unsigned int ir_lirc_poll(struct file *file, | |
597 | struct poll_table_struct *wait) | |
598 | { | |
7e45d660 SY |
599 | struct lirc_fh *fh = file->private_data; |
600 | struct rc_dev *rcdev = fh->rc; | |
42e0442f SY |
601 | unsigned int events = 0; |
602 | ||
7e45d660 | 603 | poll_wait(file, &fh->wait_poll, wait); |
42e0442f SY |
604 | |
605 | if (!rcdev->registered) { | |
606 | events = POLLHUP | POLLERR; | |
607 | } else if (rcdev->driver_type != RC_DRIVER_IR_RAW_TX) { | |
7e45d660 SY |
608 | if (fh->rec_mode == LIRC_MODE_SCANCODE && |
609 | !kfifo_is_empty(&fh->scancodes)) | |
42e0442f SY |
610 | events = POLLIN | POLLRDNORM; |
611 | ||
7e45d660 SY |
612 | if (fh->rec_mode == LIRC_MODE_MODE2 && |
613 | !kfifo_is_empty(&fh->rawir)) | |
42e0442f SY |
614 | events = POLLIN | POLLRDNORM; |
615 | } | |
616 | ||
617 | return events; | |
618 | } | |
619 | ||
620 | static ssize_t ir_lirc_read_mode2(struct file *file, char __user *buffer, | |
621 | size_t length) | |
622 | { | |
7e45d660 SY |
623 | struct lirc_fh *fh = file->private_data; |
624 | struct rc_dev *rcdev = fh->rc; | |
42e0442f SY |
625 | unsigned int copied; |
626 | int ret; | |
627 | ||
628 | if (length < sizeof(unsigned int) || length % sizeof(unsigned int)) | |
629 | return -EINVAL; | |
630 | ||
631 | do { | |
7e45d660 | 632 | if (kfifo_is_empty(&fh->rawir)) { |
42e0442f SY |
633 | if (file->f_flags & O_NONBLOCK) |
634 | return -EAGAIN; | |
635 | ||
7e45d660 SY |
636 | ret = wait_event_interruptible(fh->wait_poll, |
637 | !kfifo_is_empty(&fh->rawir) || | |
42e0442f SY |
638 | !rcdev->registered); |
639 | if (ret) | |
640 | return ret; | |
641 | } | |
642 | ||
643 | if (!rcdev->registered) | |
644 | return -ENODEV; | |
645 | ||
646 | ret = mutex_lock_interruptible(&rcdev->lock); | |
647 | if (ret) | |
648 | return ret; | |
7e45d660 | 649 | ret = kfifo_to_user(&fh->rawir, buffer, length, &copied); |
42e0442f SY |
650 | mutex_unlock(&rcdev->lock); |
651 | if (ret) | |
652 | return ret; | |
653 | } while (copied == 0); | |
654 | ||
655 | return copied; | |
656 | } | |
657 | ||
658 | static ssize_t ir_lirc_read_scancode(struct file *file, char __user *buffer, | |
659 | size_t length) | |
660 | { | |
7e45d660 SY |
661 | struct lirc_fh *fh = file->private_data; |
662 | struct rc_dev *rcdev = fh->rc; | |
42e0442f SY |
663 | unsigned int copied; |
664 | int ret; | |
665 | ||
666 | if (length < sizeof(struct lirc_scancode) || | |
667 | length % sizeof(struct lirc_scancode)) | |
668 | return -EINVAL; | |
669 | ||
670 | do { | |
7e45d660 | 671 | if (kfifo_is_empty(&fh->scancodes)) { |
42e0442f SY |
672 | if (file->f_flags & O_NONBLOCK) |
673 | return -EAGAIN; | |
674 | ||
7e45d660 SY |
675 | ret = wait_event_interruptible(fh->wait_poll, |
676 | !kfifo_is_empty(&fh->scancodes) || | |
42e0442f SY |
677 | !rcdev->registered); |
678 | if (ret) | |
679 | return ret; | |
680 | } | |
681 | ||
682 | if (!rcdev->registered) | |
683 | return -ENODEV; | |
684 | ||
685 | ret = mutex_lock_interruptible(&rcdev->lock); | |
686 | if (ret) | |
687 | return ret; | |
7e45d660 | 688 | ret = kfifo_to_user(&fh->scancodes, buffer, length, &copied); |
42e0442f SY |
689 | mutex_unlock(&rcdev->lock); |
690 | if (ret) | |
691 | return ret; | |
692 | } while (copied == 0); | |
693 | ||
694 | return copied; | |
695 | } | |
696 | ||
697 | static ssize_t ir_lirc_read(struct file *file, char __user *buffer, | |
698 | size_t length, loff_t *ppos) | |
699 | { | |
7e45d660 SY |
700 | struct lirc_fh *fh = file->private_data; |
701 | struct rc_dev *rcdev = fh->rc; | |
42e0442f SY |
702 | |
703 | if (rcdev->driver_type == RC_DRIVER_IR_RAW_TX) | |
704 | return -EINVAL; | |
705 | ||
706 | if (!rcdev->registered) | |
707 | return -ENODEV; | |
708 | ||
7e45d660 | 709 | if (fh->rec_mode == LIRC_MODE_MODE2) |
42e0442f SY |
710 | return ir_lirc_read_mode2(file, buffer, length); |
711 | else /* LIRC_MODE_SCANCODE */ | |
712 | return ir_lirc_read_scancode(file, buffer, length); | |
713 | } | |
714 | ||
715 | static const struct file_operations lirc_fops = { | |
716 | .owner = THIS_MODULE, | |
717 | .write = ir_lirc_transmit_ir, | |
718 | .unlocked_ioctl = ir_lirc_ioctl, | |
719 | #ifdef CONFIG_COMPAT | |
720 | .compat_ioctl = ir_lirc_ioctl, | |
721 | #endif | |
722 | .read = ir_lirc_read, | |
723 | .poll = ir_lirc_poll, | |
724 | .open = ir_lirc_open, | |
725 | .release = ir_lirc_close, | |
726 | .llseek = no_llseek, | |
727 | }; | |
728 | ||
b15e3937 | 729 | static void lirc_release_device(struct device *ld) |
4a62a5ab | 730 | { |
a6ddd4fe | 731 | struct rc_dev *rcdev = container_of(ld, struct rc_dev, lirc_dev); |
3381b779 | 732 | |
a6ddd4fe | 733 | put_device(&rcdev->dev); |
6ecccc37 | 734 | } |
6ecccc37 | 735 | |
a6ddd4fe | 736 | int ir_lirc_register(struct rc_dev *dev) |
6fa99e1a | 737 | { |
a6ddd4fe | 738 | int err, minor; |
4a62a5ab | 739 | |
a6ddd4fe | 740 | minor = ida_simple_get(&lirc_ida, 0, RC_DEV_MAX, GFP_KERNEL); |
7e45d660 SY |
741 | if (minor < 0) |
742 | return minor; | |
3381b779 | 743 | |
7e45d660 SY |
744 | device_initialize(&dev->lirc_dev); |
745 | dev->lirc_dev.class = lirc_class; | |
a6ddd4fe | 746 | dev->lirc_dev.parent = &dev->dev; |
7e45d660 | 747 | dev->lirc_dev.release = lirc_release_device; |
a6ddd4fe SY |
748 | dev->lirc_dev.devt = MKDEV(MAJOR(lirc_base_dev), minor); |
749 | dev_set_name(&dev->lirc_dev, "lirc%d", minor); | |
712551f0 | 750 | |
7e45d660 SY |
751 | INIT_LIST_HEAD(&dev->lirc_fh); |
752 | spin_lock_init(&dev->lirc_fh_lock); | |
753 | ||
a6ddd4fe | 754 | cdev_init(&dev->lirc_cdev, &lirc_fops); |
4a62a5ab | 755 | |
a6ddd4fe SY |
756 | err = cdev_device_add(&dev->lirc_cdev, &dev->lirc_dev); |
757 | if (err) | |
758 | goto out_ida; | |
74c839b2 | 759 | |
a6ddd4fe | 760 | get_device(&dev->dev); |
4a62a5ab | 761 | |
a6ddd4fe SY |
762 | dev_info(&dev->dev, "lirc_dev: driver %s registered at minor = %d", |
763 | dev->driver_name, minor); | |
56481f00 | 764 | |
c3c6dd75 | 765 | return 0; |
a6ddd4fe SY |
766 | |
767 | out_ida: | |
768 | ida_simple_remove(&lirc_ida, minor); | |
a6ddd4fe | 769 | return err; |
4a62a5ab | 770 | } |
4a62a5ab | 771 | |
a6ddd4fe | 772 | void ir_lirc_unregister(struct rc_dev *dev) |
4a62a5ab | 773 | { |
7e45d660 SY |
774 | unsigned long flags; |
775 | struct lirc_fh *fh; | |
776 | ||
a6ddd4fe SY |
777 | dev_dbg(&dev->dev, "lirc_dev: driver %s unregistered from minor = %d\n", |
778 | dev->driver_name, MINOR(dev->lirc_dev.devt)); | |
4a62a5ab | 779 | |
7e45d660 SY |
780 | spin_lock_irqsave(&dev->lirc_fh_lock, flags); |
781 | list_for_each_entry(fh, &dev->lirc_fh, list) | |
782 | wake_up_poll(&fh->wait_poll, POLLHUP | POLLERR); | |
783 | spin_unlock_irqrestore(&dev->lirc_fh_lock, flags); | |
4a62a5ab | 784 | |
a6ddd4fe SY |
785 | cdev_device_del(&dev->lirc_cdev, &dev->lirc_dev); |
786 | ida_simple_remove(&lirc_ida, MINOR(dev->lirc_dev.devt)); | |
4a62a5ab | 787 | } |
4a62a5ab | 788 | |
a60d64b1 | 789 | int __init lirc_dev_init(void) |
4a62a5ab JW |
790 | { |
791 | int retval; | |
792 | ||
793 | lirc_class = class_create(THIS_MODULE, "lirc"); | |
794 | if (IS_ERR(lirc_class)) { | |
3fac0314 | 795 | pr_err("class_create failed\n"); |
54fcecaf | 796 | return PTR_ERR(lirc_class); |
4a62a5ab JW |
797 | } |
798 | ||
a6ddd4fe | 799 | retval = alloc_chrdev_region(&lirc_base_dev, 0, RC_DEV_MAX, |
463015dd | 800 | "BaseRemoteCtl"); |
4a62a5ab JW |
801 | if (retval) { |
802 | class_destroy(lirc_class); | |
3fac0314 | 803 | pr_err("alloc_chrdev_region failed\n"); |
54fcecaf | 804 | return retval; |
4a62a5ab JW |
805 | } |
806 | ||
3fac0314 AS |
807 | pr_info("IR Remote Control driver registered, major %d\n", |
808 | MAJOR(lirc_base_dev)); | |
4a62a5ab | 809 | |
54fcecaf | 810 | return 0; |
4a62a5ab JW |
811 | } |
812 | ||
a60d64b1 | 813 | void __exit lirc_dev_exit(void) |
4a62a5ab JW |
814 | { |
815 | class_destroy(lirc_class); | |
a6ddd4fe | 816 | unregister_chrdev_region(lirc_base_dev, RC_DEV_MAX); |
4a62a5ab | 817 | } |