aboutsummaryrefslogtreecommitdiff
path: root/drivers/media/video/em28xx
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-04-24 11:21:08 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2008-04-24 11:21:08 -0700
commitc328d54cd4ad120d76284e46dcca6c6cf996154a (patch)
tree104c023be66faa5fce6e0a56c0a6d13c62fd21e5 /drivers/media/video/em28xx
parent346ad4b7fe392571f19314f153db9151dbc1d82b (diff)
parentb0166ab3a6ae6d7af8d9a21a7836154963c69a11 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/v4l-dvb
* git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/v4l-dvb: (452 commits) V4L/DVB (7731): tuner-xc2028: fix signal strength calculus V4L/DVB (7730): tuner-xc2028: Fix SCODE load for MTS firmwares V4L/DVB (7729): Fix VIDIOCGAP corruption in ivtv V4L/DVB (7728): tea5761: bugzilla #10462: tea5761 autodetection code were broken V4L/DVB (7726): cx23885: Enable cx23417 support on the HVR1800 V4L/DVB (7725): cx23885: Add generic cx23417 hardware encoder support V4L/DVB (7723): pvrusb2: Clean up input selection list generation in V4L interface V4L/DVB (7722): pvrusb2: Implement FM radio support for Gotview USB2.0 DVD 2 V4L/DVB (7721): pvrusb2: Restructure cx23416 firmware loading to have a common exit point V4L/DVB (7720): pvrusb2: Fix bad error code on cx23416 firmware load failure V4L/DVB (7719): pvrusb2: Implement input selection enforcement V4L/DVB (7718): pvrusb2-dvb: update Kbuild selections V4L/DVB (7717): pvrusb2-dvb: add DVB-T support for Hauppauge pvrusb2 model 73xxx V4L/DVB (7716): pvrusb2: clean up global functions V4L/DVB (7715): pvrusb2: Clean out all use of __FUNCTION__ V4L/DVB (7714): pvrusb2: Fix hang on module removal V4L/DVB (7713): pvrusb2: Implement cleaner DVB kernel thread shutdown V4L/DVB (7712): pvrusb2: Close connect/disconnect race V4L/DVB (7711): pvrusb2: Fix race on module unload V4L/DVB (7710): pvrusb2: Implement critical digital streaming quirk for onair devices ...
Diffstat (limited to 'drivers/media/video/em28xx')
-rw-r--r--drivers/media/video/em28xx/Kconfig14
-rw-r--r--drivers/media/video/em28xx/Makefile1
-rw-r--r--drivers/media/video/em28xx/em28xx-audio.c2
-rw-r--r--drivers/media/video/em28xx/em28xx-cards.c207
-rw-r--r--drivers/media/video/em28xx/em28xx-core.c776
-rw-r--r--drivers/media/video/em28xx/em28xx-dvb.c474
-rw-r--r--drivers/media/video/em28xx/em28xx-i2c.c160
-rw-r--r--drivers/media/video/em28xx/em28xx-input.c26
-rw-r--r--drivers/media/video/em28xx/em28xx-reg.h88
-rw-r--r--drivers/media/video/em28xx/em28xx-video.c1078
-rw-r--r--drivers/media/video/em28xx/em28xx.h318
11 files changed, 1856 insertions, 1288 deletions
diff --git a/drivers/media/video/em28xx/Kconfig b/drivers/media/video/em28xx/Kconfig
index 0f7a0bd86ff..9caffed2b6b 100644
--- a/drivers/media/video/em28xx/Kconfig
+++ b/drivers/media/video/em28xx/Kconfig
@@ -1,11 +1,13 @@
config VIDEO_EM28XX
- tristate "Empia EM2800/2820/2840 USB video capture support"
+ tristate "Empia EM28xx USB video capture support"
depends on VIDEO_DEV && I2C && INPUT
select VIDEO_TUNER
select VIDEO_TVEEPROM
select VIDEO_IR
+ select VIDEOBUF_VMALLOC
select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO
select VIDEO_TVP5150 if VIDEO_HELPER_CHIPS_AUTO
+ select VIDEO_MSP3400 if VIDEO_HELPER_CHIPS_AUTO
---help---
This is a video4linux driver for Empia 28xx based TV cards.
@@ -27,3 +29,13 @@ config VIDEO_EM28XX_ALSA
To compile this driver as a module, choose M here: the
module will be called em28xx-alsa
+config VIDEO_EM28XX_DVB
+ tristate "DVB/ATSC Support for em28xx based TV cards"
+ depends on VIDEO_EM28XX && DVB_CORE
+ select DVB_LGDT330X if !DVB_FE_CUSTOMISE
+ select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+ select VIDEOBUF_DVB
+ select FW_LOADER
+ ---help---
+ This adds support for DVB cards based on the
+ Empiatech em28xx chips.
diff --git a/drivers/media/video/em28xx/Makefile b/drivers/media/video/em28xx/Makefile
index 0924550992d..3d1c3cc337f 100644
--- a/drivers/media/video/em28xx/Makefile
+++ b/drivers/media/video/em28xx/Makefile
@@ -5,6 +5,7 @@ em28xx-alsa-objs := em28xx-audio.o
obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o
obj-$(CONFIG_VIDEO_EM28XX_ALSA) += em28xx-alsa.o
+obj-$(CONFIG_VIDEO_EM28XX_DVB) += em28xx-dvb.o
EXTRA_CFLAGS += -Idrivers/media/video
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
diff --git a/drivers/media/video/em28xx/em28xx-audio.c b/drivers/media/video/em28xx/em28xx-audio.c
index 8c67f678266..92b2a6db4fd 100644
--- a/drivers/media/video/em28xx/em28xx-audio.c
+++ b/drivers/media/video/em28xx/em28xx-audio.c
@@ -51,7 +51,7 @@ MODULE_PARM_DESC(debug, "activates debug info");
#define dprintk(fmt, arg...) do { \
if (debug) \
printk(KERN_INFO "em28xx-audio %s: " fmt, \
- __FUNCTION__, ##arg); \
+ __func__, ##arg); \
} while (0)
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index aae7753fef1..50ccf377120 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -36,7 +36,6 @@
#include <media/v4l2-common.h>
#include "em28xx.h"
-#include "tuner-xc2028.h"
static int tuner = -1;
module_param(tuner, int, 0444);
@@ -52,26 +51,6 @@ struct em28xx_hash_table {
unsigned int tuner;
};
-/* Boards supported by driver */
-
-#define EM2800_BOARD_UNKNOWN 0
-#define EM2820_BOARD_UNKNOWN 1
-#define EM2820_BOARD_TERRATEC_CINERGY_250 2
-#define EM2820_BOARD_PINNACLE_USB_2 3
-#define EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 4
-#define EM2820_BOARD_MSI_VOX_USB_2 5
-#define EM2800_BOARD_TERRATEC_CINERGY_200 6
-#define EM2800_BOARD_LEADTEK_WINFAST_USBII 7
-#define EM2800_BOARD_KWORLD_USB2800 8
-#define EM2820_BOARD_PINNACLE_DVC_90 9
-#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 10
-#define EM2880_BOARD_TERRATEC_HYBRID_XS 11
-#define EM2820_BOARD_KWORLD_PVRTV2800RF 12
-#define EM2880_BOARD_TERRATEC_PRODIGY_XS 13
-#define EM2820_BOARD_PROLINK_PLAYTV_USB2 14
-#define EM2800_BOARD_VGEAR_POCKETTV 15
-#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 16
-
struct em28xx_board em28xx_boards[] = {
[EM2800_BOARD_UNKNOWN] = {
.name = "Unknown EM2800 video grabber",
@@ -200,6 +179,7 @@ struct em28xx_board em28xx_boards[] = {
.tuner_type = TUNER_XC2028,
.mts_firmware = 1,
.has_12mhz_i2s = 1,
+ .has_dvb = 1,
.decoder = EM28XX_TVP5150,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
@@ -214,9 +194,6 @@ struct em28xx_board em28xx_boards[] = {
.vmux = TVP5150_SVIDEO,
.amux = 1,
} },
-
- /* gpio's 4, 1, 0 */
- .analog_gpio = 0x003d2d,
},
[EM2880_BOARD_TERRATEC_HYBRID_XS] = {
.name = "Terratec Hybrid XS",
@@ -331,7 +308,7 @@ struct em28xx_board em28xx_boards[] = {
.name = "Kworld USB2800",
.is_em2800 = 1,
.vchannels = 3,
- .tuner_type = TUNER_PHILIPS_ATSC,
+ .tuner_type = TUNER_PHILIPS_FCV1236D,
.tda9887_conf = TDA9887_PRESENT,
.decoder = EM28XX_SAA7113,
.input = { {
@@ -453,7 +430,36 @@ struct usb_device_id em28xx_id_table [] = {
};
MODULE_DEVICE_TABLE(usb, em28xx_id_table);
-/* EEPROM hash table for devices with generic USB IDs */
+/*
+ * Reset sequences for analog/digital modes
+ */
+
+/* Board Hauppauge WinTV HVR 900 analog */
+static struct em28xx_reg_seq hauppauge_wintv_hvr_900_analog[] = {
+ {EM28XX_R08_GPIO, 0x2d, ~EM_GPIO_4, 10},
+ {0x05, 0xff, 0x10, 10},
+ { -1, -1, -1, -1},
+};
+
+/* Board Hauppauge WinTV HVR 900 digital */
+static struct em28xx_reg_seq hauppauge_wintv_hvr_900_digital[] = {
+ {EM28XX_R08_GPIO, 0x2e, ~EM_GPIO_4, 10},
+ {EM2880_R04_GPO, 0x04, 0x0f, 10},
+ {EM2880_R04_GPO, 0x0c, 0x0f, 10},
+ { -1, -1, -1, -1},
+};
+
+/* Board Hauppauge WinTV HVR 900 tuner_callback */
+static struct em28xx_reg_seq hauppauge_wintv_hvr_900_tuner_callback[] = {
+ {EM28XX_R08_GPIO, EM_GPIO_4, EM_GPIO_4, 10},
+ {EM28XX_R08_GPIO, 0, EM_GPIO_4, 10},
+ {EM28XX_R08_GPIO, EM_GPIO_4, EM_GPIO_4, 10},
+ { -1, -1, -1, -1},
+};
+
+/*
+ * EEPROM hash table for devices with generic USB IDs
+ */
static struct em28xx_hash_table em28xx_eeprom_hash [] = {
/* P/N: SA 60002070465 Tuner: TVF7533-MF */
{0x6ce05a8f, EM2820_BOARD_PROLINK_PLAYTV_USB2, TUNER_YMEC_TVF_5533MF},
@@ -465,79 +471,113 @@ static struct em28xx_hash_table em28xx_i2c_hash[] = {
{0xf51200e3, EM2800_BOARD_VGEAR_POCKETTV, TUNER_LG_PAL_NEW_TAPC},
};
+int em28xx_tuner_callback(void *ptr, int command, int arg)
+{
+ int rc = 0;
+ struct em28xx *dev = ptr;
+
+ if (dev->tuner_type != TUNER_XC2028)
+ return 0;
+
+ if (command != XC2028_TUNER_RESET)
+ return 0;
+
+ if (dev->mode == EM28XX_ANALOG_MODE)
+ rc = em28xx_gpio_set(dev, dev->tun_analog_gpio);
+ else
+ rc = em28xx_gpio_set(dev, dev->tun_digital_gpio);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(em28xx_tuner_callback);
+
+static void em28xx_set_model(struct em28xx *dev)
+{
+ dev->is_em2800 = em28xx_boards[dev->model].is_em2800;
+ dev->has_msp34xx = em28xx_boards[dev->model].has_msp34xx;
+ dev->tda9887_conf = em28xx_boards[dev->model].tda9887_conf;
+ dev->decoder = em28xx_boards[dev->model].decoder;
+ dev->video_inputs = em28xx_boards[dev->model].vchannels;
+ dev->has_12mhz_i2s = em28xx_boards[dev->model].has_12mhz_i2s;
+ dev->max_range_640_480 = em28xx_boards[dev->model].max_range_640_480;
+ dev->has_dvb = em28xx_boards[dev->model].has_dvb;
+}
+
/* Since em28xx_pre_card_setup() requires a proper dev->model,
* this won't work for boards with generic PCI IDs
*/
void em28xx_pre_card_setup(struct em28xx *dev)
{
+ int rc;
+
+ rc = em28xx_read_reg(dev, EM2880_R04_GPO);
+ if (rc >= 0)
+ dev->reg_gpo = rc;
+
+ dev->wait_after_write = 5;
+ rc = em28xx_read_reg(dev, EM28XX_R0A_CHIPID);
+ if (rc > 0) {
+ switch (rc) {
+ case CHIP_ID_EM2883:
+ em28xx_info("chip ID is em2882/em2883\n");
+ dev->wait_after_write = 0;
+ break;
+ default:
+ em28xx_info("em28xx chip ID = %d\n", rc);
+ }
+ }
+ em28xx_set_model(dev);
+
/* request some modules */
switch (dev->model) {
case EM2880_BOARD_TERRATEC_PRODIGY_XS:
case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
- case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950:
case EM2880_BOARD_TERRATEC_HYBRID_XS:
- em28xx_write_regs(dev, XCLK_REG, "\x27", 1);
- em28xx_write_regs(dev, I2C_CLK_REG, "\x40", 1);
- em28xx_write_regs(dev, 0x08, "\xff", 1);
- em28xx_write_regs(dev, 0x04, "\x00", 1);
- msleep(100);
- em28xx_write_regs(dev, 0x04, "\x08", 1);
- msleep(100);
- em28xx_write_regs(dev, 0x08, "\xff", 1);
- msleep(50);
- em28xx_write_regs(dev, 0x08, "\x2d", 1);
+ case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950:
+ em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1);
+ em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1);
msleep(50);
- em28xx_write_regs(dev, 0x08, "\x3d", 1);
+
+ /* Sets GPO/GPIO sequences for this device */
+ dev->analog_gpio = hauppauge_wintv_hvr_900_analog;
+ dev->digital_gpio = hauppauge_wintv_hvr_900_digital;
+ dev->tun_analog_gpio = hauppauge_wintv_hvr_900_tuner_callback;
+ dev->tun_digital_gpio = hauppauge_wintv_hvr_900_tuner_callback;
+
break;
}
+
+ em28xx_gpio_set(dev, dev->tun_analog_gpio);
+ em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
+
+ /* Unlock device */
+ em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
}
-static int em28xx_tuner_callback(void *ptr, int command, int arg)
+static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
{
- int rc = 0;
- struct em28xx *dev = ptr;
+ memset(ctl, 0, sizeof(*ctl));
- if (dev->tuner_type != TUNER_XC2028)
- return 0;
-
- switch (command) {
- case XC2028_TUNER_RESET:
- {
- /* GPIO and initialization codes for analog TV and radio
- This code should be complemented for DTV, since reset
- codes are different.
- */
-
- dev->em28xx_write_regs_req(dev, 0x00, 0x48, "\x00", 1);
- dev->em28xx_write_regs_req(dev, 0x00, 0x12, "\x67", 1);
-
- if (dev->analog_gpio) {
- char gpio0 = dev->analog_gpio & 0xff;
- char gpio1 = (dev->analog_gpio >> 8) & 0xff;
- char gpio4 = dev->analog_gpio >> 24;
-
- if (gpio4) {
- dev->em28xx_write_regs(dev, 0x04, &gpio4, 1);
- msleep(140);
- }
-
- msleep(6);
- dev->em28xx_write_regs(dev, 0x08, &gpio0, 1);
- msleep(10);
- dev->em28xx_write_regs(dev, 0x08, &gpio1, 1);
- msleep(5);
- }
+ ctl->fname = XC2028_DEFAULT_FIRMWARE;
+ ctl->max_len = 64;
+ ctl->mts = em28xx_boards[dev->model].mts_firmware;
+ switch (dev->model) {
+ case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
+ ctl->demod = XC3028_FE_ZARLINK456;
break;
+ case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950:
+ /* FIXME: Better to specify the needed IF */
+ ctl->demod = XC3028_FE_DEFAULT;
+ break;
+ default:
+ ctl->demod = XC3028_FE_OREN538;
}
- }
- return rc;
}
static void em28xx_config_tuner(struct em28xx *dev)
{
struct v4l2_priv_tun_config xc2028_cfg;
- struct xc2028_ctrl ctl;
struct tuner_setup tun_setup;
struct v4l2_frequency f;
@@ -552,11 +592,9 @@ static void em28xx_config_tuner(struct em28xx *dev)
em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
if (dev->tuner_type == TUNER_XC2028) {
- memset(&ctl, 0, sizeof(ctl));
+ struct xc2028_ctrl ctl;
- ctl.fname = XC2028_DEFAULT_FIRMWARE;
- ctl.max_len = 64;
- ctl.mts = em28xx_boards[dev->model].mts_firmware;
+ em28xx_setup_xc3028(dev, &ctl);
xc2028_cfg.tuner = TUNER_XC2028;
xc2028_cfg.priv = &ctl;
@@ -654,19 +692,6 @@ static int em28xx_hint_board(struct em28xx *dev)
return -1;
}
-
-static void em28xx_set_model(struct em28xx *dev)
-{
- dev->is_em2800 = em28xx_boards[dev->model].is_em2800;
- dev->has_msp34xx = em28xx_boards[dev->model].has_msp34xx;
- dev->tda9887_conf = em28xx_boards[dev->model].tda9887_conf;
- dev->decoder = em28xx_boards[dev->model].decoder;
- dev->video_inputs = em28xx_boards[dev->model].vchannels;
- dev->analog_gpio = em28xx_boards[dev->model].analog_gpio;
- dev->has_12mhz_i2s = em28xx_boards[dev->model].has_12mhz_i2s;
- dev->max_range_640_480 = em28xx_boards[dev->model].max_range_640_480;
-}
-
/* ----------------------------------------------------------------------- */
void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir)
{
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
index c1caaa855b9..f8c41d8c74c 100644
--- a/drivers/media/video/em28xx/em28xx-core.c
+++ b/drivers/media/video/em28xx/em28xx-core.c
@@ -31,104 +31,33 @@
/* #define ENABLE_DEBUG_ISOC_FRAMES */
-static unsigned int core_debug = 0;
+static unsigned int core_debug;
module_param(core_debug,int,0644);
MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
#define em28xx_coredbg(fmt, arg...) do {\
if (core_debug) \
printk(KERN_INFO "%s %s :"fmt, \
- dev->name, __FUNCTION__ , ##arg); } while (0)
+ dev->name, __func__ , ##arg); } while (0)
-static unsigned int reg_debug = 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, __FUNCTION__ , ##arg); } while (0)
-
-static unsigned int isoc_debug = 0;
-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) \
- printk(KERN_INFO "%s %s :"fmt, \
- dev->name, __FUNCTION__ , ##arg); } while (0)
+ dev->name, __func__ , ##arg); } while (0)
static int alt = EM28XX_PINOUT;
module_param(alt, int, 0644);
MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint");
-
-/*
- * em28xx_request_buffers()
- * allocate a number of buffers
- */
-u32 em28xx_request_buffers(struct em28xx *dev, u32 count)
-{
- const size_t imagesize = PAGE_ALIGN(dev->frame_size); /*needs to be page aligned cause the buffers can be mapped individually! */
- void *buff = NULL;
- u32 i;
- em28xx_coredbg("requested %i buffers with size %zi\n",
- count, imagesize);
- if (count > EM28XX_NUM_FRAMES)
- count = EM28XX_NUM_FRAMES;
-
- dev->num_frames = count;
- while (dev->num_frames > 0) {
- if ((buff = vmalloc_32(dev->num_frames * imagesize))) {
- memset(buff, 0, dev->num_frames * imagesize);
- break;
- }
- dev->num_frames--;
- }
-
- for (i = 0; i < dev->num_frames; i++) {
- dev->frame[i].bufmem = buff + i * imagesize;
- dev->frame[i].buf.index = i;
- dev->frame[i].buf.m.offset = i * imagesize;
- dev->frame[i].buf.length = dev->frame_size;
- dev->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- dev->frame[i].buf.sequence = 0;
- dev->frame[i].buf.field = V4L2_FIELD_NONE;
- dev->frame[i].buf.memory = V4L2_MEMORY_MMAP;
- dev->frame[i].buf.flags = 0;
- }
- return dev->num_frames;
-}
-
-/*
- * em28xx_queue_unusedframes()
- * add all frames that are not currently in use to the inbuffer queue
- */
-void em28xx_queue_unusedframes(struct em28xx *dev)
-{
- unsigned long lock_flags;
- u32 i;
-
- for (i = 0; i < dev->num_frames; i++)
- if (dev->frame[i].state == F_UNUSED) {
- dev->frame[i].state = F_QUEUED;
- spin_lock_irqsave(&dev->queue_lock, lock_flags);
- list_add_tail(&dev->frame[i].frame, &dev->inqueue);
- spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
- }
-}
-
-/*
- * em28xx_release_buffers()
- * free frame buffers
- */
-void em28xx_release_buffers(struct em28xx *dev)
-{
- if (dev->num_frames) {
- vfree(dev->frame[0].bufmem);
- dev->num_frames = 0;
- }
-}
+/* FIXME */
+#define em28xx_isocdbg(fmt, arg...) do {\
+ if (core_debug) \
+ printk(KERN_INFO "%s %s :"fmt, \
+ dev->name, __func__ , ##arg); } while (0)
/*
* em28xx_read_reg_req()
@@ -148,11 +77,11 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0x0000, reg, buf, len, HZ);
- if (reg_debug){
+ if (reg_debug) {
printk(ret < 0 ? " failed!\n" : "%02x values: ", ret);
- for (byte = 0; byte < len; byte++) {
+ for (byte = 0; byte < len; byte++)
printk(" %02x", (unsigned char)buf[byte]);
- }
+
printk("\n");
}
@@ -205,7 +134,10 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
unsigned char *bufs;
if (dev->state & DEV_DISCONNECTED)
- return(-ENODEV);
+ return -ENODEV;
+
+ if (len < 1)
+ return -EINVAL;
bufs = kmalloc(len, GFP_KERNEL);
@@ -214,8 +146,8 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
if (reg_debug) {
int i;
for (i = 0; i < len; ++i)
- printk (" %02x", (unsigned char)buf[i]);
- printk ("\n");
+ printk(" %02x", (unsigned char)buf[i]);
+ printk("\n");
}
if (!bufs)
@@ -224,14 +156,32 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), req,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0x0000, reg, bufs, len, HZ);
- msleep(5); /* FIXME: magic number */
+ if (dev->wait_after_write)
+ msleep(dev->wait_after_write);
+
kfree(bufs);
return ret;
}
int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len)
{
- return em28xx_write_regs_req(dev, USB_REQ_GET_STATUS, reg, buf, len);
+ int rc;
+
+ rc = em28xx_write_regs_req(dev, USB_REQ_GET_STATUS, reg, buf, len);
+
+ /* Stores GPO/GPIO values at the cache, if changed
+ Only write values should be stored, since input on a GPIO
+ register will return the input bits.
+ Not sure what happens on reading GPO register.
+ */
+ if (rc >= 0) {
+ if (reg == EM2880_R04_GPO)
+ dev->reg_gpo = buf[0];
+ else if (reg == EM28XX_R08_GPIO)
+ dev->reg_gpio = buf[0];
+ }
+
+ return rc;
}
/*
@@ -244,9 +194,20 @@ static int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
{
int oldval;
u8 newval;
- if ((oldval = em28xx_read_reg(dev, reg)) < 0)
+
+ /* Uses cache for gpo/gpio registers */
+ if (reg == EM2880_R04_GPO)
+ oldval = dev->reg_gpo;
+ else if (reg == EM28XX_R08_GPIO)
+ oldval = dev->reg_gpio;
+ else
+ oldval = em28xx_read_reg(dev, reg);
+
+ if (oldval < 0)
return oldval;
+
newval = (((u8) oldval) & ~bitmask) | (val & bitmask);
+
return em28xx_write_regs(dev, reg, &newval, 1);
}
@@ -258,20 +219,26 @@ static int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 *val)
{
int ret, i;
u8 addr = reg & 0x7f;
- if ((ret = em28xx_write_regs(dev, AC97LSB_REG, val, 2)) < 0)
+
+ ret = em28xx_write_regs(dev, EM28XX_R40_AC97LSB, val, 2);
+ if (ret < 0)
return ret;
- if ((ret = em28xx_write_regs(dev, AC97ADDR_REG, &addr, 1)) < 0)
+
+ ret = em28xx_write_regs(dev, EM28XX_R42_AC97ADDR, &addr, 1);
+ if (ret < 0)
return ret;
/* Wait up to 50 ms for AC97 command to complete */
for (i = 0; i < 10; i++) {
- if ((ret = em28xx_read_reg(dev, AC97BUSY_REG)) < 0)
+ 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");
+ em28xx_warn("AC97 command still being executed: not handled properly!\n");
return 0;
}
@@ -289,7 +256,7 @@ static int em28xx_set_audio_source(struct em28xx *dev)
else
input = EM2800_AUDIO_SRC_TUNER;
- ret = em28xx_write_regs(dev, EM2800_AUDIOSRC_REG, &input, 1);
+ ret = em28xx_write_regs(dev, EM2800_R08_AUDIOSRC, &input, 1);
if (ret < 0)
return ret;
}
@@ -315,7 +282,7 @@ static int em28xx_set_audio_source(struct em28xx *dev)
}
}
- ret = em28xx_write_reg_bits(dev, AUDIOSRC_REG, input, 0xc0);
+ ret = em28xx_write_reg_bits(dev, EM28XX_R0E_AUDIOSRC, input, 0xc0);
if (ret < 0)
return ret;
msleep(5);
@@ -323,11 +290,11 @@ static int em28xx_set_audio_source(struct em28xx *dev)
/* Sets AC97 mixer registers
This is seems to be needed, even for non-ac97 configs
*/
- ret = em28xx_write_ac97(dev, VIDEO_AC97, video);
+ ret = em28xx_write_ac97(dev, EM28XX_R14_VIDEO_AC97, video);
if (ret < 0)
return ret;
- ret = em28xx_write_ac97(dev, LINE_IN_AC97, line);
+ ret = em28xx_write_ac97(dev, EM28XX_R10_LINE_IN_AC97, line);
return ret;
}
@@ -343,7 +310,7 @@ int em28xx_audio_analog_set(struct em28xx *dev)
/* Mute */
s[1] |= 0x80;
- ret = em28xx_write_ac97(dev, MASTER_AC97, s);
+ ret = em28xx_write_ac97(dev, EM28XX_R02_MASTER_AC97, s);
if (ret < 0)
return ret;
@@ -354,7 +321,7 @@ int em28xx_audio_analog_set(struct em28xx *dev)
if (!dev->mute)
xclk |= 0x80;
- ret = em28xx_write_reg_bits(dev, XCLK_REG, xclk, 0xa7);
+ ret = em28xx_write_reg_bits(dev, EM28XX_R0F_XCLK, xclk, 0xa7);
if (ret < 0)
return ret;
msleep(10);
@@ -365,7 +332,7 @@ int em28xx_audio_analog_set(struct em28xx *dev)
/* Unmute device */
if (!dev->mute)
s[1] &= ~0x80;
- ret = em28xx_write_ac97(dev, MASTER_AC97, s);
+ ret = em28xx_write_ac97(dev, EM28XX_R02_MASTER_AC97, s);
return ret;
}
@@ -373,50 +340,68 @@ EXPORT_SYMBOL_GPL(em28xx_audio_analog_set);
int em28xx_colorlevels_set_default(struct em28xx *dev)
{
- em28xx_write_regs(dev, YGAIN_REG, "\x10", 1); /* contrast */
- em28xx_write_regs(dev, YOFFSET_REG, "\x00", 1); /* brightness */
- em28xx_write_regs(dev, UVGAIN_REG, "\x10", 1); /* saturation */
- em28xx_write_regs(dev, UOFFSET_REG, "\x00", 1);
- em28xx_write_regs(dev, VOFFSET_REG, "\x00", 1);
- em28xx_write_regs(dev, SHARPNESS_REG, "\x00", 1);
-
- em28xx_write_regs(dev, GAMMA_REG, "\x20", 1);
- em28xx_write_regs(dev, RGAIN_REG, "\x20", 1);
- em28xx_write_regs(dev, GGAIN_REG, "\x20", 1);
- em28xx_write_regs(dev, BGAIN_REG, "\x20", 1);
- em28xx_write_regs(dev, ROFFSET_REG, "\x00", 1);
- em28xx_write_regs(dev, GOFFSET_REG, "\x00", 1);
- return em28xx_write_regs(dev, BOFFSET_REG, "\x00", 1);
+ em28xx_write_regs(dev, EM28XX_R20_YGAIN, "\x10", 1); /* contrast */
+ em28xx_write_regs(dev, EM28XX_R21_YOFFSET, "\x00", 1); /* brightness */
+ em28xx_write_regs(dev, EM28XX_R22_UVGAIN, "\x10", 1); /* saturation */
+ em28xx_write_regs(dev, EM28XX_R23_UOFFSET, "\x00", 1);
+ em28xx_write_regs(dev, EM28XX_R24_VOFFSET, "\x00", 1);
+ em28xx_write_regs(dev, EM28XX_R25_SHARPNESS, "\x00", 1);
+
+ em28xx_write_regs(dev, EM28XX_R14_GAMMA, "\x20", 1);
+ em28xx_write_regs(dev, EM28XX_R15_RGAIN, "\x20", 1);
+ em28xx_write_regs(dev, EM28XX_R16_GGAIN, "\x20", 1);
+ em28xx_write_regs(dev, EM28XX_R17_BGAIN, "\x20", 1);
+ em28xx_write_regs(dev, EM28XX_R18_ROFFSET, "\x00", 1);
+ em28xx_write_regs(dev, EM28XX_R19_GOFFSET, "\x00", 1);
+ return em28xx_write_regs(dev, EM28XX_R1A_BOFFSET, "\x00", 1);
}
int em28xx_capture_start(struct em28xx *dev, int start)
{
- int ret;
+ int rc;
/* FIXME: which is the best order? */
/* video registers are sampled by VREF */
- if ((ret = em28xx_write_reg_bits(dev, USBSUSP_REG, start ? 0x10 : 0x00,
- 0x10)) < 0)
- return ret;
+ 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_regs(dev, EM28XX_R12_VINENABLE, "\x27", 1);
+ return rc;
+ }
+
/* enable video capture */
- return em28xx_write_regs(dev, VINENABLE_REG, start ? "\x67" : "\x27", 1);
+ rc = em28xx_write_regs_req(dev, 0x00, 0x48, "\x00", 1);
+
+ if (dev->mode == EM28XX_ANALOG_MODE)
+ rc = em28xx_write_regs(dev, EM28XX_R12_VINENABLE, "\x67", 1);
+ else
+ rc = em28xx_write_regs(dev, EM28XX_R12_VINENABLE, "\x37", 1);
+
+ msleep(6);
+
+ return rc;
}
int em28xx_outfmt_set_yuv422(struct em28xx *dev)
{
- em28xx_write_regs(dev, OUTFMT_REG, "\x34", 1);
- em28xx_write_regs(dev, VINMODE_REG, "\x10", 1);
- return em28xx_write_regs(dev, VINCTRL_REG, "\x11", 1);
+ em28xx_write_regs(dev, EM28XX_R27_OUTFMT, "\x34", 1);
+ em28xx_write_regs(dev, EM28XX_R10_VINMODE, "\x10", 1);
+ return em28xx_write_regs(dev, EM28XX_R11_VINCTRL, "\x11", 1);
}
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_coredbg("em28xx Scale: (%d,%d)-(%d,%d)\n",
+ xmin, ymin, xmax, ymax);
- em28xx_write_regs(dev, XMIN_REG, &xmin, 1);
- em28xx_write_regs(dev, XMAX_REG, &xmax, 1);
- em28xx_write_regs(dev, YMIN_REG, &ymin, 1);
- return em28xx_write_regs(dev, YMAX_REG, &ymax, 1);
+ 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 int em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
@@ -426,34 +411,36 @@ static int em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
u8 cheight = height;
u8 overflow = (height >> 7 & 0x02) | (width >> 8 & 0x01);
- em28xx_coredbg("em28xx Area Set: (%d,%d)\n", (width | (overflow & 2) << 7),
+ em28xx_coredbg("em28xx Area Set: (%d,%d)\n",
+ (width | (overflow & 2) << 7),
(height | (overflow & 1) << 8));
- em28xx_write_regs(dev, HSTART_REG, &hstart, 1);
- em28xx_write_regs(dev, VSTART_REG, &vstart, 1);
- em28xx_write_regs(dev, CWIDTH_REG, &cwidth, 1);
- em28xx_write_regs(dev, CHEIGHT_REG, &cheight, 1);
- return em28xx_write_regs(dev, OFLOW_REG, &overflow, 1);
+ 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);
+ return em28xx_write_regs(dev, EM28XX_R1B_OFLOW, &overflow, 1);
}
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->is_em2800)
+ if (dev->is_em2800)
mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00);
else {
u8 buf[2];
buf[0] = h;
buf[1] = h >> 8;
- em28xx_write_regs(dev, HSCALELOW_REG, (char *)buf, 2);
+ em28xx_write_regs(dev, EM28XX_R30_HSCALELOW, (char *)buf, 2);
buf[0] = v;
buf[1] = v >> 8;
- em28xx_write_regs(dev, VSCALELOW_REG, (char *)buf, 2);
- /* it seems that both H and V scalers must be active to work correctly */
+ 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, COMPR_REG, mode, 0x30);
+ return em28xx_write_reg_bits(dev, EM28XX_R26_COMPR, mode, 0x30);
}
/* FIXME: this only function read values from dev */
@@ -469,376 +456,271 @@ int em28xx_resolution_set(struct em28xx *dev)
return em28xx_scaler_set(dev, dev->hscale, dev->vscale);
}
-
-/******************* isoc transfer handling ****************************/
-
-#ifdef ENABLE_DEBUG_ISOC_FRAMES
-static void em28xx_isoc_dump(struct urb *urb)
+int em28xx_set_alternate(struct em28xx *dev)
{
- int len = 0;
- int ntrans = 0;
+ int errCode, prev_alt = dev->alt;
int i;
+ unsigned int min_pkt_size = dev->width * 2 + 4;
- printk(KERN_DEBUG "isocIrq: sf=%d np=%d ec=%x\n",
- urb->start_frame, urb->number_of_packets,
- urb->error_count);
- for (i = 0; i < urb->number_of_packets; i++) {
- unsigned char *buf =
- urb->transfer_buffer +
- urb->iso_frame_desc[i].offset;
- int alen = urb->iso_frame_desc[i].actual_length;
- if (alen > 0) {
- if (buf[0] == 0x88) {
- ntrans++;
- len += alen;
- } else if (buf[0] == 0x22) {
- printk(KERN_DEBUG
- "= l=%d nt=%d bpp=%d\n",
- len - 4 * ntrans, ntrans,
- ntrans == 0 ? 0 : len / ntrans);
- ntrans = 1;
- len = alen;
- } else
- printk(KERN_DEBUG "!\n");
+ /* 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[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[i] >
+ dev->alt_max_pkt_size[dev->alt])
+ dev->alt = i;
+ }
+
+ if (dev->alt != prev_alt) {
+ em28xx_coredbg("minimum isoc packet size: %u (alt=%d)\n",
+ min_pkt_size, dev->alt);
+ dev->max_pkt_size = dev->alt_max_pkt_size[dev->alt];
+ 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;
}
- printk(KERN_DEBUG " n=%d s=%d al=%d %x\n", i,
- urb->iso_frame_desc[i].status,
- urb->iso_frame_desc[i].actual_length,
- (unsigned int)
- *((unsigned char *)(urb->transfer_buffer +
- urb->iso_frame_desc[i].
- offset)));
}
+ return 0;
}
-#endif
-static inline int em28xx_isoc_video(struct em28xx *dev,struct em28xx_frame_t **f,
- unsigned long *lock_flags, unsigned char buf)
+int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio)
{
- if (!(buf & 0x01)) {
- if ((*f)->state == F_GRABBING) {
- /*previous frame is incomplete */
- if ((*f)->fieldbytesused < dev->field_size) {
- (*f)->state = F_ERROR;
- em28xx_isocdbg ("dropping incomplete bottom field (%i missing bytes)",
- dev->field_size-(*f)->fieldbytesused);
- } else {
- (*f)->state = F_DONE;
- (*f)->buf.bytesused = dev->frame_size;
- }
- }
- if ((*f)->state == F_DONE || (*f)->state == F_ERROR) {
- /* move current frame to outqueue and get next free buffer from inqueue */
- spin_lock_irqsave(&dev-> queue_lock, *lock_flags);
- list_move_tail(&(*f)->frame, &dev->outqueue);
- if (!list_empty(&dev->inqueue))
- (*f) = list_entry(dev-> inqueue.next,
- struct em28xx_frame_t,frame);
- else
- (*f) = NULL;
- spin_unlock_irqrestore(&dev->queue_lock,*lock_flags);
- }
- if (!(*f)) {
- em28xx_isocdbg ("new frame but no buffer is free");
- return -1;
- }
- do_gettimeofday(&(*f)->buf.timestamp);
- (*f)->buf.sequence = ++dev->frame_count;
- (*f)->buf.field = V4L2_FIELD_INTERLACED;
- (*f)->state = F_GRABBING;
- (*f)->buf.bytesused = 0;
- (*f)->top_field = 1;
- (*f)->fieldbytesused = 0;
- } else {
- /* acquiring bottom field */
- if ((*f)->state == F_GRABBING) {
- if (!(*f)->top_field) {
- (*f)->state = F_ERROR;
- em28xx_isocdbg ("unexpected begin of bottom field; discarding it");
- } else if ((*f)-> fieldbytesused < dev->field_size - 172) {
- (*f)->state = F_ERROR;
- em28xx_isocdbg ("dropping incomplete top field (%i missing bytes)",
- dev->field_size-(*f)->fieldbytesused);
- } else {
- (*f)->top_field = 0;
- (*f)->fieldbytesused = 0;
- }
+ int rc = 0;
+
+ if (!gpio)
+ return rc;
+
+ dev->em28xx_write_regs_req(dev, 0x00, 0x48, "\x00", 1);
+ if (dev->mode == EM28XX_ANALOG_MODE)
+ dev->em28xx_write_regs_req(dev, 0x00, 0x12, "\x67", 1);
+ else
+ dev->em28xx_write_regs_req(dev, 0x00, 0x12, "\x37", 1);
+ msleep(6);
+
+ /* Send GPIO reset sequences specified at board entry */
+ while (gpio->sleep >= 0) {
+ if (gpio->reg >= 0) {
+ rc = em28xx_write_reg_bits(dev,
+ gpio->reg,
+ gpio->val,
+ gpio->mask);
+ if (rc < 0)
+ return rc;
}
+ if (gpio->sleep > 0)
+ msleep(gpio->sleep);
+
+ gpio++;
}
- return (0);
+ return rc;
}
-static inline void em28xx_isoc_video_copy(struct em28xx *dev,
- struct em28xx_frame_t **f, unsigned char *buf, int len)
+int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode)
{
- void *fieldstart, *startwrite, *startread;
- int linesdone, currlinedone, offset, lencopy,remain;
+ if (dev->mode == set_mode)
+ return 0;
- if(dev->frame_size != (*f)->buf.length){
- em28xx_err("frame_size %i and buf.length %i are different!!!\n",dev->frame_size,(*f)->buf.length);
- return;
+ if (set_mode == EM28XX_MODE_UNDEFINED) {
+ dev->mode = set_mode;
+ return 0;
}
- if ((*f)->fieldbytesused + len > dev->field_size)
- len =dev->field_size - (*f)->fieldbytesused;
-
- if (buf[0] != 0x88 && buf[0] != 0x22) {
- em28xx_isocdbg("frame is not complete\n");
- startread = buf;
- len+=4;
- } else
- startread = buf + 4;
-
- remain = len;
+ dev->mode = set_mode;
- if ((*f)->top_field)
- fieldstart = (*f)->bufmem;
+ if (dev->mode == EM28XX_DIGITAL_MODE)
+ return em28xx_gpio_set(dev, dev->digital_gpio);
else
- fieldstart = (*f)->bufmem + dev->bytesperline;
-
- linesdone = (*f)->fieldbytesused / dev->bytesperline;
- currlinedone = (*f)->fieldbytesused % dev->bytesperline;
- offset = linesdone * dev->bytesperline * 2 + currlinedone;
- startwrite = fieldstart + offset;
- lencopy = dev->bytesperline - currlinedone;
- lencopy = lencopy > remain ? remain : lencopy;
-
- memcpy(startwrite, startread, lencopy);
- remain -= lencopy;
-
- while (remain > 0) {
- startwrite += lencopy + dev->bytesperline;
- startread += lencopy;
- if (dev->bytesperline > remain)
- lencopy = remain;
- else
- lencopy = dev->bytesperline;
-
- memcpy(startwrite, startread, lencopy);
- remain -= lencopy;
- }
-
- (*f)->fieldbytesused += len;
+ return em28xx_gpio_set(dev, dev->analog_gpio);
}
+EXPORT_SYMBOL_GPL(em28xx_set_mode);
+
+/* ------------------------------------------------------------------
+ URB control
+ ------------------------------------------------------------------*/
/*
- * em28xx_isoIrq()
- * handles the incoming isoc urbs and fills the frames from our inqueue
+ * IRQ callback, called by URB callback
*/
-static void em28xx_isocIrq(struct urb *urb)
+static void em28xx_irq_callback(struct urb *urb)
{
- struct em28xx *dev = urb->context;
- int i, status;
- struct em28xx_frame_t **f;
- unsigned long lock_flags;
-
- if (!dev)
- return;
-#ifdef ENABLE_DEBUG_ISOC_FRAMES
- if (isoc_debug>1)
- em28xx_isoc_dump(urb);
-#endif
-
- if (urb->status == -ENOENT)
- return;
-
- f = &dev->frame_current;
-
- if (dev->stream == STREAM_INTERRUPT) {
- dev->stream = STREAM_OFF;
- if ((*f))
- (*f)->state = F_QUEUED;
- em28xx_isocdbg("stream interrupted");
- wake_up_interruptible(&dev->wait_stream);
- }
-
- if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
- return;
-
- if (dev->stream == STREAM_ON && !list_empty(&dev->inqueue)) {
- if (!(*f))
- (*f) = list_entry(dev->inqueue.next,
- struct em28xx_frame_t, frame);
-
- for (i = 0; i < urb->number_of_packets; i++) {
- unsigned char *buf = urb->transfer_buffer +
- urb->iso_frame_desc[i].offset;
- int len = urb->iso_frame_desc[i].actual_length - 4;
-
- if (urb->iso_frame_desc[i].status) {
- em28xx_isocdbg("data error: [%d] len=%d, status=%d", i,
- urb->iso_frame_desc[i].actual_length,
- urb->iso_frame_desc[i].status);
- if (urb->iso_frame_desc[i].status != -EPROTO)
- continue;
- }
- if (urb->iso_frame_desc[i].actual_length <= 0) {
- em28xx_isocdbg("packet %d is empty",i);
- continue;
- }
- if (urb->iso_frame_desc[i].actual_length >
- urb->iso_frame_desc[i].length) {
- em28xx_isocdbg("packet bigger than packet size");
- continue;
- }
- /*new frame */
- if (buf[0] == 0x22 && buf[1] == 0x5a) {
- em28xx_isocdbg("Video frame, length=%i!",len);
-
- if (em28xx_isoc_video(dev,f,&lock_flags,buf[2]))
- break;
- } else if (buf[0]==0x33 && buf[1]==0x95 && buf[2]==0x00) {
- em28xx_isocdbg("VBI HEADER!!!");
- }
+ struct em28xx_dmaqueue *dma_q = urb->context;
+ struct em28xx *dev = container_of(dma_q, struct em28xx, vidq);
+ int rc, i;
- /* actual copying */
- if ((*f)->state == F_GRABBING) {
- em28xx_isoc_video_copy(dev,f,buf, len);
- }
- }
- }
+ /* Copy data from URB */
+ spin_lock(&dev->slock);
+ rc = dev->isoc_ctl.isoc_copy(dev, urb);
+ spin_unlock(&dev->slock);
+ /* Reset urb buffers */
for (i = 0; i < urb->number_of_packets; i++) {
urb->iso_frame_desc[i].status = 0;
urb->iso_frame_desc[i].actual_length = 0;
}
-
urb->status = 0;
- if ((status = usb_submit_urb(urb, GFP_ATOMIC))) {
- em28xx_errdev("resubmit of urb failed (error=%i)\n", status);
- dev->state |= DEV_MISCONFIGURED;
+
+ urb->status = usb_submit_urb(urb, GFP_ATOMIC);
+ if (urb->status) {
+ em28xx_isocdbg("urb resubmit failed (error=%i)\n",
+ urb->status);
}
- wake_up_interruptible(&dev->wait_frame);
- return;
}
/*
- * em28xx_uninit_isoc()
- * deallocates the buffers and urbs allocated during em28xx_init_iosc()
+ * Stop and Deallocate URBs
*/
void em28xx_uninit_isoc(struct em28xx *dev)
{
+ struct urb *urb;
int i;
- for (i = 0; i < EM28XX_NUM_BUFS; i++) {
- if (dev->urb[i]) {
- usb_kill_urb(dev->urb[i]);
- if (dev->transfer_buffer[i]) {
+ em28xx_isocdbg("em28xx: called em28xx_uninit_isoc\n");
+
+ dev->isoc_ctl.nfields = -1;
+ for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+ urb = dev->isoc_ctl.urb[i];
+ if (urb) {
+ usb_kill_urb(urb);
+ usb_unlink_urb(urb);
+ if (dev->isoc_ctl.transfer_buffer[i]) {
usb_buffer_free(dev->udev,
- dev->urb[i]->transfer_buffer_length,
- dev->transfer_buffer[i],
- dev->urb[i]->transfer_dma);
+ urb->transfer_buffer_length,
+ dev->isoc_ctl.transfer_buffer[i],
+ urb->transfer_dma);
}
- usb_free_urb(dev->urb[i]);
+ usb_free_urb(urb);
+ dev->isoc_ctl.urb[i] = NULL;
}
- dev->urb[i] = NULL;
- dev->transfer_buffer[i] = NULL;
+ dev->isoc_ctl.transfer_buffer[i] = NULL;
}
+
+ kfree(dev->isoc_ctl.urb);
+ kfree(dev->isoc_ctl.transfer_buffer);
+
+ dev->isoc_ctl.urb = NULL;
+ dev->isoc_ctl.transfer_buffer = NULL;
+ dev->isoc_ctl.num_bufs = 0;
+
em28xx_capture_start(dev, 0);
}
+EXPORT_SYMBOL_GPL(em28xx_uninit_isoc);
/*
- * em28xx_init_isoc()
- * allocates transfer buffers and submits the urbs for isoc transfer
+ * Allocate URBs and start IRQ
*/
-int em28xx_init_isoc(struct em28xx *dev)
+int em28xx_init_isoc(struct em28xx *dev, int max_packets,
+ int num_bufs, int max_pkt_size,
+ int (*isoc_copy) (struct em28xx *dev, struct urb *urb))
{
- /* change interface to 3 which allows the biggest packet sizes */
- int i, errCode;
- int sb_size;
-
- em28xx_set_alternate(dev);
- sb_size = EM28XX_NUM_PACKETS * dev->max_pkt_size;
-
- /* reset streaming vars */
- dev->frame_current = NULL;
- dev->frame_count = 0;
-
- /* allocate urbs */
- for (i = 0; i < EM28XX_NUM_BUFS; i++) {
- struct urb *urb;
- int j;
- /* allocate transfer buffer */
- urb = usb_alloc_urb(EM28XX_NUM_PACKETS, GFP_KERNEL);
- if (!urb){
- em28xx_errdev("cannot alloc urb %i\n", i);
+ struct em28xx_dmaqueue *dma_q = &dev->vidq;
+ int i;
+ int sb_size, pipe;
+ struct urb *urb;
+ int j, k;
+ int rc;
+
+ em28xx_isocdbg("em28xx: called em28xx_prepare_isoc\n");
+
+ /* De-allocates all pending stuff */
+ em28xx_uninit_isoc(dev);
+
+ dev->isoc_ctl.isoc_copy = isoc_copy;
+ dev->isoc_ctl.num_bufs = num_bufs;
+
+ dev->isoc_ctl.urb = kzalloc(sizeof(void *)*num_bufs, GFP_KERNEL);
+ if (!dev->isoc_ctl.urb) {
+ em28xx_errdev("cannot alloc memory for usb buffers\n");
+ return -ENOMEM;
+ }
+
+ dev->isoc_ctl.transfer_buffer = kzalloc(sizeof(void *)*num_bufs,
+ GFP_KERNEL);
+ if (!dev->isoc_ctl.urb) {
+ em28xx_errdev("cannot allocate memory for usbtransfer\n");
+ kfree(dev->isoc_ctl.urb);
+ return -ENOMEM;
+ }
+
+ dev->isoc_ctl.max_pkt_size = max_pkt_size;
+ dev->isoc_ctl.buf = NULL;
+
+ sb_size = max_packets * dev->isoc_ctl.max_pkt_size;
+
+ /* allocate urbs and transfer buffers */
+ for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+ urb = usb_alloc_urb(max_packets, GFP_KERNEL);
+ if (!urb) {
+ em28xx_err("cannot alloc isoc_ctl.urb %i\n", i);
em28xx_uninit_isoc(dev);
return -ENOMEM;
}
- dev->transfer_buffer[i] = usb_buffer_alloc(dev->udev, sb_size,
- GFP_KERNEL,
- &urb->transfer_dma);
- if (!dev->transfer_buffer[i]) {
- em28xx_errdev
- ("unable to allocate %i bytes for transfer buffer %i\n",
- sb_size, i);
+ dev->isoc_ctl.urb[i] = urb;
+
+ dev->isoc_ctl.transfer_buffer[i] = usb_buffer_alloc(dev->udev,
+ sb_size, GFP_KERNEL, &urb->transfer_dma);
+ if (!dev->isoc_ctl.transfer_buffer[i]) {
+ em28xx_err("unable to allocate %i bytes for transfer"
+ " buffer %i%s\n",
+ sb_size, i,
+ in_interrupt()?" while in int":"");
em28xx_uninit_isoc(dev);
- usb_free_urb(urb);
return -ENOMEM;
}
- memset(dev->transfer_buffer[i], 0, sb_size);
- urb->dev = dev->udev;
- urb->context = dev;
- urb->pipe = usb_rcvisocpipe(dev->udev, 0x82);
- urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
- urb->interval = 1;
- urb->transfer_buffer = dev->transfer_buffer[i];
- urb->complete = em28xx_isocIrq;
- urb->number_of_packets = EM28XX_NUM_PACKETS;
- urb->transfer_buffer_length = sb_size;
- for (j = 0; j < EM28XX_NUM_PACKETS; j++) {
- urb->iso_frame_desc[j].offset = j * dev->max_pkt_size;
- urb->iso_frame_desc[j].length = dev->max_pkt_size;
+ memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size);
+
+ /* FIXME: this is a hack - should be
+ 'desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK'
+ should also be using 'desc.bInterval'
+ */
+ pipe = usb_rcvisocpipe(dev->udev,
+ dev->mode == EM28XX_ANALOG_MODE ? 0x82 : 0x84);
+
+ usb_fill_int_urb(urb, dev->udev, pipe,
+ dev->isoc_ctl.transfer_buffer[i], sb_size,
+ em28xx_irq_callback, dma_q, 1);
+
+ urb->number_of_packets = max_packets;
+ urb->transfer_flags = URB_ISO_ASAP;
+
+ k = 0;
+ for (j = 0; j < max_packets; j++) {
+ urb->iso_frame_desc[j].offset = k;
+ urb->iso_frame_desc[j].length =
+ dev->isoc_ctl.max_pkt_size;
+ k += dev->isoc_ctl.max_pkt_size;
}
- dev->urb[i] = urb;
}
- /* submit urbs */
- em28xx_coredbg("Submitting %d urbs of %d packets (%d each)\n",
- EM28XX_NUM_BUFS, EM28XX_NUM_PACKETS, dev->max_pkt_size);
- for (i = 0; i < EM28XX_NUM_BUFS; i++) {
- errCode = usb_submit_urb(dev->urb[i], GFP_KERNEL);
- if (errCode) {
- em28xx_errdev("submit of urb %i failed (error=%i)\n", i,
- errCode);
- em28xx_uninit_isoc(dev);
- return errCode;
- }
- }
-
- return 0;
-}
-
-int em28xx_set_alternate(struct em28xx *dev)
-{
- int errCode, prev_alt = dev->alt;
- int i;
- unsigned int min_pkt_size = dev->bytesperline+4;
-
- /* When image size is bigger than a ceirtain value,
- the frame size should be increased, otherwise, only
- green screen will be received.
- */
- if (dev->frame_size > 720*240*2)
- min_pkt_size *= 2;
+ init_waitqueue_head(&dma_q->wq);
- for (i = 0; i < dev->num_alt; i++)
- if (dev->alt_max_pkt_size[i] >= min_pkt_size)
- break;
- dev->alt = i;
+ em28xx_capture_start(dev, 1);
- if (dev->alt != prev_alt) {
- em28xx_coredbg("minimum isoc packet size: %u (alt=%d)\n",
- min_pkt_size, dev->alt);
- dev->max_pkt_size = dev->alt_max_pkt_size[dev->alt];
- 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;
+ /* submit urbs and enables IRQ */
+ for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+ rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC);
+ if (rc) {
+ em28xx_err("submit of urb %i failed (error=%i)\n", i,
+ rc);
+ em28xx_uninit_isoc(dev);
+ return rc;
}
}
+
return 0;
}
+EXPORT_SYMBOL_GPL(em28xx_init_isoc);
diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c
new file mode 100644
index 00000000000..7df81575b7f
--- /dev/null
+++ b/drivers/media/video/em28xx/em28xx-dvb.c
@@ -0,0 +1,474 @@
+/*
+ DVB device driver for em28xx
+
+ (c) 2008 Mauro Carvalho Chehab <mchehab@infradead.org>
+
+ (c) 2008 Devin Heitmueller <devin.heitmueller@gmail.com>
+ - Fixes for the driver to properly work with HVR-950
+
+ (c) 2008 Aidan Thornton <makosoft@googlemail.com>
+
+ Based on cx88-dvb, saa7134-dvb and videobuf-dvb originally written by:
+ (c) 2004, 2005 Chris Pascoe <c.pascoe@itee.uq.edu.au>
+ (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+
+ 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/usb.h>
+
+#include "em28xx.h"
+#include <media/v4l2-common.h>
+#include <media/videobuf-vmalloc.h>
+
+#include "lgdt330x.h"
+#include "zl10353.h"
+
+MODULE_DESCRIPTION("driver for em28xx based DVB cards");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
+MODULE_LICENSE("GPL");
+
+static unsigned int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable debug messages [dvb]");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define dprintk(level, fmt, arg...) do { \
+if (debug >= level) \
+ printk(KERN_DEBUG "%s/2-dvb: " fmt, dev->name, ## arg); \
+} while (0)
+
+#define EM28XX_DVB_NUM_BUFS 5
+#define EM28XX_DVB_MAX_PACKETSIZE 564
+#define EM28XX_DVB_MAX_PACKETS 64
+
+struct em28xx_dvb {
+ struct dvb_frontend *frontend;
+
+ /* feed count management */
+ struct mutex lock;
+ int nfeeds;
+
+ /* general boilerplate stuff */
+ struct dvb_adapter adapter;
+ struct dvb_demux demux;
+ struct dmxdev dmxdev;
+ struct dmx_frontend fe_hw;
+ struct dmx_frontend fe_mem;
+ struct dvb_net net;
+};
+
+
+static inline void print_err_status(struct em28xx *dev,
+ int packet, int status)
+{
+ char *errmsg = "Unknown";
+
+ switch (status) {
+ case -ENOENT:
+ errmsg = "unlinked synchronuously";
+ break;
+ case -ECONNRESET:
+ errmsg = "unlinked asynchronuously";
+ break;
+ case -ENOSR:
+ errmsg = "Buffer error (overrun)";
+ break;
+ case -EPIPE:
+ errmsg = "Stalled (device not responding)";
+ break;
+ case -EOVERFLOW:
+ errmsg = "Babble (bad cable?)";
+ break;
+ case -EPROTO:
+ errmsg = "Bit-stuff error (bad cable?)";
+ break;
+ case -EILSEQ:
+ errmsg = "CRC/Timeout (could be anything)";
+ break;
+ case -ETIME:
+ errmsg = "Device does not respond";
+ break;
+ }
+ if (packet < 0) {
+ dprintk(1, "URB status %d [%s].\n", status, errmsg);
+ } else {
+ dprintk(1, "URB packet %d, status %d [%s].\n",
+ packet, status, errmsg);
+ }
+}
+
+static inline int dvb_isoc_copy(struct em28xx *dev, struct urb *urb)
+{
+ int i;
+
+ if (!dev)
+ return 0;
+
+ if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
+ return 0;
+
+ if (urb->status < 0) {
+ print_err_status(dev, -1, urb->status);
+ if (urb->status == -ENOENT)
+ return 0;
+ }
+
+ for (i = 0; i < urb->number_of_packets; i++) {
+ int status = urb->iso_frame_desc[i].status;
+
+ if (status < 0) {
+ print_err_status(dev, i, status);
+ if (urb->iso_frame_desc[i].status != -EPROTO)
+ continue;
+ }
+
+ dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer +
+ urb->iso_frame_desc[i].offset,
+ urb->iso_frame_desc[i].actual_length);
+ }
+
+ return 0;
+}
+
+static int start_streaming(struct em28xx_dvb *dvb)
+{
+ int rc;
+ struct em28xx *dev = dvb->adapter.priv;
+
+ usb_set_interface(dev->udev, 0, 1);
+ rc = em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
+ if (rc < 0)
+ return rc;
+
+ return em28xx_init_isoc(dev, EM28XX_DVB_MAX_PACKETS,
+ EM28XX_DVB_NUM_BUFS, EM28XX_DVB_MAX_PACKETSIZE,
+ dvb_isoc_copy);
+}
+
+static int stop_streaming(struct em28xx_dvb *dvb)
+{
+ struct em28xx *dev = dvb->adapter.priv;
+
+ em28xx_uninit_isoc(dev);
+
+ em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
+
+ return 0;
+}
+
+static int start_feed(struct dvb_demux_feed *feed)
+{
+ struct dvb_demux *demux = feed->demux;
+ struct em28xx_dvb *dvb = demux->priv;
+ int rc, ret;
+
+ if (!demux->dmx.frontend)
+ return -EINVAL;
+
+ mutex_lock(&dvb->lock);
+ dvb->nfeeds++;
+ rc = dvb->nfeeds;
+
+ if (dvb->nfeeds == 1) {
+ ret = start_streaming(dvb);
+ if (ret < 0)
+ rc = ret;
+ }
+
+ mutex_unlock(&dvb->lock);
+ return rc;
+}
+
+static int stop_feed(struct dvb_demux_feed *feed)
+{
+ struct dvb_demux *demux = feed->demux;
+ struct em28xx_dvb *dvb = demux->priv;
+ int err = 0;
+
+ mutex_lock(&dvb->lock);
+ dvb->nfeeds--;
+
+ if (0 == dvb->nfeeds)
+ err = stop_streaming(dvb);
+
+ mutex_unlock(&dvb->lock);
+ return err;
+}
+
+
+
+/* ------------------------------------------------------------------ */
+static int em28xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire)
+{
+ struct em28xx *dev = fe->dvb->priv;
+
+ if (acquire)
+ return em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
+ else
+ return em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
+}
+
+/* ------------------------------------------------------------------ */
+
+static struct lgdt330x_config em2880_lgdt3303_dev = {
+ .demod_address = 0x0e,
+ .demod_chip = LGDT3303,
+};
+
+static struct zl10353_config em28xx_zl10353_with_xc3028 = {
+ .demod_address = (0x1e >> 1),
+ .no_tuner = 1,
+ .parallel_ts = 1,
+ .if2 = 45600,
+};
+
+/* ------------------------------------------------------------------ */
+
+static int attach_xc3028(u8 addr, struct em28xx *dev)
+{
+ struct dvb_frontend *fe;
+ struct xc2028_config cfg;
+
+ memset(&cfg, 0, sizeof(cfg));
+ cfg.i2c_adap = &dev->i2c_adap;
+ cfg.i2c_addr = addr;
+ cfg.callback = em28xx_tuner_callback;
+
+ if (!dev->dvb->frontend) {
+ printk(KERN_ERR "%s/2: dvb frontend not attached. "
+ "Can't attach xc3028\n",
+ dev->name);
+ return -EINVAL;
+ }
+
+ fe = dvb_attach(xc2028_attach, dev->dvb->frontend, &cfg);
+ if (!fe) {
+ printk(KERN_ERR "%s/2: xc3028 attach failed\n",
+ dev->name);
+ dvb_frontend_detach(dev->dvb->frontend);
+ dvb_unregister_frontend(dev->dvb->frontend);
+ dev->dvb->frontend = NULL;
+ return -EINVAL;
+ }
+
+ printk(KERN_INFO "%s/2: xc3028 attached\n", dev->name);
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+int register_dvb(struct em28xx_dvb *dvb,
+ struct module *module,
+ struct em28xx *dev,
+ struct device *device)
+{
+ int result;
+
+ mutex_init(&dvb->lock);
+
+ /* register adapter */
+ result = dvb_register_adapter(&dvb->adapter, dev->name, module, device,
+ adapter_nr);
+ if (result < 0) {
+ printk(KERN_WARNING "%s: dvb_register_adapter failed (errno = %d)\n",
+ dev->name, result);
+ goto fail_adapter;
+ }
+
+ /* Ensure all frontends negotiate bus access */
+ dvb->frontend->ops.ts_bus_ctrl = em28xx_dvb_bus_ctrl;
+
+ dvb->adapter.priv = dev;
+
+ /* register frontend */
+ result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
+ if (result < 0) {
+ printk(KERN_WARNING "%s: dvb_register_frontend failed (errno = %d)\n",
+ dev->name, result);
+ goto fail_frontend;
+ }
+
+ /* register demux stuff */
+ dvb->demux.dmx.capabilities =
+ DMX_TS_FILTERING | DMX_SECTION_FILTERING |
+ DMX_MEMORY_BASED_FILTERING;
+ dvb->demux.priv = dvb;
+ dvb->demux.filternum = 256;
+ dvb->demux.feednum = 256;
+ dvb->demux.start_feed = start_feed;
+ dvb->demux.stop_feed = stop_feed;
+
+ result = dvb_dmx_init(&dvb->demux);
+ if (result < 0) {
+ printk(KERN_WARNING "%s: dvb_dmx_init failed (errno = %d)\n",
+ dev->name, result);
+ goto fail_dmx;
+ }
+
+ dvb->dmxdev.filternum = 256;
+ dvb->dmxdev.demux = &dvb->demux.dmx;
+ dvb->dmxdev.capabilities = 0;
+ result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
+ if (result < 0) {
+ printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n",
+ dev->name, result);
+ goto fail_dmxdev;
+ }
+
+ dvb->fe_hw.source = DMX_FRONTEND_0;
+ result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+ if (result < 0) {
+ printk(KERN_WARNING "%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n",
+ dev->name, result);
+ goto fail_fe_hw;
+ }
+
+ dvb->fe_mem.source = DMX_MEMORY_FE;
+ result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+ if (result < 0) {
+ printk(KERN_WARNING "%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n",
+ dev->name, result);
+ goto fail_fe_mem;
+ }
+
+ result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+ if (result < 0) {
+ printk(KERN_WARNING "%s: connect_frontend failed (errno = %d)\n",
+ dev->name, result);
+ goto fail_fe_conn;
+ }
+
+ /* register network adapter */
+ dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
+ return 0;
+
+fail_fe_conn:
+ dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+fail_fe_mem:
+ dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+fail_fe_hw:
+ dvb_dmxdev_release(&dvb->dmxdev);
+fail_dmxdev:
+ dvb_dmx_release(&dvb->demux);
+fail_dmx:
+ dvb_unregister_frontend(dvb->frontend);
+fail_frontend:
+ dvb_frontend_detach(dvb->frontend);
+ dvb_unregister_adapter(&dvb->adapter);
+fail_adapter:
+ return result;
+}
+
+static void unregister_dvb(struct em28xx_dvb *dvb)
+{
+ dvb_net_release(&dvb->net);
+ dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+ dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+ dvb_dmxdev_release(&dvb->dmxdev);
+ dvb_dmx_release(&dvb->demux);
+ dvb_unregister_frontend(dvb->frontend);
+ dvb_frontend_detach(dvb->frontend);
+ dvb_unregister_adapter(&dvb->adapter);
+}
+
+
+static int dvb_init(struct em28xx *dev)
+{
+ int result = 0;
+ struct em28xx_dvb *dvb;
+
+ dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
+
+ if (dvb == NULL) {
+ printk(KERN_INFO "em28xx_dvb: memory allocation failed\n");
+ return -ENOMEM;
+ }
+ dev->dvb = dvb;
+
+ em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
+ /* init frontend */
+ switch (dev->model) {
+ case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950:
+ dvb->frontend = dvb_attach(lgdt330x_attach,
+ &em2880_lgdt3303_dev,
+ &dev->i2c_adap);
+ if (attach_xc3028(0x61, dev) < 0) {
+ result = -EINVAL;
+ goto out_free;
+ }
+ break;
+ case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
+ dvb->frontend = dvb_attach(zl10353_attach,
+ &em28xx_zl10353_with_xc3028,
+ &dev->i2c_adap);
+ if (attach_xc3028(0x61, dev) < 0) {
+ result = -EINVAL;
+ goto out_free;
+ }
+ break;
+ default:
+ printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card"
+ " isn't supported yet\n",
+ dev->name);
+ break;
+ }
+ if (NULL == dvb->frontend) {
+ printk(KERN_ERR
+ "%s/2: frontend initialization failed\n",
+ dev->name);
+ result = -EINVAL;
+ goto out_free;
+ }
+
+ /* register everything */
+ result = register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev);
+
+ if (result < 0)
+ goto out_free;
+
+ em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
+ printk(KERN_INFO "Successfully loaded em28xx-dvb\n");
+ return 0;
+
+out_free:
+ em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
+ kfree(dvb);
+ dev->dvb = NULL;
+ return result;
+}
+
+static int dvb_fini(struct em28xx *dev)
+{
+ if (dev->dvb) {
+ unregister_dvb(dev->dvb);
+ dev->dvb = NULL;
+ }
+
+ return 0;
+}
+
+static struct em28xx_ops dvb_ops = {
+ .id = EM28XX_DVB,
+ .name = "Em28xx dvb Extension",
+ .init = dvb_init,
+ .fini = dvb_fini,
+};
+
+static int __init em28xx_dvb_register(void)
+{
+ return em28xx_register_extension(&dvb_ops);
+}
+
+static void __exit em28xx_dvb_unregister(void)
+{
+ em28xx_unregister_extension(&dvb_ops);
+}
+
+module_init(em28xx_dvb_register);
+module_exit(em28xx_dvb_unregister);
diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c
index cacd04d46e9..6a78fd294ca 100644
--- a/drivers/media/video/em28xx/em28xx-i2c.c
+++ b/drivers/media/video/em28xx/em28xx-i2c.c
@@ -33,19 +33,29 @@
/* ----------------------------------------------------------- */
-static unsigned int i2c_scan = 0;
+static unsigned int i2c_scan;
module_param(i2c_scan, int, 0444);
MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
-static unsigned int i2c_debug = 0;
+static unsigned int i2c_debug;
module_param(i2c_debug, int, 0644);
MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
-#define dprintk1(lvl,fmt, args...) if (i2c_debug>=lvl) do {\
- printk(fmt, ##args); } while (0)
-#define dprintk2(lvl,fmt, args...) if (i2c_debug>=lvl) do{ \
- printk(KERN_DEBUG "%s at %s: " fmt, \
- dev->name, __FUNCTION__ , ##args); } while (0)
+
+#define dprintk1(lvl, fmt, args...) \
+do { \
+ if (i2c_debug >= lvl) { \
+ printk(fmt, ##args); \
+ } \
+} while (0)
+
+#define dprintk2(lvl, fmt, args...) \
+do { \
+ if (i2c_debug >= lvl) { \
+ printk(KERN_DEBUG "%s at %s: " fmt, \
+ dev->name, __func__ , ##args); \
+ } \
+} while (0)
/*
* em2800_i2c_send_max4()
@@ -235,16 +245,16 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
return 0;
for (i = 0; i < num; i++) {
addr = msgs[i].addr << 1;
- dprintk2(2,"%s %s addr=%x len=%d:",
+ dprintk2(2, "%s %s addr=%x len=%d:",
(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 */
if (dev->is_em2800)
rc = em2800_i2c_check_for_device(dev, addr);
else
rc = em28xx_i2c_check_for_device(dev, addr);
if (rc < 0) {
- dprintk2(2," no device\n");
+ dprintk2(2, " no device\n");
return rc;
}
@@ -258,14 +268,13 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
rc = em28xx_i2c_recv_bytes(dev, addr,
msgs[i].buf,
msgs[i].len);
- if (i2c_debug>=2) {
- for (byte = 0; byte < msgs[i].len; byte++) {
+ if (i2c_debug >= 2) {
+ for (byte = 0; byte < msgs[i].len; byte++)
printk(" %02x", msgs[i].buf[byte]);
- }
}
} else {
/* write bytes */
- if (i2c_debug>=2) {
+ if (i2c_debug >= 2) {
for (byte = 0; byte < msgs[i].len; byte++)
printk(" %02x", msgs[i].buf[byte]);
}
@@ -281,13 +290,13 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
}
if (rc < 0)
goto err;
- if (i2c_debug>=2)
+ if (i2c_debug >= 2)
printk("\n");
}
return num;
- err:
- dprintk2(2," ERROR: %i\n", rc);
+err:
+ dprintk2(2, " ERROR: %i\n", rc);
return rc;
}
@@ -330,7 +339,9 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
return -1;
buf = 0;
- if (1 != (err = i2c_master_send(&dev->i2c_client, &buf, 1))) {
+
+ err = i2c_master_send(&dev->i2c_client, &buf, 1);
+ if (err != 1) {
printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n",
dev->name, err);
return -1;
@@ -403,8 +414,10 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
break;
}
printk(KERN_INFO "Table at 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n",
- em_eeprom->string_idx_table,em_eeprom->string1,
- em_eeprom->string2,em_eeprom->string3);
+ em_eeprom->string_idx_table,
+ em_eeprom->string1,
+ em_eeprom->string2,
+ em_eeprom->string3);
return 0;
}
@@ -430,58 +443,61 @@ static int attach_inform(struct i2c_client *client)
struct em28xx *dev = client->adapter->algo_data;
switch (client->addr << 1) {
- case 0x86:
- case 0x84:
- case 0x96:
- case 0x94:
- {
- struct v4l2_priv_tun_config tda9887_cfg;
-
- struct tuner_setup tun_setup;
-
- tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
- tun_setup.type = TUNER_TDA9887;
- tun_setup.addr = client->addr;
-
- em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
-
- tda9887_cfg.tuner = TUNER_TDA9887;
- tda9887_cfg.priv = &dev->tda9887_conf;
- em28xx_i2c_call_clients(dev, TUNER_SET_CONFIG,
- &tda9887_cfg);
- break;
- }
- case 0x42:
- dprintk1(1,"attach_inform: saa7114 detected.\n");
- break;
- case 0x4a:
- dprintk1(1,"attach_inform: saa7113 detected.\n");
- break;
- case 0xa0:
- dprintk1(1,"attach_inform: eeprom detected.\n");
- break;
- case 0x60:
- case 0x8e:
- {
- struct IR_i2c *ir = i2c_get_clientdata(client);
- dprintk1(1,"attach_inform: IR detected (%s).\n",ir->phys);
- em28xx_set_ir(dev,ir);
- break;
- }
- case 0x80:
- case 0x88:
- dprintk1(1,"attach_inform: msp34xx detected.\n");
- break;
- case 0xb8:
- case 0xba:
- dprintk1(1,"attach_inform: tvp5150 detected.\n");
- break;
-
- default:
- if (!dev->tuner_addr)
- dev->tuner_addr = client->addr;
-
- dprintk1(1,"attach inform: detected I2C address %x\n", client->addr << 1);
+ case 0x86:
+ case 0x84:
+ case 0x96:
+ case 0x94:
+ {
+ struct v4l2_priv_tun_config tda9887_cfg;
+
+ struct tuner_setup tun_setup;
+
+ tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
+ tun_setup.type = TUNER_TDA9887;
+ tun_setup.addr = client->addr;
+
+ em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR,
+ &tun_setup);
+
+ tda9887_cfg.tuner = TUNER_TDA9887;
+ tda9887_cfg.priv = &dev->tda9887_conf;
+ em28xx_i2c_call_clients(dev, TUNER_SET_CONFIG,
+ &tda9887_cfg);
+ break;
+ }
+ case 0x42:
+ dprintk1(1, "attach_inform: saa7114 detected.\n");
+ break;
+ case 0x4a:
+ dprintk1(1, "attach_inform: saa7113 detected.\n");
+ break;
+ case 0xa0:
+ dprintk1(1, "attach_inform: eeprom detected.\n");
+ break;
+ case 0x60:
+ case 0x8e:
+ {
+ struct IR_i2c *ir = i2c_get_clientdata(client);
+ dprintk1(1, "attach_inform: IR detected (%s).\n",
+ ir->phys);
+ em28xx_set_ir(dev, ir);
+ break;
+ }
+ case 0x80:
+ case 0x88:
+ dprintk1(1, "attach_inform: msp34xx detected.\n");
+ break;
+ case 0xb8:
+ case 0xba:
+ dprintk1(1, "attach_inform: tvp5150 detected.\n");
+ break;
+
+ default:
+ if (!dev->tuner_addr)
+ dev->tuner_addr = client->addr;
+
+ dprintk1(1, "attach inform: detected I2C address %x\n",
+ client->addr << 1);
}
diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c
index 10da2fd8d98..bb5807159b8 100644
--- a/drivers/media/video/em28xx/em28xx-input.c
+++ b/drivers/media/video/em28xx/em28xx-input.c
@@ -32,10 +32,12 @@
static unsigned int ir_debug;
module_param(ir_debug, int, 0644);
-MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]");
+MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]");
-#define dprintk(fmt, arg...) if (ir_debug) \
- printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg)
+#define dprintk(fmt, arg...) \
+ if (ir_debug) { \
+ printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg); \
+ }
/* ----------------------------------------------------------------------- */
@@ -44,7 +46,7 @@ int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
unsigned char b;
/* poll IR chip */
- if (1 != i2c_master_recv(&ir->c,&b,1)) {
+ if (1 != i2c_master_recv(&ir->c, &b, 1)) {
dprintk("read error\n");
return -EIO;
}
@@ -74,24 +76,25 @@ int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
unsigned char code;
/* poll IR chip */
- if (2 != i2c_master_recv(&ir->c,buf,2))
+ if (2 != i2c_master_recv(&ir->c, buf, 2))
return -EIO;
/* Does eliminate repeated parity code */
- if (buf[1]==0xff)
+ if (buf[1] == 0xff)
return 0;
- ir->old=buf[1];
+ ir->old = buf[1];
/* Rearranges bits to the right order */
- code= ((buf[0]&0x01)<<5) | /* 0010 0000 */
+ code = ((buf[0]&0x01)<<5) | /* 0010 0000 */
((buf[0]&0x02)<<3) | /* 0001 0000 */
((buf[0]&0x04)<<1) | /* 0000 1000 */
((buf[0]&0x08)>>1) | /* 0000 0100 */
((buf[0]&0x10)>>3) | /* 0000 0010 */
((buf[0]&0x20)>>5); /* 0000 0001 */
- dprintk("ir hauppauge (em2840): code=0x%02x (rcv=0x%02x)\n",code,buf[0]);
+ dprintk("ir hauppauge (em2840): code=0x%02x (rcv=0x%02x)\n",
+ code, buf[0]);
/* return key */
*ir_key = code;
@@ -106,15 +109,14 @@ int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
/* poll IR chip */
- if (3 != i2c_master_recv(&ir->c,buf,3)) {
+ if (3 != i2c_master_recv(&ir->c, buf, 3)) {
dprintk("read error\n");
return -EIO;
}
dprintk("key %02x\n", buf[2]&0x3f);
- if (buf[0]!=0x00){
+ if (buf[0] != 0x00)
return 0;
- }
*ir_key = buf[2]&0x3f;
*ir_raw = buf[2]&0x3f;
diff --git a/drivers/media/video/em28xx/em28xx-reg.h b/drivers/media/video/em28xx/em28xx-reg.h
new file mode 100644
index 00000000000..9058bed0795
--- /dev/null
+++ b/drivers/media/video/em28xx/em28xx-reg.h
@@ -0,0 +1,88 @@
+#define EM_GPIO_0 (1 << 0)
+#define EM_GPIO_1 (1 << 1)
+#define EM_GPIO_2 (1 << 2)
+#define EM_GPIO_3 (1 << 3)
+#define EM_GPIO_4 (1 << 4)
+#define EM_GPIO_5 (1 << 5)
+#define EM_GPIO_6 (1 << 6)
+#define EM_GPIO_7 (1 << 7)
+
+#define EM_GPO_0 (1 << 0)
+#define EM_GPO_1 (1 << 1)
+#define EM_GPO_2 (1 << 2)
+#define EM_GPO_3 (1 << 3)
+
+/* em2800 registers */
+#define EM2800_R08_AUDIOSRC 0x08
+
+/* em28xx registers */
+
+ /* GPIO/GPO registers */
+#define EM2880_R04_GPO 0x04 /* em2880-em2883 only */
+#define EM28XX_R08_GPIO 0x08 /* em2820 or upper */
+
+#define EM28XX_R06_I2C_CLK 0x06
+#define EM28XX_R0A_CHIPID 0x0a
+#define EM28XX_R0C_USBSUSP 0x0c /* */
+
+#define EM28XX_R0E_AUDIOSRC 0x0e
+#define EM28XX_R0F_XCLK 0x0f
+
+#define EM28XX_R10_VINMODE 0x10
+#define EM28XX_R11_VINCTRL 0x11
+#define EM28XX_R12_VINENABLE 0x12 /* */
+
+#define EM28XX_R14_GAMMA 0x14
+#define EM28XX_R15_RGAIN 0x15
+#define EM28XX_R16_GGAIN 0x16
+#define EM28XX_R17_BGAIN 0x17
+#define EM28XX_R18_ROFFSET 0x18
+#define EM28XX_R19_GOFFSET 0x19
+#define EM28XX_R1A_BOFFSET 0x1a
+
+#define EM28XX_R1B_OFLOW 0x1b
+#define EM28XX_R1C_HSTART 0x1c
+#define EM28XX_R1D_VSTART 0x1d
+#define EM28XX_R1E_CWIDTH 0x1e
+#define EM28XX_R1F_CHEIGHT 0x1f
+
+#define EM28XX_R20_YGAIN 0x20
+#define EM28XX_R21_YOFFSET 0x21
+#define EM28XX_R22_UVGAIN 0x22
+#define EM28XX_R23_UOFFSET 0x23
+#define EM28XX_R24_VOFFSET 0x24
+#define EM28XX_R25_SHARPNESS 0x25
+
+#define EM28XX_R26_COMPR 0x26
+#define EM28XX_R27_OUTFMT 0x27
+
+#define EM28XX_R28_XMIN 0x28
+#define EM28XX_R29_XMAX 0x29
+#define EM28XX_R2A_YMIN 0x2a
+#define EM28XX_R2B_YMAX 0x2b
+
+#define EM28XX_R30_HSCALELOW 0x30
+#define EM28XX_R31_HSCALEHIGH 0x31
+#define EM28XX_R32_VSCALELOW 0x32
+#define EM28XX_R33_VSCALEHIGH 0x33
+
+#define EM28XX_R40_AC97LSB 0x40
+#define EM28XX_R41_AC97MSB 0x41
+#define EM28XX_R42_AC97ADDR 0x42
+#define EM28XX_R43_AC97BUSY 0x43
+
+/* em202 registers */
+#define EM28XX_R02_MASTER_AC97 0x02
+#define EM28XX_R10_LINE_IN_AC97 0x10
+#define EM28XX_R14_VIDEO_AC97 0x14
+
+/* register settings */
+#define EM2800_AUDIO_SRC_TUNER 0x0d
+#define EM2800_AUDIO_SRC_LINE 0x0c
+#define EM28XX_AUDIO_SRC_TUNER 0xc0
+#define EM28XX_AUDIO_SRC_LINE 0x80
+
+/* FIXME: Need to be populated with the other chip ID's */
+enum em28xx_chip_id {
+ CHIP_ID_EM2883 = 36,
+};
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index 4abe6701a77..8996175cc95 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -1,5 +1,6 @@
/*
- em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
+ em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB
+ video capture devices
Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
Markus Rechberger <mrechberger@gmail.com>
@@ -52,7 +53,19 @@
#define em28xx_videodbg(fmt, arg...) do {\
if (video_debug) \
printk(KERN_INFO "%s %s :"fmt, \
- dev->name, __FUNCTION__ , ##arg); } while (0)
+ 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) { \
+ printk(KERN_INFO "%s %s :"fmt, \
+ dev->name, __func__ , ##arg); \
+ } \
+ } while (0)
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
@@ -74,9 +87,9 @@ MODULE_PARM_DESC(video_nr, "video device numbers");
MODULE_PARM_DESC(vbi_nr, "vbi device numbers");
MODULE_PARM_DESC(radio_nr, "radio device numbers");
-static unsigned int video_debug = 0;
-module_param(video_debug,int,0644);
-MODULE_PARM_DESC(video_debug,"enable debug messages [video]");
+static unsigned int video_debug;
+module_param(video_debug, int, 0644);
+MODULE_PARM_DESC(video_debug, "enable debug messages [video]");
/* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS */
static unsigned long em28xx_devused;
@@ -93,7 +106,7 @@ static struct v4l2_queryctrl em28xx_qctrl[] = {
.step = 0x1,
.default_value = 0x1f,
.flags = 0,
- },{
+ }, {
.id = V4L2_CID_AUDIO_MUTE,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "Mute",
@@ -107,8 +120,391 @@ static struct v4l2_queryctrl em28xx_qctrl[] = {
static struct usb_driver em28xx_usb_driver;
+/* ------------------------------------------------------------------
+ DMA and thread functions
+ ------------------------------------------------------------------*/
+
+/*
+ * Announces that a buffer were filled and request the next
+ */
+static inline void buffer_filled(struct em28xx *dev,
+ struct em28xx_dmaqueue *dma_q,
+ struct em28xx_buffer *buf)
+{
+ /* Advice that buffer was filled */
+ em28xx_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i);
+ buf->vb.state = VIDEOBUF_DONE;
+ buf->vb.field_count++;
+ do_gettimeofday(&buf->vb.ts);
-/********************* v4l2 interface ******************************************/
+ dev->isoc_ctl.buf = NULL;
+
+ list_del(&buf->vb.queue);
+ wake_up(&buf->vb.done);
+}
+
+/*
+ * Identify the buffer header type and properly handles
+ */
+static void em28xx_copy_video(struct em28xx *dev,
+ struct em28xx_dmaqueue *dma_q,
+ struct em28xx_buffer *buf,
+ unsigned char *p,
+ unsigned char *outp, unsigned long len)
+{
+ void *fieldstart, *startwrite, *startread;
+ int linesdone, currlinedone, offset, lencopy, remain;
+ int bytesperline = dev->width << 1;
+
+ if (dma_q->pos + len > buf->vb.size)
+ len = buf->vb.size - dma_q->pos;
+
+ if (p[0] != 0x88 && p[0] != 0x22) {
+ em28xx_isocdbg("frame is not complete\n");
+ len += 4;
+ } else
+ p += 4;
+
+ startread = p;
+ remain = len;
+
+ /* Interlaces frame */
+ if (buf->top_field)
+ fieldstart = outp;
+ else
+ fieldstart = outp + bytesperline;
+
+ linesdone = dma_q->pos / bytesperline;
+ currlinedone = dma_q->pos % bytesperline;
+ offset = linesdone * bytesperline * 2 + currlinedone;
+ startwrite = fieldstart + offset;
+ lencopy = bytesperline - currlinedone;
+ lencopy = lencopy > remain ? remain : lencopy;
+
+ if ((char *)startwrite + lencopy > (char *)outp + buf->vb.size) {
+ em28xx_isocdbg("Overflow of %zi bytes past buffer end (1)\n",
+ ((char *)startwrite + lencopy) -
+ ((char *)outp + buf->vb.size));
+ lencopy = remain = (char *)outp + buf->vb.size - (char *)startwrite;
+ }
+ if (lencopy <= 0)
+ return;
+ memcpy(startwrite, startread, lencopy);
+
+ remain -= lencopy;
+
+ while (remain > 0) {
+ startwrite += lencopy + bytesperline;
+ startread += lencopy;
+ if (bytesperline > remain)
+ lencopy = remain;
+ else
+ lencopy = bytesperline;
+
+ if ((char *)startwrite + lencopy > (char *)outp + buf->vb.size) {
+ em28xx_isocdbg("Overflow of %zi bytes past buffer end (2)\n",
+ ((char *)startwrite + lencopy) -
+ ((char *)outp + buf->vb.size));
+ lencopy = remain = (char *)outp + buf->vb.size -
+ (char *)startwrite;
+ }
+ if (lencopy <= 0)
+ break;
+
+ memcpy(startwrite, startread, lencopy);
+
+ remain -= lencopy;
+ }
+
+ dma_q->pos += len;
+}
+
+static inline void print_err_status(struct em28xx *dev,
+ int packet, int status)
+{
+ char *errmsg = "Unknown";
+
+ switch (status) {
+ case -ENOENT:
+ errmsg = "unlinked synchronuously";
+ break;
+ case -ECONNRESET:
+ errmsg = "unlinked asynchronuously";
+ break;
+ case -ENOSR:
+ errmsg = "Buffer error (overrun)";
+ break;
+ case -EPIPE:
+ errmsg = "Stalled (device not responding)";
+ break;
+ case -EOVERFLOW:
+ errmsg = "Babble (bad cable?)";
+ break;
+ case -EPROTO:
+ errmsg = "Bit-stuff error (bad cable?)";
+ break;
+ case -EILSEQ:
+ errmsg = "CRC/Timeout (could be anything)";
+ break;
+ case -ETIME:
+ errmsg = "Device does not respond";
+ break;
+ }
+ if (packet < 0) {
+ em28xx_isocdbg("URB status %d [%s].\n", status, errmsg);
+ } else {
+ em28xx_isocdbg("URB packet %d, status %d [%s].\n",
+ packet, status, errmsg);
+ }
+}
+
+/*
+ * video-buf generic routine to get the next available buffer
+ */
+static inline void get_next_buf(struct em28xx_dmaqueue *dma_q,
+ struct em28xx_buffer **buf)
+{
+ struct em28xx *dev = container_of(dma_q, struct em28xx, vidq);
+ char *outp;
+
+ if (list_empty(&dma_q->active)) {
+ em28xx_isocdbg("No active queue to serve\n");
+ dev->isoc_ctl.buf = NULL;
+ *buf = NULL;
+ return;
+ }
+
+ /* Get the next buffer */
+ *buf = list_entry(dma_q->active.next, struct em28xx_buffer, vb.queue);
+
+ /* Cleans up buffer - Usefull for testing for frame/URB loss */
+ outp = videobuf_to_vmalloc(&(*buf)->vb);
+ memset(outp, 0, (*buf)->vb.size);
+
+ dev->isoc_ctl.buf = *buf;
+
+ return;
+}
+
+/*
+ * Controls the isoc copy of each urb packet
+ */
+static inline int em28xx_isoc_copy(struct em28xx *dev, struct urb *urb)
+{
+ struct em28xx_buffer *buf;
+ struct em28xx_dmaqueue *dma_q = urb->context;
+ unsigned char *outp = NULL;
+ int i, len = 0, rc = 1;
+ unsigned char *p;
+
+ if (!dev)
+ return 0;
+
+ if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
+ return 0;
+
+ if (urb->status < 0) {
+ print_err_status(dev, -1, urb->status);
+ if (urb->status == -ENOENT)
+ return 0;
+ }
+
+ buf = dev->isoc_ctl.buf;
+ if (buf != NULL)
+ outp = videobuf_to_vmalloc(&buf->vb);
+
+ for (i = 0; i < urb->number_of_packets; i++) {
+ int status = urb->iso_frame_desc[i].status;
+
+ if (status < 0) {
+ print_err_status(dev, i, status);
+ if (urb->iso_frame_desc[i].status != -EPROTO)
+ continue;
+ }
+
+ len = urb->iso_frame_desc[i].actual_length - 4;
+
+ if (urb->iso_frame_desc[i].actual_length <= 0) {
+ /* em28xx_isocdbg("packet %d is empty",i); - spammy */
+ continue;
+ }
+ if (urb->iso_frame_desc[i].actual_length >
+ dev->max_pkt_size) {
+ em28xx_isocdbg("packet bigger than packet size");
+ continue;
+ }
+
+ p = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+
+ /* FIXME: incomplete buffer checks where removed to make
+ logic simpler. Impacts of those changes should be evaluated
+ */
+ if (p[0] == 0x33 && p[1] == 0x95 && p[2] == 0x00) {
+ em28xx_isocdbg("VBI HEADER!!!\n");
+ /* FIXME: Should add vbi copy */
+ continue;
+ }
+ if (p[0] == 0x22 && p[1] == 0x5a) {
+ em28xx_isocdbg("Video frame %d, length=%i, %s\n", p[2],
+ len, (p[2] & 1)? "odd" : "even");
+
+ if (!(p[2] & 1)) {
+ if (buf != NULL)
+ buffer_filled(dev, dma_q, buf);
+ get_next_buf(dma_q, &buf);
+ if (buf == NULL)
+ outp = NULL;
+ else
+ outp = videobuf_to_vmalloc(&buf->vb);
+ }
+
+ if (buf != NULL) {
+ if (p[2] & 1)
+ buf->top_field = 0;
+ else
+ buf->top_field = 1;
+ }
+
+ dma_q->pos = 0;
+ }
+ if (buf != NULL)
+ em28xx_copy_video(dev, dma_q, buf, p, outp, len);
+ }
+ return rc;
+}
+
+/* ------------------------------------------------------------------
+ Videobuf operations
+ ------------------------------------------------------------------*/
+
+static int
+buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
+{
+ struct em28xx_fh *fh = vq->priv_data;
+ struct em28xx *dev = fh->dev;
+ struct v4l2_frequency f;
+
+ *size = 16 * fh->dev->width * fh->dev->height >> 3;
+ if (0 == *count)
+ *count = EM28XX_DEF_BUF;
+
+ if (*count < EM28XX_MIN_BUF)
+ *count = EM28XX_MIN_BUF;
+
+ /* Ask tuner to go to analog mode */
+ memset(&f, 0, sizeof(f));
+ f.frequency = dev->ctl_freq;
+
+ em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, &f);
+
+ return 0;
+}
+
+/* This is called *without* dev->slock held; please keep it that way */
+static void free_buffer(struct videobuf_queue *vq, struct em28xx_buffer *buf)
+{
+ struct em28xx_fh *fh = vq->priv_data;
+ struct em28xx *dev = fh->dev;
+ unsigned long flags = 0;
+ if (in_interrupt())
+ BUG();
+
+ /* We used to wait for the buffer to finish here, but this didn't work
+ because, as we were keeping the state as VIDEOBUF_QUEUED,
+ videobuf_queue_cancel marked it as finished for us.
+ (Also, it could wedge forever if the hardware was misconfigured.)
+
+ This should be safe; by the time we get here, the buffer isn't
+ queued anymore. If we ever start marking the buffers as
+ VIDEOBUF_ACTIVE, it won't be, though.
+ */
+ spin_lock_irqsave(&dev->slock, flags);
+ if (dev->isoc_ctl.buf == buf)
+ dev->isoc_ctl.buf = NULL;
+ spin_unlock_irqrestore(&dev->slock, flags);
+
+ videobuf_vmalloc_free(&buf->vb);
+ buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int
+buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct em28xx_fh *fh = vq->priv_data;
+ struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
+ struct em28xx *dev = fh->dev;
+ int rc = 0, urb_init = 0;
+
+ /* FIXME: It assumes depth = 16 */
+ /* The only currently supported format is 16 bits/pixel */
+ buf->vb.size = 16 * dev->width * dev->height >> 3;
+
+ if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
+ return -EINVAL;
+
+ buf->vb.width = dev->width;
+ buf->vb.height = dev->height;
+ buf->vb.field = field;
+
+ if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+ rc = videobuf_iolock(vq, &buf->vb, NULL);
+ if (rc < 0)
+ goto fail;
+ }
+
+ if (!dev->isoc_ctl.num_bufs)
+ urb_init = 1;
+
+ if (urb_init) {
+ rc = em28xx_init_isoc(dev, EM28XX_NUM_PACKETS,
+ EM28XX_NUM_BUFS, dev->max_pkt_size,
+ em28xx_isoc_copy);
+ if (rc < 0)
+ goto fail;
+ }
+
+ buf->vb.state = VIDEOBUF_PREPARED;
+ return 0;
+
+fail:
+ free_buffer(vq, buf);
+ return rc;
+}
+
+static void
+buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+ struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
+ struct em28xx_fh *fh = vq->priv_data;
+ struct em28xx *dev = fh->dev;
+ struct em28xx_dmaqueue *vidq = &dev->vidq;
+
+ buf->vb.state = VIDEOBUF_QUEUED;
+ list_add_tail(&buf->vb.queue, &vidq->active);
+
+}
+
+static void buffer_release(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb)
+{
+ struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
+ struct em28xx_fh *fh = vq->priv_data;
+ struct em28xx *dev = (struct em28xx *)fh->dev;
+
+ em28xx_isocdbg("em28xx: called buffer_release\n");
+
+ free_buffer(vq, buf);
+}
+
+static struct videobuf_queue_ops em28xx_video_qops = {
+ .buf_setup = buffer_setup,
+ .buf_prepare = buffer_prepare,
+ .buf_queue = buffer_queue,
+ .buf_release = buffer_release,
+};
+
+/********************* v4l2 interface **************************************/
/*
* em28xx_config()
@@ -123,9 +519,9 @@ static int em28xx_config(struct em28xx *dev)
/* enable vbi capturing */
-/* em28xx_write_regs_req(dev,0x00,0x0e,"\xC0",1); audio register */
-/* em28xx_write_regs_req(dev,0x00,0x0f,"\x80",1); clk register */
- em28xx_write_regs_req(dev,0x00,0x11,"\x51",1);
+/* em28xx_write_regs_req(dev, 0x00, 0x0e, "\xC0", 1); audio register */
+/* em28xx_write_regs_req(dev, 0x00, 0x0f, "\x80", 1); clk register */
+ em28xx_write_regs_req(dev, 0x00, 0x11, "\x51", 1);
dev->mute = 1; /* maybe not the right place... */
dev->volume = 0x1f;
@@ -152,23 +548,6 @@ static void em28xx_config_i2c(struct em28xx *dev)
em28xx_i2c_call_clients(dev, VIDIOC_STREAMON, NULL);
}
-/*
- * em28xx_empty_framequeues()
- * prepare queues for incoming and outgoing frames
- */
-static void em28xx_empty_framequeues(struct em28xx *dev)
-{
- u32 i;
-
- INIT_LIST_HEAD(&dev->inqueue);
- INIT_LIST_HEAD(&dev->outqueue);
-
- for (i = 0; i < EM28XX_NUM_FRAMES; i++) {
- dev->frame[i].state = F_UNUSED;
- dev->frame[i].buf.bytesused = 0;
- }
-}
-
static void video_mux(struct em28xx *dev, int index)
{
struct v4l2_routing route;
@@ -181,12 +560,15 @@ static void video_mux(struct em28xx *dev, int index)
em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route);
if (dev->has_msp34xx) {
- if (dev->i2s_speed)
- em28xx_i2c_call_clients(dev, VIDIOC_INT_I2S_CLOCK_FREQ, &dev->i2s_speed);
+ if (dev->i2s_speed) {
+ em28xx_i2c_call_clients(dev, VIDIOC_INT_I2S_CLOCK_FREQ,
+ &dev->i2s_speed);
+ }
route.input = dev->ctl_ainput;
route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
/* Note: this is msp3400 specific */
- em28xx_i2c_call_clients(dev, VIDIOC_INT_S_AUDIO_ROUTING, &route);
+ em28xx_i2c_call_clients(dev, VIDIOC_INT_S_AUDIO_ROUTING,
+ &route);
}
em28xx_audio_analog_set(dev);
@@ -202,15 +584,12 @@ static int res_get(struct em28xx_fh *fh)
if (fh->stream_on)
return rc;
- mutex_lock(&dev->lock);
-
if (dev->stream_on)
- rc = -EINVAL;
- else {
- dev->stream_on = 1;
- fh->stream_on = 1;
- }
+ return -EINVAL;
+ mutex_lock(&dev->lock);
+ dev->stream_on = 1;
+ fh->stream_on = 1;
mutex_unlock(&dev->lock);
return rc;
}
@@ -231,33 +610,6 @@ static void res_free(struct em28xx_fh *fh)
}
/*
- * em28xx_vm_open()
- */
-static void em28xx_vm_open(struct vm_area_struct *vma)
-{
- struct em28xx_frame_t *f = vma->vm_private_data;
- f->vma_use_count++;
-}
-
-/*
- * em28xx_vm_close()
- */
-static void em28xx_vm_close(struct vm_area_struct *vma)
-{
- /* NOTE: buffers are not freed here */
- struct em28xx_frame_t *f = vma->vm_private_data;
-
- if (f->vma_use_count)
- f->vma_use_count--;
-}
-
-static struct vm_operations_struct em28xx_vm_ops = {
- .open = em28xx_vm_open,
- .close = em28xx_vm_close,
-};
-
-
-/*
* em28xx_get_ctrl()
* return the current saturation, brightness or contrast, mute state
*/
@@ -296,34 +648,6 @@ static int em28xx_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
}
}
-/*
- * em28xx_stream_interrupt()
- * stops streaming
- */
-static int em28xx_stream_interrupt(struct em28xx *dev)
-{
- int rc = 0;
-
- /* stop reading from the device */
-
- dev->stream = STREAM_INTERRUPT;
- rc = wait_event_timeout(dev->wait_stream,
- (dev->stream == STREAM_OFF) ||
- (dev->state & DEV_DISCONNECTED),
- EM28XX_URB_TIMEOUT);
-
- if (rc) {
- dev->state |= DEV_MISCONFIGURED;
- em28xx_videodbg("device is misconfigured; close and "
- "open /dev/video%d again\n",
- dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN);
- return rc;
- }
-
- return 0;
-}
-
-
static int check_dev(struct em28xx *dev)
{
if (dev->state & DEV_DISCONNECTED) {
@@ -370,8 +694,8 @@ static int vidioc_g_fmt_cap(struct file *file, void *priv,
f->fmt.pix.width = dev->width;
f->fmt.pix.height = dev->height;
f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
- f->fmt.pix.bytesperline = dev->bytesperline;
- f->fmt.pix.sizeimage = dev->frame_size;
+ f->fmt.pix.bytesperline = dev->width * 2;
+ f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * dev->height;
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
/* FIXME: TOP? NONE? BOTTOM? ALTENATE? */
@@ -447,7 +771,7 @@ static int vidioc_s_fmt_cap(struct file *file, void *priv,
{
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
- int rc, i;
+ int rc;
rc = check_dev(dev);
if (rc < 0)
@@ -457,49 +781,34 @@ static int vidioc_s_fmt_cap(struct file *file, void *priv,
mutex_lock(&dev->lock);
- for (i = 0; i < dev->num_frames; i++)
- if (dev->frame[i].vma_use_count) {
- em28xx_videodbg("VIDIOC_S_FMT failed. "
- "Unmap the buffers first.\n");
- rc = -EINVAL;
- goto err;
- }
-
- /* stop io in case it is already in progress */
- if (dev->stream == STREAM_ON) {
- em28xx_videodbg("VIDIOC_SET_FMT: interrupting stream\n");
- rc = em28xx_stream_interrupt(dev);
- if (rc < 0)
- goto err;
+ if (videobuf_queue_is_busy(&fh->vb_vidq)) {
+ em28xx_errdev("%s queue busy\n", __func__);
+ rc = -EBUSY;
+ goto out;
}
- em28xx_release_buffers(dev);
- dev->io = IO_NONE;
+ if (dev->stream_on && !fh->stream_on) {
+ em28xx_errdev("%s device in use by another fh\n", __func__);
+ rc = -EBUSY;
+ goto out;
+ }
/* set new image size */
dev->width = f->fmt.pix.width;
dev->height = f->fmt.pix.height;
- dev->frame_size = dev->width * dev->height * 2;
- dev->field_size = dev->frame_size >> 1;
- dev->bytesperline = dev->width * 2;
get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
- /* FIXME: This is really weird! Why capture is starting with
- this ioctl ???
- */
- em28xx_uninit_isoc(dev);
em28xx_set_alternate(dev);
- em28xx_capture_start(dev, 1);
em28xx_resolution_set(dev);
- em28xx_init_isoc(dev);
+
rc = 0;
-err:
+out:
mutex_unlock(&dev->lock);
return rc;
}
-static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id * norm)
{
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
@@ -524,9 +833,6 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
/* set new image size */
dev->width = f.fmt.pix.width;
dev->height = f.fmt.pix.height;
- dev->frame_size = dev->width * dev->height * 2;
- dev->field_size = dev->frame_size >> 1;
- dev->bytesperline = dev->width * 2;
get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
em28xx_resolution_set(dev);
@@ -619,11 +925,11 @@ static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
index = dev->ctl_ainput;
- if (index == 0) {
+ if (index == 0)
strcpy(a->name, "Television");
- } else {
+ else
strcpy(a->name, "Line In");
- }
+
a->capability = V4L2_AUDCAP_STEREO;
a->index = index;
@@ -834,9 +1140,9 @@ static int vidioc_s_frequency(struct file *file, void *priv,
static int em28xx_reg_len(int reg)
{
switch (reg) {
- case AC97LSB_REG:
- case HSCALELOW_REG:
- case VSCALELOW_REG:
+ case EM28XX_R40_AC97LSB:
+ case EM28XX_R30_HSCALELOW:
+ case EM28XX_R32_VSCALELOW:
return 2;
default:
return 1;
@@ -918,23 +1224,11 @@ static int vidioc_streamon(struct file *file, void *priv,
if (rc < 0)
return rc;
- if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP)
- return -EINVAL;
-
- if (list_empty(&dev->inqueue))
- return -EINVAL;
-
- mutex_lock(&dev->lock);
- if (unlikely(res_get(fh) < 0)) {
- mutex_unlock(&dev->lock);
+ if (unlikely(res_get(fh) < 0))
return -EBUSY;
- }
- dev->stream = STREAM_ON; /* FIXME: Start video capture here? */
-
- mutex_unlock(&dev->lock);
- return 0;
+ return (videobuf_streamon(&fh->vb_vidq));
}
static int vidioc_streamoff(struct file *file, void *priv,
@@ -948,23 +1242,14 @@ static int vidioc_streamoff(struct file *file, void *priv,
if (rc < 0)
return rc;
- if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP)
+ if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (type != fh->type)
return -EINVAL;
- mutex_lock(&dev->lock);
-
- if (dev->stream == STREAM_ON) {
- em28xx_videodbg("VIDIOC_STREAMOFF: interrupting stream\n");
- rc = em28xx_stream_interrupt(dev);
- if (rc < 0) {
- mutex_unlock(&dev->lock);
- return rc;
- }
- }
-
- em28xx_empty_framequeues(dev);
+ videobuf_streamoff(&fh->vb_vidq);
+ res_free(fh);
- mutex_unlock(&dev->lock);
return 0;
}
@@ -1058,53 +1343,13 @@ static int vidioc_reqbufs(struct file *file, void *priv,
{
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
- u32 i;
int rc;
rc = check_dev(dev);
if (rc < 0)
return rc;
- if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
- rb->memory != V4L2_MEMORY_MMAP)
- return -EINVAL;
-
- if (dev->io == IO_READ) {
- em28xx_videodbg("method is set to read;"
- " close and open the device again to"
- " choose the mmap I/O method\n");
- return -EINVAL;
- }
-
- for (i = 0; i < dev->num_frames; i++)
- if (dev->frame[i].vma_use_count) {
- em28xx_videodbg("VIDIOC_REQBUFS failed; "
- "previous buffers are still mapped\n");
- return -EINVAL;
- }
-
- mutex_lock(&dev->lock);
-
- if (dev->stream == STREAM_ON) {
- em28xx_videodbg("VIDIOC_REQBUFS: interrupting stream\n");
- rc = em28xx_stream_interrupt(dev);
- if (rc < 0) {
- mutex_unlock(&dev->lock);
- return rc;
- }
- }
-
- em28xx_empty_framequeues(dev);
-
- em28xx_release_buffers(dev);
- if (rb->count)
- rb->count = em28xx_request_buffers(dev, rb->count);
-
- dev->frame_current = NULL;
- dev->io = rb->count ? IO_MMAP : IO_NONE;
-
- mutex_unlock(&dev->lock);
- return 0;
+ return (videobuf_reqbufs(&fh->vb_vidq, rb));
}
static int vidioc_querybuf(struct file *file, void *priv,
@@ -1118,52 +1363,20 @@ static int vidioc_querybuf(struct file *file, void *priv,
if (rc < 0)
return rc;
- if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
- b->index >= dev->num_frames || dev->io != IO_MMAP)
- return -EINVAL;
-
- mutex_lock(&dev->lock);
-
- memcpy(b, &dev->frame[b->index].buf, sizeof(*b));
-
- if (dev->frame[b->index].vma_use_count)
- b->flags |= V4L2_BUF_FLAG_MAPPED;
-
- if (dev->frame[b->index].state == F_DONE)
- b->flags |= V4L2_BUF_FLAG_DONE;
- else if (dev->frame[b->index].state != F_UNUSED)
- b->flags |= V4L2_BUF_FLAG_QUEUED;
-
- mutex_unlock(&dev->lock);
- return 0;
+ return (videobuf_querybuf(&fh->vb_vidq, b));
}
static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
{
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
- unsigned long lock_flags;
int rc;
rc = check_dev(dev);
if (rc < 0)
return rc;
- if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP ||
- b->index >= dev->num_frames)
- return -EINVAL;
-
- if (dev->frame[b->index].state != F_UNUSED)
- return -EAGAIN;
-
- dev->frame[b->index].state = F_QUEUED;
-
- /* add frame to fifo */
- spin_lock_irqsave(&dev->queue_lock, lock_flags);
- list_add_tail(&dev->frame[b->index].frame, &dev->inqueue);
- spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
-
- return 0;
+ return (videobuf_qbuf(&fh->vb_vidq, b));
}
static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
@@ -1171,46 +1384,24 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
int rc;
- struct em28xx_frame_t *f;
- unsigned long lock_flags;
rc = check_dev(dev);
if (rc < 0)
return rc;
- if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP)
- return -EINVAL;
-
- if (list_empty(&dev->outqueue)) {
- if (dev->stream == STREAM_OFF)
- return -EINVAL;
-
- if (file->f_flags & O_NONBLOCK)
- return -EAGAIN;
-
- rc = wait_event_interruptible(dev->wait_frame,
- (!list_empty(&dev->outqueue)) ||
- (dev->state & DEV_DISCONNECTED));
- if (rc)
- return rc;
-
- if (dev->state & DEV_DISCONNECTED)
- return -ENODEV;
- }
-
- spin_lock_irqsave(&dev->queue_lock, lock_flags);
- f = list_entry(dev->outqueue.next, struct em28xx_frame_t, frame);
- list_del(dev->outqueue.next);
- spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
-
- f->state = F_UNUSED;
- memcpy(b, &f->buf, sizeof(*b));
+ return (videobuf_dqbuf(&fh->vb_vidq, b,
+ file->f_flags & O_NONBLOCK));
+}
- if (f->vma_use_count)
- b->flags |= V4L2_BUF_FLAG_MAPPED;
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
+{
+ struct em28xx_fh *fh = priv;
- return 0;
+ return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
}
+#endif
+
/* ----------------------------------------------------------- */
/* RADIO ESPECIFIC IOCTLS */
@@ -1316,17 +1507,18 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
{
int minor = iminor(inode);
int errCode = 0, radio = 0;
- struct em28xx *h,*dev = NULL;
+ struct em28xx *h, *dev = NULL;
struct em28xx_fh *fh;
+ enum v4l2_buf_type fh_type = 0;
list_for_each_entry(h, &em28xx_devlist, devlist) {
if (h->vdev->minor == minor) {
dev = h;
- dev->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
}
if (h->vbi_dev->minor == minor) {
dev = h;
- dev->type = V4L2_BUF_TYPE_VBI_CAPTURE;
+ fh_type = V4L2_BUF_TYPE_VBI_CAPTURE;
}
if (h->radio_dev &&
h->radio_dev->minor == minor) {
@@ -1338,10 +1530,10 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
return -ENODEV;
em28xx_videodbg("open minor=%d type=%s users=%d\n",
- minor,v4l2_type_names[dev->type],dev->users);
+ minor, v4l2_type_names[fh_type], dev->users);
- fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL);
+ fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL);
if (!fh) {
em28xx_errdev("em28xx-video.c: Out of memory?!\n");
return -ENOMEM;
@@ -1349,28 +1541,24 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
mutex_lock(&dev->lock);
fh->dev = dev;
fh->radio = radio;
+ fh->type = fh_type;
filp->private_data = fh;
- if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
dev->width = norm_maxw(dev);
dev->height = norm_maxh(dev);
- dev->frame_size = dev->width * dev->height * 2;
- dev->field_size = dev->frame_size >> 1; /*both_fileds ? dev->frame_size>>1 : dev->frame_size; */
- dev->bytesperline = dev->width * 2;
dev->hscale = 0;
dev->vscale = 0;
+ em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
em28xx_set_alternate(dev);
- em28xx_capture_start(dev, 1);
em28xx_resolution_set(dev);
+ /* Needed, since GPIO might have disabled power of
+ some i2c device
+ */
+ em28xx_config_i2c(dev);
- /* start the transfer */
- errCode = em28xx_init_isoc(dev);
- if (errCode)
- goto err;
-
- em28xx_empty_framequeues(dev);
}
if (fh->radio) {
em28xx_videodbg("video_open: setting radio device\n");
@@ -1379,8 +1567,12 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
dev->users++;
-err:
+ videobuf_queue_vmalloc_init(&fh->vb_vidq, &em28xx_video_qops,
+ NULL, &dev->slock, fh->type, V4L2_FIELD_INTERLACED,
+ sizeof(struct em28xx_buffer), fh);
+
mutex_unlock(&dev->lock);
+
return errCode;
}
@@ -1423,12 +1615,13 @@ static void em28xx_release_resources(struct em28xx *dev)
usb_put_dev(dev->udev);
/* Mark device as unused */
- em28xx_devused&=~(1<<dev->devno);
+ em28xx_devused &= ~(1<<dev->devno);
}
/*
* em28xx_v4l2_close()
- * stops streaming and deallocates all resources allocated by the v4l2 calls and ioctls
+ * stops streaming and deallocates all resources allocated by the v4l2
+ * calls and ioctls
*/
static int em28xx_v4l2_close(struct inode *inode, struct file *filp)
{
@@ -1445,9 +1638,8 @@ static int em28xx_v4l2_close(struct inode *inode, struct file *filp)
mutex_lock(&dev->lock);
if (dev->users == 1) {
- em28xx_uninit_isoc(dev);
- em28xx_release_buffers(dev);
- dev->io = IO_NONE;
+ videobuf_stop(&fh->vb_vidq);
+ videobuf_mmap_free(&fh->vb_vidq);
/* the device is already disconnect,
free the remaining resources */
@@ -1458,6 +1650,10 @@ static int em28xx_v4l2_close(struct inode *inode, struct file *filp)
return 0;
}
+ /* do this before setting alternate! */
+ em28xx_uninit_isoc(dev);
+ em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
+
/* set alternate 0 */
dev->alt = 0;
em28xx_videodbg("setting alternate 0\n");
@@ -1479,135 +1675,29 @@ static int em28xx_v4l2_close(struct inode *inode, struct file *filp)
* will allocate buffers when called for the first time
*/
static ssize_t
-em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count,
- loff_t * f_pos)
+em28xx_v4l2_read(struct file *filp, char __user *buf, size_t count,
+ loff_t *pos)
{
- struct em28xx_frame_t *f, *i;
- unsigned long lock_flags;
- int ret = 0;
struct em28xx_fh *fh = filp->private_data;
struct em28xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
/* FIXME: read() is not prepared to allow changing the video
resolution while streaming. Seems a bug at em28xx_set_fmt
*/
- if (unlikely(res_get(fh) < 0))
- return -EBUSY;
-
- mutex_lock(&dev->lock);
-
- if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- em28xx_videodbg("V4l2_Buf_type_videocapture is set\n");
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ if (unlikely(res_get(fh)))
+ return -EBUSY;
- if (dev->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
- em28xx_videodbg("V4L2_BUF_TYPE_VBI_CAPTURE is set\n");
- em28xx_videodbg("not supported yet! ...\n");
- if (copy_to_user(buf, "", 1)) {
- mutex_unlock(&dev->lock);
- return -EFAULT;
- }
- mutex_unlock(&dev->lock);
- return (1);
- }
- if (dev->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
- em28xx_videodbg("V4L2_BUF_TYPE_SLICED_VBI_CAPTURE is set\n");
- em28xx_videodbg("not supported yet! ...\n");
- if (copy_to_user(buf, "", 1)) {
- mutex_unlock(&dev->lock);
- return -EFAULT;
- }
- mutex_unlock(&dev->lock);
- return (1);
+ return videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0,
+ filp->f_flags & O_NONBLOCK);
}
-
- if (dev->state & DEV_DISCONNECTED) {
- em28xx_videodbg("device not present\n");
- mutex_unlock(&dev->lock);
- return -ENODEV;
- }
-
- if (dev->state & DEV_MISCONFIGURED) {
- em28xx_videodbg("device misconfigured; close and open it again\n");
- mutex_unlock(&dev->lock);
- return -EIO;
- }
-
- if (dev->io == IO_MMAP) {
- em28xx_videodbg ("IO method is set to mmap; close and open"
- " the device again to choose the read method\n");
- mutex_unlock(&dev->lock);
- return -EINVAL;
- }
-
- if (dev->io == IO_NONE) {
- if (!em28xx_request_buffers(dev, EM28XX_NUM_READ_FRAMES)) {
- em28xx_errdev("read failed, not enough memory\n");
- mutex_unlock(&dev->lock);
- return -ENOMEM;
- }
- dev->io = IO_READ;
- dev->stream = STREAM_ON;
- em28xx_queue_unusedframes(dev);
- }
-
- if (!count) {
- mutex_unlock(&dev->lock);
- return 0;
- }
-
- if (list_empty(&dev->outqueue)) {
- if (filp->f_flags & O_NONBLOCK) {
- mutex_unlock(&dev->lock);
- return -EAGAIN;
- }
- ret = wait_event_interruptible
- (dev->wait_frame,
- (!list_empty(&dev->outqueue)) ||
- (dev->state & DEV_DISCONNECTED));
- if (ret) {
- mutex_unlock(&dev->lock);
- return ret;
- }
- if (dev->state & DEV_DISCONNECTED) {
- mutex_unlock(&dev->lock);
- return -ENODEV;
- }
- dev->video_bytesread = 0;
- }
-
- f = list_entry(dev->outqueue.prev, struct em28xx_frame_t, frame);
-
- em28xx_queue_unusedframes(dev);
-
- if (count > f->buf.length)
- count = f->buf.length;
-
- if ((dev->video_bytesread + count) > dev->frame_size)
- count = dev->frame_size - dev->video_bytesread;
-
- if (copy_to_user(buf, f->bufmem+dev->video_bytesread, count)) {
- em28xx_err("Error while copying to user\n");
- return -EFAULT;
- }
- dev->video_bytesread += count;
-
- if (dev->video_bytesread == dev->frame_size) {
- spin_lock_irqsave(&dev->queue_lock, lock_flags);
- list_for_each_entry(i, &dev->outqueue, frame)
- i->state = F_UNUSED;
- INIT_LIST_HEAD(&dev->outqueue);
- spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
-
- em28xx_queue_unusedframes(dev);
- dev->video_bytesread = 0;
- }
-
- *f_pos += count;
-
- mutex_unlock(&dev->lock);
-
- return count;
+ return 0;
}
/*
@@ -1616,46 +1706,21 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count,
*/
static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait)
{
- unsigned int mask = 0;
struct em28xx_fh *fh = filp->private_data;
struct em28xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
if (unlikely(res_get(fh) < 0))
return POLLERR;
- mutex_lock(&dev->lock);
-
- if (dev->state & DEV_DISCONNECTED) {
- em28xx_videodbg("device not present\n");
- } else if (dev->state & DEV_MISCONFIGURED) {
- em28xx_videodbg("device is misconfigured; close and open it again\n");
- } else {
- if (dev->io == IO_NONE) {
- if (!em28xx_request_buffers
- (dev, EM28XX_NUM_READ_FRAMES)) {
- em28xx_warn
- ("poll() failed, not enough memory\n");
- } else {
- dev->io = IO_READ;
- dev->stream = STREAM_ON;
- }
- }
-
- if (dev->io == IO_READ) {
- em28xx_queue_unusedframes(dev);
- poll_wait(filp, &dev->wait_frame, wait);
-
- if (!list_empty(&dev->outqueue))
- mask |= POLLIN | POLLRDNORM;
-
- mutex_unlock(&dev->lock);
-
- return mask;
- }
- }
+ if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
+ return POLLERR;
- mutex_unlock(&dev->lock);
- return POLLERR;
+ return videobuf_poll_stream(filp, &fh->vb_vidq, wait);
}
/*
@@ -1665,69 +1730,23 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
{
struct em28xx_fh *fh = filp->private_data;
struct em28xx *dev = fh->dev;
- unsigned long size = vma->vm_end - vma->vm_start;
- unsigned long start = vma->vm_start;
- void *pos;
- u32 i;
+ int rc;
if (unlikely(res_get(fh) < 0))
return -EBUSY;
- mutex_lock(&dev->lock);
-
- if (dev->state & DEV_DISCONNECTED) {
- em28xx_videodbg("mmap: device not present\n");
- mutex_unlock(&dev->lock);
- return -ENODEV;
- }
-
- if (dev->state & DEV_MISCONFIGURED) {
- em28xx_videodbg ("mmap: Device is misconfigured; close and "
- "open it again\n");
- mutex_unlock(&dev->lock);
- return -EIO;
- }
-
- if (dev->io != IO_MMAP || !(vma->vm_flags & VM_WRITE)) {
- mutex_unlock(&dev->lock);
- return -EINVAL;
- }
-
- if (size > PAGE_ALIGN(dev->frame[0].buf.length))
- size = PAGE_ALIGN(dev->frame[0].buf.length);
-
- for (i = 0; i < dev->num_frames; i++) {
- if ((dev->frame[i].buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
- break;
- }
- if (i == dev->num_frames) {
- em28xx_videodbg("mmap: user supplied mapping address is out of range\n");
- mutex_unlock(&dev->lock);
- return -EINVAL;
- }
-
- /* VM_IO is eventually going to replace PageReserved altogether */
- vma->vm_flags |= VM_IO;
- vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
- pos = dev->frame[i].bufmem;
- while (size > 0) { /* size is page-aligned */
- if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
- em28xx_videodbg("mmap: vm_insert_page failed\n");
- mutex_unlock(&dev->lock);
- return -EAGAIN;
- }
- start += PAGE_SIZE;
- pos += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
+ rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
- vma->vm_ops = &em28xx_vm_ops;
- vma->vm_private_data = &dev->frame[i];
+ em28xx_videodbg("vma start=0x%08lx, size=%ld, ret=%d\n",
+ (unsigned long)vma->vm_start,
+ (unsigned long)vma->vm_end-(unsigned long)vma->vm_start,
+ rc);
- em28xx_vm_open(vma);
- mutex_unlock(&dev->lock);
- return 0;
+ return rc;
}
static const struct file_operations em28xx_v4l_fops = {
@@ -1790,6 +1809,9 @@ static const struct video_device em28xx_video_template = {
.vidioc_g_register = vidioc_g_register,
.vidioc_s_register = vidioc_s_register,
#endif
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+ .vidiocgmbuf = vidiocgmbuf,
+#endif
.tvnorms = V4L2_STD_ALL,
.current_norm = V4L2_STD_PAL,
@@ -1818,7 +1840,7 @@ static struct video_device em28xx_radio_template = {
#endif
};
-/******************************** usb interface *****************************************/
+/******************************** usb interface ******************************/
static LIST_HEAD(em28xx_extension_devlist);
@@ -1875,6 +1897,7 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev,
vfd->dev = &dev->udev->dev;
vfd->release = video_device_release;
vfd->type = type;
+ vfd->debug = video_debug;
snprintf(vfd->name, sizeof(vfd->name), "%s %s",
dev->name, type_name);
@@ -1898,7 +1921,7 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
dev->udev = udev;
mutex_init(&dev->lock);
- spin_lock_init(&dev->queue_lock);
+ spin_lock_init(&dev->slock);
init_waitqueue_head(&dev->open);
init_waitqueue_head(&dev->wait_frame);
init_waitqueue_head(&dev->wait_stream);
@@ -1910,10 +1933,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
dev->em28xx_read_reg_req = em28xx_read_reg_req;
dev->is_em2800 = em28xx_boards[dev->model].is_em2800;
- errCode = em28xx_read_reg(dev, CHIPID_REG);
- if (errCode >= 0)
- em28xx_info("em28xx chip ID = %d\n", errCode);
-
em28xx_pre_card_setup(dev);
errCode = em28xx_config(dev);
@@ -1946,10 +1965,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
dev->width = maxw;
dev->height = maxh;
dev->interlaced = EM28XX_INTERLACED_DEFAULT;
- dev->field_size = dev->width * dev->height;
- dev->frame_size =
- dev->interlaced ? dev->field_size << 1 : dev->field_size;
- dev->bytesperline = dev->width * 2;
dev->hscale = 0;
dev->vscale = 0;
dev->ctl_input = 2;
@@ -2005,6 +2020,10 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
dev->radio_dev->minor & 0x1f);
}
+ /* init video dma queues */
+ INIT_LIST_HEAD(&dev->vidq.active);
+ INIT_LIST_HEAD(&dev->vidq.queued);
+
if (dev->has_msp34xx) {
/* Send a reset to other chips via gpio */
@@ -2048,6 +2067,9 @@ static void request_module_async(struct work_struct *work)
request_module("snd-usb-audio");
else
request_module("em28xx-alsa");
+
+ if (dev->has_dvb)
+ request_module("em28xx-dvb");
}
static void request_modules(struct em28xx *dev)
@@ -2077,22 +2099,24 @@ static int em28xx_usb_probe(struct usb_interface *interface,
ifnum = interface->altsetting[0].desc.bInterfaceNumber;
/* Check to see next free device and mark as used */
- nr=find_first_zero_bit(&em28xx_devused,EM28XX_MAXBOARDS);
- em28xx_devused|=1<<nr;
+ nr = find_first_zero_bit(&em28xx_devused, EM28XX_MAXBOARDS);
+ em28xx_devused |= 1<<nr;
/* Don't register audio interfaces */
if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
em28xx_err(DRIVER_NAME " audio device (%04x:%04x): interface %i, class %i\n",
- udev->descriptor.idVendor,udev->descriptor.idProduct,
+ udev->descriptor.idVendor,
+ udev->descriptor.idProduct,
ifnum,
interface->altsetting[0].desc.bInterfaceClass);
- em28xx_devused&=~(1<<nr);
+ em28xx_devused &= ~(1<<nr);
return -ENODEV;
}
em28xx_err(DRIVER_NAME " new video device (%04x:%04x): interface %i, class %i\n",
- udev->descriptor.idVendor,udev->descriptor.idProduct,
+ udev->descriptor.idVendor,
+ udev->descriptor.idProduct,
ifnum,
interface->altsetting[0].desc.bInterfaceClass);
@@ -2102,18 +2126,19 @@ static int em28xx_usb_probe(struct usb_interface *interface,
if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
USB_ENDPOINT_XFER_ISOC) {
em28xx_err(DRIVER_NAME " probing error: endpoint is non-ISO endpoint!\n");
- em28xx_devused&=~(1<<nr);
+ em28xx_devused &= ~(1<<nr);
return -ENODEV;
}
if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) {
em28xx_err(DRIVER_NAME " probing error: endpoint is ISO OUT endpoint!\n");
- em28xx_devused&=~(1<<nr);
+ em28xx_devused &= ~(1<<nr);
return -ENODEV;
}
if (nr >= EM28XX_MAXBOARDS) {
- printk (DRIVER_NAME ": Supports only %i em28xx boards.\n",EM28XX_MAXBOARDS);
- em28xx_devused&=~(1<<nr);
+ printk(DRIVER_NAME ": Supports only %i em28xx boards.\n",
+ EM28XX_MAXBOARDS);
+ em28xx_devused &= ~(1<<nr);
return -ENOMEM;
}
@@ -2121,7 +2146,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (dev == NULL) {
em28xx_err(DRIVER_NAME ": out of memory!\n");
- em28xx_devused&=~(1<<nr);
+ em28xx_devused &= ~(1<<nr);
return -ENOMEM;
}
@@ -2145,14 +2170,14 @@ static int em28xx_usb_probe(struct usb_interface *interface,
/* compute alternate max packet sizes */
uif = udev->actconfig->interface[0];
- dev->num_alt=uif->num_altsetting;
- em28xx_info("Alternate settings: %i\n",dev->num_alt);
-// dev->alt_max_pkt_size = kmalloc(sizeof(*dev->alt_max_pkt_size)*
- dev->alt_max_pkt_size = kmalloc(32*
- dev->num_alt,GFP_KERNEL);
+ dev->num_alt = uif->num_altsetting;
+ em28xx_info("Alternate settings: %i\n", dev->num_alt);
+/* dev->alt_max_pkt_size = kmalloc(sizeof(*dev->alt_max_pkt_size)* */
+ dev->alt_max_pkt_size = kmalloc(32 * dev->num_alt, GFP_KERNEL);
+
if (dev->alt_max_pkt_size == NULL) {
em28xx_errdev("out of memory!\n");
- em28xx_devused&=~(1<<nr);
+ em28xx_devused &= ~(1<<nr);
kfree(dev);
return -ENOMEM;
}
@@ -2162,11 +2187,11 @@ static int em28xx_usb_probe(struct usb_interface *interface,
wMaxPacketSize);
dev->alt_max_pkt_size[i] =
(tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
- em28xx_info("Alternate setting %i, max size= %i\n",i,
- dev->alt_max_pkt_size[i]);
+ em28xx_info("Alternate setting %i, max size= %i\n", i,
+ dev->alt_max_pkt_size[i]);
}
- if ((card[nr]>=0)&&(card[nr]<em28xx_bcount))
+ if ((card[nr] >= 0) && (card[nr] < em28xx_bcount))
dev->model = card[nr];
/* allocate device struct */
@@ -2202,7 +2227,8 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
em28xx_info("disconnecting %s\n", dev->vdev->name);
- /* wait until all current v4l2 io is finished then deallocate resources */
+ /* wait until all current v4l2 io is finished then deallocate
+ resources */
mutex_lock(&dev->lock);
wake_up_interruptible_all(&dev->open);
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h
index 04e0e48ecab..002f170b211 100644
--- a/drivers/media/video/em28xx/em28xx.h
+++ b/drivers/media/video/em28xx/em28xx.h
@@ -26,11 +26,39 @@
#define _EM28XX_H
#include <linux/videodev2.h>
+#include <media/videobuf-vmalloc.h>
+
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <media/ir-kbd-i2c.h>
-
-#define UNSET -1
+#if defined(CONFIG_VIDEO_EM28XX_DVB) || defined(CONFIG_VIDEO_EM28XX_DVB_MODULE)
+#include <media/videobuf-dvb.h>
+#endif
+#include "tuner-xc2028.h"
+#include "em28xx-reg.h"
+
+/* Boards supported by driver */
+#define EM2800_BOARD_UNKNOWN 0
+#define EM2820_BOARD_UNKNOWN 1
+#define EM2820_BOARD_TERRATEC_CINERGY_250 2
+#define EM2820_BOARD_PINNACLE_USB_2 3
+#define EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 4
+#define EM2820_BOARD_MSI_VOX_USB_2 5
+#define EM2800_BOARD_TERRATEC_CINERGY_200 6
+#define EM2800_BOARD_LEADTEK_WINFAST_USBII 7
+#define EM2800_BOARD_KWORLD_USB2800 8
+#define EM2820_BOARD_PINNACLE_DVC_90 9
+#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 10
+#define EM2880_BOARD_TERRATEC_HYBRID_XS 11
+#define EM2820_BOARD_KWORLD_PVRTV2800RF 12
+#define EM2880_BOARD_TERRATEC_PRODIGY_XS 13
+#define EM2820_BOARD_PROLINK_PLAYTV_USB2 14
+#define EM2800_BOARD_VGEAR_POCKETTV 15
+#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 16
+
+/* Limits minimum and default number of buffers */
+#define EM28XX_MIN_BUF 4
+#define EM28XX_DEF_BUF 8
/* maximum number of em28xx boards */
#define EM28XX_MAXBOARDS 4 /*FIXME: should be bigger */
@@ -81,31 +109,78 @@
/* time in msecs to wait for i2c writes to finish */
#define EM2800_I2C_WRITE_TIMEOUT 20
-/* the various frame states */
-enum em28xx_frame_state {
- F_UNUSED = 0,
- F_QUEUED,
- F_GRABBING,
- F_DONE,
- F_ERROR,
+enum em28xx_mode {
+ EM28XX_MODE_UNDEFINED,
+ EM28XX_ANALOG_MODE,
+ EM28XX_DIGITAL_MODE,
};
-/* stream states */
enum em28xx_stream_state {
STREAM_OFF,
STREAM_INTERRUPT,
STREAM_ON,
};
-/* frames */
-struct em28xx_frame_t {
- void *bufmem;
- struct v4l2_buffer buf;
- enum em28xx_frame_state state;
+struct em28xx;
+
+struct em28xx_usb_isoc_ctl {
+ /* max packet size of isoc transaction */
+ int max_pkt_size;
+
+ /* number of allocated urbs */
+ int num_bufs;
+
+ /* urb for isoc transfers */
+ struct urb **urb;
+
+ /* transfer buffers for isoc transfer */
+ char **transfer_buffer;
+
+ /* Last buffer command and region */
+ u8 cmd;
+ int pos, size, pktsize;
+
+ /* Last field: ODD or EVEN? */
+ int field;
+
+ /* Stores incomplete commands */
+ u32 tmp_buf;
+ int tmp_buf_len;
+
+ /* Stores already requested buffers */
+ struct em28xx_buffer *buf;
+
+ /* Stores the number of received fields */
+ int nfields;
+
+ /* isoc urb callback */
+ int (*isoc_copy) (struct em28xx *dev, struct urb *urb);
+
+};
+
+struct em28xx_fmt {
+ char *name;
+ u32 fourcc; /* v4l2 format id */
+};
+
+/* buffer for one video frame */
+struct em28xx_buffer {
+ /* common v4l buffer stuff -- must be first */
+ struct videobuf_buffer vb;
+
struct list_head frame;
- unsigned long vma_use_count;
int top_field;
- int fieldbytesused;
+ int receiving;
+};
+
+struct em28xx_dmaqueue {
+ struct list_head active;
+ struct list_head queued;
+
+ wait_queue_head_t wq;
+
+ /* Counters to control buffer fill */
+ int pos;
};
/* io methods */
@@ -152,6 +227,12 @@ enum em28xx_decoder {
EM28XX_SAA7114
};
+struct em28xx_reg_seq {
+ int reg;
+ unsigned char val, mask;
+ int sleep;
+};
+
struct em28xx_board {
char *name;
int vchannels;
@@ -165,8 +246,7 @@ struct em28xx_board {
unsigned int mts_firmware:1;
unsigned int has_12mhz_i2s:1;
unsigned int max_range_640_480:1;
-
- unsigned int analog_gpio;
+ unsigned int has_dvb:1;
enum em28xx_decoder decoder;
@@ -199,7 +279,10 @@ enum em28xx_dev_state {
#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
struct em28xx_audio {
char name[50];
@@ -217,13 +300,24 @@ struct em28xx_audio {
spinlock_t slock;
};
+struct em28xx;
+
+struct em28xx_fh {
+ struct em28xx *dev;
+ unsigned int stream_on:1; /* Locks streams */
+ int radio;
+
+ struct videobuf_queue vb_vidq;
+
+ enum v4l2_buf_type type;
+};
+
/* main device struct */
struct em28xx {
/* generic device properties */
char name[30]; /* name (including minor) of the device */
int model; /* index in the device_data struct */
int devno; /* marks the number of this device */
- unsigned int analog_gpio;
unsigned int is_em2800:1;
unsigned int has_msp34xx:1;
unsigned int has_tda9887:1;
@@ -231,6 +325,16 @@ struct em28xx {
unsigned int has_audio_class:1;
unsigned int has_12mhz_i2s:1;
unsigned int max_range_640_480:1;
+ unsigned int has_dvb:1;
+
+ /* Some older em28xx chips needs a waiting time after writing */
+ unsigned int wait_after_write;
+
+ /* GPIO sequences for analog and digital mode */
+ struct em28xx_reg_seq *analog_gpio, *digital_gpio;
+
+ /* GPIO sequences for tuner callbacks */
+ struct em28xx_reg_seq *tun_analog_gpio, *tun_digital_gpio;
int video_inputs; /* number of video inputs */
struct list_head devlist;
@@ -255,36 +359,28 @@ struct em28xx {
int mute;
int volume;
/* frame properties */
- struct em28xx_frame_t frame[EM28XX_NUM_FRAMES]; /* list of frames */
- int num_frames; /* number of frames currently in use */
- unsigned int frame_count; /* total number of transfered frames */
- struct em28xx_frame_t *frame_current; /* the frame that is being filled */
int width; /* current frame width */
int height; /* current frame height */
- int frame_size; /* current frame size */
- int field_size; /* current field size */
- int bytesperline;
int hscale; /* horizontal scale factor (see datasheet) */
int vscale; /* vertical scale factor (see datasheet) */
int interlaced; /* 1=interlace fileds, 0=just top fileds */
- int type;
unsigned int video_bytesread; /* Number of bytes read */
unsigned long hash; /* eeprom hash - for boards with generic ID */
- unsigned long i2c_hash; /* i2c devicelist hash - for boards with generic ID */
+ unsigned long i2c_hash; /* i2c devicelist hash -
+ for boards with generic ID */
struct em28xx_audio *adev;
/* states */
enum em28xx_dev_state state;
- enum em28xx_stream_state stream;
enum em28xx_io_method io;
struct work_struct request_module_wk;
/* locks */
struct mutex lock;
- spinlock_t queue_lock;
+ /* spinlock_t queue_lock; */
struct list_head inqueue, outqueue;
wait_queue_head_t open, wait_frame, wait_stream;
struct video_device *vbi_dev;
@@ -292,6 +388,11 @@ struct em28xx {
unsigned char eedata[256];
+ /* Isoc control struct */
+ struct em28xx_dmaqueue vidq;
+ struct em28xx_usb_isoc_ctl isoc_ctl;
+ spinlock_t slock;
+
/* usb transfer */
struct usb_device *udev; /* the usb device */
int alt; /* alternate */
@@ -301,20 +402,21 @@ struct em28xx {
struct urb *urb[EM28XX_NUM_BUFS]; /* urb for isoc transfers */
char *transfer_buffer[EM28XX_NUM_BUFS]; /* transfer buffers for isoc transfer */
/* helper funcs that call usb_control_msg */
- int (*em28xx_write_regs) (struct em28xx * dev, u16 reg, char *buf,
- int len);
- int (*em28xx_read_reg) (struct em28xx * dev, u16 reg);
- int (*em28xx_read_reg_req_len) (struct em28xx * dev, u8 req, u16 reg,
+ int (*em28xx_write_regs) (struct em28xx *dev, u16 reg,
char *buf, int len);
- int (*em28xx_write_regs_req) (struct em28xx * dev, u8 req, u16 reg,
+ int (*em28xx_read_reg) (struct em28xx *dev, u16 reg);
+ int (*em28xx_read_reg_req_len) (struct em28xx *dev, u8 req, u16 reg,
+ char *buf, int len);
+ int (*em28xx_write_regs_req) (struct em28xx *dev, u8 req, u16 reg,
char *buf, int len);
- int (*em28xx_read_reg_req) (struct em28xx * dev, u8 req, u16 reg);
-};
+ int (*em28xx_read_reg_req) (struct em28xx *dev, u8 req, u16 reg);
-struct em28xx_fh {
- struct em28xx *dev;
- unsigned int stream_on:1; /* Locks streams */
- int radio;
+ enum em28xx_mode mode;
+
+ /* Caches GPO and GPIO registers */
+ unsigned char reg_gpo, reg_gpio;
+
+ struct em28xx_dvb *dvb;
};
struct em28xx_ops {
@@ -351,22 +453,27 @@ int em28xx_colorlevels_set_default(struct em28xx *dev);
int em28xx_capture_start(struct em28xx *dev, int start);
int em28xx_outfmt_set_yuv422(struct em28xx *dev);
int em28xx_resolution_set(struct em28xx *dev);
-int em28xx_init_isoc(struct em28xx *dev);
-void em28xx_uninit_isoc(struct em28xx *dev);
int em28xx_set_alternate(struct em28xx *dev);
+int em28xx_init_isoc(struct em28xx *dev, int max_packets,
+ int num_bufs, int max_pkt_size,
+ int (*isoc_copy) (struct em28xx *dev, struct urb *urb));
+void em28xx_uninit_isoc(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);
/* Provided by em28xx-video.c */
int em28xx_register_extension(struct em28xx_ops *dev);
void em28xx_unregister_extension(struct em28xx_ops *dev);
/* Provided by em28xx-cards.c */
-extern int em2800_variant_detect(struct usb_device* udev,int model);
+extern int em2800_variant_detect(struct usb_device *udev, int model);
extern void em28xx_pre_card_setup(struct em28xx *dev);
extern void em28xx_card_setup(struct em28xx *dev);
extern struct em28xx_board em28xx_boards[];
extern struct usb_device_id em28xx_id_table[];
extern const unsigned int em28xx_bcount;
void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir);
+int em28xx_tuner_callback(void *ptr, int command, int arg);
/* Provided by em28xx-input.c */
/* TODO: Check if the standard get_key handlers on ir-common can be used */
@@ -375,71 +482,6 @@ int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
u32 *ir_raw);
-/* em2800 registers */
-#define EM2800_AUDIOSRC_REG 0x08
-
-/* em28xx registers */
-#define I2C_CLK_REG 0x06
-#define CHIPID_REG 0x0a
-#define USBSUSP_REG 0x0c /* */
-
-#define AUDIOSRC_REG 0x0e
-#define XCLK_REG 0x0f
-
-#define VINMODE_REG 0x10
-#define VINCTRL_REG 0x11
-#define VINENABLE_REG 0x12 /* */
-
-#define GAMMA_REG 0x14
-#define RGAIN_REG 0x15
-#define GGAIN_REG 0x16
-#define BGAIN_REG 0x17
-#define ROFFSET_REG 0x18
-#define GOFFSET_REG 0x19
-#define BOFFSET_REG 0x1a
-
-#define OFLOW_REG 0x1b
-#define HSTART_REG 0x1c
-#define VSTART_REG 0x1d
-#define CWIDTH_REG 0x1e
-#define CHEIGHT_REG 0x1f
-
-#define YGAIN_REG 0x20
-#define YOFFSET_REG 0x21
-#define UVGAIN_REG 0x22
-#define UOFFSET_REG 0x23
-#define VOFFSET_REG 0x24
-#define SHARPNESS_REG 0x25
-
-#define COMPR_REG 0x26
-#define OUTFMT_REG 0x27
-
-#define XMIN_REG 0x28
-#define XMAX_REG 0x29
-#define YMIN_REG 0x2a
-#define YMAX_REG 0x2b
-
-#define HSCALELOW_REG 0x30
-#define HSCALEHIGH_REG 0x31
-#define VSCALELOW_REG 0x32
-#define VSCALEHIGH_REG 0x33
-
-#define AC97LSB_REG 0x40
-#define AC97MSB_REG 0x41
-#define AC97ADDR_REG 0x42
-#define AC97BUSY_REG 0x43
-
-/* em202 registers */
-#define MASTER_AC97 0x02
-#define LINE_IN_AC97 0x10
-#define VIDEO_AC97 0x14
-
-/* register settings */
-#define EM2800_AUDIO_SRC_TUNER 0x0d
-#define EM2800_AUDIO_SRC_LINE 0x0c
-#define EM28XX_AUDIO_SRC_TUNER 0xc0
-#define EM28XX_AUDIO_SRC_LINE 0x80
-
/* printk macros */
#define em28xx_err(fmt, arg...) do {\
@@ -456,80 +498,80 @@ int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
printk(KERN_WARNING "%s: "fmt,\
dev->name , ##arg); } while (0)
-inline static int em28xx_compression_disable(struct em28xx *dev)
+static inline int em28xx_compression_disable(struct em28xx *dev)
{
/* side effect of disabling scaler and mixer */
- return em28xx_write_regs(dev, COMPR_REG, "\x00", 1);
+ return em28xx_write_regs(dev, EM28XX_R26_COMPR, "\x00", 1);
}
-inline static int em28xx_contrast_get(struct em28xx *dev)
+static inline int em28xx_contrast_get(struct em28xx *dev)
{
- return em28xx_read_reg(dev, YGAIN_REG) & 0x1f;
+ return em28xx_read_reg(dev, EM28XX_R20_YGAIN) & 0x1f;
}
-inline static int em28xx_brightness_get(struct em28xx *dev)
+static inline int em28xx_brightness_get(struct em28xx *dev)
{
- return em28xx_read_reg(dev, YOFFSET_REG);
+ return em28xx_read_reg(dev, EM28XX_R21_YOFFSET);
}
-inline static int em28xx_saturation_get(struct em28xx *dev)
+static inline int em28xx_saturation_get(struct em28xx *dev)
{
- return em28xx_read_reg(dev, UVGAIN_REG) & 0x1f;
+ return em28xx_read_reg(dev, EM28XX_R22_UVGAIN) & 0x1f;
}
-inline static int em28xx_u_balance_get(struct em28xx *dev)
+static inline int em28xx_u_balance_get(struct em28xx *dev)
{
- return em28xx_read_reg(dev, UOFFSET_REG);
+ return em28xx_read_reg(dev, EM28XX_R23_UOFFSET);
}
-inline static int em28xx_v_balance_get(struct em28xx *dev)
+static inline int em28xx_v_balance_get(struct em28xx *dev)
{
- return em28xx_read_reg(dev, VOFFSET_REG);
+ return em28xx_read_reg(dev, EM28XX_R24_VOFFSET);
}
-inline static int em28xx_gamma_get(struct em28xx *dev)
+static inline int em28xx_gamma_get(struct em28xx *dev)
{
- return em28xx_read_reg(dev, GAMMA_REG) & 0x3f;
+ return em28xx_read_reg(dev, EM28XX_R14_GAMMA) & 0x3f;
}
-inline static int em28xx_contrast_set(struct em28xx *dev, s32 val)
+static inline int em28xx_contrast_set(struct em28xx *dev, s32 val)
{
u8 tmp = (u8) val;
- return em28xx_write_regs(dev, YGAIN_REG, &tmp, 1);
+ return em28xx_write_regs(dev, EM28XX_R20_YGAIN, &tmp, 1);
}
-inline static int em28xx_brightness_set(struct em28xx *dev, s32 val)
+static inline int em28xx_brightness_set(struct em28xx *dev, s32 val)
{
u8 tmp = (u8) val;
- return em28xx_write_regs(dev, YOFFSET_REG, &tmp, 1);
+ return em28xx_write_regs(dev, EM28XX_R21_YOFFSET, &tmp, 1);
}
-inline static int em28xx_saturation_set(struct em28xx *dev, s32 val)
+static inline int em28xx_saturation_set(struct em28xx *dev, s32 val)
{
u8 tmp = (u8) val;
- return em28xx_write_regs(dev, UVGAIN_REG, &tmp, 1);
+ return em28xx_write_regs(dev, EM28XX_R22_UVGAIN, &tmp, 1);
}
-inline static int em28xx_u_balance_set(struct em28xx *dev, s32 val)
+static inline int em28xx_u_balance_set(struct em28xx *dev, s32 val)
{
u8 tmp = (u8) val;
- return em28xx_write_regs(dev, UOFFSET_REG, &tmp, 1);
+ return em28xx_write_regs(dev, EM28XX_R23_UOFFSET, &tmp, 1);
}
-inline static int em28xx_v_balance_set(struct em28xx *dev, s32 val)
+static inline int em28xx_v_balance_set(struct em28xx *dev, s32 val)
{
u8 tmp = (u8) val;
- return em28xx_write_regs(dev, VOFFSET_REG, &tmp, 1);
+ return em28xx_write_regs(dev, EM28XX_R24_VOFFSET, &tmp, 1);
}
-inline static int em28xx_gamma_set(struct em28xx *dev, s32 val)
+static inline int em28xx_gamma_set(struct em28xx *dev, s32 val)
{
u8 tmp = (u8) val;
- return em28xx_write_regs(dev, GAMMA_REG, &tmp, 1);
+ return em28xx_write_regs(dev, EM28XX_R14_GAMMA, &tmp, 1);
}
/*FIXME: maxw should be dependent of alt mode */
-inline static unsigned int norm_maxw(struct em28xx *dev)
+static inline unsigned int norm_maxw(struct em28xx *dev)
{
if (dev->max_range_640_480)
return 640;
@@ -537,7 +579,7 @@ inline static unsigned int norm_maxw(struct em28xx *dev)
return 720;
}
-inline static unsigned int norm_maxh(struct em28xx *dev)
+static inline unsigned int norm_maxh(struct em28xx *dev)
{
if (dev->max_range_640_480)
return 480;