tm6000-cards.c 35 KB

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