tm6000-cards.c 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402
  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. .caps = {
  340. .has_tuner = 1,
  341. .has_dvb = 1,
  342. .has_zl10353 = 1,
  343. .has_eeprom = 1,
  344. .has_remote = 1,
  345. },
  346. .gpio = {
  347. .tuner_reset = TM6010_GPIO_2,
  348. .tuner_on = TM6010_GPIO_3,
  349. .demod_reset = TM6010_GPIO_1,
  350. .demod_on = TM6010_GPIO_4,
  351. .power_led = TM6010_GPIO_7,
  352. .dvb_led = TM6010_GPIO_5,
  353. .ir = TM6010_GPIO_0,
  354. },
  355. .vinput = { {
  356. .type = TM6000_INPUT_TV,
  357. .vmux = TM6000_VMUX_VIDEO_B,
  358. .amux = TM6000_AMUX_SIF1,
  359. }, {
  360. .type = TM6000_INPUT_COMPOSITE1,
  361. .vmux = TM6000_VMUX_VIDEO_A,
  362. .amux = TM6000_AMUX_ADC2,
  363. }, {
  364. .type = TM6000_INPUT_SVIDEO,
  365. .vmux = TM6000_VMUX_VIDEO_AB,
  366. .amux = TM6000_AMUX_ADC2,
  367. },
  368. },
  369. },
  370. [TM6010_BOARD_BEHOLD_WANDER] = {
  371. .name = "Beholder Wander DVB-T/TV/FM USB2.0",
  372. .tuner_type = TUNER_XC5000,
  373. .tuner_addr = 0xc2 >> 1,
  374. .demod_addr = 0x1e >> 1,
  375. .type = TM6010,
  376. .caps = {
  377. .has_tuner = 1,
  378. .has_dvb = 1,
  379. .has_zl10353 = 1,
  380. .has_eeprom = 1,
  381. .has_remote = 1,
  382. .has_radio = 1,
  383. },
  384. .gpio = {
  385. .tuner_reset = TM6010_GPIO_0,
  386. .demod_reset = TM6010_GPIO_1,
  387. .power_led = TM6010_GPIO_6,
  388. },
  389. .vinput = { {
  390. .type = TM6000_INPUT_TV,
  391. .vmux = TM6000_VMUX_VIDEO_B,
  392. .amux = TM6000_AMUX_SIF1,
  393. }, {
  394. .type = TM6000_INPUT_COMPOSITE1,
  395. .vmux = TM6000_VMUX_VIDEO_A,
  396. .amux = TM6000_AMUX_ADC2,
  397. }, {
  398. .type = TM6000_INPUT_SVIDEO,
  399. .vmux = TM6000_VMUX_VIDEO_AB,
  400. .amux = TM6000_AMUX_ADC2,
  401. },
  402. },
  403. .rinput = {
  404. .type = TM6000_INPUT_RADIO,
  405. .amux = TM6000_AMUX_ADC1,
  406. },
  407. },
  408. [TM6010_BOARD_BEHOLD_VOYAGER] = {
  409. .name = "Beholder Voyager TV/FM USB2.0",
  410. .tuner_type = TUNER_XC5000,
  411. .tuner_addr = 0xc2 >> 1,
  412. .type = TM6010,
  413. .caps = {
  414. .has_tuner = 1,
  415. .has_dvb = 0,
  416. .has_zl10353 = 0,
  417. .has_eeprom = 1,
  418. .has_remote = 1,
  419. .has_radio = 1,
  420. },
  421. .gpio = {
  422. .tuner_reset = TM6010_GPIO_0,
  423. .power_led = TM6010_GPIO_6,
  424. },
  425. .vinput = { {
  426. .type = TM6000_INPUT_TV,
  427. .vmux = TM6000_VMUX_VIDEO_B,
  428. .amux = TM6000_AMUX_SIF1,
  429. }, {
  430. .type = TM6000_INPUT_COMPOSITE1,
  431. .vmux = TM6000_VMUX_VIDEO_A,
  432. .amux = TM6000_AMUX_ADC2,
  433. }, {
  434. .type = TM6000_INPUT_SVIDEO,
  435. .vmux = TM6000_VMUX_VIDEO_AB,
  436. .amux = TM6000_AMUX_ADC2,
  437. },
  438. },
  439. .rinput = {
  440. .type = TM6000_INPUT_RADIO,
  441. .amux = TM6000_AMUX_ADC1,
  442. },
  443. },
  444. [TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE] = {
  445. .name = "Terratec Cinergy Hybrid XE / Cinergy Hybrid-Stick",
  446. .tuner_type = TUNER_XC2028, /* has a XC3028 */
  447. .tuner_addr = 0xc2 >> 1,
  448. .demod_addr = 0x1e >> 1,
  449. .type = TM6010,
  450. .caps = {
  451. .has_tuner = 1,
  452. .has_dvb = 1,
  453. .has_zl10353 = 1,
  454. .has_eeprom = 1,
  455. .has_remote = 1,
  456. .has_radio = 1,
  457. },
  458. .gpio = {
  459. .tuner_reset = TM6010_GPIO_2,
  460. .tuner_on = TM6010_GPIO_3,
  461. .demod_reset = TM6010_GPIO_1,
  462. .demod_on = TM6010_GPIO_4,
  463. .power_led = TM6010_GPIO_7,
  464. .dvb_led = TM6010_GPIO_5,
  465. .ir = TM6010_GPIO_0,
  466. },
  467. .ir_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS,
  468. .vinput = { {
  469. .type = TM6000_INPUT_TV,
  470. .vmux = TM6000_VMUX_VIDEO_B,
  471. .amux = TM6000_AMUX_SIF1,
  472. }, {
  473. .type = TM6000_INPUT_COMPOSITE1,
  474. .vmux = TM6000_VMUX_VIDEO_A,
  475. .amux = TM6000_AMUX_ADC2,
  476. }, {
  477. .type = TM6000_INPUT_SVIDEO,
  478. .vmux = TM6000_VMUX_VIDEO_AB,
  479. .amux = TM6000_AMUX_ADC2,
  480. },
  481. },
  482. .rinput = {
  483. .type = TM6000_INPUT_RADIO,
  484. .amux = TM6000_AMUX_SIF1,
  485. },
  486. },
  487. [TM5600_BOARD_TERRATEC_GRABSTER] = {
  488. .name = "Terratec Grabster AV 150/250 MX",
  489. .type = TM5600,
  490. .tuner_type = TUNER_ABSENT,
  491. .vinput = { {
  492. .type = TM6000_INPUT_TV,
  493. .vmux = TM6000_VMUX_VIDEO_B,
  494. .amux = TM6000_AMUX_ADC1,
  495. }, {
  496. .type = TM6000_INPUT_COMPOSITE1,
  497. .vmux = TM6000_VMUX_VIDEO_A,
  498. .amux = TM6000_AMUX_ADC2,
  499. }, {
  500. .type = TM6000_INPUT_SVIDEO,
  501. .vmux = TM6000_VMUX_VIDEO_AB,
  502. .amux = TM6000_AMUX_ADC2,
  503. },
  504. },
  505. },
  506. [TM6010_BOARD_TWINHAN_TU501] = {
  507. .name = "Twinhan TU501(704D1)",
  508. .tuner_type = TUNER_XC2028, /* has a XC3028 */
  509. .tuner_addr = 0xc2 >> 1,
  510. .demod_addr = 0x1e >> 1,
  511. .type = TM6010,
  512. .caps = {
  513. .has_tuner = 1,
  514. .has_dvb = 1,
  515. .has_zl10353 = 1,
  516. .has_eeprom = 1,
  517. .has_remote = 1,
  518. },
  519. .gpio = {
  520. .tuner_reset = TM6010_GPIO_2,
  521. .tuner_on = TM6010_GPIO_3,
  522. .demod_reset = TM6010_GPIO_1,
  523. .demod_on = TM6010_GPIO_4,
  524. .power_led = TM6010_GPIO_7,
  525. .dvb_led = TM6010_GPIO_5,
  526. .ir = TM6010_GPIO_0,
  527. },
  528. .vinput = { {
  529. .type = TM6000_INPUT_TV,
  530. .vmux = TM6000_VMUX_VIDEO_B,
  531. .amux = TM6000_AMUX_SIF1,
  532. }, {
  533. .type = TM6000_INPUT_COMPOSITE1,
  534. .vmux = TM6000_VMUX_VIDEO_A,
  535. .amux = TM6000_AMUX_ADC2,
  536. }, {
  537. .type = TM6000_INPUT_SVIDEO,
  538. .vmux = TM6000_VMUX_VIDEO_AB,
  539. .amux = TM6000_AMUX_ADC2,
  540. },
  541. },
  542. },
  543. [TM6010_BOARD_BEHOLD_WANDER_LITE] = {
  544. .name = "Beholder Wander Lite DVB-T/TV/FM USB2.0",
  545. .tuner_type = TUNER_XC5000,
  546. .tuner_addr = 0xc2 >> 1,
  547. .demod_addr = 0x1e >> 1,
  548. .type = TM6010,
  549. .caps = {
  550. .has_tuner = 1,
  551. .has_dvb = 1,
  552. .has_zl10353 = 1,
  553. .has_eeprom = 1,
  554. .has_remote = 0,
  555. .has_radio = 1,
  556. },
  557. .gpio = {
  558. .tuner_reset = TM6010_GPIO_0,
  559. .demod_reset = TM6010_GPIO_1,
  560. .power_led = TM6010_GPIO_6,
  561. },
  562. .vinput = { {
  563. .type = TM6000_INPUT_TV,
  564. .vmux = TM6000_VMUX_VIDEO_B,
  565. .amux = TM6000_AMUX_SIF1,
  566. },
  567. },
  568. .rinput = {
  569. .type = TM6000_INPUT_RADIO,
  570. .amux = TM6000_AMUX_ADC1,
  571. },
  572. },
  573. [TM6010_BOARD_BEHOLD_VOYAGER_LITE] = {
  574. .name = "Beholder Voyager Lite TV/FM USB2.0",
  575. .tuner_type = TUNER_XC5000,
  576. .tuner_addr = 0xc2 >> 1,
  577. .type = TM6010,
  578. .caps = {
  579. .has_tuner = 1,
  580. .has_dvb = 0,
  581. .has_zl10353 = 0,
  582. .has_eeprom = 1,
  583. .has_remote = 0,
  584. .has_radio = 1,
  585. },
  586. .gpio = {
  587. .tuner_reset = TM6010_GPIO_0,
  588. .power_led = TM6010_GPIO_6,
  589. },
  590. .vinput = { {
  591. .type = TM6000_INPUT_TV,
  592. .vmux = TM6000_VMUX_VIDEO_B,
  593. .amux = TM6000_AMUX_SIF1,
  594. },
  595. },
  596. .rinput = {
  597. .type = TM6000_INPUT_RADIO,
  598. .amux = TM6000_AMUX_ADC1,
  599. },
  600. },
  601. };
  602. /* table of devices that work with this driver */
  603. static struct usb_device_id tm6000_id_table[] = {
  604. { USB_DEVICE(0x6000, 0x0001), .driver_info = TM5600_BOARD_GENERIC },
  605. { USB_DEVICE(0x6000, 0x0002), .driver_info = TM6010_BOARD_GENERIC },
  606. { USB_DEVICE(0x06e1, 0xf332), .driver_info = TM6000_BOARD_ADSTECH_DUAL_TV },
  607. { USB_DEVICE(0x14aa, 0x0620), .driver_info = TM6000_BOARD_FREECOM_AND_SIMILAR },
  608. { USB_DEVICE(0x06e1, 0xb339), .driver_info = TM6000_BOARD_ADSTECH_MINI_DUAL_TV },
  609. { USB_DEVICE(0x2040, 0x6600), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
  610. { USB_DEVICE(0x2040, 0x6601), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
  611. { USB_DEVICE(0x2040, 0x6610), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
  612. { USB_DEVICE(0x2040, 0x6611), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
  613. { USB_DEVICE(0x6000, 0xdec0), .driver_info = TM6010_BOARD_BEHOLD_WANDER },
  614. { USB_DEVICE(0x6000, 0xdec1), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER },
  615. { USB_DEVICE(0x0ccd, 0x0086), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE },
  616. { USB_DEVICE(0x0ccd, 0x00A5), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE },
  617. { USB_DEVICE(0x0ccd, 0x0079), .driver_info = TM5600_BOARD_TERRATEC_GRABSTER },
  618. { USB_DEVICE(0x13d3, 0x3240), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
  619. { USB_DEVICE(0x13d3, 0x3241), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
  620. { USB_DEVICE(0x13d3, 0x3243), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
  621. { USB_DEVICE(0x13d3, 0x3264), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
  622. { USB_DEVICE(0x6000, 0xdec2), .driver_info = TM6010_BOARD_BEHOLD_WANDER_LITE },
  623. { USB_DEVICE(0x6000, 0xdec3), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER_LITE },
  624. { }
  625. };
  626. /* Control power led for show some activity */
  627. void tm6000_flash_led(struct tm6000_core *dev, u8 state)
  628. {
  629. /* Power LED unconfigured */
  630. if (!dev->gpio.power_led)
  631. return;
  632. /* ON Power LED */
  633. if (state) {
  634. switch (dev->model) {
  635. case TM6010_BOARD_HAUPPAUGE_900H:
  636. case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
  637. case TM6010_BOARD_TWINHAN_TU501:
  638. tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
  639. dev->gpio.power_led, 0x00);
  640. break;
  641. case TM6010_BOARD_BEHOLD_WANDER:
  642. case TM6010_BOARD_BEHOLD_VOYAGER:
  643. case TM6010_BOARD_BEHOLD_WANDER_LITE:
  644. case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
  645. tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
  646. dev->gpio.power_led, 0x01);
  647. break;
  648. }
  649. }
  650. /* OFF Power LED */
  651. else {
  652. switch (dev->model) {
  653. case TM6010_BOARD_HAUPPAUGE_900H:
  654. case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
  655. case TM6010_BOARD_TWINHAN_TU501:
  656. tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
  657. dev->gpio.power_led, 0x01);
  658. break;
  659. case TM6010_BOARD_BEHOLD_WANDER:
  660. case TM6010_BOARD_BEHOLD_VOYAGER:
  661. case TM6010_BOARD_BEHOLD_WANDER_LITE:
  662. case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
  663. tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
  664. dev->gpio.power_led, 0x00);
  665. break;
  666. }
  667. }
  668. }
  669. /* Tuner callback to provide the proper gpio changes needed for xc5000 */
  670. int tm6000_xc5000_callback(void *ptr, int component, int command, int arg)
  671. {
  672. int rc = 0;
  673. struct tm6000_core *dev = ptr;
  674. if (dev->tuner_type != TUNER_XC5000)
  675. return 0;
  676. switch (command) {
  677. case XC5000_TUNER_RESET:
  678. tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
  679. dev->gpio.tuner_reset, 0x01);
  680. msleep(15);
  681. tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
  682. dev->gpio.tuner_reset, 0x00);
  683. msleep(15);
  684. tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
  685. dev->gpio.tuner_reset, 0x01);
  686. break;
  687. }
  688. return rc;
  689. }
  690. EXPORT_SYMBOL_GPL(tm6000_xc5000_callback);
  691. /* Tuner callback to provide the proper gpio changes needed for xc2028 */
  692. int tm6000_tuner_callback(void *ptr, int component, int command, int arg)
  693. {
  694. int rc = 0;
  695. struct tm6000_core *dev = ptr;
  696. if (dev->tuner_type != TUNER_XC2028)
  697. return 0;
  698. switch (command) {
  699. case XC2028_RESET_CLK:
  700. tm6000_ir_wait(dev, 0);
  701. tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT,
  702. 0x02, arg);
  703. msleep(10);
  704. rc = tm6000_i2c_reset(dev, 10);
  705. break;
  706. case XC2028_TUNER_RESET:
  707. /* Reset codes during load firmware */
  708. switch (arg) {
  709. case 0:
  710. /* newer tuner can faster reset */
  711. switch (dev->model) {
  712. case TM5600_BOARD_10MOONS_UT821:
  713. tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
  714. dev->gpio.tuner_reset, 0x01);
  715. tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
  716. 0x300, 0x01);
  717. msleep(10);
  718. tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
  719. dev->gpio.tuner_reset, 0x00);
  720. tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
  721. 0x300, 0x00);
  722. msleep(10);
  723. tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
  724. dev->gpio.tuner_reset, 0x01);
  725. tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
  726. 0x300, 0x01);
  727. break;
  728. case TM6010_BOARD_HAUPPAUGE_900H:
  729. case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
  730. case TM6010_BOARD_TWINHAN_TU501:
  731. tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
  732. dev->gpio.tuner_reset, 0x01);
  733. msleep(60);
  734. tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
  735. dev->gpio.tuner_reset, 0x00);
  736. msleep(75);
  737. tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
  738. dev->gpio.tuner_reset, 0x01);
  739. msleep(60);
  740. break;
  741. default:
  742. tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
  743. dev->gpio.tuner_reset, 0x00);
  744. msleep(130);
  745. tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
  746. dev->gpio.tuner_reset, 0x01);
  747. msleep(130);
  748. break;
  749. }
  750. tm6000_ir_wait(dev, 1);
  751. break;
  752. case 1:
  753. tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT,
  754. 0x02, 0x01);
  755. msleep(10);
  756. break;
  757. case 2:
  758. rc = tm6000_i2c_reset(dev, 100);
  759. break;
  760. }
  761. break;
  762. case XC2028_I2C_FLUSH:
  763. tm6000_set_reg(dev, REQ_50_SET_START, 0, 0);
  764. tm6000_set_reg(dev, REQ_51_SET_STOP, 0, 0);
  765. break;
  766. }
  767. return rc;
  768. }
  769. EXPORT_SYMBOL_GPL(tm6000_tuner_callback);
  770. int tm6000_cards_setup(struct tm6000_core *dev)
  771. {
  772. /*
  773. * Board-specific initialization sequence. Handles all GPIO
  774. * initialization sequences that are board-specific.
  775. * Up to now, all found devices use GPIO1 and GPIO4 at the same way.
  776. * Probably, they're all based on some reference device. Due to that,
  777. * there's a common routine at the end to handle those GPIO's. Devices
  778. * that use different pinups or init sequences can just return at
  779. * the board-specific session.
  780. */
  781. switch (dev->model) {
  782. case TM6010_BOARD_HAUPPAUGE_900H:
  783. case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
  784. case TM6010_BOARD_TWINHAN_TU501:
  785. case TM6010_BOARD_GENERIC:
  786. /* Turn xceive 3028 on */
  787. tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.tuner_on, 0x01);
  788. msleep(15);
  789. /* Turn zarlink zl10353 on */
  790. tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x00);
  791. msleep(15);
  792. /* Reset zarlink zl10353 */
  793. tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x00);
  794. msleep(50);
  795. tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x01);
  796. msleep(15);
  797. /* Turn zarlink zl10353 off */
  798. tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x01);
  799. msleep(15);
  800. /* ir ? */
  801. tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.ir, 0x01);
  802. msleep(15);
  803. /* Power led on (blue) */
  804. tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x00);
  805. msleep(15);
  806. /* DVB led off (orange) */
  807. tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.dvb_led, 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. break;
  813. case TM6010_BOARD_BEHOLD_WANDER:
  814. case TM6010_BOARD_BEHOLD_WANDER_LITE:
  815. /* Power led on (blue) */
  816. tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01);
  817. msleep(15);
  818. /* Reset zarlink zl10353 */
  819. tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x00);
  820. msleep(50);
  821. tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x01);
  822. msleep(15);
  823. break;
  824. case TM6010_BOARD_BEHOLD_VOYAGER:
  825. case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
  826. /* Power led on (blue) */
  827. tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01);
  828. msleep(15);
  829. break;
  830. default:
  831. break;
  832. }
  833. /*
  834. * Default initialization. Most of the devices seem to use GPIO1
  835. * and GPIO4.on the same way, so, this handles the common sequence
  836. * used by most devices.
  837. * If a device uses a different sequence or different GPIO pins for
  838. * reset, just add the code at the board-specific part
  839. */
  840. if (dev->gpio.tuner_reset) {
  841. int rc;
  842. int i;
  843. for (i = 0; i < 2; i++) {
  844. rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
  845. dev->gpio.tuner_reset, 0x00);
  846. if (rc < 0) {
  847. printk(KERN_ERR "Error %i doing tuner reset\n", rc);
  848. return rc;
  849. }
  850. msleep(10); /* Just to be conservative */
  851. rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
  852. dev->gpio.tuner_reset, 0x01);
  853. if (rc < 0) {
  854. printk(KERN_ERR "Error %i doing tuner reset\n", rc);
  855. return rc;
  856. }
  857. }
  858. } else {
  859. printk(KERN_ERR "Tuner reset is not configured\n");
  860. return -1;
  861. }
  862. msleep(50);
  863. return 0;
  864. };
  865. static void tm6000_config_tuner(struct tm6000_core *dev)
  866. {
  867. struct tuner_setup tun_setup;
  868. /* Load tuner module */
  869. v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
  870. "tuner", dev->tuner_addr, NULL);
  871. memset(&tun_setup, 0, sizeof(tun_setup));
  872. tun_setup.type = dev->tuner_type;
  873. tun_setup.addr = dev->tuner_addr;
  874. tun_setup.mode_mask = 0;
  875. if (dev->caps.has_tuner)
  876. tun_setup.mode_mask |= (T_ANALOG_TV | T_RADIO);
  877. switch (dev->tuner_type) {
  878. case TUNER_XC2028:
  879. tun_setup.tuner_callback = tm6000_tuner_callback;
  880. break;
  881. case TUNER_XC5000:
  882. tun_setup.tuner_callback = tm6000_xc5000_callback;
  883. break;
  884. }
  885. v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup);
  886. switch (dev->tuner_type) {
  887. case TUNER_XC2028: {
  888. struct v4l2_priv_tun_config xc2028_cfg;
  889. struct xc2028_ctrl ctl;
  890. memset(&xc2028_cfg, 0, sizeof(xc2028_cfg));
  891. memset(&ctl, 0, sizeof(ctl));
  892. ctl.demod = XC3028_FE_ZARLINK456;
  893. xc2028_cfg.tuner = TUNER_XC2028;
  894. xc2028_cfg.priv = &ctl;
  895. switch (dev->model) {
  896. case TM6010_BOARD_HAUPPAUGE_900H:
  897. case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
  898. case TM6010_BOARD_TWINHAN_TU501:
  899. ctl.fname = "xc3028L-v36.fw";
  900. break;
  901. default:
  902. if (dev->dev_type == TM6010)
  903. ctl.fname = "xc3028-v27.fw";
  904. else
  905. ctl.fname = "xc3028-v24.fw";
  906. }
  907. printk(KERN_INFO "Setting firmware parameters for xc2028\n");
  908. v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config,
  909. &xc2028_cfg);
  910. }
  911. break;
  912. case TUNER_XC5000:
  913. {
  914. struct v4l2_priv_tun_config xc5000_cfg;
  915. struct xc5000_config ctl = {
  916. .i2c_address = dev->tuner_addr,
  917. .if_khz = 4570,
  918. .radio_input = XC5000_RADIO_FM1_MONO,
  919. };
  920. xc5000_cfg.tuner = TUNER_XC5000;
  921. xc5000_cfg.priv = &ctl;
  922. v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config,
  923. &xc5000_cfg);
  924. }
  925. break;
  926. default:
  927. printk(KERN_INFO "Unknown tuner type. Tuner is not configured.\n");
  928. break;
  929. }
  930. }
  931. static int fill_board_specific_data(struct tm6000_core *dev)
  932. {
  933. int rc;
  934. dev->dev_type = tm6000_boards[dev->model].type;
  935. dev->tuner_type = tm6000_boards[dev->model].tuner_type;
  936. dev->tuner_addr = tm6000_boards[dev->model].tuner_addr;
  937. dev->gpio = tm6000_boards[dev->model].gpio;
  938. dev->ir_codes = tm6000_boards[dev->model].ir_codes;
  939. dev->demod_addr = tm6000_boards[dev->model].demod_addr;
  940. dev->caps = tm6000_boards[dev->model].caps;
  941. dev->vinput[0] = tm6000_boards[dev->model].vinput[0];
  942. dev->vinput[1] = tm6000_boards[dev->model].vinput[1];
  943. dev->vinput[2] = tm6000_boards[dev->model].vinput[2];
  944. dev->rinput = tm6000_boards[dev->model].rinput;
  945. /* setup per-model quirks */
  946. switch (dev->model) {
  947. case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
  948. dev->quirks |= TM6000_QUIRK_NO_USB_DELAY;
  949. break;
  950. default:
  951. break;
  952. }
  953. /* initialize hardware */
  954. rc = tm6000_init(dev);
  955. if (rc < 0)
  956. return rc;
  957. return v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev);
  958. }
  959. static void use_alternative_detection_method(struct tm6000_core *dev)
  960. {
  961. int i, model = -1;
  962. if (!dev->eedata_size)
  963. return;
  964. for (i = 0; i < ARRAY_SIZE(tm6000_boards); i++) {
  965. if (!tm6000_boards[i].eename_size)
  966. continue;
  967. if (dev->eedata_size < tm6000_boards[i].eename_pos +
  968. tm6000_boards[i].eename_size)
  969. continue;
  970. if (!memcmp(&dev->eedata[tm6000_boards[i].eename_pos],
  971. tm6000_boards[i].eename,
  972. tm6000_boards[i].eename_size)) {
  973. model = i;
  974. break;
  975. }
  976. }
  977. if (model < 0) {
  978. printk(KERN_INFO "Device has eeprom but is currently unknown\n");
  979. return;
  980. }
  981. dev->model = model;
  982. printk(KERN_INFO "Device identified via eeprom as %s (type = %d)\n",
  983. tm6000_boards[model].name, model);
  984. }
  985. static int tm6000_init_dev(struct tm6000_core *dev)
  986. {
  987. struct v4l2_frequency f;
  988. int rc = 0;
  989. mutex_init(&dev->lock);
  990. mutex_lock(&dev->lock);
  991. if (!is_generic(dev->model)) {
  992. rc = fill_board_specific_data(dev);
  993. if (rc < 0)
  994. goto err;
  995. /* register i2c bus */
  996. rc = tm6000_i2c_register(dev);
  997. if (rc < 0)
  998. goto err;
  999. } else {
  1000. /* register i2c bus */
  1001. rc = tm6000_i2c_register(dev);
  1002. if (rc < 0)
  1003. goto err;
  1004. use_alternative_detection_method(dev);
  1005. rc = fill_board_specific_data(dev);
  1006. if (rc < 0)
  1007. goto err;
  1008. }
  1009. /* Default values for STD and resolutions */
  1010. dev->width = 720;
  1011. dev->height = 480;
  1012. dev->norm = V4L2_STD_PAL_M;
  1013. /* Configure tuner */
  1014. tm6000_config_tuner(dev);
  1015. /* Set video standard */
  1016. v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
  1017. /* Set tuner frequency - also loads firmware on xc2028/xc3028 */
  1018. f.tuner = 0;
  1019. f.type = V4L2_TUNER_ANALOG_TV;
  1020. f.frequency = 3092; /* 193.25 MHz */
  1021. dev->freq = f.frequency;
  1022. v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
  1023. if (dev->caps.has_tda9874)
  1024. v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
  1025. "tvaudio", I2C_ADDR_TDA9874, NULL);
  1026. /* register and initialize V4L2 */
  1027. rc = tm6000_v4l2_register(dev);
  1028. if (rc < 0)
  1029. goto err;
  1030. tm6000_add_into_devlist(dev);
  1031. tm6000_init_extension(dev);
  1032. tm6000_ir_init(dev);
  1033. mutex_unlock(&dev->lock);
  1034. return 0;
  1035. err:
  1036. mutex_unlock(&dev->lock);
  1037. return rc;
  1038. }
  1039. /* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
  1040. #define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
  1041. static void get_max_endpoint(struct usb_device *udev,
  1042. struct usb_host_interface *alt,
  1043. char *msgtype,
  1044. struct usb_host_endpoint *curr_e,
  1045. struct tm6000_endpoint *tm_ep)
  1046. {
  1047. u16 tmp = le16_to_cpu(curr_e->desc.wMaxPacketSize);
  1048. unsigned int size = tmp & 0x7ff;
  1049. if (udev->speed == USB_SPEED_HIGH)
  1050. size = size * hb_mult(tmp);
  1051. if (size > tm_ep->maxsize) {
  1052. tm_ep->endp = curr_e;
  1053. tm_ep->maxsize = size;
  1054. tm_ep->bInterfaceNumber = alt->desc.bInterfaceNumber;
  1055. tm_ep->bAlternateSetting = alt->desc.bAlternateSetting;
  1056. printk(KERN_INFO "tm6000: %s endpoint: 0x%02x (max size=%u bytes)\n",
  1057. msgtype, curr_e->desc.bEndpointAddress,
  1058. size);
  1059. }
  1060. }
  1061. /*
  1062. * tm6000_usb_probe()
  1063. * checks for supported devices
  1064. */
  1065. static int tm6000_usb_probe(struct usb_interface *interface,
  1066. const struct usb_device_id *id)
  1067. {
  1068. struct usb_device *usbdev;
  1069. struct tm6000_core *dev = NULL;
  1070. int i, rc = 0;
  1071. int nr = 0;
  1072. char *speed;
  1073. usbdev = usb_get_dev(interface_to_usbdev(interface));
  1074. /* Selects the proper interface */
  1075. rc = usb_set_interface(usbdev, 0, 1);
  1076. if (rc < 0)
  1077. goto err;
  1078. /* Check to see next free device and mark as used */
  1079. nr = find_first_zero_bit(&tm6000_devused, TM6000_MAXBOARDS);
  1080. if (nr >= TM6000_MAXBOARDS) {
  1081. printk(KERN_ERR "tm6000: Supports only %i tm60xx boards.\n", TM6000_MAXBOARDS);
  1082. usb_put_dev(usbdev);
  1083. return -ENOMEM;
  1084. }
  1085. /* Create and initialize dev struct */
  1086. dev = kzalloc(sizeof(*dev), GFP_KERNEL);
  1087. if (dev == NULL) {
  1088. printk(KERN_ERR "tm6000" ": out of memory!\n");
  1089. usb_put_dev(usbdev);
  1090. return -ENOMEM;
  1091. }
  1092. spin_lock_init(&dev->slock);
  1093. mutex_init(&dev->usb_lock);
  1094. /* Increment usage count */
  1095. set_bit(nr, &tm6000_devused);
  1096. snprintf(dev->name, 29, "tm6000 #%d", nr);
  1097. dev->model = id->driver_info;
  1098. if (card[nr] < ARRAY_SIZE(tm6000_boards))
  1099. dev->model = card[nr];
  1100. dev->udev = usbdev;
  1101. dev->devno = nr;
  1102. switch (usbdev->speed) {
  1103. case USB_SPEED_LOW:
  1104. speed = "1.5";
  1105. break;
  1106. case USB_SPEED_UNKNOWN:
  1107. case USB_SPEED_FULL:
  1108. speed = "12";
  1109. break;
  1110. case USB_SPEED_HIGH:
  1111. speed = "480";
  1112. break;
  1113. default:
  1114. speed = "unknown";
  1115. }
  1116. /* Get endpoints */
  1117. for (i = 0; i < interface->num_altsetting; i++) {
  1118. int ep;
  1119. for (ep = 0; ep < interface->altsetting[i].desc.bNumEndpoints; ep++) {
  1120. struct usb_host_endpoint *e;
  1121. int dir_out;
  1122. e = &interface->altsetting[i].endpoint[ep];
  1123. dir_out = ((e->desc.bEndpointAddress &
  1124. USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT);
  1125. printk(KERN_INFO "tm6000: alt %d, interface %i, class %i\n",
  1126. i,
  1127. interface->altsetting[i].desc.bInterfaceNumber,
  1128. interface->altsetting[i].desc.bInterfaceClass);
  1129. switch (e->desc.bmAttributes) {
  1130. case USB_ENDPOINT_XFER_BULK:
  1131. if (!dir_out) {
  1132. get_max_endpoint(usbdev,
  1133. &interface->altsetting[i],
  1134. "Bulk IN", e,
  1135. &dev->bulk_in);
  1136. } else {
  1137. get_max_endpoint(usbdev,
  1138. &interface->altsetting[i],
  1139. "Bulk OUT", e,
  1140. &dev->bulk_out);
  1141. }
  1142. break;
  1143. case USB_ENDPOINT_XFER_ISOC:
  1144. if (!dir_out) {
  1145. get_max_endpoint(usbdev,
  1146. &interface->altsetting[i],
  1147. "ISOC IN", e,
  1148. &dev->isoc_in);
  1149. } else {
  1150. get_max_endpoint(usbdev,
  1151. &interface->altsetting[i],
  1152. "ISOC OUT", e,
  1153. &dev->isoc_out);
  1154. }
  1155. break;
  1156. case USB_ENDPOINT_XFER_INT:
  1157. if (!dir_out) {
  1158. get_max_endpoint(usbdev,
  1159. &interface->altsetting[i],
  1160. "INT IN", e,
  1161. &dev->int_in);
  1162. } else {
  1163. get_max_endpoint(usbdev,
  1164. &interface->altsetting[i],
  1165. "INT OUT", e,
  1166. &dev->int_out);
  1167. }
  1168. break;
  1169. }
  1170. }
  1171. }
  1172. printk(KERN_INFO "tm6000: New video device @ %s Mbps (%04x:%04x, ifnum %d)\n",
  1173. speed,
  1174. le16_to_cpu(dev->udev->descriptor.idVendor),
  1175. le16_to_cpu(dev->udev->descriptor.idProduct),
  1176. interface->altsetting->desc.bInterfaceNumber);
  1177. /* check if the the device has the iso in endpoint at the correct place */
  1178. if (!dev->isoc_in.endp) {
  1179. printk(KERN_ERR "tm6000: probing error: no IN ISOC endpoint!\n");
  1180. rc = -ENODEV;
  1181. goto err;
  1182. }
  1183. /* save our data pointer in this interface device */
  1184. usb_set_intfdata(interface, dev);
  1185. printk(KERN_INFO "tm6000: Found %s\n", tm6000_boards[dev->model].name);
  1186. rc = tm6000_init_dev(dev);
  1187. if (rc < 0)
  1188. goto err;
  1189. return 0;
  1190. err:
  1191. printk(KERN_ERR "tm6000: Error %d while registering\n", rc);
  1192. clear_bit(nr, &tm6000_devused);
  1193. usb_put_dev(usbdev);
  1194. kfree(dev);
  1195. return rc;
  1196. }
  1197. /*
  1198. * tm6000_usb_disconnect()
  1199. * called when the device gets diconencted
  1200. * video device will be unregistered on v4l2_close in case it is still open
  1201. */
  1202. static void tm6000_usb_disconnect(struct usb_interface *interface)
  1203. {
  1204. struct tm6000_core *dev = usb_get_intfdata(interface);
  1205. usb_set_intfdata(interface, NULL);
  1206. if (!dev)
  1207. return;
  1208. printk(KERN_INFO "tm6000: disconnecting %s\n", dev->name);
  1209. tm6000_ir_fini(dev);
  1210. if (dev->gpio.power_led) {
  1211. switch (dev->model) {
  1212. case TM6010_BOARD_HAUPPAUGE_900H:
  1213. case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
  1214. case TM6010_BOARD_TWINHAN_TU501:
  1215. /* Power led off */
  1216. tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
  1217. dev->gpio.power_led, 0x01);
  1218. msleep(15);
  1219. break;
  1220. case TM6010_BOARD_BEHOLD_WANDER:
  1221. case TM6010_BOARD_BEHOLD_VOYAGER:
  1222. case TM6010_BOARD_BEHOLD_WANDER_LITE:
  1223. case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
  1224. /* Power led off */
  1225. tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
  1226. dev->gpio.power_led, 0x00);
  1227. msleep(15);
  1228. break;
  1229. }
  1230. }
  1231. tm6000_v4l2_unregister(dev);
  1232. tm6000_i2c_unregister(dev);
  1233. v4l2_device_unregister(&dev->v4l2_dev);
  1234. dev->state |= DEV_DISCONNECTED;
  1235. usb_put_dev(dev->udev);
  1236. tm6000_close_extension(dev);
  1237. tm6000_remove_from_devlist(dev);
  1238. clear_bit(dev->devno, &tm6000_devused);
  1239. kfree(dev);
  1240. }
  1241. static struct usb_driver tm6000_usb_driver = {
  1242. .name = "tm6000",
  1243. .probe = tm6000_usb_probe,
  1244. .disconnect = tm6000_usb_disconnect,
  1245. .id_table = tm6000_id_table,
  1246. };
  1247. static int __init tm6000_module_init(void)
  1248. {
  1249. int result;
  1250. printk(KERN_INFO "tm6000" " v4l2 driver version %d.%d.%d loaded\n",
  1251. (TM6000_VERSION >> 16) & 0xff,
  1252. (TM6000_VERSION >> 8) & 0xff, TM6000_VERSION & 0xff);
  1253. /* register this driver with the USB subsystem */
  1254. result = usb_register(&tm6000_usb_driver);
  1255. if (result)
  1256. printk(KERN_ERR "tm6000"
  1257. " usb_register failed. Error number %d.\n", result);
  1258. return result;
  1259. }
  1260. static void __exit tm6000_module_exit(void)
  1261. {
  1262. /* deregister at USB subsystem */
  1263. usb_deregister(&tm6000_usb_driver);
  1264. }
  1265. module_init(tm6000_module_init);
  1266. module_exit(tm6000_module_exit);
  1267. MODULE_DESCRIPTION("Trident TVMaster TM5600/TM6000/TM6010 USB2 adapter");
  1268. MODULE_AUTHOR("Mauro Carvalho Chehab");
  1269. MODULE_LICENSE("GPL");