Re: [RFC PATCH 1/4] si470x: Clean up, introduce the control framework.
Hello Hans, thanks for the improvements. Looks good to me. Acked-by: Tobias Lorenz tobias.lor...@gmx.net Bye, Toby Am Freitag, 4. Mai 2012, 15:30:29 schrieb Hans Verkuil: From: Hans Verkuil hans.verk...@cisco.com This cleans up the code and si470x now uses the proper v4l2 frameworks and passes most of the v4l2-compliance tests. Signed-off-by: Hans Verkuil hans.verk...@cisco.com --- drivers/media/radio/si470x/radio-si470x-common.c | 193 +++--- drivers/media/radio/si470x/radio-si470x-i2c.c| 65 ++-- drivers/media/radio/si470x/radio-si470x-usb.c| 146 +++- drivers/media/radio/si470x/radio-si470x.h| 14 +- 4 files changed, 105 insertions(+), 313 deletions(-) diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c index 0e740c9..de9475f 100644 --- a/drivers/media/radio/si470x/radio-si470x-common.c +++ b/drivers/media/radio/si470x/radio-si470x-common.c @@ -196,9 +196,9 @@ static int si470x_set_chan(struct si470x_device *radio, unsigned short chan) } if ((radio-registers[STATUSRSSI] STATUSRSSI_STC) == 0) - dev_warn(radio-videodev-dev, tune does not complete\n); + dev_warn(radio-videodev.dev, tune does not complete\n); if (timed_out) - dev_warn(radio-videodev-dev, + dev_warn(radio-videodev.dev, tune timed out after %u ms\n, tune_timeout); stop: @@ -344,12 +344,12 @@ static int si470x_set_seek(struct si470x_device *radio, } if ((radio-registers[STATUSRSSI] STATUSRSSI_STC) == 0) - dev_warn(radio-videodev-dev, seek does not complete\n); + dev_warn(radio-videodev.dev, seek does not complete\n); if (radio-registers[STATUSRSSI] STATUSRSSI_SF) - dev_warn(radio-videodev-dev, + dev_warn(radio-videodev.dev, seek failed / band limit reached\n); if (timed_out) - dev_warn(radio-videodev-dev, + dev_warn(radio-videodev.dev, seek timed out after %u ms\n, seek_timeout); stop: @@ -463,7 +463,6 @@ static ssize_t si470x_fops_read(struct file *file, char __user *buf, unsigned int block_count = 0; /* switch on rds reception */ - mutex_lock(radio-lock); if ((radio-registers[SYSCONFIG1] SYSCONFIG1_RDS) == 0) si470x_rds_on(radio); @@ -505,7 +504,6 @@ static ssize_t si470x_fops_read(struct file *file, char __user *buf, } done: - mutex_unlock(radio-lock); return retval; } @@ -521,10 +519,8 @@ static unsigned int si470x_fops_poll(struct file *file, /* 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); @@ -553,134 +549,27 @@ static const struct v4l2_file_operations si470x_fops = { * Video4Linux Interface ** / -/* - * si470x_vidioc_queryctrl - enumerate control items - */ -static int si470x_vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - struct si470x_device *radio = video_drvdata(file); - int retval = -EINVAL; - - /* abort if qc-id is below V4L2_CID_BASE */ - if (qc-id V4L2_CID_BASE) - goto done; - - /* search video control */ - switch (qc-id) { - case V4L2_CID_AUDIO_VOLUME: - return v4l2_ctrl_query_fill(qc, 0, 15, 1, 15); - case V4L2_CID_AUDIO_MUTE: - return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); - } - /* disable unsupported base controls */ - /* to satisfy kradio and such apps */ - if ((retval == -EINVAL) (qc-id V4L2_CID_LASTP1)) { - qc-flags = V4L2_CTRL_FLAG_DISABLED; - retval = 0; - } - -done: - if (retval 0) - dev_warn(radio-videodev-dev, - query controls failed with %d\n, retval); - return retval; -} - - -/* - * si470x_vidioc_g_ctrl - get the value of a control - */ -static int si470x_vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) +static int si470x_s_ctrl(struct v4l2_ctrl *ctrl) { - struct si470x_device *radio = video_drvdata(file); - int retval = 0; - - mutex_lock(radio-lock); - /* safety checks */ - retval = si470x_disconnect_check(radio); - if (retval) - goto done; - - switch (ctrl-id) { - case V4L2_CID_AUDIO_VOLUME: - ctrl-value = radio-registers[SYSCONFIG2] - SYSCONFIG2_VOLUME; - break; - case V4L2_CID_AUDIO_MUTE: - ctrl-value = ((radio-registers[POWERCFG
Re: [RFC PATCH 2/4] si470x: add control event support and more v4l2 compliancy fixes.
Hello Hans, thanks for the improvements. Looks good to me. Acked-by: Tobias Lorenz tobias.lor...@gmx.net Bye, Toby Am Freitag, 4. Mai 2012, 15:30:30 schrieb Hans Verkuil: From: Hans Verkuil hans.verk...@cisco.com Signed-off-by: Hans Verkuil hans.verk...@cisco.com --- drivers/media/radio/si470x/radio-si470x-common.c | 45 ++ 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c index de9475f..e70badf 100644 --- a/drivers/media/radio/si470x/radio-si470x-common.c +++ b/drivers/media/radio/si470x/radio-si470x-common.c @@ -262,7 +262,7 @@ static int si470x_get_freq(struct si470x_device *radio, unsigned int *freq) */ int si470x_set_freq(struct si470x_device *radio, unsigned int freq) { - unsigned int spacing, band_bottom; + unsigned int spacing, band_bottom, band_top; unsigned short chan; /* Spacing (kHz) */ @@ -278,19 +278,26 @@ int si470x_set_freq(struct si470x_device *radio, unsigned int freq) spacing = 0.050 * FREQ_MUL; break; }; - /* Bottom of Band (MHz) */ + /* Bottom/Top of Band (MHz) */ switch ((radio-registers[SYSCONFIG2] SYSCONFIG2_BAND) 6) { /* 0: 87.5 - 108 MHz (USA, Europe) */ case 0: - band_bottom = 87.5 * FREQ_MUL; break; + band_bottom = 87.5 * FREQ_MUL; + band_top = 108 * FREQ_MUL; + break; /* 1: 76 - 108 MHz (Japan wide band) */ default: - band_bottom = 76 * FREQ_MUL; break; + band_bottom = 76 * FREQ_MUL; + band_top = 108 * FREQ_MUL; + break; /* 2: 76 - 90 MHz (Japan) */ case 2: - band_bottom = 76 * FREQ_MUL; break; + band_bottom = 76 * FREQ_MUL; + band_top = 90 * FREQ_MUL; + break; }; + freq = clamp(freq, band_bottom, band_top); /* Chan = [ Freq (Mhz) - Bottom of Band (MHz) ] / Spacing (kHz) */ chan = (freq - band_bottom) / spacing; @@ -515,17 +522,19 @@ static unsigned int si470x_fops_poll(struct file *file, struct poll_table_struct *pts) { struct si470x_device *radio = video_drvdata(file); - int retval = 0; - - /* switch on rds reception */ + unsigned long req_events = poll_requested_events(pts); + int retval = v4l2_ctrl_poll(file, pts); - if ((radio-registers[SYSCONFIG1] SYSCONFIG1_RDS) == 0) - si470x_rds_on(radio); + if (req_events (POLLIN | POLLRDNORM)) { + /* switch on rds reception */ + if ((radio-registers[SYSCONFIG1] SYSCONFIG1_RDS) == 0) + si470x_rds_on(radio); - poll_wait(file, radio-read_queue, pts); + poll_wait(file, radio-read_queue, pts); - if (radio-rd_index != radio-wr_index) - retval = POLLIN | POLLRDNORM; + if (radio-rd_index != radio-wr_index) + retval |= POLLIN | POLLRDNORM; + } return retval; } @@ -637,6 +646,8 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv, tuner-signal = (radio-registers[STATUSRSSI] STATUSRSSI_RSSI); /* the ideal factor is 0x/75 = 873,8 */ tuner-signal = (tuner-signal * 873) + (8 * tuner-signal / 10); + if (tuner-signal 0x) + tuner-signal = 0x; /* automatic frequency control: -1: freq to low, 1 freq to high */ /* AFCRL does only indicate that freq. differs, not if too low/high */ @@ -660,7 +671,7 @@ static int si470x_vidioc_s_tuner(struct file *file, void *priv, int retval = 0; if (tuner-index != 0) - goto done; + return -EINVAL; /* mono/stereo selector */ switch (tuner-audmode) { @@ -668,15 +679,13 @@ static int si470x_vidioc_s_tuner(struct file *file, void *priv, radio-registers[POWERCFG] |= POWERCFG_MONO; /* force mono */ break; case V4L2_TUNER_MODE_STEREO: + default: radio-registers[POWERCFG] = ~POWERCFG_MONO; /* try stereo */ break; - default: - goto done; } retval = si470x_set_register(radio, POWERCFG); -done: if (retval 0) dev_warn(radio-videodev.dev, set tuner failed with %d\n, retval); @@ -770,6 +779,8 @@ static const struct v4l2_ioctl_ops si470x_ioctl_ops = { .vidioc_g_frequency = si470x_vidioc_g_frequency, .vidioc_s_frequency = si470x_vidioc_s_frequency, .vidioc_s_hw_freq_seek = si470x_vidioc_s_hw_freq_seek, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; -- To unsubscribe from this list: send the line unsubscribe linux-media in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo
Re: [RFC PATCH 3/4] radio-si470x-common.c: remove unnecessary kernel log spam.
Hello Hans, thanks for the improvements. Looks good to me. Acked-by: Tobias Lorenz tobias.lor...@gmx.net Bye, Toby Am Freitag, 4. Mai 2012, 15:30:31 schrieb Hans Verkuil: From: Hans Verkuil hans.verk...@cisco.com There is no need to report an error in the log, you are already returning that error to userspace after all. Signed-off-by: Hans Verkuil hans.verk...@cisco.com --- drivers/media/radio/si470x/radio-si470x-common.c | 78 +- 1 file changed, 17 insertions(+), 61 deletions(-) diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c index e70badf..b9a44d4 100644 --- a/drivers/media/radio/si470x/radio-si470x-common.c +++ b/drivers/media/radio/si470x/radio-si470x-common.c @@ -327,7 +327,7 @@ static int si470x_set_seek(struct si470x_device *radio, radio-registers[POWERCFG] = ~POWERCFG_SEEKUP; retval = si470x_set_register(radio, POWERCFG); if (retval 0) - goto done; + return retval; /* currently I2C driver only uses interrupt way to seek */ if (radio-stci_enabled) { @@ -355,20 +355,15 @@ static int si470x_set_seek(struct si470x_device *radio, if (radio-registers[STATUSRSSI] STATUSRSSI_SF) dev_warn(radio-videodev.dev, seek failed / band limit reached\n); - if (timed_out) - dev_warn(radio-videodev.dev, - seek timed out after %u ms\n, seek_timeout); stop: /* stop seeking */ radio-registers[POWERCFG] = ~POWERCFG_SEEK; retval = si470x_set_register(radio, POWERCFG); -done: /* try again, if timed out */ - if ((retval == 0) timed_out) - retval = -EAGAIN; - + if (retval == 0 timed_out) + return -EAGAIN; return retval; } @@ -589,16 +584,14 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *tuner) { struct si470x_device *radio = video_drvdata(file); - int retval = 0; + int retval; - if (tuner-index != 0) { - retval = -EINVAL; - goto done; - } + if (tuner-index != 0) + return -EINVAL; retval = si470x_get_register(radio, STATUSRSSI); if (retval 0) - goto done; + return retval; /* driver constants */ strcpy(tuner-name, FM); @@ -653,10 +646,6 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv, /* AFCRL does only indicate that freq. differs, not if too low/high */ tuner-afc = (radio-registers[STATUSRSSI] STATUSRSSI_AFCRL) ? 1 : 0; -done: - if (retval 0) - dev_warn(radio-videodev.dev, - get tuner failed with %d\n, retval); return retval; } @@ -668,7 +657,6 @@ static int si470x_vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *tuner) { struct si470x_device *radio = video_drvdata(file); - int retval = 0; if (tuner-index != 0) return -EINVAL; @@ -684,12 +672,7 @@ static int si470x_vidioc_s_tuner(struct file *file, void *priv, break; } - retval = si470x_set_register(radio, POWERCFG); - - if (retval 0) - dev_warn(radio-videodev.dev, - set tuner failed with %d\n, retval); - return retval; + return si470x_set_register(radio, POWERCFG); } @@ -700,21 +683,12 @@ static int si470x_vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *freq) { struct si470x_device *radio = video_drvdata(file); - int retval = 0; - if (freq-tuner != 0) { - retval = -EINVAL; - goto done; - } + if (freq-tuner != 0) + return -EINVAL; freq-type = V4L2_TUNER_RADIO; - retval = si470x_get_freq(radio, freq-frequency); - -done: - if (retval 0) - dev_warn(radio-videodev.dev, - get frequency failed with %d\n, retval); - return retval; + return si470x_get_freq(radio, freq-frequency); } @@ -725,20 +699,11 @@ static int si470x_vidioc_s_frequency(struct file *file, void *priv, struct v4l2_frequency *freq) { struct si470x_device *radio = video_drvdata(file); - int retval = 0; - - if (freq-tuner != 0) { - retval = -EINVAL; - goto done; - } - retval = si470x_set_freq(radio, freq-frequency); + if (freq-tuner != 0) + return -EINVAL; -done: - if (retval 0) - dev_warn(radio-videodev.dev, - set frequency failed with %d\n, retval); - return retval; + return si470x_set_freq(radio, freq-frequency); } @@ -749,20 +714,11 @@ static int si470x_vidioc_s_hw_freq_seek(struct file *file, void *priv, struct v4l2_hw_freq_seek *seek) { struct si470x_device *radio = video_drvdata(file
Re: [RFC PATCH 4/4] radio-si470x-usb: remove autosuspend, implement suspend/resume.
Hello Hans, thanks for the improvements. Looks good to me. Acked-by: Tobias Lorenz tobias.lor...@gmx.net Bye, Toby Am Freitag, 4. Mai 2012, 15:30:32 schrieb Hans Verkuil: From: Hans Verkuil hans.verk...@cisco.com The radio-si470x-usb driver supported both autosuspend and it stopped the radio the moment the last user of the radio device closed it. However, that was very confusing since if you play the audio from the device (e.g. through arecord -D ... | aplay) then no sound would play unless you had the radio device open at the same time, even though there is no need to do anything with that node. On the other hand, the actual suspend/resume functions didn't do anything, which would fail if you *did* have the radio node open at that time. So: - remove autosuspend (bad idea in general for USB radio devices) - move the start/stop out of the open/release functions into the resume/suspend functions. Signed-off-by: Hans Verkuil hans.verk...@cisco.com --- drivers/media/radio/si470x/radio-si470x-common.c |1 - drivers/media/radio/si470x/radio-si470x-usb.c| 149 ++ 2 files changed, 70 insertions(+), 80 deletions(-) diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c index b9a44d4..969cf49 100644 --- a/drivers/media/radio/si470x/radio-si470x-common.c +++ b/drivers/media/radio/si470x/radio-si470x-common.c @@ -570,7 +570,6 @@ static int si470x_s_ctrl(struct v4l2_ctrl *ctrl) else radio-registers[POWERCFG] |= POWERCFG_DMUTE; return si470x_set_register(radio, POWERCFG); - break; default: return -EINVAL; } diff --git a/drivers/media/radio/si470x/radio-si470x-usb.c b/drivers/media/radio/si470x/radio-si470x-usb.c index f133c3d..e9f6387 100644 --- a/drivers/media/radio/si470x/radio-si470x-usb.c +++ b/drivers/media/radio/si470x/radio-si470x-usb.c @@ -481,91 +481,20 @@ resubmit: } - -/* * - * File Operations Interface - ** / - -/* - * si470x_fops_open - file open - */ int si470x_fops_open(struct file *file) { - struct si470x_device *radio = video_drvdata(file); - int retval = v4l2_fh_open(file); - - if (retval) - return retval; - - retval = usb_autopm_get_interface(radio-intf); - if (retval 0) - goto done; - - if (v4l2_fh_is_singular_file(file)) { - /* start radio */ - retval = si470x_start(radio); - if (retval 0) { - usb_autopm_put_interface(radio-intf); - goto done; - } - - /* initialize interrupt urb */ - usb_fill_int_urb(radio-int_in_urb, radio-usbdev, - usb_rcvintpipe(radio-usbdev, - radio-int_in_endpoint-bEndpointAddress), - radio-int_in_buffer, - le16_to_cpu(radio-int_in_endpoint-wMaxPacketSize), - si470x_int_in_callback, - radio, - radio-int_in_endpoint-bInterval); - - radio-int_in_running = 1; - mb(); - - retval = usb_submit_urb(radio-int_in_urb, GFP_KERNEL); - if (retval) { - dev_info(radio-intf-dev, - submitting int urb failed (%d)\n, retval); - radio-int_in_running = 0; - usb_autopm_put_interface(radio-intf); - } - } - -done: - if (retval) - v4l2_fh_release(file); - return retval; + return v4l2_fh_open(file); } - -/* - * si470x_fops_release - file release - */ int si470x_fops_release(struct file *file) { - struct si470x_device *radio = video_drvdata(file); - - if (v4l2_fh_is_singular_file(file)) { - /* shutdown interrupt handler */ - if (radio-int_in_running) { - radio-int_in_running = 0; - if (radio-int_in_urb) - usb_kill_urb(radio-int_in_urb); - } - - /* cancel read processes */ - wake_up_interruptible(radio-read_queue); - - /* stop radio */ - si470x_stop(radio); - usb_autopm_put_interface(radio-intf); - } return v4l2_fh_release(file); } -static void si470x_usb_release(struct video_device *vdev) +static void si470x_usb_release(struct v4l2_device *v4l2_dev) { - struct si470x_device *radio = video_get_drvdata(vdev); + struct si470x_device *radio = + container_of(v4l2_dev, struct si470x_device, v4l2_dev); usb_free_urb(radio-int_in_urb); v4l2_ctrl_handler_free
Re: radio-si470x-usb.c warning: can I remove 'buf'?
Hi Hans, While going through the compile warnings generated in the daily build I came across this one: v4l-dvb-git/drivers/media/radio/si470x/radio-si470x-usb.c: In function 'si470x_int_in_callback': v4l-dvb-git/drivers/media/radio/si470x/radio-si470x-usb.c:398:16: warning: variable 'buf' set but not used [-Wunused-but-set-variable] The 'unsigned char buf[RDS_REPORT_SIZE];' is indeed unused, but can I just remove it? There is this single assignment to buf: 'buf[0] = RDS_REPORT;'. This makes me wonder if it is perhaps supposed to be used after all. Please let me know if I can remove it, or if it is a bug that someone needs to fix. this is an artifact from shifting the rds processing function into interrupt context. Yes, this can safely be removed. Can you do this? Bye, Toby -- To unsubscribe from this list: send the line unsubscribe linux-media in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 3/6] remove #ifdef to show rds support by i2c driver.
This removes some #ifdef statements. RDS support is now indicated by I2C driver too. The functionality was already in the driver. Signed-off-by: Tobias Lorenz tobias.lor...@gmx.net --- drivers/media/radio/si470x/radio-si470x-common.c |6 -- 1 files changed, 0 insertions(+), 6 deletions(-) diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c index f016220..bf58931 100644 --- a/drivers/media/radio/si470x/radio-si470x-common.c +++ b/drivers/media/radio/si470x/radio-si470x-common.c @@ -687,12 +687,8 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv, /* driver constants */ strcpy(tuner-name, FM); tuner-type = V4L2_TUNER_RADIO; -#if defined(CONFIG_USB_SI470X) || defined(CONFIG_USB_SI470X_MODULE) tuner-capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO; -#else - tuner-capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; -#endif /* range limits */ switch ((radio-registers[SYSCONFIG2] SYSCONFIG2_BAND) 6) { @@ -718,12 +714,10 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv, tuner-rxsubchans = V4L2_TUNER_SUB_MONO; else tuner-rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; -#if defined(CONFIG_USB_SI470X) || defined(CONFIG_USB_SI470X_MODULE) /* If there is a reliable method of detecting an RDS channel, then this code should check for that before setting this RDS subchannel. */ tuner-rxsubchans |= V4L2_TUNER_SUB_RDS; -#endif /* mono/stereo selector */ if ((radio-registers[POWERCFG] POWERCFG_MONO) == 0) -- 1.7.4.1 -- To unsubscribe from this list: send the line unsubscribe linux-media in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 1/6] important fix for rds locking
This patch removes a redundant mutex_lock in fops_read. Every rds read attempt would stall otherwise. Signed-off-by: Tobias Lorenz tobias.lor...@gmx.net --- drivers/media/radio/si470x/radio-si470x-common.c |3 +-- 1 files changed, 1 insertions(+), 2 deletions(-) diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c index ac76dfe..5cbeeb3 100644 --- a/drivers/media/radio/si470x/radio-si470x-common.c +++ b/drivers/media/radio/si470x/radio-si470x-common.c @@ -438,7 +438,6 @@ static ssize_t si470x_fops_read(struct file *file, char __user *buf, unsigned int block_count = 0; /* switch on rds reception */ - mutex_lock(radio-lock); if ((radio-registers[SYSCONFIG1] SYSCONFIG1_RDS) == 0) si470x_rds_on(radio); @@ -479,9 +478,9 @@ static ssize_t si470x_fops_read(struct file *file, char __user *buf, buf += 3; retval += 3; } + mutex_unlock(radio-lock); done: - mutex_unlock(radio-lock); return retval; } -- 1.7.4.1 -- To unsubscribe from this list: send the line unsubscribe linux-media in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 5/6] documentation improvements
This patch moves the history to the documentation and updated the copyrights. Signed-off-by: Tobias Lorenz tobias.lor...@gmx.net --- Documentation/video4linux/si470x.txt | 94 ++- drivers/media/radio/si470x/radio-si470x-common.c | 91 -- drivers/media/radio/si470x/radio-si470x-usb.c|8 - drivers/media/radio/si470x/radio-si470x.h|2 4 files changed, 93 insertions(+), 102 deletions(-) diff --git a/Documentation/video4linux/si470x.txt b/Documentation/video4linux/si470x.txt index 3a7823e..8fc6edb 100644 --- a/Documentation/video4linux/si470x.txt +++ b/Documentation/video4linux/si470x.txt @@ -1,6 +1,6 @@ Driver for USB radios for the Silicon Labs Si470x FM Radio Receivers -Copyright (c) 2009 Tobias Lorenz tobias.lor...@gmx.net +Copyright (c) 2011 Tobias Lorenz tobias.lor...@gmx.net Information from Silicon Labs @@ -86,6 +86,7 @@ mplayer -radio adevice=hw=1.0:arate=96000 \ -rawaudio rate=96000 \ radio://frequency/capture + Module Parameters = After loading the module, you still have access to some of them in the sysfs @@ -111,9 +111,6 @@ currently under discussion. There is an USB interface for downloading/uploading new firmware images. Support for it can be implemented using the request_firmware interface. -There is a RDS interrupt mode. The driver is already using the same interface -for polling RDS information, but is currently not using the interrupt mode. - There is a LED interface, which can be used to override the LED control programmed in the firmware. This can be made available using the LED support functions in the kernel. @@ -122,3 +119,91 @@ functions in the kernel. Other useful information and links == http://www.silabs.com/usbradio + + +History +=== +2008-01-12 Tobias Lorenz tobias.lor...@gmx.net + Version 1.0.0 + - First working version +2008-01-13 Tobias Lorenz tobias.lor...@gmx.net + Version 1.0.1 + - Improved error handling, every function now returns errno + - Improved multi user access (start/mute/stop) + - Channel doesn't get lost anymore after start/mute/stop + - RDS support added (polling mode via interrupt EP 1) + - marked default module parameters with *value* + - switched from bit structs to bit masks + - header file cleaned and integrated +2008-01-14 Tobias Lorenz tobias.lor...@gmx.net + Version 1.0.2 + - hex values are now lower case + - commented USB ID for ADS/Tech moved on todo list + - blacklisted si470x in hid-quirks.c + - rds buffer handling functions integrated into *_work, *_read + - rds_command in si470x_poll exchanged against simple retval + - check for firmware version 15 + - code order and prototypes still remain the same + - spacing and bottom of band codes remain the same +2008-01-16 Tobias Lorenz tobias.lor...@gmx.net + Version 1.0.3 + - code reordered to avoid function prototypes + - switch/case defaults are now more user-friendly + - unified comment style + - applied all checkpatch.pl v1.12 suggestions + except the warning about the too long lines with bit comments + - renamed FMRADIO to RADIO to cut line length (checkpatch.pl) +2008-01-22 Tobias Lorenz tobias.lor...@gmx.net + Version 1.0.4 + - avoid poss. locking when doing copy_to_user which may sleep + - RDS is automatically activated on read now + - code cleaned of unnecessary rds_commands + - USB Vendor/Product ID for ADS/Tech FM Radio Receiver verified + (thanks to Guillaume RAMOUSSE) +2008-01-27 Tobias Lorenz tobias.lor...@gmx.net + Version 1.0.5 + - number of seek_retries changed to tune_timeout + - fixed problem with incomplete tune operations by own buffers + - optimization of variables and printf types + - improved error logging +2008-01-31 Tobias Lorenz tobias.lor...@gmx.net + Oliver Neukum oli...@neukum.org + Version 1.0.6 + - fixed coverity checker warnings in *_usb_driver_disconnect + - probe()/open() race by correct ordering in probe() + - DMA coherency rules by separate allocation of all buffers + - use of endianness macros + - abuse of spinlock, replaced by mutex + - racy handling of timer in disconnect, + replaced by delayed_work + - racy interruptible_sleep_on(), + replaced with wait_event_interruptible() + - handle
[PATCH 6/6] removement of locking mechanisms
This patch minimized the use of locking. Basically locking is only required where open/close/disconnect is done. Interfering calls usually happen only to rds read/write operations. The code for ring buffer handling is changed in a way that makes locking there unnecessary. In case of extensive compiler optimization, the worst that can happen is dropped new data or redundant read of data. The good thing is that the clicking noise problem seems finally resolved with that patch! Signed-off-by: Tobias Lorenz tobias.lor...@gmx.net --- drivers/media/radio/si470x/radio-si470x-common.c | 39 + drivers/media/radio/si470x/radio-si470x-i2c.c| 16 ++--- drivers/media/radio/si470x/radio-si470x-usb.c| 19 +++ drivers/media/radio/si470x/radio-si470x.h|2 +- 4 files changed, 34 insertions(+), 42 deletions(-) diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c index 60bd95d..b184292 100644 --- a/drivers/media/radio/si470x/radio-si470x-common.c +++ 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
[PATCH] fix of mutex locking bug in fops_read
This patch fixes a mutex locking bug causing userspace processes to hang indefinitely upon reading the radio device for RDS data. Signed-off-by: Nils Faerber nils.faer...@kernelconcepts.de Acked-by: Tobias Lorenz tobias.lor...@gmx.net --- drivers/media/radio/si470x/radio-si470x-common.c |1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c index 4c69698..41ee757 100644 --- a/drivers/media/radio/si470x/radio-si470x-common.c +++ b/drivers/media/radio/si470x/radio-si470x-common.c @@ -483,7 +483,6 @@ static ssize_t si470x_fops_read(struct file *file, char __user *buf, count /= 3; /* copy RDS block out of internal buffer and to user buffer */ - mutex_lock(radio-lock); while (block_count count) { if (radio-rd_index == radio-wr_index) break; -- 1.7.2.3 -- To unsubscribe from this list: send the line unsubscribe linux-media in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 1/1] Media: radio: si470x: remove double mutex lock
Hi, good catch! Thanks. Acked-by: Tobias Lorenz tobias.lor...@gmx.net Bye, Toby On Sun, 23 Jan 2011 12:16:54 +0300, Alexander Strakh croml...@gmail.com wrote: From: Alexander Strakh croml...@gmail.com 1. First mutex_lock on radio-lock in line 441 2. Second in line 462 I think that mutex in line 462 is not needed. In kernel v2.6.36.3 function si470 x_rds_on contains mutex_lock/mutex_unlock. Have no mutex_lock in line 441. In kernel v2.6.37 mutex_lock/mutex_unlock has been moved from si470x_rds_on to fops_read. But old mutex_lock (line 462) forgot to remove. 433static ssize_t si470x_fops_read(struct file *file, char __user *buf, 434size_t count, loff_t *ppos) 435{ 441mutex_lock(radio-lock); 442if ((radio-registers[SYSCONFIG1] SYSCONFIG1_RDS) == 0) 443si470x_rds_on(radio); 444 445/* block if no new data available */ 446while (radio-wr_index == radio-rd_index) { 447if (file-f_flags O_NONBLOCK) { 448retval = -EWOULDBLOCK; 449goto done; 450} 451if (wait_event_interruptible(radio-read_queue, 452radio-wr_index != radio-rd_index) 0) { 453retval = -EINTR; 454goto done; 455} 456} 457 458/* calculate block count from byte count */ 459count /= 3; 460 461/* copy RDS block out of internal buffer and to user buffer */ 462mutex_lock(radio-lock); Found by Linux Device Drivers Verification Project Remove second mutex_lock from fops_read Signed-off-by: Alexander Strakh str...@ispras.ru --- drivers/media/radio/si470x/radio-si470x-common.c |1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c index 60c176f..38ae6cd 100644 --- a/drivers/media/radio/si470x/radio-si470x-common.c +++ b/drivers/media/radio/si470x/radio-si470x-common.c @@ -460,7 +460,6 @@ static ssize_t si470x_fops_read(struct file *file, char __user *buf, count /= 3; /* copy RDS block out of internal buffer and to user buffer */ - mutex_lock(radio-lock); while (block_count count) { if (radio-rd_index == radio-wr_index) break; -- To unsubscribe from this list: send the line unsubscribe linux-media in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PULL] radio-si470x
Hi Mauro, Please pull from http://linuxtv.org/hg/~tlorenz/v4l-dvb for the following 5 changesets: 01/05: The de-emphasis should be setted if requested by module parameter http://linuxtv.org/hg/~tlorenz/v4l-dvb/rev/b29f01f1b11d 02/05: The si470x i2c and usb driver support the RDS, so this ifdef statement http://linuxtv.org/hg/~tlorenz/v4l-dvb/rev/74bf5826ae4e 03/05: We should go to err_video instead of err_all if this error is occured http://linuxtv.org/hg/~tlorenz/v4l-dvb/rev/7ea10526e134 04/05: V4L/DVB: radio-si470x: remove the BKL lock used internally at the driver http://linuxtv.org/hg/~tlorenz/v4l-dvb/rev/9ddfe7347b9a 05/05: V4L/DVB: radio-si470x: use unlocked ioctl http://linuxtv.org/hg/~tlorenz/v4l-dvb/rev/87712135ac8d Thanks, Tobias -- To unsubscribe from this list: send the line unsubscribe linux-media in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: Status of the patches under review at LMML (60 patches)
Hi Mauro, == Waiting for Tobias Lorenz tobias.lor...@gmx.net review == Feb, 3 2010: radio-si470x-common: -EINVAL overwritten in si470x_vidioc_s_tuner()http://patchwork.kernel.org/patch/76786 This patch was superseded by the following patch: http://linuxtv.org/hg/~tlorenz/v4l-dvb/raw-rev/72a2f38d5956 Please use this instead. Bye, Toby -- To unsubscribe from this list: send the line unsubscribe linux-media in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] radio-si470x-common: -EINVAL overwritten in si470x_vidioc_s_tuner()
Hello Mauro, no, the default value of retval makes no difference to the function. Retval is set by si470x_disconnect_check and si470x_set_register. After each call, retval is checked. There is no need to reset it passed. You may just do then: int retval = si470x_disconnect_check(radio); In all other set/get functions of v4l2_ioctl_ops in the driver, I just set the default value of retval to 0. To be identical in si470x_vidioc_s_tuner, I modified the patch to the one below. I already pushed this and another cosmetic patch into mercurial: http://linuxtv.org/hg/~tlorenz/v4l-dvb/rev/72a2f38d5956 http://linuxtv.org/hg/~tlorenz/v4l-dvb/rev/3efd5d32a618 Mauro, can you pull them? Bye, Tobias --- a/linux/drivers/media/radio/si470x/radio-si470x-common.cThu Feb 11 23:11:30 2010 -0200 +++ b/linux/drivers/media/radio/si470x/radio-si470x-common.cThu Feb 18 20:31:33 2010 +0100 @@ -748,7 +748,7 @@ struct v4l2_tuner *tuner) { struct si470x_device *radio = video_drvdata(file); - int retval = -EINVAL; + int retval = 0; /* safety checks */ retval = si470x_disconnect_check(radio); -- To unsubscribe from this list: send the line unsubscribe linux-media in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] radio-si470x-common: -EINVAL overwritten in si470x_vidioc_s_tuner()
Hello Roel, no, the default value of retval makes no difference to the function. Retval is set by si470x_disconnect_check and si470x_set_register. After each call, retval is checked. There is no need to reset it passed. The only reason, there is a default value is my static code checker, saying variables should have default values. Setting it to -EINVAL seems more reasonable to me than setting it 0. In fact the patch would bring up the warning on setting default values again. Bye, Toby Am Mittwoch 03 Februar 2010 20:48:05 schrieb Roel Kluin: The -EINVAL was overwritten by the si470x_disconnect_check(). Signed-off-by: Roel Kluin roel.kl...@gmail.com --- Is this needed? diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c index 4da0f15..65b4a92 100644 --- a/drivers/media/radio/si470x/radio-si470x-common.c +++ b/drivers/media/radio/si470x/radio-si470x-common.c @@ -748,12 +748,13 @@ static int si470x_vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *tuner) { struct si470x_device *radio = video_drvdata(file); - int retval = -EINVAL; + int retval; /* safety checks */ retval = si470x_disconnect_check(radio); if (retval) goto done; + retval = -EINVAL; if (tuner-index != 0) goto done; -- To unsubscribe from this list: send the line unsubscribe linux-media in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2 1/3] radio-si470x: move some file operations to common file
Hi, good patch. This saves quite some code in the I2C part of the driver... Acked-by: Tobias Lorenz tobias.lor...@gmx.net Bye, Toby Am Donnerstag 03 Dezember 2009 13:57:22 schrieb Joonyoung Shim: The read and poll file operations of the si470x usb driver can be used also equally on the si470x i2c driver, so they go to the common file. Signed-off-by: Joonyoung Shim jy0922.s...@samsung.com --- drivers/media/radio/si470x/radio-si470x-common.c | 98 ++ drivers/media/radio/si470x/radio-si470x-i2c.c| 15 +--- drivers/media/radio/si470x/radio-si470x-usb.c| 97 +- drivers/media/radio/si470x/radio-si470x.h|3 +- 4 files changed, 104 insertions(+), 109 deletions(-) diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c index 7296cf4..f4645d4 100644 --- a/drivers/media/radio/si470x/radio-si470x-common.c +++ b/drivers/media/radio/si470x/radio-si470x-common.c @@ -426,6 +426,104 @@ int si470x_rds_on(struct si470x_device *radio) /** + * File Operations Interface + **/ + +/* + * si470x_fops_read - read RDS data + */ +static ssize_t si470x_fops_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct si470x_device *radio = video_drvdata(file); + int retval = 0; + unsigned int block_count = 0; + + /* switch on rds reception */ + if ((radio-registers[SYSCONFIG1] SYSCONFIG1_RDS) == 0) + si470x_rds_on(radio); + + /* block if no new data available */ + while (radio-wr_index == radio-rd_index) { + if (file-f_flags O_NONBLOCK) { + retval = -EWOULDBLOCK; + goto done; + } + if (wait_event_interruptible(radio-read_queue, + radio-wr_index != radio-rd_index) 0) { + retval = -EINTR; + goto done; + } + } + + /* 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) { + if (radio-rd_index == radio-wr_index) + break; + + /* always transfer rds complete 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) + radio-rd_index = 0; + + /* increment counters */ + block_count++; + buf += 3; + retval += 3; + } + mutex_unlock(radio-lock); + +done: + return retval; +} + + +/* + * si470x_fops_poll - poll RDS data + */ +static unsigned int si470x_fops_poll(struct file *file, + struct poll_table_struct *pts) +{ + struct si470x_device *radio = video_drvdata(file); + int retval = 0; + + /* switch on rds reception */ + if ((radio-registers[SYSCONFIG1] SYSCONFIG1_RDS) == 0) + si470x_rds_on(radio); + + poll_wait(file, radio-read_queue, pts); + + if (radio-rd_index != radio-wr_index) + retval = POLLIN | POLLRDNORM; + + return retval; +} + + +/* + * si470x_fops - file operations interface + */ +static const struct v4l2_file_operations si470x_fops = { + .owner = THIS_MODULE, + .read = si470x_fops_read, + .poll = si470x_fops_poll, + .ioctl = video_ioctl2, + .open = si470x_fops_open, + .release= si470x_fops_release, +}; + + + +/** * Video4Linux Interface **/ diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c index 2d53b6a..4816a6d 100644 --- a/drivers/media/radio/si470x/radio-si470x-i2c.c +++ b/drivers/media/radio/si470x/radio-si470x-i2c.c @@ -173,7 +173,7 @@ int si470x_disconnect_check(struct si470x_device *radio) /* * si470x_fops_open - file open */ -static int si470x_fops_open(struct file *file) +int si470x_fops_open(struct file *file) { struct si470x_device *radio = video_drvdata(file); int retval = 0; @@ -194,7 +194,7 @@ static int si470x_fops_open(struct file *file) /* * si470x_fops_release - file release */ -static int si470x_fops_release(struct file *file) +int si470x_fops_release(struct file
Re: [PATCH v2 2/3] radio-si470x: support RDS on si470x i2c driver
Hi, I'm unable to test the functionality, due to missing devices. But the code compiles cleanly. Acked-by: Tobias Lorenz tobias.lor...@gmx.net Bye, Toby Am Donnerstag 03 Dezember 2009 13:57:27 schrieb Joonyoung Shim: This patch is to support RDS on si470x i2c driver. The routine of RDS operation is almost same with thing of usb driver, but this uses RDS interrupt. Signed-off-by: Joonyoung Shim jy0922.s...@samsung.com --- drivers/media/radio/si470x/radio-si470x-i2c.c | 164 +++-- drivers/media/radio/si470x/radio-si470x.h |1 + 2 files changed, 155 insertions(+), 10 deletions(-) diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c index 6a40db8..5466015 100644 --- a/drivers/media/radio/si470x/radio-si470x-i2c.c +++ b/drivers/media/radio/si470x/radio-si470x-i2c.c @@ -22,22 +22,17 @@ */ -/* - * ToDo: - * - RDS support - */ - - /* driver definitions */ #define DRIVER_AUTHOR Joonyoung Shim jy0922.s...@samsung.com; -#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 0) +#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 1) #define DRIVER_CARD Silicon Labs Si470x FM Radio Receiver #define DRIVER_DESC I2C radio driver for Si470x FM Radio Receivers -#define DRIVER_VERSION 1.0.0 +#define DRIVER_VERSION 1.0.1 /* kernel includes */ #include linux/i2c.h #include linux/delay.h +#include linux/interrupt.h #include radio-si470x.h @@ -62,6 +57,20 @@ static int radio_nr = -1; module_param(radio_nr, int, 0444); MODULE_PARM_DESC(radio_nr, Radio Nr); +/* RDS buffer blocks */ +static unsigned int rds_buf = 100; +module_param(rds_buf, uint, 0444); +MODULE_PARM_DESC(rds_buf, RDS buffer entries: *100*); + +/* RDS maximum block errors */ +static unsigned short max_rds_errors = 1; +/* 0 means 0 errors requiring correction */ +/* 1 means 1-2 errors requiring correction (used by original USBRadio.exe) */ +/* 2 means 3-5 errors requiring correction */ +/* 3 means 6+ errors or errors in checkword, correction not possible */ +module_param(max_rds_errors, ushort, 0644); +MODULE_PARM_DESC(max_rds_errors, RDS maximum block errors: *1*); + /** @@ -181,12 +190,21 @@ int si470x_fops_open(struct file *file) mutex_lock(radio-lock); radio-users++; - if (radio-users == 1) + if (radio-users == 1) { /* start radio */ retval = si470x_start(radio); + if (retval 0) + goto done; + + /* enable RDS interrupt */ + radio-registers[SYSCONFIG1] |= SYSCONFIG1_RDSIEN; + radio-registers[SYSCONFIG1] = ~SYSCONFIG1_GPIO2; + radio-registers[SYSCONFIG1] |= 0x1 2; + retval = si470x_set_register(radio, SYSCONFIG1); + } +done: mutex_unlock(radio-lock); - return retval; } @@ -242,6 +260,105 @@ int si470x_vidioc_querycap(struct file *file, void *priv, **/ /* + * si470x_i2c_interrupt_work - rds processing function + */ +static void si470x_i2c_interrupt_work(struct work_struct *work) +{ + struct si470x_device *radio = container_of(work, + struct si470x_device, radio_work); + unsigned char regnr; + unsigned char blocknum; + unsigned short bler; /* rds block errors */ + unsigned short rds; + unsigned char tmpbuf[3]; + int retval = 0; + + /* safety checks */ + if ((radio-registers[SYSCONFIG1] SYSCONFIG1_RDS) == 0) + return; + + /* Update RDS registers */ + for (regnr = 0; regnr RDS_REGISTER_NUM; regnr++) { + retval = si470x_get_register(radio, STATUSRSSI + regnr); + if (retval 0) + return; + } + + /* get rds blocks */ + if ((radio-registers[STATUSRSSI] STATUSRSSI_RDSR) == 0) + /* No RDS group ready, better luck next time */ + return; + + for (blocknum = 0; blocknum 4; blocknum++) { + switch (blocknum) { + default: + bler = (radio-registers[STATUSRSSI] + STATUSRSSI_BLERA) 9; + rds = radio-registers[RDSA]; + break; + case 1: + bler = (radio-registers[READCHAN] + READCHAN_BLERB) 14; + rds = radio-registers[RDSB]; + break; + case 2: + bler = (radio-registers[READCHAN] + READCHAN_BLERC) 12; + rds = radio-registers[RDSC]; + break; + case 3: + bler = (radio-registers[READCHAN
Re: [PATCH v2 3/3] radio-si470x: support PM functions
Hi, the same here. I'm unable to test it, but it compiles cleanly. Acked-by: Tobias Lorenz tobias.lor...@gmx.net Bye, Toby Am Donnerstag 03 Dezember 2009 13:57:29 schrieb Joonyoung Shim: This patch is to support PM of the si470x i2c driver. Signed-off-by: Joonyoung Shim jy0922.s...@samsung.com --- drivers/media/radio/si470x/radio-si470x-i2c.c | 40 + 1 files changed, 40 insertions(+), 0 deletions(-) diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c index 77532e6..4c6e586 100644 --- a/drivers/media/radio/si470x/radio-si470x-i2c.c +++ b/drivers/media/radio/si470x/radio-si470x-i2c.c @@ -486,6 +486,44 @@ static __devexit int si470x_i2c_remove(struct i2c_client *client) } +#ifdef CONFIG_PM +/* + * si470x_i2c_suspend - suspend the device + */ +static int si470x_i2c_suspend(struct i2c_client *client, pm_message_t mesg) +{ + struct si470x_device *radio = i2c_get_clientdata(client); + + /* power down */ + radio-registers[POWERCFG] |= POWERCFG_DISABLE; + if (si470x_set_register(radio, POWERCFG) 0) + return -EIO; + + return 0; +} + + +/* + * si470x_i2c_resume - resume the device + */ +static int si470x_i2c_resume(struct i2c_client *client) +{ + struct si470x_device *radio = i2c_get_clientdata(client); + + /* power up : need 110ms */ + radio-registers[POWERCFG] |= POWERCFG_ENABLE; + if (si470x_set_register(radio, POWERCFG) 0) + return -EIO; + msleep(110); + + return 0; +} +#else +#define si470x_i2c_suspend NULL +#define si470x_i2c_resumeNULL +#endif + + /* * si470x_i2c_driver - i2c driver interface */ @@ -496,6 +534,8 @@ static struct i2c_driver si470x_i2c_driver = { }, .probe = si470x_i2c_probe, .remove = __devexit_p(si470x_i2c_remove), + .suspend= si470x_i2c_suspend, + .resume = si470x_i2c_resume, .id_table = si470x_i2c_id, }; -- To unsubscribe from this list: send the line unsubscribe linux-media in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/3] radio-si470x: move some file operations to common file
Hi, yes, good point. Acked-by: Tobias Lorenz tobias.lor...@gmx.net Bye, Toby Am Mittwoch 18 November 2009 07:21:30 schrieb Joonyoung Shim: The read and poll file operations of the si470x usb driver can be used also equally on the si470x i2c driver, so they go to the common file. Signed-off-by: Joonyoung Shim jy0922.s...@samsung.com --- drivers/media/radio/si470x/radio-si470x-common.c | 98 ++ drivers/media/radio/si470x/radio-si470x-i2c.c| 15 +--- drivers/media/radio/si470x/radio-si470x-usb.c| 97 +- drivers/media/radio/si470x/radio-si470x.h|3 +- 4 files changed, 104 insertions(+), 109 deletions(-) diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c index 7296cf4..f4645d4 100644 --- a/drivers/media/radio/si470x/radio-si470x-common.c +++ b/drivers/media/radio/si470x/radio-si470x-common.c @@ -426,6 +426,104 @@ int si470x_rds_on(struct si470x_device *radio) /** + * File Operations Interface + **/ + +/* + * si470x_fops_read - read RDS data + */ +static ssize_t si470x_fops_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct si470x_device *radio = video_drvdata(file); + int retval = 0; + unsigned int block_count = 0; + + /* switch on rds reception */ + if ((radio-registers[SYSCONFIG1] SYSCONFIG1_RDS) == 0) + si470x_rds_on(radio); + + /* block if no new data available */ + while (radio-wr_index == radio-rd_index) { + if (file-f_flags O_NONBLOCK) { + retval = -EWOULDBLOCK; + goto done; + } + if (wait_event_interruptible(radio-read_queue, + radio-wr_index != radio-rd_index) 0) { + retval = -EINTR; + goto done; + } + } + + /* 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) { + if (radio-rd_index == radio-wr_index) + break; + + /* always transfer rds complete 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) + radio-rd_index = 0; + + /* increment counters */ + block_count++; + buf += 3; + retval += 3; + } + mutex_unlock(radio-lock); + +done: + return retval; +} + + +/* + * si470x_fops_poll - poll RDS data + */ +static unsigned int si470x_fops_poll(struct file *file, + struct poll_table_struct *pts) +{ + struct si470x_device *radio = video_drvdata(file); + int retval = 0; + + /* switch on rds reception */ + if ((radio-registers[SYSCONFIG1] SYSCONFIG1_RDS) == 0) + si470x_rds_on(radio); + + poll_wait(file, radio-read_queue, pts); + + if (radio-rd_index != radio-wr_index) + retval = POLLIN | POLLRDNORM; + + return retval; +} + + +/* + * si470x_fops - file operations interface + */ +static const struct v4l2_file_operations si470x_fops = { + .owner = THIS_MODULE, + .read = si470x_fops_read, + .poll = si470x_fops_poll, + .ioctl = video_ioctl2, + .open = si470x_fops_open, + .release= si470x_fops_release, +}; + + + +/** * Video4Linux Interface **/ diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c index 2d53b6a..4816a6d 100644 --- a/drivers/media/radio/si470x/radio-si470x-i2c.c +++ b/drivers/media/radio/si470x/radio-si470x-i2c.c @@ -173,7 +173,7 @@ int si470x_disconnect_check(struct si470x_device *radio) /* * si470x_fops_open - file open */ -static int si470x_fops_open(struct file *file) +int si470x_fops_open(struct file *file) { struct si470x_device *radio = video_drvdata(file); int retval = 0; @@ -194,7 +194,7 @@ static int si470x_fops_open(struct file *file) /* * si470x_fops_release - file release */ -static int si470x_fops_release(struct file *file) +int si470x_fops_release(struct file *file) { struct si470x_device *radio
Re: [v4l-dvb-maintainer] [PULL] radio-si470x: I2C support
Hi Mauro, Could you please verify if everything is correct at my git tree: http://git.kernel.org/?p=linux/kernel/git/mchehab/linux-next.git;a=shortlog Yes. It looks okay. Thanks, Toby -- To unsubscribe from this list: send the line unsubscribe linux-media in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2 0/4] radio-si470x: separate usb and i2c interface
Hi, I am concerned about one thing. I cannot test the si470x usb radio driver because i don't have the si470x usb radio device, so i believe you would have probably tested it. It is working. I tested it with the most common radio applications and with some RDS decoders. As the I2C part is working, I will send Mauro a pull request. The patch 1/4 is for separating common and usb code. The patch 2/4 is about using dev_* macro instead of printk. The patch 3/4 is about adding disconnect check function for i2c interface. The patch 4/4 is for supporting si470x i2c interface. Bye, Toby -- To unsubscribe from this list: send the line unsubscribe linux-media in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2 2/4] radio-si470x: change to dev_* macro from printk
Hi, Acked-by: Tobias Lorenz tobias.lor...@gmx.net Bye, Toby On Tuesday 14 July 2009 07:11:44 Joonyoung Shim wrote: This patch is for using dev_* macro instead of printk. Signed-off-by: Joonyoung Shim jy0922.s...@samsung.com --- .../media/radio/si470x/radio-si470x-common.c | 50 +- .../drivers/media/radio/si470x/radio-si470x-usb.c | 58 +--- 2 files changed, 52 insertions(+), 56 deletions(-) diff --git a/linux/drivers/media/radio/si470x/radio-si470x-common.c b/linux/drivers/media/radio/si470x/radio-si470x-common.c index d2dc1ff..2be22bd 100644 --- a/linux/drivers/media/radio/si470x/radio-si470x-common.c +++ b/linux/drivers/media/radio/si470x/radio-si470x-common.c @@ -184,10 +184,10 @@ static int si470x_set_chan(struct si470x_device *radio, unsigned short chan) } while (((radio-registers[STATUSRSSI] STATUSRSSI_STC) == 0) (!timed_out)); if ((radio-registers[STATUSRSSI] STATUSRSSI_STC) == 0) - printk(KERN_WARNING DRIVER_NAME : tune does not complete\n); + dev_warn(radio-videodev-dev, tune does not complete\n); if (timed_out) - printk(KERN_WARNING DRIVER_NAME - : tune timed out after %u ms\n, tune_timeout); + dev_warn(radio-videodev-dev, + tune timed out after %u ms\n, tune_timeout); stop: /* stop tuning */ @@ -320,13 +320,13 @@ static int si470x_set_seek(struct si470x_device *radio, } while (((radio-registers[STATUSRSSI] STATUSRSSI_STC) == 0) (!timed_out)); if ((radio-registers[STATUSRSSI] STATUSRSSI_STC) == 0) - printk(KERN_WARNING DRIVER_NAME : seek does not complete\n); + dev_warn(radio-videodev-dev, seek does not complete\n); if (radio-registers[STATUSRSSI] STATUSRSSI_SF) - printk(KERN_WARNING DRIVER_NAME - : seek failed / band limit reached\n); + dev_warn(radio-videodev-dev, + seek failed / band limit reached\n); if (timed_out) - printk(KERN_WARNING DRIVER_NAME - : seek timed out after %u ms\n, seek_timeout); + dev_warn(radio-videodev-dev, + seek timed out after %u ms\n, seek_timeout); stop: /* stop seeking */ @@ -435,6 +435,7 @@ int si470x_rds_on(struct si470x_device *radio) static int si470x_vidioc_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *qc) { + struct si470x_device *radio = video_drvdata(file); int retval = -EINVAL; /* abort if qc-id is below V4L2_CID_BASE */ @@ -458,8 +459,8 @@ static int si470x_vidioc_queryctrl(struct file *file, void *priv, done: if (retval 0) - printk(KERN_WARNING DRIVER_NAME - : query controls failed with %d\n, retval); + dev_warn(radio-videodev-dev, + query controls failed with %d\n, retval); return retval; } @@ -494,8 +495,8 @@ static int si470x_vidioc_g_ctrl(struct file *file, void *priv, done: if (retval 0) - printk(KERN_WARNING DRIVER_NAME - : get control failed with %d\n, retval); + dev_warn(radio-videodev-dev, + get control failed with %d\n, retval); return retval; } @@ -534,8 +535,8 @@ static int si470x_vidioc_s_ctrl(struct file *file, void *priv, done: if (retval 0) - printk(KERN_WARNING DRIVER_NAME - : set control failed with %d\n, retval); + dev_warn(radio-videodev-dev, + set control failed with %d\n, retval); return retval; } @@ -632,8 +633,8 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv, done: if (retval 0) - printk(KERN_WARNING DRIVER_NAME - : get tuner failed with %d\n, retval); + dev_warn(radio-videodev-dev, + get tuner failed with %d\n, retval); return retval; } @@ -671,8 +672,8 @@ static int si470x_vidioc_s_tuner(struct file *file, void *priv, done: if (retval 0) - printk(KERN_WARNING DRIVER_NAME - : set tuner failed with %d\n, retval); + dev_warn(radio-videodev-dev, + set tuner failed with %d\n, retval); return retval; } @@ -701,8 +702,8 @@ static int si470x_vidioc_g_frequency(struct file *file, void *priv, done: if (retval 0) - printk(KERN_WARNING DRIVER_NAME - : get frequency failed with %d\n, retval); + dev_warn(radio-videodev-dev, + get frequency failed with %d\n, retval); return retval; } @@ -730,8 +731,8 @@ static int si470x_vidioc_s_frequency(struct file *file, void *priv
Re: [PATCH v2 4/4] radio-si470x: add i2c driver for si470x
Hi, okay for the moment. We can later think about optimizations, like return 0 functions. I have no possibility of testing this functionality. But I guess it works with your device, so Acked-by: Tobias Lorenz tobias.lor...@gmx.net Bye, Toby On Sunday 19 July 2009 16:19:24 Alexey Klimov wrote: Hello, On Tue, Jul 14, 2009 at 9:15 AM, Joonyoung Shimjy0922.s...@samsung.com wrote: This patch supports i2c interface of si470x. The i2c specific part exists in radio-si470x-i2c.c file and the common part uses radio-si470x-common.c file. The '#if defined' is inserted inevitably because of parts used only si470x usb in the common file. The current driver version doesn't support the RDS. Signed-off-by: Joonyoung Shim jy0922.s...@samsung.com --- linux/drivers/media/radio/si470x/Kconfig | 13 + linux/drivers/media/radio/si470x/Makefile |2 + .../media/radio/si470x/radio-si470x-common.c |6 + .../drivers/media/radio/si470x/radio-si470x-i2c.c | 254 linux/drivers/media/radio/si470x/radio-si470x.h|6 + 5 files changed, 281 insertions(+), 0 deletions(-) create mode 100644 linux/drivers/media/radio/si470x/radio-si470x-i2c.c diff --git a/linux/drivers/media/radio/si470x/Kconfig b/linux/drivers/media/radio/si470x/Kconfig index 20d05c0..a466654 100644 --- a/linux/drivers/media/radio/si470x/Kconfig +++ b/linux/drivers/media/radio/si470x/Kconfig @@ -22,3 +22,16 @@ config USB_SI470X To compile this driver as a module, choose M here: the module will be called radio-usb-si470x. + +config I2C_SI470X + tristate Silicon Labs Si470x FM Radio Receiver support with I2C + depends on I2C RADIO_SI470X !USB_SI470X + ---help--- + This is a driver for I2C devices with the Silicon Labs SI470x + chip. + + Say Y here if you want to connect this type of radio to your + computer's I2C port. + + To compile this driver as a module, choose M here: the + module will be called radio-i2c-si470x. diff --git a/linux/drivers/media/radio/si470x/Makefile b/linux/drivers/media/radio/si470x/Makefile index 3cb777f..0696481 100644 --- a/linux/drivers/media/radio/si470x/Makefile +++ b/linux/drivers/media/radio/si470x/Makefile @@ -3,5 +3,7 @@ # radio-usb-si470x-objs := radio-si470x-usb.o radio-si470x-common.o +radio-i2c-si470x-objs := radio-si470x-i2c.o radio-si470x-common.o obj-$(CONFIG_USB_SI470X) += radio-usb-si470x.o +obj-$(CONFIG_I2C_SI470X) += radio-i2c-si470x.o diff --git a/linux/drivers/media/radio/si470x/radio-si470x-common.c b/linux/drivers/media/radio/si470x/radio-si470x-common.c index 84cbea3..0a48159 100644 --- a/linux/drivers/media/radio/si470x/radio-si470x-common.c +++ b/linux/drivers/media/radio/si470x/radio-si470x-common.c @@ -581,8 +581,12 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv, /* driver constants */ strcpy(tuner-name, FM); tuner-type = V4L2_TUNER_RADIO; +#if defined(CONFIG_USB_SI470X) || defined(CONFIG_USB_SI470X_MODULE) tuner-capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS; +#else + tuner-capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; +#endif /* range limits */ switch ((radio-registers[SYSCONFIG2] SYSCONFIG2_BAND) 6) { @@ -608,10 +612,12 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv, tuner-rxsubchans = V4L2_TUNER_SUB_MONO; else tuner-rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; +#if defined(CONFIG_USB_SI470X) || defined(CONFIG_USB_SI470X_MODULE) /* If there is a reliable method of detecting an RDS channel, then this code should check for that before setting this RDS subchannel. */ tuner-rxsubchans |= V4L2_TUNER_SUB_RDS; +#endif /* mono/stereo selector */ if ((radio-registers[POWERCFG] POWERCFG_MONO) == 0) diff --git a/linux/drivers/media/radio/si470x/radio-si470x-i2c.c b/linux/drivers/media/radio/si470x/radio-si470x-i2c.c new file mode 100644 index 000..2181021 --- /dev/null +++ b/linux/drivers/media/radio/si470x/radio-si470x-i2c.c @@ -0,0 +1,254 @@ +/* + * drivers/media/radio/si470x/radio-si470x-i2c.c + * + * I2C driver for radios with Silicon Labs Si470x FM Radio Receivers + * + * Copyright (C) 2009 Samsung Electronics Co.Ltd + * Author: Joonyoung Shim jy0922.s...@samsung.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * + * TODO: + * - RDS support