aboutsummaryrefslogtreecommitdiff
path: root/drivers/media/radio
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/radio')
-rw-r--r--drivers/media/radio/Kconfig34
-rw-r--r--drivers/media/radio/Makefile4
-rw-r--r--drivers/media/radio/lm7000.h43
-rw-r--r--drivers/media/radio/radio-aimslab.c66
-rw-r--r--drivers/media/radio/radio-cadet.c388
-rw-r--r--drivers/media/radio/radio-mr800.c5
-rw-r--r--drivers/media/radio/radio-sf16fmi.c61
-rw-r--r--drivers/media/radio/radio-shark.c376
-rw-r--r--drivers/media/radio/radio-shark2.c348
-rw-r--r--drivers/media/radio/radio-tea5777.c491
-rw-r--r--drivers/media/radio/radio-tea5777.h87
-rw-r--r--drivers/media/radio/radio-wl1273.c3
-rw-r--r--drivers/media/radio/si470x/radio-si470x-common.c289
-rw-r--r--drivers/media/radio/si470x/radio-si470x-i2c.c6
-rw-r--r--drivers/media/radio/si470x/radio-si470x-usb.c47
-rw-r--r--drivers/media/radio/si470x/radio-si470x.h7
-rw-r--r--drivers/media/radio/wl128x/fmdrv_rx.c2
-rw-r--r--drivers/media/radio/wl128x/fmdrv_v4l2.c4
18 files changed, 1801 insertions, 460 deletions
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig
index c257da13d76..8090b87b306 100644
--- a/drivers/media/radio/Kconfig
+++ b/drivers/media/radio/Kconfig
@@ -5,6 +5,7 @@
menuconfig RADIO_ADAPTERS
bool "Radio Adapters"
depends on VIDEO_V4L2
+ depends on MEDIA_RADIO_SUPPORT
default y
---help---
Say Y here to enable selecting AM/FM radio adapters.
@@ -56,6 +57,39 @@ config RADIO_MAXIRADIO
To compile this driver as a module, choose M here: the
module will be called radio-maxiradio.
+config RADIO_SHARK
+ tristate "Griffin radioSHARK USB radio receiver"
+ depends on USB && SND
+ ---help---
+ Choose Y here if you have this radio receiver.
+
+ There are 2 versions of this device, this driver is for version 1,
+ which is white.
+
+ In order to control your radio card, you will need to use programs
+ that are compatible with the Video For Linux API. Information on
+ this API and pointers to "v4l" programs may be found at
+ <file:Documentation/video4linux/API.html>.
+
+ To compile this driver as a module, choose M here: the
+ module will be called radio-shark.
+
+config RADIO_SHARK2
+ tristate "Griffin radioSHARK2 USB radio receiver"
+ depends on USB
+ ---help---
+ Choose Y here if you have this radio receiver.
+
+ There are 2 versions of this device, this driver is for version 2,
+ which is black.
+
+ In order to control your radio card, you will need to use programs
+ that are compatible with the Video For Linux API. Information on
+ this API and pointers to "v4l" programs may be found at
+ <file:Documentation/video4linux/API.html>.
+
+ To compile this driver as a module, choose M here: the
+ module will be called radio-shark2.
config I2C_SI4713
tristate "I2C driver for Silicon Labs Si4713 device"
diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile
index ca8c7d134b9..c03ce4fe74e 100644
--- a/drivers/media/radio/Makefile
+++ b/drivers/media/radio/Makefile
@@ -11,6 +11,8 @@ obj-$(CONFIG_RADIO_CADET) += radio-cadet.o
obj-$(CONFIG_RADIO_TYPHOON) += radio-typhoon.o
obj-$(CONFIG_RADIO_TERRATEC) += radio-terratec.o
obj-$(CONFIG_RADIO_MAXIRADIO) += radio-maxiradio.o
+obj-$(CONFIG_RADIO_SHARK) += radio-shark.o
+obj-$(CONFIG_RADIO_SHARK2) += shark2.o
obj-$(CONFIG_RADIO_RTRACK) += radio-aimslab.o
obj-$(CONFIG_RADIO_ZOLTRIX) += radio-zoltrix.o
obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o
@@ -29,4 +31,6 @@ obj-$(CONFIG_RADIO_TIMBERDALE) += radio-timb.o
obj-$(CONFIG_RADIO_WL1273) += radio-wl1273.o
obj-$(CONFIG_RADIO_WL128X) += wl128x/
+shark2-objs := radio-shark2.o radio-tea5777.o
+
ccflags-y += -Isound
diff --git a/drivers/media/radio/lm7000.h b/drivers/media/radio/lm7000.h
new file mode 100644
index 00000000000..139cd6b6882
--- /dev/null
+++ b/drivers/media/radio/lm7000.h
@@ -0,0 +1,43 @@
+#ifndef __LM7000_H
+#define __LM7000_H
+
+/* Sanyo LM7000 tuner chip control
+ *
+ * Copyright 2012 Ondrej Zary <linux@rainbow-software.org>
+ * based on radio-aimslab.c by M. Kirkwood
+ * and radio-sf16fmi.c by M. Kirkwood and Petr Vandrovec
+ */
+
+#define LM7000_DATA (1 << 0)
+#define LM7000_CLK (1 << 1)
+#define LM7000_CE (1 << 2)
+
+#define LM7000_FM_100 (0 << 20)
+#define LM7000_FM_50 (1 << 20)
+#define LM7000_FM_25 (2 << 20)
+#define LM7000_BIT_FM (1 << 23)
+
+static inline void lm7000_set_freq(u32 freq, void *handle,
+ void (*set_pins)(void *handle, u8 pins))
+{
+ int i;
+ u8 data;
+ u32 val;
+
+ freq += 171200; /* Add 10.7 MHz IF */
+ freq /= 400; /* Convert to 25 kHz units */
+ val = freq | LM7000_FM_25 | LM7000_BIT_FM;
+ /* write the 24-bit register, starting with LSB */
+ for (i = 0; i < 24; i++) {
+ data = val & (1 << i) ? LM7000_DATA : 0;
+ set_pins(handle, data | LM7000_CE);
+ udelay(2);
+ set_pins(handle, data | LM7000_CE | LM7000_CLK);
+ udelay(2);
+ set_pins(handle, data | LM7000_CE);
+ udelay(2);
+ }
+ set_pins(handle, 0);
+}
+
+#endif /* __LM7000_H */
diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c
index 98e0c8c2031..12c70e876f5 100644
--- a/drivers/media/radio/radio-aimslab.c
+++ b/drivers/media/radio/radio-aimslab.c
@@ -37,6 +37,7 @@
#include <media/v4l2-ioctl.h>
#include <media/v4l2-ctrls.h>
#include "radio-isa.h"
+#include "lm7000.h"
MODULE_AUTHOR("M. Kirkwood");
MODULE_DESCRIPTION("A driver for the RadioTrack/RadioReveal radio card.");
@@ -72,55 +73,38 @@ static struct radio_isa_card *rtrack_alloc(void)
return rt ? &rt->isa : NULL;
}
-/* The 128+64 on these outb's is to keep the volume stable while tuning.
- * Without them, the volume _will_ creep up with each frequency change
- * and bit 4 (+16) is to keep the signal strength meter enabled.
- */
+#define AIMS_BIT_TUN_CE (1 << 0)
+#define AIMS_BIT_TUN_CLK (1 << 1)
+#define AIMS_BIT_TUN_DATA (1 << 2)
+#define AIMS_BIT_VOL_CE (1 << 3)
+#define AIMS_BIT_TUN_STRQ (1 << 4)
+/* bit 5 is not connected */
+#define AIMS_BIT_VOL_UP (1 << 6) /* active low */
+#define AIMS_BIT_VOL_DN (1 << 7) /* active low */
-static void send_0_byte(struct radio_isa_card *isa, int on)
+void rtrack_set_pins(void *handle, u8 pins)
{
- outb_p(128+64+16+on+1, isa->io); /* wr-enable + data low */
- outb_p(128+64+16+on+2+1, isa->io); /* clock */
- msleep(1);
-}
+ struct radio_isa_card *isa = handle;
+ struct rtrack *rt = container_of(isa, struct rtrack, isa);
+ u8 bits = AIMS_BIT_VOL_DN | AIMS_BIT_VOL_UP | AIMS_BIT_TUN_STRQ;
-static void send_1_byte(struct radio_isa_card *isa, int on)
-{
- outb_p(128+64+16+on+4+1, isa->io); /* wr-enable+data high */
- outb_p(128+64+16+on+4+2+1, isa->io); /* clock */
- msleep(1);
+ if (!v4l2_ctrl_g_ctrl(rt->isa.mute))
+ bits |= AIMS_BIT_VOL_CE;
+
+ if (pins & LM7000_DATA)
+ bits |= AIMS_BIT_TUN_DATA;
+ if (pins & LM7000_CLK)
+ bits |= AIMS_BIT_TUN_CLK;
+ if (pins & LM7000_CE)
+ bits |= AIMS_BIT_TUN_CE;
+
+ outb_p(bits, rt->isa.io);
}
static int rtrack_s_frequency(struct radio_isa_card *isa, u32 freq)
{
- int on = v4l2_ctrl_g_ctrl(isa->mute) ? 0 : 8;
- int i;
-
- freq += 171200; /* Add 10.7 MHz IF */
- freq /= 800; /* Convert to 50 kHz units */
-
- send_0_byte(isa, on); /* 0: LSB of frequency */
-
- for (i = 0; i < 13; i++) /* : frequency bits (1-13) */
- if (freq & (1 << i))
- send_1_byte(isa, on);
- else
- send_0_byte(isa, on);
-
- send_0_byte(isa, on); /* 14: test bit - always 0 */
- send_0_byte(isa, on); /* 15: test bit - always 0 */
-
- send_0_byte(isa, on); /* 16: band data 0 - always 0 */
- send_0_byte(isa, on); /* 17: band data 1 - always 0 */
- send_0_byte(isa, on); /* 18: band data 2 - always 0 */
- send_0_byte(isa, on); /* 19: time base - always 0 */
-
- send_0_byte(isa, on); /* 20: spacing (0 = 25 kHz) */
- send_1_byte(isa, on); /* 21: spacing (1 = 25 kHz) */
- send_0_byte(isa, on); /* 22: spacing (0 = 25 kHz) */
- send_1_byte(isa, on); /* 23: AM/FM (FM = 1, always) */
+ lm7000_set_freq(freq, isa, rtrack_set_pins);
- outb(0xd0 + on, isa->io); /* volume steady + sigstr */
return 0;
}
diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c
index 16a089fad90..697a421c994 100644
--- a/drivers/media/radio/radio-cadet.c
+++ b/drivers/media/radio/radio-cadet.c
@@ -41,6 +41,9 @@
#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-fh.h>
+#include <media/v4l2-event.h>
MODULE_AUTHOR("Fred Gleason, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath");
MODULE_DESCRIPTION("A driver for the ADS Cadet AM/FM/RDS radio card.");
@@ -61,14 +64,15 @@ module_param(radio_nr, int, 0);
struct cadet {
struct v4l2_device v4l2_dev;
struct video_device vdev;
+ struct v4l2_ctrl_handler ctrl_handler;
int io;
- int users;
- int curtuner;
+ bool is_fm_band;
+ u32 curfreq;
int tunestat;
int sigstrength;
wait_queue_head_t read_queue;
struct timer_list readtimer;
- __u8 rdsin, rdsout, rdsstat;
+ u8 rdsin, rdsout, rdsstat;
unsigned char rdsbuf[RDS_BUFFER];
struct mutex lock;
int reading;
@@ -81,9 +85,9 @@ static struct cadet cadet_card;
* The V4L API spec does not define any particular unit for the signal
* strength value. These values are in microvolts of RF at the tuner's input.
*/
-static __u16 sigtable[2][4] = {
- { 5, 10, 30, 150 },
- { 28, 40, 63, 1000 }
+static u16 sigtable[2][4] = {
+ { 1835, 2621, 4128, 65535 },
+ { 2185, 4369, 13107, 65535 },
};
@@ -91,14 +95,12 @@ static int cadet_getstereo(struct cadet *dev)
{
int ret = V4L2_TUNER_SUB_MONO;
- if (dev->curtuner != 0) /* Only FM has stereo capability! */
+ if (!dev->is_fm_band) /* Only FM has stereo capability! */
return V4L2_TUNER_SUB_MONO;
- mutex_lock(&dev->lock);
outb(7, dev->io); /* Select tuner control */
if ((inb(dev->io + 1) & 0x40) == 0)
ret = V4L2_TUNER_SUB_STEREO;
- mutex_unlock(&dev->lock);
return ret;
}
@@ -111,8 +113,6 @@ static unsigned cadet_gettune(struct cadet *dev)
* Prepare for read
*/
- mutex_lock(&dev->lock);
-
outb(7, dev->io); /* Select tuner control */
curvol = inb(dev->io + 1); /* Save current volume/mute setting */
outb(0x00, dev->io + 1); /* Ensure WRITE-ENABLE is LOW */
@@ -134,8 +134,6 @@ static unsigned cadet_gettune(struct cadet *dev)
* Restore volume/mute setting
*/
outb(curvol, dev->io + 1);
- mutex_unlock(&dev->lock);
-
return fifo;
}
@@ -152,20 +150,18 @@ static unsigned cadet_getfreq(struct cadet *dev)
/*
* Convert to actual frequency
*/
- if (dev->curtuner == 0) { /* FM */
- test = 12500;
- for (i = 0; i < 14; i++) {
- if ((fifo & 0x01) != 0)
- freq += test;
- test = test << 1;
- fifo = fifo >> 1;
- }
- freq -= 10700000; /* IF frequency is 10.7 MHz */
- freq = (freq * 16) / 1000000; /* Make it 1/16 MHz */
+ if (!dev->is_fm_band) /* AM */
+ return ((fifo & 0x7fff) - 450) * 16;
+
+ test = 12500;
+ for (i = 0; i < 14; i++) {
+ if ((fifo & 0x01) != 0)
+ freq += test;
+ test = test << 1;
+ fifo = fifo >> 1;
}
- if (dev->curtuner == 1) /* AM */
- freq = ((fifo & 0x7fff) - 2010) * 16;
-
+ freq -= 10700000; /* IF frequency is 10.7 MHz */
+ freq = (freq * 16) / 1000; /* Make it 1/16 kHz */
return freq;
}
@@ -174,8 +170,6 @@ static void cadet_settune(struct cadet *dev, unsigned fifo)
int i;
unsigned test;
- mutex_lock(&dev->lock);
-
outb(7, dev->io); /* Select tuner control */
/*
* Write the shift register
@@ -194,7 +188,6 @@ static void cadet_settune(struct cadet *dev, unsigned fifo)
test = 0x1c | ((fifo >> 23) & 0x02);
outb(test, dev->io + 1);
}
- mutex_unlock(&dev->lock);
}
static void cadet_setfreq(struct cadet *dev, unsigned freq)
@@ -203,13 +196,14 @@ static void cadet_setfreq(struct cadet *dev, unsigned freq)
int i, j, test;
int curvol;
+ dev->curfreq = freq;
/*
* Formulate a fifo command
*/
fifo = 0;
- if (dev->curtuner == 0) { /* FM */
+ if (dev->is_fm_band) { /* FM */
test = 102400;
- freq = (freq * 1000) / 16; /* Make it kHz */
+ freq = freq / 16; /* Make it kHz */
freq += 10700; /* IF is 10700 kHz */
for (i = 0; i < 14; i++) {
fifo = fifo << 1;
@@ -219,20 +213,17 @@ static void cadet_setfreq(struct cadet *dev, unsigned freq)
}
test = test >> 1;
}
- }
- if (dev->curtuner == 1) { /* AM */
- fifo = (freq / 16) + 2010; /* Make it kHz */
- fifo |= 0x100000; /* Select AM Band */
+ } else { /* AM */
+ fifo = (freq / 16) + 450; /* Make it kHz */
+ fifo |= 0x100000; /* Select AM Band */
}
/*
* Save current volume/mute setting
*/
- mutex_lock(&dev->lock);
outb(7, dev->io); /* Select tuner control */
curvol = inb(dev->io + 1);
- mutex_unlock(&dev->lock);
/*
* Tune the card
@@ -240,49 +231,24 @@ static void cadet_setfreq(struct cadet *dev, unsigned freq)
for (j = 3; j > -1; j--) {
cadet_settune(dev, fifo | (j << 16));
- mutex_lock(&dev->lock);
outb(7, dev->io); /* Select tuner control */
outb(curvol, dev->io + 1);
- mutex_unlock(&dev->lock);
msleep(100);
cadet_gettune(dev);
if ((dev->tunestat & 0x40) == 0) { /* Tuned */
- dev->sigstrength = sigtable[dev->curtuner][j];
- return;
+ dev->sigstrength = sigtable[dev->is_fm_band][j];
+ goto reset_rds;
}
}
dev->sigstrength = 0;
+reset_rds:
+ outb(3, dev->io);
+ outb(inb(dev->io + 1) & 0x7f, dev->io + 1);
}
-static int cadet_getvol(struct cadet *dev)
-{
- int ret = 0;
-
- mutex_lock(&dev->lock);
-
- outb(7, dev->io); /* Select tuner control */
- if ((inb(dev->io + 1) & 0x20) != 0)
- ret = 0xffff;
-
- mutex_unlock(&dev->lock);
- return ret;
-}
-
-
-static void cadet_setvol(struct cadet *dev, int vol)
-{
- mutex_lock(&dev->lock);
- outb(7, dev->io); /* Select tuner control */
- if (vol > 0)
- outb(0x20, dev->io + 1);
- else
- outb(0x00, dev->io + 1);
- mutex_unlock(&dev->lock);
-}
-
static void cadet_handler(unsigned long data)
{
struct cadet *dev = (void *)data;
@@ -295,7 +261,7 @@ static void cadet_handler(unsigned long data)
outb(0x80, dev->io); /* Select RDS fifo */
while ((inb(dev->io) & 0x80) != 0) {
dev->rdsbuf[dev->rdsin] = inb(dev->io + 1);
- if (dev->rdsin == dev->rdsout)
+ if (dev->rdsin + 1 == dev->rdsout)
printk(KERN_WARNING "cadet: RDS buffer overflow\n");
else
dev->rdsin++;
@@ -314,11 +280,21 @@ static void cadet_handler(unsigned long data)
*/
init_timer(&dev->readtimer);
dev->readtimer.function = cadet_handler;
- dev->readtimer.data = (unsigned long)0;
+ dev->readtimer.data = data;
dev->readtimer.expires = jiffies + msecs_to_jiffies(50);
add_timer(&dev->readtimer);
}
+static void cadet_start_rds(struct cadet *dev)
+{
+ dev->rdsstat = 1;
+ outb(0x80, dev->io); /* Select RDS fifo */
+ init_timer(&dev->readtimer);
+ dev->readtimer.function = cadet_handler;
+ dev->readtimer.data = (unsigned long)dev;
+ dev->readtimer.expires = jiffies + msecs_to_jiffies(50);
+ add_timer(&dev->readtimer);
+}
static ssize_t cadet_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
{
@@ -327,28 +303,24 @@ static ssize_t cadet_read(struct file *file, char __user *data, size_t count, lo
int i = 0;
mutex_lock(&dev->lock);
- if (dev->rdsstat == 0) {
- dev->rdsstat = 1;
- outb(0x80, dev->io); /* Select RDS fifo */
- init_timer(&dev->readtimer);
- dev->readtimer.function = cadet_handler;
- dev->readtimer.data = (unsigned long)dev;
- dev->readtimer.expires = jiffies + msecs_to_jiffies(50);
- add_timer(&dev->readtimer);
- }
+ if (dev->rdsstat == 0)
+ cadet_start_rds(dev);
if (dev->rdsin == dev->rdsout) {
+ if (file->f_flags & O_NONBLOCK) {
+ i = -EWOULDBLOCK;
+ goto unlock;
+ }
mutex_unlock(&dev->lock);
- if (file->f_flags & O_NONBLOCK)
- return -EWOULDBLOCK;
interruptible_sleep_on(&dev->read_queue);
mutex_lock(&dev->lock);
}
while (i < count && dev->rdsin != dev->rdsout)
readbuf[i++] = dev->rdsbuf[dev->rdsout++];
- mutex_unlock(&dev->lock);
- if (copy_to_user(data, readbuf, i))
- return -EFAULT;
+ if (i && copy_to_user(data, readbuf, i))
+ i = -EFAULT;
+unlock:
+ mutex_unlock(&dev->lock);
return i;
}
@@ -359,48 +331,58 @@ static int vidioc_querycap(struct file *file, void *priv,
strlcpy(v->driver, "ADS Cadet", sizeof(v->driver));
strlcpy(v->card, "ADS Cadet", sizeof(v->card));
strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
- v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO |
+ v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO |
V4L2_CAP_READWRITE | V4L2_CAP_RDS_CAPTURE;
+ v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
+static const struct v4l2_frequency_band bands[] = {
+ {
+ .index = 0,
+ .type = V4L2_TUNER_RADIO,
+ .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_FREQ_BANDS,
+ .rangelow = 8320, /* 520 kHz */
+ .rangehigh = 26400, /* 1650 kHz */
+ .modulation = V4L2_BAND_MODULATION_AM,
+ }, {
+ .index = 1,
+ .type = V4L2_TUNER_RADIO,
+ .capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS |
+ V4L2_TUNER_CAP_RDS_BLOCK_IO | V4L2_TUNER_CAP_LOW |
+ V4L2_TUNER_CAP_FREQ_BANDS,
+ .rangelow = 1400000, /* 87.5 MHz */
+ .rangehigh = 1728000, /* 108.0 MHz */
+ .modulation = V4L2_BAND_MODULATION_FM,
+ },
+};
+
static int vidioc_g_tuner(struct file *file, void *priv,
struct v4l2_tuner *v)
{
struct cadet *dev = video_drvdata(file);
+ if (v->index)
+ return -EINVAL;
v->type = V4L2_TUNER_RADIO;
- switch (v->index) {
- case 0:
- strlcpy(v->name, "FM", sizeof(v->name));
- v->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS |
- V4L2_TUNER_CAP_RDS_BLOCK_IO;
- v->rangelow = 1400; /* 87.5 MHz */
- v->rangehigh = 1728; /* 108.0 MHz */
+ strlcpy(v->name, "Radio", sizeof(v->name));
+ v->capability = bands[0].capability | bands[1].capability;
+ v->rangelow = bands[0].rangelow; /* 520 kHz (start of AM band) */
+ v->rangehigh = bands[1].rangehigh; /* 108.0 MHz (end of FM band) */
+ if (dev->is_fm_band) {
v->rxsubchans = cadet_getstereo(dev);
- switch (v->rxsubchans) {
- case V4L2_TUNER_SUB_MONO:
- v->audmode = V4L2_TUNER_MODE_MONO;
- break;
- case V4L2_TUNER_SUB_STEREO:
- v->audmode = V4L2_TUNER_MODE_STEREO;
- break;
- default:
- break;
- }
- v->rxsubchans |= V4L2_TUNER_SUB_RDS;
- break;
- case 1:
- strlcpy(v->name, "AM", sizeof(v->name));
- v->capability = V4L2_TUNER_CAP_LOW;
+ outb(3, dev->io);
+ outb(inb(dev->io + 1) & 0x7f, dev->io + 1);
+ mdelay(100);
+ outb(3, dev->io);
+ if (inb(dev->io + 1) & 0x80)
+ v->rxsubchans |= V4L2_TUNER_SUB_RDS;
+ } else {
v->rangelow = 8320; /* 520 kHz */
v->rangehigh = 26400; /* 1650 kHz */
v->rxsubchans = V4L2_TUNER_SUB_MONO;
- v->audmode = V4L2_TUNER_MODE_MONO;
- break;
- default:
- return -EINVAL;
}
+ v->audmode = V4L2_TUNER_MODE_STEREO;
v->signal = dev->sigstrength; /* We might need to modify scaling of this */
return 0;
}
@@ -408,11 +390,17 @@ static int vidioc_g_tuner(struct file *file, void *priv,
static int vidioc_s_tuner(struct file *file, void *priv,
struct v4l2_tuner *v)
{
- struct cadet *dev = video_drvdata(file);
+ return v->index ? -EINVAL : 0;
+}
- if (v->index != 0 && v->index != 1)
+static int vidioc_enum_freq_bands(struct file *file, void *priv,
+ struct v4l2_frequency_band *band)
+{
+ if (band->tuner)
+ return -EINVAL;
+ if (band->index >= ARRAY_SIZE(bands))
return -EINVAL;
- dev->curtuner = v->index;
+ *band = bands[band->index];
return 0;
}
@@ -421,9 +409,10 @@ static int vidioc_g_frequency(struct file *file, void *priv,
{
struct cadet *dev = video_drvdata(file);
- f->tuner = dev->curtuner;
+ if (f->tuner)
+ return -EINVAL;
f->type = V4L2_TUNER_RADIO;
- f->frequency = cadet_getfreq(dev);
+ f->frequency = dev->curfreq;
return 0;
}
@@ -433,103 +422,46 @@ static int vidioc_s_frequency(struct file *file, void *priv,
{
struct cadet *dev = video_drvdata(file);
- if (f->type != V4L2_TUNER_RADIO)
- return -EINVAL;
- if (dev->curtuner == 0 && (f->frequency < 1400 || f->frequency > 1728))
- return -EINVAL;
- if (dev->curtuner == 1 && (f->frequency < 8320 || f->frequency > 26400))
+ if (f->tuner)
return -EINVAL;
+ dev->is_fm_band =
+ f->frequency >= (bands[0].rangehigh + bands[1].rangelow) / 2;
+ clamp(f->frequency, bands[dev->is_fm_band].rangelow,
+ bands[dev->is_fm_band].rangehigh);
cadet_setfreq(dev, f->frequency);
return 0;
}
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
+static int cadet_s_ctrl(struct v4l2_ctrl *ctrl)
{
- switch (qc->id) {
- case V4L2_CID_AUDIO_MUTE:
- return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
- case V4L2_CID_AUDIO_VOLUME:
- return v4l2_ctrl_query_fill(qc, 0, 0xff, 1, 0xff);
- }
- return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct cadet *dev = video_drvdata(file);
+ struct cadet *dev = container_of(ctrl->handler, struct cadet, ctrl_handler);
switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE: /* TODO: Handle this correctly */
- ctrl->value = (cadet_getvol(dev) == 0);
- break;
- case V4L2_CID_AUDIO_VOLUME:
- ctrl->value = cadet_getvol(dev);
- break;
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct cadet *dev = video_drvdata(file);
-
- switch (ctrl->id){
- case V4L2_CID_AUDIO_MUTE: /* TODO: Handle this correctly */
- if (ctrl->value)
- cadet_setvol(dev, 0);
+ case V4L2_CID_AUDIO_MUTE:
+ outb(7, dev->io); /* Select tuner control */
+ if (ctrl->val)
+ outb(0x00, dev->io + 1);
else
- cadet_setvol(dev, 0xffff);
- break;
- case V4L2_CID_AUDIO_VOLUME:
- cadet_setvol(dev, ctrl->value);
- break;
- default:
- return -EINVAL;
+ outb(0x20, dev->io + 1);
+ return 0;
}
- return 0;
-}
-
-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,
- struct v4l2_audio *a)
-{
- return a->index ? -EINVAL : 0;
+ return -EINVAL;
}
static int cadet_open(struct file *file)
{
struct cadet *dev = video_drvdata(file);
+ int err;
mutex_lock(&dev->lock);
- dev->users++;
- if (1 == dev->users)
+ err = v4l2_fh_open(file);
+ if (err)
+ goto fail;
+ if (v4l2_fh_is_singular_file(file))
init_waitqueue_head(&dev->read_queue);
+fail:
mutex_unlock(&dev->lock);
- return 0;
+ return err;
}
static int cadet_release(struct file *file)
@@ -537,11 +469,11 @@ static int cadet_release(struct file *file)
struct cadet *dev = video_drvdata(file);
mutex_lock(&dev->lock);
- dev->users--;
- if (0 == dev->users) {
+ if (v4l2_fh_is_singular_file(file) && dev->rdsstat) {
del_timer_sync(&dev->readtimer);
dev->rdsstat = 0;
}
+ v4l2_fh_release(file);
mutex_unlock(&dev->lock);
return 0;
}
@@ -549,11 +481,19 @@ static int cadet_release(struct file *file)
static unsigned int cadet_poll(struct file *file, struct poll_table_struct *wait)
{
struct cadet *dev = video_drvdata(file);
+ unsigned long req_events = poll_requested_events(wait);
+ unsigned int res = v4l2_ctrl_poll(file, wait);
poll_wait(file, &dev->read_queue, wait);
+ if (dev->rdsstat == 0 && (req_events & (POLLIN | POLLRDNORM))) {
+ mutex_lock(&dev->lock);
+ if (dev->rdsstat == 0)
+ cadet_start_rds(dev);
+ mutex_unlock(&dev->lock);
+ }
if (dev->rdsin != dev->rdsout)
- return POLLIN | POLLRDNORM;
- return 0;
+ res |= POLLIN | POLLRDNORM;
+ return res;
}
@@ -572,13 +512,14 @@ static const struct v4l2_ioctl_ops cadet_ioctl_ops = {
.vidioc_s_tuner = vidioc_s_tuner,
.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_g_audio = vidioc_g_audio,
- .vidioc_s_audio = vidioc_s_audio,
- .vidioc_g_input = vidioc_g_input,
- .vidioc_s_input = vidioc_s_input,
+ .vidioc_enum_freq_bands = vidioc_enum_freq_bands,
+ .vidioc_log_status = v4l2_ctrl_log_status,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+static const struct v4l2_ctrl_ops cadet_ctrl_ops = {
+ .s_ctrl = cadet_s_ctrl,
};
#ifdef CONFIG_PNP
@@ -628,8 +569,8 @@ static void cadet_probe(struct cadet *dev)
for (i = 0; i < 8; i++) {
dev->io = iovals[i];
if (request_region(dev->io, 2, "cadet-probe")) {
- cadet_setfreq(dev, 1410);
- if (cadet_getfreq(dev) == 1410) {
+ cadet_setfreq(dev, bands[1].rangelow);
+ if (cadet_getfreq(dev) == bands[1].rangelow) {
release_region(dev->io, 2);
return;
}
@@ -648,7 +589,8 @@ static int __init cadet_init(void)
{
struct cadet *dev = &cadet_card;
struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
- int res;
+ struct v4l2_ctrl_handler *hdl;
+ int res = -ENODEV;
strlcpy(v4l2_dev->name, "cadet", sizeof(v4l2_dev->name));
mutex_init(&dev->lock);
@@ -680,23 +622,40 @@ static int __init cadet_init(void)
goto fail;
}
+ hdl = &dev->ctrl_handler;
+ v4l2_ctrl_handler_init(hdl, 2);
+ v4l2_ctrl_new_std(hdl, &cadet_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");
+ goto err_hdl;
+ }
+
+ dev->is_fm_band = true;
+ dev->curfreq = bands[dev->is_fm_band].rangelow;
+ cadet_setfreq(dev, dev->curfreq);
strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
dev->vdev.v4l2_dev = v4l2_dev;
dev->vdev.fops = &cadet_fops;
dev->vdev.ioctl_ops = &cadet_ioctl_ops;
dev->vdev.release = video_device_release_empty;
+ dev->vdev.lock = &dev->lock;
+ set_bit(V4L2_FL_USE_FH_PRIO, &dev->vdev.flags);
video_set_drvdata(&dev->vdev, dev);
- if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
- v4l2_device_unregister(v4l2_dev);
- release_region(dev->io, 2);
- goto fail;
- }
+ if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0)
+ goto err_hdl;
v4l2_info(v4l2_dev, "ADS Cadet Radio Card at 0x%x\n", dev->io);
return 0;
+err_hdl:
+ v4l2_ctrl_handler_free(hdl);
+ v4l2_device_unregister(v4l2_dev);
+ release_region(dev->io, 2);
fail:
pnp_unregister_driver(&cadet_pnp_driver);
- return -ENODEV;
+ return res;
}
static void __exit cadet_exit(void)
@@ -704,7 +663,10 @@ static void __exit cadet_exit(void)
struct cadet *dev = &cadet_card;
video_unregister_device(&dev->vdev);
+ v4l2_ctrl_handler_free(&dev->ctrl_handler);
v4l2_device_unregister(&dev->v4l2_dev);
+ outb(7, dev->io); /* Mute */
+ outb(0x00, dev->io + 1);
release_region(dev->io, 2);
pnp_unregister_driver(&cadet_pnp_driver);
}
diff --git a/drivers/media/radio/radio-mr800.c b/drivers/media/radio/radio-mr800.c
index 94cb6bc690f..3182b26d6ef 100644
--- a/drivers/media/radio/radio-mr800.c
+++ b/drivers/media/radio/radio-mr800.c
@@ -295,7 +295,8 @@ static int vidioc_g_tuner(struct file *file, void *priv,
v->type = V4L2_TUNER_RADIO;
v->rangelow = FREQ_MIN * FREQ_MUL;
v->rangehigh = FREQ_MAX * FREQ_MUL;
- v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
+ v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
+ V4L2_TUNER_CAP_HWSEEK_WRAP;
v->rxsubchans = is_stereo ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
v->audmode = radio->stereo ?
V4L2_TUNER_MODE_STEREO : V4L2_TUNER_MODE_MONO;
@@ -372,7 +373,7 @@ static int vidioc_s_hw_freq_seek(struct file *file, void *priv,
timeout = jiffies + msecs_to_jiffies(30000);
for (;;) {
if (time_after(jiffies, timeout)) {
- retval = -EAGAIN;
+ retval = -ENODATA;
break;
}
if (schedule_timeout_interruptible(msecs_to_jiffies(10))) {
diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
index a81d723b8c7..8185d5fbfa8 100644
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -27,6 +27,7 @@
#include <linux/io.h> /* outb, outb_p */
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
+#include "lm7000.h"
MODULE_AUTHOR("Petr Vandrovec, vandrove@vc.cvut.cz and M. Kirkwood");
MODULE_DESCRIPTION("A driver for the SF16-FMI, SF16-FMP and SF16-FMD radio.");
@@ -54,31 +55,33 @@ static struct fmi fmi_card;
static struct pnp_dev *dev;
bool pnp_attached;
-/* freq is in 1/16 kHz to internal number, hw precision is 50 kHz */
-/* It is only useful to give freq in interval of 800 (=0.05Mhz),
- * other bits will be truncated, e.g 92.7400016 -> 92.7, but
- * 92.7400017 -> 92.75
- */
-#define RSF16_ENCODE(x) ((x) / 800 + 214)
#define RSF16_MINFREQ (87 * 16000)
#define RSF16_MAXFREQ (108 * 16000)
-static void outbits(int bits, unsigned int data, int io)
+#define FMI_BIT_TUN_CE (1 << 0)
+#define FMI_BIT_TUN_CLK (1 << 1)
+#define FMI_BIT_TUN_DATA (1 << 2)
+#define FMI_BIT_VOL_SW (1 << 3)
+#define FMI_BIT_TUN_STRQ (1 << 4)
+
+void fmi_set_pins(void *handle, u8 pins)
{
- while (bits--) {
- if (data & 1) {
- outb(5, io);
- udelay(6);
- outb(7, io);
- udelay(6);
- } else {
- outb(1, io);
- udelay(6);
- outb(3, io);
- udelay(6);
- }
- data >>= 1;
- }
+ struct fmi *fmi = handle;
+ u8 bits = FMI_BIT_TUN_STRQ;
+
+ if (!fmi->mute)
+ bits |= FMI_BIT_VOL_SW;
+
+ if (pins & LM7000_DATA)
+ bits |= FMI_BIT_TUN_DATA;
+ if (pins & LM7000_CLK)
+ bits |= FMI_BIT_TUN_CLK;