]> Pileus Git - ~andy/linux/blobdiff - drivers/media/video/em28xx/em28xx-cards.c
[media] em28xx: Make em28xx-input.c a separate module
[~andy/linux] / drivers / media / video / em28xx / em28xx-cards.c
index 93807dcf944e4be4d9a4ed4604d358fa0c2e0b90..0ac117c23c47ca1d06d5ed19a46a0db7c68b93da 100644 (file)
@@ -336,6 +336,61 @@ static struct em28xx_reg_seq pctv_460e[] = {
        {             -1,   -1,   -1,  -1},
 };
 
+#if 0
+static struct em28xx_reg_seq hauppauge_930c_gpio[] = {
+       {EM2874_R80_GPIO,       0x6f,   0xff,   10},
+       {EM2874_R80_GPIO,       0x4f,   0xff,   10}, /* xc5000 reset */
+       {EM2874_R80_GPIO,       0x6f,   0xff,   10},
+       {EM2874_R80_GPIO,       0x4f,   0xff,   10},
+       { -1,                   -1,     -1,     -1},
+};
+
+static struct em28xx_reg_seq hauppauge_930c_digital[] = {
+       {EM2874_R80_GPIO,       0xf6,   0xff,   10},
+       {EM2874_R80_GPIO,       0xe6,   0xff,   100},
+       {EM2874_R80_GPIO,       0xa6,   0xff,   10},
+       { -1,                   -1,     -1,     -1},
+};
+#endif
+
+/* 1b80:e425 MaxMedia UB425-TC
+ * GPIO_6 - demod reset, 0=active
+ * GPIO_7 - LED, 0=active
+ */
+static struct em28xx_reg_seq maxmedia_ub425_tc[] = {
+       {EM2874_R80_GPIO,  0x83,  0xff,  100},
+       {EM2874_R80_GPIO,  0xc3,  0xff,  100}, /* GPIO_6 = 1 */
+       {EM2874_R80_GPIO,  0x43,  0xff,  000}, /* GPIO_7 = 0 */
+       {-1,                 -1,    -1,   -1},
+};
+
+/* 2304:0242 PCTV QuatroStick (510e)
+ * GPIO_2: decoder reset, 0=active
+ * GPIO_4: decoder suspend, 0=active
+ * GPIO_6: demod reset, 0=active
+ * GPIO_7: LED, 1=active
+ */
+static struct em28xx_reg_seq pctv_510e[] = {
+       {EM2874_R80_GPIO, 0x10, 0xff, 100},
+       {EM2874_R80_GPIO, 0x14, 0xff, 100}, /* GPIO_2 = 1 */
+       {EM2874_R80_GPIO, 0x54, 0xff, 050}, /* GPIO_6 = 1 */
+       {             -1,   -1,   -1,  -1},
+};
+
+/* 2013:0251 PCTV QuatroStick nano (520e)
+ * GPIO_2: decoder reset, 0=active
+ * GPIO_4: decoder suspend, 0=active
+ * GPIO_6: demod reset, 0=active
+ * GPIO_7: LED, 1=active
+ */
+static struct em28xx_reg_seq pctv_520e[] = {
+       {EM2874_R80_GPIO, 0x10, 0xff, 100},
+       {EM2874_R80_GPIO, 0x14, 0xff, 100}, /* GPIO_2 = 1 */
+       {EM2874_R80_GPIO, 0x54, 0xff, 050}, /* GPIO_6 = 1 */
+       {EM2874_R80_GPIO, 0xd4, 0xff, 000}, /* GPIO_7 = 1 */
+       {             -1,   -1,   -1,  -1},
+};
+
 /*
  *  Board definitions
  */
