]> err.no Git - linux-2.6/commitdiff
[PATCH] v4l: 767: included support for em2800
authorMauro Carvalho Chehab <mchehab@brturbo.com.br>
Wed, 9 Nov 2005 05:37:24 +0000 (21:37 -0800)
committerLinus Torvalds <torvalds@g5.osdl.org>
Wed, 9 Nov 2005 15:56:17 +0000 (07:56 -0800)
- Included support for em2800.

Signed-off-by: Mauro Carvalho Chehab <mchehab@brturbo.com.br>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Documentation/video4linux/CARDLIST.em28xx
drivers/media/video/em28xx/em28xx-cards.c
drivers/media/video/em28xx/em28xx-core.c
drivers/media/video/em28xx/em28xx-i2c.c
drivers/media/video/em28xx/em28xx-video.c
drivers/media/video/em28xx/em28xx.h

index a33ddea0b6f5e68d5a0ad06a771481e29c952d55..d86aae09450bc56d421d63e5e562c59a9dc1e543 100644 (file)
@@ -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)
index 7333bbad887104f4e583d8077900ff5e892e631e..91c70ebd0ea4cf08c16ad49a190fb7150ffe8c5c 100644 (file)
@@ -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>
 
 #include "em2820.h"
 
-enum em2820_board_entry {
-       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[] = {
+       [EM2800_BOARD_UNKNOWN] = {
+               .name         = "Unknown EM2800 video grabber",
+               .is_em2800    = 1,
+               .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,
+               },{
+                       .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,
+               },{
+                       .type     = EM2820_VMUX_SVIDEO,
+                       .vmux     = 9,
+                       .amux     = 1,
+               }},
+       },
        [EM2820_BOARD_TERRATEC_CINERGY_250] = {
                .name         = "Terratec Cinergy 250 USB",
                .vchannels    = 3,
@@ -129,17 +158,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 },
        { },
 };
 
@@ -163,6 +263,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);
index e187422f6d6dd376789fc8027c1eee1cdd177295..594e6d681ba413337a64aee755eee412337a4470 100644 (file)
@@ -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>
@@ -562,6 +562,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;
@@ -780,6 +785,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;
@@ -788,6 +798,7 @@ int em2820_set_alternate(struct em2820 *dev)
                        dev->alt = i;
                        break;
                        }
+               }
        }
 
        if (dev->alt != prev_alt) {
index 3065ddb4b368be03e22b76786e47b0ffb964bc87..b7360d579a8a3288a866e5a0a083f5f4cab3e544 100644 (file)
@@ -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>
 #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] : "???");
        }
 }
index 7e4114ea15f962145d66efa10a09117b3046aa66..d3a959b9ee64c60ab45aa2ae01b37541deecd6c9 100644 (file)
@@ -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,11 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
+static unsigned int card[]  = {[0 ... (EM2820_MAXBOARDS - 1)] = UNSET };
+
+module_param_array(card,  int, NULL, 0444);
+MODULE_PARM_DESC(card,"card type");
+
 static int tuner = -1;
 module_param(tuner, int, 0444);
 MODULE_PARM_DESC(tuner, "tuner type");
@@ -1081,7 +1086,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;
@@ -1520,21 +1525,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);
@@ -1545,6 +1541,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;
@@ -1595,7 +1592,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);
@@ -1688,7 +1685,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;
 }
 
@@ -1703,27 +1699,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);
index 7779121a3dea6fc7f4320b6f00462f32c216f756..4115938a173114125c523dd6a52074e828bd6fdf 100644 (file)
@@ -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>
 #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() */
@@ -79,6 +96,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,
@@ -145,12 +165,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;
@@ -195,6 +216,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;
@@ -304,11 +326,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