summaryrefslogtreecommitdiff
path: root/drivers/media/usb/em28xx/em28xx-core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/usb/em28xx/em28xx-core.c')
-rw-r--r--drivers/media/usb/em28xx/em28xx-core.c871
1 files changed, 363 insertions, 508 deletions
diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
index fc157af5234a..29a7f3f19b56 100644
--- a/drivers/media/usb/em28xx/em28xx-core.c
+++ b/drivers/media/usb/em28xx/em28xx-core.c
@@ -1,28 +1,17 @@
-/*
- em28xx-core.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
-
- Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
- Markus Rechberger <mrechberger@gmail.com>
- Mauro Carvalho Chehab <mchehab@infradead.org>
- Sascha Sommer <saschasommer@freenet.de>
- Copyright (C) 2012 Frank Schäfer <fschaefer.oss@googlemail.com>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- 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.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// em28xx-core.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
+//
+// Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
+// Markus Rechberger <mrechberger@gmail.com>
+// Mauro Carvalho Chehab <mchehab@kernel.org>
+// Sascha Sommer <saschasommer@freenet.de>
+// Copyright (C) 2012 Frank Schäfer <fschaefer.oss@googlemail.com>
+
+#include "em28xx.h"
#include <linux/init.h>
+#include <linux/jiffies.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -31,51 +20,55 @@
#include <sound/ac97_codec.h>
#include <media/v4l2-common.h>
-#include "em28xx.h"
+#define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \
+ "Markus Rechberger <mrechberger@gmail.com>, " \
+ "Mauro Carvalho Chehab <mchehab@kernel.org>, " \
+ "Sascha Sommer <saschasommer@freenet.de>"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(EM28XX_VERSION);
/* #define ENABLE_DEBUG_ISOC_FRAMES */
static unsigned int core_debug;
module_param(core_debug, int, 0644);
-MODULE_PARM_DESC(core_debug, "enable debug messages [core]");
+MODULE_PARM_DESC(core_debug, "enable debug messages [core and isoc]");
-#define em28xx_coredbg(fmt, arg...) do {\
- if (core_debug) \
- printk(KERN_INFO "%s %s :"fmt, \
- dev->name, __func__ , ##arg); } while (0)
+#define em28xx_coredbg(fmt, arg...) do { \
+ if (core_debug) \
+ dev_printk(KERN_DEBUG, &dev->intf->dev, \
+ "core: %s: " fmt, __func__, ## arg); \
+} while (0)
static unsigned int reg_debug;
module_param(reg_debug, int, 0644);
MODULE_PARM_DESC(reg_debug, "enable debug messages [URB reg]");
-#define em28xx_regdbg(fmt, arg...) do {\
- if (reg_debug) \
- printk(KERN_INFO "%s %s :"fmt, \
- dev->name, __func__ , ##arg); } while (0)
+#define em28xx_regdbg(fmt, arg...) do { \
+ if (reg_debug) \
+ dev_printk(KERN_DEBUG, &dev->intf->dev, \
+ "reg: %s: " fmt, __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) \
- printk(KERN_INFO "%s %s :"fmt, \
- dev->name, __func__ , ##arg); } while (0)
+/* FIXME: don't abuse core_debug */
+#define em28xx_isocdbg(fmt, arg...) do { \
+ if (core_debug) \
+ dev_printk(KERN_DEBUG, &dev->intf->dev, \
+ "core: %s: " fmt, __func__, ## arg); \
+} while (0)
/*
* em28xx_read_reg_req()
* reads data from the usb device specifying bRequest
*/
int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
- char *buf, int len)
+ char *buf, int len)
{
int ret;
- int pipe = usb_rcvctrlpipe(dev->udev, 0);
+ struct usb_device *udev = interface_to_usbdev(dev->intf);
+ int pipe = usb_rcvctrlpipe(udev, 0);
if (dev->disconnected)
return -ENODEV;
@@ -83,23 +76,17 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
if (len > URB_MAX_CTRL_SIZE)
return -EINVAL;
- if (reg_debug) {
- printk(KERN_DEBUG "(pipe 0x%08x): "
- "IN: %02x %02x %02x %02x %02x %02x %02x %02x ",
- pipe,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- req, 0, 0,
- reg & 0xff, reg >> 8,
- len & 0xff, len >> 8);
- }
-
mutex_lock(&dev->ctrl_urb_lock);
- ret = usb_control_msg(dev->udev, pipe, req,
+ ret = usb_control_msg(udev, pipe, req,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0x0000, reg, dev->urb_buf, len, HZ);
+ 0x0000, reg, dev->urb_buf, len, 1000);
if (ret < 0) {
- if (reg_debug)
- printk(" failed!\n");
+ em28xx_regdbg("(pipe 0x%08x): IN: %02x %02x %02x %02x %02x %02x %02x %02x failed with error %i\n",
+ pipe,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ req, 0, 0,
+ reg & 0xff, reg >> 8,
+ len & 0xff, len >> 8, ret);
mutex_unlock(&dev->ctrl_urb_lock);
return usb_translate_errors(ret);
}
@@ -109,14 +96,11 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
mutex_unlock(&dev->ctrl_urb_lock);
- if (reg_debug) {
- int byte;
-
- printk("<<<");
- for (byte = 0; byte < len; byte++)
- printk(" %02x", (unsigned char)buf[byte]);
- printk("\n");
- }
+ em28xx_regdbg("(pipe 0x%08x): IN: %02x %02x %02x %02x %02x %02x %02x %02x <<< %*ph\n",
+ pipe, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ req, 0, 0,
+ reg & 0xff, reg >> 8,
+ len & 0xff, len >> 8, len, buf);
return ret;
}
@@ -148,42 +132,41 @@ EXPORT_SYMBOL_GPL(em28xx_read_reg);
* sends data to the usb device, specifying bRequest
*/
int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
- int len)
+ int len)
{
int ret;
- int pipe = usb_sndctrlpipe(dev->udev, 0);
+ struct usb_device *udev = interface_to_usbdev(dev->intf);
+ int pipe = usb_sndctrlpipe(udev, 0);
if (dev->disconnected)
return -ENODEV;
- if ((len < 1) || (len > URB_MAX_CTRL_SIZE))
+ if (len < 1 || len > URB_MAX_CTRL_SIZE)
return -EINVAL;
- if (reg_debug) {
- int byte;
-
- printk(KERN_DEBUG "(pipe 0x%08x): "
- "OUT: %02x %02x %02x %02x %02x %02x %02x %02x >>>",
- pipe,
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- req, 0, 0,
- reg & 0xff, reg >> 8,
- len & 0xff, len >> 8);
-
- for (byte = 0; byte < len; byte++)
- printk(" %02x", (unsigned char)buf[byte]);
- printk("\n");
- }
-
mutex_lock(&dev->ctrl_urb_lock);
memcpy(dev->urb_buf, buf, len);
- ret = usb_control_msg(dev->udev, pipe, req,
+ ret = usb_control_msg(udev, pipe, req,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0x0000, reg, dev->urb_buf, len, HZ);
+ 0x0000, reg, dev->urb_buf, len, 1000);
mutex_unlock(&dev->ctrl_urb_lock);
- if (ret < 0)
+ if (ret < 0) {
+ em28xx_regdbg("(pipe 0x%08x): OUT: %02x %02x %02x %02x %02x %02x %02x %02x >>> %*ph failed with error %i\n",
+ pipe,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ req, 0, 0,
+ reg & 0xff, reg >> 8,
+ len & 0xff, len >> 8, len, buf, ret);
return usb_translate_errors(ret);
+ }
+
+ em28xx_regdbg("(pipe 0x%08x): OUT: %02x %02x %02x %02x %02x %02x %02x %02x >>> %*ph\n",
+ pipe,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ req, 0, 0,
+ reg & 0xff, reg >> 8,
+ len & 0xff, len >> 8, len, buf);
if (dev->wait_after_write)
msleep(dev->wait_after_write);
@@ -210,7 +193,7 @@ EXPORT_SYMBOL_GPL(em28xx_write_reg);
* the actual value
*/
int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
- u8 bitmask)
+ u8 bitmask)
{
int oldval;
u8 newval;
@@ -219,31 +202,53 @@ int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
if (oldval < 0)
return oldval;
- newval = (((u8) oldval) & ~bitmask) | (val & bitmask);
+ newval = (((u8)oldval) & ~bitmask) | (val & bitmask);
return em28xx_write_regs(dev, reg, &newval, 1);
}
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");
+ dev_warn(&dev->intf->dev,
+ "AC97 command still being executed: not handled properly!\n");
return -EBUSY;
}
@@ -255,7 +260,7 @@ int em28xx_read_ac97(struct em28xx *dev, u8 reg)
{
int ret;
u8 addr = (reg & 0x7f) | 0x80;
- u16 val;
+ __le16 val;
ret = em28xx_is_ac97_ready(dev);
if (ret < 0)
@@ -290,7 +295,7 @@ int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val)
if (ret < 0)
return ret;
- ret = em28xx_write_regs(dev, EM28XX_R40_AC97LSB, (u8 *) &value, 2);
+ ret = em28xx_write_regs(dev, EM28XX_R40_AC97LSB, (u8 *)&value, 2);
if (ret < 0)
return ret;
@@ -322,8 +327,9 @@ static int set_ac97_input(struct em28xx *dev)
int ret, i;
enum em28xx_amux amux = dev->ctl_ainput;
- /* EM28XX_AMUX_VIDEO2 is a special case used to indicate that
- em28xx should point to LINE IN, while AC97 should use VIDEO
+ /*
+ * EM28XX_AMUX_VIDEO2 is a special case used to indicate that
+ * em28xx should point to LINE IN, while AC97 should use VIDEO
*/
if (amux == EM28XX_AMUX_VIDEO2)
amux = EM28XX_AMUX_VIDEO;
@@ -336,8 +342,9 @@ static int set_ac97_input(struct em28xx *dev)
ret = em28xx_write_ac97(dev, inputs[i].reg, 0x8000);
if (ret < 0)
- em28xx_warn("couldn't setup AC97 register %d\n",
- inputs[i].reg);
+ dev_warn(&dev->intf->dev,
+ "couldn't setup AC97 register %d\n",
+ inputs[i].reg);
}
return 0;
}
@@ -358,9 +365,9 @@ static int em28xx_set_audio_source(struct em28xx *dev)
return ret;
}
- if (dev->board.has_msp34xx)
+ if (dev->has_msp34xx) {
input = EM28XX_AUDIO_SRC_TUNER;
- else {
+ } else {
switch (dev->ctl_ainput) {
case EM28XX_AMUX_VIDEO:
input = EM28XX_AUDIO_SRC_TUNER;
@@ -379,7 +386,7 @@ static int em28xx_set_audio_source(struct em28xx *dev)
ret = em28xx_write_reg_bits(dev, EM28XX_R0E_AUDIOSRC, input, 0xc0);
if (ret < 0)
return ret;
- msleep(5);
+ usleep_range(10000, 11000);
switch (dev->audio_mode.ac97) {
case EM28XX_NO_AC97:
@@ -409,19 +416,22 @@ int em28xx_audio_analog_set(struct em28xx *dev)
int ret, i;
u8 xclk;
- if (!dev->audio_mode.has_audio)
- return 0;
+ /* Set GPIOs here for boards without audio */
+ if (dev->int_audio_type == EM28XX_INT_AUDIO_NONE)
+ return em28xx_gpio_set(dev, INPUT(dev->ctl_input)->gpio);
- /* It is assumed that all devices use master volume for output.
- It would be possible to use also line output.
+ /*
+ * It is assumed that all devices use master volume for output.
+ * It would be possible to use also line output.
*/
if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
/* Mute all outputs */
for (i = 0; i < ARRAY_SIZE(outputs); i++) {
ret = em28xx_write_ac97(dev, outputs[i].reg, 0x8000);
if (ret < 0)
- em28xx_warn("couldn't setup AC97 register %d\n",
- outputs[i].reg);
+ dev_warn(&dev->intf->dev,
+ "couldn't setup AC97 register %d\n",
+ outputs[i].reg);
}
}
@@ -432,7 +442,7 @@ int em28xx_audio_analog_set(struct em28xx *dev)
ret = em28xx_write_reg(dev, EM28XX_R0F_XCLK, xclk);
if (ret < 0)
return ret;
- msleep(10);
+ usleep_range(10000, 11000);
/* Selects the proper audio input */
ret = em28xx_set_audio_source(dev);
@@ -458,15 +468,18 @@ int em28xx_audio_analog_set(struct em28xx *dev)
ret = em28xx_write_ac97(dev, outputs[i].reg,
vol);
if (ret < 0)
- em28xx_warn("couldn't setup AC97 register %d\n",
- outputs[i].reg);
+ dev_warn(&dev->intf->dev,
+ "couldn't setup AC97 register %d\n",
+ outputs[i].reg);
}
if (dev->ctl_aoutput & EM28XX_AOUT_PCM_IN) {
int sel = ac97_return_record_select(dev->ctl_aoutput);
- /* Use the same input for both left and right
- channels */
+ /*
+ * Use the same input for both left and right
+ * channels
+ */
sel |= (sel << 8);
em28xx_write_ac97(dev, AC97_REC_SEL, sel);
@@ -480,44 +493,49 @@ EXPORT_SYMBOL_GPL(em28xx_audio_analog_set);
int em28xx_audio_setup(struct em28xx *dev)
{
int vid1, vid2, feat, cfg;
- u32 vid;
+ u32 vid = 0;
+ u8 i2s_samplerates;
- if (dev->chip_id == CHIP_ID_EM2870 || dev->chip_id == CHIP_ID_EM2874
- || dev->chip_id == CHIP_ID_EM28174) {
+ 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;
+ dev->int_audio_type = EM28XX_INT_AUDIO_NONE;
+ dev->usb_audio_type = EM28XX_USB_AUDIO_NONE;
return 0;
}
- dev->audio_mode.has_audio = true;
-
/* See how this device is configured */
cfg = em28xx_read_reg(dev, EM28XX_R00_CHIPCFG);
- em28xx_info("Config register raw data: 0x%02x\n", cfg);
- if (cfg < 0) {
- /* Register read error? */
- cfg = EM28XX_CHIPCFG_AC97; /* Be conservative */
+ dev_info(&dev->intf->dev, "Config register raw data: 0x%02x\n", cfg);
+ if (cfg < 0) { /* Register read error */
+ /* Be conservative */
+ dev->int_audio_type = EM28XX_INT_AUDIO_AC97;
} else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) == 0x00) {
/* The device doesn't have vendor audio at all */
- dev->has_alsa_audio = false;
- dev->audio_mode.has_audio = false;
+ dev->int_audio_type = EM28XX_INT_AUDIO_NONE;
+ dev->usb_audio_type = EM28XX_USB_AUDIO_NONE;
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) {
+ dev->int_audio_type = EM28XX_INT_AUDIO_I2S;
+ if (dev->chip_id < CHIP_ID_EM2860 &&
+ (cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
+ EM2820_CHIPCFG_I2S_1_SAMPRATE)
+ i2s_samplerates = 1;
+ else if (dev->chip_id >= CHIP_ID_EM2860 &&
+ (cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
+ EM2860_CHIPCFG_I2S_5_SAMPRATES)
+ i2s_samplerates = 5;
+ else
+ i2s_samplerates = 3;
+ dev_info(&dev->intf->dev, "I2S Audio (%d sample rate(s))\n",
+ i2s_samplerates);
/* Skip the code that does AC97 vendor detection */
dev->audio_mode.ac97 = EM28XX_NO_AC97;
goto init_audio;
+ } else {
+ dev->int_audio_type = EM28XX_INT_AUDIO_AC97;
}
dev->audio_mode.ac97 = EM28XX_AC97_OTHER;
@@ -529,10 +547,12 @@ int em28xx_audio_setup(struct em28xx *dev)
* Note: (some) em2800 devices without eeprom reports 0x91 on
* CHIPCFG register, even not having an AC97 chip
*/
- em28xx_warn("AC97 chip type couldn't be determined\n");
+ dev_warn(&dev->intf->dev,
+ "AC97 chip type couldn't be determined\n");
dev->audio_mode.ac97 = EM28XX_NO_AC97;
- dev->has_alsa_audio = false;
- dev->audio_mode.has_audio = false;
+ if (dev->usb_audio_type == EM28XX_USB_AUDIO_VENDOR)
+ dev->usb_audio_type = EM28XX_USB_AUDIO_NONE;
+ dev->int_audio_type = EM28XX_INT_AUDIO_NONE;
goto init_audio;
}
@@ -541,19 +561,16 @@ int em28xx_audio_setup(struct em28xx *dev)
goto init_audio;
vid = vid1 << 16 | vid2;
-
- dev->audio_mode.ac97_vendor_id = vid;
- em28xx_warn("AC97 vendor ID = 0x%08x\n", vid);
+ dev_warn(&dev->intf->dev, "AC97 vendor ID = 0x%08x\n", vid);
feat = em28xx_read_ac97(dev, AC97_RESET);
if (feat < 0)
goto init_audio;
- dev->audio_mode.ac97_feat = feat;
- em28xx_warn("AC97 features = 0x%04x\n", feat);
+ dev_warn(&dev->intf->dev, "AC97 features = 0x%04x\n", feat);
/* Try to identify what audio processor we have */
- if (((vid == 0xffffffff) || (vid == 0x83847650)) && (feat == 0x6a90))
+ if ((vid == 0xffffffff || vid == 0x83847650) && feat == 0x6a90)
dev->audio_mode.ac97 = EM28XX_AC97_EM202;
else if ((vid >> 8) == 0x838476)
dev->audio_mode.ac97 = EM28XX_AC97_SIGMATEL;
@@ -562,17 +579,20 @@ init_audio:
/* Reports detected AC97 processor */
switch (dev->audio_mode.ac97) {
case EM28XX_NO_AC97:
- em28xx_info("No AC97 audio processor\n");
+ dev_info(&dev->intf->dev, "No AC97 audio processor\n");
break;
case EM28XX_AC97_EM202:
- em28xx_info("Empia 202 AC97 audio processor detected\n");
+ dev_info(&dev->intf->dev,
+ "Empia 202 AC97 audio processor detected\n");
break;
case EM28XX_AC97_SIGMATEL:
- em28xx_info("Sigmatel audio processor detected(stac 97%02x)\n",
- dev->audio_mode.ac97_vendor_id & 0xff);
+ dev_info(&dev->intf->dev,
+ "Sigmatel audio processor detected (stac 97%02x)\n",
+ vid & 0xff);
break;
case EM28XX_AC97_OTHER:
- em28xx_warn("Unknown AC97 audio processor detected!\n");
+ dev_warn(&dev->intf->dev,
+ "Unknown AC97 audio processor detected!\n");
break;
default:
break;
@@ -582,298 +602,108 @@ 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)
{
int rc;
+ const struct em28xx_led *led = NULL;
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;
+ if (dev->dvb_xfer_bulk) {
+ /* Max Tx Size = 188 * 256 = 48128 - LCM(188,512) * 2 */
+ em28xx_write_reg(dev, (dev->ts == PRIMARY_TS) ?
+ EM2874_R5D_TS1_PKT_SIZE :
+ EM2874_R5E_TS2_PKT_SIZE,
+ 0xff);
+ } else {
+ /* ISOC Maximum Transfer Size = 188 * 5 */
+ em28xx_write_reg(dev, (dev->ts == PRIMARY_TS) ?
+ EM2874_R5D_TS1_PKT_SIZE :
+ EM2874_R5E_TS2_PKT_SIZE,
+ dev->dvb_max_pkt_size_isoc / 188);
}
+ if (dev->ts == PRIMARY_TS)
+ rc = em28xx_write_reg_bits(dev,
+ EM2874_R5F_TS_ENABLE,
+ start ? EM2874_TS1_CAPTURE_ENABLE : 0x00,
+ EM2874_TS1_CAPTURE_ENABLE | EM2874_TS1_FILTER_ENABLE | EM2874_TS1_NULL_DISCARD);
+ else
+ rc = em28xx_write_reg_bits(dev,
+ EM2874_R5F_TS_ENABLE,
+ start ? EM2874_TS2_CAPTURE_ENABLE : 0x00,
+ EM2874_TS2_CAPTURE_ENABLE | EM2874_TS2_FILTER_ENABLE | EM2874_TS2_NULL_DISCARD);
+ } else {
+ /* 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;
- /* Enable Transport Stream */
- rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE,
- EM2874_TS1_CAPTURE_ENABLE,
- EM2874_TS1_CAPTURE_ENABLE);
- return rc;
- }
+ if (start) {
+ if (dev->is_webcam)
+ rc = em28xx_write_reg(dev, 0x13, 0x0c);
+ /* Enable video capture */
+ rc = em28xx_write_reg(dev, 0x48, 0x00);
+ if (rc < 0)
+ 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 (dev->mode == EM28XX_ANALOG_MODE)
+ rc = em28xx_write_reg(dev,
+ EM28XX_R12_VINENABLE,
+ 0x67);
+ else
+ rc = em28xx_write_reg(dev,
+ EM28XX_R12_VINENABLE,
+ 0x37);
+ if (rc < 0)
+ return rc;
- if (!start) {
- /* disable video capture */
- rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x27);
- return rc;
+ usleep_range(10000, 11000);
+ } else {
+ /* disable video capture */
+ rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x27);
+ }
}
- 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);
+ led = em28xx_find_led(dev, EM28XX_LED_ANALOG_CAPTURING);
+ else if (dev->ts == PRIMARY_TS)
+ led = em28xx_find_led(dev, EM28XX_LED_DIGITAL_CAPTURING);
else
- rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x37);
+ led = em28xx_find_led(dev, EM28XX_LED_DIGITAL_CAPTURING_TS2);
- msleep(6);
+ if (led)
+ em28xx_write_reg_bits(dev, led->gpio_reg,
+ (!start ^ led->inverted) ?
+ ~led->gpio_mask : led->gpio_mask,
+ led->gpio_mask);
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);
-
- 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 */
-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;
- }
- 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_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;
-}
-
-int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio)
+int em28xx_gpio_set(struct em28xx *dev, const struct em28xx_reg_seq *gpio)
{
int rc = 0;
@@ -886,7 +716,7 @@ int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio)
em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x67);
else
em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x37);
- msleep(6);
+ usleep_range(10000, 11000);
}
/* Send GPIO reset sequences specified at board entry */
@@ -930,9 +760,9 @@ int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode)
}
EXPORT_SYMBOL_GPL(em28xx_set_mode);
-/* ------------------------------------------------------------------
- URB control
- ------------------------------------------------------------------*/
+/*
+ *URB control
+ */
/*
* URB completion handler for isoc/bulk transfers
@@ -940,6 +770,7 @@ EXPORT_SYMBOL_GPL(em28xx_set_mode);
static void em28xx_irq_callback(struct urb *urb)
{
struct em28xx *dev = urb->context;
+ unsigned long flags;
int i;
switch (urb->status) {
@@ -951,14 +782,14 @@ static void em28xx_irq_callback(struct urb *urb)
case -ESHUTDOWN:
return;
default: /* error */
- em28xx_isocdbg("urb completition error %d.\n", urb->status);
+ em28xx_isocdbg("urb completion error %d.\n", urb->status);
break;
}
/* Copy data from URB */
- spin_lock(&dev->slock);
+ spin_lock_irqsave(&dev->slock, flags);
dev->usb_ctl.urb_data_copy(dev, urb);
- spin_unlock(&dev->slock);
+ spin_unlock_irqrestore(&dev->slock, flags);
/* Reset urb buffers */
for (i = 0; i < urb->number_of_packets; i++) {
@@ -984,8 +815,7 @@ void em28xx_uninit_usb_xfer(struct em28xx *dev, enum em28xx_mode mode)
struct em28xx_usb_bufs *usb_bufs;
int i;
- em28xx_isocdbg("em28xx: called em28xx_uninit_usb_xfer in mode %d\n",
- mode);
+ em28xx_isocdbg("called %s in mode %d\n", __func__, mode);
if (mode == EM28XX_DIGITAL_MODE)
usb_bufs = &dev->usb_ctl.digital_bufs;
@@ -1000,23 +830,16 @@ void em28xx_uninit_usb_xfer(struct em28xx *dev, enum em28xx_mode mode)
else
usb_unlink_urb(urb);
- if (usb_bufs->transfer_buffer[i]) {
- usb_free_coherent(dev->udev,
- urb->transfer_buffer_length,
- usb_bufs->transfer_buffer[i],
- urb->transfer_dma);
- }
usb_free_urb(urb);
usb_bufs->urb[i] = NULL;
}
- usb_bufs->transfer_buffer[i] = NULL;
}
kfree(usb_bufs->urb);
- kfree(usb_bufs->transfer_buffer);
+ kfree(usb_bufs->buf);
usb_bufs->urb = NULL;
- usb_bufs->transfer_buffer = NULL;
+ usb_bufs->buf = NULL;
usb_bufs->num_bufs = 0;
em28xx_capture_start(dev, 0);
@@ -1032,7 +855,7 @@ void em28xx_stop_urbs(struct em28xx *dev)
struct urb *urb;
struct em28xx_usb_bufs *isoc_bufs = &dev->usb_ctl.digital_bufs;
- em28xx_isocdbg("em28xx: called em28xx_stop_urbs\n");
+ em28xx_isocdbg("called %s\n", __func__);
for (i = 0; i < isoc_bufs->num_bufs; i++) {
urb = isoc_bufs->urb[i];
@@ -1055,33 +878,38 @@ int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk,
int num_bufs, int max_pkt_size, int packet_multiplier)
{
struct em28xx_usb_bufs *usb_bufs;
+ struct urb *urb;
+ struct usb_device *udev = interface_to_usbdev(dev->intf);
int i;
int sb_size, pipe;
- struct urb *urb;
int j, k;
- em28xx_isocdbg("em28xx: called em28xx_alloc_isoc in mode %d\n", mode);
+ em28xx_isocdbg("em28xx: called %s in mode %d\n", __func__, mode);
- /* Check mode and if we have an endpoint for the selected
- transfer type, select buffer */
+ /*
+ * Check mode and if we have an endpoint for the selected
+ * transfer type, select buffer
+ */
if (mode == EM28XX_DIGITAL_MODE) {
if ((xfer_bulk && !dev->dvb_ep_bulk) ||
(!xfer_bulk && !dev->dvb_ep_isoc)) {
- em28xx_errdev("no endpoint for DVB mode and transfer type %d\n",
- xfer_bulk > 0);
+ dev_err(&dev->intf->dev,
+ "no endpoint for DVB mode and transfer type %d\n",
+ xfer_bulk > 0);
return -EINVAL;
}
usb_bufs = &dev->usb_ctl.digital_bufs;
} else if (mode == EM28XX_ANALOG_MODE) {
if ((xfer_bulk && !dev->analog_ep_bulk) ||
(!xfer_bulk && !dev->analog_ep_isoc)) {
- em28xx_errdev("no endpoint for analog mode and transfer type %d\n",
- xfer_bulk > 0);
+ dev_err(&dev->intf->dev,
+ "no endpoint for analog mode and transfer type %d\n",
+ xfer_bulk > 0);
return -EINVAL;
}
usb_bufs = &dev->usb_ctl.analog_bufs;
} else {
- em28xx_errdev("invalid mode selected\n");
+ dev_err(&dev->intf->dev, "invalid mode selected\n");
return -EINVAL;
}
@@ -1090,16 +918,12 @@ int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk,
usb_bufs->num_bufs = num_bufs;
- usb_bufs->urb = kzalloc(sizeof(void *)*num_bufs, GFP_KERNEL);
- if (!usb_bufs->urb) {
- em28xx_errdev("cannot alloc memory for usb buffers\n");
+ usb_bufs->urb = kcalloc(num_bufs, sizeof(void *), GFP_KERNEL);
+ if (!usb_bufs->urb)
return -ENOMEM;
- }
- usb_bufs->transfer_buffer = kzalloc(sizeof(void *)*num_bufs,
- GFP_KERNEL);
- if (!usb_bufs->transfer_buffer) {
- em28xx_errdev("cannot allocate memory for usb transfer\n");
+ usb_bufs->buf = kcalloc(num_bufs, sizeof(void *), GFP_KERNEL);
+ if (!usb_bufs->buf) {
kfree(usb_bufs->urb);
return -ENOMEM;
}
@@ -1118,43 +942,37 @@ int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk,
for (i = 0; i < usb_bufs->num_bufs; i++) {
urb = usb_alloc_urb(usb_bufs->num_packets, GFP_KERNEL);
if (!urb) {
- em28xx_err("cannot alloc usb_ctl.urb %i\n", i);
em28xx_uninit_usb_xfer(dev, mode);
return -ENOMEM;
}
usb_bufs->urb[i] = urb;
- usb_bufs->transfer_buffer[i] = usb_alloc_coherent(dev->udev,
- sb_size, GFP_KERNEL, &urb->transfer_dma);
- if (!usb_bufs->transfer_buffer[i]) {
- em28xx_err("unable to allocate %i bytes for transfer"
- " buffer %i%s\n",
- sb_size, i,
- in_interrupt() ? " while in int" : "");
+ usb_bufs->buf[i] = kzalloc(sb_size, GFP_KERNEL);
+ if (!usb_bufs->buf[i]) {
+ for (i--; i >= 0; i--)
+ kfree(usb_bufs->buf[i]);
+
em28xx_uninit_usb_xfer(dev, mode);
return -ENOMEM;
}
- memset(usb_bufs->transfer_buffer[i], 0, sb_size);
+
+ urb->transfer_flags = URB_FREE_BUFFER;
if (xfer_bulk) { /* bulk */
- pipe = usb_rcvbulkpipe(dev->udev,
+ pipe = usb_rcvbulkpipe(udev,
mode == EM28XX_ANALOG_MODE ?
dev->analog_ep_bulk :
dev->dvb_ep_bulk);
- usb_fill_bulk_urb(urb, dev->udev, pipe,
- usb_bufs->transfer_buffer[i], sb_size,
- em28xx_irq_callback, dev);
- urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
+ usb_fill_bulk_urb(urb, udev, pipe, usb_bufs->buf[i],
+ sb_size, em28xx_irq_callback, dev);
} else { /* isoc */
- pipe = usb_rcvisocpipe(dev->udev,
+ pipe = usb_rcvisocpipe(udev,
mode == EM28XX_ANALOG_MODE ?
dev->analog_ep_isoc :
dev->dvb_ep_isoc);
- usb_fill_int_urb(urb, dev->udev, pipe,
- usb_bufs->transfer_buffer[i], sb_size,
- em28xx_irq_callback, dev, 1);
- urb->transfer_flags = URB_ISO_ASAP |
- URB_NO_TRANSFER_DMA_MAP;
+ usb_fill_int_urb(urb, udev, pipe, usb_bufs->buf[i],
+ sb_size, em28xx_irq_callback, dev, 1);
+ urb->transfer_flags |= URB_ISO_ASAP;
k = 0;
for (j = 0; j < usb_bufs->num_packets; j++) {
urb->iso_frame_desc[j].offset = k;
@@ -1175,19 +993,19 @@ EXPORT_SYMBOL_GPL(em28xx_alloc_urbs);
* Allocate URBs and start IRQ
*/
int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode,
- int xfer_bulk, int num_bufs, int max_pkt_size,
+ int xfer_bulk, int num_bufs, int max_pkt_size,
int packet_multiplier,
- int (*urb_data_copy) (struct em28xx *dev, struct urb *urb))
+ int (*urb_data_copy)(struct em28xx *dev, struct urb *urb))
{
struct em28xx_dmaqueue *dma_q = &dev->vidq;
struct em28xx_dmaqueue *vbi_dma_q = &dev->vbiq;
struct em28xx_usb_bufs *usb_bufs;
+ struct usb_device *udev = interface_to_usbdev(dev->intf);
int i;
int rc;
int alloc;
- em28xx_isocdbg("em28xx: called em28xx_init_usb_xfer in mode %d\n",
- mode);
+ em28xx_isocdbg("em28xx: called %s in mode %d\n", __func__, mode);
dev->usb_ctl.urb_data_copy = urb_data_copy;
@@ -1208,10 +1026,11 @@ int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode,
}
if (xfer_bulk) {
- rc = usb_clear_halt(dev->udev, usb_bufs->urb[0]->pipe);
+ rc = usb_clear_halt(udev, usb_bufs->urb[0]->pipe);
if (rc < 0) {
- em28xx_err("failed to clear USB bulk endpoint stall/halt condition (error=%i)\n",
- rc);
+ dev_err(&dev->intf->dev,
+ "failed to clear USB bulk endpoint stall/halt condition (error=%i)\n",
+ rc);
em28xx_uninit_usb_xfer(dev, mode);
return rc;
}
@@ -1224,10 +1043,10 @@ int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode,
/* submit urbs and enables IRQ */
for (i = 0; i < usb_bufs->num_bufs; i++) {
- rc = usb_submit_urb(usb_bufs->urb[i], GFP_ATOMIC);
+ rc = usb_submit_urb(usb_bufs->urb[i], GFP_KERNEL);
if (rc) {
- em28xx_err("submit of urb %i failed (error=%i)\n", i,
- rc);
+ dev_err(&dev->intf->dev,
+ "submit of urb %i failed (error=%i)\n", i, rc);
em28xx_uninit_usb_xfer(dev, mode);
return rc;
}
@@ -1238,18 +1057,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
*/
@@ -1269,10 +1076,14 @@ int em28xx_register_extension(struct em28xx_ops *ops)
mutex_lock(&em28xx_devlist_mutex);
list_add_tail(&ops->next, &em28xx_extension_devlist);
list_for_each_entry(dev, &em28xx_devlist, devlist) {
- ops->init(dev);
+ if (ops->init) {
+ ops->init(dev);
+ if (dev->dev_next)
+ ops->init(dev->dev_next);
+ }
}
mutex_unlock(&em28xx_devlist_mutex);
- printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name);
+ pr_info("em28xx: Registered (%s) extension\n", ops->name);
return 0;
}
EXPORT_SYMBOL(em28xx_register_extension);
@@ -1283,11 +1094,15 @@ void em28xx_unregister_extension(struct em28xx_ops *ops)
mutex_lock(&em28xx_devlist_mutex);
list_for_each_entry(dev, &em28xx_devlist, devlist) {
- ops->fini(dev);
+ if (ops->fini) {
+ if (dev->dev_next)
+ ops->fini(dev->dev_next);
+ ops->fini(dev);
+ }
}
list_del(&ops->next);
mutex_unlock(&em28xx_devlist_mutex);
- printk(KERN_INFO "Em28xx: Removed (%s) extension\n", ops->name);
+ pr_info("em28xx: Removed (%s) extension\n", ops->name);
}
EXPORT_SYMBOL(em28xx_unregister_extension);
@@ -1298,8 +1113,11 @@ void em28xx_init_extension(struct em28xx *dev)
mutex_lock(&em28xx_devlist_mutex);
list_add_tail(&dev->devlist, &em28xx_devlist);
list_for_each_entry(ops, &em28xx_extension_devlist, next) {
- if (ops->init)
+ if (ops->init) {
ops->init(dev);
+ if (dev->dev_next)
+ ops->init(dev->dev_next);
+ }
}
mutex_unlock(&em28xx_devlist_mutex);
}
@@ -1310,9 +1128,46 @@ void em28xx_close_extension(struct em28xx *dev)
mutex_lock(&em28xx_devlist_mutex);
list_for_each_entry(ops, &em28xx_extension_devlist, next) {
- if (ops->fini)
+ if (ops->fini) {
+ if (dev->dev_next)
+ ops->fini(dev->dev_next);
ops->fini(dev);
+ }
}
list_del(&dev->devlist);
mutex_unlock(&em28xx_devlist_mutex);
}
+
+int em28xx_suspend_extension(struct em28xx *dev)
+{
+ const struct em28xx_ops *ops = NULL;
+
+ dev_info(&dev->intf->dev, "Suspending extensions\n");
+ mutex_lock(&em28xx_devlist_mutex);
+ list_for_each_entry(ops, &em28xx_extension_devlist, next) {
+ if (!ops->suspend)
+ continue;
+ ops->suspend(dev);
+ if (dev->dev_next)
+ ops->suspend(dev->dev_next);
+ }
+ mutex_unlock(&em28xx_devlist_mutex);
+ return 0;
+}
+
+int em28xx_resume_extension(struct em28xx *dev)
+{
+ const struct em28xx_ops *ops = NULL;
+
+ dev_info(&dev->intf->dev, "Resuming extensions\n");
+ mutex_lock(&em28xx_devlist_mutex);
+ list_for_each_entry(ops, &em28xx_extension_devlist, next) {
+ if (!ops->resume)
+ continue;
+ ops->resume(dev);
+ if (dev->dev_next)
+ ops->resume(dev->dev_next);
+ }
+ mutex_unlock(&em28xx_devlist_mutex);
+ return 0;
+}