Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.14.15.
   1/*
   2 *  tm6000-cards.c - driver for TM5600/TM6000/TM6010 USB video capture devices
   3 *
   4 *  Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
   5 *
   6 *  This program is free software; you can redistribute it and/or modify
   7 *  it under the terms of the GNU General Public License as published by
   8 *  the Free Software Foundation version 2
   9 *
  10 *  This program is distributed in the hope that it will be useful,
  11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 *  GNU General Public License for more details.
  14 *
  15 *  You should have received a copy of the GNU General Public License
  16 *  along with this program; if not, write to the Free Software
  17 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18 */
  19
  20#include <linux/init.h>
  21#include <linux/module.h>
  22#include <linux/pci.h>
  23#include <linux/delay.h>
  24#include <linux/i2c.h>
  25#include <linux/usb.h>
  26#include <linux/slab.h>
  27#include <media/v4l2-common.h>
  28#include <media/tuner.h>
  29#include <media/tvaudio.h>
  30#include <media/i2c-addr.h>
  31#include <media/rc-map.h>
  32
  33#include "tm6000.h"
  34#include "tm6000-regs.h"
  35#include "tuner-xc2028.h"
  36#include "xc5000.h"
  37
  38#define TM6000_BOARD_UNKNOWN			0
  39#define TM5600_BOARD_GENERIC			1
  40#define TM6000_BOARD_GENERIC			2
  41#define TM6010_BOARD_GENERIC			3
  42#define TM5600_BOARD_10MOONS_UT821		4
  43#define TM5600_BOARD_10MOONS_UT330		5
  44#define TM6000_BOARD_ADSTECH_DUAL_TV		6
  45#define TM6000_BOARD_FREECOM_AND_SIMILAR	7
  46#define TM6000_BOARD_ADSTECH_MINI_DUAL_TV	8
  47#define TM6010_BOARD_HAUPPAUGE_900H		9
  48#define TM6010_BOARD_BEHOLD_WANDER		10
  49#define TM6010_BOARD_BEHOLD_VOYAGER		11
  50#define TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE	12
  51#define TM6010_BOARD_TWINHAN_TU501		13
  52#define TM6010_BOARD_BEHOLD_WANDER_LITE		14
  53#define TM6010_BOARD_BEHOLD_VOYAGER_LITE	15
  54#define TM5600_BOARD_TERRATEC_GRABSTER		16
  55
  56#define is_generic(model) ((model == TM6000_BOARD_UNKNOWN) || \
  57			   (model == TM5600_BOARD_GENERIC) || \
  58			   (model == TM6000_BOARD_GENERIC) || \
  59			   (model == TM6010_BOARD_GENERIC))
  60
  61#define TM6000_MAXBOARDS        16
  62static unsigned int card[]     = {[0 ... (TM6000_MAXBOARDS - 1)] = UNSET };
  63
  64module_param_array(card,  int, NULL, 0444);
  65
  66static unsigned long tm6000_devused;
  67
  68
  69struct tm6000_board {
  70	char            *name;
  71	char		eename[16];		/* EEPROM name */
  72	unsigned	eename_size;		/* size of EEPROM name */
  73	unsigned	eename_pos;		/* Position where it appears at ROM */
  74
  75	struct tm6000_capabilities caps;
  76
  77	enum		tm6000_devtype type;	/* variant of the chipset */
  78	int             tuner_type;     /* type of the tuner */
  79	int             tuner_addr;     /* tuner address */
  80	int             demod_addr;     /* demodulator address */
  81
  82	struct tm6000_gpio gpio;
  83
  84	struct tm6000_input	vinput[3];
  85	struct tm6000_input	rinput;
  86
  87	char		*ir_codes;
  88};
  89
  90struct tm6000_board tm6000_boards[] = {
  91	[TM6000_BOARD_UNKNOWN] = {
  92		.name         = "Unknown tm6000 video grabber",
  93		.caps = {
  94			.has_tuner	= 1,
  95			.has_eeprom	= 1,
  96		},
  97		.gpio = {
  98			.tuner_reset	= TM6000_GPIO_1,
  99		},
 100		.vinput = { {
 101			.type	= TM6000_INPUT_TV,
 102			.vmux	= TM6000_VMUX_VIDEO_B,
 103			.amux	= TM6000_AMUX_ADC1,
 104			}, {
 105			.type	= TM6000_INPUT_COMPOSITE1,
 106			.vmux	= TM6000_VMUX_VIDEO_A,
 107			.amux	= TM6000_AMUX_ADC2,
 108			}, {
 109			.type	= TM6000_INPUT_SVIDEO,
 110			.vmux	= TM6000_VMUX_VIDEO_AB,
 111			.amux	= TM6000_AMUX_ADC2,
 112			},
 113		},
 114	},
 115	[TM5600_BOARD_GENERIC] = {
 116		.name         = "Generic tm5600 board",
 117		.type         = TM5600,
 118		.tuner_type   = TUNER_XC2028,
 119		.tuner_addr   = 0xc2 >> 1,
 120		.caps = {
 121			.has_tuner	= 1,
 122			.has_eeprom	= 1,
 123		},
 124		.gpio = {
 125			.tuner_reset	= TM6000_GPIO_1,
 126		},
 127		.vinput = { {
 128			.type	= TM6000_INPUT_TV,
 129			.vmux	= TM6000_VMUX_VIDEO_B,
 130			.amux	= TM6000_AMUX_ADC1,
 131			}, {
 132			.type	= TM6000_INPUT_COMPOSITE1,
 133			.vmux	= TM6000_VMUX_VIDEO_A,
 134			.amux	= TM6000_AMUX_ADC2,
 135			}, {
 136			.type	= TM6000_INPUT_SVIDEO,
 137			.vmux	= TM6000_VMUX_VIDEO_AB,
 138			.amux	= TM6000_AMUX_ADC2,
 139			},
 140		},
 141	},
 142	[TM6000_BOARD_GENERIC] = {
 143		.name         = "Generic tm6000 board",
 144		.tuner_type   = TUNER_XC2028,
 145		.tuner_addr   = 0xc2 >> 1,
 146		.caps = {
 147			.has_tuner	= 1,
 148			.has_eeprom	= 1,
 149		},
 150		.gpio = {
 151			.tuner_reset	= TM6000_GPIO_1,
 152		},
 153		.vinput = { {
 154			.type	= TM6000_INPUT_TV,
 155			.vmux	= TM6000_VMUX_VIDEO_B,
 156			.amux	= TM6000_AMUX_ADC1,
 157			}, {
 158			.type	= TM6000_INPUT_COMPOSITE1,
 159			.vmux	= TM6000_VMUX_VIDEO_A,
 160			.amux	= TM6000_AMUX_ADC2,
 161			}, {
 162			.type	= TM6000_INPUT_SVIDEO,
 163			.vmux	= TM6000_VMUX_VIDEO_AB,
 164			.amux	= TM6000_AMUX_ADC2,
 165			},
 166		},
 167	},
 168	[TM6010_BOARD_GENERIC] = {
 169		.name         = "Generic tm6010 board",
 170		.type         = TM6010,
 171		.tuner_type   = TUNER_XC2028,
 172		.tuner_addr   = 0xc2 >> 1,
 173		.demod_addr   = 0x1e >> 1,
 174		.caps = {
 175			.has_tuner	= 1,
 176			.has_dvb	= 1,
 177			.has_zl10353	= 1,
 178			.has_eeprom	= 1,
 179			.has_remote	= 1,
 180		},
 181		.gpio = {
 182			.tuner_reset	= TM6010_GPIO_2,
 183			.tuner_on	= TM6010_GPIO_3,
 184			.demod_reset	= TM6010_GPIO_1,
 185			.demod_on	= TM6010_GPIO_4,
 186			.power_led	= TM6010_GPIO_7,
 187			.dvb_led	= TM6010_GPIO_5,
 188			.ir		= TM6010_GPIO_0,
 189		},
 190		.vinput = { {
 191			.type	= TM6000_INPUT_TV,
 192			.vmux	= TM6000_VMUX_VIDEO_B,
 193			.amux	= TM6000_AMUX_SIF1,
 194			}, {
 195			.type	= TM6000_INPUT_COMPOSITE1,
 196			.vmux	= TM6000_VMUX_VIDEO_A,
 197			.amux	= TM6000_AMUX_ADC2,
 198			}, {
 199			.type	= TM6000_INPUT_SVIDEO,
 200			.vmux	= TM6000_VMUX_VIDEO_AB,
 201			.amux	= TM6000_AMUX_ADC2,
 202			},
 203		},
 204	},
 205	[TM5600_BOARD_10MOONS_UT821] = {
 206		.name         = "10Moons UT 821",
 207		.tuner_type   = TUNER_XC2028,
 208		.eename       = { '1', '0', 'M', 'O', 'O', 'N', 'S', '5', '6', '0', '0', 0xff, 0x45, 0x5b},
 209		.eename_size  = 14,
 210		.eename_pos   = 0x14,
 211		.type         = TM5600,
 212		.tuner_addr   = 0xc2 >> 1,
 213		.caps = {
 214			.has_tuner    = 1,
 215			.has_eeprom   = 1,
 216		},
 217		.gpio = {
 218			.tuner_reset	= TM6000_GPIO_1,
 219		},
 220		.vinput = { {
 221			.type	= TM6000_INPUT_TV,
 222			.vmux	= TM6000_VMUX_VIDEO_B,
 223			.amux	= TM6000_AMUX_ADC1,
 224			}, {
 225			.type	= TM6000_INPUT_COMPOSITE1,
 226			.vmux	= TM6000_VMUX_VIDEO_A,
 227			.amux	= TM6000_AMUX_ADC2,
 228			}, {
 229			.type	= TM6000_INPUT_SVIDEO,
 230			.vmux	= TM6000_VMUX_VIDEO_AB,
 231			.amux	= TM6000_AMUX_ADC2,
 232			},
 233		},
 234	},
 235	[TM5600_BOARD_10MOONS_UT330] = {
 236		.name         = "10Moons UT 330",
 237		.tuner_type   = TUNER_PHILIPS_FQ1216AME_MK4,
 238		.tuner_addr   = 0xc8 >> 1,
 239		.caps = {
 240			.has_tuner    = 1,
 241			.has_dvb      = 0,
 242			.has_zl10353  = 0,
 243			.has_eeprom   = 1,
 244		},
 245		.vinput = { {
 246			.type	= TM6000_INPUT_TV,
 247			.vmux	= TM6000_VMUX_VIDEO_B,
 248			.amux	= TM6000_AMUX_ADC1,
 249			}, {
 250			.type	= TM6000_INPUT_COMPOSITE1,
 251			.vmux	= TM6000_VMUX_VIDEO_A,
 252			.amux	= TM6000_AMUX_ADC2,
 253			}, {
 254			.type	= TM6000_INPUT_SVIDEO,
 255			.vmux	= TM6000_VMUX_VIDEO_AB,
 256			.amux	= TM6000_AMUX_ADC2,
 257			},
 258		},
 259	},
 260	[TM6000_BOARD_ADSTECH_DUAL_TV] = {
 261		.name         = "ADSTECH Dual TV USB",
 262		.tuner_type   = TUNER_XC2028,
 263		.tuner_addr   = 0xc8 >> 1,
 264		.caps = {
 265			.has_tuner    = 1,
 266			.has_tda9874  = 1,
 267			.has_dvb      = 1,
 268			.has_zl10353  = 1,
 269			.has_eeprom   = 1,
 270		},
 271		.vinput = { {
 272			.type	= TM6000_INPUT_TV,
 273			.vmux	= TM6000_VMUX_VIDEO_B,
 274			.amux	= TM6000_AMUX_ADC1,
 275			}, {
 276			.type	= TM6000_INPUT_COMPOSITE1,
 277			.vmux	= TM6000_VMUX_VIDEO_A,
 278			.amux	= TM6000_AMUX_ADC2,
 279			}, {
 280			.type	= TM6000_INPUT_SVIDEO,
 281			.vmux	= TM6000_VMUX_VIDEO_AB,
 282			.amux	= TM6000_AMUX_ADC2,
 283			},
 284		},
 285	},
 286	[TM6000_BOARD_FREECOM_AND_SIMILAR] = {
 287		.name         = "Freecom Hybrid Stick / Moka DVB-T Receiver Dual",
 288		.tuner_type   = TUNER_XC2028, /* has a XC3028 */
 289		.tuner_addr   = 0xc2 >> 1,
 290		.demod_addr   = 0x1e >> 1,
 291		.caps = {
 292			.has_tuner    = 1,
 293			.has_dvb      = 1,
 294			.has_zl10353  = 1,
 295			.has_eeprom   = 0,
 296			.has_remote   = 1,
 297		},
 298		.gpio = {
 299			.tuner_reset	= TM6000_GPIO_4,
 300		},
 301		.vinput = { {
 302			.type	= TM6000_INPUT_TV,
 303			.vmux	= TM6000_VMUX_VIDEO_B,
 304			.amux	= TM6000_AMUX_ADC1,
 305			}, {
 306			.type	= TM6000_INPUT_COMPOSITE1,
 307			.vmux	= TM6000_VMUX_VIDEO_A,
 308			.amux	= TM6000_AMUX_ADC2,
 309			}, {
 310			.type	= TM6000_INPUT_SVIDEO,
 311			.vmux	= TM6000_VMUX_VIDEO_AB,
 312			.amux	= TM6000_AMUX_ADC2,
 313			},
 314		},
 315	},
 316	[TM6000_BOARD_ADSTECH_MINI_DUAL_TV] = {
 317		.name         = "ADSTECH Mini Dual TV USB",
 318		.tuner_type   = TUNER_XC2028, /* has a XC3028 */
 319		.tuner_addr   = 0xc8 >> 1,
 320		.demod_addr   = 0x1e >> 1,
 321		.caps = {
 322			.has_tuner    = 1,
 323			.has_dvb      = 1,
 324			.has_zl10353  = 1,
 325			.has_eeprom   = 0,
 326		},
 327		.gpio = {
 328			.tuner_reset	= TM6000_GPIO_4,
 329		},
 330		.vinput = { {
 331			.type	= TM6000_INPUT_TV,
 332			.vmux	= TM6000_VMUX_VIDEO_B,
 333			.amux	= TM6000_AMUX_ADC1,
 334			}, {
 335			.type	= TM6000_INPUT_COMPOSITE1,
 336			.vmux	= TM6000_VMUX_VIDEO_A,
 337			.amux	= TM6000_AMUX_ADC2,
 338			}, {
 339			.type	= TM6000_INPUT_SVIDEO,
 340			.vmux	= TM6000_VMUX_VIDEO_AB,
 341			.amux	= TM6000_AMUX_ADC2,
 342			},
 343		},
 344	},
 345	[TM6010_BOARD_HAUPPAUGE_900H] = {
 346		.name         = "Hauppauge WinTV HVR-900H / WinTV USB2-Stick",
 347		.eename       = { 'H', 0, 'V', 0, 'R', 0, '9', 0, '0', 0, '0', 0, 'H', 0 },
 348		.eename_size  = 14,
 349		.eename_pos   = 0x42,
 350		.tuner_type   = TUNER_XC2028, /* has a XC3028 */
 351		.tuner_addr   = 0xc2 >> 1,
 352		.demod_addr   = 0x1e >> 1,
 353		.type         = TM6010,
 354		.caps = {
 355			.has_tuner    = 1,
 356			.has_dvb      = 1,
 357			.has_zl10353  = 1,
 358			.has_eeprom   = 1,
 359			.has_remote   = 1,
 360		},
 361		.gpio = {
 362			.tuner_reset	= TM6010_GPIO_2,
 363			.tuner_on	= TM6010_GPIO_3,
 364			.demod_reset	= TM6010_GPIO_1,
 365			.demod_on	= TM6010_GPIO_4,
 366			.power_led	= TM6010_GPIO_7,
 367			.dvb_led	= TM6010_GPIO_5,
 368			.ir		= TM6010_GPIO_0,
 369		},
 370		.vinput = { {
 371			.type	= TM6000_INPUT_TV,
 372			.vmux	= TM6000_VMUX_VIDEO_B,
 373			.amux	= TM6000_AMUX_SIF1,
 374			}, {
 375			.type	= TM6000_INPUT_COMPOSITE1,
 376			.vmux	= TM6000_VMUX_VIDEO_A,
 377			.amux	= TM6000_AMUX_ADC2,
 378			}, {
 379			.type	= TM6000_INPUT_SVIDEO,
 380			.vmux	= TM6000_VMUX_VIDEO_AB,
 381			.amux	= TM6000_AMUX_ADC2,
 382			},
 383		},
 384	},
 385	[TM6010_BOARD_BEHOLD_WANDER] = {
 386		.name         = "Beholder Wander DVB-T/TV/FM USB2.0",
 387		.tuner_type   = TUNER_XC5000,
 388		.tuner_addr   = 0xc2 >> 1,
 389		.demod_addr   = 0x1e >> 1,
 390		.type         = TM6010,
 391		.caps = {
 392			.has_tuner      = 1,
 393			.has_dvb        = 1,
 394			.has_zl10353    = 1,
 395			.has_eeprom     = 1,
 396			.has_remote     = 1,
 397			.has_radio	= 1.
 398		},
 399		.gpio = {
 400			.tuner_reset	= TM6010_GPIO_0,
 401			.demod_reset	= TM6010_GPIO_1,
 402			.power_led	= TM6010_GPIO_6,
 403		},
 404		.vinput = { {
 405			.type	= TM6000_INPUT_TV,
 406			.vmux	= TM6000_VMUX_VIDEO_B,
 407			.amux	= TM6000_AMUX_SIF1,
 408			}, {
 409			.type	= TM6000_INPUT_COMPOSITE1,
 410			.vmux	= TM6000_VMUX_VIDEO_A,
 411			.amux	= TM6000_AMUX_ADC2,
 412			}, {
 413			.type	= TM6000_INPUT_SVIDEO,
 414			.vmux	= TM6000_VMUX_VIDEO_AB,
 415			.amux	= TM6000_AMUX_ADC2,
 416			},
 417		},
 418		.rinput = {
 419			.type	= TM6000_INPUT_RADIO,
 420			.amux	= TM6000_AMUX_ADC1,
 421		},
 422	},
 423	[TM6010_BOARD_BEHOLD_VOYAGER] = {
 424		.name         = "Beholder Voyager TV/FM USB2.0",
 425		.tuner_type   = TUNER_XC5000,
 426		.tuner_addr   = 0xc2 >> 1,
 427		.type         = TM6010,
 428		.caps = {
 429			.has_tuner      = 1,
 430			.has_dvb        = 0,
 431			.has_zl10353    = 0,
 432			.has_eeprom     = 1,
 433			.has_remote     = 1,
 434			.has_radio	= 1,
 435		},
 436		.gpio = {
 437			.tuner_reset	= TM6010_GPIO_0,
 438			.power_led	= TM6010_GPIO_6,
 439		},
 440		.vinput = { {
 441			.type	= TM6000_INPUT_TV,
 442			.vmux	= TM6000_VMUX_VIDEO_B,
 443			.amux	= TM6000_AMUX_SIF1,
 444			}, {
 445			.type	= TM6000_INPUT_COMPOSITE1,
 446			.vmux	= TM6000_VMUX_VIDEO_A,
 447			.amux	= TM6000_AMUX_ADC2,
 448			}, {
 449			.type	= TM6000_INPUT_SVIDEO,
 450			.vmux	= TM6000_VMUX_VIDEO_AB,
 451			.amux	= TM6000_AMUX_ADC2,
 452			},
 453		},
 454		.rinput = {
 455			.type	= TM6000_INPUT_RADIO,
 456			.amux	= TM6000_AMUX_ADC1,
 457		},
 458	},
 459	[TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE] = {
 460		.name         = "Terratec Cinergy Hybrid XE / Cinergy Hybrid-Stick",
 461		.tuner_type   = TUNER_XC2028, /* has a XC3028 */
 462		.tuner_addr   = 0xc2 >> 1,
 463		.demod_addr   = 0x1e >> 1,
 464		.type         = TM6010,
 465		.caps = {
 466			.has_tuner    = 1,
 467			.has_dvb      = 1,
 468			.has_zl10353  = 1,
 469			.has_eeprom   = 1,
 470			.has_remote   = 1,
 471		},
 472		.gpio = {
 473			.tuner_reset	= TM6010_GPIO_2,
 474			.tuner_on	= TM6010_GPIO_3,
 475			.demod_reset	= TM6010_GPIO_1,
 476			.demod_on	= TM6010_GPIO_4,
 477			.power_led	= TM6010_GPIO_7,
 478			.dvb_led	= TM6010_GPIO_5,
 479			.ir		= TM6010_GPIO_0,
 480		},
 481		.ir_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS,
 482		.vinput = { {
 483			.type	= TM6000_INPUT_TV,
 484			.vmux	= TM6000_VMUX_VIDEO_B,
 485			.amux	= TM6000_AMUX_SIF1,
 486			}, {
 487			.type	= TM6000_INPUT_COMPOSITE1,
 488			.vmux	= TM6000_VMUX_VIDEO_A,
 489			.amux	= TM6000_AMUX_ADC2,
 490			}, {
 491			.type	= TM6000_INPUT_SVIDEO,
 492			.vmux	= TM6000_VMUX_VIDEO_AB,
 493			.amux	= TM6000_AMUX_ADC2,
 494			},
 495		},
 496	},
 497	[TM5600_BOARD_TERRATEC_GRABSTER] = {
 498		.name         = "Terratec Grabster AV 150/250 MX",
 499		.type         = TM5600,
 500		.tuner_type   = TUNER_ABSENT,
 501		.vinput = { {
 502			.type	= TM6000_INPUT_TV,
 503			.vmux	= TM6000_VMUX_VIDEO_B,
 504			.amux	= TM6000_AMUX_ADC1,
 505			}, {
 506			.type	= TM6000_INPUT_COMPOSITE1,
 507			.vmux	= TM6000_VMUX_VIDEO_A,
 508			.amux	= TM6000_AMUX_ADC2,
 509			}, {
 510			.type	= TM6000_INPUT_SVIDEO,
 511			.vmux	= TM6000_VMUX_VIDEO_AB,
 512			.amux	= TM6000_AMUX_ADC2,
 513			},
 514		},
 515	},
 516	[TM6010_BOARD_TWINHAN_TU501] = {
 517		.name         = "Twinhan TU501(704D1)",
 518		.tuner_type   = TUNER_XC2028, /* has a XC3028 */
 519		.tuner_addr   = 0xc2 >> 1,
 520		.demod_addr   = 0x1e >> 1,
 521		.type         = TM6010,
 522		.caps = {
 523			.has_tuner    = 1,
 524			.has_dvb      = 1,
 525			.has_zl10353  = 1,
 526			.has_eeprom   = 1,
 527			.has_remote   = 1,
 528		},
 529		.gpio = {
 530			.tuner_reset	= TM6010_GPIO_2,
 531			.tuner_on	= TM6010_GPIO_3,
 532			.demod_reset	= TM6010_GPIO_1,
 533			.demod_on	= TM6010_GPIO_4,
 534			.power_led	= TM6010_GPIO_7,
 535			.dvb_led	= TM6010_GPIO_5,
 536			.ir		= TM6010_GPIO_0,
 537		},
 538		.vinput = { {
 539			.type	= TM6000_INPUT_TV,
 540			.vmux	= TM6000_VMUX_VIDEO_B,
 541			.amux	= TM6000_AMUX_SIF1,
 542			}, {
 543			.type	= TM6000_INPUT_COMPOSITE1,
 544			.vmux	= TM6000_VMUX_VIDEO_A,
 545			.amux	= TM6000_AMUX_ADC2,
 546			}, {
 547			.type	= TM6000_INPUT_SVIDEO,
 548			.vmux	= TM6000_VMUX_VIDEO_AB,
 549			.amux	= TM6000_AMUX_ADC2,
 550			},
 551		},
 552	},
 553	[TM6010_BOARD_BEHOLD_WANDER_LITE] = {
 554		.name         = "Beholder Wander Lite DVB-T/TV/FM USB2.0",
 555		.tuner_type   = TUNER_XC5000,
 556		.tuner_addr   = 0xc2 >> 1,
 557		.demod_addr   = 0x1e >> 1,
 558		.type         = TM6010,
 559		.caps = {
 560			.has_tuner      = 1,
 561			.has_dvb        = 1,
 562			.has_zl10353    = 1,
 563			.has_eeprom     = 1,
 564			.has_remote     = 0,
 565			.has_radio	= 1,
 566		},
 567		.gpio = {
 568			.tuner_reset	= TM6010_GPIO_0,
 569			.demod_reset	= TM6010_GPIO_1,
 570			.power_led	= TM6010_GPIO_6,
 571		},
 572		.vinput = { {
 573			.type	= TM6000_INPUT_TV,
 574			.vmux	= TM6000_VMUX_VIDEO_B,
 575			.amux	= TM6000_AMUX_SIF1,
 576			},
 577		},
 578		.rinput = {
 579			.type	= TM6000_INPUT_RADIO,
 580			.amux	= TM6000_AMUX_ADC1,
 581		},
 582	},
 583	[TM6010_BOARD_BEHOLD_VOYAGER_LITE] = {
 584		.name         = "Beholder Voyager Lite TV/FM USB2.0",
 585		.tuner_type   = TUNER_XC5000,
 586		.tuner_addr   = 0xc2 >> 1,
 587		.type         = TM6010,
 588		.caps = {
 589			.has_tuner      = 1,
 590			.has_dvb        = 0,
 591			.has_zl10353    = 0,
 592			.has_eeprom     = 1,
 593			.has_remote     = 0,
 594			.has_radio	= 1,
 595		},
 596		.gpio = {
 597			.tuner_reset	= TM6010_GPIO_0,
 598			.power_led	= TM6010_GPIO_6,
 599		},
 600		.vinput = { {
 601			.type	= TM6000_INPUT_TV,
 602			.vmux	= TM6000_VMUX_VIDEO_B,
 603			.amux	= TM6000_AMUX_SIF1,
 604			},
 605		},
 606		.rinput = {
 607			.type	= TM6000_INPUT_RADIO,
 608			.amux	= TM6000_AMUX_ADC1,
 609		},
 610	},
 611};
 612
 613/* table of devices that work with this driver */
 614struct usb_device_id tm6000_id_table[] = {
 615	{ USB_DEVICE(0x6000, 0x0001), .driver_info = TM5600_BOARD_GENERIC },
 616	{ USB_DEVICE(0x6000, 0x0002), .driver_info = TM6010_BOARD_GENERIC },
 617	{ USB_DEVICE(0x06e1, 0xf332), .driver_info = TM6000_BOARD_ADSTECH_DUAL_TV },
 618	{ USB_DEVICE(0x14aa, 0x0620), .driver_info = TM6000_BOARD_FREECOM_AND_SIMILAR },
 619	{ USB_DEVICE(0x06e1, 0xb339), .driver_info = TM6000_BOARD_ADSTECH_MINI_DUAL_TV },
 620	{ USB_DEVICE(0x2040, 0x6600), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
 621	{ USB_DEVICE(0x2040, 0x6601), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
 622	{ USB_DEVICE(0x2040, 0x6610), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
 623	{ USB_DEVICE(0x2040, 0x6611), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
 624	{ USB_DEVICE(0x6000, 0xdec0), .driver_info = TM6010_BOARD_BEHOLD_WANDER },
 625	{ USB_DEVICE(0x6000, 0xdec1), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER },
 626	{ USB_DEVICE(0x0ccd, 0x0086), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE },
 627	{ USB_DEVICE(0x0ccd, 0x00A5), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE },
 628	{ USB_DEVICE(0x0ccd, 0x0079), .driver_info = TM5600_BOARD_TERRATEC_GRABSTER },
 629	{ USB_DEVICE(0x13d3, 0x3240), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
 630	{ USB_DEVICE(0x13d3, 0x3241), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
 631	{ USB_DEVICE(0x13d3, 0x3243), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
 632	{ USB_DEVICE(0x13d3, 0x3264), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
 633	{ USB_DEVICE(0x6000, 0xdec2), .driver_info = TM6010_BOARD_BEHOLD_WANDER_LITE },
 634	{ USB_DEVICE(0x6000, 0xdec3), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER_LITE },
 635	{ },
 636};
 637
 638/* Control power led for show some activity */
 639void tm6000_flash_led(struct tm6000_core *dev, u8 state)
 640{
 641	/* Power LED unconfigured */
 642	if (!dev->gpio.power_led)
 643		return;
 644
 645	/* ON Power LED */
 646	if (state) {
 647		switch (dev->model) {
 648		case TM6010_BOARD_HAUPPAUGE_900H:
 649		case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
 650		case TM6010_BOARD_TWINHAN_TU501:
 651			tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
 652				dev->gpio.power_led, 0x00);
 653			break;
 654		case TM6010_BOARD_BEHOLD_WANDER:
 655		case TM6010_BOARD_BEHOLD_VOYAGER:
 656		case TM6010_BOARD_BEHOLD_WANDER_LITE:
 657		case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
 658			tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
 659				dev->gpio.power_led, 0x01);
 660			break;
 661		}
 662	}
 663	/* OFF Power LED */
 664	else {
 665		switch (dev->model) {
 666		case TM6010_BOARD_HAUPPAUGE_900H:
 667		case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
 668		case TM6010_BOARD_TWINHAN_TU501:
 669			tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
 670				dev->gpio.power_led, 0x01);
 671			break;
 672		case TM6010_BOARD_BEHOLD_WANDER:
 673		case TM6010_BOARD_BEHOLD_VOYAGER:
 674		case TM6010_BOARD_BEHOLD_WANDER_LITE:
 675		case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
 676			tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
 677				dev->gpio.power_led, 0x00);
 678			break;
 679		}
 680	}
 681}
 682
 683/* Tuner callback to provide the proper gpio changes needed for xc5000 */
 684int tm6000_xc5000_callback(void *ptr, int component, int command, int arg)
 685{
 686	int rc = 0;
 687	struct tm6000_core *dev = ptr;
 688
 689	if (dev->tuner_type != TUNER_XC5000)
 690		return 0;
 691
 692	switch (command) {
 693	case XC5000_TUNER_RESET:
 694		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
 695			       dev->gpio.tuner_reset, 0x01);
 696		msleep(15);
 697		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
 698			       dev->gpio.tuner_reset, 0x00);
 699		msleep(15);
 700		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
 701			       dev->gpio.tuner_reset, 0x01);
 702		break;
 703	}
 704	return rc;
 705}
 706EXPORT_SYMBOL_GPL(tm6000_xc5000_callback);
 707
 708/* Tuner callback to provide the proper gpio changes needed for xc2028 */
 709
 710int tm6000_tuner_callback(void *ptr, int component, int command, int arg)
 711{
 712	int rc = 0;
 713	struct tm6000_core *dev = ptr;
 714
 715	if (dev->tuner_type != TUNER_XC2028)
 716		return 0;
 717
 718	switch (command) {
 719	case XC2028_RESET_CLK:
 720		tm6000_ir_wait(dev, 0);
 721
 722		tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT,
 723					0x02, arg);
 724		msleep(10);
 725		rc = tm6000_i2c_reset(dev, 10);
 726		break;
 727	case XC2028_TUNER_RESET:
 728		/* Reset codes during load firmware */
 729		switch (arg) {
 730		case 0:
 731			/* newer tuner can faster reset */
 732			switch (dev->model) {
 733			case TM5600_BOARD_10MOONS_UT821:
 734				tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
 735					       dev->gpio.tuner_reset, 0x01);
 736				tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
 737					       0x300, 0x01);
 738				msleep(10);
 739				tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
 740					       dev->gpio.tuner_reset, 0x00);
 741				tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
 742					       0x300, 0x00);
 743				msleep(10);
 744				tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
 745					       dev->gpio.tuner_reset, 0x01);
 746				tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
 747					       0x300, 0x01);
 748				break;
 749			case TM6010_BOARD_HAUPPAUGE_900H:
 750			case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
 751			case TM6010_BOARD_TWINHAN_TU501:
 752				tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
 753					       dev->gpio.tuner_reset, 0x01);
 754				msleep(60);
 755				tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
 756					       dev->gpio.tuner_reset, 0x00);
 757				msleep(75);
 758				tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
 759					       dev->gpio.tuner_reset, 0x01);
 760				msleep(60);
 761				break;
 762			default:
 763				tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
 764					       dev->gpio.tuner_reset, 0x00);
 765				msleep(130);
 766				tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
 767					       dev->gpio.tuner_reset, 0x01);
 768				msleep(130);
 769				break;
 770			}
 771
 772			tm6000_ir_wait(dev, 1);
 773			break;
 774		case 1:
 775			tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT,
 776						0x02, 0x01);
 777			msleep(10);
 778			break;
 779		case 2:
 780			rc = tm6000_i2c_reset(dev, 100);
 781			break;
 782		}
 783	}
 784	return rc;
 785}
 786EXPORT_SYMBOL_GPL(tm6000_tuner_callback);
 787
 788int tm6000_cards_setup(struct tm6000_core *dev)
 789{
 790	int i, rc;
 791
 792	/*
 793	 * Board-specific initialization sequence. Handles all GPIO
 794	 * initialization sequences that are board-specific.
 795	 * Up to now, all found devices use GPIO1 and GPIO4 at the same way.
 796	 * Probably, they're all based on some reference device. Due to that,
 797	 * there's a common routine at the end to handle those GPIO's. Devices
 798	 * that use different pinups or init sequences can just return at
 799	 * the board-specific session.
 800	 */
 801	switch (dev->model) {
 802	case TM6010_BOARD_HAUPPAUGE_900H:
 803	case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
 804	case TM6010_BOARD_TWINHAN_TU501:
 805	case TM6010_BOARD_GENERIC:
 806		/* Turn xceive 3028 on */
 807		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.tuner_on, 0x01);
 808		msleep(15);
 809		/* Turn zarlink zl10353 on */
 810		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x00);
 811		msleep(15);
 812		/* Reset zarlink zl10353 */
 813		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x00);
 814		msleep(50);
 815		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x01);
 816		msleep(15);
 817		/* Turn zarlink zl10353 off */
 818		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x01);
 819		msleep(15);
 820		/* ir ? */
 821		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.ir, 0x01);
 822		msleep(15);
 823		/* Power led on (blue) */
 824		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x00);
 825		msleep(15);
 826		/* DVB led off (orange) */
 827		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.dvb_led, 0x01);
 828		msleep(15);
 829		/* Turn zarlink zl10353 on */
 830		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x00);
 831		msleep(15);
 832		break;
 833	case TM6010_BOARD_BEHOLD_WANDER:
 834	case TM6010_BOARD_BEHOLD_WANDER_LITE:
 835		/* Power led on (blue) */
 836		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01);
 837		msleep(15);
 838		/* Reset zarlink zl10353 */
 839		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x00);
 840		msleep(50);
 841		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x01);
 842		msleep(15);
 843		break;
 844	case TM6010_BOARD_BEHOLD_VOYAGER:
 845	case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
 846		/* Power led on (blue) */
 847		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01);
 848		msleep(15);
 849		break;
 850	default:
 851		break;
 852	}
 853
 854	/*
 855	 * Default initialization. Most of the devices seem to use GPIO1
 856	 * and GPIO4.on the same way, so, this handles the common sequence
 857	 * used by most devices.
 858	 * If a device uses a different sequence or different GPIO pins for
 859	 * reset, just add the code at the board-specific part
 860	 */
 861
 862	if (dev->gpio.tuner_reset) {
 863		for (i = 0; i < 2; i++) {
 864			rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
 865						dev->gpio.tuner_reset, 0x00);
 866			if (rc < 0) {
 867				printk(KERN_ERR "Error %i doing tuner reset\n", rc);
 868				return rc;
 869			}
 870
 871			msleep(10); /* Just to be conservative */
 872			rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
 873						dev->gpio.tuner_reset, 0x01);
 874			if (rc < 0) {
 875				printk(KERN_ERR "Error %i doing tuner reset\n", rc);
 876				return rc;
 877			}
 878		}
 879	} else {
 880		printk(KERN_ERR "Tuner reset is not configured\n");
 881		return -1;
 882	}
 883
 884	msleep(50);
 885
 886	return 0;
 887};
 888
 889static void tm6000_config_tuner(struct tm6000_core *dev)
 890{
 891	struct tuner_setup tun_setup;
 892
 893	/* Load tuner module */
 894	v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
 895		"tuner", dev->tuner_addr, NULL);
 896
 897	memset(&tun_setup, 0, sizeof(tun_setup));
 898	tun_setup.type = dev->tuner_type;
 899	tun_setup.addr = dev->tuner_addr;
 900
 901	tun_setup.mode_mask = 0;
 902	if (dev->caps.has_tuner)
 903		tun_setup.mode_mask |= (T_ANALOG_TV | T_RADIO);
 904
 905	switch (dev->tuner_type) {
 906	case TUNER_XC2028:
 907		tun_setup.tuner_callback = tm6000_tuner_callback;
 908		break;
 909	case TUNER_XC5000:
 910		tun_setup.tuner_callback = tm6000_xc5000_callback;
 911		break;
 912	}
 913
 914	v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup);
 915
 916	switch (dev->tuner_type) {
 917	case TUNER_XC2028: {
 918		struct v4l2_priv_tun_config xc2028_cfg;
 919		struct xc2028_ctrl ctl;
 920
 921		memset(&xc2028_cfg, 0, sizeof(xc2028_cfg));
 922		memset(&ctl, 0, sizeof(ctl));
 923
 924		ctl.demod = XC3028_FE_ZARLINK456;
 925
 926		xc2028_cfg.tuner = TUNER_XC2028;
 927		xc2028_cfg.priv  = &ctl;
 928
 929		switch (dev->model) {
 930		case TM6010_BOARD_HAUPPAUGE_900H:
 931		case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
 932		case TM6010_BOARD_TWINHAN_TU501:
 933			ctl.fname = "xc3028L-v36.fw";
 934			break;
 935		default:
 936			if (dev->dev_type == TM6010)
 937				ctl.fname = "xc3028-v27.fw";
 938			else
 939				ctl.fname = "xc3028-v24.fw";
 940		}
 941
 942		printk(KERN_INFO "Setting firmware parameters for xc2028\n");
 943		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config,
 944				     &xc2028_cfg);
 945
 946		}
 947		break;
 948	case TUNER_XC5000:
 949		{
 950		struct v4l2_priv_tun_config  xc5000_cfg;
 951		struct xc5000_config ctl = {
 952			.i2c_address = dev->tuner_addr,
 953			.if_khz      = 4570,
 954			.radio_input = XC5000_RADIO_FM1_MONO,
 955			};
 956
 957		xc5000_cfg.tuner = TUNER_XC5000;
 958		xc5000_cfg.priv  = &ctl;
 959
 960		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config,
 961				     &xc5000_cfg);
 962		}
 963		break;
 964	default:
 965		printk(KERN_INFO "Unknown tuner type. Tuner is not configured.\n");
 966		break;
 967	}
 968}
 969
 970static int fill_board_specific_data(struct tm6000_core *dev)
 971{
 972	int rc;
 973
 974	dev->dev_type   = tm6000_boards[dev->model].type;
 975	dev->tuner_type = tm6000_boards[dev->model].tuner_type;
 976	dev->tuner_addr = tm6000_boards[dev->model].tuner_addr;
 977
 978	dev->gpio = tm6000_boards[dev->model].gpio;
 979
 980	dev->ir_codes = tm6000_boards[dev->model].ir_codes;
 981
 982	dev->demod_addr = tm6000_boards[dev->model].demod_addr;
 983
 984	dev->caps = tm6000_boards[dev->model].caps;
 985
 986	dev->vinput[0] = tm6000_boards[dev->model].vinput[0];
 987	dev->vinput[1] = tm6000_boards[dev->model].vinput[1];
 988	dev->vinput[2] = tm6000_boards[dev->model].vinput[2];
 989	dev->rinput = tm6000_boards[dev->model].rinput;
 990
 991	/* initialize hardware */
 992	rc = tm6000_init(dev);
 993	if (rc < 0)
 994		return rc;
 995
 996	return v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev);
 997}
 998
 999
