blob: a2c5ed0181c1bf5985d75bce9257ad8f2d9d4b75 [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
Srinivas Kandagatlaca7a7222013-07-22 04:23:07 -030029#include <media/rc-core.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
37struct irctl {
38 struct lirc_driver d;
David Härdeman3bce5572017-06-25 09:31:55 -030039 bool attached;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -030040 int open;
41
David Härdeman3381b772017-06-30 05:41:57 -030042 struct mutex mutex; /* protect from simultaneous accesses */
Jarod Wilson4a62a5a2010-07-03 01:06:57 -030043 struct lirc_buffer *buf;
David Härdeman0f7c4062017-05-01 10:32:34 -030044 bool buf_internal;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -030045
Sean Young74c839b2017-01-30 13:49:58 -020046 struct device dev;
47 struct cdev cdev;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -030048};
49
David Härdeman46c8f472017-06-25 09:32:05 -030050/* Used to keep track of allocated lirc devices */
51#define LIRC_MAX_DEVICES 256
52static DEFINE_IDA(lirc_ida);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -030053
54/* Only used for sysfs but defined to void otherwise */
55static struct class *lirc_class;
56
David Härdeman3381b772017-06-30 05:41:57 -030057static void lirc_free_buffer(struct irctl *ir)
Jarod Wilson4a62a5a2010-07-03 01:06:57 -030058{
Sean Younga607f512017-08-04 10:12:03 -040059 put_device(ir->dev.parent);
60
David Härdeman0f7c4062017-05-01 10:32:34 -030061 if (ir->buf_internal) {
Jarod Wilson4a62a5a2010-07-03 01:06:57 -030062 lirc_buffer_free(ir->buf);
63 kfree(ir->buf);
David Härdeman3381b772017-06-30 05:41:57 -030064 ir->buf = NULL;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -030065 }
David Härdeman3381b772017-06-30 05:41:57 -030066}
67
68static void lirc_release(struct device *ld)
69{
70 struct irctl *ir = container_of(ld, struct irctl, dev);
Sean Young74c839b2017-01-30 13:49:58 -020071
David Härdeman3381b772017-06-30 05:41:57 -030072 lirc_free_buffer(ir);
Sean Young74c839b2017-01-30 13:49:58 -020073 kfree(ir);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -030074}
75
Andi Shyti6fa99e12016-07-06 06:01:13 -030076static int lirc_allocate_buffer(struct irctl *ir)
77{
Andi Shyti70143982016-07-06 06:01:14 -030078 int err = 0;
Andi Shyti6fa99e12016-07-06 06:01:13 -030079 struct lirc_driver *d = &ir->d;
80
Andi Shyti6fa99e12016-07-06 06:01:13 -030081 if (d->rbuf) {
82 ir->buf = d->rbuf;
David Härdeman0f7c4062017-05-01 10:32:34 -030083 ir->buf_internal = false;
Andi Shyti6fa99e12016-07-06 06:01:13 -030084 } else {
85 ir->buf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
Andi Shyti70143982016-07-06 06:01:14 -030086 if (!ir->buf) {
87 err = -ENOMEM;
88 goto out;
89 }
Andi Shyti6fa99e12016-07-06 06:01:13 -030090
David Härdemanb145ef92017-06-25 09:31:45 -030091 err = lirc_buffer_init(ir->buf, d->chunk_size, d->buffer_size);
Andi Shyti6fa99e12016-07-06 06:01:13 -030092 if (err) {
93 kfree(ir->buf);
David Härdeman0f7c4062017-05-01 10:32:34 -030094 ir->buf = NULL;
Andi Shyti70143982016-07-06 06:01:14 -030095 goto out;
Andi Shyti6fa99e12016-07-06 06:01:13 -030096 }
David Härdeman0f7c4062017-05-01 10:32:34 -030097
98 ir->buf_internal = true;
David Härdeman56481f02017-05-01 13:04:11 -030099 d->rbuf = ir->buf;
Andi Shyti6fa99e12016-07-06 06:01:13 -0300100 }
Andi Shyti6fa99e12016-07-06 06:01:13 -0300101
Andi Shyti70143982016-07-06 06:01:14 -0300102out:
Andi Shyti70143982016-07-06 06:01:14 -0300103 return err;
Andi Shyti6fa99e12016-07-06 06:01:13 -0300104}
105
David Härdeman56481f02017-05-01 13:04:11 -0300106int lirc_register_driver(struct lirc_driver *d)
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300107{
108 struct irctl *ir;
David Härdeman46c8f472017-06-25 09:32:05 -0300109 int minor;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300110 int err;
111
112 if (!d) {
Andi Shyti3fac0312016-07-06 06:01:16 -0300113 pr_err("driver pointer must be not NULL!\n");
Andi Shyti54fceca2016-07-06 06:01:17 -0300114 return -EBADRQC;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300115 }
116
Jarod Wilson715d29a72010-10-18 12:02:01 -0300117 if (!d->dev) {
Andi Shyti3fac0312016-07-06 06:01:16 -0300118 pr_err("dev pointer not filled in!\n");
Andi Shyti54fceca2016-07-06 06:01:17 -0300119 return -EINVAL;
Jarod Wilson715d29a72010-10-18 12:02:01 -0300120 }
121
David Härdeman712551f2017-05-01 13:04:21 -0300122 if (!d->fops) {
123 pr_err("fops pointer not filled in!\n");
124 return -EINVAL;
125 }
126
David Härdemanb145ef92017-06-25 09:31:45 -0300127 if (!d->rbuf && d->chunk_size < 1) {
128 pr_err("chunk_size must be set!\n");
129 return -EINVAL;
130 }
131
132 if (!d->rbuf && d->buffer_size < 1) {
133 pr_err("buffer_size must be set!\n");
134 return -EINVAL;
135 }
136
Andi Shyti9675ee52016-07-06 06:01:23 -0300137 if (d->code_length < 1 || d->code_length > (BUFLEN * 8)) {
Andi Shyti3fac0312016-07-06 06:01:16 -0300138 dev_err(d->dev, "code length must be less than %d bits\n",
139 BUFLEN * 8);
Andi Shyti54fceca2016-07-06 06:01:17 -0300140 return -EBADRQC;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300141 }
142
David Härdemanc3104e12017-05-01 13:03:56 -0300143 if (!d->rbuf && !(d->fops && d->fops->read &&
144 d->fops->poll && d->fops->unlocked_ioctl)) {
Andi Shyti14db9fc2016-07-06 06:01:21 -0300145 dev_err(d->dev, "undefined read, poll, ioctl\n");
Andi Shyti54fceca2016-07-06 06:01:17 -0300146 return -EBADRQC;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300147 }
148
David Härdeman3381b772017-06-30 05:41:57 -0300149 /* some safety check 8-) */
150 d->name[sizeof(d->name) - 1] = '\0';
151
152 if (d->features == 0)
153 d->features = LIRC_CAN_REC_LIRCCODE;
154
155 ir = kzalloc(sizeof(*ir), GFP_KERNEL);
156 if (!ir)
157 return -ENOMEM;
158
159 mutex_init(&ir->mutex);
160 ir->d = *d;
161
162 if (LIRC_CAN_REC(d->features)) {
163 err = lirc_allocate_buffer(ir);
164 if (err) {
165 kfree(ir);
166 return err;
167 }
168 d->rbuf = ir->buf;
169 }
170
David Härdeman46c8f472017-06-25 09:32:05 -0300171 minor = ida_simple_get(&lirc_ida, 0, LIRC_MAX_DEVICES, GFP_KERNEL);
172 if (minor < 0) {
David Härdeman3381b772017-06-30 05:41:57 -0300173 lirc_free_buffer(ir);
174 kfree(ir);
David Härdeman46c8f472017-06-25 09:32:05 -0300175 return minor;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300176 }
177
David Härdemanc3c6dd72017-06-25 09:31:24 -0300178 d->irctl = ir;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300179 d->minor = minor;
David Härdeman3381b772017-06-30 05:41:57 -0300180 ir->d.minor = minor;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300181
David Härdeman25823222017-05-01 13:04:01 -0300182 device_initialize(&ir->dev);
Sean Young74c839b2017-01-30 13:49:58 -0200183 ir->dev.devt = MKDEV(MAJOR(lirc_base_dev), ir->d.minor);
184 ir->dev.class = lirc_class;
185 ir->dev.parent = d->dev;
186 ir->dev.release = lirc_release;
187 dev_set_name(&ir->dev, "lirc%d", ir->d.minor);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300188
David Härdeman712551f2017-05-01 13:04:21 -0300189 cdev_init(&ir->cdev, d->fops);
190 ir->cdev.owner = ir->d.owner;
David Härdeman3bce5572017-06-25 09:31:55 -0300191 ir->attached = true;
Sean Young74c839b2017-01-30 13:49:58 -0200192
David Härdeman0510d812017-06-25 09:31:35 -0300193 err = cdev_device_add(&ir->cdev, &ir->dev);
David Härdeman3381b772017-06-30 05:41:57 -0300194 if (err) {
David Härdeman46c8f472017-06-25 09:32:05 -0300195 ida_simple_remove(&lirc_ida, minor);
David Härdeman3381b772017-06-30 05:41:57 -0300196 put_device(&ir->dev);
197 return err;
198 }
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300199
Sean Younga607f512017-08-04 10:12:03 -0400200 get_device(ir->dev.parent);
201
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300202 dev_info(ir->d.dev, "lirc_dev: driver %s registered at minor = %d\n",
203 ir->d.name, ir->d.minor);
David Härdeman56481f02017-05-01 13:04:11 -0300204
David Härdemanc3c6dd72017-06-25 09:31:24 -0300205 return 0;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300206}
207EXPORT_SYMBOL(lirc_register_driver);
208
David Härdemanc3c6dd72017-06-25 09:31:24 -0300209void lirc_unregister_driver(struct lirc_driver *d)
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300210{
211 struct irctl *ir;
212
David Härdemanc3c6dd72017-06-25 09:31:24 -0300213 if (!d || !d->irctl)
214 return;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300215
David Härdemanc3c6dd72017-06-25 09:31:24 -0300216 ir = d->irctl;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300217
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300218 dev_dbg(ir->d.dev, "lirc_dev: driver %s unregistered from minor = %d\n",
David Härdemanc3c6dd72017-06-25 09:31:24 -0300219 d->name, d->minor);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300220
David Härdeman3381b772017-06-30 05:41:57 -0300221 cdev_device_del(&ir->cdev, &ir->dev);
222
223 mutex_lock(&ir->mutex);
224
David Härdeman3bce5572017-06-25 09:31:55 -0300225 ir->attached = false;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300226 if (ir->open) {
227 dev_dbg(ir->d.dev, LOGHEAD "releasing opened driver\n",
David Härdemanc3c6dd72017-06-25 09:31:24 -0300228 d->name, d->minor);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300229 wake_up_interruptible(&ir->buf->wait_poll);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300230 }
231
David Härdeman3381b772017-06-30 05:41:57 -0300232 mutex_unlock(&ir->mutex);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300233
David Härdeman46c8f472017-06-25 09:32:05 -0300234 ida_simple_remove(&lirc_ida, d->minor);
Sean Young74c839b2017-01-30 13:49:58 -0200235 put_device(&ir->dev);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300236}
237EXPORT_SYMBOL(lirc_unregister_driver);
238
239int lirc_dev_fop_open(struct inode *inode, struct file *file)
240{
David Härdeman615cd3f2017-06-25 09:31:40 -0300241 struct irctl *ir = container_of(inode->i_cdev, struct irctl, cdev);
David Härdemande226ec2017-06-25 09:31:19 -0300242 int retval;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300243
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300244 dev_dbg(ir->d.dev, LOGHEAD "open called\n", ir->d.name, ir->d.minor);
245
David Härdeman3381b772017-06-30 05:41:57 -0300246 retval = mutex_lock_interruptible(&ir->mutex);
247 if (retval)
248 return retval;
249
250 if (!ir->attached) {
251 retval = -ENODEV;
252 goto out;
253 }
254
255 if (ir->open) {
256 retval = -EBUSY;
257 goto out;
258 }
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300259
Srinivas Kandagatlaca7a7222013-07-22 04:23:07 -0300260 if (ir->d.rdev) {
261 retval = rc_open(ir->d.rdev);
262 if (retval)
David Härdeman3381b772017-06-30 05:41:57 -0300263 goto out;
Srinivas Kandagatlaca7a7222013-07-22 04:23:07 -0300264 }
265
David Härdeman2c5a1f442017-05-01 13:03:46 -0300266 if (ir->buf)
267 lirc_buffer_clear(ir->buf);
268
Sean Young74c839b2017-01-30 13:49:58 -0200269 ir->open++;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300270
David Härdeman615cd3f2017-06-25 09:31:40 -0300271 lirc_init_pdata(inode, file);
Arnd Bergmannd9d2e9d2010-08-15 18:51:56 +0200272 nonseekable_open(inode, file);
David Härdeman3381b772017-06-30 05:41:57 -0300273 mutex_unlock(&ir->mutex);
Arnd Bergmannd9d2e9d2010-08-15 18:51:56 +0200274
David Härdemande226ec2017-06-25 09:31:19 -0300275 return 0;
David Härdeman3381b772017-06-30 05:41:57 -0300276
277out:
278 mutex_unlock(&ir->mutex);
279 return retval;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300280}
281EXPORT_SYMBOL(lirc_dev_fop_open);
282
283int lirc_dev_fop_close(struct inode *inode, struct file *file)
284{
David Härdeman615cd3f2017-06-25 09:31:40 -0300285 struct irctl *ir = file->private_data;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300286
David Härdeman3381b772017-06-30 05:41:57 -0300287 mutex_lock(&ir->mutex);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300288
Markus Elfring3dd94f02014-11-20 09:01:32 -0300289 rc_close(ir->d.rdev);
Jarod Wilson715d29a72010-10-18 12:02:01 -0300290 ir->open--;
David Härdeman3381b772017-06-30 05:41:57 -0300291
292 mutex_unlock(&ir->mutex);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300293
294 return 0;
295}
296EXPORT_SYMBOL(lirc_dev_fop_close);
297
298unsigned int lirc_dev_fop_poll(struct file *file, poll_table *wait)
299{
David Härdeman615cd3f2017-06-25 09:31:40 -0300300 struct irctl *ir = file->private_data;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300301 unsigned int ret;
302
Dan Carpenter5c769a62010-11-17 02:12:23 -0300303 if (!ir->attached)
David Härdeman29debf32017-05-01 13:04:37 -0300304 return POLLHUP | POLLERR;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300305
Andy Shevchenko3656cdd2015-01-06 22:53:37 -0300306 if (ir->buf) {
307 poll_wait(file, &ir->buf->wait_poll, wait);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300308
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300309 if (lirc_buffer_empty(ir->buf))
310 ret = 0;
311 else
312 ret = POLLIN | POLLRDNORM;
Andy Shevchenko3656cdd2015-01-06 22:53:37 -0300313 } else
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300314 ret = POLLERR;
315
316 dev_dbg(ir->d.dev, LOGHEAD "poll result = %d\n",
317 ir->d.name, ir->d.minor, ret);
318
319 return ret;
320}
321EXPORT_SYMBOL(lirc_dev_fop_poll);
322
Arnd Bergmann044e5872010-08-02 15:43:35 -0300323long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300324{
David Härdeman615cd3f2017-06-25 09:31:40 -0300325 struct irctl *ir = file->private_data;
Jarod Wilsonbe1f9852010-10-08 17:24:21 -0300326 __u32 mode;
David Härdeman3381b772017-06-30 05:41:57 -0300327 int result;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300328
329 dev_dbg(ir->d.dev, LOGHEAD "ioctl called (0x%x)\n",
330 ir->d.name, ir->d.minor, cmd);
331
David Härdeman3381b772017-06-30 05:41:57 -0300332 result = mutex_lock_interruptible(&ir->mutex);
333 if (result)
334 return result;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300335
David Härdeman3381b772017-06-30 05:41:57 -0300336 if (!ir->attached) {
337 result = -ENODEV;
338 goto out;
339 }
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300340
341 switch (cmd) {
342 case LIRC_GET_FEATURES:
Hans Verkuil60519af2014-08-20 19:41:03 -0300343 result = put_user(ir->d.features, (__u32 __user *)arg);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300344 break;
345 case LIRC_GET_REC_MODE:
Sean Youngbd291202016-12-02 15:16:08 -0200346 if (!LIRC_CAN_REC(ir->d.features)) {
Andi Shytib4088092016-07-06 06:01:24 -0300347 result = -ENOTTY;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300348 break;
349 }
350
351 result = put_user(LIRC_REC2MODE
352 (ir->d.features & LIRC_CAN_REC_MASK),
Hans Verkuil60519af2014-08-20 19:41:03 -0300353 (__u32 __user *)arg);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300354 break;
355 case LIRC_SET_REC_MODE:
Sean Youngbd291202016-12-02 15:16:08 -0200356 if (!LIRC_CAN_REC(ir->d.features)) {
Andi Shytib4088092016-07-06 06:01:24 -0300357 result = -ENOTTY;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300358 break;
359 }
360
Hans Verkuil60519af2014-08-20 19:41:03 -0300361 result = get_user(mode, (__u32 __user *)arg);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300362 if (!result && !(LIRC_MODE2REC(mode) & ir->d.features))
363 result = -EINVAL;
364 /*
365 * FIXME: We should actually set the mode somehow but
366 * for now, lirc_serial doesn't support mode changing either
367 */
368 break;
369 case LIRC_GET_LENGTH:
Hans Verkuil60519af2014-08-20 19:41:03 -0300370 result = put_user(ir->d.code_length, (__u32 __user *)arg);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300371 break;
372 case LIRC_GET_MIN_TIMEOUT:
373 if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) ||
374 ir->d.min_timeout == 0) {
Andi Shytib4088092016-07-06 06:01:24 -0300375 result = -ENOTTY;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300376 break;
377 }
378
Hans Verkuil60519af2014-08-20 19:41:03 -0300379 result = put_user(ir->d.min_timeout, (__u32 __user *)arg);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300380 break;
381 case LIRC_GET_MAX_TIMEOUT:
382 if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) ||
383 ir->d.max_timeout == 0) {
Andi Shytib4088092016-07-06 06:01:24 -0300384 result = -ENOTTY;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300385 break;
386 }
387
Hans Verkuil60519af2014-08-20 19:41:03 -0300388 result = put_user(ir->d.max_timeout, (__u32 __user *)arg);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300389 break;
390 default:
Sean Young5c8627582017-01-26 15:19:33 -0200391 result = -ENOTTY;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300392 }
393
David Härdeman3381b772017-06-30 05:41:57 -0300394out:
395 mutex_unlock(&ir->mutex);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300396 return result;
397}
398EXPORT_SYMBOL(lirc_dev_fop_ioctl);
399
400ssize_t lirc_dev_fop_read(struct file *file,
Dan Carpenter0e835082010-11-17 02:13:39 -0300401 char __user *buffer,
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300402 size_t length,
403 loff_t *ppos)
404{
David Härdeman615cd3f2017-06-25 09:31:40 -0300405 struct irctl *ir = file->private_data;
Jarod Wilson715d29a72010-10-18 12:02:01 -0300406 unsigned char *buf;
David Härdeman3381b772017-06-30 05:41:57 -0300407 int ret, written = 0;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300408 DECLARE_WAITQUEUE(wait, current);
409
410 dev_dbg(ir->d.dev, LOGHEAD "read called\n", ir->d.name, ir->d.minor);
411
David Härdemanb145ef92017-06-25 09:31:45 -0300412 buf = kzalloc(ir->buf->chunk_size, GFP_KERNEL);
Jarod Wilson715d29a72010-10-18 12:02:01 -0300413 if (!buf)
414 return -ENOMEM;
415
David Härdeman3381b772017-06-30 05:41:57 -0300416 ret = mutex_lock_interruptible(&ir->mutex);
417 if (ret) {
418 kfree(buf);
419 return ret;
Dan Carpenter250f7a52010-11-17 02:20:15 -0300420 }
David Härdeman3381b772017-06-30 05:41:57 -0300421
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300422 if (!ir->attached) {
Dan Carpenter250f7a52010-11-17 02:20:15 -0300423 ret = -ENODEV;
424 goto out_locked;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300425 }
426
David Härdeman3381b772017-06-30 05:41:57 -0300427 if (!LIRC_CAN_REC(ir->d.features)) {
428 ret = -EINVAL;
429 goto out_locked;
430 }
431
David Härdemanb145ef92017-06-25 09:31:45 -0300432 if (length % ir->buf->chunk_size) {
Dan Carpenter250f7a52010-11-17 02:20:15 -0300433 ret = -EINVAL;
434 goto out_locked;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300435 }
436
437 /*
438 * we add ourselves to the task queue before buffer check
439 * to avoid losing scan code (in case when queue is awaken somewhere
440 * between while condition checking and scheduling)
441 */
442 add_wait_queue(&ir->buf->wait_poll, &wait);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300443
444 /*
445 * while we didn't provide 'length' bytes, device is opened in blocking
446 * mode and 'copy_to_user' is happy, wait for data.
447 */
448 while (written < length && ret == 0) {
449 if (lirc_buffer_empty(ir->buf)) {
450 /* According to the read(2) man page, 'written' can be
451 * returned as less than 'length', instead of blocking
452 * again, returning -EWOULDBLOCK, or returning
Andi Shyti62e92682016-07-06 06:01:25 -0300453 * -ERESTARTSYS
454 */
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300455 if (written)
456 break;
457 if (file->f_flags & O_NONBLOCK) {
458 ret = -EWOULDBLOCK;
459 break;
460 }
461 if (signal_pending(current)) {
462 ret = -ERESTARTSYS;
463 break;
464 }
465
David Härdeman3381b772017-06-30 05:41:57 -0300466 mutex_unlock(&ir->mutex);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300467 set_current_state(TASK_INTERRUPTIBLE);
Sean Young12accdc2016-10-31 15:52:25 -0200468 schedule();
469 set_current_state(TASK_RUNNING);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300470
David Härdeman3381b772017-06-30 05:41:57 -0300471 ret = mutex_lock_interruptible(&ir->mutex);
472 if (ret) {
Jarod Wilson69c271f2010-07-07 11:29:44 -0300473 remove_wait_queue(&ir->buf->wait_poll, &wait);
Jarod Wilson69c271f2010-07-07 11:29:44 -0300474 goto out_unlocked;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300475 }
476
477 if (!ir->attached) {
478 ret = -ENODEV;
Sean Youngc77d17c02016-10-31 15:52:27 -0200479 goto out_locked;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300480 }
481 } else {
482 lirc_buffer_read(ir->buf, buf);
Hans Verkuil60519af2014-08-20 19:41:03 -0300483 ret = copy_to_user((void __user *)buffer+written, buf,
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300484 ir->buf->chunk_size);
Dan Carpenter250f7a52010-11-17 02:20:15 -0300485 if (!ret)
486 written += ir->buf->chunk_size;
487 else
488 ret = -EFAULT;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300489 }
490 }
491
492 remove_wait_queue(&ir->buf->wait_poll, &wait);
Dan Carpenter250f7a52010-11-17 02:20:15 -0300493
494out_locked:
David Härdeman3381b772017-06-30 05:41:57 -0300495 mutex_unlock(&ir->mutex);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300496
Jarod Wilson69c271f2010-07-07 11:29:44 -0300497out_unlocked:
Jarod Wilson715d29a72010-10-18 12:02:01 -0300498 kfree(buf);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300499
500 return ret ? ret : written;
501}
502EXPORT_SYMBOL(lirc_dev_fop_read);
503
David Härdeman615cd3f2017-06-25 09:31:40 -0300504void lirc_init_pdata(struct inode *inode, struct file *file)
505{
506 struct irctl *ir = container_of(inode->i_cdev, struct irctl, cdev);
507
508 file->private_data = ir;
509}
510EXPORT_SYMBOL(lirc_init_pdata);
511
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300512void *lirc_get_pdata(struct file *file)
513{
David Härdeman615cd3f2017-06-25 09:31:40 -0300514 struct irctl *ir = file->private_data;
515
516 return ir->d.data;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300517}
518EXPORT_SYMBOL(lirc_get_pdata);
519
520
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300521static int __init lirc_dev_init(void)
522{
523 int retval;
524
525 lirc_class = class_create(THIS_MODULE, "lirc");
526 if (IS_ERR(lirc_class)) {
Andi Shyti3fac0312016-07-06 06:01:16 -0300527 pr_err("class_create failed\n");
Andi Shyti54fceca2016-07-06 06:01:17 -0300528 return PTR_ERR(lirc_class);
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300529 }
530
David Härdeman46c8f472017-06-25 09:32:05 -0300531 retval = alloc_chrdev_region(&lirc_base_dev, 0, LIRC_MAX_DEVICES,
David Härdeman463015d2017-05-01 13:04:47 -0300532 "BaseRemoteCtl");
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300533 if (retval) {
534 class_destroy(lirc_class);
Andi Shyti3fac0312016-07-06 06:01:16 -0300535 pr_err("alloc_chrdev_region failed\n");
Andi Shyti54fceca2016-07-06 06:01:17 -0300536 return retval;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300537 }
538
Andi Shyti3fac0312016-07-06 06:01:16 -0300539 pr_info("IR Remote Control driver registered, major %d\n",
540 MAJOR(lirc_base_dev));
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300541
Andi Shyti54fceca2016-07-06 06:01:17 -0300542 return 0;
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300543}
544
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300545static void __exit lirc_dev_exit(void)
546{
547 class_destroy(lirc_class);
David Härdeman46c8f472017-06-25 09:32:05 -0300548 unregister_chrdev_region(lirc_base_dev, LIRC_MAX_DEVICES);
Andi Shyti3fac0312016-07-06 06:01:16 -0300549 pr_info("module unloaded\n");
Jarod Wilson4a62a5a2010-07-03 01:06:57 -0300550}
551
552module_init(lirc_dev_init);
553module_exit(lirc_dev_exit);
554
555MODULE_DESCRIPTION("LIRC base driver module");
556MODULE_AUTHOR("Artur Lipowski");
557MODULE_LICENSE("GPL");