blob: 3cc95deaa84eab23f0ee99c502f355dcff4776c4 [file] [log] [blame]
Jarod Wilson4a62a5a2010-07-03 01:06:57 -03001/*
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 *
Jarod Wilson4a62a5a2010-07-03 01:06:57 -030016 */
17
Andi Shyti3fac0312016-07-06 06:01:16 -030018#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
19
Jarod Wilson4a62a5a2010-07-03 01:06:57 -030020#include <linux/module.h>
Ingo Molnar174cd4b2017-02-02 19:15:33 +010021#include <linux/sched/signal.h>
Jarod Wilson4a62a5a2010-07-03 01:06:57 -030022#include <linux/ioctl.h>
Jarod Wilson4a62a5a2010-07-03 01:06:57 -030023#include <linux/poll.h>
Jarod Wilson4a62a5a2010-07-03 01:06:57 -030024#include <linux/mutex.h>
Jarod Wilson4a62a5a2010-07-03 01:06:57 -030025#include <linux/device.h>
26#include <linux/cdev.h>
David Härdeman46c8f472017-06-25 09:32:05 -030027#include <linux/idr.h>
Jarod Wilson4a62a5a2010-07-03 01:06:57 -030028
Sean Younga60d64b2017-09-23 10:41:13 -040029#include "rc-core-priv.h"
Jarod Wilson4a62a5a2010-07-03 01:06:57 -030030#include <media/lirc.h>
Jarod Wilson56900852010-07-16 14:25:33 -030031#include <media/lirc_dev.h>
Jarod Wilson4a62a5a2010-07-03 01:06:57 -030032
Jarod Wilson4a62a5a2010-07-03 01:06:57 -030033#define LOGHEAD "lirc_dev (%s[%d]): "
34
35static dev_t lirc_base_dev;
36
David Härdeman46c8f472017-06-25 09:32:05 -030037/* Used to keep track of allocated lirc devices */
38#define LIRC_MAX_DEVICES 256
39static DEFINE_IDA(lirc_ida);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -030040
41/* Only used for sysfs but defined to void otherwise */
42static struct class *lirc_class;
43
David Härdemanb15e3932017-06-25 09:32:36 -030044static void lirc_release_device(struct device *ld)
Jarod Wilson4a62a5a2010-07-03 01:06:57 -030045{
David Härdemanb15e3932017-06-25 09:32:36 -030046 struct lirc_dev *d = container_of(ld, struct lirc_dev, dev);
Sean Younga607f512017-08-04 10:12:03 -040047
David Härdemanb15e3932017-06-25 09:32:36 -030048 put_device(d->dev.parent);
49
50 if (d->buf_internal) {
51 lirc_buffer_free(d->buf);
52 kfree(d->buf);
53 d->buf = NULL;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -030054 }
David Härdemanb15e3932017-06-25 09:32:36 -030055 kfree(d);
56 module_put(THIS_MODULE);
David Härdeman3381b772017-06-30 05:41:57 -030057}
58
David Härdemanb15e3932017-06-25 09:32:36 -030059static int lirc_allocate_buffer(struct lirc_dev *d)
David Härdeman3381b772017-06-30 05:41:57 -030060{
David Härdemanb15e3932017-06-25 09:32:36 -030061 int err;
Sean Young74c839b2017-01-30 13:49:58 -020062
David Härdemanb15e3932017-06-25 09:32:36 -030063 if (d->buf) {
64 d->buf_internal = false;
65 return 0;
Andi Shyti6fa99e12016-07-06 06:01:13 -030066 }
Andi Shyti6fa99e12016-07-06 06:01:13 -030067
David Härdemanb15e3932017-06-25 09:32:36 -030068 d->buf = kmalloc(sizeof(*d->buf), GFP_KERNEL);
69 if (!d->buf)
70 return -ENOMEM;
71
72 err = lirc_buffer_init(d->buf, d->chunk_size, d->buffer_size);
73 if (err) {
74 kfree(d->buf);
75 d->buf = NULL;
76 return err;
77 }
78
79 d->buf_internal = true;
80 return 0;
Andi Shyti6fa99e12016-07-06 06:01:13 -030081}
82
David Härdeman6ecccc32017-06-25 09:32:15 -030083struct lirc_dev *
84lirc_allocate_device(void)
85{
David Härdemanb15e3932017-06-25 09:32:36 -030086 struct lirc_dev *d;
87
88 d = kzalloc(sizeof(*d), GFP_KERNEL);
89 if (d) {
90 mutex_init(&d->mutex);
91 device_initialize(&d->dev);
92 d->dev.class = lirc_class;
93 d->dev.release = lirc_release_device;
94 __module_get(THIS_MODULE);
95 }
96
97 return d;
David Härdeman6ecccc32017-06-25 09:32:15 -030098}
99EXPORT_SYMBOL(lirc_allocate_device);
100
101void lirc_free_device(struct lirc_dev *d)
102{
David Härdemanb15e3932017-06-25 09:32:36 -0300103 if (!d)
104 return;
105
106 put_device(&d->dev);
David Härdeman6ecccc32017-06-25 09:32:15 -0300107}
108EXPORT_SYMBOL(lirc_free_device);
109
David Härdeman5ddc9c02017-09-21 16:13:34 -0300110int lirc_register_device(struct lirc_dev *d)
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300111{
David Härdeman46c8f472017-06-25 09:32:05 -0300112 int minor;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300113 int err;
114
115 if (!d) {
Andi Shyti3fac0312016-07-06 06:01:16 -0300116 pr_err("driver pointer must be not NULL!\n");
Andi Shyti54fceca2016-07-06 06:01:17 -0300117 return -EBADRQC;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300118 }
119
David Härdemanb15e3932017-06-25 09:32:36 -0300120 if (!d->dev.parent) {
121 pr_err("dev parent pointer not filled in!\n");
Andi Shyti54fceca2016-07-06 06:01:17 -0300122 return -EINVAL;
Jarod Wilson715d29a72010-10-18 12:02:01 -0300123 }
124
David Härdeman712551f2017-05-01 13:04:21 -0300125 if (!d->fops) {
126 pr_err("fops pointer not filled in!\n");
127 return -EINVAL;
128 }
129
David Härdemanb15e3932017-06-25 09:32:36 -0300130 if (!d->buf && d->chunk_size < 1) {
David Härdemanb145ef92017-06-25 09:31:45 -0300131 pr_err("chunk_size must be set!\n");
132 return -EINVAL;
133 }
134
David Härdemanb15e3932017-06-25 09:32:36 -0300135 if (!d->buf && d->buffer_size < 1) {
David Härdemanb145ef92017-06-25 09:31:45 -0300136 pr_err("buffer_size must be set!\n");
137 return -EINVAL;
138 }
139
David Härdemanb15e3932017-06-25 09:32:36 -0300140 if (!d->buf && !(d->fops && d->fops->read &&
141 d->fops->poll && d->fops->unlocked_ioctl)) {
142 dev_err(&d->dev, "undefined read, poll, ioctl\n");
Andi Shyti54fceca2016-07-06 06:01:17 -0300143 return -EBADRQC;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300144 }
145
David Härdeman3381b772017-06-30 05:41:57 -0300146 /* some safety check 8-) */
147 d->name[sizeof(d->name) - 1] = '\0';
148
David Härdeman3381b772017-06-30 05:41:57 -0300149 if (LIRC_CAN_REC(d->features)) {
David Härdemanb15e3932017-06-25 09:32:36 -0300150 err = lirc_allocate_buffer(d);
151 if (err)
David Härdeman3381b772017-06-30 05:41:57 -0300152 return err;
David Härdeman3381b772017-06-30 05:41:57 -0300153 }
154
David Härdeman46c8f472017-06-25 09:32:05 -0300155 minor = ida_simple_get(&lirc_ida, 0, LIRC_MAX_DEVICES, GFP_KERNEL);
David Härdemanb15e3932017-06-25 09:32:36 -0300156 if (minor < 0)
David Härdeman46c8f472017-06-25 09:32:05 -0300157 return minor;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300158
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300159 d->minor = minor;
David Härdemanb15e3932017-06-25 09:32:36 -0300160 d->dev.devt = MKDEV(MAJOR(lirc_base_dev), d->minor);
161 dev_set_name(&d->dev, "lirc%d", d->minor);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300162
David Härdemanb15e3932017-06-25 09:32:36 -0300163 cdev_init(&d->cdev, d->fops);
164 d->cdev.owner = d->owner;
165 d->attached = true;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300166
David Härdemanb15e3932017-06-25 09:32:36 -0300167 err = cdev_device_add(&d->cdev, &d->dev);
David Härdeman3381b772017-06-30 05:41:57 -0300168 if (err) {
David Härdeman46c8f472017-06-25 09:32:05 -0300169 ida_simple_remove(&lirc_ida, minor);
David Härdeman3381b772017-06-30 05:41:57 -0300170 return err;
171 }
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300172
David Härdemanb15e3932017-06-25 09:32:36 -0300173 get_device(d->dev.parent);
Sean Younga607f512017-08-04 10:12:03 -0400174
David Härdemanb15e3932017-06-25 09:32:36 -0300175 dev_info(&d->dev, "lirc_dev: driver %s registered at minor = %d\n",
176 d->name, d->minor);
David Härdeman56481f02017-05-01 13:04:11 -0300177
David Härdemanc3c6dd72017-06-25 09:31:24 -0300178 return 0;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300179}
David Härdeman5ddc9c02017-09-21 16:13:34 -0300180EXPORT_SYMBOL(lirc_register_device);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300181
David Härdeman5ddc9c02017-09-21 16:13:34 -0300182void lirc_unregister_device(struct lirc_dev *d)
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300183{
David Härdemanb15e3932017-06-25 09:32:36 -0300184 if (!d)
David Härdemanc3c6dd72017-06-25 09:31:24 -0300185 return;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300186
David Härdemanb15e3932017-06-25 09:32:36 -0300187 dev_dbg(&d->dev, "lirc_dev: driver %s unregistered from minor = %d\n",
David Härdemanc3c6dd72017-06-25 09:31:24 -0300188 d->name, d->minor);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300189
David Härdemanb15e3932017-06-25 09:32:36 -0300190 mutex_lock(&d->mutex);
David Härdeman3381b772017-06-30 05:41:57 -0300191
David Härdemanb15e3932017-06-25 09:32:36 -0300192 d->attached = false;
193 if (d->open) {
194 dev_dbg(&d->dev, LOGHEAD "releasing opened driver\n",
David Härdemanc3c6dd72017-06-25 09:31:24 -0300195 d->name, d->minor);
David Härdemanb15e3932017-06-25 09:32:36 -0300196 wake_up_interruptible(&d->buf->wait_poll);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300197 }
198
David Härdemanb15e3932017-06-25 09:32:36 -0300199 mutex_unlock(&d->mutex);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300200
David Härdemanb15e3932017-06-25 09:32:36 -0300201 cdev_device_del(&d->cdev, &d->dev);
David Härdeman46c8f472017-06-25 09:32:05 -0300202 ida_simple_remove(&lirc_ida, d->minor);
David Härdemanb15e3932017-06-25 09:32:36 -0300203 put_device(&d->dev);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300204}
David Härdeman5ddc9c02017-09-21 16:13:34 -0300205EXPORT_SYMBOL(lirc_unregister_device);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300206
207int lirc_dev_fop_open(struct inode *inode, struct file *file)
208{
David Härdemanb15e3932017-06-25 09:32:36 -0300209 struct lirc_dev *d = container_of(inode->i_cdev, struct lirc_dev, cdev);
David Härdemande226ec2017-06-25 09:31:19 -0300210 int retval;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300211
David Härdemanb15e3932017-06-25 09:32:36 -0300212 dev_dbg(&d->dev, LOGHEAD "open called\n", d->name, d->minor);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300213
David Härdemanb15e3932017-06-25 09:32:36 -0300214 retval = mutex_lock_interruptible(&d->mutex);
David Härdeman3381b772017-06-30 05:41:57 -0300215 if (retval)
216 return retval;
217
David Härdemanb15e3932017-06-25 09:32:36 -0300218 if (!d->attached) {
David Härdeman3381b772017-06-30 05:41:57 -0300219 retval = -ENODEV;
220 goto out;
221 }
222
David Härdemanb15e3932017-06-25 09:32:36 -0300223 if (d->open) {
David Härdeman3381b772017-06-30 05:41:57 -0300224 retval = -EBUSY;
225 goto out;
226 }
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300227
David Härdemanb15e3932017-06-25 09:32:36 -0300228 if (d->rdev) {
229 retval = rc_open(d->rdev);
Srinivas Kandagatlaca7a7222013-07-22 04:23:07 -0300230 if (retval)
David Härdeman3381b772017-06-30 05:41:57 -0300231 goto out;
Srinivas Kandagatlaca7a7222013-07-22 04:23:07 -0300232 }
233
David Härdemanb15e3932017-06-25 09:32:36 -0300234 if (d->buf)
235 lirc_buffer_clear(d->buf);
David Härdeman2c5a1f442017-05-01 13:03:46 -0300236
David Härdemanb15e3932017-06-25 09:32:36 -0300237 d->open++;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300238
Sean Younga60d64b2017-09-23 10:41:13 -0400239 file->private_data = d->rdev;
Arnd Bergmannd9d2e9d2010-08-15 18:51:56 +0200240 nonseekable_open(inode, file);
David Härdemanb15e3932017-06-25 09:32:36 -0300241 mutex_unlock(&d->mutex);
Arnd Bergmannd9d2e9d2010-08-15 18:51:56 +0200242
David Härdemande226ec2017-06-25 09:31:19 -0300243 return 0;
David Härdeman3381b772017-06-30 05:41:57 -0300244
245out:
David Härdemanb15e3932017-06-25 09:32:36 -0300246 mutex_unlock(&d->mutex);
David Härdeman3381b772017-06-30 05:41:57 -0300247 return retval;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300248}
249EXPORT_SYMBOL(lirc_dev_fop_open);
250
251int lirc_dev_fop_close(struct inode *inode, struct file *file)
252{
Sean Younga60d64b2017-09-23 10:41:13 -0400253 struct rc_dev *rcdev = file->private_data;
254 struct lirc_dev *d = rcdev->lirc_dev;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300255
David Härdemanb15e3932017-06-25 09:32:36 -0300256 mutex_lock(&d->mutex);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300257
Sean Younga60d64b2017-09-23 10:41:13 -0400258 rc_close(rcdev);
David Härdemanb15e3932017-06-25 09:32:36 -0300259 d->open--;
David Härdeman3381b772017-06-30 05:41:57 -0300260
David Härdemanb15e3932017-06-25 09:32:36 -0300261 mutex_unlock(&d->mutex);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300262
263 return 0;
264}
265EXPORT_SYMBOL(lirc_dev_fop_close);
266
267unsigned int lirc_dev_fop_poll(struct file *file, poll_table *wait)
268{
Sean Younga60d64b2017-09-23 10:41:13 -0400269 struct rc_dev *rcdev = file->private_data;
270 struct lirc_dev *d = rcdev->lirc_dev;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300271 unsigned int ret;
272
David Härdemanb15e3932017-06-25 09:32:36 -0300273 if (!d->attached)
David Härdeman29debf32017-05-01 13:04:37 -0300274 return POLLHUP | POLLERR;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300275
David Härdemanb15e3932017-06-25 09:32:36 -0300276 if (d->buf) {
277 poll_wait(file, &d->buf->wait_poll, wait);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300278
David Härdemanb15e3932017-06-25 09:32:36 -0300279 if (lirc_buffer_empty(d->buf))
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300280 ret = 0;
281 else
282 ret = POLLIN | POLLRDNORM;
David Härdemanb15e3932017-06-25 09:32:36 -0300283 } else {
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300284 ret = POLLERR;
David Härdemanb15e3932017-06-25 09:32:36 -0300285 }
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300286
David Härdemanb15e3932017-06-25 09:32:36 -0300287 dev_dbg(&d->dev, LOGHEAD "poll result = %d\n", d->name, d->minor, ret);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300288
289 return ret;
290}
291EXPORT_SYMBOL(lirc_dev_fop_poll);
292
Arnd Bergmann044e5872010-08-02 15:43:35 -0300293long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300294{
Sean Younga60d64b2017-09-23 10:41:13 -0400295 struct rc_dev *rcdev = file->private_data;
296 struct lirc_dev *d = rcdev->lirc_dev;
Jarod Wilsonbe1f9852010-10-08 17:24:21 -0300297 __u32 mode;
David Härdeman3381b772017-06-30 05:41:57 -0300298 int result;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300299
David Härdemanb15e3932017-06-25 09:32:36 -0300300 dev_dbg(&d->dev, LOGHEAD "ioctl called (0x%x)\n",
301 d->name, d->minor, cmd);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300302
David Härdemanb15e3932017-06-25 09:32:36 -0300303 result = mutex_lock_interruptible(&d->mutex);
David Härdeman3381b772017-06-30 05:41:57 -0300304 if (result)
305 return result;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300306
David Härdemanb15e3932017-06-25 09:32:36 -0300307 if (!d->attached) {
David Härdeman3381b772017-06-30 05:41:57 -0300308 result = -ENODEV;
309 goto out;
310 }
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300311
312 switch (cmd) {
313 case LIRC_GET_FEATURES:
David Härdemanb15e3932017-06-25 09:32:36 -0300314 result = put_user(d->features, (__u32 __user *)arg);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300315 break;
316 case LIRC_GET_REC_MODE:
David Härdemanb15e3932017-06-25 09:32:36 -0300317 if (!LIRC_CAN_REC(d->features)) {
Andi Shytib4088092016-07-06 06:01:24 -0300318 result = -ENOTTY;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300319 break;
320 }
321
322 result = put_user(LIRC_REC2MODE
David Härdemanb15e3932017-06-25 09:32:36 -0300323 (d->features & LIRC_CAN_REC_MASK),
Hans Verkuil60519af2014-08-20 19:41:03 -0300324 (__u32 __user *)arg);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300325 break;
326 case LIRC_SET_REC_MODE:
David Härdemanb15e3932017-06-25 09:32:36 -0300327 if (!LIRC_CAN_REC(d->features)) {
Andi Shytib4088092016-07-06 06:01:24 -0300328 result = -ENOTTY;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300329 break;
330 }
331
Hans Verkuil60519af2014-08-20 19:41:03 -0300332 result = get_user(mode, (__u32 __user *)arg);
David Härdemanb15e3932017-06-25 09:32:36 -0300333 if (!result && !(LIRC_MODE2REC(mode) & d->features))
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300334 result = -EINVAL;
335 /*
336 * FIXME: We should actually set the mode somehow but
337 * for now, lirc_serial doesn't support mode changing either
338 */
339 break;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300340 default:
Sean Young5c8627582017-01-26 15:19:33 -0200341 result = -ENOTTY;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300342 }
343
David Härdeman3381b772017-06-30 05:41:57 -0300344out:
David Härdemanb15e3932017-06-25 09:32:36 -0300345 mutex_unlock(&d->mutex);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300346 return result;
347}
348EXPORT_SYMBOL(lirc_dev_fop_ioctl);
349
350ssize_t lirc_dev_fop_read(struct file *file,
Dan Carpenter0e835082010-11-17 02:13:39 -0300351 char __user *buffer,
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300352 size_t length,
353 loff_t *ppos)
354{
Sean Younga60d64b2017-09-23 10:41:13 -0400355 struct rc_dev *rcdev = file->private_data;
356 struct lirc_dev *d = rcdev->lirc_dev;
Jarod Wilson715d29a72010-10-18 12:02:01 -0300357 unsigned char *buf;
David Härdeman3381b772017-06-30 05:41:57 -0300358 int ret, written = 0;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300359 DECLARE_WAITQUEUE(wait, current);
360
David Härdemanb15e3932017-06-25 09:32:36 -0300361 buf = kzalloc(d->buf->chunk_size, GFP_KERNEL);
Jarod Wilson715d29a72010-10-18 12:02:01 -0300362 if (!buf)
363 return -ENOMEM;
364
David Härdemanb15e3932017-06-25 09:32:36 -0300365 dev_dbg(&d->dev, LOGHEAD "read called\n", d->name, d->minor);
366
367 ret = mutex_lock_interruptible(&d->mutex);
David Härdeman3381b772017-06-30 05:41:57 -0300368 if (ret) {
369 kfree(buf);
370 return ret;
Dan Carpenter250f7a52010-11-17 02:20:15 -0300371 }
David Härdeman3381b772017-06-30 05:41:57 -0300372
David Härdemanb15e3932017-06-25 09:32:36 -0300373 if (!d->attached) {
Dan Carpenter250f7a52010-11-17 02:20:15 -0300374 ret = -ENODEV;
375 goto out_locked;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300376 }
377
David Härdemanb15e3932017-06-25 09:32:36 -0300378 if (!LIRC_CAN_REC(d->features)) {
David Härdeman3381b772017-06-30 05:41:57 -0300379 ret = -EINVAL;
380 goto out_locked;
381 }
382
David Härdemanb15e3932017-06-25 09:32:36 -0300383 if (length % d->buf->chunk_size) {
Dan Carpenter250f7a52010-11-17 02:20:15 -0300384 ret = -EINVAL;
385 goto out_locked;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300386 }
387
388 /*
389 * we add ourselves to the task queue before buffer check
390 * to avoid losing scan code (in case when queue is awaken somewhere
391 * between while condition checking and scheduling)
392 */
David Härdemanb15e3932017-06-25 09:32:36 -0300393 add_wait_queue(&d->buf->wait_poll, &wait);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300394
395 /*
396 * while we didn't provide 'length' bytes, device is opened in blocking
397 * mode and 'copy_to_user' is happy, wait for data.
398 */
399 while (written < length && ret == 0) {
David Härdemanb15e3932017-06-25 09:32:36 -0300400 if (lirc_buffer_empty(d->buf)) {
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300401 /* According to the read(2) man page, 'written' can be
402 * returned as less than 'length', instead of blocking
403 * again, returning -EWOULDBLOCK, or returning
Andi Shyti62e92682016-07-06 06:01:25 -0300404 * -ERESTARTSYS
405 */
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300406 if (written)
407 break;
408 if (file->f_flags & O_NONBLOCK) {
409 ret = -EWOULDBLOCK;
410 break;
411 }
412 if (signal_pending(current)) {
413 ret = -ERESTARTSYS;
414 break;
415 }
416
David Härdemanb15e3932017-06-25 09:32:36 -0300417 mutex_unlock(&d->mutex);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300418 set_current_state(TASK_INTERRUPTIBLE);
Sean Young12accdc2016-10-31 15:52:25 -0200419 schedule();
420 set_current_state(TASK_RUNNING);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300421
David Härdemanb15e3932017-06-25 09:32:36 -0300422 ret = mutex_lock_interruptible(&d->mutex);
David Härdeman3381b772017-06-30 05:41:57 -0300423 if (ret) {
David Härdemanb15e3932017-06-25 09:32:36 -0300424 remove_wait_queue(&d->buf->wait_poll, &wait);
Jarod Wilson69c271f2010-07-07 11:29:44 -0300425 goto out_unlocked;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300426 }
427
David Härdemanb15e3932017-06-25 09:32:36 -0300428 if (!d->attached) {
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300429 ret = -ENODEV;
Sean Youngc77d17c02016-10-31 15:52:27 -0200430 goto out_locked;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300431 }
432 } else {
David Härdemanb15e3932017-06-25 09:32:36 -0300433 lirc_buffer_read(d->buf, buf);
Hans Verkuil60519af2014-08-20 19:41:03 -0300434 ret = copy_to_user((void __user *)buffer+written, buf,
David Härdemanb15e3932017-06-25 09:32:36 -0300435 d->buf->chunk_size);
Dan Carpenter250f7a52010-11-17 02:20:15 -0300436 if (!ret)
David Härdemanb15e3932017-06-25 09:32:36 -0300437 written += d->buf->chunk_size;
Dan Carpenter250f7a52010-11-17 02:20:15 -0300438 else
439 ret = -EFAULT;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300440 }
441 }
442
David Härdemanb15e3932017-06-25 09:32:36 -0300443 remove_wait_queue(&d->buf->wait_poll, &wait);
Dan Carpenter250f7a52010-11-17 02:20:15 -0300444
445out_locked:
David Härdemanb15e3932017-06-25 09:32:36 -0300446 mutex_unlock(&d->mutex);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300447
Jarod Wilson69c271f2010-07-07 11:29:44 -0300448out_unlocked:
Jarod Wilson715d29a72010-10-18 12:02:01 -0300449 kfree(buf);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300450
451 return ret ? ret : written;
452}
453EXPORT_SYMBOL(lirc_dev_fop_read);
454
Sean Younga60d64b2017-09-23 10:41:13 -0400455int __init lirc_dev_init(void)
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300456{
457 int retval;
458
459 lirc_class = class_create(THIS_MODULE, "lirc");
460 if (IS_ERR(lirc_class)) {
Andi Shyti3fac0312016-07-06 06:01:16 -0300461 pr_err("class_create failed\n");
Andi Shyti54fceca2016-07-06 06:01:17 -0300462 return PTR_ERR(lirc_class);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300463 }
464
David Härdeman46c8f472017-06-25 09:32:05 -0300465 retval = alloc_chrdev_region(&lirc_base_dev, 0, LIRC_MAX_DEVICES,
David Härdeman463015d2017-05-01 13:04:47 -0300466 "BaseRemoteCtl");
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300467 if (retval) {
468 class_destroy(lirc_class);
Andi Shyti3fac0312016-07-06 06:01:16 -0300469 pr_err("alloc_chrdev_region failed\n");
Andi Shyti54fceca2016-07-06 06:01:17 -0300470 return retval;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300471 }
472
Andi Shyti3fac0312016-07-06 06:01:16 -0300473 pr_info("IR Remote Control driver registered, major %d\n",
474 MAJOR(lirc_base_dev));
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300475
Andi Shyti54fceca2016-07-06 06:01:17 -0300476 return 0;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300477}
478
Sean Younga60d64b2017-09-23 10:41:13 -0400479void __exit lirc_dev_exit(void)
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300480{
481 class_destroy(lirc_class);
David Härdeman46c8f472017-06-25 09:32:05 -0300482 unregister_chrdev_region(lirc_base_dev, LIRC_MAX_DEVICES);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300483}