b/drivers/media/radio/si470x/radio-si470x-common.c
@@ -347,7 +347,8 @@ static ssize_t si470x_fops_read(struct file *file, char
__user *buf,
{
struct si470x_device *radio = video_drvdata(file);
int retval = 0;
- unsigned int block_count = 0;
+ size_t copied = 0;
+ unsigned int new_rd_index = 0;
/* switch on rds reception */
if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
@@ -366,31 +367,28 @@ static ssize_t si470x_fops_read(struct file *file, char
__user *buf,
}
}
- /* calculate block count from byte count */
- count /= 3;
-
/* copy RDS block out of internal buffer and to user buffer */
- mutex_lock(&radio->lock);
- while (block_count < count) {
+ while (copied < count) {
if (radio->rd_index == radio->wr_index)
break;
- /* always transfer rds complete blocks */
+ /* always transfer complete rds blocks */
if (copy_to_user(buf, &radio->buffer[radio->rd_index], 3))
/* retval = -EFAULT; */
break;
/* increment and wrap read pointer */
- radio->rd_index += 3;
- if (radio->rd_index >= radio->buf_size)
+ new_rd_index = radio->rd_index + 3;
+ if (new_rd_index < radio->buf_size)
+ radio->rd_index = new_rd_index;
+ else
radio->rd_index = 0;
/* increment counters */
- block_count++;
+ copied += 3;
buf += 3;
- retval += 3;
}
- mutex_unlock(&radio->lock);
+ retval = copied;
done:
return retval;
@@ -407,11 +405,8 @@ static unsigned int si470x_fops_poll(struct file *file,
int retval = 0;
/* switch on rds reception */
-
- mutex_lock(&radio->lock);
if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
si470x_rds_on(radio);
- mutex_unlock(&radio->lock);
poll_wait(file, &radio->read_queue, pts);
@@ -485,7 +480,6 @@ static int si470x_vidioc_g_ctrl(struct file *file, void
*priv,
struct si470x_device *radio = video_drvdata(file);
int retval = 0;
- mutex_lock(&radio->lock);
/* safety checks */
retval = si470x_disconnect_check(radio);
if (retval)
@@ -509,7 +503,6 @@ done:
dev_warn(&radio->videodev->dev,
"get control failed with %d\n", retval);
- mutex_unlock(&radio->lock);
return retval;
}
@@ -523,7 +516,6 @@ static int si470x_vidioc_s_ctrl(struct file *file, void
*priv,
struct si470x_device *radio = video_drvdata(file);
int retval = 0;
- mutex_lock(&radio->lock);
/* safety checks */
retval = si470x_disconnect_check(radio);
if (retval)
@@ -550,7 +542,6 @@ done:
if (retval < 0)
dev_warn(&radio->videodev->dev,
"set control failed with %d\n", retval);
- mutex_unlock(&radio->lock);
return retval;
}
@@ -580,7 +571,6 @@ static int si470x_vidioc_g_tuner(struct file *file, void
*priv,
struct si470x_device *radio = video_drvdata(file);
int retval = 0;
- mutex_lock(&radio->lock);
/* safety checks */
retval = si470x_disconnect_check(radio);
if (retval)
@@ -650,7 +640,6 @@ done:
if (retval < 0)
dev_warn(&radio->videodev->dev,
"get tuner failed with %d\n", retval);
- mutex_unlock(&radio->lock);
return retval;
}
@@ -664,7 +653,6 @@ static int si470x_vidioc_s_tuner(struct file *file, void
*priv,
struct si470x_device *radio = video_drvdata(file);
int retval = 0;
- mutex_lock(&radio->lock);
/* safety checks */
retval = si470x_disconnect_check(radio);
if (retval)
@@ -691,7 +679,6 @@ done:
if (retval < 0)
dev_warn(&radio->videodev->dev,
"set tuner failed with %d\n", retval);
- mutex_unlock(&radio->lock);
return retval;
}
@@ -706,7 +693,6 @@ static int si470x_vidioc_g_frequency(struct file *file,
void *priv,
int retval = 0;
/* safety checks */
- mutex_lock(&radio->lock);
retval = si470x_disconnect_check(radio);
if (retval)
goto done;
@@ -723,7 +709,6 @@ done:
if (retval < 0)
dev_warn(&radio->videodev->dev,
"get frequency failed with %d\n", retval);
- mutex_unlock(&radio->lock);
return retval;
}
@@ -737,7 +722,6 @@ static int si470x_vidioc_s_frequency(struct file *file,
void *priv,
struct si470x_device *radio = video_drvdata(file);
int retval = 0;
- mutex_lock(&radio->lock);
/* safety checks */
retval = si470x_disconnect_check(radio);
if (retval)
@@ -754,7 +738,6 @@ done:
if (retval < 0)
dev_warn(&radio->videodev->dev,
"set frequency failed with %d\n", retval);
- mutex_unlock(&radio->lock);
return retval;
}
@@ -768,7 +751,6 @@ static int si470x_vidioc_s_hw_freq_seek(struct file *file,
void *priv,
struct si470x_device *radio = video_drvdata(file);
int retval = 0;
- mutex_lock(&radio->lock);
/* safety checks */
retval = si470x_disconnect_check(radio);
if (retval)
@@ -785,7 +767,6 @@ done:
if (retval < 0)
dev_warn(&radio->videodev->dev,
"set hardware frequency seek failed with %d\n", retval);
- mutex_unlock(&radio->lock);
return retval;
}
b/drivers/media/radio/si470x/radio-si470x-i2c.c
@@ -273,6 +273,8 @@ static void si470x_i2c_interrupt_work(struct work_struct
*work)
unsigned short rds;
unsigned char tmpbuf[3];
int retval = 0;
+ unsigned int new_wr_index = 0;
+ unsigned int new_rd_index = 0;
/* safety checks */
if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
@@ -325,17 +327,21 @@ static void si470x_i2c_interrupt_work(struct work_struct
*work)
/* copy RDS block to internal buffer */
memcpy(&radio->buffer[radio->wr_index], &tmpbuf, 3);
- radio->wr_index += 3;
- /* wrap write pointer */
- if (radio->wr_index >= radio->buf_size)
+ /* increment and wrap write pointer */
+ new_wr_index = radio->wr_index + 3;
+ if (radio->wr_index < radio->buf_size)
+ radio->wr_index = new_wr_index;
+ else
radio->wr_index = 0;
/* check for overflow */
if (radio->wr_index == radio->rd_index) {
/* increment and wrap read pointer */
- radio->rd_index += 3;
- if (radio->rd_index >= radio->buf_size)
+ new_rd_index = radio->rd_index + 3;
+ if (radio->rd_index < radio->buf_size)
+ radio->rd_index = new_rd_index;
+ else
radio->rd_index = 0;
}
}
b/drivers/media/radio/si470x/radio-si470x-usb.c
@@ -375,8 +375,6 @@ int si470x_disconnect_check(struct si470x_device *radio)
/*
* si470x_int_in_callback - rds callback and processing function
- *
- * TODO: do we need to use mutex locks in some sections?
*/
static void si470x_int_in_callback(struct urb *urb)
{
@@ -388,6 +386,8 @@ static void si470x_int_in_callback(struct urb *urb)
unsigned short bler; /* rds block errors */
unsigned short rds;
unsigned char tmpbuf[3];
+ unsigned int new_wr_index = 0;
+ unsigned int new_rd_index = 0;
if (urb->status) {
if (urb->status == -ENOENT ||
@@ -458,20 +458,25 @@ static void si470x_int_in_callback(struct urb *urb)
/* copy RDS block to internal buffer */
memcpy(&radio->buffer[radio->wr_index], &tmpbuf, 3);
- radio->wr_index += 3;
- /* wrap write pointer */
- if (radio->wr_index >= radio->buf_size)
+ /* increment and wrap write pointer */
+ new_wr_index = radio->wr_index + 3;
+ if (radio->wr_index < radio->buf_size)
+ radio->wr_index = new_wr_index;
+ else
radio->wr_index = 0;
/* check for overflow */
if (radio->wr_index == radio->rd_index) {
/* increment and wrap read pointer */
- radio->rd_index += 3;
- if (radio->rd_index >= radio->buf_size)
+ new_rd_index = radio->rd_index + 3;
+ if (radio->rd_index < radio->buf_size)
+ radio->rd_index = new_rd_index;
+ else
radio->rd_index = 0;
}
}
+
if (radio->wr_index != radio->rd_index)
wake_up_interruptible(&radio->read_queue);
}
b/drivers/media/radio/si470x/radio-si470x.h
@@ -147,13 +147,13 @@ struct si470x_device {
/* driver management */
unsigned int users;
+ struct mutex lock;
/* Silabs internal registers (0..15) */
unsigned short registers[RADIO_REGISTER_NUM];
/* RDS receive buffer */
wait_queue_head_t read_queue;
- struct mutex lock; /* buffer locking */
unsigned char *buffer; /* size is always multiple of three */
unsigned int buf_size;
unsigned int rd_index;