media video cx23888 driver: ported to new kfifo API
authorStefani Seibold <stefani@seibold.net>
Mon, 21 Dec 2009 22:37:33 +0000 (14:37 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 22 Dec 2009 22:17:57 +0000 (14:17 -0800)
Fix the cx23888 driver to use the new kfifo API.  Using kfifo_reset()
may result in a possible race conditions.  This patch fixes it by using
a spinlock around the kfifo_reset() function.

Signed-off-by: Stefani Seibold <stefani@seibold.net>
Cc: Mauro Carvalho Chehab <mchehab@infradead.org>
Reviewed-by: Andy Walls <awalls@radix.net>
Acked-by: Andy Walls <awalls@radix.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
drivers/media/video/cx23885/cx23888-ir.c

index 3ccc8af..2bf57a4 100644 (file)
@@ -124,15 +124,12 @@ struct cx23888_ir_state {
        atomic_t rxclk_divider;
        atomic_t rx_invert;
 
-       struct kfifo *rx_kfifo;
+       struct kfifo rx_kfifo;
        spinlock_t rx_kfifo_lock;
 
        struct v4l2_subdev_ir_parameters tx_params;
        struct mutex tx_params_lock;
        atomic_t txclk_divider;
-
-       struct kfifo *tx_kfifo;
-       spinlock_t tx_kfifo_lock;
 };
 
 static inline struct cx23888_ir_state *to_state(struct v4l2_subdev *sd)
@@ -522,6 +519,7 @@ static int cx23888_ir_irq_handler(struct v4l2_subdev *sd, u32 status,
 {
        struct cx23888_ir_state *state = to_state(sd);
        struct cx23885_dev *dev = state->dev;
+       unsigned long flags;
 
        u32 cntrl = cx23888_ir_read4(dev, CX23888_IR_CNTRL_REG);
        u32 irqen = cx23888_ir_read4(dev, CX23888_IR_IRQEN_REG);
@@ -594,8 +592,9 @@ static int cx23888_ir_irq_handler(struct v4l2_subdev *sd, u32 status,
                        if (i == 0)
                                break;
                        j = i * sizeof(u32);
-                       k = kfifo_put(state->rx_kfifo,
-                                     (unsigned char *) rx_data, j);
+                       k = kfifo_in_locked(&state->rx_kfifo,
+                                     (unsigned char *) rx_data, j,
+                                     &state->rx_kfifo_lock);
                        if (k != j)
                                kror++; /* rx_kfifo over run */
                }
@@ -631,8 +630,11 @@ static int cx23888_ir_irq_handler(struct v4l2_subdev *sd, u32 status,
                cx23888_ir_write4(dev, CX23888_IR_CNTRL_REG, cntrl);
                *handled = true;
        }
-       if (kfifo_len(state->rx_kfifo) >= CX23888_IR_RX_KFIFO_SIZE / 2)
+
+       spin_lock_irqsave(&state->rx_kfifo_lock, flags);
+       if (kfifo_len(&state->rx_kfifo) >= CX23888_IR_RX_KFIFO_SIZE / 2)
                events |= V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ;
+       spin_unlock_irqrestore(&state->rx_kfifo_lock, flags);
 
        if (events)
                v4l2_subdev_notify(sd, V4L2_SUBDEV_IR_RX_NOTIFY, &events);
@@ -657,7 +659,7 @@ static int cx23888_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count,
                return 0;
        }
 
-       n = kfifo_get(state->rx_kfifo, buf, n);
+       n = kfifo_out_locked(&state->rx_kfifo, buf, n, &state->rx_kfifo_lock);
 
        n /= sizeof(u32);
        *num = n * sizeof(u32);
@@ -785,7 +787,12 @@ static int cx23888_ir_rx_s_parameters(struct v4l2_subdev *sd,
        o->interrupt_enable = p->interrupt_enable;
        o->enable = p->enable;
        if (p->enable) {
-               kfifo_reset(state->rx_kfifo);
+               unsigned long flags;
+
+               spin_lock_irqsave(&state->rx_kfifo_lock, flags);
+               kfifo_reset(&state->rx_kfifo);
+               /* reset tx_fifo too if there is one... */
+               spin_unlock_irqrestore(&state->rx_kfifo_lock, flags);
                if (p->interrupt_enable)
                        irqenable_rx(dev, IRQEN_RSE | IRQEN_RTE | IRQEN_ROE);
                control_rx_enable(dev, p->enable);
@@ -892,7 +899,6 @@ static int cx23888_ir_tx_s_parameters(struct v4l2_subdev *sd,
        o->interrupt_enable = p->interrupt_enable;
        o->enable = p->enable;
        if (p->enable) {
-               kfifo_reset(state->tx_kfifo);
                if (p->interrupt_enable)
                        irqenable_tx(dev, IRQEN_TSE);
                control_tx_enable(dev, p->enable);
@@ -1168,18 +1174,8 @@ int cx23888_ir_probe(struct cx23885_dev *dev)
                return -ENOMEM;
 
        spin_lock_init(&state->rx_kfifo_lock);
-       state->rx_kfifo = kfifo_alloc(CX23888_IR_RX_KFIFO_SIZE, GFP_KERNEL,
-                                     &state->rx_kfifo_lock);
-       if (state->rx_kfifo == NULL)
-               return -ENOMEM;
-
-       spin_lock_init(&state->tx_kfifo_lock);
-       state->tx_kfifo = kfifo_alloc(CX23888_IR_TX_KFIFO_SIZE, GFP_KERNEL,
-                                     &state->tx_kfifo_lock);
-       if (state->tx_kfifo == NULL) {
-               kfifo_free(state->rx_kfifo);
+       if (kfifo_alloc(&state->rx_kfifo, CX23888_IR_RX_KFIFO_SIZE, GFP_KERNEL))
                return -ENOMEM;
-       }
 
        state->dev = dev;
        state->id = V4L2_IDENT_CX23888_IR;
@@ -1211,8 +1207,7 @@ int cx23888_ir_probe(struct cx23885_dev *dev)
                       sizeof(struct v4l2_subdev_ir_parameters));
                v4l2_subdev_call(sd, ir, tx_s_parameters, &default_params);
        } else {
-               kfifo_free(state->rx_kfifo);
-               kfifo_free(state->tx_kfifo);
+               kfifo_free(&state->rx_kfifo);
        }
        return ret;
 }
@@ -1231,8 +1226,7 @@ int cx23888_ir_remove(struct cx23885_dev *dev)
 
        state = to_state(sd);
        v4l2_device_unregister_subdev(sd);
-       kfifo_free(state->rx_kfifo);
-       kfifo_free(state->tx_kfifo);
+       kfifo_free(&state->rx_kfifo);
        kfree(state);
        /* Nothing more to free() as state held the actual v4l2_subdev object */
        return 0;