diff options
Diffstat (limited to 'drivers/media/radio')
-rw-r--r-- | drivers/media/radio/Kconfig | 1 | ||||
-rw-r--r-- | drivers/media/radio/radio-keene.c | 7 | ||||
-rw-r--r-- | drivers/media/radio/radio-sf16fmi.c | 127 | ||||
-rw-r--r-- | drivers/media/radio/radio-si476x.c | 13 | ||||
-rw-r--r-- | drivers/media/radio/radio-tea5764.c | 190 | ||||
-rw-r--r-- | drivers/media/radio/radio-timb.c | 81 | ||||
-rw-r--r-- | drivers/media/radio/saa7706h.c | 66 | ||||
-rw-r--r-- | drivers/media/radio/tef6862.c | 24 | ||||
-rw-r--r-- | drivers/media/radio/wl128x/fmdrv.h | 2 | ||||
-rw-r--r-- | drivers/media/radio/wl128x/fmdrv_common.c | 24 | ||||
-rw-r--r-- | drivers/media/radio/wl128x/fmdrv_v4l2.c | 8 |
11 files changed, 211 insertions, 332 deletions
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index c0beee2fa37..d529ba788f4 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -22,6 +22,7 @@ config RADIO_SI476X tristate "Silicon Laboratories Si476x I2C FM Radio" depends on I2C && VIDEO_V4L2 depends on MFD_SI476X_CORE + depends on SND_SOC select SND_SOC_SI476X ---help--- Choose Y here if you have this FM radio chip. diff --git a/drivers/media/radio/radio-keene.c b/drivers/media/radio/radio-keene.c index 4c9ae767fb3..21db23b196b 100644 --- a/drivers/media/radio/radio-keene.c +++ b/drivers/media/radio/radio-keene.c @@ -93,7 +93,7 @@ static int keene_cmd_main(struct keene_device *radio, unsigned freq, bool play) /* If bit 4 is set, then tune to the frequency. If bit 3 is set, then unmute; if bit 2 is set, then mute. If bit 1 is set, then enter idle mode; if bit 0 is set, - then enter transit mode. + then enter transmit mode. */ radio->buffer[5] = (radio->muted ? 4 : 8) | (play ? 1 : 2) | (freq ? 0x10 : 0); @@ -350,7 +350,6 @@ static int usb_keene_probe(struct usb_interface *intf, radio->pa = 118; radio->tx = 0x32; radio->stereo = true; - radio->curfreq = 95.16 * FREQ_MUL; if (hdl->error) { retval = hdl->error; @@ -383,6 +382,10 @@ static int usb_keene_probe(struct usb_interface *intf, video_set_drvdata(&radio->vdev, radio); set_bit(V4L2_FL_USE_FH_PRIO, &radio->vdev.flags); + /* at least 11ms is needed in order to settle hardware */ + msleep(20); + keene_cmd_main(radio, 95.16 * FREQ_MUL, false); + retval = video_register_device(&radio->vdev, VFL_TYPE_RADIO, -1); if (retval < 0) { dev_err(&intf->dev, "could not register video device\n"); diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c index adfcc61bdf0..6f4318ff0db 100644 --- a/drivers/media/radio/radio-sf16fmi.c +++ b/drivers/media/radio/radio-sf16fmi.c @@ -27,6 +27,8 @@ #include <linux/io.h> /* outb, outb_p */ #include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-event.h> #include "lm7000.h" MODULE_AUTHOR("Petr Vandrovec, vandrove@vc.cvut.cz and M. Kirkwood"); @@ -44,10 +46,11 @@ module_param(radio_nr, int, 0); struct fmi { struct v4l2_device v4l2_dev; + struct v4l2_ctrl_handler hdl; struct video_device vdev; int io; bool mute; - unsigned long curfreq; /* freq in kHz */ + u32 curfreq; /* freq in kHz */ struct mutex lock; }; @@ -55,8 +58,8 @@ static struct fmi fmi_card; static struct pnp_dev *dev; bool pnp_attached; -#define RSF16_MINFREQ (87 * 16000) -#define RSF16_MAXFREQ (108 * 16000) +#define RSF16_MINFREQ (87U * 16000) +#define RSF16_MAXFREQ (108U * 16000) #define FMI_BIT_TUN_CE (1 << 0) #define FMI_BIT_TUN_CLK (1 << 1) @@ -115,13 +118,22 @@ static inline int fmi_getsigstr(struct fmi *fmi) return (res & 2) ? 0 : 0xFFFF; } +static void fmi_set_freq(struct fmi *fmi) +{ + fmi->curfreq = clamp(fmi->curfreq, RSF16_MINFREQ, RSF16_MAXFREQ); + /* rounding in steps of 800 to match the freq + that will be used */ + lm7000_set_freq((fmi->curfreq / 800) * 800, fmi, fmi_set_pins); +} + static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *v) { strlcpy(v->driver, "radio-sf16fmi", sizeof(v->driver)); strlcpy(v->card, "SF16-FMI/FMP/FMD radio", sizeof(v->card)); - strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); - v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; + strlcpy(v->bus_info, "ISA:radio-sf16fmi", sizeof(v->bus_info)); + v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO; + v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -157,12 +169,10 @@ static int vidioc_s_frequency(struct file *file, void *priv, if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) return -EINVAL; - if (f->frequency < RSF16_MINFREQ || - f->frequency > RSF16_MAXFREQ) - return -EINVAL; - /* rounding in steps of 800 to match the freq - that will be used */ - lm7000_set_freq((f->frequency / 800) * 800, fmi, fmi_set_pins); + + fmi->curfreq = f->frequency; + fmi_set_freq(fmi); + return 0; } @@ -178,74 +188,31 @@ static int vidioc_g_frequency(struct file *file, void *priv, return 0; } -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) +static int fmi_s_ctrl(struct v4l2_ctrl *ctrl) { - switch (qc->id) { - case V4L2_CID_AUDIO_MUTE: - return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); - } - return -EINVAL; -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct fmi *fmi = video_drvdata(file); + struct fmi *fmi = container_of(ctrl->handler, struct fmi, hdl); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: - ctrl->value = fmi->mute; - return 0; - } - return -EINVAL; -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct fmi *fmi = video_drvdata(file); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (ctrl->value) + if (ctrl->val) fmi_mute(fmi); else fmi_unmute(fmi); - fmi->mute = ctrl->value; + fmi->mute = ctrl->val; return 0; } return -EINVAL; } -static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) -{ - return i ? -EINVAL : 0; -} - -static int vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - a->index = 0; - strlcpy(a->name, "Radio", sizeof(a->name)); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} - -static int vidioc_s_audio(struct file *file, void *priv, - const struct v4l2_audio *a) -{ - return a->index ? -EINVAL : 0; -} +static const struct v4l2_ctrl_ops fmi_ctrl_ops = { + .s_ctrl = fmi_s_ctrl, +}; static const struct v4l2_file_operations fmi_fops = { .owner = THIS_MODULE, + .open = v4l2_fh_open, + .release = v4l2_fh_release, + .poll = v4l2_ctrl_poll, .unlocked_ioctl = video_ioctl2, }; @@ -253,15 +220,11 @@ static const struct v4l2_ioctl_ops fmi_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, .vidioc_g_frequency = vidioc_g_frequency, .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_log_status = v4l2_ctrl_log_status, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; /* ladis: this is my card. does any other types exist? */ @@ -311,6 +274,7 @@ static int __init fmi_init(void) { struct fmi *fmi = &fmi_card; struct v4l2_device *v4l2_dev = &fmi->v4l2_dev; + struct v4l2_ctrl_handler *hdl = &fmi->hdl; int res, i; int probe_ports[] = { 0, 0x284, 0x384 }; @@ -363,19 +327,35 @@ static int __init fmi_init(void) return res; } + v4l2_ctrl_handler_init(hdl, 1); + v4l2_ctrl_new_std(hdl, &fmi_ctrl_ops, + V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1); + v4l2_dev->ctrl_handler = hdl; + if (hdl->error) { + res = hdl->error; + v4l2_err(v4l2_dev, "Could not register controls\n"); + v4l2_ctrl_handler_free(hdl); + v4l2_device_unregister(v4l2_dev); + return res; + } + strlcpy(fmi->vdev.name, v4l2_dev->name, sizeof(fmi->vdev.name)); fmi->vdev.v4l2_dev = v4l2_dev; fmi->vdev.fops = &fmi_fops; fmi->vdev.ioctl_ops = &fmi_ioctl_ops; fmi->vdev.release = video_device_release_empty; + set_bit(V4L2_FL_USE_FH_PRIO, &fmi->vdev.flags); video_set_drvdata(&fmi->vdev, fmi); mutex_init(&fmi->lock); - /* mute card - prevents noisy bootups */ - fmi_mute(fmi); + /* mute card and set default frequency */ + fmi->mute = 1; + fmi->curfreq = RSF16_MINFREQ; + fmi_set_freq(fmi); if (video_register_device(&fmi->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { + v4l2_ctrl_handler_free(hdl); v4l2_device_unregister(v4l2_dev); release_region(fmi->io, 2); if (pnp_attached) @@ -391,6 +371,7 @@ static void __exit fmi_exit(void) { struct fmi *fmi = &fmi_card; + v4l2_ctrl_handler_free(&fmi->hdl); video_unregister_device(&fmi->vdev); v4l2_device_unregister(&fmi->v4l2_dev); release_region(fmi->io, 2); diff --git a/drivers/media/radio/radio-si476x.c b/drivers/media/radio/radio-si476x.c index 9430c6a2993..9c9084cb99f 100644 --- a/drivers/media/radio/radio-si476x.c +++ b/drivers/media/radio/radio-si476x.c @@ -44,7 +44,7 @@ #define FREQ_MUL (10000000 / 625) -#define SI476X_PHDIV_STATUS_LINK_LOCKED(status) (0b10000000 & (status)) +#define SI476X_PHDIV_STATUS_LINK_LOCKED(status) (0x80 & (status)) #define DRIVER_NAME "si476x-radio" #define DRIVER_CARD "SI476x AM/FM Receiver" @@ -1018,16 +1018,6 @@ static int si476x_radio_s_ctrl(struct v4l2_ctrl *ctrl) return retval; } -static int si476x_radio_g_chip_ident(struct file *file, void *fh, - struct v4l2_dbg_chip_ident *chip) -{ - if (chip->match.type == V4L2_CHIP_MATCH_HOST && - v4l2_chip_match_host(&chip->match)) - return 0; - return -EINVAL; -} - - #ifdef CONFIG_VIDEO_ADV_DEBUG static int si476x_radio_g_register(struct file *file, void *fh, struct v4l2_dbg_register *reg) @@ -1203,7 +1193,6 @@ static const struct v4l2_ioctl_ops si4761_ioctl_ops = { .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, - .vidioc_g_chip_ident = si476x_radio_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG .vidioc_g_register = si476x_radio_g_register, .vidioc_s_register = si476x_radio_s_register, diff --git a/drivers/media/radio/radio-tea5764.c b/drivers/media/radio/radio-tea5764.c index 38d563d6259..036e2f54f4d 100644 --- a/drivers/media/radio/radio-tea5764.c +++ b/drivers/media/radio/radio-tea5764.c @@ -39,6 +39,9 @@ #include <linux/i2c.h> /* I2C */ #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> +#include <media/v4l2-device.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-event.h> #define DRIVER_VERSION "0.0.2" @@ -57,8 +60,8 @@ /* Frequency limits in MHz -- these are European values. For Japanese devices, that would be 76000 and 91000. */ -#define FREQ_MIN 87500 -#define FREQ_MAX 108000 +#define FREQ_MIN 87500U +#define FREQ_MAX 108000U #define FREQ_MUL 16 /* TEA5764 registers */ @@ -138,8 +141,10 @@ static int radio_nr = -1; static int use_xtal = RADIO_TEA5764_XTAL; struct tea5764_device { + struct v4l2_device v4l2_dev; + struct v4l2_ctrl_handler ctrl_handler; struct i2c_client *i2c_client; - struct video_device *videodev; + struct video_device vdev; struct tea5764_regs regs; struct mutex mutex; }; @@ -187,18 +192,6 @@ static int tea5764_i2c_write(struct tea5764_device *radio) return 0; } -/* V4L2 code related */ -static struct v4l2_queryctrl radio_qctrl[] = { - { - .id = V4L2_CID_AUDIO_MUTE, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .default_value = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - } -}; - static void tea5764_power_up(struct tea5764_device *radio) { struct tea5764_regs *r = &radio->regs; @@ -291,23 +284,19 @@ static void tea5764_mute(struct tea5764_device *radio, int on) tea5764_i2c_write(radio); } -static int tea5764_is_muted(struct tea5764_device *radio) -{ - return radio->regs.tnctrl & TEA5764_TNCTRL_MU; -} - /* V4L2 vidioc */ static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *v) { struct tea5764_device *radio = video_drvdata(file); - struct video_device *dev = radio->videodev; + struct video_device *dev = &radio->vdev; strlcpy(v->driver, dev->dev.driver->name, sizeof(v->driver)); strlcpy(v->card, dev->name, sizeof(v->card)); snprintf(v->bus_info, sizeof(v->bus_info), "I2C:%s", dev_name(&dev->dev)); - v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; + v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO; + v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -320,8 +309,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, if (v->index > 0) return -EINVAL; - memset(v, 0, sizeof(*v)); - strcpy(v->name, "FM"); + strlcpy(v->name, "FM", sizeof(v->name)); v->type = V4L2_TUNER_RADIO; tea5764_i2c_read(radio); v->rangelow = FREQ_MIN * FREQ_MUL; @@ -354,19 +342,23 @@ static int vidioc_s_frequency(struct file *file, void *priv, const struct v4l2_frequency *f) { struct tea5764_device *radio = video_drvdata(file); + unsigned freq = f->frequency; if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) return -EINVAL; - if (f->frequency == 0) { + if (freq == 0) { /* We special case this as a power down control. */ tea5764_power_down(radio); - } - if (f->frequency < (FREQ_MIN * FREQ_MUL)) - return -EINVAL; - if (f->frequency > (FREQ_MAX * FREQ_MUL)) + /* Yes, that's what is returned in this case. This + whole special case is non-compliant and should really + be replaced with something better, but changing this + might well break code that depends on this behavior. + So we keep it as-is. */ return -EINVAL; + } + clamp(freq, FREQ_MIN * FREQ_MUL, FREQ_MAX * FREQ_MUL); tea5764_power_up(radio); - tea5764_tune(radio, (f->frequency * 125) / 2); + tea5764_tune(radio, (freq * 125) / 2); return 0; } @@ -379,7 +371,6 @@ static int vidioc_g_frequency(struct file *file, void *priv, if (f->tuner != 0) return -EINVAL; tea5764_i2c_read(radio); - memset(f, 0, sizeof(*f)); f->type = V4L2_TUNER_RADIO; if (r->tnctrl & TEA5764_TNCTRL_PUPD0) f->frequency = (tea5764_get_freq(radio) * 2) / 125; @@ -389,83 +380,29 @@ static int vidioc_g_frequency(struct file *file, void *priv, return 0; } -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) +static int tea5764_s_ctrl(struct v4l2_ctrl *ctrl) { - int i; - - for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { - if (qc->id && qc->id == radio_qctrl[i].id) { - memcpy(qc, &(radio_qctrl[i]), sizeof(*qc)); - return 0; - } - } - return -EINVAL; -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct tea5764_device *radio = video_drvdata(file); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - tea5764_i2c_read(radio); - ctrl->value = tea5764_is_muted(radio) ? 1 : 0; - return 0; - } - return -EINVAL; -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct tea5764_device *radio = video_drvdata(file); + struct tea5764_device *radio = + container_of(ctrl->handler, struct tea5764_device, ctrl_handler); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: - tea5764_mute(radio, ctrl->value); + tea5764_mute(radio, ctrl->val); return 0; } return -EINVAL; } -static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) -{ - if (i != 0) - return -EINVAL; - return 0; -} - -static int vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - if (a->index > 1) - return -EINVAL; - - strcpy(a->name, "Radio"); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} - -static int vidioc_s_audio(struct file *file, void *priv, - const struct v4l2_audio *a) -{ - if (a->index != 0) - return -EINVAL; - - return 0; -} +static const struct v4l2_ctrl_ops tea5764_ctrl_ops = { + .s_ctrl = tea5764_s_ctrl, +}; /* File system interface */ static const struct v4l2_file_operations tea5764_fops = { .owner = THIS_MODULE, + .open = v4l2_fh_open, + .release = v4l2_fh_release, + .poll = v4l2_ctrl_poll, .unlocked_ioctl = video_ioctl2, }; @@ -473,15 +410,11 @@ static const struct v4l2_ioctl_ops tea5764_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, .vidioc_g_frequency = vidioc_g_frequency, .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_log_status = v4l2_ctrl_log_status, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; /* V4L2 interface */ @@ -489,7 +422,7 @@ static struct video_device tea5764_radio_template = { .name = "TEA5764 FM-Radio", .fops = &tea5764_fops, .ioctl_ops = &tea5764_ioctl_ops, - .release = video_device_release, + .release = video_device_release_empty, }; /* I2C probe: check if the device exists and register with v4l if it is */ @@ -497,6 +430,8 @@ static int tea5764_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct tea5764_device *radio; + struct v4l2_device *v4l2_dev; + struct v4l2_ctrl_handler *hdl; struct tea5764_regs *r; int ret; @@ -505,31 +440,45 @@ static int tea5764_i2c_probe(struct i2c_client *client, if (!radio) return -ENOMEM; + v4l2_dev = &radio->v4l2_dev; + ret = v4l2_device_register(&client->dev, v4l2_dev); + if (ret < 0) { + v4l2_err(v4l2_dev, "could not register v4l2_device\n"); + goto errfr; + } + + hdl = &radio->ctrl_handler; + v4l2_ctrl_handler_init(hdl, 1); + v4l2_ctrl_new_std(hdl, &tea5764_ctrl_ops, + V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1); + v4l2_dev->ctrl_handler = hdl; + if (hdl->error) { + ret = hdl->error; + v4l2_err(v4l2_dev, "Could not register controls\n"); + goto errunreg; + } + mutex_init(&radio->mutex); radio->i2c_client = client; ret = tea5764_i2c_read(radio); if (ret) - goto errfr; + goto errunreg; r = &radio->regs; PDEBUG("chipid = %04X, manid = %04X", r->chipid, r->manid); if (r->chipid != TEA5764_CHIPID || (r->manid & 0x0fff) != TEA5764_MANID) { PWARN("This chip is not a TEA5764!"); ret = -EINVAL; - goto errfr; + goto errunreg; } - radio->videodev = video_device_alloc(); - if (!(radio->videodev)) { - ret = -ENOMEM; - goto errfr; - } - memcpy(radio->videodev, &tea5764_radio_template, - sizeof(tea5764_radio_template)); + radio->vdev = tea5764_radio_template; i2c_set_clientdata(client, radio); - video_set_drvdata(radio->videodev, radio); - radio->videodev->lock = &radio->mutex; + video_set_drvdata(&radio->vdev, radio); + radio->vdev.lock = &radio->mutex; + radio->vdev.v4l2_dev = v4l2_dev; + set_bit(V4L2_FL_USE_FH_PRIO, &radio->vdev.flags); /* initialize and power off the chip */ tea5764_i2c_read(radio); @@ -537,16 +486,17 @@ static int tea5764_i2c_probe(struct i2c_client *client, tea5764_mute(radio, 1); tea5764_power_down(radio); - ret = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr); + ret = video_register_device(&radio->vdev, VFL_TYPE_RADIO, radio_nr); if (ret < 0) { PWARN("Could not register video device!"); - goto errrel; + goto errunreg; } PINFO("registered."); return 0; -errrel: - video_device_release(radio->videodev); +errunreg: + v4l2_ctrl_handler_free(hdl); + v4l2_device_unregister(v4l2_dev); errfr: kfree(radio); return ret; @@ -559,7 +509,9 @@ static int tea5764_i2c_remove(struct i2c_client *client) PDEBUG("remove"); if (radio) { tea5764_power_down(radio); - video_unregister_device(radio->videodev); + video_unregister_device(&radio->vdev); + v4l2_ctrl_handler_free(&radio->ctrl_handler); + v4l2_device_unregister(&radio->v4l2_dev); kfree(radio); } return 0; diff --git a/drivers/media/radio/radio-timb.c b/drivers/media/radio/radio-timb.c index bb7b143b65d..0817964d917 100644 --- a/drivers/media/radio/radio-timb.c +++ b/drivers/media/radio/radio-timb.c @@ -19,6 +19,8 @@ #include <linux/io.h> #include <media/v4l2-ioctl.h> #include <media/v4l2-device.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-event.h> #include <linux/platform_device.h> #include <linux/interrupt.h> #include <linux/slab.h> @@ -44,7 +46,8 @@ static int timbradio_vidioc_querycap(struct file *file, void *priv, strlcpy(v->driver, DRIVER_NAME, sizeof(v->driver)); strlcpy(v->card, "Timberdale Radio", sizeof(v->card)); snprintf(v->bus_info, sizeof(v->bus_info), "platform:"DRIVER_NAME); - v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; + v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO; + v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -62,34 +65,6 @@ static int timbradio_vidioc_s_tuner(struct file *file, void *priv, return v4l2_subdev_call(tr->sd_tuner, tuner, s_tuner, v); } -static int timbradio_vidioc_g_input(struct file *filp, void *priv, - unsigned int *i) -{ - *i = 0; - return 0; -} - -static int timbradio_vidioc_s_input(struct file *filp, void *priv, - unsigned int i) -{ - return i ? -EINVAL : 0; -} - -static int timbradio_vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - a->index = 0; - strlcpy(a->name, "Radio", sizeof(a->name)); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} - -static int timbradio_vidioc_s_audio(struct file *file, void *priv, - const struct v4l2_audio *a) -{ - return a->index ? -EINVAL : 0; -} - static int timbradio_vidioc_s_frequency(struct file *file, void *priv, const struct v4l2_frequency *f) { @@ -104,44 +79,22 @@ static int timbradio_vidioc_g_frequency(struct file *file, void *priv, return v4l2_subdev_call(tr->sd_tuner, tuner, g_frequency, f); } -static int timbradio_vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - struct timbradio *tr = video_drvdata(file); - return v4l2_subdev_call(tr->sd_dsp, core, queryctrl, qc); -} - -static int timbradio_vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct timbradio *tr = video_drvdata(file); - return v4l2_subdev_call(tr->sd_dsp, core, g_ctrl, ctrl); -} - -static int timbradio_vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct timbradio *tr = video_drvdata(file); - return v4l2_subdev_call(tr->sd_dsp, core, s_ctrl, ctrl); -} - static const struct v4l2_ioctl_ops timbradio_ioctl_ops = { .vidioc_querycap = timbradio_vidioc_querycap, .vidioc_g_tuner = timbradio_vidioc_g_tuner, .vidioc_s_tuner = timbradio_vidioc_s_tuner, .vidioc_g_frequency = timbradio_vidioc_g_frequency, .vidioc_s_frequency = timbradio_vidioc_s_frequency, - .vidioc_g_input = timbradio_vidioc_g_input, - .vidioc_s_input = timbradio_vidioc_s_input, - .vidioc_g_audio = timbradio_vidioc_g_audio, - .vidioc_s_audio = timbradio_vidioc_s_audio, - .vidioc_queryctrl = timbradio_vidioc_queryctrl, - .vidioc_g_ctrl = timbradio_vidioc_g_ctrl, - .vidioc_s_ctrl = timbradio_vidioc_s_ctrl + .vidioc_log_status = v4l2_ctrl_log_status, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; static const struct v4l2_file_operations timbradio_fops = { .owner = THIS_MODULE, + .open = v4l2_fh_open, + .release = v4l2_fh_release, + .poll = v4l2_ctrl_poll, .unlocked_ioctl = video_ioctl2, }; @@ -173,6 +126,7 @@ static int timbradio_probe(struct platform_device *pdev) tr->video_dev.release = video_device_release_empty; tr->video_dev.minor = -1; tr->video_dev.lock = &tr->lock; + set_bit(V4L2_FL_USE_FH_PRIO, &tr->video_dev.flags); strlcpy(tr->v4l2_dev.name, DRIVER_NAME, sizeof(tr->v4l2_dev.name)); err = v4l2_device_register(NULL, &tr->v4l2_dev); @@ -181,6 +135,15 @@ static int timbradio_probe(struct platform_device *pdev) tr->video_dev.v4l2_dev = &tr->v4l2_dev; + tr->sd_tuner = v4l2_i2c_new_subdev_board(&tr->v4l2_dev, + i2c_get_adapter(pdata->i2c_adapter), pdata->tuner, NULL); + tr->sd_dsp = v4l2_i2c_new_subdev_board(&tr->v4l2_dev, + i2c_get_adapter(pdata->i2c_adapter), pdata->dsp, NULL); + if (tr->sd_tuner == NULL || tr->sd_dsp == NULL) + goto err_video_req; + + tr->v4l2_dev.ctrl_handler = tr->sd_dsp->ctrl_handler; + err = video_register_device(&tr->video_dev, VFL_TYPE_RADIO, -1); if (err) { dev_err(&pdev->dev, "Error reg video\n"); @@ -193,7 +156,6 @@ static int timbradio_probe(struct platform_device *pdev) return 0; err_video_req: - video_device_release_empty(&tr->video_dev); v4l2_device_unregister(&tr->v4l2_dev); err: dev_err(&pdev->dev, "Failed to register: %d\n", err); @@ -206,10 +168,7 @@ static int timbradio_remove(struct platform_device *pdev) struct timbradio *tr = platform_get_drvdata(pdev); video_unregister_device(&tr->video_dev); - video_device_release_empty(&tr->video_dev); - v4l2_device_unregister(&tr->v4l2_dev); - return 0; } diff --git a/drivers/media/radio/saa7706h.c b/drivers/media/radio/saa7706h.c index 06c06cc9ff2..ec805b09c60 100644 --- a/drivers/media/radio/saa7706h.c +++ b/drivers/media/radio/saa7706h.c @@ -25,7 +25,7 @@ #include <linux/i2c.h> #include <linux/slab.h> #include <media/v4l2-device.h> -#include <media/v4l2-chip-ident.h> +#include <media/v4l2-ctrls.h> #define DRIVER_NAME "saa7706h" @@ -127,6 +127,7 @@ struct saa7706h_state { struct v4l2_subdev sd; + struct v4l2_ctrl_handler hdl; unsigned muted; }; @@ -317,51 +318,32 @@ static int saa7706h_mute(struct v4l2_subdev *sd) return err; } -static int saa7706h_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) +static int saa7706h_s_ctrl(struct v4l2_ctrl *ctrl) { - switch (qc->id) { - case V4L2_CID_AUDIO_MUTE: - return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); - } - return -EINVAL; -} - -static int saa7706h_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct saa7706h_state *state = to_state(sd); + struct saa7706h_state *state = + container_of(ctrl->handler, struct saa7706h_state, hdl); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: - ctrl->value = state->muted; - return 0; + if (ctrl->val) + return saa7706h_mute(&state->sd); + return saa7706h_unmute(&state->sd); } return -EINVAL; } -static int saa7706h_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (ctrl->value) - return saa7706h_mute(sd); - return saa7706h_unmute(sd); - } - return -EINVAL; -} - -static int saa7706h_g_chip_ident(struct v4l2_subdev *sd, - struct v4l2_dbg_chip_ident *chip) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA7706H, 0); -} +static const struct v4l2_ctrl_ops saa7706h_ctrl_ops = { + .s_ctrl = saa7706h_s_ctrl, +}; static const struct v4l2_subdev_core_ops saa7706h_core_ops = { - .g_chip_ident = saa7706h_g_chip_ident, - .queryctrl = saa7706h_queryctrl, - .g_ctrl = saa7706h_g_ctrl, - .s_ctrl = saa7706h_s_ctrl, + .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, + .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, + .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, + .g_ctrl = v4l2_subdev_g_ctrl, + .s_ctrl = v4l2_subdev_s_ctrl, + .queryctrl = v4l2_subdev_queryctrl, + .querymenu = v4l2_subdev_querymenu, }; static const struct v4l2_subdev_ops saa7706h_ops = { @@ -393,13 +375,20 @@ static int saa7706h_probe(struct i2c_client *client, sd = &state->sd; v4l2_i2c_subdev_init(sd, client, &saa7706h_ops); + v4l2_ctrl_handler_init(&state->hdl, 4); + v4l2_ctrl_new_std(&state->hdl, &saa7706h_ctrl_ops, + V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1); + sd->ctrl_handler = &state->hdl; + err = state->hdl.error; + if (err) + goto err; + /* check the rom versions */ err = saa7706h_get_reg16(sd, SAA7706H_DSP1_ROM_VER); if (err < 0) goto err; if (err != SUPPORTED_DSP1_ROM_VER) v4l2_warn(sd, "Unknown DSP1 ROM code version: 0x%x\n", err); - state->muted = 1; /* startup in a muted state */ @@ -411,6 +400,7 @@ static int saa7706h_probe(struct i2c_client *client, err: v4l2_device_unregister_subdev(sd); + v4l2_ctrl_handler_free(&state->hdl); kfree(to_state(sd)); printk(KERN_ERR DRIVER_NAME ": Failed to probe: %d\n", err); @@ -421,9 +411,11 @@ err: static int saa7706h_remove(struct i2c_client *client) { struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct saa7706h_state *state = to_state(sd); saa7706h_mute(sd); v4l2_device_unregister_subdev(sd); + v4l2_ctrl_handler_free(&state->hdl); kfree(to_state(sd)); return 0; } diff --git a/drivers/media/radio/tef6862.c b/drivers/media/radio/tef6862.c index 82c6c9475d7..06ac69245ca 100644 --- a/drivers/media/radio/tef6862.c +++ b/drivers/media/radio/tef6862.c @@ -25,14 +25,13 @@ #include <linux/slab.h> #include <media/v4l2-ioctl.h> #include <media/v4l2-device.h> -#include <media/v4l2-chip-ident.h> #define DRIVER_NAME "tef6862" #define FREQ_MUL 16000 -#define TEF6862_LO_FREQ (875 * FREQ_MUL / 10) -#define TEF6862_HI_FREQ (108 * FREQ_MUL) +#define TEF6862_LO_FREQ (875U * FREQ_MUL / 10) +#define TEF6862_HI_FREQ (108U * FREQ_MUL) /* Write mode sub addresses */ #define WM_SUB_BANDWIDTH 0x0 @@ -105,6 +104,7 @@ static int tef6862_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequen { struct tef6862_state *state = to_state(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); + unsigned freq = f->frequency; u16 pll; u8 i2cmsg[3]; int err; @@ -112,7 +112,8 @@ static int tef6862_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequen if (f->tuner != 0) return -EINVAL; - pll = 1964 + ((f->frequency - TEF6862_LO_FREQ) * 20) / FREQ_MUL; + clamp(freq, TEF6862_LO_FREQ, TEF6862_HI_FREQ); + pll = 1964 + ((freq - TEF6862_LO_FREQ) * 20) / FREQ_MUL; i2cmsg[0] = (MODE_PRESET << MODE_SHIFT) | WM_SUB_PLLM; i2cmsg[1] = (pll >> 8) & 0xff; i2cmsg[2] = pll & 0xff; @@ -121,7 +122,7 @@ static int tef6862_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequen if (err != sizeof(i2cmsg)) return err < 0 ? err : -EIO; - state->freq = f->frequency; + state->freq = freq; return 0; } @@ -136,14 +137,6 @@ static int tef6862_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) return 0; } -static int tef6862_g_chip_ident(struct v4l2_subdev *sd, - struct v4l2_dbg_chip_ident *chip) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TEF6862, 0); -} - static const struct v4l2_subdev_tuner_ops tef6862_tuner_ops = { .g_tuner = tef6862_g_tuner, .s_tuner = tef6862_s_tuner, @@ -151,12 +144,7 @@ static const struct v4l2_subdev_tuner_ops tef6862_tuner_ops = { .g_frequency = tef6862_g_frequency, }; -static const struct v4l2_subdev_core_ops tef6862_core_ops = { - .g_chip_ident = tef6862_g_chip_ident, -}; - static const struct v4l2_subdev_ops tef6862_ops = { - .core = &tef6862_core_ops, .tuner = &tef6862_tuner_ops, }; diff --git a/drivers/media/radio/wl128x/fmdrv.h b/drivers/media/radio/wl128x/fmdrv.h index aac0f025f76..a587c9bac93 100644 --- a/drivers/media/radio/wl128x/fmdrv.h +++ b/drivers/media/radio/wl128x/fmdrv.h @@ -30,6 +30,7 @@ #include <linux/timer.h> #include <media/v4l2-ioctl.h> #include <media/v4l2-common.h> +#include <media/v4l2-device.h> #include <media/v4l2-ctrls.h> #define FM_DRV_VERSION "0.1.1" @@ -202,6 +203,7 @@ struct fmtx_data { /* FM driver operation structure */ struct fmdev { struct video_device *radio_dev; /* V4L2 video device pointer */ + struct v4l2_device v4l2_dev; /* V4L2 top level struct */ struct snd_card *card; /* Card which holds FM mixer controls */ u16 asci_id; spinlock_t rds_buff_lock; /* To protect access to RDS buffer */ diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c index a002234ed5d..253f307f0b3 100644 --- a/drivers/media/radio/wl128x/fmdrv_common.c +++ b/drivers/media/radio/wl128x/fmdrv_common.c @@ -715,7 +715,7 @@ static void fm_irq_handle_rdsdata_getcmd_resp(struct fmdev *fmdev) struct fm_rdsdata_format rds_fmt; struct fm_rds *rds = &fmdev->rx.rds; unsigned long group_idx, flags; - u8 *rds_data, meta_data, tmpbuf[3]; + u8 *rds_data, meta_data, tmpbuf[FM_RDS_BLK_SIZE]; u8 type, blk_idx; u16 cur_picode; u32 rds_len; @@ -1073,6 +1073,7 @@ int fmc_transfer_rds_from_internal_buff(struct fmdev *fmdev, struct file *file, u8 __user *buf, size_t count) { u32 block_count; + u8 tmpbuf[FM_RDS_BLK_SIZE]; unsigned long flags; int ret; @@ -1087,29 +1088,32 @@ int fmc_transfer_rds_from_internal_buff(struct fmdev *fmdev, struct file *file, } /* Calculate block count from byte count */ - count /= 3; + count /= FM_RDS_BLK_SIZE; block_count = 0; ret = 0; - spin_lock_irqsave(&fmdev->rds_buff_lock, flags); - while (block_count < count) { - if (fmdev->rx.rds.wr_idx == fmdev->rx.rds.rd_idx) - break; + spin_lock_irqsave(&fmdev->rds_buff_lock, flags); - if (copy_to_user(buf, &fmdev->rx.rds.buff[fmdev->rx.rds.rd_idx], - FM_RDS_BLK_SIZE)) + if (fmdev->rx.rds.wr_idx == fmdev->rx.rds.rd_idx) { + spin_unlock_irqrestore(&fmdev->rds_buff_lock, flags); break; - + } + memcpy(tmpbuf, &fmdev->rx.rds.buff[fmdev->rx.rds.rd_idx], + FM_RDS_BLK_SIZE); fmdev->rx.rds.rd_idx += FM_RDS_BLK_SIZE; if (fmdev->rx.rds.rd_idx >= fmdev->rx.rds.buf_size) fmdev->rx.rds.rd_idx = 0; + spin_unlock_irqrestore(&fmdev->rds_buff_lock, flags); + + if (copy_to_user(buf, tmpbuf, FM_RDS_BLK_SIZE)) + break; + block_count++; buf += FM_RDS_BLK_SIZE; ret += FM_RDS_BLK_SIZE; } - spin_unlock_irqrestore(&fmdev->rds_buff_lock, flags); return ret; } diff --git a/drivers/media/radio/wl128x/fmdrv_v4l2.c b/drivers/media/radio/wl128x/fmdrv_v4l2.c index 5dec323f424..b55012c1184 100644 --- a/drivers/media/radio/wl128x/fmdrv_v4l2.c +++ b/drivers/media/radio/wl128x/fmdrv_v4l2.c @@ -533,6 +533,11 @@ int fm_v4l2_init_video_device(struct fmdev *fmdev, int radio_nr) struct v4l2_ctrl *ctrl; int ret; + strlcpy(fmdev->v4l2_dev.name, FM_DRV_NAME, sizeof(fmdev->v4l2_dev.name)); + ret = v4l2_device_register(NULL, &fmdev->v4l2_dev); + if (ret < 0) + return ret; + /* Init mutex for core locking */ mutex_init(&fmdev->mutex); @@ -549,6 +554,7 @@ int fm_v4l2_init_video_device(struct fmdev *fmdev, int radio_nr) video_set_drvdata(gradio_dev, fmdev); gradio_dev->lock = &fmdev->mutex; + gradio_dev->v4l2_dev = &fmdev->v4l2_dev; /* Register with V4L2 subsystem as RADIO device */ if (video_register_device(gradio_dev, VFL_TYPE_RADIO, radio_nr)) { @@ -611,5 +617,7 @@ void *fm_v4l2_deinit_video_device(void) /* Unregister RADIO device from V4L2 subsystem */ video_unregister_device(gradio_dev); + v4l2_device_unregister(&fmdev->v4l2_dev); + return fmdev; } |