aboutsummaryrefslogtreecommitdiff
path: root/drivers/media/usb/em28xx
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/usb/em28xx')
-rw-r--r--drivers/media/usb/em28xx/Kconfig8
-rw-r--r--drivers/media/usb/em28xx/Makefile5
-rw-r--r--drivers/media/usb/em28xx/em28xx-audio.c429
-rw-r--r--drivers/media/usb/em28xx/em28xx-camera.c1
-rw-r--r--drivers/media/usb/em28xx/em28xx-cards.c553
-rw-r--r--drivers/media/usb/em28xx/em28xx-core.c410
-rw-r--r--drivers/media/usb/em28xx/em28xx-dvb.c112
-rw-r--r--drivers/media/usb/em28xx/em28xx-i2c.c199
-rw-r--r--drivers/media/usb/em28xx/em28xx-input.c209
-rw-r--r--drivers/media/usb/em28xx/em28xx-reg.h11
-rw-r--r--drivers/media/usb/em28xx/em28xx-v4l.h20
-rw-r--r--drivers/media/usb/em28xx/em28xx-vbi.c1
-rw-r--r--drivers/media/usb/em28xx/em28xx-video.c652
-rw-r--r--drivers/media/usb/em28xx/em28xx.h120
14 files changed, 1770 insertions, 960 deletions
diff --git a/drivers/media/usb/em28xx/Kconfig b/drivers/media/usb/em28xx/Kconfig
index ca5ee6aceb6..a1fccf3096d 100644
--- a/drivers/media/usb/em28xx/Kconfig
+++ b/drivers/media/usb/em28xx/Kconfig
@@ -1,8 +1,12 @@
config VIDEO_EM28XX
- tristate "Empia EM28xx USB video capture support"
+ tristate "Empia EM28xx USB devices support"
depends on VIDEO_DEV && I2C
select VIDEO_TUNER
select VIDEO_TVEEPROM
+
+config VIDEO_EM28XX_V4L2
+ tristate "Empia EM28xx analog TV, video capture and/or webcam support"
+ depends on VIDEO_EM28XX
select VIDEOBUF2_VMALLOC
select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT
select VIDEO_TVP5150 if MEDIA_SUBDRV_AUTOSELECT
@@ -49,6 +53,8 @@ config VIDEO_EM28XX_DVB
select DVB_MB86A20S if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_M88DS3103 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_M88TS2022 if MEDIA_SUBDRV_AUTOSELECT
---help---
This adds support for DVB cards based on the
Empiatech em28xx chips.
diff --git a/drivers/media/usb/em28xx/Makefile b/drivers/media/usb/em28xx/Makefile
index ad6d4855794..3f850d5063d 100644
--- a/drivers/media/usb/em28xx/Makefile
+++ b/drivers/media/usb/em28xx/Makefile
@@ -1,10 +1,11 @@
-em28xx-y += em28xx-video.o em28xx-i2c.o em28xx-cards.o
-em28xx-y += em28xx-core.o em28xx-vbi.o em28xx-camera.o
+em28xx-y += em28xx-core.o em28xx-i2c.o em28xx-cards.o em28xx-camera.o
+em28xx-v4l-objs := em28xx-video.o em28xx-vbi.o
em28xx-alsa-objs := em28xx-audio.o
em28xx-rc-objs := em28xx-input.o
obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o
+obj-$(CONFIG_VIDEO_EM28XX_V4L2) += em28xx-v4l.o
obj-$(CONFIG_VIDEO_EM28XX_ALSA) += em28xx-alsa.o
obj-$(CONFIG_VIDEO_EM28XX_DVB) += em28xx-dvb.o
obj-$(CONFIG_VIDEO_EM28XX_RC) += em28xx-rc.o
diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
index 2fdb66ee44a..05e9bd11a3f 100644
--- a/drivers/media/usb/em28xx/em28xx-audio.c
+++ b/drivers/media/usb/em28xx/em28xx-audio.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2006 Markus Rechberger <mrechberger@gmail.com>
*
- * Copyright (C) 2007-2011 Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (C) 2007-2014 Mauro Carvalho Chehab
* - Port to work with the in-kernel driver
* - Cleanups, fixes, alsa-controls, etc.
*
@@ -50,6 +50,9 @@ static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "activates debug info");
+#define EM28XX_MAX_AUDIO_BUFS 5
+#define EM28XX_MIN_AUDIO_PACKETS 64
+
#define dprintk(fmt, arg...) do { \
if (debug) \
printk(KERN_INFO "em28xx-audio %s: " fmt, \
@@ -63,17 +66,13 @@ static int em28xx_deinit_isoc_audio(struct em28xx *dev)
int i;
dprintk("Stopping isoc\n");
- for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
+ for (i = 0; i < dev->adev.num_urb; i++) {
+ struct urb *urb = dev->adev.urb[i];
+
if (!irqs_disabled())
- usb_kill_urb(dev->adev.urb[i]);
+ usb_kill_urb(urb);
else
- usb_unlink_urb(dev->adev.urb[i]);
-
- usb_free_urb(dev->adev.urb[i]);
- dev->adev.urb[i] = NULL;
-
- kfree(dev->adev.transfer_buffer[i]);
- dev->adev.transfer_buffer[i] = NULL;
+ usb_unlink_urb(urb);
}
return 0;
@@ -91,6 +90,12 @@ static void em28xx_audio_isocirq(struct urb *urb)
struct snd_pcm_substream *substream;
struct snd_pcm_runtime *runtime;
+ if (dev->disconnected) {
+ dprintk("device disconnected while streaming. URB status=%d.\n", urb->status);
+ atomic_set(&dev->stream_started, 0);
+ return;
+ }
+
switch (urb->status) {
case 0: /* success */
case -ETIMEDOUT: /* NAK */
@@ -158,63 +163,27 @@ static void em28xx_audio_isocirq(struct urb *urb)
urb->status = 0;
status = usb_submit_urb(urb, GFP_ATOMIC);
- if (status < 0) {
+ if (status < 0)
em28xx_errdev("resubmit of audio urb failed (error=%i)\n",
status);
- }
return;
}
static int em28xx_init_audio_isoc(struct em28xx *dev)
{
int i, errCode;
- const int sb_size = EM28XX_NUM_AUDIO_PACKETS *
- EM28XX_AUDIO_MAX_PACKET_SIZE;
dprintk("Starting isoc transfers\n");
- for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
- struct urb *urb;
- int j, k;
-
- dev->adev.transfer_buffer[i] = kmalloc(sb_size, GFP_ATOMIC);
- if (!dev->adev.transfer_buffer[i])
- return -ENOMEM;
-
- memset(dev->adev.transfer_buffer[i], 0x80, sb_size);
- urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS, GFP_ATOMIC);
- if (!urb) {
- em28xx_errdev("usb_alloc_urb failed!\n");
- for (j = 0; j < i; j++) {
- usb_free_urb(dev->adev.urb[j]);
- kfree(dev->adev.transfer_buffer[j]);
- }
- return -ENOMEM;
- }
-
- urb->dev = dev->udev;
- urb->context = dev;
- urb->pipe = usb_rcvisocpipe(dev->udev, EM28XX_EP_AUDIO);
- urb->transfer_flags = URB_ISO_ASAP;
- urb->transfer_buffer = dev->adev.transfer_buffer[i];
- urb->interval = 1;
- urb->complete = em28xx_audio_isocirq;
- urb->number_of_packets = EM28XX_NUM_AUDIO_PACKETS;
- urb->transfer_buffer_length = sb_size;
-
- for (j = k = 0; j < EM28XX_NUM_AUDIO_PACKETS;
- j++, k += EM28XX_AUDIO_MAX_PACKET_SIZE) {
- urb->iso_frame_desc[j].offset = k;
- urb->iso_frame_desc[j].length =
- EM28XX_AUDIO_MAX_PACKET_SIZE;
- }
- dev->adev.urb[i] = urb;
- }
+ /* Start streaming */
+ for (i = 0; i < dev->adev.num_urb; i++) {
+ memset(dev->adev.transfer_buffer[i], 0x80,
+ dev->adev.urb[i]->transfer_buffer_length);
- for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC);
if (errCode) {
- em28xx_errdev("submit of audio urb failed\n");
+ em28xx_errdev("submit of audio urb failed (error=%i)\n",
+ errCode);
em28xx_deinit_isoc_audio(dev);
atomic_set(&dev->stream_started, 0);
return errCode;
@@ -255,15 +224,26 @@ static struct snd_pcm_hardware snd_em28xx_hw_capture = {
.formats = SNDRV_PCM_FMTBIT_S16_LE,
- .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_KNOT,
+ .rates = SNDRV_PCM_RATE_48000,
.rate_min = 48000,
.rate_max = 48000,
.channels_min = 2,
.channels_max = 2,
.buffer_bytes_max = 62720 * 8, /* just about the value in usbaudio.c */
- .period_bytes_min = 64, /* 12544/2, */
- .period_bytes_max = 12544,
+
+
+ /*
+ * The period is 12.288 bytes. Allow a 10% of variation along its
+ * value, in order to avoid overruns/underruns due to some clock
+ * drift.
+ *
+ * FIXME: This period assumes 64 packets, and a 48000 PCM rate.
+ * Calculate it dynamically.
+ */
+ .period_bytes_min = 11059,
+ .period_bytes_max = 13516,
+
.periods_min = 2,
.periods_max = 98, /* 12544, */
};
@@ -274,28 +254,48 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
int ret = 0;
- dprintk("opening device and trying to acquire exclusive lock\n");
-
if (!dev) {
em28xx_err("BUG: em28xx can't find device struct."
" Can't proceed with open\n");
return -ENODEV;
}
+ if (dev->disconnected)
+ return -ENODEV;
+
+ dprintk("opening device and trying to acquire exclusive lock\n");
+
runtime->hw = snd_em28xx_hw_capture;
- if ((dev->alt == 0 || dev->audio_ifnum) && dev->adev.users == 0) {
- if (dev->audio_ifnum)
+ if ((dev->alt == 0 || dev->is_audio_only) && dev->adev.users == 0) {
+ int nonblock = !!(substream->f_flags & O_NONBLOCK);
+
+ if (nonblock) {
+ if (!mutex_trylock(&dev->lock))
+ return -EAGAIN;
+ } else
+ mutex_lock(&dev->lock);
+ if (dev->is_audio_only)
+ /* vendor audio is on a separate interface */
dev->alt = 1;
else
+ /* vendor audio is on the same interface as video */
dev->alt = 7;
+ /*
+ * FIXME: The intention seems to be to select the alt
+ * setting with the largest wMaxPacketSize for the video
+ * endpoint.
+ * At least dev->alt should be used instead, but we
+ * should probably not touch it at all if it is
+ * already >0, because wMaxPacketSize of the audio
+ * endpoints seems to be the same for all.
+ */
dprintk("changing alternate number on interface %d to %d\n",
- dev->audio_ifnum, dev->alt);
- usb_set_interface(dev->udev, dev->audio_ifnum, dev->alt);
+ dev->ifnum, dev->alt);
+ usb_set_interface(dev->udev, dev->ifnum, dev->alt);
/* Sets volume, mute, etc */
dev->mute = 0;
- mutex_lock(&dev->lock);
ret = em28xx_audio_analog_set(dev);
if (ret < 0)
goto err;
@@ -304,7 +304,12 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
mutex_unlock(&dev->lock);
}
+ /* Dynamically adjust the period size */
snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+ snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
+ dev->adev.period * 95 / 100,
+ dev->adev.period * 105 / 100);
+
dev->adev.capture_pcm_substream = substream;
return 0;
@@ -344,6 +349,10 @@ static int snd_em28xx_hw_capture_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
int ret;
+ struct em28xx *dev = snd_pcm_substream_chip(substream);
+
+ if (dev->disconnected)
+ return -ENODEV;
dprintk("Setting capture parameters\n");
@@ -383,6 +392,9 @@ static int snd_em28xx_prepare(struct snd_pcm_substream *substream)
{
struct em28xx *dev = snd_pcm_substream_chip(substream);
+ if (dev->disconnected)
+ return -ENODEV;
+
dev->adev.hwptr_done_capture = 0;
dev->adev.capture_transfer_done = 0;
@@ -408,6 +420,9 @@ static int snd_em28xx_capture_trigger(struct snd_pcm_substream *substream,
struct em28xx *dev = snd_pcm_substream_chip(substream);
int retval = 0;
+ if (dev->disconnected)
+ return -ENODEV;
+
switch (cmd) {
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */
case SNDRV_PCM_TRIGGER_RESUME: /* fall through */
@@ -434,6 +449,9 @@ static snd_pcm_uframes_t snd_em28xx_capture_pointer(struct snd_pcm_substream
snd_pcm_uframes_t hwptr_done;
dev = snd_pcm_substream_chip(substream);
+ if (dev->disconnected)
+ return SNDRV_PCM_POS_XRUN;
+
spin_lock_irqsave(&dev->adev.slock, flags);
hwptr_done = dev->adev.hwptr_done_capture;
spin_unlock_irqrestore(&dev->adev.slock, flags);
@@ -455,6 +473,11 @@ static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs,
static int em28xx_vol_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *info)
{
+ struct em28xx *dev = snd_kcontrol_chip(kcontrol);
+
+ if (dev->disconnected)
+ return -ENODEV;
+
info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
info->count = 2;
info->value.integer.min = 0;
@@ -467,11 +490,22 @@ static int em28xx_vol_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *value)
{
struct em28xx *dev = snd_kcontrol_chip(kcontrol);
+ struct snd_pcm_substream *substream = dev->adev.capture_pcm_substream;
u16 val = (0x1f - (value->value.integer.value[0] & 0x1f)) |
(0x1f - (value->value.integer.value[1] & 0x1f)) << 8;
+ int nonblock = 0;
int rc;
- mutex_lock(&dev->lock);
+ if (dev->disconnected)
+ return -ENODEV;
+
+ if (substream)
+ nonblock = !!(substream->f_flags & O_NONBLOCK);
+ if (nonblock) {
+ if (!mutex_trylock(&dev->lock))
+ return -EAGAIN;
+ } else
+ mutex_lock(&dev->lock);
rc = em28xx_read_ac97(dev, kcontrol->private_value);
if (rc < 0)
goto err;
@@ -496,9 +530,20 @@ static int em28xx_vol_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *value)
{
struct em28xx *dev = snd_kcontrol_chip(kcontrol);
+ struct snd_pcm_substream *substream = dev->adev.capture_pcm_substream;
+ int nonblock = 0;
int val;
- mutex_lock(&dev->lock);
+ if (dev->disconnected)
+ return -ENODEV;
+
+ if (substream)
+ nonblock = !!(substream->f_flags & O_NONBLOCK);
+ if (nonblock) {
+ if (!mutex_trylock(&dev->lock))
+ return -EAGAIN;
+ } else
+ mutex_lock(&dev->lock);
val = em28xx_read_ac97(dev, kcontrol->private_value);
mutex_unlock(&dev->lock);
if (val < 0)
@@ -520,9 +565,20 @@ static int em28xx_vol_put_mute(struct snd_kcontrol *kcontrol,
{
struct em28xx *dev = snd_kcontrol_chip(kcontrol);
u16 val = value->value.integer.value[0];
+ struct snd_pcm_substream *substream = dev->adev.capture_pcm_substream;
+ int nonblock = 0;
int rc;
- mutex_lock(&dev->lock);
+ if (dev->disconnected)
+ return -ENODEV;
+
+ if (substream)
+ nonblock = !!(substream->f_flags & O_NONBLOCK);
+ if (nonblock) {
+ if (!mutex_trylock(&dev->lock))
+ return -EAGAIN;
+ } else
+ mutex_lock(&dev->lock);
rc = em28xx_read_ac97(dev, kcontrol->private_value);
if (rc < 0)
goto err;
@@ -550,9 +606,20 @@ static int em28xx_vol_get_mute(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *value)
{
struct em28xx *dev = snd_kcontrol_chip(kcontrol);
+ struct snd_pcm_substream *substream = dev->adev.capture_pcm_substream;
+ int nonblock = 0;
int val;
- mutex_lock(&dev->lock);
+ if (dev->disconnected)
+ return -ENODEV;
+
+ if (substream)
+ nonblock = !!(substream->f_flags & O_NONBLOCK);
+ if (nonblock) {
+ if (!mutex_trylock(&dev->lock))
+ return -EAGAIN;
+ } else
+ mutex_lock(&dev->lock);
val = em28xx_read_ac97(dev, kcontrol->private_value);
mutex_unlock(&dev->lock);
if (val < 0)
@@ -634,25 +701,204 @@ static struct snd_pcm_ops snd_em28xx_pcm_capture = {
.page = snd_pcm_get_vmalloc_page,
};
+static void em28xx_audio_free_urb(struct em28xx *dev)
+{
+ int i;
+
+ for (i = 0; i < dev->adev.num_urb; i++) {
+ struct urb *urb = dev->adev.urb[i];
+
+ if (!urb)
+ continue;
+
+ usb_free_coherent(dev->udev, urb->transfer_buffer_length,
+ dev->adev.transfer_buffer[i],
+ urb->transfer_dma);
+
+ usb_free_urb(urb);
+ }
+ kfree(dev->adev.urb);
+ kfree(dev->adev.transfer_buffer);
+ dev->adev.num_urb = 0;
+}
+
+/* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
+static int em28xx_audio_ep_packet_size(struct usb_device *udev,
+ struct usb_endpoint_descriptor *e)
+{
+ int size = le16_to_cpu(e->wMaxPacketSize);
+
+ if (udev->speed == USB_SPEED_HIGH)
+ return (size & 0x7ff) * (1 + (((size) >> 11) & 0x03));
+
+ return size & 0x7ff;
+}
+
+static int em28xx_audio_urb_init(struct em28xx *dev)
+{
+ struct usb_interface *intf;
+ struct usb_endpoint_descriptor *e, *ep = NULL;
+ int i, ep_size, interval, num_urb, npackets;
+ int urb_size, bytes_per_transfer;
+ u8 alt;
+
+ if (dev->ifnum)
+ alt = 1;
+ else
+ alt = 7;
+
+ intf = usb_ifnum_to_if(dev->udev, dev->ifnum);
+
+ if (intf->num_altsetting <= alt) {
+ em28xx_errdev("alt %d doesn't exist on interface %d\n",
+ dev->ifnum, alt);
+ return -ENODEV;
+ }
+
+ for (i = 0; i < intf->altsetting[alt].desc.bNumEndpoints; i++) {
+ e = &intf->altsetting[alt].endpoint[i].desc;
+ if (!usb_endpoint_dir_in(e))
+ continue;
+ if (e->bEndpointAddress == EM28XX_EP_AUDIO) {
+ ep = e;
+ break;
+ }
+ }
+
+ if (!ep) {
+ em28xx_errdev("Couldn't find an audio endpoint");
+ return -ENODEV;
+ }
+
+ ep_size = em28xx_audio_ep_packet_size(dev->udev, ep);
+ interval = 1 << (ep->bInterval - 1);
+
+ em28xx_info("Endpoint 0x%02x %s on intf %d alt %d interval = %d, size %d\n",
+ EM28XX_EP_AUDIO, usb_speed_string(dev->udev->speed),
+ dev->ifnum, alt,
+ interval,
+ ep_size);
+
+ /* Calculate the number and size of URBs to better fit the audio samples */
+
+ /*
+ * Estimate the number of bytes per DMA transfer.
+ *
+ * This is given by the bit rate (for now, only 48000 Hz) multiplied
+ * by 2 channels and 2 bytes/sample divided by the number of microframe
+ * intervals and by the microframe rate (125 us)
+ */
+ bytes_per_transfer = DIV_ROUND_UP(48000 * 2 * 2, 125 * interval);
+
+ /*
+ * Estimate the number of transfer URBs. Don't let it go past the
+ * maximum number of URBs that is known to be supported by the device.
+ */
+ num_urb = DIV_ROUND_UP(bytes_per_transfer, ep_size);
+ if (num_urb > EM28XX_MAX_AUDIO_BUFS)
+ num_urb = EM28XX_MAX_AUDIO_BUFS;
+
+ /*
+ * Now that we know the number of bytes per transfer and the number of
+ * URBs, estimate the typical size of an URB, in order to adjust the
+ * minimal number of packets.
+ */
+ urb_size = bytes_per_transfer / num_urb;
+
+ /*
+ * Now, calculate the amount of audio packets to be filled on each
+ * URB. In order to preserve the old behaviour, use a minimal
+ * threshold for this value.
+ */
+ npackets = EM28XX_MIN_AUDIO_PACKETS;
+ if (urb_size > ep_size * npackets)
+ npackets = DIV_ROUND_UP(urb_size, ep_size);
+
+ em28xx_info("Number of URBs: %d, with %d packets and %d size",
+ num_urb, npackets, urb_size);
+
+ /* Estimate the bytes per period */
+ dev->adev.period = urb_size * npackets;
+
+ /* Allocate space to store the number of URBs to be used */
+
+ dev->adev.transfer_buffer = kcalloc(num_urb,
+ sizeof(*dev->adev.transfer_buffer),
+ GFP_ATOMIC);
+ if (!dev->adev.transfer_buffer) {
+ return -ENOMEM;
+ }
+
+ dev->adev.urb = kcalloc(num_urb, sizeof(*dev->adev.urb), GFP_ATOMIC);
+ if (!dev->adev.urb) {
+ kfree(dev->adev.transfer_buffer);
+ return -ENOMEM;
+ }
+
+ /* Alloc memory for each URB and for each transfer buffer */
+ dev->adev.num_urb = num_urb;
+ for (i = 0; i < num_urb; i++) {
+ struct urb *urb;
+ int j, k;
+ void *buf;
+
+ urb = usb_alloc_urb(npackets, GFP_ATOMIC);
+ if (!urb) {
+ em28xx_errdev("usb_alloc_urb failed!\n");
+ em28xx_audio_free_urb(dev);
+ return -ENOMEM;
+ }
+ dev->adev.urb[i] = urb;
+
+ buf = usb_alloc_coherent(dev->udev, npackets * ep_size, GFP_ATOMIC,
+ &urb->transfer_dma);
+ if (!buf) {
+ em28xx_errdev("usb_alloc_coherent failed!\n");
+ em28xx_audio_free_urb(dev);
+ return -ENOMEM;
+ }
+ dev->adev.transfer_buffer[i] = buf;
+
+ urb->dev = dev->udev;
+ urb->context = dev;
+ urb->pipe = usb_rcvisocpipe(dev->udev, EM28XX_EP_AUDIO);
+ urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+ urb->transfer_buffer = buf;
+ urb->interval = interval;
+ urb->complete = em28xx_audio_isocirq;
+ urb->number_of_packets = npackets;
+ urb->transfer_buffer_length = ep_size * npackets;
+
+ for (j = k = 0; j < npackets; j++, k += ep_size) {
+ urb->iso_frame_desc[j].offset = k;
+ urb->iso_frame_desc[j].length = ep_size;
+ }
+ }
+
+ return 0;
+}
+
static int em28xx_audio_init(struct em28xx *dev)
{
struct em28xx_audio *adev = &dev->adev;
struct snd_pcm *pcm;
struct snd_card *card;
static int devnr;
- int err;
+ int err;
- if (!dev->has_alsa_audio || dev->audio_ifnum < 0) {
+ if (!dev->has_alsa_audio) {
/* This device does not support the extension (in this case
the device is expecting the snd-usb-audio module or
doesn't have analog audio support at all) */
return 0;
}
- printk(KERN_INFO "em28xx-audio.c: probing for em28xx Audio Vendor Class\n");
+ em28xx_info("Binding audio extension\n");
+
printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
"Rechberger\n");
- printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2007-2011 Mauro Carvalho Chehab\n");
+ printk(KERN_INFO
+ "em28xx-audio.c: Copyright (C) 2007-2014 Mauro Carvalho Chehab\n");
err = snd_card_create(index[devnr], "Em28xx Audio", THIS_MODULE, 0,
&card);
@@ -660,11 +906,12 @@ static int em28xx_audio_init(struct em28xx *dev)
return err;
spin_lock_init(&adev->slock);
+ adev->sndcard = card;
+ adev->udev = dev->udev;
+
err = snd_pcm_new(card, "Em28xx Audio", 0, 0, 1, &pcm);
- if (err < 0) {
- snd_card_free(card);
- return err;
- }
+ if (err < 0)
+ goto card_free;
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_em28xx_pcm_capture);
pcm->info_flags = 0;
@@ -694,15 +941,25 @@ static int em28xx_audio_init(struct em28xx *dev)
em28xx_cvol_new(card, dev, "Surround", AC97_SURROUND_MASTER);
}
+ err = em28xx_audio_urb_init(dev);
+ if (err)
+ goto card_free;
+
err = snd_card_register(card);
- if (err < 0) {
- snd_card_free(card);
- return err;
- }
- adev->sndcard = card;
- adev->udev = dev->udev;
+ if (err < 0)
+ goto urb_free;
+ em28xx_info("Audio extension successfully initialized\n");
return 0;
+
+urb_free:
+ em28xx_audio_free_urb(dev);
+
+card_free:
+ snd_card_free(card);
+ adev->sndcard = NULL;
+
+ return err;
}
static int em28xx_audio_fini(struct em28xx *dev)
@@ -717,7 +974,14 @@ static int em28xx_audio_fini(struct em28xx *dev)
return 0;
}
+ em28xx_info("Closing audio extension");
+
if (dev->adev.sndcard) {
+ snd_card_disconnect(dev->adev.sndcard);
+ flush_work(&dev->wq_trigger);
+
+ em28xx_audio_free_urb(dev);
+
snd_card_free(dev->adev.sndcard);
dev->adev.sndcard = NULL;
}
@@ -745,7 +1009,8 @@ static void __exit em28xx_alsa_unregister(void)
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Markus Rechberger <mrechberger@gmail.com>");
MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
-MODULE_DESCRIPTION("Em28xx Audio driver");
+MODULE_DESCRIPTION(DRIVER_DESC " - audio interface");
+MODULE_VERSION(EM28XX_VERSION);
module_init(em28xx_alsa_register);
module_exit(em28xx_alsa_unregister);
diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c
index d666741797d..c29f5c4e7b4 100644
--- a/drivers/media/usb/em28xx/em28xx-camera.c
+++ b/drivers/media/usb/em28xx/em28xx-camera.c
@@ -454,3 +454,4 @@ int em28xx_init_camera(struct em28xx *dev)
return ret;
}
+EXPORT_SYMBOL_GPL(em28xx_init_camera);
diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index a5196697627..4d97a76cc3b 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -36,7 +36,6 @@
#include <media/tvaudio.h>
#include <media/i2c-addr.h>
#include <media/tveeprom.h>
-#include <media/v4l2-clk.h>
#include <media/v4l2-common.h>
#include "em28xx.h"
@@ -67,7 +66,7 @@ MODULE_PARM_DESC(usb_xfer_mode,
/* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS - 1 */
-static unsigned long em28xx_devused;
+DECLARE_BITMAP(em28xx_devused, EM28XX_MAXBOARDS);
struct em28xx_hash_table {
unsigned long hash;
@@ -356,6 +355,28 @@ static struct em28xx_reg_seq c3tech_digital_duo_digital[] = {
{ -1, -1, -1, -1},
};
+/*
+ * 2013:0258 PCTV DVB-S2 Stick (461e)
+ * GPIO 0 = POWER_ON
+ * GPIO 1 = BOOST
+ * GPIO 2 = VUV_LNB (red LED)
+ * GPIO 3 = #EXT_12V
+ * GPIO 4 = INT_DEM
+ * GPIO 5 = INT_LNB
+ * GPIO 6 = #RESET_DEM
+ * GPIO 7 = P07_LED (green LED)
+ */
+static struct em28xx_reg_seq pctv_461e[] = {
+ {EM2874_R80_GPIO_P0_CTRL, 0x7f, 0xff, 0},
+ {0x0d, 0xff, 0xff, 0},
+ {EM2874_R80_GPIO_P0_CTRL, 0x3f, 0xff, 100}, /* reset demod */
+ {EM2874_R80_GPIO_P0_CTRL, 0x7f, 0xff, 200}, /* reset demod */
+ {0x0d, 0x42, 0xff, 0},
+ {EM2874_R80_GPIO_P0_CTRL, 0xeb, 0xff, 0},
+ {EM2874_R5F_TS_ENABLE, 0x84, 0x84, 0}, /* parallel? | null discard */
+ { -1, -1, -1, -1},
+};
+
#if 0
static struct em28xx_reg_seq hauppauge_930c_gpio[] = {
{EM2874_R80_GPIO_P0_CTRL, 0x6f, 0xff, 10},
@@ -412,6 +433,70 @@ static struct em28xx_reg_seq pctv_520e[] = {
{ -1, -1, -1, -1},
};
+/* 1ae7:9003/9004 SpeedLink Vicious And Devine Laplace webcam
+ * reg 0x80/0x84:
+ * GPIO_0: capturing LED, 0=on, 1=off
+ * GPIO_2: AV mute button, 0=pressed, 1=unpressed
+ * GPIO 3: illumination button, 0=pressed, 1=unpressed
+ * GPIO_6: illumination/flash LED, 0=on, 1=off
+ * reg 0x81/0x85:
+ * GPIO_7: snapshot button, 0=pressed, 1=unpressed
+ */
+static struct em28xx_reg_seq speedlink_vad_laplace_reg_seq[] = {
+ {EM2820_R08_GPIO_CTRL, 0xf7, 0xff, 10},
+ {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xb2, 10},
+ { -1, -1, -1, -1},
+};
+
+/*
+ * Button definitions
+ */
+static struct em28xx_button std_snapshot_button[] = {
+ {
+ .role = EM28XX_BUTTON_SNAPSHOT,
+ .reg_r = EM28XX_R0C_USBSUSP,
+ .reg_clearing = EM28XX_R0C_USBSUSP,
+ .mask = EM28XX_R0C_USBSUSP_SNAPSHOT,
+ .inverted = 0,
+ },
+ {-1, 0, 0, 0, 0},
+};
+
+static struct em28xx_button speedlink_vad_laplace_buttons[] = {
+ {
+ .role = EM28XX_BUTTON_SNAPSHOT,
+ .reg_r = EM2874_R85_GPIO_P1_STATE,
+ .mask = 0x80,
+ .inverted = 1,
+ },
+ {
+ .role = EM28XX_BUTTON_ILLUMINATION,
+ .reg_r = EM2874_R84_GPIO_P0_STATE,
+ .mask = 0x08,
+ .inverted = 1,
+ },
+ {-1, 0, 0, 0, 0},
+};
+
+/*
+ * LED definitions
+ */
+static struct em28xx_led speedlink_vad_laplace_leds[] = {
+ {
+ .role = EM28XX_LED_ANALOG_CAPTURING,
+ .gpio_reg = EM2874_R80_GPIO_P0_CTRL,
+ .gpio_mask = 0x01,
+ .inverted = 1,
+ },
+ {
+ .role = EM28XX_LED_ILLUMINATION,
+ .gpio_reg = EM2874_R80_GPIO_P0_CTRL,
+ .gpio_mask = 0x40,
+ .inverted = 1,
+ },
+ {-1, 0, 0, 0},
+};
+
/*
* Board definitions
*/
@@ -1391,7 +1476,7 @@ struct em28xx_board em28xx_boards[] = {
},
[EM2820_BOARD_PROLINK_PLAYTV_USB2] = {
.name = "SIIG AVTuner-PVR / Pixelview Prolink PlayTV USB 2.0",
- .has_snapshot_button = 1,
+ .buttons = std_snapshot_button,
.tda9887_conf = TDA9887_PRESENT,
.tuner_type = TUNER_YMEC_TVF_5533MF,
.decoder = EM28XX_SAA711X,
@@ -1413,7 +1498,7 @@ struct em28xx_board em28xx_boards[] = {
},
[EM2860_BOARD_SAA711X_REFERENCE_DESIGN] = {
.name = "EM2860/SAA711X Reference Design",
- .has_snapshot_button = 1,
+ .buttons = std_snapshot_button,
.tuner_type = TUNER_ABSENT,
.decoder = EM28XX_SAA711X,
.input = { {
@@ -2020,7 +2105,7 @@ struct em28xx_board em28xx_boards[] = {
},
/* 1b80:e1cc Delock 61959
* Empia EM2874B + Micronas DRX 3913KA2 + NXP TDA18271HDC2
- * mostly the same as MaxMedia UB-425-TC but different remote */
+ * mostly the same as MaxMedia UB-425-TC but different remote */
[EM2874_BOARD_DELOCK_61959] = {
.name = "Delock 61959",
.tuner_type = TUNER_ABSENT,
@@ -2043,7 +2128,38 @@ struct em28xx_board em28xx_boards[] = {
.tuner_gpio = default_tuner_gpio,
.def_i2c_bus = 1,
},
+ /* 1ae7:9003/9004 SpeedLink Vicious And Devine Laplace webcam
+ * Empia EM2765 + OmniVision OV2640 */
+ [EM2765_BOARD_SPEEDLINK_VAD_LAPLACE] = {
+ .name = "SpeedLink Vicious And Devine Laplace webcam",
+ .xclk = EM28XX_XCLK_FREQUENCY_24MHZ,
+ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE |
+ EM28XX_I2C_FREQ_100_KHZ,
+ .def_i2c_bus = 1,
+ .tuner_type = TUNER_ABSENT,
+ .is_webcam = 1,
+ .input = { {
+ .type = EM28XX_VMUX_COMPOSITE1,
+ .amux = EM28XX_AMUX_VIDEO,
+ .gpio = speedlink_vad_laplace_reg_seq,
+ } },
+ .buttons = speedlink_vad_laplace_buttons,
+ .leds = speedlink_vad_laplace_leds,
+ },
+ /* 2013:0258 PCTV DVB-S2 Stick (461e)
+ * Empia EM28178, Montage M88DS3103, Montage M88TS2022, Allegro A8293 */
+ [EM28178_BOARD_PCTV_461E] = {
+ .def_i2c_bus = 1,
+ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ,
+ .name = "PCTV DVB-S2 Stick (461e)",
+ .tuner_type = TUNER_ABSENT,
+ .tuner_gpio = pctv_461e,
+ .has_dvb = 1,
+ .ir_codes = RC_MAP_PINNACLE_PCTV_HD,
+ },
};
+EXPORT_SYMBOL_GPL(em28xx_boards);
+
const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
/* table of devices that work with this driver */
@@ -2208,6 +2324,12 @@ struct usb_device_id em28xx_id_table[] = {
.driver_info = EM2884_BOARD_PCTV_520E },
{ USB_DEVICE(0x1b80, 0xe1cc),
.driver_info = EM2874_BOARD_DELOCK_61959 },
+ { USB_DEVICE(0x1ae7, 0x9003),
+ .driver_info = EM2765_BOARD_SPEEDLINK_VAD_LAPLACE },
+ { USB_DEVICE(0x1ae7, 0x9004),
+ .driver_info = EM2765_BOARD_SPEEDLINK_VAD_LAPLACE },
+ { USB_DEVICE(0x2013, 0x0258),
+ .driver_info = EM28178_BOARD_PCTV_461E },
{ },
};
MODULE_DEVICE_TABLE(usb, em28xx_id_table);
@@ -2239,24 +2361,6 @@ static struct em28xx_hash_table em28xx_i2c_hash[] = {
};
/* NOTE: introduce a separate hash table for devices with 16 bit eeproms */
-/* I2C possible address to saa7115, tvp5150, msp3400, tvaudio */
-static unsigned short saa711x_addrs[] = {
- 0x4a >> 1, 0x48 >> 1, /* SAA7111, SAA7111A and SAA7113 */
- 0x42 >> 1, 0x40 >> 1, /* SAA7114, SAA7115 and SAA7118 */
- I2C_CLIENT_END };
-
-static unsigned short tvp5150_addrs[] = {
- 0xb8 >> 1,
- 0xba >> 1,
- I2C_CLIENT_END
-};
-
-static unsigned short msp3400_addrs[] = {
- 0x80 >> 1,
- 0x88 >> 1,
- I2C_CLIENT_END
-};
-
int em28xx_tuner_callback(void *ptr, int component, int command, int arg)
{
struct em28xx_i2c_bus *i2c_bus = ptr;
@@ -2408,113 +2512,6 @@ static void em28xx_pre_card_setup(struct em28xx *dev)
em28xx_set_mode(dev, EM28XX_SUSPEND);
}
-static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
-{
- memset(ctl, 0, sizeof(*ctl));
-
- ctl->fname = XC2028_DEFAULT_FIRMWARE;
- ctl->max_len = 64;
- ctl->mts = em28xx_boards[dev->model].mts_firmware;
-
- switch (dev->model) {
- case EM2880_BOARD_EMPIRE_DUAL_TV:
- case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
- case EM2882_BOARD_TERRATEC_HYBRID_XS:
- ctl->demod = XC3028_FE_ZARLINK456;
- break;
- case EM2880_BOARD_TERRATEC_HYBRID_XS:
- case EM2880_BOARD_TERRATEC_HYBRID_XS_FR:
- case EM2881_BOARD_PINNACLE_HYBRID_PRO:
- ctl->demod = XC3028_FE_ZARLINK456;
- break;
- case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
- case EM2882_BOARD_PINNACLE_HYBRID_PRO_330E:
- ctl->demod = XC3028_FE_DEFAULT;
- break;
- case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600:
- ctl->demod = XC3028_FE_DEFAULT;
- ctl->fname = XC3028L_DEFAULT_FIRMWARE;
- break;
- case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850:
- case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
- case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
- /* FIXME: Better to specify the needed IF */
- ctl->demod = XC3028_FE_DEFAULT;
- break;
- case EM2883_BOARD_KWORLD_HYBRID_330U:
- case EM2882_BOARD_DIKOM_DK300:
- case EM2882_BOARD_KWORLD_VS_DVBT:
- ctl->demod = XC3028_FE_CHINA;
- ctl->fname = XC2028_DEFAULT_FIRMWARE;
- break;
- case EM2882_BOARD_EVGA_INDTUBE:
- ctl->demod = XC3028_FE_CHINA;
- ctl->fname = XC3028L_DEFAULT_FIRMWARE;
- break;
- default:
- ctl->demod = XC3028_FE_OREN538;
- }
-}
-
-static void em28xx_tuner_setup(struct em28xx *dev)
-{
- struct tuner_setup tun_setup;
- struct v4l2_frequency f;
-
- if (dev->tuner_type == TUNER_ABSENT)
- return;
-
- memset(&tun_setup, 0, sizeof(tun_setup));
-
- tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
- tun_setup.tuner_callback = em28xx_tuner_callback;
-
- if (dev->board.radio.type) {
- tun_setup.type = dev->board.radio.type;
- tun_setup.addr = dev->board.radio_addr;
-
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup);
- }
-
- if ((dev->tuner_type != TUNER_ABSENT) && (dev->tuner_type)) {
- tun_setup.type = dev->tuner_type;
- tun_setup.addr = dev->tuner_addr;
-
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup);
- }
-
- if (dev->tda9887_conf) {
- struct v4l2_priv_tun_config tda9887_cfg;
-
- tda9887_cfg.tuner = TUNER_TDA9887;
- tda9887_cfg.priv = &dev->tda9887_conf;
-
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, &tda9887_cfg);
- }
-
- if (dev->tuner_type == TUNER_XC2028) {
- struct v4l2_priv_tun_config xc2028_cfg;
- struct xc2028_ctrl ctl;
-
- memset(&xc2028_cfg, 0, sizeof(xc2028_cfg));
- memset(&ctl, 0, sizeof(ctl));
-
- em28xx_setup_xc3028(dev, &ctl);
-
- xc2028_cfg.tuner = TUNER_XC2028;
- xc2028_cfg.priv = &ctl;
-
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, &xc2028_cfg);
- }
-
- /* configure tuner */
- f.tuner = 0;
- f.type = V4L2_TUNER_ANALOG_TV;
- f.frequency = 9076; /* just a magic number */
- dev->ctl_freq = f.frequency;
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
-}
-
static int em28xx_hint_board(struct em28xx *dev)
{
int i;
@@ -2768,57 +2765,56 @@ static void em28xx_card_setup(struct em28xx *dev)
/* Allow override tuner type by a module parameter */
if (tuner >= 0)
dev->tuner_type = tuner;
+}
- /* request some modules */
- if (dev->board.has_msp34xx)
- v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
- "msp3400", 0, msp3400_addrs);
-
- if (dev->board.decoder == EM28XX_SAA711X)
- v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
- "saa7115_auto", 0, saa711x_addrs);
-
- if (dev->board.decoder == EM28XX_TVP5150)
- v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
- "tvp5150", 0, tvp5150_addrs);
-
- if (dev->board.adecoder == EM28XX_TVAUDIO)
- v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
- "tvaudio", dev->board.tvaudio_addr, NULL);
-
- if (dev->board.tuner_type != TUNER_ABSENT) {
- int has_demod = (dev->tda9887_conf & TDA9887_PRESENT);
-
- if (dev->board.radio.type)
- v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
- "tuner", dev->board.radio_addr, NULL);
-
- if (has_demod)
- v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_adap[dev->def_i2c_bus], "tuner",
- 0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
- if (dev->tuner_addr == 0) {
- enum v4l2_i2c_tuner_type type =
- has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV;
- struct v4l2_subdev *sd;
-
- sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_adap[dev->def_i2c_bus], "tuner",
- 0, v4l2_i2c_tuner_addrs(type));
-
- if (sd)
- dev->tuner_addr = v4l2_i2c_subdev_addr(sd);
- } else {
- v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
- "tuner", dev->tuner_addr, NULL);
- }
- }
+void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
+{
+ memset(ctl, 0, sizeof(*ctl));
- em28xx_tuner_setup(dev);
+ ctl->fname = XC2028_DEFAULT_FIRMWARE;
+ ctl->max_len = 64;
+ ctl->mts = em28xx_boards[dev->model].mts_firmware;
- em28xx_init_camera(dev);
+ switch (dev->model) {
+ case EM2880_BOARD_EMPIRE_DUAL_TV:
+ case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
+ case EM2882_BOARD_TERRATEC_HYBRID_XS:
+ ctl->demod = XC3028_FE_ZARLINK456;
+ break;
+ case EM2880_BOARD_TERRATEC_HYBRID_XS:
+ case EM2880_BOARD_TERRATEC_HYBRID_XS_FR:
+ case EM2881_BOARD_PINNACLE_HYBRID_PRO:
+ ctl->demod = XC3028_FE_ZARLINK456;
+ break;
+ case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
+ case EM2882_BOARD_PINNACLE_HYBRID_PRO_330E:
+ ctl->demod = XC3028_FE_DEFAULT;
+ break;
+ case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600:
+ ctl->demod = XC3028_FE_DEFAULT;
+ ctl->fname = XC3028L_DEFAULT_FIRMWARE;
+ break;
+ case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850:
+ case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
+ case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
+ /* FIXME: Better to specify the needed IF */
+ ctl->demod = XC3028_FE_DEFAULT;
+ break;
+ case EM2883_BOARD_KWORLD_HYBRID_330U:
+ case EM2882_BOARD_DIKOM_DK300:
+ case EM2882_BOARD_KWORLD_VS_DVBT:
+ ctl->demod = XC3028_FE_CHINA;
+ ctl->fname = XC2028_DEFAULT_FIRMWARE;
+ break;
+ case EM2882_BOARD_EVGA_INDTUBE:
+ ctl->demod = XC3028_FE_CHINA;
+ ctl->fname = XC3028L_DEFAULT_FIRMWARE;
+ break;
+ default:
+ ctl->demod = XC3028_FE_OREN538;
+ }
}
-
+EXPORT_SYMBOL_GPL(em28xx_setup_xc3028);
static void request_module_async(struct work_struct *work)
{
@@ -2831,17 +2827,30 @@ static void request_module_async(struct work_struct *work)
* can be initialised right now. Otherwise, the module init
* code will do it.
*/
+
+ /*
+ * Devicdes with an audio-only interface also have a V4L/DVB/RC
+ * interface. Don't register extensions twice on those devices.
+ */
+ if (dev->is_audio_only) {
+#if defined(CONFIG_MODULES) && defined(MODULE)
+ request_module("em28xx-alsa");
+#endif
+ return;
+ }
+
em28xx_init_extension(dev);
#if defined(CONFIG_MODULES) && defined(MODULE)
+ if (dev->has_video)
+ request_module("em28xx-v4l");
if (dev->has_audio_class)
request_module("snd-usb-audio");
else if (dev->has_alsa_audio)
request_module("em28xx-alsa");
-
if (dev->board.has_dvb)
request_module("em28xx-dvb");
- if (dev->board.has_snapshot_button ||
+ if (dev->board.buttons ||
((dev->board.ir_codes || dev->board.has_ir_i2c) && !disable_ir))
request_module("em28xx-rc");
#endif /* CONFIG_MODULES */
@@ -2867,23 +2876,20 @@ void em28xx_release_resources(struct em28xx *dev)
{
/*FIXME: I2C IR should be disconnected */
- em28xx_release_analog_resources(dev);
+ mutex_lock(&dev->lock);
if (dev->def_i2c_bus)
em28xx_i2c_unregister(dev, 1);
em28xx_i2c_unregister(dev, 0);
- if (dev->clk)
- v4l2_clk_unregister_fixed(dev->clk);
-
- v4l2_ctrl_handler_free(&dev->ctrl_handler);
-
- v4l2_device_unregister(&dev->v4l2_dev);
usb_put_dev(dev->udev);
/* Mark device as unused */
- clear_bit(dev->devno, &em28xx_devused);
+ clear_bit(dev->devno, em28xx_devused);
+
+ mutex_unlock(&dev->lock);
};
+EXPORT_SYMBOL_GPL(em28xx_release_resources);
/*
* em28xx_init_dev()
@@ -2893,7 +2899,6 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
struct usb_interface *interface,
int minor)
{
- struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
int retval;
static const char *default_chip_name = "em28xx";
const char *chip_name = default_chip_name;
@@ -2968,6 +2973,11 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
dev->wait_after_write = 0;
dev->eeprom_addrwidth_16bit = 1;
break;
+ case CHIP_ID_EM28178:
+ chip_name = "em28178";
+ dev->wait_after_write = 0;
+ dev->eeprom_addrwidth_16bit = 1;
+ break;
case CHIP_ID_EM2883:
chip_name = "em2882/3";
dev->wait_after_write = 0;
@@ -2983,6 +2993,16 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
}
}
+ if (dev->chip_id == CHIP_ID_EM2870 ||
+ dev->chip_id == CHIP_ID_EM2874 ||
+ dev->chip_id == CHIP_ID_EM28174 ||
+ dev->chip_id == CHIP_ID_EM28178) {
+ /* Digital only device - don't load any alsa module */
+ dev->audio_mode.has_audio = false;
+ dev->has_audio_class = false;
+ dev->has_alsa_audio = false;
+ }
+
if (chip_name != default_chip_name)
printk(KERN_INFO DRIVER_NAME
": chip ID is %s\n", chip_name);
@@ -3015,15 +3035,6 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
}
}
- retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev);
- if (retval < 0) {
- em28xx_errdev("Call to v4l2_device_register() failed!\n");
- return retval;
- }
-
- v4l2_ctrl_handler_init(hdl, 8);
- dev->v4l2_dev.ctrl_handler = hdl;
-
rt_mutex_init(&dev->i2c_bus_lock);
/* register i2c bus 0 */
@@ -3034,7 +3045,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
if (retval < 0) {
em28xx_errdev("%s: em28xx_i2c_register bus 0 - error [%d]!\n",
__func__, retval);
- goto unregister_dev;
+ return retval;
}
/* register i2c bus 1 */
@@ -3048,88 +3059,17 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
if (retval < 0) {
em28xx_errdev("%s: em28xx_i2c_register bus 1 - error [%d]!\n",
__func__, retval);
- goto unregister_dev;
- }
- }
-
- /*
- * Default format, used for tvp5150 or saa711x output formats
- */
- dev->vinmode = 0x10;
- dev->vinctl = EM28XX_VINCTRL_INTERLACED |
- EM28XX_VINCTRL_CCIR656_ENABLE;
- /* Do board specific init and eeprom reading */
- em28xx_card_setup(dev);
+ em28xx_i2c_unregister(dev, 0);
- /* Configure audio */
- retval = em28xx_audio_setup(dev);
- if (retval < 0) {
- em28xx_errdev("%s: Error while setting audio - error [%d]!\n",
- __func__, retval);
- goto fail;
- }
- if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
- v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
- V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
- v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
- V4L2_CID_AUDIO_VOLUME, 0, 0x1f, 1, 0x1f);
- } else {
- /* install the em28xx notify callback */
- v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_MUTE),
- em28xx_ctrl_notify, dev);
- v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_VOLUME),
- em28xx_ctrl_notify, dev);
- }
-
- /* wake i2c devices */
- em28xx_wake_i2c(dev);
-
- /* init video dma queues */
- INIT_LIST_HEAD(&dev->vidq.active);
- INIT_LIST_HEAD(&dev->vbiq.active);
-
- if (dev->board.has_msp34xx) {
- /* Send a reset to other chips via gpio */
- retval = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xf7);
- if (retval < 0) {
- em28xx_errdev("%s: em28xx_write_reg - "
- "msp34xx(1) failed! error [%d]\n",
- __func__, retval);
- goto fail;
- }
- msleep(3);
-
- retval = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xff);
- if (retval < 0) {
- em28xx_errdev("%s: em28xx_write_reg - "
- "msp34xx(2) failed! error [%d]\n",
- __func__, retval);
- goto fail;
+ return retval;
}
- msleep(3);
- }
-
- retval = em28xx_register_analog_devices(dev);
- if (retval < 0) {
- goto fail;
}
- /* Save some power by putting tuner to sleep */
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
+ /* Do board specific init and eeprom reading */
+ em28xx_card_setup(dev);
return 0;
-
-fail:
- if (dev->def_i2c_bus)
- em28xx_i2c_unregister(dev, 1);
- em28xx_i2c_unregister(dev, 0);
- v4l2_ctrl_handler_free(&dev->ctrl_handler);
-
-unregister_dev:
- v4l2_device_unregister(&dev->v4l2_dev);
-
- return retval;
}
/* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
@@ -3154,7 +3094,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
/* Check to see next free device and mark as used */
do {
- nr = find_first_zero_bit(&em28xx_devused, EM28XX_MAXBOARDS);
+ nr = find_first_zero_bit(em28xx_devused, EM28XX_MAXBOARDS);
if (nr >= EM28XX_MAXBOARDS) {
/* No free device slots */
printk(DRIVER_NAME ": Supports only %i em28xx boards.\n",
@@ -3162,7 +3102,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
retval = -ENOMEM;
goto err_no_slot;
}
- } while (test_and_set_bit(nr, &em28xx_devused));
+ } while (test_and_set_bit(nr, em28xx_devused));
/* Don't register audio interfaces */
if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
@@ -3332,7 +3272,9 @@ static int em28xx_usb_probe(struct usb_interface *interface,
dev->alt = -1;
dev->is_audio_only = has_audio && !(has_video || has_dvb);
dev->has_alsa_audio = has_audio;
- dev->audio_ifnum = ifnum;
+ dev->audio_mode.has_audio = has_audio;
+ dev->has_video = has_video;
+ dev->ifnum = ifnum;
/* Checks if audio is provided by some interface */
for (i = 0; i < udev->config->desc.bNumInterfaces; i++) {
@@ -3369,15 +3311,11 @@ static int em28xx_usb_probe(struct usb_interface *interface,
/* save our data pointer in this interface device */
usb_set_intfdata(interface, dev);
- /* initialize videobuf2 stuff */
- em28xx_vb2_setup(dev);
-
/* allocate device struct */
mutex_init(&dev->lock);
- mutex_lock(&dev->lock);
retval = em28xx_init_dev(dev, udev, interface, nr);
if (retval) {
- goto unlock_and_free;
+ goto err_free;
}
if (usb_xfer_mode < 0) {
@@ -3402,26 +3340,6 @@ static int em28xx_usb_probe(struct usb_interface *interface,
em28xx_info("dvb set to %s mode.\n",
dev->dvb_xfer_bulk ? "bulk" : "isoc");
-
- /* pre-allocate DVB usb transfer buffers */
- if (dev->dvb_xfer_bulk) {
- retval = em28xx_alloc_urbs(dev, EM28XX_DIGITAL_MODE,
- dev->dvb_xfer_bulk,
- EM28XX_DVB_NUM_BUFS,
- 512,
- EM28XX_DVB_BULK_PACKET_MULTIPLIER);
- } else {
- retval = em28xx_alloc_urbs(dev, EM28XX_DIGITAL_MODE,
- dev->dvb_xfer_bulk,
- EM28XX_DVB_NUM_BUFS,
- dev->dvb_max_pkt_size_isoc,
- EM28XX_DVB_NUM_ISOC_PACKETS);
- }
- if (retval) {
- printk(DRIVER_NAME
- ": Failed to pre-allocate USB transfer buffers for DVB.\n");
- goto unlock_and_free;
- }
}
request_modules(dev);
@@ -3429,19 +3347,15 @@ static int em28xx_usb_probe(struct usb_interface *interface,
/* Should be the last thing to do, to avoid newer udev's to
open the device before fully initializing it
*/
- mutex_unlock(&dev->lock);
return 0;
-unlock_and_free:
- mutex_unlock(&dev->lock);
-
err_free:
kfree(dev->alt_max_pkt_size_isoc);
kfree(dev);
err:
- clear_bit(nr, &em28xx_devused);
+ clear_bit(nr, em28xx_devused);
err_no_slot:
usb_put_dev(udev);
@@ -3465,36 +3379,13 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
dev->disconnected = 1;
- if (dev->is_audio_only) {
- mutex_lock(&dev->lock);
- em28xx_close_extension(dev);
- mutex_unlock(&dev->lock);
- return;
- }
-
- em28xx_info("disconnecting %s\n", dev->vdev->name);
+ em28xx_info("Disconnecting %s\n", dev->name);
flush_request_modules(dev);
- mutex_lock(&dev->lock);
-
- v4l2_device_disconnect(&dev->v4l2_dev);
-
- if (dev->users) {
- em28xx_warn("device %s is open! Deregistration and memory deallocation are deferred on close.\n",
- video_device_node_name(dev->vdev));
-
- em28xx_uninit_usb_xfer(dev, EM28XX_ANALOG_MODE);
- em28xx_uninit_usb_xfer(dev, EM28XX_DIGITAL_MODE);
- }
-
em28xx_close_extension(dev);
- /* NOTE: must be called BEFORE the resources are released */
-
- if (!dev->users)
- em28xx_release_resources(dev);
- mutex_unlock(&dev->lock);
+ em28xx_release_resources(dev);
if (!dev->users) {
kfree(dev->alt_max_pkt_size_isoc);
diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
index fc157af5234..898fb9bd88a 100644
--- a/drivers/media/usb/em28xx/em28xx-core.c
+++ b/drivers/media/usb/em28xx/em28xx-core.c
@@ -23,6 +23,7 @@
*/
#include <linux/init.h>
+#include <linux/jiffies.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -33,6 +34,16 @@
#include "em28xx.h"
+#define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \
+ "Markus Rechberger <mrechberger@gmail.com>, " \
+ "Mauro Carvalho Chehab <mchehab@infradead.org>, " \
+ "Sascha Sommer <saschasommer@freenet.de>"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+MODULE_VERSION(EM28XX_VERSION);
+
/* #define ENABLE_DEBUG_ISOC_FRAMES */
static unsigned int core_debug;
@@ -53,14 +64,6 @@ MODULE_PARM_DESC(reg_debug, "enable debug messages [URB reg]");
printk(KERN_INFO "%s %s :"fmt, \
dev->name, __func__ , ##arg); } while (0)
-static int alt;
-module_param(alt, int, 0644);
-MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint");
-
-static unsigned int disable_vbi;
-module_param(disable_vbi, int, 0644);
-MODULE_PARM_DESC(disable_vbi, "disable vbi support");
-
/* FIXME */
#define em28xx_isocdbg(fmt, arg...) do {\
if (core_debug) \
@@ -226,21 +229,42 @@ int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
EXPORT_SYMBOL_GPL(em28xx_write_reg_bits);
/*
+ * em28xx_toggle_reg_bits()
+ * toggles/inverts the bits (specified by bitmask) of a register
+ */
+int em28xx_toggle_reg_bits(struct em28xx *dev, u16 reg, u8 bitmask)
+{
+ int oldval;
+ u8 newval;
+
+ oldval = em28xx_read_reg(dev, reg);
+ if (oldval < 0)
+ return oldval;
+
+ newval = (~oldval & bitmask) | (oldval & ~bitmask);
+
+ return em28xx_write_reg(dev, reg, newval);
+}
+EXPORT_SYMBOL_GPL(em28xx_toggle_reg_bits);
+
+/*
* em28xx_is_ac97_ready()
* Checks if ac97 is ready
*/
static int em28xx_is_ac97_ready(struct em28xx *dev)
{
- int ret, i;
+ unsigned long timeout = jiffies + msecs_to_jiffies(EM28XX_AC97_XFER_TIMEOUT);
+ int ret;
/* Wait up to 50 ms for AC97 command to complete */
- for (i = 0; i < 10; i++, msleep(5)) {
+ while (time_is_after_jiffies(timeout)) {
ret = em28xx_read_reg(dev, EM28XX_R43_AC97BUSY);
if (ret < 0)
return ret;
if (!(ret & 0x01))
return 0;
+ msleep(5);
}
em28xx_warn("AC97 command still being executed: not handled properly!\n");
@@ -482,16 +506,8 @@ int em28xx_audio_setup(struct em28xx *dev)
int vid1, vid2, feat, cfg;
u32 vid;
- if (dev->chip_id == CHIP_ID_EM2870 || dev->chip_id == CHIP_ID_EM2874
- || dev->chip_id == CHIP_ID_EM28174) {
- /* Digital only device - don't load any alsa module */
- dev->audio_mode.has_audio = false;
- dev->has_audio_class = false;
- dev->has_alsa_audio = false;
+ if (!dev->audio_mode.has_audio)
return 0;
- }
-
- dev->audio_mode.has_audio = true;
/* See how this device is configured */
cfg = em28xx_read_reg(dev, EM28XX_R00_CHIPCFG);
@@ -504,17 +520,19 @@ int em28xx_audio_setup(struct em28xx *dev)
dev->has_alsa_audio = false;
dev->audio_mode.has_audio = false;
return 0;
- } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
- EM28XX_CHIPCFG_I2S_3_SAMPRATES) {
- em28xx_info("I2S Audio (3 sample rates)\n");
- dev->audio_mode.i2s_3rates = 1;
- } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
- EM28XX_CHIPCFG_I2S_5_SAMPRATES) {
- em28xx_info("I2S Audio (5 sample rates)\n");
- dev->audio_mode.i2s_5rates = 1;
- }
-
- if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) != EM28XX_CHIPCFG_AC97) {
+ } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) != EM28XX_CHIPCFG_AC97) {
+ if (dev->chip_id < CHIP_ID_EM2860 &&
+ (cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
+ EM2820_CHIPCFG_I2S_1_SAMPRATE)
+ dev->audio_mode.i2s_samplerates = 1;
+ else if (dev->chip_id >= CHIP_ID_EM2860 &&
+ (cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
+ EM2860_CHIPCFG_I2S_5_SAMPRATES)
+ dev->audio_mode.i2s_samplerates = 5;
+ else
+ dev->audio_mode.i2s_samplerates = 3;
+ em28xx_info("I2S Audio (%d sample rate(s))\n",
+ dev->audio_mode.i2s_samplerates);
/* Skip the code that does AC97 vendor detection */
dev->audio_mode.ac97 = EM28XX_NO_AC97;
goto init_audio;
@@ -582,23 +600,21 @@ init_audio:
}
EXPORT_SYMBOL_GPL(em28xx_audio_setup);
-int em28xx_colorlevels_set_default(struct em28xx *dev)
+const struct em28xx_led *em28xx_find_led(struct em28xx *dev,
+ enum em28xx_led_role role)
{
- em28xx_write_reg(dev, EM28XX_R20_YGAIN, CONTRAST_DEFAULT);
- em28xx_write_reg(dev, EM28XX_R21_YOFFSET, BRIGHTNESS_DEFAULT);
- em28xx_write_reg(dev, EM28XX_R22_UVGAIN, SATURATION_DEFAULT);
- em28xx_write_reg(dev, EM28XX_R23_UOFFSET, BLUE_BALANCE_DEFAULT);
- em28xx_write_reg(dev, EM28XX_R24_VOFFSET, RED_BALANCE_DEFAULT);
- em28xx_write_reg(dev, EM28XX_R25_SHARPNESS, SHARPNESS_DEFAULT);
-
- em28xx_write_reg(dev, EM28XX_R14_GAMMA, 0x20);
- em28xx_write_reg(dev, EM28XX_R15_RGAIN, 0x20);
- em28xx_write_reg(dev, EM28XX_R16_GGAIN, 0x20);
- em28xx_write_reg(dev, EM28XX_R17_BGAIN, 0x20);
- em28xx_write_reg(dev, EM28XX_R18_ROFFSET, 0x00);
- em28xx_write_reg(dev, EM28XX_R19_GOFFSET, 0x00);
- return em28xx_write_reg(dev, EM28XX_R1A_BOFFSET, 0x00);
+ if (dev->board.leds) {
+ u8 k = 0;
+ while (dev->board.leds[k].role >= 0 &&
+ dev->board.leds[k].role < EM28XX_NUM_LED_ROLES) {
+ if (dev->board.leds[k].role == role)
+ return &dev->board.leds[k];
+ k++;
+ }
+ }
+ return NULL;
}
+EXPORT_SYMBOL_GPL(em28xx_find_led);
int em28xx_capture_start(struct em28xx *dev, int start)
{
@@ -606,271 +622,57 @@ int em28xx_capture_start(struct em28xx *dev, int start)
if (dev->chip_id == CHIP_ID_EM2874 ||
dev->chip_id == CHIP_ID_EM2884 ||
- dev->chip_id == CHIP_ID_EM28174) {
+ dev->chip_id == CHIP_ID_EM28174 ||
+ dev->chip_id == CHIP_ID_EM28178) {
/* The Transport Stream Enable Register moved in em2874 */
- if (!start) {
- rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE,
- 0x00,
- EM2874_TS1_CAPTURE_ENABLE);
- return rc;
- }
-
- /* Enable Transport Stream */
rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE,
- EM2874_TS1_CAPTURE_ENABLE,
+ start ?
+ EM2874_TS1_CAPTURE_ENABLE : 0x00,
EM2874_TS1_CAPTURE_ENABLE);
- return rc;
- }
-
-
- /* FIXME: which is the best order? */
- /* video registers are sampled by VREF */
- rc = em28xx_write_reg_bits(dev, EM28XX_R0C_USBSUSP,
- start ? 0x10 : 0x00, 0x10);
- if (rc < 0)
- return rc;
-
- if (!start) {
- /* disable video capture */
- rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x27);
- return rc;
- }
-
- if (dev->board.is_webcam)
- rc = em28xx_write_reg(dev, 0x13, 0x0c);
-
- /* enable video capture */
- rc = em28xx_write_reg(dev, 0x48, 0x00);
-
- if (dev->mode == EM28XX_ANALOG_MODE)
- rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x67);
- else
- rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x37);
-
- msleep(6);
-
- return rc;
-}
-
-int em28xx_vbi_supported(struct em28xx *dev)
-{
- /* Modprobe option to manually disable */
- if (disable_vbi == 1)
- return 0;
-
- if (dev->board.is_webcam)
- return 0;
-
- /* FIXME: check subdevices for VBI support */
-
- if (dev->chip_id == CHIP_ID_EM2860 ||
- dev->chip_id == CHIP_ID_EM2883)
- return 1;
-
- /* Version of em28xx that does not support VBI */
- return 0;
-}
-
-int em28xx_set_outfmt(struct em28xx *dev)
-{
- int ret;
- u8 fmt, vinctrl;
-
- fmt = dev->format->reg;
- if (!dev->is_em25xx)
- fmt |= 0x20;
- /*
- * NOTE: it's not clear if this is really needed !
- * The datasheets say bit 5 is a reserved bit and devices seem to work
- * fine without it. But the Windows driver sets it for em2710/50+em28xx
- * devices and we've always been setting it, too.
- *
- * em2765 (em25xx, em276x/7x/8x) devices do NOT work with this bit set,
- * it's likely used for an additional (compressed ?) format there.
- */
- ret = em28xx_write_reg(dev, EM28XX_R27_OUTFMT, fmt);
- if (ret < 0)
- return ret;
-
- ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, dev->vinmode);
- if (ret < 0)
- return ret;
-
- vinctrl = dev->vinctl;
- if (em28xx_vbi_supported(dev) == 1) {
- vinctrl |= EM28XX_VINCTRL_VBI_RAW;
- em28xx_write_reg(dev, EM28XX_R34_VBI_START_H, 0x00);
- em28xx_write_reg(dev, EM28XX_R36_VBI_WIDTH, dev->vbi_width/4);
- em28xx_write_reg(dev, EM28XX_R37_VBI_HEIGHT, dev->vbi_height);
- if (dev->norm & V4L2_STD_525_60) {
- /* NTSC */
- em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x09);
- } else if (dev->norm & V4L2_STD_625_50) {
- /* PAL */
- em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x07);
- }
- }
-
- return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, vinctrl);
-}
-
-static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax,
- u8 ymin, u8 ymax)
-{
- em28xx_coredbg("em28xx Scale: (%d,%d)-(%d,%d)\n",
- xmin, ymin, xmax, ymax);
-
- em28xx_write_regs(dev, EM28XX_R28_XMIN, &xmin, 1);
- em28xx_write_regs(dev, EM28XX_R29_XMAX, &xmax, 1);
- em28xx_write_regs(dev, EM28XX_R2A_YMIN, &ymin, 1);
- return em28xx_write_regs(dev, EM28XX_R2B_YMAX, &ymax, 1);
-}
-
-static void em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
- u16 width, u16 height)
-{
- u8 cwidth = width >> 2;
- u8 cheight = height >> 2;
- u8 overflow = (height >> 9 & 0x02) | (width >> 10 & 0x01);
- /* NOTE: size limit: 2047x1023 = 2MPix */
-
- em28xx_coredbg("capture area set to (%d,%d): %dx%d\n",
- hstart, vstart,
- ((overflow & 2) << 9 | cwidth << 2),
- ((overflow & 1) << 10 | cheight << 2));
-
- em28xx_write_regs(dev, EM28XX_R1C_HSTART, &hstart, 1);
- em28xx_write_regs(dev, EM28XX_R1D_VSTART, &vstart, 1);
- em28xx_write_regs(dev, EM28XX_R1E_CWIDTH, &cwidth, 1);
- em28xx_write_regs(dev, EM28XX_R1F_CHEIGHT, &cheight, 1);
- em28xx_write_regs(dev, EM28XX_R1B_OFLOW, &overflow, 1);
-
- /* FIXME: function/meaning of these registers ? */
- /* FIXME: align width+height to multiples of 4 ?! */
- if (dev->is_em25xx) {
- em28xx_write_reg(dev, 0x34, width >> 4);
- em28xx_write_reg(dev, 0x35, height >> 4);
- }
-}
-
-static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
-{
- u8 mode;
- /* the em2800 scaler only supports scaling down to 50% */
-
- if (dev->board.is_em2800) {
- mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00);
} else {
- u8 buf[2];
-
- buf[0] = h;
- buf[1] = h >> 8;
- em28xx_write_regs(dev, EM28XX_R30_HSCALELOW, (char *)buf, 2);
-
- buf[0] = v;
- buf[1] = v >> 8;
- em28xx_write_regs(dev, EM28XX_R32_VSCALELOW, (char *)buf, 2);
- /* it seems that both H and V scalers must be active
- to work correctly */
- mode = (h || v) ? 0x30 : 0x00;
- }
- return em28xx_write_reg_bits(dev, EM28XX_R26_COMPR, mode, 0x30);
-}
-
-/* FIXME: this only function read values from dev */
-int em28xx_resolution_set(struct em28xx *dev)
-{
- int width, height;
- width = norm_maxw(dev);
- height = norm_maxh(dev);
-
- /* Properly setup VBI */
- dev->vbi_width = 720;
- if (dev->norm & V4L2_STD_525_60)
- dev->vbi_height = 12;
- else
- dev->vbi_height = 18;
-
- em28xx_set_outfmt(dev);
+ /* FIXME: which is the best order? */
+ /* video registers are sampled by VREF */
+ rc = em28xx_write_reg_bits(dev, EM28XX_R0C_USBSUSP,
+ start ? 0x10 : 0x00, 0x10);
+ if (rc < 0)
+ return rc;
- em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2);
+ if (start) {
+ if (dev->board.is_webcam)
+ rc = em28xx_write_reg(dev, 0x13, 0x0c);
- /* If we don't set the start position to 2 in VBI mode, we end up
- with line 20/21 being YUYV encoded instead of being in 8-bit
- greyscale. The core of the issue is that line 21 (and line 23 for
- PAL WSS) are inside of active video region, and as a result they
- get the pixelformatting associated with that area. So by cropping
- it out, we end up with the same format as the rest of the VBI
- region */
- if (em28xx_vbi_supported(dev) == 1)
- em28xx_capture_area_set(dev, 0, 2, width, height);
- else
- em28xx_capture_area_set(dev, 0, 0, width, height);
+ /* Enable video capture */
+ rc = em28xx_write_reg(dev, 0x48, 0x00);
- return em28xx_scaler_set(dev, dev->hscale, dev->vscale);
-}
+ if (dev->mode == EM28XX_ANALOG_MODE)
+ rc = em28xx_write_reg(dev,
+ EM28XX_R12_VINENABLE, 0x67);
+ else
+ rc = em28xx_write_reg(dev,
+ EM28XX_R12_VINENABLE, 0x37);
-/* Set USB alternate setting for analog video */
-int em28xx_set_alternate(struct em28xx *dev)
-{
- int errCode;
- int i;
- unsigned int min_pkt_size = dev->width * 2 + 4;
-
- /* NOTE: for isoc transfers, only alt settings > 0 are allowed
- bulk transfers seem to work only with alt=0 ! */
- dev->alt = 0;
- if ((alt > 0) && (alt < dev->num_alt)) {
- em28xx_coredbg("alternate forced to %d\n", dev->alt);
- dev->alt = alt;
- goto set_alt;
+ msleep(6);
+ } else {
+ /* disable video capture */
+ rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x27);
+ }
}
- if (dev->analog_xfer_bulk)
- goto set_alt;
- /* When image size is bigger than a certain value,
- the frame size should be increased, otherwise, only
- green screen will be received.
- */
- if (dev->width * 2 * dev->height > 720 * 240 * 2)
- min_pkt_size *= 2;
+ if (rc < 0)
+ return rc;
- for (i = 0; i < dev->num_alt; i++) {
- /* stop when the selected alt setting offers enough bandwidth */
- if (dev->alt_max_pkt_size_isoc[i] >= min_pkt_size) {
- dev->alt = i;
- break;
- /* otherwise make sure that we end up with the maximum bandwidth
- because the min_pkt_size equation might be wrong...
- */
- } else if (dev->alt_max_pkt_size_isoc[i] >
- dev->alt_max_pkt_size_isoc[dev->alt])
- dev->alt = i;
+ /* Switch (explicitly controlled) analog capturing LED on/off */
+ if (dev->mode == EM28XX_ANALOG_MODE) {
+ const struct em28xx_led *led;
+ led = em28xx_find_led(dev, EM28XX_LED_ANALOG_CAPTURING);
+ if (led)
+ em28xx_write_reg_bits(dev, led->gpio_reg,
+ (!start ^ led->inverted) ?
+ ~led->gpio_mask : led->gpio_mask,
+ led->gpio_mask);
}
-set_alt:
- /* NOTE: for bulk transfers, we need to call usb_set_interface()
- * even if the previous settings were the same. Otherwise streaming
- * fails with all urbs having status = -EOVERFLOW ! */
- if (dev->analog_xfer_bulk) {
- dev->max_pkt_size = 512; /* USB 2.0 spec */
- dev->packet_multiplier = EM28XX_BULK_PACKET_MULTIPLIER;
- } else { /* isoc */
- em28xx_coredbg("minimum isoc packet size: %u (alt=%d)\n",
- min_pkt_size, dev->alt);
- dev->max_pkt_size =
- dev->alt_max_pkt_size_isoc[dev->alt];
- dev->packet_multiplier = EM28XX_NUM_ISOC_PACKETS;
- }
- em28xx_coredbg("setting alternate %d with wMaxPacketSize=%u\n",
- dev->alt, dev->max_pkt_size);
- errCode = usb_set_interface(dev->udev, 0, dev->alt);
- if (errCode < 0) {
- em28xx_errdev("cannot change alternate number to %d (error=%i)\n",
- dev->alt, errCode);
- return errCode;
- }
- return 0;
+ return rc;
}
int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio)
@@ -1238,18 +1040,6 @@ int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode,
EXPORT_SYMBOL_GPL(em28xx_init_usb_xfer);
/*
- * em28xx_wake_i2c()
- * configure i2c attached devices
- */
-void em28xx_wake_i2c(struct em28xx *dev)
-{
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, reset, 0);
- v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing,
- INPUT(dev->ctl_input)->vmux, 0, 0);
- v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
-}
-
-/*
* Device control list
*/
@@ -1272,7 +1062,7 @@ int em28xx_register_extension(struct em28xx_ops *ops)
ops->init(dev);
}
mutex_unlock(&em28xx_devlist_mutex);
- printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name);
+ printk(KERN_INFO "em28xx: Registered (%s) extension\n", ops->name);
return 0;
}
EXPORT_SYMBOL(em28xx_register_extension);
diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
index 344042bb845..a0a669e8136 100644
--- a/drivers/media/usb/em28xx/em28xx-dvb.c
+++ b/drivers/media/usb/em28xx/em28xx-dvb.c
@@ -51,10 +51,14 @@
#include "a8293.h"
#include "qt1010.h"
#include "mb86a20s.h"
+#include "m88ds3103.h"
+#include "m88ts2022.h"
-MODULE_DESCRIPTION("driver for em28xx based DVB cards");
MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(DRIVER_DESC " - digital TV interface");
+MODULE_VERSION(EM28XX_VERSION);
+
static unsigned int debug;
module_param(debug, int, 0644);
@@ -87,6 +91,7 @@ struct em28xx_dvb {
struct semaphore pll_mutex;
bool dont_attach_fe1;
int lna_gpio;
+ struct i2c_client *i2c_client_tuner;
};
@@ -198,7 +203,7 @@ static int em28xx_start_streaming(struct em28xx_dvb *dvb)
dvb_alt = dev->dvb_alt_isoc;
}
- usb_set_interface(dev->udev, 0, dvb_alt);
+ usb_set_interface(dev->udev, dev->ifnum, dvb_alt);
rc = em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
if (rc < 0)
return rc;
@@ -271,7 +276,7 @@ static int em28xx_stop_feed(struct dvb_demux_feed *feed)
static int em28xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire)
{
struct em28xx_i2c_bus *i2c_bus = fe->dvb->priv;
- struct em28xx *dev = i2c_bus->dev;
+ struct em28xx *dev = i2c_bus->dev;
if (acquire)
return em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
@@ -370,7 +375,6 @@ static struct drxk_config terratec_h5_drxk = {
.no_i2c_bridge = 1,
.microcode_name = "dvb-usb-terratec-h5-drxk.fw",
.qam_demod_parameter_count = 2,
- .load_firmware_sync = true,
};
static struct drxk_config hauppauge_930c_drxk = {
@@ -380,7 +384,6 @@ static struct drxk_config hauppauge_930c_drxk = {
.microcode_name = "dvb-usb-hauppauge-hvr930c-drxk.fw",
.chunk_size = 56,
.qam_demod_parameter_count = 2,
- .load_firmware_sync = true,
};
static struct drxk_config terratec_htc_stick_drxk = {
@@ -394,7 +397,6 @@ static struct drxk_config terratec_htc_stick_drxk = {
.antenna_dvbt = true,
/* The windows driver uses the same. This will disable LNA. */
.antenna_gpio = 0x6,
- .load_firmware_sync = true,
};
static struct drxk_config maxmedia_ub425_tc_drxk = {
@@ -403,7 +405,6 @@ static struct drxk_config maxmedia_ub425_tc_drxk = {
.no_i2c_bridge = 1,
.microcode_name = "dvb-demod-drxk-01.fw",
.chunk_size = 62,
- .load_firmware_sync = true,
.qam_demod_parameter_count = 2,
};
@@ -415,7 +416,6 @@ static struct drxk_config pctv_520e_drxk = {
.chunk_size = 58,
.antenna_dvbt = true, /* disable LNA */
.antenna_gpio = (1 << 2), /* disable LNA */
- .load_firmware_sync = true,
};
static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
@@ -808,6 +808,14 @@ static struct tda18271_config c3tech_duo_tda18271_config = {
.small_i2c = TDA18271_03_BYTE_CHUNK_INIT,
};
+static const struct m88ds3103_config pctv_461e_m88ds3103_config = {
+ .i2c_addr = 0x68,
+ .clock = 27000000,
+ .i2c_wr_max = 33,
+ .clock_out = 0,
+ .ts_mode = M88DS3103_TS_PARALLEL_16,
+ .agc = 0x99,
+};
/* ------------------------------------------------------------------ */
@@ -815,11 +823,16 @@ static int em28xx_attach_xc3028(u8 addr, struct em28xx *dev)
{
struct dvb_frontend *fe;
struct xc2028_config cfg;
+ struct xc2028_ctrl ctl;
memset(&cfg, 0, sizeof(cfg));
cfg.i2c_adap = &dev->i2c_adap[dev->def_i2c_bus];
cfg.i2c_addr = addr;
+ memset(&ctl, 0, sizeof(ctl));
+ em28xx_setup_xc3028(dev, &ctl);
+ cfg.ctrl = &ctl;
+
if (!dev->dvb->fe[0]) {
em28xx_errdev("/2: dvb frontend not attached. "
"Can't attach xc3028\n");
@@ -979,12 +992,18 @@ static int em28xx_dvb_init(struct em28xx *dev)
int result = 0, mfe_shared = 0;
struct em28xx_dvb *dvb;
+ if (dev->is_audio_only) {
+ /* Shouldn't initialize IR for this interface */
+ return 0;
+ }
+
if (!dev->board.has_dvb) {
/* This device does not support the extension */
- printk(KERN_INFO "em28xx_dvb: This device does not support the extension\n");
return 0;
}
+ em28xx_info("Binding DVB extension\n");
+
dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
if (dvb == NULL) {
@@ -994,6 +1013,27 @@ static int em28xx_dvb_init(struct em28xx *dev)
dev->dvb = dvb;
dvb->fe[0] = dvb->fe[1] = NULL;
+ /* pre-allocate DVB usb transfer buffers */
+ if (dev->dvb_xfer_bulk) {
+ result = em28xx_alloc_urbs(dev, EM28XX_DIGITAL_MODE,
+ dev->dvb_xfer_bulk,
+ EM28XX_DVB_NUM_BUFS,
+ 512,
+ EM28XX_DVB_BULK_PACKET_MULTIPLIER);
+ } else {
+ result = em28xx_alloc_urbs(dev, EM28XX_DIGITAL_MODE,
+ dev->dvb_xfer_bulk,
+ EM28XX_DVB_NUM_BUFS,
+ dev->dvb_max_pkt_size_isoc,
+ EM28XX_DVB_NUM_ISOC_PACKETS);
+ }
+ if (result) {
+ em28xx_errdev("em28xx_dvb: failed to pre-allocate USB transfer buffers for DVB.\n");
+ kfree(dvb);
+ dev->dvb = NULL;
+ return result;
+ }
+
mutex_lock(&dev->lock);
em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
/* init frontend */
@@ -1330,6 +1370,48 @@ static int em28xx_dvb_init(struct em28xx *dev)
goto out_free;
}
break;
+ case EM28178_BOARD_PCTV_461E:
+ {
+ /* demod I2C adapter */
+ struct i2c_adapter *i2c_adapter;
+ struct i2c_board_info info;
+ struct m88ts2022_config m88ts2022_config = {
+ .clock = 27000000,
+ };
+ memset(&info, 0, sizeof(struct i2c_board_info));
+
+ /* attach demod */
+ dvb->fe[0] = dvb_attach(m88ds3103_attach,
+ &pctv_461e_m88ds3103_config,
+ &dev->i2c_adap[dev->def_i2c_bus],
+ &i2c_adapter);
+ if (dvb->fe[0] == NULL) {
+ result = -ENODEV;
+ goto out_free;
+ }
+
+ /* attach tuner */
+ m88ts2022_config.fe = dvb->fe[0];
+ strlcpy(info.type, "m88ts2022", I2C_NAME_SIZE);
+ info.addr = 0x60;
+ info.platform_data = &m88ts2022_config;
+ request_module("m88ts2022");
+ dvb->i2c_client_tuner = i2c_new_device(i2c_adapter, &info);
+
+ /* delegate signal strength measurement to tuner */
+ dvb->fe[0]->ops.read_signal_strength =
+ dvb->fe[0]->ops.tuner_ops.get_rf_strength;
+
+ /* attach SEC */
+ if (!dvb_attach(a8293_attach, dvb->fe[0],
+ &dev->i2c_adap[dev->def_i2c_bus],
+ &em28xx_a8293_config)) {
+ dvb_frontend_detach(dvb->fe[0]);
+ result = -ENODEV;
+ goto out_free;
+ }
+ }
+ break;
default:
em28xx_errdev("/2: The frontend of your DVB/ATSC card"
" isn't supported yet\n");
@@ -1354,7 +1436,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
/* MFE lock */
dvb->adapter.mfe_shared = mfe_shared;
- em28xx_info("Successfully loaded em28xx-dvb\n");
+ em28xx_info("DVB extension successfully initialized\n");
ret:
em28xx_set_mode(dev, EM28XX_SUSPEND);
mutex_unlock(&dev->lock);
@@ -1375,14 +1457,23 @@ static inline void prevent_sleep(struct dvb_frontend_ops *ops)
static int em28xx_dvb_fini(struct em28xx *dev)
{
+ if (dev->is_audio_only) {
+ /* Shouldn't initialize IR for this interface */
+ return 0;
+ }
+
if (!dev->board.has_dvb) {
/* This device does not support the extension */
return 0;
}
+ em28xx_info("Closing DVB extension");
+
if (dev->dvb) {
struct em28xx_dvb *dvb = dev->dvb;
+ em28xx_uninit_usb_xfer(dev, EM28XX_DIGITAL_MODE);
+
if (dev->disconnected) {
/* We cannot tell the device to sleep
* once it has been unplugged. */
@@ -1392,6 +1483,7 @@ static int em28xx_dvb_fini(struct em28xx *dev)
prevent_sleep(&dvb->fe[1]->ops);
}
+ i2c_release_client(dvb->i2c_client_tuner);
em28xx_unregister_dvb(dvb);
kfree(dvb);
dev->dvb = NULL;
diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c
index c4ff9739a7a..7e1724076ac 100644
--- a/drivers/media/usb/em28xx/em28xx-i2c.c
+++ b/drivers/media/usb/em28xx/em28xx-i2c.c
@@ -26,6 +26,7 @@
#include <linux/kernel.h>
#include <linux/usb.h>
#include <linux/i2c.h>
+#include <linux/jiffies.h>
#include "em28xx.h"
#include "tuner-xc2028.h"
@@ -40,7 +41,7 @@ MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
static unsigned int i2c_debug;
module_param(i2c_debug, int, 0644);
-MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
+MODULE_PARM_DESC(i2c_debug, "i2c debug message level (1: normal debug, 2: show I2C transfers)");
/*
* em2800_i2c_send_bytes()
@@ -48,8 +49,8 @@ MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
*/
static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
{
+ unsigned long timeout = jiffies + msecs_to_jiffies(EM28XX_I2C_XFER_TIMEOUT);
int ret;
- int write_timeout;
u8 b2[6];
if (len < 1 || len > 4)
@@ -74,22 +75,26 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
return (ret < 0) ? ret : -EIO;
}
/* wait for completion */
- for (write_timeout = EM2800_I2C_XFER_TIMEOUT; write_timeout > 0;
- write_timeout -= 5) {
+ while (time_is_after_jiffies(timeout)) {
ret = dev->em28xx_read_reg(dev, 0x05);
- if (ret == 0x80 + len - 1) {
+ if (ret == 0x80 + len - 1)
return len;
- } else if (ret == 0x94 + len - 1) {
- return -ENODEV;
- } else if (ret < 0) {
+ if (ret == 0x94 + len - 1) {
+ if (i2c_debug == 1)
+ em28xx_warn("R05 returned 0x%02x: I2C timeout",
+ ret);
+ return -ENXIO;
+ }
+ if (ret < 0) {
em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
ret);
return ret;
}
msleep(5);
}
- em28xx_warn("write to i2c device at 0x%x timed out\n", addr);
- return -EIO;
+ if (i2c_debug)
+ em28xx_warn("write to i2c device at 0x%x timed out\n", addr);
+ return -ETIMEDOUT;
}
/*
@@ -98,9 +103,9 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
*/
static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
{
+ unsigned long timeout = jiffies + msecs_to_jiffies(EM28XX_I2C_XFER_TIMEOUT);
u8 buf2[4];
int ret;
- int read_timeout;
int i;
if (len < 1 || len > 4)
@@ -117,22 +122,28 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
}
/* wait for completion */
- for (read_timeout = EM2800_I2C_XFER_TIMEOUT; read_timeout > 0;
- read_timeout -= 5) {
+ while (time_is_after_jiffies(timeout)) {
ret = dev->em28xx_read_reg(dev, 0x05);
- if (ret == 0x84 + len - 1) {
+ if (ret == 0x84 + len - 1)
break;
- } else if (ret == 0x94 + len - 1) {
- return -ENODEV;
- } else if (ret < 0) {
+ if (ret == 0x94 + len - 1) {
+ if (i2c_debug == 1)
+ em28xx_warn("R05 returned 0x%02x: I2C timeout",
+ ret);
+ return -ENXIO;
+ }
+ if (ret < 0) {
em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
ret);
return ret;
}
msleep(5);
}
- if (ret != 0x84 + len - 1)
- em28xx_warn("read from i2c device at 0x%x timed out\n", addr);
+ if (ret != 0x84 + len - 1) {
+ if (i2c_debug)
+ em28xx_warn("read from i2c device at 0x%x timed out\n",
+ addr);
+ }
/* get the received message */
ret = dev->em28xx_read_reg_req_len(dev, 0x00, 4-len, buf2, len);
@@ -168,7 +179,8 @@ static int em2800_i2c_check_for_device(struct em28xx *dev, u8 addr)
static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
u16 len, int stop)
{
- int write_timeout, ret;
+ unsigned long timeout = jiffies + msecs_to_jiffies(EM28XX_I2C_XFER_TIMEOUT);
+ int ret;
if (len < 1 || len > 64)
return -EOPNOTSUPP;
@@ -191,16 +203,19 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
}
}
- /* Check success of the i2c operation */
- for (write_timeout = EM2800_I2C_XFER_TIMEOUT; write_timeout > 0;
- write_timeout -= 5) {
+ /* wait for completion */
+ while (time_is_after_jiffies(timeout)) {
ret = dev->em28xx_read_reg(dev, 0x05);
- if (ret == 0) { /* success */
+ if (ret == 0) /* success */
return len;
- } else if (ret == 0x10) {
- return -ENODEV;
- } else if (ret < 0) {
- em28xx_warn("failed to read i2c transfer status from bridge (error=%i)\n",
+ if (ret == 0x10) {
+ if (i2c_debug == 1)
+ em28xx_warn("I2C transfer timeout on writing to addr 0x%02x",
+ addr);
+ return -ENXIO;
+ }
+ if (ret < 0) {
+ em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
ret);
return ret;
}
@@ -211,8 +226,10 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
* (even with high payload) ...
*/
}
- em28xx_warn("write to i2c device at 0x%x timed out\n", addr);
- return -EIO;
+ if (i2c_debug)
+ em28xx_warn("write to i2c device at 0x%x timed out (status=%i)\n",
+ addr, ret);
+ return -ETIMEDOUT;
}
/*
@@ -242,26 +259,28 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len)
* bytes if we are on bus B AND there was no write attempt to the
* specified slave address before AND no device is present at the
* requested slave address.
- * Anyway, the next check will fail with -ENODEV in this case, so avoid
+ * Anyway, the next check will fail with -ENXIO in this case, so avoid
* spamming the system log on device probing and do nothing here.
*/
/* Check success of the i2c operation */
ret = dev->em28xx_read_reg(dev, 0x05);
+ if (ret == 0) /* success */
+ return len;
if (ret < 0) {
- em28xx_warn("failed to read i2c transfer status from bridge (error=%i)\n",
+ em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
ret);
return ret;
}
- if (ret > 0) {
- if (ret == 0x10) {
- return -ENODEV;
- } else {
- em28xx_warn("unknown i2c error (status=%i)\n", ret);
- return -EIO;
- }
+ if (ret == 0x10) {
+ if (i2c_debug == 1)
+ em28xx_warn("I2C transfer timeout on writing to addr 0x%02x",
+ addr);
+ return -ENXIO;
}
- return len;
+
+ em28xx_warn("unknown i2c error (status=%i)\n", ret);
+ return -ETIMEDOUT;
}
/*
@@ -316,8 +335,12 @@ static int em25xx_bus_B_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
*/
if (!ret)
return len;
- else if (ret > 0)
- return -ENODEV;
+ else if (ret > 0) {
+ if (i2c_debug == 1)
+ em28xx_warn("Bus B R08 returned 0x%02x: I2C timeout",
+ ret);
+ return -ENXIO;
+ }
return ret;
/*
@@ -355,7 +378,7 @@ static int em25xx_bus_B_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf,
* bytes if we are on bus B AND there was no write attempt to the
* specified slave address before AND no device is present at the
* requested slave address.
- * Anyway, the next check will fail with -ENODEV in this case, so avoid
+ * Anyway, the next check will fail with -ENXIO in this case, so avoid
* spamming the system log on device probing and do nothing here.
*/
@@ -367,8 +390,12 @@ static int em25xx_bus_B_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf,
*/
if (!ret)
return len;
- else if (ret > 0)
- return -ENODEV;
+ else if (ret > 0) {
+ if (i2c_debug == 1)
+ em28xx_warn("Bus B R08 returned 0x%02x: I2C timeout",
+ ret);
+ return -ENXIO;
+ }
return ret;
/*
@@ -409,10 +436,6 @@ static inline int i2c_check_for_device(struct em28xx_i2c_bus *i2c_bus, u16 addr)
rc = em2800_i2c_check_for_device(dev, addr);
else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B)
rc = em25xx_bus_B_check_for_device(dev, addr);
- if (rc == -ENODEV) {
- if (i2c_debug)
- printk(" no device\n");
- }
return rc;
}
@@ -421,7 +444,7 @@ static inline int i2c_recv_bytes(struct em28xx_i2c_bus *i2c_bus,
{
struct em28xx *dev = i2c_bus->dev;
u16 addr = msg.addr << 1;
- int byte, rc = -EOPNOTSUPP;
+ int rc = -EOPNOTSUPP;
if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX)
rc = em28xx_i2c_recv_bytes(dev, addr, msg.buf, msg.len);
@@ -429,10 +452,6 @@ static inline int i2c_recv_bytes(struct em28xx_i2c_bus *i2c_bus,
rc = em2800_i2c_recv_bytes(dev, addr, msg.buf, msg.len);
else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B)
rc = em25xx_bus_B_recv_bytes(dev, addr, msg.buf, msg.len);
- if (i2c_debug) {
- for (byte = 0; byte < msg.len; byte++)
- printk(" %02x", msg.buf[byte]);
- }
return rc;
}
@@ -441,12 +460,8 @@ static inline int i2c_send_bytes(struct em28xx_i2c_bus *i2c_bus,
{
struct em28xx *dev = i2c_bus->dev;
u16 addr = msg.addr << 1;
- int byte, rc = -EOPNOTSUPP;
+ int rc = -EOPNOTSUPP;
- if (i2c_debug) {
- for (byte = 0; byte < msg.len; byte++)
- printk(" %02x", msg.buf[byte]);
- }
if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX)
rc = em28xx_i2c_send_bytes(dev, addr, msg.buf, msg.len, stop);
else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM2800)
@@ -491,33 +506,53 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
}
for (i = 0; i < num; i++) {
addr = msgs[i].addr << 1;
- if (i2c_debug)
+ if (i2c_debug > 1)
printk(KERN_DEBUG "%s at %s: %s %s addr=%02x len=%d:",
dev->name, __func__ ,
(msgs[i].flags & I2C_M_RD) ? "read" : "write",
i == num - 1 ? "stop" : "nonstop",
addr, msgs[i].len);
- if (!msgs[i].len) { /* no len: check only for device presence */
+ if (!msgs[i].len) {
+ /*
+ * no len: check only for device presence
+ * This code is only called during device probe.
+ */
rc = i2c_check_for_device(i2c_bus, addr);
- if (rc == -ENODEV) {
+ if (rc < 0) {
+ if (rc == -ENXIO) {
+ if (i2c_debug > 1)
+ printk(KERN_CONT " no device\n");
+ rc = -ENODEV;
+ } else {
+ if (i2c_debug > 1)
+ printk(KERN_CONT " ERROR: %i\n", rc);
+ }
rt_mutex_unlock(&dev->i2c_bus_lock);
return rc;
}
} else if (msgs[i].flags & I2C_M_RD) {
/* read bytes */
rc = i2c_recv_bytes(i2c_bus, msgs[i]);
+
+ if (i2c_debug > 1 && rc >= 0)
+ printk(KERN_CONT " %*ph",
+ msgs[i].len, msgs[i].buf);
} else {
+ if (i2c_debug > 1)
+ printk(KERN_CONT " %*ph",
+ msgs[i].len, msgs[i].buf);
+
/* write bytes */
rc = i2c_send_bytes(i2c_bus, msgs[i], i == num - 1);
}
if (rc < 0) {
- if (i2c_debug)
- printk(" ERROR: %i\n", rc);
+ if (i2c_debug > 1)
+ printk(KERN_CONT " ERROR: %i\n", rc);
rt_mutex_unlock(&dev->i2c_bus_lock);
return rc;
}
- if (i2c_debug)
- printk("\n");
+ if (i2c_debug > 1)
+ printk(KERN_CONT "\n");
}
rt_mutex_unlock(&dev->i2c_bus_lock);
@@ -600,7 +635,7 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus,
* calculation and returned device dataset. Simplifies the code a lot,
* but we might have to deal with multiple sizes in the future !
*/
- int i, err;
+ int err;
struct em28xx_eeprom *dev_config;
u8 buf, *data;
@@ -631,20 +666,14 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus,
goto error;
}
- /* Display eeprom content */
- for (i = 0; i < len; i++) {
- if (0 == (i % 16)) {
- if (dev->eeprom_addrwidth_16bit)
- em28xx_info("i2c eeprom %04x:", i);
- else
- em28xx_info("i2c eeprom %02x:", i);
- }
- printk(" %02x", data[i]);
- if (15 == (i % 16))
- printk("\n");
+ if (i2c_debug) {
+ /* Display eeprom content */
+ print_hex_dump(KERN_INFO, "eeprom ", DUMP_PREFIX_OFFSET,
+ 16, 1, data, len, true);
+
+ if (dev->eeprom_addrwidth_16bit)
+ em28xx_info("eeprom %06x: ... (skipped)\n", 256);
}
- if (dev->eeprom_addrwidth_16bit)
- em28xx_info("i2c eeprom %04x: ... (skipped)\n", i);
if (dev->eeprom_addrwidth_16bit &&
data[0] == 0x26 && data[3] == 0x00) {
@@ -736,10 +765,16 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus,
em28xx_info("\tAC97 audio (5 sample rates)\n");
break;
case 2:
- em28xx_info("\tI2S audio, sample rate=32k\n");
+ if (dev->chip_id < CHIP_ID_EM2860)
+ em28xx_info("\tI2S audio, sample rate=32k\n");
+ else
+ em28xx_info("\tI2S audio, 3 sample rates\n");
break;
case 3:
- em28xx_info("\tI2S audio, 3 sample rates\n");
+ if (dev->chip_id < CHIP_ID_EM2860)
+ em28xx_info("\tI2S audio, 3 sample rates\n");
+ else
+ em28xx_info("\tI2S audio, 5 sample rates\n");
break;
}
diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
index ea181e4b68c..18f65d89d4b 100644
--- a/drivers/media/usb/em28xx/em28xx-input.c
+++ b/drivers/media/usb/em28xx/em28xx-input.c
@@ -30,8 +30,9 @@
#include "em28xx.h"
-#define EM28XX_SNAPSHOT_KEY KEY_CAMERA
-#define EM28XX_SBUTTON_QUERY_INTERVAL 500
+#define EM28XX_SNAPSHOT_KEY KEY_CAMERA
+#define EM28XX_BUTTONS_DEBOUNCED_QUERY_INTERVAL 500 /* [ms] */
+#define EM28XX_BUTTONS_VOLATILE_QUERY_INTERVAL 100 /* [ms] */
static unsigned int ir_debug;
module_param(ir_debug, int, 0644);
@@ -442,6 +443,7 @@ static int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 *rc_type)
case CHIP_ID_EM2884:
case CHIP_ID_EM2874:
case CHIP_ID_EM28174:
+ case CHIP_ID_EM28178:
return em2874_ir_change_protocol(rc_dev, rc_type);
default:
printk("Unrecognized em28xx chip id 0x%02x: IR not supported\n",
@@ -470,54 +472,98 @@ static int em28xx_probe_i2c_ir(struct em28xx *dev)
}
/**********************************************************
- Handle Webcam snapshot button
+ Handle buttons
**********************************************************/
-static void em28xx_query_sbutton(struct work_struct *work)
+static void em28xx_query_buttons(struct work_struct *work)
{
- /* Poll the register and see if the button is depressed */
struct em28xx *dev =
- container_of(work, struct em28xx, sbutton_query_work.work);
- int ret;
-
- ret = em28xx_read_reg(dev, EM28XX_R0C_USBSUSP);
-
- if (ret & EM28XX_R0C_USBSUSP_SNAPSHOT) {
- u8 cleared;
- /* Button is depressed, clear the register */
- cleared = ((u8) ret) & ~EM28XX_R0C_USBSUSP_SNAPSHOT;
- em28xx_write_regs(dev, EM28XX_R0C_USBSUSP, &cleared, 1);
-
- /* Not emulate the keypress */
- input_report_key(dev->sbutton_input_dev, EM28XX_SNAPSHOT_KEY,
- 1);
- /* Now unpress the key */
- input_report_key(dev->sbutton_input_dev, EM28XX_SNAPSHOT_KEY,
- 0);
+ container_of(work, struct em28xx, buttons_query_work.work);
+ u8 i, j;
+ int regval;
+ bool is_pressed, was_pressed;
+ const struct em28xx_led *led;
+
+ /* Poll and evaluate all addresses */
+ for (i = 0; i < dev->num_button_polling_addresses; i++) {
+ /* Read value from register */
+ regval = em28xx_read_reg(dev, dev->button_polling_addresses[i]);
+ if (regval < 0)
+ continue;
+ /* Check states of the buttons and act */
+ j = 0;
+ while (dev->board.buttons[j].role >= 0 &&
+ dev->board.buttons[j].role < EM28XX_NUM_BUTTON_ROLES) {
+ struct em28xx_button *button = &dev->board.buttons[j];
+ /* Check if button uses the current address */
+ if (button->reg_r != dev->button_polling_addresses[i]) {
+ j++;
+ continue;
+ }
+ /* Determine if button is and was pressed last time */
+ is_pressed = regval & button->mask;
+ was_pressed = dev->button_polling_last_values[i]
+ & button->mask;
+ if (button->inverted) {
+ is_pressed = !is_pressed;
+ was_pressed = !was_pressed;
+ }
+ /* Clear button state (if needed) */
+ if (is_pressed && button->reg_clearing)
+ em28xx_write_reg(dev, button->reg_clearing,
+ (~regval & button->mask)
+ | (regval & ~button->mask));
+ /* Handle button state */
+ if (!is_pressed || was_pressed) {
+ j++;
+ continue;
+ }
+ switch (button->role) {
+ case EM28XX_BUTTON_SNAPSHOT:
+ /* Emulate the keypress */
+ input_report_key(dev->sbutton_input_dev,
+ EM28XX_SNAPSHOT_KEY, 1);
+ /* Unpress the key */
+ input_report_key(dev->sbutton_input_dev,
+ EM28XX_SNAPSHOT_KEY, 0);
+ break;
+ case EM28XX_BUTTON_ILLUMINATION:
+ led = em28xx_find_led(dev,
+ EM28XX_LED_ILLUMINATION);
+ /* Switch illumination LED on/off */
+ if (led)
+ em28xx_toggle_reg_bits(dev,
+ led->gpio_reg,
+ led->gpio_mask);
+ break;
+ default:
+ WARN_ONCE(1, "BUG: unhandled button role.");
+ }
+ /* Next button */
+ j++;
+ }
+ /* Save current value for comparison during the next polling */
+ dev->button_polling_last_values[i] = regval;
}
-
/* Schedule next poll */
- schedule_delayed_work(&dev->sbutton_query_work,
- msecs_to_jiffies(EM28XX_SBUTTON_QUERY_INTERVAL));
+ schedule_delayed_work(&dev->buttons_query_work,
+ msecs_to_jiffies(dev->button_polling_interval));
}
-static void em28xx_register_snapshot_button(struct em28xx *dev)
+static int em28xx_register_snapshot_button(struct em28xx *dev)
{
struct input_dev *input_dev;
int err;
em28xx_info("Registering snapshot button...\n");
input_dev = input_allocate_device();
- if (!input_dev) {
- em28xx_errdev("input_allocate_device failed\n");
- return;
- }
+ if (!input_dev)
+ return -ENOMEM;
usb_make_path(dev->udev, dev->snapshot_button_path,
sizeof(dev->snapshot_button_path));
strlcat(dev->snapshot_button_path, "/sbutton",
sizeof(dev->snapshot_button_path));
- INIT_DELAYED_WORK(&dev->sbutton_query_work, em28xx_query_sbutton);
input_dev->name = "em28xx snapshot button";
input_dev->phys = dev->snapshot_button_path;
@@ -535,25 +581,86 @@ static void em28xx_register_snapshot_button(struct em28xx *dev)
if (err) {
em28xx_errdev("input_register_device failed\n");
input_free_device(input_dev);
- return;
+ return err;
}
dev->sbutton_input_dev = input_dev;
- schedule_delayed_work(&dev->sbutton_query_work,
- msecs_to_jiffies(EM28XX_SBUTTON_QUERY_INTERVAL));
- return;
+ return 0;
+}
+static void em28xx_init_buttons(struct em28xx *dev)
+{
+ u8 i = 0, j = 0;
+ bool addr_new = 0;
+
+ dev->button_polling_interval = EM28XX_BUTTONS_DEBOUNCED_QUERY_INTERVAL;
+ while (dev->board.buttons[i].role >= 0 &&
+ dev->board.buttons[i].role < EM28XX_NUM_BUTTON_ROLES) {
+ struct em28xx_button *button = &dev->board.buttons[i];
+ /* Check if polling address is already on the list */
+ addr_new = 1;
+ for (j = 0; j < dev->num_button_polling_addresses; j++) {
+ if (button->reg_r == dev->button_polling_addresses[j]) {
+ addr_new = 0;
+ break;
+ }
+ }
+ /* Check if max. number of polling addresses is exceeded */
+ if (addr_new && dev->num_button_polling_addresses
+ >= EM28XX_NUM_BUTTON_ADDRESSES_MAX) {
+ WARN_ONCE(1, "BUG: maximum number of button polling addresses exceeded.");
+ goto next_button;
+ }
+ /* Button role specific checks and actions */
+ if (button->role == EM28XX_BUTTON_SNAPSHOT) {
+ /* Register input device */
+ if (em28xx_register_snapshot_button(dev) < 0)
+ goto next_button;
+ } else if (button->role == EM28XX_BUTTON_ILLUMINATION) {
+ /* Check sanity */
+ if (!em28xx_find_led(dev, EM28XX_LED_ILLUMINATION)) {
+ em28xx_errdev("BUG: illumination button defined, but no illumination LED.\n");
+ goto next_button;
+ }
+ }
+ /* Add read address to list of polling addresses */
+ if (addr_new) {
+ unsigned int index = dev->num_button_polling_addresses;
+ dev->button_polling_addresses[index] = button->reg_r;
+ dev->num_button_polling_addresses++;
+ }
+ /* Reduce polling interval if necessary */
+ if (!button->reg_clearing)
+ dev->button_polling_interval =
+ EM28XX_BUTTONS_VOLATILE_QUERY_INTERVAL;
+next_button:
+ /* Next button */
+ i++;
+ }
+
+ /* Start polling */
+ if (dev->num_button_polling_addresses) {
+ memset(dev->button_polling_last_values, 0,
+ EM28XX_NUM_BUTTON_ADDRESSES_MAX);
+ INIT_DELAYED_WORK(&dev->buttons_query_work,
+ em28xx_query_buttons);
+ schedule_delayed_work(&dev->buttons_query_work,
+ msecs_to_jiffies(dev->button_polling_interval));
+ }
}
-static void em28xx_deregister_snapshot_button(struct em28xx *dev)
+static void em28xx_shutdown_buttons(struct em28xx *dev)
{
+ /* Cancel polling */
+ cancel_delayed_work_sync(&dev->buttons_query_work);
+ /* Clear polling addresses list */
+ dev->num_button_polling_addresses = 0;
+ /* Deregister input devices */
if (dev->sbutton_input_dev != NULL) {
em28xx_info("Deregistering snapshot button\n");
- cancel_delayed_work_sync(&dev->sbutton_query_work);
input_unregister_device(dev->sbutton_input_dev);
dev->sbutton_input_dev = NULL;
}
- return;
}
static int em28xx_ir_init(struct em28xx *dev)
@@ -564,8 +671,13 @@ static int em28xx_ir_init(struct em28xx *dev)
u64 rc_type;
u16 i2c_rc_dev_addr = 0;
- if (dev->board.has_snapshot_button)
- em28xx_register_snapshot_button(dev);
+ if (dev->is_audio_only) {
+ /* Shouldn't initialize IR for this interface */
+ return 0;
+ }
+
+ if (dev->board.buttons)
+ em28xx_init_buttons(dev);
if (dev->board.has_ir_i2c) {
i2c_rc_dev_addr = em28xx_probe_i2c_ir(dev);
@@ -583,6 +695,8 @@ static int em28xx_ir_init(struct em28xx *dev)
return 0;
}
+ em28xx_info("Registering input extension\n");
+
ir = kzalloc(sizeof(*ir), GFP_KERNEL);
rc = rc_allocate_device();
if (!ir || !rc)
@@ -633,6 +747,7 @@ static int em28xx_ir_init(struct em28xx *dev)
case CHIP_ID_EM2884:
case CHIP_ID_EM2874:
case CHIP_ID_EM28174:
+ case CHIP_ID_EM28178:
ir->get_key = em2874_polling_getkey;
rc->allowed_protos = RC_BIT_RC5 | RC_BIT_NEC |
RC_BIT_RC6_0;
@@ -675,6 +790,8 @@ static int em28xx_ir_init(struct em28xx *dev)
if (err)
goto error;
+ em28xx_info("Input extension successfully initalized\n");
+
return 0;
error:
@@ -688,7 +805,14 @@ static int em28xx_ir_fini(struct em28xx *dev)
{
struct em28xx_IR *ir = dev->ir;
- em28xx_deregister_snapshot_button(dev);
+ if (dev->is_audio_only) {
+ /* Shouldn't initialize IR for this interface */
+ return 0;
+ }
+
+ em28xx_info("Closing input extension");
+
+ em28xx_shutdown_buttons(dev);
/* skip detach on non attached boards */
if (!ir)
@@ -722,7 +846,8 @@ static void __exit em28xx_rc_unregister(void)
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
-MODULE_DESCRIPTION("Em28xx Input driver");
+MODULE_DESCRIPTION(DRIVER_DESC " - input interface");
+MODULE_VERSION(EM28XX_VERSION);
module_init(em28xx_rc_register);
module_exit(em28xx_rc_unregister);
diff --git a/drivers/media/usb/em28xx/em28xx-reg.h b/drivers/media/usb/em28xx/em28xx-reg.h
index 0e047784796..311fb349daf 100644
--- a/drivers/media/usb/em28xx/em28xx-reg.h
+++ b/drivers/media/usb/em28xx/em28xx-reg.h
@@ -25,10 +25,12 @@
#define EM28XX_R00_CHIPCFG 0x00
/* em28xx Chip Configuration 0x00 */
-#define EM28XX_CHIPCFG_VENDOR_AUDIO 0x80
-#define EM28XX_CHIPCFG_I2S_VOLUME_CAPABLE 0x40
-#define EM28XX_CHIPCFG_I2S_5_SAMPRATES 0x30
-#define EM28XX_CHIPCFG_I2S_3_SAMPRATES 0x20
+#define EM2860_CHIPCFG_VENDOR_AUDIO 0x80
+#define EM2860_CHIPCFG_I2S_VOLUME_CAPABLE 0x40
+#define EM2820_CHIPCFG_I2S_3_SAMPRATES 0x30
+#define EM2860_CHIPCFG_I2S_5_SAMPRATES 0x30
+#define EM2820_CHIPCFG_I2S_1_SAMPRATE 0x20
+#define EM2860_CHIPCFG_I2S_3_SAMPRATES 0x20
#define EM28XX_CHIPCFG_AC97 0x10
#define EM28XX_CHIPCFG_AUDIOMASK 0x30
@@ -245,6 +247,7 @@ enum em28xx_chip_id {
CHIP_ID_EM2874 = 65,
CHIP_ID_EM2884 = 68,
CHIP_ID_EM28174 = 113,
+ CHIP_ID_EM28178 = 114,
};
/*
diff --git a/drivers/media/usb/em28xx/em28xx-v4l.h b/drivers/media/usb/em28xx/em28xx-v4l.h
new file mode 100644
index 00000000000..bce438691e0
--- /dev/null
+++ b/drivers/media/usb/em28xx/em28xx-v4l.h
@@ -0,0 +1,20 @@
+/*
+ em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB
+ video capture devices
+
+ Copyright (C) 2013-2014 Mauro Carvalho Chehab <m.chehab@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 version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+ */
+
+
+int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count);
+int em28xx_stop_vbi_streaming(struct vb2_queue *vq);
+extern struct vb2_ops em28xx_vbi_qops;
diff --git a/drivers/media/usb/em28xx/em28xx-vbi.c b/drivers/media/usb/em28xx/em28xx-vbi.c
index 39f39c527c1..db3d655600d 100644
--- a/drivers/media/usb/em28xx/em28xx-vbi.c
+++ b/drivers/media/usb/em28xx/em28xx-vbi.c
@@ -27,6 +27,7 @@
#include <linux/init.h>
#include "em28xx.h"
+#include "em28xx-v4l.h"
static unsigned int vbibufs = 5;
module_param(vbibufs, int, 0644);
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index dd19c9ff76e..c3c928937dc 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -38,9 +38,11 @@
#include <linux/slab.h>
#include "em28xx.h"
+#include "em28xx-v4l.h"
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-event.h>
+#include <media/v4l2-clk.h>
#include <media/msp3400.h>
#include <media/tuner.h>
@@ -49,19 +51,23 @@
"Mauro Carvalho Chehab <mchehab@infradead.org>, " \
"Sascha Sommer <saschasommer@freenet.de>"
-#define DRIVER_DESC "Empia em28xx based USB video device driver"
+static unsigned int isoc_debug;
+module_param(isoc_debug, int, 0644);
+MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]");
+
+static unsigned int disable_vbi;
+module_param(disable_vbi, int, 0644);
+MODULE_PARM_DESC(disable_vbi, "disable vbi support");
-#define EM28XX_VERSION "0.2.0"
+static int alt;
+module_param(alt, int, 0644);
+MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint");
#define em28xx_videodbg(fmt, arg...) do {\
if (video_debug) \
printk(KERN_INFO "%s %s :"fmt, \
dev->name, __func__ , ##arg); } while (0)
-static unsigned int isoc_debug;
-module_param(isoc_debug, int, 0644);
-MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]");
-
#define em28xx_isocdbg(fmt, arg...) \
do {\
if (isoc_debug) { \
@@ -71,7 +77,7 @@ do {\
} while (0)
MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_DESCRIPTION(DRIVER_DESC " - v4l2 interface");
MODULE_LICENSE("GPL");
MODULE_VERSION(EM28XX_VERSION);
@@ -135,6 +141,257 @@ static struct em28xx_fmt format[] = {
},
};
+static int em28xx_vbi_supported(struct em28xx *dev)
+{
+ /* Modprobe option to manually disable */
+ if (disable_vbi == 1)
+ return 0;
+
+ if (dev->board.is_webcam)
+ return 0;
+
+ /* FIXME: check subdevices for VBI support */
+
+ if (dev->chip_id == CHIP_ID_EM2860 ||
+ dev->chip_id == CHIP_ID_EM2883)
+ return 1;
+
+ /* Version of em28xx that does not support VBI */
+ return 0;
+}
+
+/*
+ * em28xx_wake_i2c()
+ * configure i2c attached devices
+ */
+static void em28xx_wake_i2c(struct em28xx *dev)
+{
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, reset, 0);
+ v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing,
+ INPUT(dev->ctl_input)->vmux, 0, 0);
+ v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
+}
+
+static int em28xx_colorlevels_set_default(struct em28xx *dev)
+{
+ em28xx_write_reg(dev, EM28XX_R20_YGAIN, CONTRAST_DEFAULT);
+ em28xx_write_reg(dev, EM28XX_R21_YOFFSET, BRIGHTNESS_DEFAULT);
+ em28xx_write_reg(dev, EM28XX_R22_UVGAIN, SATURATION_DEFAULT);
+ em28xx_write_reg(dev, EM28XX_R23_UOFFSET, BLUE_BALANCE_DEFAULT);
+ em28xx_write_reg(dev, EM28XX_R24_VOFFSET, RED_BALANCE_DEFAULT);
+ em28xx_write_reg(dev, EM28XX_R25_SHARPNESS, SHARPNESS_DEFAULT);
+
+ em28xx_write_reg(dev, EM28XX_R14_GAMMA, 0x20);
+ em28xx_write_reg(dev, EM28XX_R15_RGAIN, 0x20);
+ em28xx_write_reg(dev, EM28XX_R16_GGAIN, 0x20);
+ em28xx_write_reg(dev, EM28XX_R17_BGAIN, 0x20);
+ em28xx_write_reg(dev, EM28XX_R18_ROFFSET, 0x00);
+ em28xx_write_reg(dev, EM28XX_R19_GOFFSET, 0x00);
+ return em28xx_write_reg(dev, EM28XX_R1A_BOFFSET, 0x00);
+}
+
+static int em28xx_set_outfmt(struct em28xx *dev)
+{
+ int ret;
+ u8 fmt, vinctrl;
+
+ fmt = dev->format->reg;
+ if (!dev->is_em25xx)
+ fmt |= 0x20;
+ /*
+ * NOTE: it's not clear if this is really needed !
+ * The datasheets say bit 5 is a reserved bit and devices seem to work
+ * fine without it. But the Windows driver sets it for em2710/50+em28xx
+ * devices and we've always been setting it, too.
+ *
+ * em2765 (em25xx, em276x/7x/8x) devices do NOT work with this bit set,
+ * it's likely used for an additional (compressed ?) format there.
+ */
+ ret = em28xx_write_reg(dev, EM28XX_R27_OUTFMT, fmt);
+ if (ret < 0)
+ return ret;
+
+ ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, dev->vinmode);
+ if (ret < 0)
+ return ret;
+
+ vinctrl = dev->vinctl;
+ if (em28xx_vbi_supported(dev) == 1) {
+ vinctrl |= EM28XX_VINCTRL_VBI_RAW;
+ em28xx_write_reg(dev, EM28XX_R34_VBI_START_H, 0x00);
+ em28xx_write_reg(dev, EM28XX_R36_VBI_WIDTH, dev->vbi_width/4);
+ em28xx_write_reg(dev, EM28XX_R37_VBI_HEIGHT, dev->vbi_height);
+ if (dev->norm & V4L2_STD_525_60) {
+ /* NTSC */
+ em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x09);
+ } else if (dev->norm & V4L2_STD_625_50) {
+ /* PAL */
+ em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x07);
+ }
+ }
+
+ return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, vinctrl);
+}
+
+static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax,
+ u8 ymin, u8 ymax)
+{
+ em28xx_videodbg("em28xx Scale: (%d,%d)-(%d,%d)\n",
+ xmin, ymin, xmax, ymax);
+
+ em28xx_write_regs(dev, EM28XX_R28_XMIN, &xmin, 1);
+ em28xx_write_regs(dev, EM28XX_R29_XMAX, &xmax, 1);
+ em28xx_write_regs(dev, EM28XX_R2A_YMIN, &ymin, 1);
+ return em28xx_write_regs(dev, EM28XX_R2B_YMAX, &ymax, 1);
+}
+
+static void em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
+ u16 width, u16 height)
+{
+ u8 cwidth = width >> 2;
+ u8 cheight = height >> 2;
+ u8 overflow = (height >> 9 & 0x02) | (width >> 10 & 0x01);
+ /* NOTE: size limit: 2047x1023 = 2MPix */
+
+ em28xx_videodbg("capture area set to (%d,%d): %dx%d\n",
+ hstart, vstart,
+ ((overflow & 2) << 9 | cwidth << 2),
+ ((overflow & 1) << 10 | cheight << 2));
+
+ em28xx_write_regs(dev, EM28XX_R1C_HSTART, &hstart, 1);
+ em28xx_write_regs(dev, EM28XX_R1D_VSTART, &vstart, 1);
+ em28xx_write_regs(dev, EM28XX_R1E_CWIDTH, &cwidth, 1);
+ em28xx_write_regs(dev, EM28XX_R1F_CHEIGHT, &cheight, 1);
+ em28xx_write_regs(dev, EM28XX_R1B_OFLOW, &overflow, 1);
+
+ /* FIXME: function/meaning of these registers ? */
+ /* FIXME: align width+height to multiples of 4 ?! */
+ if (dev->is_em25xx) {
+ em28xx_write_reg(dev, 0x34, width >> 4);
+ em28xx_write_reg(dev, 0x35, height >> 4);
+ }
+}
+
+static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
+{
+ u8 mode;
+ /* the em2800 scaler only supports scaling down to 50% */
+
+ if (dev->board.is_em2800) {
+ mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00);
+ } else {
+ u8 buf[2];
+
+ buf[0] = h;
+ buf[1] = h >> 8;
+ em28xx_write_regs(dev, EM28XX_R30_HSCALELOW, (char *)buf, 2);
+
+ buf[0] = v;
+ buf[1] = v >> 8;
+ em28xx_write_regs(dev, EM28XX_R32_VSCALELOW, (char *)buf, 2);
+ /* it seems that both H and V scalers must be active
+ to work correctly */
+ mode = (h || v) ? 0x30 : 0x00;
+ }
+ return em28xx_write_reg_bits(dev, EM28XX_R26_COMPR, mode, 0x30);
+}
+
+/* FIXME: this only function read values from dev */
+static int em28xx_resolution_set(struct em28xx *dev)
+{
+ int width, height;
+ width = norm_maxw(dev);
+ height = norm_maxh(dev);
+
+ /* Properly setup VBI */
+ dev->vbi_width = 720;
+ if (dev->norm & V4L2_STD_525_60)
+ dev->vbi_height = 12;
+ else
+ dev->vbi_height = 18;
+
+ em28xx_set_outfmt(dev);
+
+ em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2);
+
+ /* If we don't set the start position to 2 in VBI mode, we end up
+ with line 20/21 being YUYV encoded instead of being in 8-bit
+ greyscale. The core of the issue is that line 21 (and line 23 for
+ PAL WSS) are inside of active video region, and as a result they
+ get the pixelformatting associated with that area. So by cropping
+ it out, we end up with the same format as the rest of the VBI
+ region */
+ if (em28xx_vbi_supported(dev) == 1)
+ em28xx_capture_area_set(dev, 0, 2, width, height);
+ else
+ em28xx_capture_area_set(dev, 0, 0, width, height);
+
+ return em28xx_scaler_set(dev, dev->hscale, dev->vscale);
+}
+
+/* Set USB alternate setting for analog video */
+static int em28xx_set_alternate(struct em28xx *dev)
+{
+ int errCode;
+ int i;
+ unsigned int min_pkt_size = dev->width * 2 + 4;
+
+ /* NOTE: for isoc transfers, only alt settings > 0 are allowed
+ bulk transfers seem to work only with alt=0 ! */
+ dev->alt = 0;
+ if ((alt > 0) && (alt < dev->num_alt)) {
+ em28xx_videodbg("alternate forced to %d\n", dev->alt);
+ dev->alt = alt;
+ goto set_alt;
+ }
+ if (dev->analog_xfer_bulk)
+ goto set_alt;
+
+ /* When image size is bigger than a certain value,
+ the frame size should be increased, otherwise, only
+ green screen will be received.
+ */
+ if (dev->width * 2 * dev->height > 720 * 240 * 2)
+ min_pkt_size *= 2;
+
+ for (i = 0; i < dev->num_alt; i++) {
+ /* stop when the selected alt setting offers enough bandwidth */
+ if (dev->alt_max_pkt_size_isoc[i] >= min_pkt_size) {
+ dev->alt = i;
+ break;
+ /* otherwise make sure that we end up with the maximum bandwidth
+ because the min_pkt_size equation might be wrong...
+ */
+ } else if (dev->alt_max_pkt_size_isoc[i] >
+ dev->alt_max_pkt_size_isoc[dev->alt])
+ dev->alt = i;
+ }
+
+set_alt:
+ /* NOTE: for bulk transfers, we need to call usb_set_interface()
+ * even if the previous settings were the same. Otherwise streaming
+ * fails with all urbs having status = -EOVERFLOW ! */
+ if (dev->analog_xfer_bulk) {
+ dev->max_pkt_size = 512; /* USB 2.0 spec */
+ dev->packet_multiplier = EM28XX_BULK_PACKET_MULTIPLIER;
+ } else { /* isoc */
+ em28xx_videodbg("minimum isoc packet size: %u (alt=%d)\n",
+ min_pkt_size, dev->alt);
+ dev->max_pkt_size =
+ dev->alt_max_pkt_size_isoc[dev->alt];
+ dev->packet_multiplier = EM28XX_NUM_ISOC_PACKETS;
+ }
+ em28xx_videodbg("setting alternate %d with wMaxPacketSize=%u\n",
+ dev->alt, dev->max_pkt_size);
+ errCode = usb_set_interface(dev->udev, dev->ifnum, dev->alt);
+ if (errCode < 0) {
+ em28xx_errdev("cannot change alternate number to %d (error=%i)\n",
+ dev->alt, errCode);
+ return errCode;
+ }
+ return 0;
+}
+
/* ------------------------------------------------------------------
DMA and thread functions
------------------------------------------------------------------*/
@@ -763,7 +1020,7 @@ static struct vb2_ops em28xx_video_qops = {
.wait_finish = vb2_ops_wait_finish,
};
-int em28xx_vb2_setup(struct em28xx *dev)
+static int em28xx_vb2_setup(struct em28xx *dev)
{
int rc;
struct vb2_queue *q;
@@ -831,7 +1088,7 @@ static void video_mux(struct em28xx *dev, int index)
em28xx_audio_analog_set(dev);
}
-void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv)
+static void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv)
{
struct em28xx *dev = priv;
@@ -890,7 +1147,7 @@ static int em28xx_s_ctrl(struct v4l2_ctrl *ctrl)
return (ret < 0) ? ret : 0;
}
-const struct v4l2_ctrl_ops em28xx_ctrl_ops = {
+static const struct v4l2_ctrl_ops em28xx_ctrl_ops = {
.s_ctrl = em28xx_s_ctrl,
};
@@ -1368,7 +1625,7 @@ static int vidioc_g_register(struct file *file, void *priv,
reg->val = ret;
} else {
__le16 val = 0;
- ret = em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS,
+ ret = dev->em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS,
reg->reg, (char *)&val, 2);
if (ret < 0)
return ret;
@@ -1570,6 +1827,10 @@ static int em28xx_v4l2_open(struct file *filp)
case VFL_TYPE_VBI:
fh_type = V4L2_BUF_TYPE_VBI_CAPTURE;
break;
+ case VFL_TYPE_RADIO:
+ break;
+ default:
+ return -EINVAL;
}
em28xx_videodbg("open dev=%s type=%s users=%d\n",
@@ -1590,15 +1851,17 @@ static int em28xx_v4l2_open(struct file *filp)
fh->type = fh_type;
filp->private_data = fh;
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
+ if (dev->users == 0) {
em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
- em28xx_resolution_set(dev);
- /* Needed, since GPIO might have disabled power of
- some i2c device
+ if (vdev->vfl_type != VFL_TYPE_RADIO)
+ em28xx_resolution_set(dev);
+
+ /*
+ * Needed, since GPIO might have disabled power
+ * of some i2c devices
*/
em28xx_wake_i2c(dev);
-
}
if (vdev->vfl_type == VFL_TYPE_RADIO) {
@@ -1615,40 +1878,59 @@ static int em28xx_v4l2_open(struct file *filp)
}
/*
- * em28xx_realease_resources()
+ * em28xx_v4l2_fini()
* unregisters the v4l2,i2c and usb devices
* called when the device gets disconected or at module unload
*/
-void em28xx_release_analog_resources(struct em28xx *dev)
+static int em28xx_v4l2_fini(struct em28xx *dev)
{
+ if (dev->is_audio_only) {
+ /* Shouldn't initialize IR for this interface */
+ return 0;
+ }
+
+ if (!dev->has_video) {
+ /* This device does not support the v4l2 extension */
+ return 0;
+ }
- /*FIXME: I2C IR should be disconnected */
+ em28xx_info("Closing video extension");
+
+ mutex_lock(&dev->lock);
+
+ v4l2_device_disconnect(&dev->v4l2_dev);
+
+ em28xx_uninit_usb_xfer(dev, EM28XX_ANALOG_MODE);
if (dev->radio_dev) {
- if (video_is_registered(dev->radio_dev))
- video_unregister_device(dev->radio_dev);
- else
- video_device_release(dev->radio_dev);
- dev->radio_dev = NULL;
+ em28xx_info("V4L2 device %s deregistered\n",
+ video_device_node_name(dev->radio_dev));
+ video_unregister_device(dev->radio_dev);
}
if (dev->vbi_dev) {
em28xx_info("V4L2 device %s deregistered\n",
video_device_node_name(dev->vbi_dev));
- if (video_is_registered(dev->vbi_dev))
- video_unregister_device(dev->vbi_dev);
- else
- video_device_release(dev->vbi_dev);
- dev->vbi_dev = NULL;
+ video_unregister_device(dev->vbi_dev);
}
if (dev->vdev) {
em28xx_info("V4L2 device %s deregistered\n",
video_device_node_name(dev->vdev));
- if (video_is_registered(dev->vdev))
- video_unregister_device(dev->vdev);
- else
- video_device_release(dev->vdev);
- dev->vdev = NULL;
+ video_unregister_device(dev->vdev);
}
+
+ if (dev->clk) {
+ v4l2_clk_unregister_fixed(dev->clk);
+ dev->clk = NULL;
+ }
+
+ v4l2_ctrl_handler_free(&dev->ctrl_handler);
+ v4l2_device_unregister(&dev->v4l2_dev);
+
+ if (dev->users)
+ em28xx_warn("Device is open ! Memory deallocation is deferred on last close.\n");
+ mutex_unlock(&dev->lock);
+
+ return 0;
}
/*
@@ -1668,14 +1950,10 @@ static int em28xx_v4l2_close(struct file *filp)
mutex_lock(&dev->lock);
if (dev->users == 1) {
- /* the device is already disconnect,
- free the remaining resources */
+ /* free the remaining resources if device is disconnected */
if (dev->disconnected) {
- em28xx_release_resources(dev);
kfree(dev->alt_max_pkt_size_isoc);
- mutex_unlock(&dev->lock);
- kfree(dev);
- return 0;
+ goto exit;
}
/* Save some power by putting tuner to sleep */
@@ -1694,11 +1972,29 @@ static int em28xx_v4l2_close(struct file *filp)
}
}
+exit:
dev->users--;
mutex_unlock(&dev->lock);
return 0;
}
+/*
+ * em28xx_videodevice_release()
+ * called when the last user of the video device exits and frees the memeory
+ */
+static void em28xx_videodevice_release(struct video_device *vdev)
+{
+ struct em28xx *dev = video_get_drvdata(vdev);
+
+ video_device_release(vdev);
+ if (vdev == dev->vdev)
+ dev->vdev = NULL;
+ else if (vdev == dev->vbi_dev)
+ dev->vbi_dev = NULL;
+ else if (vdev == dev->radio_dev)
+ dev->radio_dev = NULL;
+}
+
static const struct v4l2_file_operations em28xx_v4l_fops = {
.owner = THIS_MODULE,
.open = em28xx_v4l2_open,
@@ -1753,11 +2049,10 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
};
static const struct video_device em28xx_video_template = {
- .fops = &em28xx_v4l_fops,
- .release = video_device_release_empty,
- .ioctl_ops = &video_ioctl_ops,
-
- .tvnorms = V4L2_STD_ALL,
+ .fops = &em28xx_v4l_fops,
+ .ioctl_ops = &video_ioctl_ops,
+ .release = em28xx_videodevice_release,
+ .tvnorms = V4L2_STD_ALL,
};
static const struct v4l2_file_operations radio_fops = {
@@ -1783,14 +2078,30 @@ static const struct v4l2_ioctl_ops radio_ioctl_ops = {
};
static struct video_device em28xx_radio_template = {
- .name = "em28xx-radio",
- .fops = &radio_fops,
- .ioctl_ops = &radio_ioctl_ops,
+ .fops = &radio_fops,
+ .ioctl_ops = &radio_ioctl_ops,
+ .release = em28xx_videodevice_release,
};
-/******************************** usb interface ******************************/
+/* I2C possible address to saa7115, tvp5150, msp3400, tvaudio */
+static unsigned short saa711x_addrs[] = {
+ 0x4a >> 1, 0x48 >> 1, /* SAA7111, SAA7111A and SAA7113 */
+ 0x42 >> 1, 0x40 >> 1, /* SAA7114, SAA7115 and SAA7118 */
+ I2C_CLIENT_END };
+static unsigned short tvp5150_addrs[] = {
+ 0xb8 >> 1,
+ 0xba >> 1,
+ I2C_CLIENT_END
+};
+static unsigned short msp3400_addrs[] = {
+ 0x80 >> 1,
+ 0x88 >> 1,
+ I2C_CLIENT_END
+};
+
+/******************************** usb interface ******************************/
static struct video_device *em28xx_vdev_init(struct em28xx *dev,
const struct video_device *template,
@@ -1817,14 +2128,198 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev,
return vfd;
}
-int em28xx_register_analog_devices(struct em28xx *dev)
+static void em28xx_tuner_setup(struct em28xx *dev)
+{
+ struct tuner_setup tun_setup;
+ struct v4l2_frequency f;
+
+ if (dev->tuner_type == TUNER_ABSENT)
+ return;
+
+ memset(&tun_setup, 0, sizeof(tun_setup));
+
+ tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
+ tun_setup.tuner_callback = em28xx_tuner_callback;
+
+ if (dev->board.radio.type) {
+ tun_setup.type = dev->board.radio.type;
+ tun_setup.addr = dev->board.radio_addr;
+
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup);
+ }
+
+ if ((dev->tuner_type != TUNER_ABSENT) && (dev->tuner_type)) {
+ tun_setup.type = dev->tuner_type;
+ tun_setup.addr = dev->tuner_addr;
+
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup);
+ }
+
+ if (dev->tda9887_conf) {
+ struct v4l2_priv_tun_config tda9887_cfg;
+
+ tda9887_cfg.tuner = TUNER_TDA9887;
+ tda9887_cfg.priv = &dev->tda9887_conf;
+
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, &tda9887_cfg);
+ }
+
+ if (dev->tuner_type == TUNER_XC2028) {
+ struct v4l2_priv_tun_config xc2028_cfg;
+ struct xc2028_ctrl ctl;
+
+ memset(&xc2028_cfg, 0, sizeof(xc2028_cfg));
+ memset(&ctl, 0, sizeof(ctl));
+
+ em28xx_setup_xc3028(dev, &ctl);
+
+ xc2028_cfg.tuner = TUNER_XC2028;
+ xc2028_cfg.priv = &ctl;
+
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, &xc2028_cfg);
+ }
+
+ /* configure tuner */
+ f.tuner = 0;
+ f.type = V4L2_TUNER_ANALOG_TV;
+ f.frequency = 9076; /* just a magic number */
+ dev->ctl_freq = f.frequency;
+ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
+}
+
+static int em28xx_v4l2_init(struct em28xx *dev)
{
u8 val;
int ret;
unsigned int maxw;
+ struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
+
+ if (dev->is_audio_only) {
+ /* Shouldn't initialize IR for this interface */
+ return 0;
+ }
+
+ if (!dev->has_video) {
+ /* This device does not support the v4l2 extension */
+ return 0;
+ }
+
+ em28xx_info("Registering V4L2 extension\n");
+
+ mutex_lock(&dev->lock);
+
+ ret = v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev);
+ if (ret < 0) {
+ em28xx_errdev("Call to v4l2_device_register() failed!\n");
+ goto err;
+ }
+
+ v4l2_ctrl_handler_init(hdl, 8);
+ dev->v4l2_dev.ctrl_handler = hdl;
+
+ /*
+ * Default format, used for tvp5150 or saa711x output formats
+ */
+ dev->vinmode = 0x10;
+ dev->vinctl = EM28XX_VINCTRL_INTERLACED |
+ EM28XX_VINCTRL_CCIR656_ENABLE;
+
+ /* request some modules */
+
+ if (dev->board.has_msp34xx)
+ v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
+ "msp3400", 0, msp3400_addrs);
+
+ if (dev->board.decoder == EM28XX_SAA711X)
+ v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
+ "saa7115_auto", 0, saa711x_addrs);
+
+ if (dev->board.decoder == EM28XX_TVP5150)
+ v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
+ "tvp5150", 0, tvp5150_addrs);
+
+ if (dev->board.adecoder == EM28XX_TVAUDIO)
+ v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
+ "tvaudio", dev->board.tvaudio_addr, NULL);
+
+ /* Initialize tuner and camera */
+
+ if (dev->board.tuner_type != TUNER_ABSENT) {
+ int has_demod = (dev->tda9887_conf & TDA9887_PRESENT);
+
+ if (dev->board.radio.type)
+ v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
+ "tuner", dev->board.radio_addr, NULL);
+
+ if (has_demod)
+ v4l2_i2c_new_subdev(&dev->v4l2_dev,
+ &dev->i2c_adap[dev->def_i2c_bus], "tuner",
+ 0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
+ if (dev->tuner_addr == 0) {
+ enum v4l2_i2c_tuner_type type =
+ has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV;
+ struct v4l2_subdev *sd;
+
+ sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
+ &dev->i2c_adap[dev->def_i2c_bus], "tuner",
+ 0, v4l2_i2c_tuner_addrs(type));
+
+ if (sd)
+ dev->tuner_addr = v4l2_i2c_subdev_addr(sd);
+ } else {
+ v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
+ "tuner", dev->tuner_addr, NULL);
+ }
+ }
+
+ em28xx_tuner_setup(dev);
+ em28xx_init_camera(dev);
+
+ /* Configure audio */
+ ret = em28xx_audio_setup(dev);
+ if (ret < 0) {
+ em28xx_errdev("%s: Error while setting audio - error [%d]!\n",
+ __func__, ret);
+ goto unregister_dev;
+ }
+ if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
+ v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
+ V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
+ v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
+ V4L2_CID_AUDIO_VOLUME, 0, 0x1f, 1, 0x1f);
+ } else {
+ /* install the em28xx notify callback */
+ v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_MUTE),
+ em28xx_ctrl_notify, dev);
+ v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_VOLUME),
+ em28xx_ctrl_notify, dev);
+ }
+
+ /* wake i2c devices */
+ em28xx_wake_i2c(dev);
+
+ /* init video dma queues */
+ INIT_LIST_HEAD(&dev->vidq.active);
+ INIT_LIST_HEAD(&dev->vbiq.active);
- printk(KERN_INFO "%s: v4l2 driver version %s\n",
- dev->name, EM28XX_VERSION);
+ if (dev->board.has_msp34xx) {
+ /* Send a reset to other chips via gpio */
+ ret = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xf7);
+ if (ret < 0) {
+ em28xx_errdev("%s: em28xx_write_reg - msp34xx(1) failed! error [%d]\n",
+ __func__, ret);
+ goto unregister_dev;
+ }
+ msleep(3);
+
+ ret = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xff);
+ if (ret < 0) {
+ em28xx_errdev("%s: em28xx_write_reg - msp34xx(2) failed! error [%d]\n",
+ __func__, ret);
+ goto unregister_dev;
+ }
+ msleep(3);
+ }
/* set default norm */
dev->norm = V4L2_STD_PAL;
@@ -1888,14 +2383,16 @@ int em28xx_register_analog_devices(struct em28xx *dev)
/* Reset image controls */
em28xx_colorlevels_set_default(dev);
v4l2_ctrl_handler_setup(&dev->ctrl_handler);
- if (dev->ctrl_handler.error)
- return dev->ctrl_handler.error;
+ ret = dev->ctrl_handler.error;
+ if (ret)
+ goto unregister_dev;
/* allocate and fill video video_device struct */
dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template, "video");
if (!dev->vdev) {
em28xx_errdev("cannot allocate video_device.\n");
- return -ENODEV;
+ ret = -ENODEV;
+ goto unregister_dev;
}
dev->vdev->queue = &dev->vb_vidq;
dev->vdev->queue->lock = &dev->vb_queue_lock;
@@ -1925,7 +2422,7 @@ int em28xx_register_analog_devices(struct em28xx *dev)
if (ret) {
em28xx_errdev("unable to register video device (error=%i).\n",
ret);
- return ret;
+ goto unregister_dev;
}
/* Allocate and fill vbi video_device struct */
@@ -1954,7 +2451,7 @@ int em28xx_register_analog_devices(struct em28xx *dev)
vbi_nr[dev->devno]);
if (ret < 0) {
em28xx_errdev("unable to register vbi device\n");
- return ret;
+ goto unregister_dev;
}
}
@@ -1963,13 +2460,14 @@ int em28xx_register_analog_devices(struct em28xx *dev)
"radio");
if (!dev->radio_dev) {
em28xx_errdev("cannot allocate video_device.\n");
- return -ENODEV;
+ ret = -ENODEV;
+ goto unregister_dev;
}
ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO,
radio_nr[dev->devno]);
if (ret < 0) {
em28xx_errdev("can't register radio device\n");
- return ret;
+ goto unregister_dev;
}
em28xx_info("Registered radio device as %s\n",
video_device_node_name(dev->radio_dev));
@@ -1982,5 +2480,41 @@ int em28xx_register_analog_devices(struct em28xx *dev)
em28xx_info("V4L2 VBI device registered as %s\n",
video_device_node_name(dev->vbi_dev));
+ /* Save some power by putting tuner to sleep */
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
+
+ /* initialize videobuf2 stuff */
+ em28xx_vb2_setup(dev);
+
+ em28xx_info("V4L2 extension successfully initialized\n");
+
+ mutex_unlock(&dev->lock);
return 0;
+
+unregister_dev:
+ v4l2_ctrl_handler_free(&dev->ctrl_handler);
+ v4l2_device_unregister(&dev->v4l2_dev);
+err:
+ mutex_unlock(&dev->lock);
+ return ret;
+}
+
+static struct em28xx_ops v4l2_ops = {
+ .id = EM28XX_V4L2,
+ .name = "Em28xx v4l2 Extension",
+ .init = em28xx_v4l2_init,
+ .fini = em28xx_v4l2_fini,
+};
+
+static int __init em28xx_video_register(void)
+{
+ return em28xx_register_extension(&v4l2_ops);
+}
+
+static void __exit em28xx_video_unregister(void)
+{
+ em28xx_unregister_extension(&v4l2_ops);
}
+
+module_init(em28xx_video_register);
+module_exit(em28xx_video_unregister);
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index f8726ad5d0a..32d8a4bb796 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -26,6 +26,9 @@
#ifndef _EM28XX_H
#define _EM28XX_H
+#define EM28XX_VERSION "0.2.1"
+#define DRIVER_DESC "Empia em28xx device driver"
+
#include <linux/workqueue.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
@@ -132,6 +135,8 @@
#define EM2884_BOARD_C3TECH_DIGITAL_DUO 88
#define EM2874_BOARD_DELOCK_61959 89
#define EM2874_BOARD_KWORLD_UB435Q_V2 90
+#define EM2765_BOARD_SPEEDLINK_VAD_LAPLACE 91
+#define EM28178_BOARD_PCTV_461E 92
/* Limits minimum and default number of buffers */
#define EM28XX_MIN_BUF 4
@@ -178,8 +183,27 @@
#define EM28XX_INTERLACED_DEFAULT 1
-/* time in msecs to wait for i2c writes to finish */
-#define EM2800_I2C_XFER_TIMEOUT 20
+/*
+ * Time in msecs to wait for i2c xfers to finish.
+ * 35ms is the maximum time a SMBUS device could wait when
+ * clock stretching is used. As the transfer itself will take
+ * some time to happen, set it to 35 ms.
+ *
+ * Ok, I2C doesn't specify any limit. So, eventually, we may need
+ * to increase this timeout.
+ *
+ * FIXME: this assumes that an I2C message is not longer than 1ms.
+ * This is actually dependent on the I2C bus speed, although most
+ * devices use a 100kHz clock. So, this assumtion is true most of
+ * the time.
+ */
+#define EM28XX_I2C_XFER_TIMEOUT 36
+
+/* time in msecs to wait for AC97 xfers to finish */
+#define EM28XX_AC97_XFER_TIMEOUT 100
+
+/* max. number of button state polling addresses */
+#define EM28XX_NUM_BUTTON_ADDRESSES_MAX 5
enum em28xx_mode {
EM28XX_SUSPEND,
@@ -287,8 +311,7 @@ struct em28xx_audio_mode {
unsigned int has_audio:1;
- unsigned int i2s_3rates:1;
- unsigned int i2s_5rates:1;
+ u8 i2s_samplerates;
};
/* em28xx has two audio inputs: tuner and line in.
@@ -374,6 +397,33 @@ enum em28xx_adecoder {
EM28XX_TVAUDIO,
};
+enum em28xx_led_role {
+ EM28XX_LED_ANALOG_CAPTURING = 0,
+ EM28XX_LED_ILLUMINATION,
+ EM28XX_NUM_LED_ROLES, /* must be the last */
+};
+
+struct em28xx_led {
+ enum em28xx_led_role role;
+ u8 gpio_reg;
+ u8 gpio_mask;
+ bool inverted;
+};
+
+enum em28xx_button_role {
+ EM28XX_BUTTON_SNAPSHOT = 0,
+ EM28XX_BUTTON_ILLUMINATION,
+ EM28XX_NUM_BUTTON_ROLES, /* must be the last */
+};
+
+struct em28xx_button {
+ enum em28xx_button_role role;
+ u8 reg_r;
+ u8 reg_clearing;
+ u8 mask;
+ bool inverted;
+};
+
struct em28xx_board {
char *name;
int vchannels;
@@ -395,7 +445,6 @@ struct em28xx_board {
unsigned int mts_firmware:1;
unsigned int max_range_640_480:1;
unsigned int has_dvb:1;
- unsigned int has_snapshot_button:1;
unsigned int is_webcam:1;
unsigned int valid:1;
unsigned int has_ir_i2c:1;
@@ -410,6 +459,12 @@ struct em28xx_board {
struct em28xx_input input[MAX_EM28XX_INPUT];
struct em28xx_input radio;
char *ir_codes;
+
+ /* LEDs that need to be controlled explicitly */
+ struct em28xx_led *leds;
+
+ /* Buttons */
+ struct em28xx_button *buttons;
};
struct em28xx_eeprom {
@@ -426,15 +481,13 @@ struct em28xx_eeprom {
u8 string_idx_table;
};
-#define EM28XX_AUDIO_BUFS 5
-#define EM28XX_NUM_AUDIO_PACKETS 64
-#define EM28XX_AUDIO_MAX_PACKET_SIZE 196 /* static value */
#define EM28XX_CAPTURE_STREAM_EN 1
/* em28xx extensions */
#define EM28XX_AUDIO 0x10
#define EM28XX_DVB 0x20
#define EM28XX_RC 0x30
+#define EM28XX_V4L2 0x40
/* em28xx resource types (used for res_get/res_lock etc */
#define EM28XX_RESOURCE_VIDEO 0x01
@@ -442,8 +495,9 @@ struct em28xx_eeprom {
struct em28xx_audio {
char name[50];
- char *transfer_buffer[EM28XX_AUDIO_BUFS];
- struct urb *urb[EM28XX_AUDIO_BUFS];
+ unsigned num_urb;
+ char **transfer_buffer;
+ struct urb **urb;
struct usb_device *udev;
unsigned int capture_transfer_done;
struct snd_pcm_substream *capture_pcm_substream;
@@ -451,6 +505,8 @@ struct em28xx_audio {
unsigned int hwptr_done_capture;
struct snd_card *sndcard;
+ size_t period;
+
int users;
spinlock_t slock;
};
@@ -485,11 +541,13 @@ struct em28xx {
int model; /* index in the device_data struct */
int devno; /* marks the number of this device */
enum em28xx_chip_id chip_id;
- unsigned int is_em25xx:1; /* em25xx/em276x/7x/8x family bridge */
+ unsigned int is_em25xx:1; /* em25xx/em276x/7x/8x family bridge */
unsigned char disconnected:1; /* device has been diconnected */
-
- int audio_ifnum;
+ unsigned int has_video:1;
+ unsigned int has_audio_class:1;
+ unsigned int has_alsa_audio:1;
+ unsigned int is_audio_only:1;
struct v4l2_device v4l2_dev;
struct v4l2_ctrl_handler ctrl_handler;
@@ -507,10 +565,6 @@ struct em28xx {
/* Vinmode/Vinctl used at the driver */
int vinmode, vinctl;
- unsigned int has_audio_class:1;
- unsigned int has_alsa_audio:1;
- unsigned int is_audio_only:1;
-
/* Controls audio streaming */
struct work_struct wq_trigger; /* Trigger to start/stop audio for alsa module */
atomic_t stream_started; /* stream should be running if true */
@@ -608,6 +662,7 @@ struct em28xx {
/* usb transfer */
struct usb_device *udev; /* the usb device */
+ u8 ifnum; /* number of the assigned usb interface */
u8 analog_ep_isoc; /* address of isoc endpoint for analog */
u8 analog_ep_bulk; /* address of bulk endpoint for analog */
u8 dvb_ep_isoc; /* address of isoc endpoint for DVB */
@@ -639,10 +694,15 @@ struct em28xx {
enum em28xx_mode mode;
- /* Snapshot button */
+ /* Button state polling */
+ struct delayed_work buttons_query_work;
+ u8 button_polling_addresses[EM28XX_NUM_BUTTON_ADDRESSES_MAX];
+ u8 button_polling_last_values[EM28XX_NUM_BUTTON_ADDRESSES_MAX];
+ u8 num_button_polling_addresses;
+ u16 button_polling_interval; /* [ms] */
+ /* Snapshot button input device */
char snapshot_button_path[30]; /* path of the input dev */
struct input_dev *sbutton_input_dev;
- struct delayed_work sbutton_query_work;
struct em28xx_dvb *dvb;
};
@@ -672,6 +732,7 @@ int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len);
int em28xx_write_reg(struct em28xx *dev, u16 reg, u8 val);
int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
u8 bitmask);
+int em28xx_toggle_reg_bits(struct em28xx *dev, u16 reg, u8 bitmask);
int em28xx_read_ac97(struct em28xx *dev, u8 reg);
int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val);
@@ -679,12 +740,9 @@ int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val);
int em28xx_audio_analog_set(struct em28xx *dev);
int em28xx_audio_setup(struct em28xx *dev);
-int em28xx_colorlevels_set_default(struct em28xx *dev);
+const struct em28xx_led *em28xx_find_led(struct em28xx *dev,
+ enum em28xx_led_role role);
int em28xx_capture_start(struct em28xx *dev, int start);
-int em28xx_vbi_supported(struct em28xx *dev);
-int em28xx_set_outfmt(struct em28xx *dev);
-int em28xx_resolution_set(struct em28xx *dev);
-int em28xx_set_alternate(struct em28xx *dev);
int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk,
int num_bufs, int max_pkt_size, int packet_multiplier);
int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode,
@@ -696,30 +754,18 @@ void em28xx_uninit_usb_xfer(struct em28xx *dev, enum em28xx_mode mode);
void em28xx_stop_urbs(struct em28xx *dev);
int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode);
int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio);
-void em28xx_wake_i2c(struct em28xx *dev);
int em28xx_register_extension(struct em28xx_ops *dev);
void em28xx_unregister_extension(struct em28xx_ops *dev);
void em28xx_init_extension(struct em28xx *dev);
void em28xx_close_extension(struct em28xx *dev);
-/* Provided by em28xx-video.c */
-int em28xx_vb2_setup(struct em28xx *dev);
-int em28xx_register_analog_devices(struct em28xx *dev);
-void em28xx_release_analog_resources(struct em28xx *dev);
-void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv);
-int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count);
-int em28xx_stop_vbi_streaming(struct vb2_queue *vq);
-extern const struct v4l2_ctrl_ops em28xx_ctrl_ops;
-
/* Provided by em28xx-cards.c */
extern struct em28xx_board em28xx_boards[];
extern struct usb_device_id em28xx_id_table[];
int em28xx_tuner_callback(void *ptr, int component, int command, int arg);
+void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl);
void em28xx_release_resources(struct em28xx *dev);
-/* Provided by em28xx-vbi.c */
-extern struct vb2_ops em28xx_vbi_qops;
-
/* Provided by em28xx-camera.c */
int em28xx_detect_sensor(struct em28xx *dev);
int em28xx_init_camera(struct em28xx *dev);