tm6000-cards.c 35 KB

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