budget-core.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  1. /*
  2. * budget-core.c: driver for the SAA7146 based Budget DVB cards
  3. *
  4. * Compiled from various sources by Michael Hunold <michael@mihu.de>
  5. *
  6. * Copyright (C) 2002 Ralph Metzler <rjkm@metzlerbros.de>
  7. *
  8. * Copyright (C) 1999-2002 Ralph Metzler
  9. * & Marcus Metzler for convergence integrated media GmbH
  10. *
  11. * 26feb2004 Support for FS Activy Card (Grundig tuner) by
  12. * Michael Dreher <michael@5dot1.de>,
  13. * Oliver Endriss <o.endriss@gmx.de>,
  14. * Andreas 'randy' Weinberger
  15. *
  16. * This program is free software; you can redistribute it and/or
  17. * modify it under the terms of the GNU General Public License
  18. * as published by the Free Software Foundation; either version 2
  19. * of the License, or (at your option) any later version.
  20. *
  21. *
  22. * This program is distributed in the hope that it will be useful,
  23. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  24. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  25. * GNU General Public License for more details.
  26. *
  27. *
  28. * You should have received a copy of the GNU General Public License
  29. * along with this program; if not, write to the Free Software
  30. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  31. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
  32. *
  33. *
  34. * the project's page is at http://www.linuxtv.org/dvb/
  35. */
  36. #include <linux/moduleparam.h>
  37. #include "budget.h"
  38. #include "ttpci-eeprom.h"
  39. int budget_debug;
  40. module_param_named(debug, budget_debug, int, 0644);
  41. MODULE_PARM_DESC(debug, "Turn on/off budget debugging (default:off).");
  42. /****************************************************************************
  43. * TT budget / WinTV Nova
  44. ****************************************************************************/
  45. static int stop_ts_capture(struct budget *budget)
  46. {
  47. dprintk(2, "budget: %p\n", budget);
  48. if (--budget->feeding)
  49. return budget->feeding;
  50. saa7146_write(budget->dev, MC1, MASK_20); // DMA3 off
  51. SAA7146_IER_DISABLE(budget->dev, MASK_10);
  52. return 0;
  53. }
  54. static int start_ts_capture(struct budget *budget)
  55. {
  56. struct saa7146_dev *dev = budget->dev;
  57. dprintk(2, "budget: %p\n", budget);
  58. if (budget->feeding)
  59. return ++budget->feeding;
  60. saa7146_write(dev, MC1, MASK_20); // DMA3 off
  61. memset(budget->grabbing, 0x00, TS_HEIGHT * TS_WIDTH);
  62. saa7146_write(dev, PCI_BT_V1, 0x001c0000 | (saa7146_read(dev, PCI_BT_V1) & ~0x001f0000));
  63. budget->tsf = 0xff;
  64. budget->ttbp = 0;
  65. /*
  66. * Signal path on the Activy:
  67. *
  68. * tuner -> SAA7146 port A -> SAA7146 BRS -> SAA7146 DMA3 -> memory
  69. *
  70. * Since the tuner feeds 204 bytes packets into the SAA7146,
  71. * DMA3 is configured to strip the trailing 16 FEC bytes:
  72. * Pitch: 188, NumBytes3: 188, NumLines3: 1024
  73. */
  74. switch(budget->card->type) {
  75. case BUDGET_FS_ACTIVY:
  76. saa7146_write(dev, DD1_INIT, 0x04000000);
  77. saa7146_write(dev, MC2, (MASK_09 | MASK_25));
  78. saa7146_write(dev, BRS_CTRL, 0x00000000);
  79. break;
  80. case BUDGET_PATCH:
  81. saa7146_write(dev, DD1_INIT, 0x00000200);
  82. saa7146_write(dev, MC2, (MASK_10 | MASK_26));
  83. saa7146_write(dev, BRS_CTRL, 0x60000000);
  84. break;
  85. default:
  86. if (budget->video_port == BUDGET_VIDEO_PORTA) {
  87. saa7146_write(dev, DD1_INIT, 0x06000200);
  88. saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
  89. saa7146_write(dev, BRS_CTRL, 0x00000000);
  90. } else {
  91. saa7146_write(dev, DD1_INIT, 0x02000600);
  92. saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
  93. saa7146_write(dev, BRS_CTRL, 0x60000000);
  94. }
  95. }
  96. saa7146_write(dev, MC2, (MASK_08 | MASK_24));
  97. mdelay(10);
  98. saa7146_write(dev, BASE_ODD3, 0);
  99. saa7146_write(dev, BASE_EVEN3, 0);
  100. saa7146_write(dev, PROT_ADDR3, TS_WIDTH * TS_HEIGHT);
  101. saa7146_write(dev, BASE_PAGE3, budget->pt.dma | ME1 | 0x90);
  102. if (budget->card->type == BUDGET_FS_ACTIVY) {
  103. saa7146_write(dev, PITCH3, TS_WIDTH / 2);
  104. saa7146_write(dev, NUM_LINE_BYTE3, ((TS_HEIGHT * 2) << 16) | (TS_WIDTH / 2));
  105. } else {
  106. saa7146_write(dev, PITCH3, TS_WIDTH);
  107. saa7146_write(dev, NUM_LINE_BYTE3, (TS_HEIGHT << 16) | TS_WIDTH);
  108. }
  109. saa7146_write(dev, MC2, (MASK_04 | MASK_20));
  110. SAA7146_ISR_CLEAR(budget->dev, MASK_10); /* VPE */
  111. SAA7146_IER_ENABLE(budget->dev, MASK_10); /* VPE */
  112. saa7146_write(dev, MC1, (MASK_04 | MASK_20)); /* DMA3 on */
  113. return ++budget->feeding;
  114. }
  115. static void vpeirq(unsigned long data)
  116. {
  117. struct budget *budget = (struct budget *) data;
  118. u8 *mem = (u8 *) (budget->grabbing);
  119. u32 olddma = budget->ttbp;
  120. u32 newdma = saa7146_read(budget->dev, PCI_VDP3);
  121. /* nearest lower position divisible by 188 */
  122. newdma -= newdma % 188;
  123. if (newdma >= TS_BUFLEN)
  124. return;
  125. budget->ttbp = newdma;
  126. if (budget->feeding == 0 || newdma == olddma)
  127. return;
  128. if (newdma > olddma) { /* no wraparound, dump olddma..newdma */
  129. dvb_dmx_swfilter_packets(&budget->demux, mem + olddma, (newdma - olddma) / 188);
  130. } else { /* wraparound, dump olddma..buflen and 0..newdma */
  131. dvb_dmx_swfilter_packets(&budget->demux, mem + olddma, (TS_BUFLEN - olddma) / 188);
  132. dvb_dmx_swfilter_packets(&budget->demux, mem, newdma / 188);
  133. }
  134. }
  135. int ttpci_budget_debiread(struct budget *budget, u32 config, int addr, int count,
  136. int uselocks, int nobusyloop)
  137. {
  138. struct saa7146_dev *saa = budget->dev;
  139. int result = 0;
  140. unsigned long flags = 0;
  141. if (count > 4 || count <= 0)
  142. return 0;
  143. if (uselocks)
  144. spin_lock_irqsave(&budget->debilock, flags);
  145. if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) {
  146. if (uselocks)
  147. spin_unlock_irqrestore(&budget->debilock, flags);
  148. return result;
  149. }
  150. saa7146_write(saa, DEBI_COMMAND, (count << 17) | 0x10000 | (addr & 0xffff));
  151. saa7146_write(saa, DEBI_CONFIG, config);
  152. saa7146_write(saa, DEBI_PAGE, 0);
  153. saa7146_write(saa, MC2, (2 << 16) | 2);
  154. if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) {
  155. if (uselocks)
  156. spin_unlock_irqrestore(&budget->debilock, flags);
  157. return result;
  158. }
  159. result = saa7146_read(saa, DEBI_AD);
  160. result &= (0xffffffffUL >> ((4 - count) * 8));
  161. if (uselocks)
  162. spin_unlock_irqrestore(&budget->debilock, flags);
  163. return result;
  164. }
  165. int ttpci_budget_debiwrite(struct budget *budget, u32 config, int addr,
  166. int count, u32 value, int uselocks, int nobusyloop)
  167. {
  168. struct saa7146_dev *saa = budget->dev;
  169. unsigned long flags = 0;
  170. int result;
  171. if (count > 4 || count <= 0)
  172. return 0;
  173. if (uselocks)
  174. spin_lock_irqsave(&budget->debilock, flags);
  175. if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) {
  176. if (uselocks)
  177. spin_unlock_irqrestore(&budget->debilock, flags);
  178. return result;
  179. }
  180. saa7146_write(saa, DEBI_COMMAND, (count << 17) | 0x00000 | (addr & 0xffff));
  181. saa7146_write(saa, DEBI_CONFIG, config);
  182. saa7146_write(saa, DEBI_PAGE, 0);
  183. saa7146_write(saa, DEBI_AD, value);
  184. saa7146_write(saa, MC2, (2 << 16) | 2);
  185. if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) {
  186. if (uselocks)
  187. spin_unlock_irqrestore(&budget->debilock, flags);
  188. return result;
  189. }
  190. if (uselocks)
  191. spin_unlock_irqrestore(&budget->debilock, flags);
  192. return 0;
  193. }
  194. /****************************************************************************
  195. * DVB API SECTION
  196. ****************************************************************************/
  197. static int budget_start_feed(struct dvb_demux_feed *feed)
  198. {
  199. struct dvb_demux *demux = feed->demux;
  200. struct budget *budget = (struct budget *) demux->priv;
  201. int status;
  202. dprintk(2, "budget: %p\n", budget);
  203. if (!demux->dmx.frontend)
  204. return -EINVAL;
  205. spin_lock(&budget->feedlock);
  206. feed->pusi_seen = 0; /* have a clean section start */
  207. status = start_ts_capture(budget);
  208. spin_unlock(&budget->feedlock);
  209. return status;
  210. }
  211. static int budget_stop_feed(struct dvb_demux_feed *feed)
  212. {
  213. struct dvb_demux *demux = feed->demux;
  214. struct budget *budget = (struct budget *) demux->priv;
  215. int status;
  216. dprintk(2, "budget: %p\n", budget);
  217. spin_lock(&budget->feedlock);
  218. status = stop_ts_capture(budget);
  219. spin_unlock(&budget->feedlock);
  220. return status;
  221. }
  222. static int budget_register(struct budget *budget)
  223. {
  224. struct dvb_demux *dvbdemux = &budget->demux;
  225. int ret;
  226. dprintk(2, "budget: %p\n", budget);
  227. dvbdemux->priv = (void *) budget;
  228. dvbdemux->filternum = 256;
  229. dvbdemux->feednum = 256;
  230. dvbdemux->start_feed = budget_start_feed;
  231. dvbdemux->stop_feed = budget_stop_feed;
  232. dvbdemux->write_to_decoder = NULL;
  233. dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING |
  234. DMX_MEMORY_BASED_FILTERING);
  235. dvb_dmx_init(&budget->demux);
  236. budget->dmxdev.filternum = 256;
  237. budget->dmxdev.demux = &dvbdemux->dmx;
  238. budget->dmxdev.capabilities = 0;
  239. dvb_dmxdev_init(&budget->dmxdev, &budget->dvb_adapter);
  240. budget->hw_frontend.source = DMX_FRONTEND_0;
  241. ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &budget->hw_frontend);
  242. if (ret < 0)
  243. return ret;
  244. budget->mem_frontend.source = DMX_MEMORY_FE;
  245. ret = dvbdemux->dmx.add_frontend(&dvbdemux->dmx, &budget->mem_frontend);
  246. if (ret < 0)
  247. return ret;
  248. ret = dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, &budget->hw_frontend);
  249. if (ret < 0)
  250. return ret;
  251. dvb_net_init(&budget->dvb_adapter, &budget->dvb_net, &dvbdemux->dmx);
  252. return 0;
  253. }
  254. static void budget_unregister(struct budget *budget)
  255. {
  256. struct dvb_demux *dvbdemux = &budget->demux;
  257. dprintk(2, "budget: %p\n", budget);
  258. dvb_net_release(&budget->dvb_net);
  259. dvbdemux->dmx.close(&dvbdemux->dmx);
  260. dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &budget->hw_frontend);
  261. dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &budget->mem_frontend);
  262. dvb_dmxdev_release(&budget->dmxdev);
  263. dvb_dmx_release(&budget->demux);
  264. }
  265. int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev,
  266. struct saa7146_pci_extension_data *info,
  267. struct module *owner)
  268. {
  269. int length = TS_WIDTH * TS_HEIGHT;
  270. int ret = 0;
  271. struct budget_info *bi = info->ext_priv;
  272. memset(budget, 0, sizeof(struct budget));
  273. dprintk(2, "dev: %p, budget: %p\n", dev, budget);
  274. budget->card = bi;
  275. budget->dev = (struct saa7146_dev *) dev;
  276. dvb_register_adapter(&budget->dvb_adapter, budget->card->name, owner);
  277. /* set dd1 stream a & b */
  278. saa7146_write(dev, DD1_STREAM_B, 0x00000000);
  279. saa7146_write(dev, MC2, (MASK_09 | MASK_25));
  280. saa7146_write(dev, MC2, (MASK_10 | MASK_26));
  281. saa7146_write(dev, DD1_INIT, 0x02000000);
  282. saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
  283. if (bi->type != BUDGET_FS_ACTIVY)
  284. budget->video_port = BUDGET_VIDEO_PORTB;
  285. else
  286. budget->video_port = BUDGET_VIDEO_PORTA;
  287. spin_lock_init(&budget->feedlock);
  288. spin_lock_init(&budget->debilock);
  289. /* the Siemens DVB needs this if you want to have the i2c chips
  290. get recognized before the main driver is loaded */
  291. if (bi->type != BUDGET_FS_ACTIVY)
  292. saa7146_write(dev, GPIO_CTRL, 0x500000); /* GPIO 3 = 1 */
  293. #ifdef I2C_ADAP_CLASS_TV_DIGITAL
  294. budget->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL;
  295. #else
  296. budget->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
  297. #endif
  298. strlcpy(budget->i2c_adap.name, budget->card->name, sizeof(budget->i2c_adap.name));
  299. saa7146_i2c_adapter_prepare(dev, &budget->i2c_adap, SAA7146_I2C_BUS_BIT_RATE_120);
  300. strcpy(budget->i2c_adap.name, budget->card->name);
  301. if (i2c_add_adapter(&budget->i2c_adap) < 0) {
  302. dvb_unregister_adapter(&budget->dvb_adapter);
  303. return -ENOMEM;
  304. }
  305. ttpci_eeprom_parse_mac(&budget->i2c_adap, budget->dvb_adapter.proposed_mac);
  306. if (NULL ==
  307. (budget->grabbing = saa7146_vmalloc_build_pgtable(dev->pci, length, &budget->pt))) {
  308. ret = -ENOMEM;
  309. goto err;
  310. }
  311. saa7146_write(dev, PCI_BT_V1, 0x001c0000);
  312. /* upload all */
  313. saa7146_write(dev, GPIO_CTRL, 0x000000);
  314. tasklet_init(&budget->vpe_tasklet, vpeirq, (unsigned long) budget);
  315. /* frontend power on */
  316. if (bi->type == BUDGET_FS_ACTIVY)
  317. saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI);
  318. else
  319. saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
  320. if (budget_register(budget) == 0) {
  321. return 0;
  322. }
  323. err:
  324. i2c_del_adapter(&budget->i2c_adap);
  325. vfree(budget->grabbing);
  326. dvb_unregister_adapter(&budget->dvb_adapter);
  327. return ret;
  328. }
  329. int ttpci_budget_deinit(struct budget *budget)
  330. {
  331. struct saa7146_dev *dev = budget->dev;
  332. dprintk(2, "budget: %p\n", budget);
  333. budget_unregister(budget);
  334. i2c_del_adapter(&budget->i2c_adap);
  335. dvb_unregister_adapter(&budget->dvb_adapter);
  336. tasklet_kill(&budget->vpe_tasklet);
  337. saa7146_pgtable_free(dev->pci, &budget->pt);
  338. vfree(budget->grabbing);
  339. return 0;
  340. }
  341. void ttpci_budget_irq10_handler(struct saa7146_dev *dev, u32 * isr)
  342. {
  343. struct budget *budget = (struct budget *) dev->ext_priv;
  344. dprintk(8, "dev: %p, budget: %p\n", dev, budget);
  345. if (*isr & MASK_10)
  346. tasklet_schedule(&budget->vpe_tasklet);
  347. }
  348. void ttpci_budget_set_video_port(struct saa7146_dev *dev, int video_port)
  349. {
  350. struct budget *budget = (struct budget *) dev->ext_priv;
  351. spin_lock(&budget->feedlock);
  352. budget->video_port = video_port;
  353. if (budget->feeding) {
  354. int oldfeeding = budget->feeding;
  355. budget->feeding = 1;
  356. stop_ts_capture(budget);
  357. start_ts_capture(budget);
  358. budget->feeding = oldfeeding;
  359. }
  360. spin_unlock(&budget->feedlock);
  361. }
  362. EXPORT_SYMBOL_GPL(ttpci_budget_debiread);
  363. EXPORT_SYMBOL_GPL(ttpci_budget_debiwrite);
  364. EXPORT_SYMBOL_GPL(ttpci_budget_init);
  365. EXPORT_SYMBOL_GPL(ttpci_budget_deinit);
  366. EXPORT_SYMBOL_GPL(ttpci_budget_irq10_handler);
  367. EXPORT_SYMBOL_GPL(ttpci_budget_set_video_port);
  368. EXPORT_SYMBOL_GPL(budget_debug);
  369. MODULE_LICENSE("GPL");