@@ -839,6 +894,10 @@ struct em28xx_board em28xx_boards[] = {
        [EM2870_BOARD_KWORLD_355U] = {
                .name         = "Kworld 355 U DVB-T",
                .valid        = EM28XX_BOARD_NOT_VALIDATED,
+               .tuner_type   = TUNER_ABSENT,
+               .tuner_gpio   = default_tuner_gpio,
+               .has_dvb      = 1,
+               .dvb_gpio     = default_digital,
        },
        [EM2870_BOARD_PINNACLE_PCTV_DVB] = {
                .name         = "Pinnacle PCTV DVB-T",
@@ -887,6 +946,37 @@ struct em28xx_board em28xx_boards[] = {
                .tuner_addr   = 0x41,
                .dvb_gpio     = terratec_h5_digital, /* FIXME: probably wrong */
                .tuner_gpio   = terratec_h5_gpio,
+#else
+               .tuner_type   = TUNER_ABSENT,
+#endif
+               .i2c_speed    = EM2874_I2C_SECONDARY_BUS_SELECT |
+                               EM28XX_I2C_CLK_WAIT_ENABLE |
+                               EM28XX_I2C_FREQ_400_KHZ,
+       },
+       [EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C] = {
+               .name         = "Hauppauge WinTV HVR 930C",
+               .has_dvb      = 1,
+#if 0 /* FIXME: Add analog support */
+               .tuner_type   = TUNER_XC5000,
+               .tuner_addr   = 0x41,
+               .dvb_gpio     = hauppauge_930c_digital,
+               .tuner_gpio   = hauppauge_930c_gpio,
+#else
+               .tuner_type   = TUNER_ABSENT,
+#endif
+               .ir_codes     = RC_MAP_HAUPPAUGE,
+               .i2c_speed    = EM2874_I2C_SECONDARY_BUS_SELECT |
+                               EM28XX_I2C_CLK_WAIT_ENABLE |
+                               EM28XX_I2C_FREQ_400_KHZ,
+       },
+       [EM2884_BOARD_CINERGY_HTC_STICK] = {
+               .name         = "Terratec Cinergy HTC Stick",
+               .has_dvb      = 1,
+#if 0
+               .tuner_type   = TUNER_PHILIPS_TDA8290,
+               .tuner_addr   = 0x41,
+               .dvb_gpio     = terratec_h5_digital, /* FIXME: probably wrong */
+               .tuner_gpio   = terratec_h5_gpio,
 #endif
                .i2c_speed    = EM2874_I2C_SECONDARY_BUS_SELECT |
                                EM28XX_I2C_CLK_WAIT_ENABLE |
@@ -1127,7 +1217,7 @@ struct em28xx_board em28xx_boards[] = {
                .name         = "Terratec Cinergy 200 USB",
                .is_em2800    = 1,
                .has_ir_i2c   = 1,
-               .tuner_type   = TUNER_LG_PAL_NEW_TAPC,
+               .tuner_type   = TUNER_LG_TALN,
                .tda9887_conf = TDA9887_PRESENT,
                .decoder      = EM28XX_SAA711X,
                .input        = { {
@@ -1218,7 +1308,7 @@ struct em28xx_board em28xx_boards[] = {
        },
        [EM2820_BOARD_PINNACLE_DVC_90] = {
                .name         = "Pinnacle Dazzle DVC 90/100/101/107 / Kaiser Baas Video to DVD maker "
-                               "/ Kworld DVD Maker 2",
+                              "/ Kworld DVD Maker 2 / Plextor ConvertX PX-AV100U",
                .tuner_type   = TUNER_ABSENT, /* capture only board */
                .decoder      = EM28XX_SAA711X,
                .input        = { {
@@ -1840,6 +1930,57 @@ struct em28xx_board em28xx_boards[] = {
                .has_dvb       = 1,
                .ir_codes      = RC_MAP_PINNACLE_PCTV_HD,
        },
+       /* eb1a:5006 Honestech VIDBOX NW03
+        * Empia EM2860, Philips SAA7113, Empia EMP202, No Tuner */
+       [EM2860_BOARD_HT_VIDBOX_NW03] = {
+               .name                = "Honestech Vidbox NW03",
+               .tuner_type          = TUNER_ABSENT,
+               .decoder             = EM28XX_SAA711X,
+               .input               = { {
+                       .type     = EM28XX_VMUX_COMPOSITE1,
+                       .vmux     = SAA7115_COMPOSITE0,
+                       .amux     = EM28XX_AMUX_LINE_IN,
+               }, {
+                       .type     = EM28XX_VMUX_SVIDEO,
+                       .vmux     = SAA7115_SVIDEO3,  /* S-VIDEO needs confirming */
+                       .amux     = EM28XX_AMUX_LINE_IN,
+               } },
+       },
+       /* 1b80:e425 MaxMedia UB425-TC
+        * Empia EM2874B + Micronas DRX 3913KA2 + NXP TDA18271HDC2 */
+       [EM2874_BOARD_MAXMEDIA_UB425_TC] = {
+               .name          = "MaxMedia UB425-TC",
+               .tuner_type    = TUNER_ABSENT,
+               .tuner_gpio    = maxmedia_ub425_tc,
+               .has_dvb       = 1,
+               .i2c_speed     = EM2874_I2C_SECONDARY_BUS_SELECT |
+                               EM28XX_I2C_CLK_WAIT_ENABLE |
+                               EM28XX_I2C_FREQ_400_KHZ,
+       },
+       /* 2304:0242 PCTV QuatroStick (510e)
+        * Empia EM2884 + Micronas DRX 3926K + NXP TDA18271HDC2 */
+       [EM2884_BOARD_PCTV_510E] = {
+               .name          = "PCTV QuatroStick (510e)",
+               .tuner_type    = TUNER_ABSENT,
+               .tuner_gpio    = pctv_510e,
+               .has_dvb       = 1,
+               .ir_codes      = RC_MAP_PINNACLE_PCTV_HD,
+               .i2c_speed     = EM2874_I2C_SECONDARY_BUS_SELECT |
+                               EM28XX_I2C_CLK_WAIT_ENABLE |
+                               EM28XX_I2C_FREQ_400_KHZ,
+       },
+       /* 2013:0251 PCTV QuatroStick nano (520e)
+        * Empia EM2884 + Micronas DRX 3926K + NXP TDA18271HDC2 */
+       [EM2884_BOARD_PCTV_520E] = {
+               .name          = "PCTV QuatroStick nano (520e)",
+               .tuner_type    = TUNER_ABSENT,
+               .tuner_gpio    = pctv_520e,
+               .has_dvb       = 1,
+               .ir_codes      = RC_MAP_PINNACLE_PCTV_HD,
+               .i2c_speed     = EM2874_I2C_SECONDARY_BUS_SELECT |
+                               EM28XX_I2C_CLK_WAIT_ENABLE |
+                               EM28XX_I2C_FREQ_400_KHZ,
+       },
 };
 const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
 
@@ -1899,6 +2040,8 @@ struct usb_device_id em28xx_id_table[] = {
                        .driver_info = EM2800_BOARD_GRABBEEX_USB2800 },
        { USB_DEVICE(0xeb1a, 0xe357),
                        .driver_info = EM2870_BOARD_KWORLD_355U },
+       { USB_DEVICE(0xeb1a, 0xe359),
+                       .driver_info = EM2870_BOARD_KWORLD_355U },
        { USB_DEVICE(0x1b80, 0xe302),
                        .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, /* Kaiser Baas Video to DVD maker */
        { USB_DEVICE(0x1b80, 0xe304),
@@ -1914,17 +2057,23 @@ struct usb_device_id em28xx_id_table[] = {
        { USB_DEVICE(0x0ccd, 0x0042),
                        .driver_info = EM2882_BOARD_TERRATEC_HYBRID_XS },
        { USB_DEVICE(0x0ccd, 0x0043),
+                       .driver_info = EM2870_BOARD_TERRATEC_XS },
+       { USB_DEVICE(0x0ccd, 0x008e),   /* Cinergy HTC USB XS Rev. 1 */
+                       .driver_info = EM2884_BOARD_TERRATEC_H5 },
+       { USB_DEVICE(0x0ccd, 0x00ac),   /* Cinergy HTC USB XS Rev. 2 */
+                       .driver_info = EM2884_BOARD_TERRATEC_H5 },
+       { USB_DEVICE(0x0ccd, 0x10a2),   /* H5 Rev. 1 */
                        .driver_info = EM2884_BOARD_TERRATEC_H5 },
-       { USB_DEVICE(0x0ccd, 0x10a2),   /* Rev. 1 */
+       { USB_DEVICE(0x0ccd, 0x10ad),   /* H5 Rev. 2 */
                        .driver_info = EM2884_BOARD_TERRATEC_H5 },
-       { USB_DEVICE(0x0ccd, 0x10ad),   /* Rev. 2 */
-                       .driver_info = EM2880_BOARD_TERRATEC_PRODIGY_XS },
        { USB_DEVICE(0x0ccd, 0x0084),
                        .driver_info = EM2860_BOARD_TERRATEC_AV350 },
        { USB_DEVICE(0x0ccd, 0x0096),
                        .driver_info = EM2860_BOARD_TERRATEC_GRABBY },
        { USB_DEVICE(0x0ccd, 0x10AF),
                        .driver_info = EM2860_BOARD_TERRATEC_GRABBY },
+       { USB_DEVICE(0x0ccd, 0x00b2),
+                       .driver_info = EM2884_BOARD_CINERGY_HTC_STICK },
        { USB_DEVICE(0x0fd9, 0x0033),
                        .driver_info = EM2860_BOARD_ELGATO_VIDEO_CAPTURE},
        { USB_DEVICE(0x185b, 0x2870),
@@ -1963,6 +2112,8 @@ struct usb_device_id em28xx_id_table[] = {
                        .driver_info = EM2880_BOARD_PINNACLE_PCTV_HD_PRO },
        { USB_DEVICE(0x0413, 0x6023),
                        .driver_info = EM2800_BOARD_LEADTEK_WINFAST_USBII },
+       { USB_DEVICE(0x093b, 0xa003),
+                      .driver_info = EM2820_BOARD_PINNACLE_DVC_90 },
        { USB_DEVICE(0x093b, 0xa005),
                        .driver_info = EM2861_BOARD_PLEXTOR_PX_TV100U },
        { USB_DEVICE(0x04bb, 0x0515),
@@ -1975,6 +2126,18 @@ struct usb_device_id em28xx_id_table[] = {
                        .driver_info = EM28174_BOARD_PCTV_290E },
        { USB_DEVICE(0x2013, 0x024c),
                        .driver_info = EM28174_BOARD_PCTV_460E },
+       { USB_DEVICE(0x2040, 0x1605),
+                       .driver_info = EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C },
+       { USB_DEVICE(0xeb1a, 0x5006),
+                       .driver_info = EM2860_BOARD_HT_VIDBOX_NW03 },
+       { USB_DEVICE(0x1b80, 0xe309), /* Sveon STV40 */
+                       .driver_info = EM2860_BOARD_EASYCAP },
+       { USB_DEVICE(0x1b80, 0xe425),
+                       .driver_info = EM2874_BOARD_MAXMEDIA_UB425_TC },
+       { USB_DEVICE(0x2304, 0x0242),
+                       .driver_info = EM2884_BOARD_PCTV_510E },
+       { USB_DEVICE(0x2013, 0x0251),
+                       .driver_info = EM2884_BOARD_PCTV_520E },
        { },
 };
 MODULE_DEVICE_TABLE(usb, em28xx_id_table);
@@ -2028,10 +2191,10 @@ int em28xx_tuner_callback(void *ptr, int component, int command, int arg)
        int rc = 0;
        struct em28xx *dev = ptr;
 
-       if (dev->tuner_type != TUNER_XC2028)
+       if (dev->tuner_type != TUNER_XC2028 && dev->tuner_type != TUNER_XC5000)
                return 0;
 
-       if (command != XC2028_TUNER_RESET)
+       if (command != XC2028_TUNER_RESET && command != XC5000_TUNER_RESET)
                return 0;
 
        rc = em28xx_gpio_set(dev, dev->board.tuner_gpio);
@@ -2203,7 +2366,8 @@ void em28xx_pre_card_setup(struct em28xx *dev)
        /* Set the initial XCLK and I2C clock values based on the board
           definition */
        em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk & 0x7f);
-       em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed);
+       if (!dev->board.is_em2800)
+               em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed);
        msleep(50);
 
        /* request some modules */
@@ -2497,54 +2661,6 @@ static int em28xx_hint_board(struct em28xx *dev)
        return -1;
 }
 
-/* ----------------------------------------------------------------------- */
-void em28xx_register_i2c_ir(struct em28xx *dev)
-{
-       /* Leadtek winfast tv USBII deluxe can find a non working IR-device */
-       /* at address 0x18, so if that address is needed for another board in */
-       /* the future, please put it after 0x1f. */
-       struct i2c_board_info info;
-       const unsigned short addr_list[] = {
-                0x1f, 0x30, 0x47, I2C_CLIENT_END
-       };
-
-       if (disable_ir)
-               return;
-
-       memset(&info, 0, sizeof(struct i2c_board_info));
-       memset(&dev->init_data, 0, sizeof(dev->init_data));
-       strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
-
-       /* detect & configure */
-       switch (dev->model) {
-       case EM2800_BOARD_TERRATEC_CINERGY_200:
-       case EM2820_BOARD_TERRATEC_CINERGY_250:
-               dev->init_data.ir_codes = RC_MAP_EM_TERRATEC;
-               dev->init_data.get_key = em28xx_get_key_terratec;
-               dev->init_data.name = "i2c IR (EM28XX Terratec)";
-               break;
-       case EM2820_BOARD_PINNACLE_USB_2:
-               dev->init_data.ir_codes = RC_MAP_PINNACLE_GREY;
-               dev->init_data.get_key = em28xx_get_key_pinnacle_usb_grey;
-               dev->init_data.name = "i2c IR (EM28XX Pinnacle PCTV)";
-               break;
-       case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2:
-               dev->init_data.ir_codes = RC_MAP_HAUPPAUGE;
-               dev->init_data.get_key = em28xx_get_key_em_haup;
-               dev->init_data.name = "i2c IR (EM2840 Hauppauge)";
-               break;
-       case EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE:
-               dev->init_data.ir_codes = RC_MAP_WINFAST_USBII_DELUXE;
-               dev->init_data.get_key = em28xx_get_key_winfast_usbii_deluxe;
-               dev->init_data.name = "i2c IR (EM2820 Winfast TV USBII Deluxe)";
-               break;
-       }
-
-       if (dev->init_data.name)
-               info.platform_data = &dev->init_data;
-       i2c_new_probed_device(&dev->i2c_adap, &info, addr_list, NULL);
-}
-
 void em28xx_card_setup(struct em28xx *dev)
 {
        /*
@@ -2685,13 +2801,6 @@ void em28xx_card_setup(struct em28xx *dev)
                break;
        }
 
-#if defined(CONFIG_MODULES) && defined(MODULE)
-       if (dev->board.has_ir_i2c && !disable_ir)
-               request_module("ir-kbd-i2c");
-#endif
-       if (dev->board.has_snapshot_button)
-               em28xx_register_snapshot_button(dev);
-
        if (dev->board.valid == EM28XX_BOARD_NOT_VALIDATED) {
                em28xx_errdev("\n\n");
                em28xx_errdev("The support for this board weren't "
@@ -2765,9 +2874,6 @@ void em28xx_card_setup(struct em28xx *dev)
        }
 
        em28xx_tuner_setup(dev);
-
-       if(!disable_ir)
-               em28xx_ir_init(dev);
 }
 
 
@@ -2784,6 +2890,8 @@ static void request_module_async(struct work_struct *work)
 
        if (dev->board.has_dvb)
                request_module("em28xx-dvb");
+       if (dev->board.has_ir_i2c && !disable_ir)
+               request_module("em28xx-rc");
 }
 
 static void request_modules(struct em28xx *dev)
@@ -2808,12 +2916,6 @@ static void flush_request_modules(struct em28xx *dev)
 */
 void em28xx_release_resources(struct em28xx *dev)
 {
-       if (dev->sbutton_input_dev)
-               em28xx_deregister_snapshot_button(dev);
-
-       if (dev->ir)
-               em28xx_ir_fini(dev);
-
        /*FIXME: I2C IR should be disconnected */
 
        em28xx_release_analog_resources(dev);
@@ -2832,11 +2934,10 @@ void em28xx_release_resources(struct em28xx *dev)
  * em28xx_init_dev()
  * allocates and inits the device structs, registers i2c bus and v4l device
  */
-static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
+static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
                           struct usb_interface *interface,
                           int minor)
 {
-       struct em28xx *dev = *devhandle;
        int retval;
 
        dev->udev = udev;
@@ -2931,7 +3032,7 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
 
        if (!dev->board.is_em2800) {
                /* Resets I2C speed */
-               em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed);
+               retval = em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed);
                if (retval < 0) {
                        em28xx_errdev("%s: em28xx_write_reg failed!"
                                      " retval [%d]\n",
@@ -3031,15 +3132,13 @@ unregister_dev:
 static int em28xx_usb_probe(struct usb_interface *interface,
                            const struct usb_device_id *id)
 {
-       const struct usb_endpoint_descriptor *endpoint;
        struct usb_device *udev;
        struct em28xx *dev = NULL;
        int retval;
-       bool is_audio_only = false, has_audio = false;
-       int i, nr, isoc_pipe;
+       bool has_audio = false, has_video = false, has_dvb = false;
+       int i, nr;
        const int ifnum = interface->altsetting[0].desc.bInterfaceNumber;
        char *speed;
-       char descr[255] = "";
 
        udev = usb_get_dev(interface_to_usbdev(interface));
 
@@ -3068,54 +3167,65 @@ static int em28xx_usb_probe(struct usb_interface *interface,
                goto err;
        }
 
+       /* allocate memory for our device state and initialize it */
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (dev == NULL) {
+               em28xx_err(DRIVER_NAME ": out of memory!\n");
+               retval = -ENOMEM;
+               goto err;
+       }
+
+       /* compute alternate max packet sizes */
+       dev->alt_max_pkt_size = kmalloc(sizeof(dev->alt_max_pkt_size[0]) *
+                                       interface->num_altsetting, GFP_KERNEL);
+       if (dev->alt_max_pkt_size == NULL) {
+               em28xx_errdev("out of memory!\n");
+               kfree(dev);
+               retval = -ENOMEM;
+               goto err;
+       }
+
        /* Get endpoints */
        for (i = 0; i < interface->num_altsetting; i++) {
                int ep;
 
                for (ep = 0; ep < interface->altsetting[i].desc.bNumEndpoints; ep++) {
-                       struct usb_host_endpoint        *e;
-                       e = &interface->altsetting[i].endpoint[ep];
-
-                       if (e->desc.bEndpointAddress == 0x83)
-                               has_audio = true;
+                       const struct usb_endpoint_descriptor *e;
+                       int sizedescr, size;
+
+                       e = &interface->altsetting[i].endpoint[ep].desc;
+
+                       sizedescr = le16_to_cpu(e->wMaxPacketSize);
+                       size = sizedescr & 0x7ff;
+
+                       if (udev->speed == USB_SPEED_HIGH)
+                               size = size * hb_mult(sizedescr);
+
+                       if (usb_endpoint_xfer_isoc(e) &&
+                           usb_endpoint_dir_in(e)) {
+                               switch (e->bEndpointAddress) {
+                               case EM28XX_EP_AUDIO:
+                                       has_audio = true;
+                                       break;
+                               case EM28XX_EP_ANALOG:
+                                       has_video = true;
+                                       dev->alt_max_pkt_size[i] = size;
+                                       break;
+                               case EM28XX_EP_DIGITAL:
+                                       has_dvb = true;
+                                       if (size > dev->dvb_max_pkt_size) {
+                                               dev->dvb_max_pkt_size = size;
+                                               dev->dvb_alt = i;
+                                       }
+                                       break;
+                               }
+                       }
                }
        }
 
-       endpoint = &interface->cur_altsetting->endpoint[0].desc;
-
-       /* check if the device has the iso in endpoint at the correct place */
-       if (usb_endpoint_xfer_isoc(endpoint)
-           &&
-           (interface->altsetting[1].endpoint[0].desc.wMaxPacketSize == 940)) {
-               /* It's a newer em2874/em2875 device */
-               isoc_pipe = 0;
-       } else {
-               int check_interface = 1;
-               isoc_pipe = 1;
-               endpoint = &interface->cur_altsetting->endpoint[1].desc;
-               if (!usb_endpoint_xfer_isoc(endpoint))
-                       check_interface = 0;
-
-               if (usb_endpoint_dir_out(endpoint))
-                       check_interface = 0;
-
-               if (!check_interface) {
-                       if (has_audio) {
-                               is_audio_only = true;
-                       } else {
-                               em28xx_err(DRIVER_NAME " video device (%04x:%04x): "
-                                       "interface %i, class %i found.\n",
-                                       le16_to_cpu(udev->descriptor.idVendor),
-                                       le16_to_cpu(udev->descriptor.idProduct),
-                                       ifnum,
-                                       interface->altsetting[0].desc.bInterfaceClass);
-                               em28xx_err(DRIVER_NAME " This is an anciliary "
-                                       "interface not used by the driver\n");
-
-                               retval = -ENODEV;
-                               goto err;
-                       }
-               }
+       if (!(has_audio || has_video || has_dvb)) {
+               retval = -ENODEV;
+               goto err_free;
        }
 
        switch (udev->speed) {
@@ -3133,20 +3243,11 @@ static int em28xx_usb_probe(struct usb_interface *interface,
                speed = "unknown";
        }
 
-       if (udev->manufacturer)
-               strlcpy(descr, udev->manufacturer, sizeof(descr));
-
-       if (udev->product) {
-               if (*descr)
-                       strlcat(descr, " ", sizeof(descr));
-               strlcat(descr, udev->product, sizeof(descr));
-       }
-       if (*descr)
-               strlcat(descr, " ", sizeof(descr));
-
        printk(KERN_INFO DRIVER_NAME
-               ": New device %s@ %s Mbps (%04x:%04x, interface %d, class %d)\n",
-               descr,
+               ": New device %s %s @ %s Mbps "
+               "(%04x:%04x, interface %d, class %d)\n",
+               udev->manufacturer ? udev->manufacturer : "",
+               udev->product ? udev->product : "",
                speed,
                le16_to_cpu(udev->descriptor.idVendor),
                le16_to_cpu(udev->descriptor.idProduct),
@@ -3157,6 +3258,14 @@ static int em28xx_usb_probe(struct usb_interface *interface,
                printk(KERN_INFO DRIVER_NAME
                       ": Audio Vendor Class interface %i found\n",
                       ifnum);
+       if (has_video)
+               printk(KERN_INFO DRIVER_NAME
+                      ": Video interface %i found\n",
+                      ifnum);
+       if (has_dvb)
+               printk(KERN_INFO DRIVER_NAME
+                      ": DVB interface %i found\n",
+                      ifnum);
 
        /*
         * Make sure we have 480 Mbps of bandwidth, otherwise things like
@@ -3168,22 +3277,14 @@ static int em28xx_usb_probe(struct usb_interface *interface,
                printk(DRIVER_NAME ": Device must be connected to a high-speed"
                       " USB 2.0 port.\n");
                retval = -ENODEV;
-               goto err;
-       }
-
-       /* allocate memory for our device state and initialize it */
-       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
-       if (dev == NULL) {
-               em28xx_err(DRIVER_NAME ": out of memory!\n");
-               retval = -ENOMEM;
-               goto err;
+               goto err_free;
        }
 
        snprintf(dev->name, sizeof(dev->name), "em28xx #%d", nr);
        dev->devno = nr;
        dev->model = id->driver_info;
        dev->alt   = -1;
-       dev->is_audio_only = is_audio_only;
+       dev->is_audio_only = has_audio && !(has_video || has_dvb);
        dev->has_alsa_audio = has_audio;
        dev->audio_ifnum = ifnum;
 
@@ -3196,26 +3297,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
                }
        }
 
-       /* compute alternate max packet sizes */
        dev->num_alt = interface->num_altsetting;
-       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");
-               kfree(dev);
-               retval = -ENOMEM;
-               goto err;
-       }
-
-       for (i = 0; i < dev->num_alt ; i++) {
-               u16 tmp = le16_to_cpu(interface->altsetting[i].endpoint[isoc_pipe].desc.wMaxPacketSize);
-               unsigned int size = tmp & 0x7ff;
-
-               if (udev->speed == USB_SPEED_HIGH)
-                       size = size * hb_mult(tmp);
-
-               dev->alt_max_pkt_size[i] = size;
-       }
 
        if ((card[nr] >= 0) && (card[nr] < em28xx_bcount))
                dev->model = card[nr];
@@ -3226,12 +3308,20 @@ static int em28xx_usb_probe(struct usb_interface *interface,
        /* allocate device struct */
        mutex_init(&dev->lock);
        mutex_lock(&dev->lock);
-       retval = em28xx_init_dev(&dev, udev, interface, nr);
+       retval = em28xx_init_dev(dev, udev, interface, nr);
        if (retval) {
-               mutex_unlock(&dev->lock);
-               kfree(dev->alt_max_pkt_size);
-               kfree(dev);
-               goto err;
+               goto unlock_and_free;
+       }
+
+       if (has_dvb) {
+               /* pre-allocate DVB isoc transfer buffers */
+               retval = em28xx_alloc_isoc(dev, EM28XX_DIGITAL_MODE,
+                                          EM28XX_DVB_MAX_PACKETS,
+                                          EM28XX_DVB_NUM_BUFS,
+                                          dev->dvb_max_pkt_size);
+               if (retval) {
+                       goto unlock_and_free;
+               }
        }
 
        request_modules(dev);
@@ -3250,6 +3340,13 @@ static int em28xx_usb_probe(struct usb_interface *interface,
 
        return 0;
 
+unlock_and_free:
+       mutex_unlock(&dev->lock);
+
+err_free:
+       kfree(dev->alt_max_pkt_size);
+       kfree(dev);
+
 err:
        clear_bit(nr, &em28xx_devused);
 
@@ -3299,7 +3396,7 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
                     video_device_node_name(dev->vdev));
 
                dev->state |= DEV_MISCONFIGURED;
-               em28xx_uninit_isoc(dev);
+               em28xx_uninit_isoc(dev, dev->mode);
                dev->state |= DEV_DISCONNECTED;
                wake_up_interruptible(&dev->wait_frame);
                wake_up_interruptible(&dev->wait_stream);
@@ -3308,6 +3405,9 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
                em28xx_release_resources(dev);
        }
 
+       /* free DVB isoc buffers */
+       em28xx_uninit_isoc(dev, EM28XX_DIGITAL_MODE);
+
        mutex_unlock(&dev->lock);
 
        em28xx_close_extension(dev);