Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[media] media: rc: raw: improve FIFO handling

The FIFO is used for ir_raw_event records, however for some historic
reason the FIFO is used on a per byte basis. IMHO this adds unneeded
complexity. Therefore set up the FIFO for ir_raw_event records.

This also allows to define the FIFO statically as part of
ir_raw_event_ctrl instead of having to allocate the FIFO dynamically.
In addition:

- When writing into the FIFO and it's full return ENOSPC instead of
ENOMEM thus making it easier to tell between "FIFO full" and
"Dynamic memory allocation failed" when the error is propagated to
a higher level.
Also add an error message.

- When reading from the FIFO check whether it's empty.
This is not strictly needed here but kfifo_out is annotated
"must check" anyway.

Successfully tested it with the nuvoton-cir driver.

Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>

authored by

Heiner Kallweit and committed by
Mauro Carvalho Chehab
464254e5 33cb5401

+13 -16
+5 -1
drivers/media/rc/rc-core-priv.h
··· 16 16 #ifndef _RC_CORE_PRIV 17 17 #define _RC_CORE_PRIV 18 18 19 + /* Define the max number of pulse/space transitions to buffer */ 20 + #define MAX_IR_EVENT_SIZE 512 21 + 19 22 #include <linux/slab.h> 20 23 #include <linux/spinlock.h> 21 24 #include <media/rc-core.h> ··· 38 35 struct list_head list; /* to keep track of raw clients */ 39 36 struct task_struct *thread; 40 37 spinlock_t lock; 41 - struct kfifo_rec_ptr_1 kfifo; /* fifo for the pulse/space durations */ 38 + /* fifo for the pulse/space durations */ 39 + DECLARE_KFIFO(kfifo, struct ir_raw_event, MAX_IR_EVENT_SIZE); 42 40 ktime_t last_event; /* when last event occurred */ 43 41 enum raw_event_type last_type; /* last event type */ 44 42 struct rc_dev *dev; /* pointer to the parent rc_dev */
+8 -15
drivers/media/rc/rc-ir-raw.c
··· 20 20 #include <linux/freezer.h> 21 21 #include "rc-core-priv.h" 22 22 23 - /* Define the max number of pulse/space transitions to buffer */ 24 - #define MAX_IR_EVENT_SIZE 512 25 - 26 23 /* Used to keep track of IR raw clients, protected by ir_raw_handler_lock */ 27 24 static LIST_HEAD(ir_raw_client_list); 28 25 ··· 33 36 struct ir_raw_event ev; 34 37 struct ir_raw_handler *handler; 35 38 struct ir_raw_event_ctrl *raw = (struct ir_raw_event_ctrl *)data; 36 - int retval; 37 39 38 40 while (!kthread_should_stop()) { 39 41 40 42 spin_lock_irq(&raw->lock); 41 - retval = kfifo_len(&raw->kfifo); 42 43 43 - if (retval < sizeof(ev)) { 44 + if (!kfifo_len(&raw->kfifo)) { 44 45 set_current_state(TASK_INTERRUPTIBLE); 45 46 46 47 if (kthread_should_stop()) ··· 49 54 continue; 50 55 } 51 56 52 - retval = kfifo_out(&raw->kfifo, &ev, sizeof(ev)); 57 + if(!kfifo_out(&raw->kfifo, &ev, 1)) 58 + dev_err(&raw->dev->dev, "IR event FIFO is empty!\n"); 53 59 spin_unlock_irq(&raw->lock); 54 60 55 61 mutex_lock(&ir_raw_handler_lock); ··· 83 87 IR_dprintk(2, "sample: (%05dus %s)\n", 84 88 TO_US(ev->duration), TO_STR(ev->pulse)); 85 89 86 - if (kfifo_in(&dev->raw->kfifo, ev, sizeof(*ev)) != sizeof(*ev)) 87 - return -ENOMEM; 90 + if (!kfifo_put(&dev->raw->kfifo, *ev)) { 91 + dev_err(&dev->dev, "IR event FIFO is full!\n"); 92 + return -ENOSPC; 93 + } 88 94 89 95 return 0; 90 96 } ··· 271 273 272 274 dev->raw->dev = dev; 273 275 dev->change_protocol = change_protocol; 274 - rc = kfifo_alloc(&dev->raw->kfifo, 275 - sizeof(struct ir_raw_event) * MAX_IR_EVENT_SIZE, 276 - GFP_KERNEL); 277 - if (rc < 0) 278 - goto out; 276 + INIT_KFIFO(dev->raw->kfifo); 279 277 280 278 spin_lock_init(&dev->raw->lock); 281 279 dev->raw->thread = kthread_run(ir_raw_event_thread, dev->raw, ··· 313 319 handler->raw_unregister(dev); 314 320 mutex_unlock(&ir_raw_handler_lock); 315 321 316 - kfifo_free(&dev->raw->kfifo); 317 322 kfree(dev->raw); 318 323 dev->raw = NULL; 319 324 }