tm6000-cards.c 35 KB

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