1000static void use_alternative_detection_method(struct tm6000_core *dev)
1001{
1002	int i, model = -1;
1003
1004	if (!dev->eedata_size)
1005		return;
1006
1007	for (i = 0; i < ARRAY_SIZE(tm6000_boards); i++) {
1008		if (!tm6000_boards[i].eename_size)
1009			continue;
1010		if (dev->eedata_size < tm6000_boards[i].eename_pos +
1011				       tm6000_boards[i].eename_size)
1012			continue;
1013
1014		if (!memcmp(&dev->eedata[tm6000_boards[i].eename_pos],
1015			    tm6000_boards[i].eename,
1016			    tm6000_boards[i].eename_size)) {
1017			model = i;
1018			break;
1019		}
1020	}
1021	if (model < 0) {
1022		printk(KERN_INFO "Device has eeprom but is currently unknown\n");
1023		return;
1024	}
1025
1026	dev->model = model;
1027
1028	printk(KERN_INFO "Device identified via eeprom as %s (type = %d)\n",
1029	       tm6000_boards[model].name, model);
1030}
1031
1032static int tm6000_init_dev(struct tm6000_core *dev)
1033{
1034	struct v4l2_frequency f;
1035	int rc = 0;
1036
1037	mutex_init(&dev->lock);
1038	mutex_lock(&dev->lock);
1039
1040	if (!is_generic(dev->model)) {
1041		rc = fill_board_specific_data(dev);
1042		if (rc < 0)
1043			goto err;
1044
1045		/* register i2c bus */
1046		rc = tm6000_i2c_register(dev);
1047		if (rc < 0)
1048			goto err;
1049	} else {
1050		/* register i2c bus */
1051		rc = tm6000_i2c_register(dev);
1052		if (rc < 0)
1053			goto err;
1054
1055		use_alternative_detection_method(dev);
1056
1057		rc = fill_board_specific_data(dev);
1058		if (rc < 0)
1059			goto err;
1060	}
1061
1062	/* Default values for STD and resolutions */
1063	dev->width = 720;
1064	dev->height = 480;
1065	dev->norm = V4L2_STD_PAL_M;
1066
1067	/* Configure tuner */
1068	tm6000_config_tuner(dev);
1069
1070	/* Set video standard */
1071	v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
1072
1073	/* Set tuner frequency - also loads firmware on xc2028/xc3028 */
1074	f.tuner = 0;
1075	f.type = V4L2_TUNER_ANALOG_TV;
1076	f.frequency = 3092;	/* 193.25 MHz */
1077	dev->freq = f.frequency;
1078	v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
1079
1080	if (dev->caps.has_tda9874)
1081		v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
1082			"tvaudio", I2C_ADDR_TDA9874, NULL);
1083
1084	/* register and initialize V4L2 */
1085	rc = tm6000_v4l2_register(dev);
1086	if (rc < 0)
1087		goto err;
1088
1089	tm6000_add_into_devlist(dev);
1090	tm6000_init_extension(dev);
1091
1092	tm6000_ir_init(dev);
1093
1094	mutex_unlock(&dev->lock);
1095	return 0;
1096
1097err:
1098	mutex_unlock(&dev->lock);
1099	return rc;
1100}
1101
1102/* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
1103#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
1104
1105static void get_max_endpoint(struct usb_device *udev,
1106			     struct usb_host_interface *alt,
1107			     char *msgtype,
1108			     struct usb_host_endpoint *curr_e,
1109			     struct tm6000_endpoint *tm_ep)
1110{
1111	u16 tmp = le16_to_cpu(curr_e->desc.wMaxPacketSize);
1112	unsigned int size = tmp & 0x7ff;
1113
1114	if (udev->speed == USB_SPEED_HIGH)
1115		size = size * hb_mult(tmp);
1116
1117	if (size > tm_ep->maxsize) {
1118		tm_ep->endp = curr_e;
1119		tm_ep->maxsize = size;
1120		tm_ep->bInterfaceNumber = alt->desc.bInterfaceNumber;
1121		tm_ep->bAlternateSetting = alt->desc.bAlternateSetting;
1122
1123		printk(KERN_INFO "tm6000: %s endpoint: 0x%02x (max size=%u bytes)\n",
1124					msgtype, curr_e->desc.bEndpointAddress,
1125					size);
1126	}
1127}
1128
1129/*
1130 * tm6000_usb_probe()
1131 * checks for supported devices
1132 */
1133static int tm6000_usb_probe(struct usb_interface *interface,
1134			    const struct usb_device_id *id)
1135{
1136	struct usb_device *usbdev;
1137	struct tm6000_core *dev = NULL;
1138	int i, rc = 0;
1139	int nr = 0;
1140	char *speed;
1141
1142	usbdev = usb_get_dev(interface_to_usbdev(interface));
1143
1144	/* Selects the proper interface */
1145	rc = usb_set_interface(usbdev, 0, 1);
1146	if (rc < 0)
1147		goto err;
1148
1149	/* Check to see next free device and mark as used */
1150	nr = find_first_zero_bit(&tm6000_devused, TM6000_MAXBOARDS);
1151	if (nr >= TM6000_MAXBOARDS) {
1152		printk(KERN_ERR "tm6000: Supports only %i tm60xx boards.\n", TM6000_MAXBOARDS);
1153		usb_put_dev(usbdev);
1154		return -ENOMEM;
1155	}
1156
1157	/* Create and initialize dev struct */
1158	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
1159	if (dev == NULL) {
1160		printk(KERN_ERR "tm6000" ": out of memory!\n");
1161		usb_put_dev(usbdev);
1162		return -ENOMEM;
1163	}
1164	spin_lock_init(&dev->slock);
1165
1166	/* Increment usage count */
1167	tm6000_devused |= 1<<nr;
1168	snprintf(dev->name, 29, "tm6000 #%d", nr);
1169
1170	dev->model = id->driver_info;
1171	if ((card[nr] >= 0) && (card[nr] < ARRAY_SIZE(tm6000_boards)))
1172		dev->model = card[nr];
1173
1174	dev->udev = usbdev;
1175	dev->devno = nr;
1176
1177	switch (usbdev->speed) {
1178	case USB_SPEED_LOW:
1179		speed = "1.5";
1180		break;
1181	case USB_SPEED_UNKNOWN:
1182	case USB_SPEED_FULL:
1183		speed = "12";
1184		break;
1185	case USB_SPEED_HIGH:
1186		speed = "480";
1187		break;
1188	default:
1189		speed = "unknown";
1190	}
1191
1192
1193
1194	/* Get endpoints */
1195	for (i = 0; i < interface->num_altsetting; i++) {
1196		int ep;
1197
1198		for (ep = 0; ep < interface->altsetting[i].desc.bNumEndpoints; ep++) {
1199			struct usb_host_endpoint	*e;
1200			int dir_out;
1201
1202			e = &interface->altsetting[i].endpoint[ep];
1203
1204			dir_out = ((e->desc.bEndpointAddress &
1205					USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT);
1206
1207			printk(KERN_INFO "tm6000: alt %d, interface %i, class %i\n",
1208			       i,
1209			       interface->altsetting[i].desc.bInterfaceNumber,
1210			       interface->altsetting[i].desc.bInterfaceClass);
1211
1212			switch (e->desc.bmAttributes) {
1213			case USB_ENDPOINT_XFER_BULK:
1214				if (!dir_out) {
1215					get_max_endpoint(usbdev,
1216							 &interface->altsetting[i],
1217							 "Bulk IN", e,
1218							 &dev->bulk_in);
1219				} else {
1220					get_max_endpoint(usbdev,
1221							 &interface->altsetting[i],
1222							 "Bulk OUT", e,
1223							 &dev->bulk_out);
1224				}
1225				break;
1226			case USB_ENDPOINT_XFER_ISOC:
1227				if (!dir_out) {
1228					get_max_endpoint(usbdev,
1229							 &interface->altsetting[i],
1230							 "ISOC IN", e,
1231							 &dev->isoc_in);
1232				} else {
1233					get_max_endpoint(usbdev,
1234							 &interface->altsetting[i],
1235							 "ISOC OUT", e,
1236							 &dev->isoc_out);
1237				}
1238				break;
1239			case USB_ENDPOINT_XFER_INT:
1240				if (!dir_out) {
1241					get_max_endpoint(usbdev,
1242							&interface->altsetting[i],
1243							"INT IN", e,
1244							&dev->int_in);
1245				} else {
1246					get_max_endpoint(usbdev,
1247							&interface->altsetting[i],
1248							"INT OUT", e,
1249							&dev->int_out);
1250				}
1251				break;
1252			}
1253		}
1254	}
1255
1256
1257	printk(KERN_INFO "tm6000: New video device @ %s Mbps (%04x:%04x, ifnum %d)\n",
1258		speed,
1259		le16_to_cpu(dev->udev->descriptor.idVendor),
1260		le16_to_cpu(dev->udev->descriptor.idProduct),
1261		interface->altsetting->desc.bInterfaceNumber);
1262
1263/* check if the the device has the iso in endpoint at the correct place */
1264	if (!dev->isoc_in.endp) {
1265		printk(KERN_ERR "tm6000: probing error: no IN ISOC endpoint!\n");
1266		rc = -ENODEV;
1267
1268		goto err;
1269	}
1270
1271	/* save our data pointer in this interface device */
1272	usb_set_intfdata(interface, dev);
1273
1274	printk(KERN_INFO "tm6000: Found %s\n", tm6000_boards[dev->model].name);
1275
1276	rc = tm6000_init_dev(dev);
1277
1278	if (rc < 0)
1279		goto err;
1280
1281	return 0;
1282
1283err:
1284	printk(KERN_ERR "tm6000: Error %d while registering\n", rc);
1285
1286	tm6000_devused &= ~(1<<nr);
1287	usb_put_dev(usbdev);
1288
1289	kfree(dev);
1290	return rc;
1291}
1292
1293/*
1294 * tm6000_usb_disconnect()
1295 * called when the device gets diconencted
1296 * video device will be unregistered on v4l2_close in case it is still open
1297 */
1298static void tm6000_usb_disconnect(struct usb_interface *interface)
1299{
1300	struct tm6000_core *dev = usb_get_intfdata(interface);
1301	usb_set_intfdata(interface, NULL);
1302
1303	if (!dev)
1304		return;
1305
1306	printk(KERN_INFO "tm6000: disconnecting %s\n", dev->name);
1307
1308	tm6000_ir_fini(dev);
1309
1310	if (dev->gpio.power_led) {
1311		switch (dev->model) {
1312		case TM6010_BOARD_HAUPPAUGE_900H:
1313		case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
1314		case TM6010_BOARD_TWINHAN_TU501:
1315			/* Power led off */
1316			tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
1317				dev->gpio.power_led, 0x01);
1318			msleep(15);
1319			break;
1320		case TM6010_BOARD_BEHOLD_WANDER:
1321		case TM6010_BOARD_BEHOLD_VOYAGER:
1322		case TM6010_BOARD_BEHOLD_WANDER_LITE:
1323		case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
1324			/* Power led off */
1325			tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
1326				dev->gpio.power_led, 0x00);
1327			msleep(15);
1328			break;
1329		}
1330	}
1331	tm6000_v4l2_unregister(dev);
1332
1333	tm6000_i2c_unregister(dev);
1334
1335	v4l2_device_unregister(&dev->v4l2_dev);
1336
1337	dev->state |= DEV_DISCONNECTED;
1338
1339	usb_put_dev(dev->udev);
1340
1341	tm6000_close_extension(dev);
1342	tm6000_remove_from_devlist(dev);
1343
1344	kfree(dev);
1345}
1346
1347static struct usb_driver tm6000_usb_driver = {
1348		.name = "tm6000",
1349		.probe = tm6000_usb_probe,
1350		.disconnect = tm6000_usb_disconnect,
1351		.id_table = tm6000_id_table,
1352};
1353
1354static int __init tm6000_module_init(void)
1355{
1356	int result;
1357
1358	printk(KERN_INFO "tm6000" " v4l2 driver version %d.%d.%d loaded\n",
1359	       (TM6000_VERSION  >> 16) & 0xff,
1360	       (TM6000_VERSION  >> 8) & 0xff, TM6000_VERSION  & 0xff);
1361
1362	/* register this driver with the USB subsystem */
1363	result = usb_register(&tm6000_usb_driver);
1364	if (result)
1365		printk(KERN_ERR "tm6000"
1366			   " usb_register failed. Error number %d.\n", result);
1367
1368	return result;
1369}
1370
1371static void __exit tm6000_module_exit(void)
1372{
1373	/* deregister at USB subsystem */
1374	usb_deregister(&tm6000_usb_driver);
1375}
1376
1377module_init(tm6000_module_init);
1378module_exit(tm6000_module_exit);
1379
1380MODULE_DESCRIPTION("Trident TVMaster TM5600/TM6000/TM6010 USB2 adapter");
1381MODULE_AUTHOR("Mauro Carvalho Chehab");
1382MODULE_LICENSE("GPL");