summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--linux/Documentation/video4linux/CARDLIST.em282013
-rw-r--r--linux/Documentation/video4linux/CARDLIST.em28xx13
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-cards.c124
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-core.c13
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-i2c.c182
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-video.c80
-rw-r--r--linux/drivers/media/video/em28xx/em28xx.h29
-rw-r--r--linux/drivers/usb/media/em2820-cards.c124
-rw-r--r--linux/drivers/usb/media/em2820-core.c13
-rw-r--r--linux/drivers/usb/media/em2820-i2c.c182
-rw-r--r--linux/drivers/usb/media/em2820-video.c80
-rw-r--r--linux/drivers/usb/media/em2820.h29
-rw-r--r--v4l/ChangeLog23
-rw-r--r--v4l/scripts/cardlist2
-rw-r--r--v4l/scripts/em2820.pl31
15 files changed, 783 insertions, 155 deletions
diff --git a/linux/Documentation/video4linux/CARDLIST.em2820 b/linux/Documentation/video4linux/CARDLIST.em2820
index a33ddea0b..d86aae094 100644
--- a/linux/Documentation/video4linux/CARDLIST.em2820
+++ b/linux/Documentation/video4linux/CARDLIST.em2820
@@ -1,4 +1,9 @@
- 0 -> Terratec Cinergy 250 USB [0ccd:0036]
- 1 -> Pinnacle PCTV USB 2 [2304:0208]
- 2 -> Hauppauge WinTV USB 2 [2040:4200]
- 3 -> MSI VOX USB 2.0 [eb1a:2820]
+ 0 -> Unknown EM2800 video grabber (em2800) [eb1a:2800]
+ 1 -> Unknown EM2820/2840 video grabber (em2820/em2840) [eb1a:2820]
+ 2 -> Terratec Cinergy 250 USB (em2820/em2840) [0ccd:0036]
+ 3 -> Pinnacle PCTV USB 2 (em2820/em2840) [2304:0208]
+ 4 -> Hauppauge WinTV USB 2 (em2820/em2840) [2040:4200]
+ 5 -> MSI VOX USB 2.0 (em2820/em2840)
+ 6 -> Terratec Cinergy 200 USB (em2800)
+ 7 -> Leadtek Winfast USB II (em2800)
+ 8 -> Kworld USB2800 (em2800)
diff --git a/linux/Documentation/video4linux/CARDLIST.em28xx b/linux/Documentation/video4linux/CARDLIST.em28xx
index a33ddea0b..d86aae094 100644
--- a/linux/Documentation/video4linux/CARDLIST.em28xx
+++ b/linux/Documentation/video4linux/CARDLIST.em28xx
@@ -1,4 +1,9 @@
- 0 -> Terratec Cinergy 250 USB [0ccd:0036]
- 1 -> Pinnacle PCTV USB 2 [2304:0208]
- 2 -> Hauppauge WinTV USB 2 [2040:4200]
- 3 -> MSI VOX USB 2.0 [eb1a:2820]
+ 0 -> Unknown EM2800 video grabber (em2800) [eb1a:2800]
+ 1 -> Unknown EM2820/2840 video grabber (em2820/em2840) [eb1a:2820]
+ 2 -> Terratec Cinergy 250 USB (em2820/em2840) [0ccd:0036]
+ 3 -> Pinnacle PCTV USB 2 (em2820/em2840) [2304:0208]
+ 4 -> Hauppauge WinTV USB 2 (em2820/em2840) [2040:4200]
+ 5 -> MSI VOX USB 2.0 (em2820/em2840)
+ 6 -> Terratec Cinergy 200 USB (em2800)
+ 7 -> Leadtek Winfast USB II (em2800)
+ 8 -> Kworld USB2800 (em2800)
diff --git a/linux/drivers/media/video/em28xx/em28xx-cards.c b/linux/drivers/media/video/em28xx/em28xx-cards.c
index d9014eb89..57d88e44f 100644
--- a/linux/drivers/media/video/em28xx/em28xx-cards.c
+++ b/linux/drivers/media/video/em28xx/em28xx-cards.c
@@ -1,5 +1,5 @@
/*
- em2820-cards.c - driver for Empia EM2820/2840 USB video capture devices
+ em2820-cards.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
Copyright (C) 2005 Markus Rechberger <mrechberger@gmail.com>
Ludovico Cavedon <cavedon@sssup.it>
@@ -36,31 +36,34 @@
#include "em2820.h"
-enum em2820_board_entry {
-#if 0
- EM2800_BOARD_TERRATEC_CINERGY_200,
-#endif
- EM2820_BOARD_TERRATEC_CINERGY_250,
- EM2820_BOARD_PINNACLE_USB_2,
- EM2820_BOARD_HAUPPAUGE_WINTV_USB_2,
- EM2820_BOARD_MSI_VOX_USB_2
-};
-
struct em2820_board em2820_boards[] = {
-#if 0
- [EM2800_BOARD_TERRATEC_CINERGY_200] = {
- .name = "Terratec Cinergy 200 USB",
- .vchannels = 3,
+ [EM2800_BOARD_UNKNOWN] = {
+ .name = "Unknown EM2800 video grabber",
+ .is_em2800 = 1,
+ .vchannels = 2,
.norm = VIDEO_MODE_PAL,
- .tuner_type = TUNER_LG_PAL_NEW_TAPC,
.tda9887_conf = TDA9887_PRESENT,
.has_tuner = 1,
.decoder = EM2820_SAA7113,
- .input = {{
- .type = EM2820_VMUX_TELEVISION,
- .vmux = 2,
- .amux = 0,
+ .input = {{
+ .type = EM2820_VMUX_COMPOSITE1,
+ .vmux = 0,
+ .amux = 1,
},{
+ .type = EM2820_VMUX_SVIDEO,
+ .vmux = 9,
+ .amux = 1,
+ }},
+ },
+ [EM2820_BOARD_UNKNOWN] = {
+ .name = "Unknown EM2820/2840 video grabber",
+ .is_em2800 = 0,
+ .vchannels = 2,
+ .norm = VIDEO_MODE_PAL,
+ .tda9887_conf = TDA9887_PRESENT,
+ .has_tuner = 1,
+ .decoder = EM2820_SAA7113,
+ .input = {{
.type = EM2820_VMUX_COMPOSITE1,
.vmux = 0,
.amux = 1,
@@ -70,7 +73,6 @@ struct em2820_board em2820_boards[] = {
.amux = 1,
}},
},
-#endif
[EM2820_BOARD_TERRATEC_CINERGY_250] = {
.name = "Terratec Cinergy 250 USB",
.vchannels = 3,
@@ -157,17 +159,88 @@ struct em2820_board em2820_boards[] = {
.amux = 1,
}},
},
- { } /* Terminating entry */
+ [EM2800_BOARD_TERRATEC_CINERGY_200] = {
+ .name = "Terratec Cinergy 200 USB",
+ .chip_id = 0x4,
+ .is_em2800 = 1,
+ .vchannels = 3,
+ .norm = VIDEO_MODE_PAL,
+ .tuner_type = TUNER_LG_PAL_NEW_TAPC,
+ .tda9887_conf = TDA9887_PRESENT,
+ .has_tuner = 1,
+ .decoder = EM2820_SAA7113,
+ .input = {{
+ .type = EM2820_VMUX_TELEVISION,
+ .vmux = 2,
+ .amux = 0,
+ },{
+ .type = EM2820_VMUX_COMPOSITE1,
+ .vmux = 0,
+ .amux = 1,
+ },{
+ .type = EM2820_VMUX_SVIDEO,
+ .vmux = 9,
+ .amux = 1,
+ }},
+ },
+ [EM2800_BOARD_LEADTEK_WINFAST_USBII] = {
+ .name = "Leadtek Winfast USB II",
+ .chip_id = 0x2,
+ .is_em2800 = 1,
+ .vchannels = 3,
+ .norm = VIDEO_MODE_PAL,
+ .tuner_type = TUNER_LG_PAL_NEW_TAPC,
+ .tda9887_conf = TDA9887_PRESENT,
+ .has_tuner = 1,
+ .decoder = EM2820_SAA7113,
+ .input = {{
+ .type = EM2820_VMUX_TELEVISION,
+ .vmux = 2,
+ .amux = 0,
+ },{
+ .type = EM2820_VMUX_COMPOSITE1,
+ .vmux = 0,
+ .amux = 1,
+ },{
+ .type = EM2820_VMUX_SVIDEO,
+ .vmux = 9,
+ .amux = 1,
+ }},
+ },
+ [EM2800_BOARD_KWORLD_USB2800] = {
+ .name = "Kworld USB2800",
+ .chip_id = 0x7,
+ .is_em2800 = 1,
+ .vchannels = 3,
+ .norm = VIDEO_MODE_PAL,
+ .tuner_type = TUNER_PHILIPS_ATSC,
+ .tda9887_conf = TDA9887_PRESENT,
+ .has_tuner = 1,
+ .decoder = EM2820_SAA7113,
+ .input = {{
+ .type = EM2820_VMUX_TELEVISION,
+ .vmux = 2,
+ .amux = 0,
+ },{
+ .type = EM2820_VMUX_COMPOSITE1,
+ .vmux = 0,
+ .amux = 1,
+ },{
+ .type = EM2820_VMUX_SVIDEO,
+ .vmux = 9,
+ .amux = 1,
+ }},
+ },
};
+const unsigned int em2820_bcount = ARRAY_SIZE(em2820_boards);
/* table of devices that work with this driver */
struct usb_device_id em2820_id_table [] = {
- /* Terratec Cinerhy 200 USB: em2800 nor supported, at the moment */
- /* { USB_DEVICE(0xeb1a, 0x2800), .driver_info = EM2800_BOARD_TERRATEC_CINERGY_200 }, */
+ { USB_DEVICE(0xeb1a, 0x2800), .driver_info = EM2800_BOARD_UNKNOWN },
+ { USB_DEVICE(0xeb1a, 0x2820), .driver_info = EM2820_BOARD_UNKNOWN },
{ USB_DEVICE(0x0ccd, 0x0036), .driver_info = EM2820_BOARD_TERRATEC_CINERGY_250 },
{ USB_DEVICE(0x2304, 0x0208), .driver_info = EM2820_BOARD_PINNACLE_USB_2 },
{ USB_DEVICE(0x2040, 0x4200), .driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 },
- { USB_DEVICE(0xeb1a, 0x2820), .driver_info = EM2820_BOARD_MSI_VOX_USB_2 },
{ },
};
@@ -499,6 +572,7 @@ void em2820_card_setup(struct em2820 *dev)
}
EXPORT_SYMBOL(em2820_boards);
+EXPORT_SYMBOL(em2820_bcount);
EXPORT_SYMBOL(em2820_id_table);
MODULE_DEVICE_TABLE (usb, em2820_id_table);
diff --git a/linux/drivers/media/video/em28xx/em28xx-core.c b/linux/drivers/media/video/em28xx/em28xx-core.c
index 4bc4b4c6c..07fcfcc9b 100644
--- a/linux/drivers/media/video/em28xx/em28xx-core.c
+++ b/linux/drivers/media/video/em28xx/em28xx-core.c
@@ -1,5 +1,5 @@
/*
- em2820-core.c - driver for Empia EM2820/2840 USB video capture devices
+ em2820-core.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
Copyright (C) 2005 Markus Rechberger <mrechberger@gmail.com>
Ludovico Cavedon <cavedon@sssup.it>
@@ -570,6 +570,11 @@ static inline void em2820_isoc_video_copy(struct em2820 *dev,
void *fieldstart, *startwrite, *startread;
int linesdone, currlinedone, offset, lencopy,remain;
+ if(dev->frame_size != (*f)->buf.length){
+ em2820_err("frame_size %i and buf.length %i are different!!!\n",dev->frame_size,(*f)->buf.length);
+ return;
+ }
+
if ((*f)->fieldbytesused + len > dev->field_size)
len =dev->field_size - (*f)->fieldbytesused;
remain = len;
@@ -788,6 +793,11 @@ int em2820_set_alternate(struct em2820 *dev)
dev->alt = alt;
if (dev->alt == 0) {
int i;
+ if(dev->is_em2800){ /* always use the max packet size for em2800 based devices */
+ for(i=0;i< EM2820_MAX_ALT; i++)
+ if(dev->alt_max_pkt_size[i]>dev->alt_max_pkt_size[dev->alt])
+ dev->alt=i;
+ }else{
unsigned int min_pkt_size = dev->field_size / 137; /* FIXME: empiric magic number */
em2820_coredbg("minimum isoc packet size: %u", min_pkt_size);
dev->alt = 7;
@@ -796,6 +806,7 @@ int em2820_set_alternate(struct em2820 *dev)
dev->alt = i;
break;
}
+ }
}
if (dev->alt != prev_alt) {
diff --git a/linux/drivers/media/video/em28xx/em28xx-i2c.c b/linux/drivers/media/video/em28xx/em28xx-i2c.c
index fa56179b0..3413ec51c 100644
--- a/linux/drivers/media/video/em28xx/em28xx-i2c.c
+++ b/linux/drivers/media/video/em28xx/em28xx-i2c.c
@@ -1,5 +1,5 @@
/*
- em2820-i2c.c - driver for Empia EM2820/2840 USB video capture devices
+ em2820-i2c.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
Copyright (C) 2005 Markus Rechberger <mrechberger@gmail.com>
Ludovico Cavedon <cavedon@sssup.it>
@@ -29,11 +29,6 @@
#include <media/tuner.h>
#include <linux/video_decoder.h>
-/* To be moved to compat.h */
-#if !defined(I2C_HW_B_EM2820)
-#define I2C_HW_B_EM2820 0x99
-#endif
-
#include "em2820.h"
/* ----------------------------------------------------------- */
@@ -56,11 +51,132 @@ MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
printk(fmt, ##args); } while (0)
/*
- * i2c_send_bytes()
+ * em2800_i2c_send_max4()
+ * send up to 4 bytes to the i2c device
+ */
+static int em2800_i2c_send_max4(struct em2820 *dev, unsigned char addr,
+ char *buf, int len)
+{
+ int ret;
+ int write_timeout;
+ unsigned char b2[6];
+ BUG_ON(len < 1 || len > 4);
+ b2[5] = 0x80 + len - 1;
+ b2[4] = addr;
+ b2[3] = buf[0];
+ if (len > 1)
+ b2[2] = buf[1];
+ if (len > 2)
+ b2[1] = buf[2];
+ if (len > 3)
+ b2[0] = buf[3];
+
+ ret = dev->em2820_write_regs(dev, 4 - len, &b2[4 - len], 2 + len);
+ if (ret != 2 + len) {
+ em2820_warn("writting to i2c device failed (error=%i)\n", ret);
+ return -EIO;
+ }
+ for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0;
+ write_timeout -= 5) {
+ ret = dev->em2820_read_reg(dev, 0x05);
+ if (ret == 0x80 + len - 1)
+ return len;
+ mdelay(5);
+ }
+ em2820_warn("i2c write timed out\n");
+ return -EIO;
+}
+
+/*
+ * em2800_i2c_send_bytes()
+ */
+static int em2800_i2c_send_bytes(void *data, unsigned char addr, char *buf,
+ short len)
+{
+ char *bufPtr = buf;
+ int ret;
+ int wrcount = 0;
+ int count;
+ int maxLen = 4;
+ struct em2820 *dev = (struct em2820 *)data;
+ while (len > 0) {
+ count = (len > maxLen) ? maxLen : len;
+ ret = em2800_i2c_send_max4(dev, addr, bufPtr, count);
+ if (ret > 0) {
+ len -= count;
+ bufPtr += count;
+ wrcount += count;
+ } else
+ return (ret < 0) ? ret : -EFAULT;
+ }
+ return wrcount;
+}
+
+/*
+ * em2800_i2c_check_for_device()
+ * check if there is a i2c_device at the supplied address
+ */
+static int em2800_i2c_check_for_device(struct em2820 *dev, unsigned char addr)
+{
+ char msg;
+ int ret;
+ int write_timeout;
+ msg = addr;
+ ret = dev->em2820_write_regs(dev, 0x04, &msg, 1);
+ if (ret < 0) {
+ em2820_warn("setting i2c device address failed (error=%i)\n",
+ ret);
+ return ret;
+ }
+ msg = 0x84;
+ ret = dev->em2820_write_regs(dev, 0x05, &msg, 1);
+ if (ret < 0) {
+ em2820_warn("preparing i2c read failed (error=%i)\n", ret);
+ return ret;
+ }
+ for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0;
+ write_timeout -= 5) {
+ unsigned msg = dev->em2820_read_reg(dev, 0x5);
+ if (msg == 0x94)
+ return -ENODEV;
+ else if (msg == 0x84)
+ return 0;
+ mdelay(5);
+ }
+ return -ENODEV;
+}
+
+/*
+ * em2800_i2c_recv_bytes()
+ * read from the i2c device
+ */
+static int em2800_i2c_recv_bytes(struct em2820 *dev, unsigned char addr,
+ char *buf, int len)
+{
+ int ret;
+ /* check for the device and set i2c read address */
+ ret = em2800_i2c_check_for_device(dev, addr);
+ if (ret) {
+ em2820_warn
+ ("preparing read at i2c address 0x%x failed (error=%i)\n",
+ addr, ret);
+ return ret;
+ }
+ ret = dev->em2820_read_reg_req_len(dev, 0x0, 0x3, buf, len);
+ if (ret < 0) {
+ em2820_warn("reading from i2c device at 0x%x failed (error=%i)",
+ addr, ret);
+ return ret;
+ }
+ return ret;
+}
+
+/*
+ * em2820_i2c_send_bytes()
* untested for more than 4 bytes
*/
-static int i2c_send_bytes(void *data, unsigned char addr, char *buf, short len,
- int stop)
+static int em2820_i2c_send_bytes(void *data, unsigned char addr, char *buf,
+ short len, int stop)
{
int wrcount = 0;
struct em2820 *dev = (struct em2820 *)data;
@@ -71,11 +187,11 @@ static int i2c_send_bytes(void *data, unsigned char addr, char *buf, short len,
}
/*
- * i2c_recv_byte()
+ * em2820_i2c_recv_bytes()
* read a byte from the i2c device
*/
-static int i2c_recv_bytes(struct em2820 *dev, unsigned char addr, char *buf,
- int len)
+static int em2820_i2c_recv_bytes(struct em2820 *dev, unsigned char addr,
+ char *buf, int len)
{
int ret;
ret = dev->em2820_read_reg_req_len(dev, 2, addr, buf, len);
@@ -89,10 +205,10 @@ static int i2c_recv_bytes(struct em2820 *dev, unsigned char addr, char *buf,
}
/*
- * i2c_check_for_device()
+ * em2820_i2c_check_for_device()
* check if there is a i2c_device at the supplied address
*/
-static int i2c_check_for_device(struct em2820 *dev, unsigned char addr)
+static int em2820_i2c_check_for_device(struct em2820 *dev, unsigned char addr)
{
char msg;
int ret;
@@ -126,18 +242,25 @@ static int em2820_i2c_xfer(struct i2c_adapter *i2c_adap,
(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 */
- rc = i2c_check_for_device(dev, addr);
+ if (dev->is_em2800)
+ rc = em2800_i2c_check_for_device(dev, addr);
+ else
+ rc = em2820_i2c_check_for_device(dev, addr);
if (rc < 0) {
dprintk2(" no device\n");
return rc;
}
- }
- if (msgs[i].flags & I2C_M_RD) {
+ } else if (msgs[i].flags & I2C_M_RD) {
/* read bytes */
-
- rc = i2c_recv_bytes(dev, addr, msgs[i].buf,
- msgs[i].len);
+ if (dev->is_em2800)
+ rc = em2800_i2c_recv_bytes(dev, addr,
+ msgs[i].buf,
+ msgs[i].len);
+ else
+ rc = em2820_i2c_recv_bytes(dev, addr,
+ msgs[i].buf,
+ msgs[i].len);
if (i2c_debug) {
for (byte = 0; byte < msgs[i].len; byte++) {
printk(" %02x", msgs[i].buf[byte]);
@@ -149,8 +272,15 @@ static int em2820_i2c_xfer(struct i2c_adapter *i2c_adap,
for (byte = 0; byte < msgs[i].len; byte++)
printk(" %02x", msgs[i].buf[byte]);
}
- rc = i2c_send_bytes(dev, addr, msgs[i].buf, msgs[i].len,
- i == num - 1);
+ if (dev->is_em2800)
+ rc = em2800_i2c_send_bytes(dev, addr,
+ msgs[i].buf,
+ msgs[i].len);
+ else
+ rc = em2820_i2c_send_bytes(dev, addr,
+ msgs[i].buf,
+ msgs[i].len,
+ i == num - 1);
if (rc < 0)
goto err;
}
@@ -171,6 +301,12 @@ static int em2820_i2c_eeprom(struct em2820 *dev, unsigned char *eedata, int len)
int i, err, size = len, block;
dev->i2c_client.addr = 0xa0 >> 1;
+
+ /* Check if board has eeprom */
+ err = i2c_master_recv(&dev->i2c_client, &buf, 0);
+ if (err < 0)
+ return -1;
+
buf = 0;
if (1 != (err = i2c_master_send(&dev->i2c_client, &buf, 1))) {
printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n",
@@ -389,7 +525,7 @@ static void do_i2c_scan(char *name, struct i2c_client *c)
rc = i2c_master_recv(c, &buf, 0);
if (rc < 0)
continue;
- printk(KERN_INFO "%s: found device @ 0x%x [%s]", name,
+ printk(KERN_INFO "%s: found i2c device @ 0x%x [%s]\n", name,
i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
}
}
diff --git a/linux/drivers/media/video/em28xx/em28xx-video.c b/linux/drivers/media/video/em28xx/em28xx-video.c
index be3caad98..d3a659172 100644
--- a/linux/drivers/media/video/em28xx/em28xx-video.c
+++ b/linux/drivers/media/video/em28xx/em28xx-video.c
@@ -1,5 +1,5 @@
/*
- em2820-video.c - driver for Empia EM2820/2840 USB video capture devices
+ em2820-video.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
Copyright (C) 2005 Markus Rechberger <mrechberger@gmail.com>
Ludovico Cavedon <cavedon@sssup.it>
@@ -50,6 +50,18 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
+static unsigned int card[] = {[0 ... (EM2820_MAXBOARDS - 1)] = UNSET };
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+MODULE_PARM(card,"1-" __stringify(EM2820_MAXBOARDS) "i");
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
+static int dummy;
+module_param_array(card, int, dummy, 0444);
+#else
+module_param_array(card, int, NULL, 0444);
+#endif
+MODULE_PARM_DESC(card,"card type");
+
static int tuner = -1;
module_param(tuner, int, 0444);
MODULE_PARM_DESC(tuner, "tuner type");
@@ -1174,7 +1186,7 @@ static int em2820_do_ioctl(struct inode *inode, struct file *filp,
struct v4l2_cropcap *cc = arg;
if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return EINVAL;
+ return -EINVAL;
cc->bounds.left = 0;
cc->bounds.top = 0;
cc->bounds.width = dev->width;
@@ -1668,21 +1680,12 @@ static struct file_operations em2820_v4l_fops = {
static int em2820_init_dev(struct em2820 **devhandle, struct usb_device *udev,
int minor, int model)
{
- struct em2820 *dev;
+ struct em2820 *dev = *devhandle;
int retval = -ENOMEM;
int errCode, i;
unsigned int maxh, maxw;
struct usb_interface *uif;
- /* allocate memory for our device state and initialize it */
- dev = kmalloc(sizeof(*dev), GFP_KERNEL);
- if (dev == NULL) {
- em2820_err(DRIVER_NAME ": out of memory!\n");
- return -ENOMEM;
- }
- memset(dev, 0x00, sizeof(*dev));
-
- snprintf(dev->name, 29, "em2820 #%d", minor);
dev->udev = udev;
dev->model = model;
init_MUTEX(&dev->lock);
@@ -1693,6 +1696,7 @@ static int em2820_init_dev(struct em2820 **devhandle, struct usb_device *udev,
dev->em2820_read_reg_req_len = em2820_read_reg_req_len;
dev->em2820_write_regs_req = em2820_write_regs_req;
dev->em2820_read_reg_req = em2820_read_reg_req;
+ dev->is_em2800 = em2820_boards[model].is_em2800;
dev->has_tuner = em2820_boards[model].has_tuner;
dev->has_msp34xx = em2820_boards[model].has_msp34xx;
dev->tda9887_conf = em2820_boards[model].tda9887_conf;
@@ -1743,7 +1747,7 @@ static int em2820_init_dev(struct em2820 **devhandle, struct usb_device *udev,
/* compute alternate max packet sizes */
uif = dev->udev->actconfig->interface[0];
dev->alt_max_pkt_size[0] = 0;
- for (i = 1; i <= EM2820_MAX_ALT; i++) {
+ for (i = 1; i <= EM2820_MAX_ALT && i < uif->num_altsetting ; i++) {
u16 tmp =
le16_to_cpu(uif->altsetting[i].endpoint[1].desc.
wMaxPacketSize);
@@ -1861,7 +1865,6 @@ static int em2820_init_dev(struct em2820 **devhandle, struct usb_device *udev,
em2820_info("V4L2 device registered as /dev/video%d\n",
dev->vdev->minor);
- *devhandle = dev;
return 0;
}
@@ -1876,27 +1879,68 @@ static int em2820_usb_probe(struct usb_interface *interface,
struct usb_device *udev;
struct em2820 *dev = NULL;
int retval = -ENODEV;
+ int model,i,nr;
udev = usb_get_dev(interface_to_usbdev(interface));
endpoint = &interface->cur_altsetting->endpoint[1].desc;
+ /* Don't register audio interfaces */
+ if (interface->altsetting[1].desc.bInterfaceClass == USB_CLASS_AUDIO)
+ return -ENODEV;
+
/* check if the the device has the iso in endpoint at the correct place */
if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
USB_ENDPOINT_XFER_ISOC) {
-/* em2820_err(DRIVER_NAME " probing error: endpoint is non-ISO endpoint!\n"); */
+ em2820_err(DRIVER_NAME " probing error: endpoint is non-ISO endpoint!\n");
return -ENODEV;
}
if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) {
-/* em2820_err(DRIVER_NAME " probing error: endpoint is ISO OUT endpoint!\n"); */
+ em2820_err(DRIVER_NAME " probing error: endpoint is ISO OUT endpoint!\n");
return -ENODEV;
}
+ model=id->driver_info;
+ nr=interface->minor;
+
+ if (nr>EM2820_MAXBOARDS) {
+ printk ("em2820: Supports only %i em28xx boards.\n",EM2820_MAXBOARDS);
+ return -ENOMEM;
+ }
+
+ /* allocate memory for our device state and initialize it */
+ dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+ if (dev == NULL) {
+ em2820_err(DRIVER_NAME ": out of memory!\n");
+ return -ENOMEM;
+ }
+ memset(dev, 0, sizeof(*dev));
+
+ snprintf(dev->name, 29, "em2820 #%d", nr);
+
+ if ((card[nr]>=0)&&(card[nr]<em2820_bcount))
+ model=card[nr];
+
+ if ((model==EM2800_BOARD_UNKNOWN)||(model==EM2820_BOARD_UNKNOWN)) {
+ printk( "%s: Your board has no eeprom inside it and thus can't\n"
+ "%s: be autodetected. Please pass card=<n> insmod option to\n"
+ "%s: workaround that. Redirect complaints to the vendor of\n"
+ "%s: the TV card. Best regards,\n"
+ "%s: -- tux\n",
+ dev->name,dev->name,dev->name,dev->name,dev->name);
+ printk("%s: Here is a list of valid choices for the card=<n> insmod option:\n",
+ dev->name);
+ for (i = 0; i < em2820_bcount; i++) {
+ printk("%s: card=%d -> %s\n",
+ dev->name, i, em2820_boards[i].name);
+ }
+ }
+
/* allocate device struct */
- retval = em2820_init_dev(&dev, udev, interface->minor, id->driver_info);
+ retval = em2820_init_dev(&dev, udev, nr, model);
if (retval)
return retval;
- em2820_info("Found %s\n", em2820_boards[id->driver_info].name);
+ em2820_info("Found %s\n", em2820_boards[model].name);
/* save our data pointer in this interface device */
usb_set_intfdata(interface, dev);
diff --git a/linux/drivers/media/video/em28xx/em28xx.h b/linux/drivers/media/video/em28xx/em28xx.h
index b60ef31f1..dd4229d13 100644
--- a/linux/drivers/media/video/em28xx/em28xx.h
+++ b/linux/drivers/media/video/em28xx/em28xx.h
@@ -1,5 +1,5 @@
/*
- em2820-cards.c - driver for Empia EM2820/2840 USB video capture devices
+ em2820-cards.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
Copyright (C) 2005 Markus Rechberger <mrechberger@gmail.com>
Ludovico Cavedon <cavedon@sssup.it>
@@ -29,6 +29,23 @@
#include <linux/videodev.h>
#include <linux/i2c.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 UNSET -1
+
+/* maximum number of em28xx boards */
+#define EM2820_MAXBOARDS 1 /*FIXME: should be bigger */
+
/* maximum number of frames that can be queued */
#define EM2820_NUM_FRAMES 5
/* number of frames that get used for v4l2_read() */
@@ -80,6 +97,9 @@
/* time to wait when stopping the isoc transfer */
#define EM2820_URB_TIMEOUT msecs_to_jiffies(EM2820_NUM_BUFS * EM2820_NUM_PACKETS)
+/* time in msecs to wait for i2c writes to finish */
+#define EM2800_I2C_WRITE_TIMEOUT 20
+
/* the various frame states */
enum em2820_frame_state {
F_UNUSED = 0,
@@ -146,12 +166,13 @@ enum em2820_decoder {
struct em2820_board {
char *name;
-
+ unsigned char chip_id;
int vchannels;
int norm;
int tuner_type;
/* i2c flags */
+ unsigned int is_em2800;
unsigned int tda9887_conf;
unsigned int has_tuner:1;
@@ -196,6 +217,7 @@ struct em2820 {
/* generic device properties */
char name[30]; /* name (including minor) of the device */
int model; /* index in the device_data struct */
+ unsigned int is_em2800;
int video_inputs; /* number of video inputs */
unsigned int has_tuner:1;
unsigned int has_msp34xx:1;
@@ -305,11 +327,14 @@ void em2820_uninit_isoc(struct em2820 *dev);
int em2820_set_alternate(struct em2820 *dev);
/* Provided by em2820-cards.c */
+extern int em2800_variant_detect(struct usb_device* udev,int model);
extern void em2820_card_setup(struct em2820 *dev);
extern struct em2820_board em2820_boards[];
extern struct usb_device_id em2820_id_table[];
+extern const unsigned int em2820_bcount;
/* em2820 registers */
+#define CHIPID_REG 0x0a
#define USBSUSP_REG 0x0c /* */
#define AUDIOSRC_REG 0x0e
diff --git a/linux/drivers/usb/media/em2820-cards.c b/linux/drivers/usb/media/em2820-cards.c
index d9014eb89..57d88e44f 100644
--- a/linux/drivers/usb/media/em2820-cards.c
+++ b/linux/drivers/usb/media/em2820-cards.c
@@ -1,5 +1,5 @@
/*
- em2820-cards.c - driver for Empia EM2820/2840 USB video capture devices
+ em2820-cards.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
Copyright (C) 2005 Markus Rechberger <mrechberger@gmail.com>
Ludovico Cavedon <cavedon@sssup.it>
@@ -36,31 +36,34 @@
#include "em2820.h"
-enum em2820_board_entry {
-#if 0
- EM2800_BOARD_TERRATEC_CINERGY_200,
-#endif
- EM2820_BOARD_TERRATEC_CINERGY_250,
- EM2820_BOARD_PINNACLE_USB_2,
- EM2820_BOARD_HAUPPAUGE_WINTV_USB_2,
- EM2820_BOARD_MSI_VOX_USB_2
-};
-
struct em2820_board em2820_boards[] = {
-#if 0
- [EM2800_BOARD_TERRATEC_CINERGY_200] = {
- .name = "Terratec Cinergy 200 USB",
- .vchannels = 3,
+ [EM2800_BOARD_UNKNOWN] = {
+ .name = "Unknown EM2800 video grabber",
+ .is_em2800 = 1,
+ .vchannels = 2,
.norm = VIDEO_MODE_PAL,
- .tuner_type = TUNER_LG_PAL_NEW_TAPC,
.tda9887_conf = TDA9887_PRESENT,
.has_tuner = 1,
.decoder = EM2820_SAA7113,
- .input = {{
- .type = EM2820_VMUX_TELEVISION,
- .vmux = 2,
- .amux = 0,
+ .input = {{
+ .type = EM2820_VMUX_COMPOSITE1,
+ .vmux = 0,
+ .amux = 1,
},{
+ .type = EM2820_VMUX_SVIDEO,
+ .vmux = 9,
+ .amux = 1,
+ }},
+ },
+ [EM2820_BOARD_UNKNOWN] = {
+ .name = "Unknown EM2820/2840 video grabber",
+ .is_em2800 = 0,
+ .vchannels = 2,
+ .norm = VIDEO_MODE_PAL,
+ .tda9887_conf = TDA9887_PRESENT,
+ .has_tuner = 1,
+ .decoder = EM2820_SAA7113,
+ .input = {{
.type = EM2820_VMUX_COMPOSITE1,
.vmux = 0,
.amux = 1,
@@ -70,7 +73,6 @@ struct em2820_board em2820_boards[] = {
.amux = 1,
}},
},
-#endif
[EM2820_BOARD_TERRATEC_CINERGY_250] = {
.name = "Terratec Cinergy 250 USB",
.vchannels = 3,
@@ -157,17 +159,88 @@ struct em2820_board em2820_boards[] = {
.amux = 1,
}},
},
- { } /* Terminating entry */
+ [EM2800_BOARD_TERRATEC_CINERGY_200] = {
+ .name = "Terratec Cinergy 200 USB",
+ .chip_id = 0x4,
+ .is_em2800 = 1,
+ .vchannels = 3,
+ .norm = VIDEO_MODE_PAL,
+ .tuner_type = TUNER_LG_PAL_NEW_TAPC,
+ .tda9887_conf = TDA9887_PRESENT,
+ .has_tuner = 1,
+ .decoder = EM2820_SAA7113,
+ .input = {{
+ .type = EM2820_VMUX_TELEVISION,
+ .vmux = 2,
+ .amux = 0,
+ },{
+ .type = EM2820_VMUX_COMPOSITE1,
+ .vmux = 0,
+ .amux = 1,
+ },{
+ .type = EM2820_VMUX_SVIDEO,
+ .vmux = 9,
+ .amux = 1,
+ }},
+ },
+ [EM2800_BOARD_LEADTEK_WINFAST_USBII] = {
+ .name = "Leadtek Winfast USB II",
+ .chip_id = 0x2,
+ .is_em2800 = 1,
+ .vchannels = 3,
+ .norm = VIDEO_MODE_PAL,
+ .tuner_type = TUNER_LG_PAL_NEW_TAPC,
+ .tda9887_conf = TDA9887_PRESENT,
+ .has_tuner = 1,
+ .decoder = EM2820_SAA7113,
+ .input = {{
+ .type = EM2820_VMUX_TELEVISION,
+ .vmux = 2,
+ .amux = 0,
+ },{
+ .type = EM2820_VMUX_COMPOSITE1,
+ .vmux = 0,
+ .amux = 1,
+ },{
+ .type = EM2820_VMUX_SVIDEO,
+ .vmux = 9,
+ .amux = 1,
+ }},
+ },
+ [EM2800_BOARD_KWORLD_USB2800] = {
+ .name = "Kworld USB2800",
+ .chip_id = 0x7,
+ .is_em2800 = 1,
+ .vchannels = 3,
+ .norm = VIDEO_MODE_PAL,
+ .tuner_type = TUNER_PHILIPS_ATSC,
+ .tda9887_conf = TDA9887_PRESENT,
+ .has_tuner = 1,
+ .decoder = EM2820_SAA7113,
+ .input = {{
+ .type = EM2820_VMUX_TELEVISION,
+ .vmux = 2,
+ .amux = 0,
+ },{
+ .type = EM2820_VMUX_COMPOSITE1,
+ .vmux = 0,
+ .amux = 1,
+ },{
+ .type = EM2820_VMUX_SVIDEO,
+ .vmux = 9,
+ .amux = 1,
+ }},
+ },
};
+const unsigned int em2820_bcount = ARRAY_SIZE(em2820_boards);
/* table of devices that work with this driver */
struct usb_device_id em2820_id_table [] = {
- /* Terratec Cinerhy 200 USB: em2800 nor supported, at the moment */
- /* { USB_DEVICE(0xeb1a, 0x2800), .driver_info = EM2800_BOARD_TERRATEC_CINERGY_200 }, */
+ { USB_DEVICE(0xeb1a, 0x2800), .driver_info = EM2800_BOARD_UNKNOWN },
+ { USB_DEVICE(0xeb1a, 0x2820), .driver_info = EM2820_BOARD_UNKNOWN },
{ USB_DEVICE(0x0ccd, 0x0036), .driver_info = EM2820_BOARD_TERRATEC_CINERGY_250 },
{ USB_DEVICE(0x2304, 0x0208), .driver_info = EM2820_BOARD_PINNACLE_USB_2 },
{ USB_DEVICE(0x2040, 0x4200), .driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 },
- { USB_DEVICE(0xeb1a, 0x2820), .driver_info = EM2820_BOARD_MSI_VOX_USB_2 },
{ },
};
@@ -499,6 +572,7 @@ void em2820_card_setup(struct em2820 *dev)
}
EXPORT_SYMBOL(em2820_boards);
+EXPORT_SYMBOL(em2820_bcount);
EXPORT_SYMBOL(em2820_id_table);
MODULE_DEVICE_TABLE (usb, em2820_id_table);
diff --git a/linux/drivers/usb/media/em2820-core.c b/linux/drivers/usb/media/em2820-core.c
index 4bc4b4c6c..07fcfcc9b 100644
--- a/linux/drivers/usb/media/em2820-core.c
+++ b/linux/drivers/usb/media/em2820-core.c
@@ -1,5 +1,5 @@
/*
- em2820-core.c - driver for Empia EM2820/2840 USB video capture devices
+ em2820-core.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
Copyright (C) 2005 Markus Rechberger <mrechberger@gmail.com>
Ludovico Cavedon <cavedon@sssup.it>
@@ -570,6 +570,11 @@ static inline void em2820_isoc_video_copy(struct em2820 *dev,
void *fieldstart, *startwrite, *startread;
int linesdone, currlinedone, offset, lencopy,remain;
+ if(dev->frame_size != (*f)->buf.length){
+ em2820_err("frame_size %i and buf.length %i are different!!!\n",dev->frame_size,(*f)->buf.length);
+ return;
+ }
+
if ((*f)->fieldbytesused + len > dev->field_size)
len =dev->field_size - (*f)->fieldbytesused;
remain = len;
@@ -788,6 +793,11 @@ int em2820_set_alternate(struct em2820 *dev)
dev->alt = alt;
if (dev->alt == 0) {
int i;
+ if(dev->is_em2800){ /* always use the max packet size for em2800 based devices */
+ for(i=0;i< EM2820_MAX_ALT; i++)
+ if(dev->alt_max_pkt_size[i]>dev->alt_max_pkt_size[dev->alt])
+ dev->alt=i;
+ }else{
unsigned int min_pkt_size = dev->field_size / 137; /* FIXME: empiric magic number */
em2820_coredbg("minimum isoc packet size: %u", min_pkt_size);
dev->alt = 7;
@@ -796,6 +806,7 @@ int em2820_set_alternate(struct em2820 *dev)
dev->alt = i;
break;
}
+ }
}
if (dev->alt != prev_alt) {
diff --git a/linux/drivers/usb/media/em2820-i2c.c b/linux/drivers/usb/media/em2820-i2c.c
index fa56179b0..3413ec51c 100644
--- a/linux/drivers/usb/media/em2820-i2c.c
+++ b/linux/drivers/usb/media/em2820-i2c.c
@@ -1,5 +1,5 @@
/*
- em2820-i2c.c - driver for Empia EM2820/2840 USB video capture devices
+ em2820-i2c.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
Copyright (C) 2005 Markus Rechberger <mrechberger@gmail.com>
Ludovico Cavedon <cavedon@sssup.it>
@@ -29,11 +29,6 @@
#include <media/tuner.h>
#include <linux/video_decoder.h>
-/* To be moved to compat.h */
-#if !defined(I2C_HW_B_EM2820)
-#define I2C_HW_B_EM2820 0x99
-#endif
-
#include "em2820.h"
/* ----------------------------------------------------------- */
@@ -56,11 +51,132 @@ MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
printk(fmt, ##args); } while (0)
/*
- * i2c_send_bytes()
+ * em2800_i2c_send_max4()
+ * send up to 4 bytes to the i2c device
+ */
+static int em2800_i2c_send_max4(struct em2820 *dev, unsigned char addr,
+ char *buf, int len)
+{
+ int ret;
+ int write_timeout;
+ unsigned char b2[6];
+ BUG_ON(len < 1 || len > 4);
+ b2[5] = 0x80 + len - 1;
+ b2[4] = addr;
+ b2[3] = buf[0];
+ if (len > 1)
+ b2[2] = buf[1];
+ if (len > 2)
+ b2[1] = buf[2];
+ if (len > 3)
+ b2[0] = buf[3];
+
+ ret = dev->em2820_write_regs(dev, 4 - len, &b2[4 - len], 2 + len);
+ if (ret != 2 + len) {
+ em2820_warn("writting to i2c device failed (error=%i)\n", ret);
+ return -EIO;
+ }
+ for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0;
+ write_timeout -= 5) {
+ ret = dev->em2820_read_reg(dev, 0x05);
+ if (ret == 0x80 + len - 1)
+ return len;
+ mdelay(5);
+ }
+ em2820_warn("i2c write timed out\n");
+ return -EIO;
+}
+
+/*
+ * em2800_i2c_send_bytes()
+ */
+static int em2800_i2c_send_bytes(void *data, unsigned char addr, char *buf,
+ short len)
+{
+ char *bufPtr = buf;
+ int ret;
+ int wrcount = 0;
+ int count;
+ int maxLen = 4;
+ struct em2820 *dev = (struct em2820 *)data;
+ while (len > 0) {
+ count = (len > maxLen) ? maxLen : len;
+ ret = em2800_i2c_send_max4(dev, addr, bufPtr, count);
+ if (ret > 0) {
+ len -= count;
+ bufPtr += count;
+ wrcount += count;
+ } else
+ return (ret < 0) ? ret : -EFAULT;
+ }
+ return wrcount;
+}
+
+/*
+ * em2800_i2c_check_for_device()
+ * check if there is a i2c_device at the supplied address
+ */
+static int em2800_i2c_check_for_device(struct em2820 *dev, unsigned char addr)
+{
+ char msg;
+ int ret;
+ int write_timeout;
+ msg = addr;
+ ret = dev->em2820_write_regs(dev, 0x04, &msg, 1);
+ if (ret < 0) {
+ em2820_warn("setting i2c device address failed (error=%i)\n",
+ ret);
+ return ret;
+ }
+ msg = 0x84;
+ ret = dev->em2820_write_regs(dev, 0x05, &msg, 1);
+ if (ret < 0) {
+ em2820_warn("preparing i2c read failed (error=%i)\n", ret);
+ return ret;
+ }
+ for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0;
+ write_timeout -= 5) {
+ unsigned msg = dev->em2820_read_reg(dev, 0x5);
+ if (msg == 0x94)
+ return -ENODEV;
+ else if (msg == 0x84)
+ return 0;
+ mdelay(5);
+ }
+ return -ENODEV;
+}
+
+/*
+ * em2800_i2c_recv_bytes()
+ * read from the i2c device
+ */
+static int em2800_i2c_recv_bytes(struct em2820 *dev, unsigned char addr,
+ char *buf, int len)
+{
+ int ret;
+ /* check for the device and set i2c read address */
+ ret = em2800_i2c_check_for_device(dev, addr);
+ if (ret) {
+ em2820_warn
+ ("preparing read at i2c address 0x%x failed (error=%i)\n",
+ addr, ret);
+ return ret;
+ }
+ ret = dev->em2820_read_reg_req_len(dev, 0x0, 0x3, buf, len);
+ if (ret < 0) {
+ em2820_warn("reading from i2c device at 0x%x failed (error=%i)",
+ addr, ret);
+ return ret;
+ }
+ return ret;
+}
+
+/*
+ * em2820_i2c_send_bytes()
* untested for more than 4 bytes
*/
-static int i2c_send_bytes(void *data, unsigned char addr, char *buf, short len,
- int stop)
+static int em2820_i2c_send_bytes(void *data, unsigned char addr, char *buf,
+ short len, int stop)
{
int wrcount = 0;
struct em2820 *dev = (struct em2820 *)data;
@@ -71,11 +187,11 @@ static int i2c_send_bytes(void *data, unsigned char addr, char *buf, short len,
}
/*
- * i2c_recv_byte()
+ * em2820_i2c_recv_bytes()
* read a byte from the i2c device
*/
-static int i2c_recv_bytes(struct em2820 *dev, unsigned char addr, char *buf,
- int len)
+static int em2820_i2c_recv_bytes(struct em2820 *dev, unsigned char addr,
+ char *buf, int len)
{
int ret;
ret = dev->em2820_read_reg_req_len(dev, 2, addr, buf, len);
@@ -89,10 +205,10 @@ static int i2c_recv_bytes(struct em2820 *dev, unsigned char addr, char *buf,
}
/*
- * i2c_check_for_device()
+ * em2820_i2c_check_for_device()
* check if there is a i2c_device at the supplied address
*/
-static int i2c_check_for_device(struct em2820 *dev, unsigned char addr)
+static int em2820_i2c_check_for_device(struct em2820 *dev, unsigned char addr)
{
char msg;
int ret;
@@ -126,18 +242,25 @@ static int em2820_i2c_xfer(struct i2c_adapter *i2c_adap,
(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 */
- rc = i2c_check_for_device(dev, addr);
+ if (dev->is_em2800)
+ rc = em2800_i2c_check_for_device(dev, addr);
+ else
+ rc = em2820_i2c_check_for_device(dev, addr);
if (rc < 0) {
dprintk2(" no device\n");
return rc;
}
- }
- if (msgs[i].flags & I2C_M_RD) {
+ } else if (msgs[i].flags & I2C_M_RD) {
/* read bytes */
-
- rc = i2c_recv_bytes(dev, addr, msgs[i].buf,
- msgs[i].len);
+ if (dev->is_em2800)
+ rc = em2800_i2c_recv_bytes(dev, addr,
+ msgs[i].buf,
+ msgs[i].len);
+ else
+ rc = em2820_i2c_recv_bytes(dev, addr,
+ msgs[i].buf,
+ msgs[i].len);
if (i2c_debug) {
for (byte = 0; byte < msgs[i].len; byte++) {
printk(" %02x", msgs[i].buf[byte]);
@@ -149,8 +272,15 @@ static int em2820_i2c_xfer(struct i2c_adapter *i2c_adap,
for (byte = 0; byte < msgs[i].len; byte++)
printk(" %02x", msgs[i].buf[byte]);
}
- rc = i2c_send_bytes(dev, addr, msgs[i].buf, msgs[i].len,
- i == num - 1);
+ if (dev->is_em2800)
+ rc = em2800_i2c_send_bytes(dev, addr,
+ msgs[i].buf,
+ msgs[i].len);
+ else
+ rc = em2820_i2c_send_bytes(dev, addr,
+ msgs[i].buf,
+ msgs[i].len,
+ i == num - 1);
if (rc < 0)
goto err;
}
@@ -171,6 +301,12 @@ static int em2820_i2c_eeprom(struct em2820 *dev, unsigned char *eedata, int len)
int i, err, size = len, block;
dev->i2c_client.addr = 0xa0 >> 1;
+
+ /* Check if board has eeprom */
+ err = i2c_master_recv(&dev->i2c_client, &buf, 0);
+ if (err < 0)
+ return -1;
+
buf = 0;
if (1 != (err = i2c_master_send(&dev->i2c_client, &buf, 1))) {
printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n",
@@ -389,7 +525,7 @@ static void do_i2c_scan(char *name, struct i2c_client *c)
rc = i2c_master_recv(c, &buf, 0);
if (rc < 0)
continue;
- printk(KERN_INFO "%s: found device @ 0x%x [%s]", name,
+ printk(KERN_INFO "%s: found i2c device @ 0x%x [%s]\n", name,
i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
}
}
diff --git a/linux/drivers/usb/media/em2820-video.c b/linux/drivers/usb/media/em2820-video.c
index be3caad98..d3a659172 100644
--- a/linux/drivers/usb/media/em2820-video.c
+++ b/linux/drivers/usb/media/em2820-video.c
@@ -1,5 +1,5 @@
/*
- em2820-video.c - driver for Empia EM2820/2840 USB video capture devices
+ em2820-video.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
Copyright (C) 2005 Markus Rechberger <mrechberger@gmail.com>
Ludovico Cavedon <cavedon@sssup.it>
@@ -50,6 +50,18 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
+static unsigned int card[] = {[0 ... (EM2820_MAXBOARDS - 1)] = UNSET };
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+MODULE_PARM(card,"1-" __stringify(EM2820_MAXBOARDS) "i");
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
+static int dummy;
+module_param_array(card, int, dummy, 0444);
+#else
+module_param_array(card, int, NULL, 0444);
+#endif
+MODULE_PARM_DESC(card,"card type");
+
static int tuner = -1;
module_param(tuner, int, 0444);
MODULE_PARM_DESC(tuner, "tuner type");
@@ -1174,7 +1186,7 @@ static int em2820_do_ioctl(struct inode *inode, struct file *filp,
struct v4l2_cropcap *cc = arg;
if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return EINVAL;
+ return -EINVAL;
cc->bounds.left = 0;
cc->bounds.top = 0;
cc->bounds.width = dev->width;
@@ -1668,21 +1680,12 @@ static struct file_operations em2820_v4l_fops = {
static int em2820_init_dev(struct em2820 **devhandle, struct usb_device *udev,
int minor, int model)
{
- struct em2820 *dev;
+ struct em2820 *dev = *devhandle;
int retval = -ENOMEM;
int errCode, i;
unsigned int maxh, maxw;
struct usb_interface *uif;
- /* allocate memory for our device state and initialize it */
- dev = kmalloc(sizeof(*dev), GFP_KERNEL);
- if (dev == NULL) {
- em2820_err(DRIVER_NAME ": out of memory!\n");
- return -ENOMEM;
- }
- memset(dev, 0x00, sizeof(*dev));
-
- snprintf(dev->name, 29, "em2820 #%d", minor);
dev->udev = udev;
dev->model = model;
init_MUTEX(&dev->lock);
@@ -1693,6 +1696,7 @@ static int em2820_init_dev(struct em2820 **devhandle, struct usb_device *udev,
dev->em2820_read_reg_req_len = em2820_read_reg_req_len;
dev->em2820_write_regs_req = em2820_write_regs_req;
dev->em2820_read_reg_req = em2820_read_reg_req;
+ dev->is_em2800 = em2820_boards[model].is_em2800;
dev->has_tuner = em2820_boards[model].has_tuner;
dev->has_msp34xx = em2820_boards[model].has_msp34xx;
dev->tda9887_conf = em2820_boards[model].tda9887_conf;
@@ -1743,7 +1747,7 @@ static int em2820_init_dev(struct em2820 **devhandle, struct usb_device *udev,
/* compute alternate max packet sizes */
uif = dev->udev->actconfig->interface[0];
dev->alt_max_pkt_size[0] = 0;
- for (i = 1; i <= EM2820_MAX_ALT; i++) {
+ for (i = 1; i <= EM2820_MAX_ALT && i < uif->num_altsetting ; i++) {
u16 tmp =
le16_to_cpu(uif->altsetting[i].endpoint[1].desc.
wMaxPacketSize);
@@ -1861,7 +1865,6 @@ static int em2820_init_dev(struct em2820 **devhandle, struct usb_device *udev,
em2820_info("V4L2 device registered as /dev/video%d\n",
dev->vdev->minor);
- *devhandle = dev;
return 0;
}
@@ -1876,27 +1879,68 @@ static int em2820_usb_probe(struct usb_interface *interface,
struct usb_device *udev;
struct em2820 *dev = NULL;
int retval = -ENODEV;
+ int model,i,nr;
udev = usb_get_dev(interface_to_usbdev(interface));
endpoint = &interface->cur_altsetting->endpoint[1].desc;
+ /* Don't register audio interfaces */
+ if (interface->altsetting[1].desc.bInterfaceClass == USB_CLASS_AUDIO)
+ return -ENODEV;
+
/* check if the the device has the iso in endpoint at the correct place */
if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
USB_ENDPOINT_XFER_ISOC) {
-/* em2820_err(DRIVER_NAME " probing error: endpoint is non-ISO endpoint!\n"); */
+ em2820_err(DRIVER_NAME " probing error: endpoint is non-ISO endpoint!\n");
return -ENODEV;
}
if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) {
-/* em2820_err(DRIVER_NAME " probing error: endpoint is ISO OUT endpoint!\n"); */
+ em2820_err(DRIVER_NAME " probing error: endpoint is ISO OUT endpoint!\n");
return -ENODEV;
}
+ model=id->driver_info;
+ nr=interface->minor;
+
+ if (nr>EM2820_MAXBOARDS) {
+ printk ("em2820: Supports only %i em28xx boards.\n",EM2820_MAXBOARDS);
+ return -ENOMEM;
+ }
+
+ /* allocate memory for our device state and initialize it */
+ dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+ if (dev == NULL) {
+ em2820_err(DRIVER_NAME ": out of memory!\n");
+ return -ENOMEM;
+ }
+ memset(dev, 0, sizeof(*dev));
+
+ snprintf(dev->name, 29, "em2820 #%d", nr);
+
+ if ((card[nr]>=0)&&(card[nr]<em2820_bcount))
+ model=card[nr];
+
+ if ((model==EM2800_BOARD_UNKNOWN)||(model==EM2820_BOARD_UNKNOWN)) {
+ printk( "%s: Your board has no eeprom inside it and thus can't\n"
+ "%s: be autodetected. Please pass card=<n> insmod option to\n"
+ "%s: workaround that. Redirect complaints to the vendor of\n"
+ "%s: the TV card. Best regards,\n"
+ "%s: -- tux\n",
+ dev->name,dev->name,dev->name,dev->name,dev->name);
+ printk("%s: Here is a list of valid choices for the card=<n> insmod option:\n",
+ dev->name);
+ for (i = 0; i < em2820_bcount; i++) {
+ printk("%s: card=%d -> %s\n",
+ dev->name, i, em2820_boards[i].name);
+ }
+ }
+
/* allocate device struct */
- retval = em2820_init_dev(&dev, udev, interface->minor, id->driver_info);
+ retval = em2820_init_dev(&dev, udev, nr, model);
if (retval)
return retval;
- em2820_info("Found %s\n", em2820_boards[id->driver_info].name);
+ em2820_info("Found %s\n", em2820_boards[model].name);
/* save our data pointer in this interface device */
usb_set_intfdata(interface, dev);
diff --git a/linux/drivers/usb/media/em2820.h b/linux/drivers/usb/media/em2820.h
index b60ef31f1..dd4229d13 100644
--- a/linux/drivers/usb/media/em2820.h
+++ b/linux/drivers/usb/media/em2820.h
@@ -1,5 +1,5 @@
/*
- em2820-cards.c - driver for Empia EM2820/2840 USB video capture devices
+ em2820-cards.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
Copyright (C) 2005 Markus Rechberger <mrechberger@gmail.com>
Ludovico Cavedon <cavedon@sssup.it>
@@ -29,6 +29,23 @@
#include <linux/videodev.h>
#include <linux/i2c.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 UNSET -1
+
+/* maximum number of em28xx boards */
+#define EM2820_MAXBOARDS 1 /*FIXME: should be bigger */
+
/* maximum number of frames that can be queued */
#define EM2820_NUM_FRAMES 5
/* number of frames that get used for v4l2_read() */
@@ -80,6 +97,9 @@
/* time to wait when stopping the isoc transfer */
#define EM2820_URB_TIMEOUT msecs_to_jiffies(EM2820_NUM_BUFS * EM2820_NUM_PACKETS)
+/* time in msecs to wait for i2c writes to finish */
+#define EM2800_I2C_WRITE_TIMEOUT 20
+
/* the various frame states */
enum em2820_frame_state {
F_UNUSED = 0,
@@ -146,12 +166,13 @@ enum em2820_decoder {
struct em2820_board {
char *name;
-
+ unsigned char chip_id;
int vchannels;
int norm;
int tuner_type;
/* i2c flags */
+ unsigned int is_em2800;
unsigned int tda9887_conf;
unsigned int has_tuner:1;
@@ -196,6 +217,7 @@ struct em2820 {
/* generic device properties */
char name[30]; /* name (including minor) of the device */
int model; /* index in the device_data struct */
+ unsigned int is_em2800;
int video_inputs; /* number of video inputs */
unsigned int has_tuner:1;
unsigned int has_msp34xx:1;
@@ -305,11 +327,14 @@ void em2820_uninit_isoc(struct em2820 *dev);
int em2820_set_alternate(struct em2820 *dev);
/* Provided by em2820-cards.c */
+extern int em2800_variant_detect(struct usb_device* udev,int model);
extern void em2820_card_setup(struct em2820 *dev);
extern struct em2820_board em2820_boards[];
extern struct usb_device_id em2820_id_table[];
+extern const unsigned int em2820_bcount;
/* em2820 registers */
+#define CHIPID_REG 0x0a
#define USBSUSP_REG 0x0c /* */
#define AUDIOSRC_REG 0x0e
diff --git a/v4l/ChangeLog b/v4l/ChangeLog
index ba4c643ce..8cfe7caa2 100644
--- a/v4l/ChangeLog
+++ b/v4l/ChangeLog
@@ -1,3 +1,26 @@
+2005-10-11 16:48 mchehab
+
+ * ../linux/Documentation/video4linux/CARDLIST.em2820:
+ * ../linux/drivers/usb/media/em2820-cards.c:
+ * ../linux/drivers/usb/media/em2820-core.c:
+ (em2820_isoc_video_copy), (em2820_set_alternate):
+ * ../linux/drivers/usb/media/em2820-i2c.c: (em2800_i2c_send_max4),
+ (em2800_i2c_send_bytes), (em2800_i2c_check_for_device),
+ (em2800_i2c_recv_bytes), (em2820_i2c_send_bytes),
+ (em2820_i2c_recv_bytes), (em2820_i2c_check_for_device),
+ (em2820_i2c_xfer), (em2820_i2c_eeprom), (do_i2c_scan):
+ * ../linux/drivers/usb/media/em2820-video.c: (em2820_do_ioctl),
+ (em2820_init_dev), (em2820_usb_probe):
+ * ../linux/drivers/usb/media/em2820.h:
+ * ../v4l/scripts/cardlist:
+ * ../v4l/scripts/em2820.pl:
+
+ - Included support for em2800.
+ - Included card insmod parameter.
+ - Now it will not try to register audio anymore.
+
+ Signed-off-by: Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+
2005-10-11 05:17 mkrufky
* ../linux/Documentation/video4linux/CARDLIST.cx88:
diff --git a/v4l/scripts/cardlist b/v4l/scripts/cardlist
index ae8bfb59f..a4c59763e 100644
--- a/v4l/scripts/cardlist
+++ b/v4l/scripts/cardlist
@@ -6,7 +6,7 @@ scripts/bttv.pl ../linux/drivers/media/video/bttv.h ../linux/drivers/media/vide
scripts/cx88.pl ../linux/drivers/media/video/cx88/cx88.h ../linux/drivers/media/video/cx88/cx88-cards.c \
| perl -ne 's/[ \t]+$//; print' > ../linux/Documentation/video4linux/CARDLIST.cx88
-./scripts/em2820.pl ../linux/drivers/usb/media/em2820-cards.c \
+./scripts/em2820.pl ../linux/drivers/usb/media/em2820.h ../linux/drivers/usb/media/em2820-cards.c \
| perl -ne 's/[ \t]+$//; print' > ../linux/Documentation/video4linux/CARDLIST.em2820
cat ../linux/drivers/media/video/tuner-simple.c \
| grep "{ \"" \
diff --git a/v4l/scripts/em2820.pl b/v4l/scripts/em2820.pl
index ba498f0fd..278dfc214 100644
--- a/v4l/scripts/em2820.pl
+++ b/v4l/scripts/em2820.pl
@@ -8,18 +8,27 @@ my %data;
while (<>) {
# defines in header file
-# if (/#define\s+(EM2820_BOARD_\w+)\s+(\d+)/) {
-# $data{$1}->{nr} = $2;
-# next;
-# }
+ if (/#define\s+(EM2820_BOARD_\w+)\s+(\d+)/) {
+ $data{$1}->{nr} = $2;
+ next;
+ }
+ if (/#define\s+(EM2800_BOARD_\w+)\s+(\d+)/) {
+ $data{$1}->{nr} = $2;
+ next;
+ }
# em2820_boards
if (/\[(EM2820_BOARD_\w+)\]/) {
$id = $1;
$data{$id}->{id} = $id;
- $data{$id}->{nr} = $nr++;
+ $data{$id}->{type} = "(em2820/em2840)";
+# $data{$id}->{nr} = $nr++;
+ };
+ if (/\[(EM2800_BOARD_\w+)\]/) {
+ $id = $1;
+ $data{$id}->{id} = $id;
+ $data{$id}->{type} = "(em2800)";
+# $data{$id}->{nr} = $nr++;
};
-
-# { USB_DEVICE(0x0ccd, 0x0036), .driver_info = EM2820_BOARD_TERRATEC_CINERGY_250 },
next unless defined($id);
@@ -29,6 +38,12 @@ while (<>) {
push @{$data{$3}->{subid}}, "$subvendor:$subdevice";
}
+ if (/USB_DEVICE.*0x([0-9a-fA-F]*).*0x([0-9a-fA-F]*).*driver_info.*(EM2800_BOARD_\w+)/ ) {
+ $subvendor=$1;
+ $subdevice=$2;
+ push @{$data{$3}->{subid}}, "$subvendor:$subdevice";
+ }
+
if (!defined($data{$id}) || !defined($data{$id}->{name})) {
$data{$id}->{name} = $1 if (/\.name\s*=\s*\"([^\"]+)\"/);
@@ -40,7 +55,7 @@ while (<>) {
}
foreach my $item (sort { $data{$a}->{nr} <=> $data{$b}->{nr} } keys %data) {
- printf("%3d -> %-51s", $data{$item}->{nr}, $data{$item}->{name});
+ printf("%3d -> %-40s %-15s", $data{$item}->{nr}, $data{$item}->{name},$data{$item}->{type});
printf(" [%s]",join(",",@{$data{$item}->{subid}}))
if defined($data{$item}->{subid});
print "\n";