media video cx23888 driver: ported to new kfifo API

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>
This commit is contained in:
Stefani Seibold 2009-12-21 14:37:33 -08:00 committed by Linus Torvalds
parent 86d4880313
commit 7801edb0b8
1 changed files with 19 additions and 25 deletions

View 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,19 +1174,9 @@ 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)
if (kfifo_alloc(&state->rx_kfifo, CX23888_IR_RX_KFIFO_SIZE, GFP_KERNEL))
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);
return -ENOMEM;
}
state->dev = dev;
state->id = V4L2_IDENT_CX23888_IR;
state->rev = 0;
@ -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;