PageRenderTime 56ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/trunk/cdk/driver/avia/avia_gt_pcm.c

https://github.com/nx111/OpenPLi.cn
C | 693 lines | 356 code | 222 blank | 115 comment | 106 complexity | c0031ac5dd30572ba89055924b4950c7 MD5 | raw file
Possible License(s): GPL-2.0, AGPL-1.0, MPL-2.0-no-copyleft-exception
  1. /*
  2. * avia_gt_pcm.c - AViA eNX/GTX pcm driver (dbox-II-project)
  3. *
  4. * Homepage: http://dbox2.elxsi.de
  5. *
  6. * Copyright (C) 2002 Florian Schirmer (jolt@tuxbox.org)
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21. *
  22. *
  23. * $Log: avia_gt_pcm.c,v $
  24. * Revision 1.19 2002/10/03 11:12:42 thegoodguy
  25. * Reenable full volume
  26. *
  27. * Revision 1.18 2002/09/25 18:50:52 Jolt
  28. * Added 24000 and 12000 sample rate support
  29. *
  30. * Revision 1.17 2002/08/22 13:39:33 Jolt
  31. * - GCC warning fixes
  32. * - screen flicker fixes
  33. * Thanks a lot to Massa
  34. *
  35. * Revision 1.16 2002/08/19 00:02:01 TheDOC
  36. * export the poll-stuff
  37. *
  38. * Revision 1.15 2002/08/18 18:22:30 tmbinc
  39. * added poll()-support for pcm device (untested)
  40. *
  41. * Revision 1.14 2002/06/07 18:06:03 Jolt
  42. * GCC31 fixes 2nd shot (GTX version) - sponsored by Frankster (THX!)
  43. *
  44. * Revision 1.13 2002/06/07 17:53:45 Jolt
  45. * GCC31 fixes 2nd shot - sponsored by Frankster (THX!)
  46. *
  47. * Revision 1.12 2002/05/08 12:56:41 obi
  48. * export avia_gt_pcm_set_mpeg_attenuation
  49. * plus some cleanup
  50. *
  51. * Revision 1.11 2002/04/22 17:40:01 Jolt
  52. * Major cleanup
  53. *
  54. * Revision 1.10 2002/04/14 18:06:19 Jolt
  55. * eNX/GTX merge
  56. *
  57. * Revision 1.9 2002/04/13 23:19:05 Jolt
  58. * eNX/GTX merge
  59. *
  60. * Revision 1.8 2002/04/13 21:00:28 Jolt
  61. * eNX/GTX merge
  62. *
  63. * Revision 1.7 2002/04/13 14:47:19 Jolt
  64. * eNX/GTX merge
  65. *
  66. * Revision 1.6 2002/04/12 13:50:37 Jolt
  67. * eNX/GTX merge
  68. *
  69. * Revision 1.5 2002/04/10 21:53:31 Jolt
  70. * Further cleanups/bugfixes
  71. * More OSS API stuff
  72. * Revision 1.4 2002/04/05 23:15:13 Jolt
  73. * Improved buffer management - MP3 is rocking solid now
  74. *
  75. * Revision 1.3 2002/04/02 18:14:10 Jolt
  76. * Further features/bugfixes. MP3 works very well now 8-)
  77. *
  78. * Revision 1.2 2002/04/02 13:56:50 Jolt
  79. * Dependency fixes
  80. *
  81. * Revision 1.1 2002/04/01 22:23:22 Jolt
  82. * Basic PCM driver for eNX - more to come later
  83. *
  84. *
  85. *
  86. * $Revision: 1.19 $
  87. *
  88. */
  89. #include <linux/module.h>
  90. #include <linux/kernel.h>
  91. #include <linux/ioport.h>
  92. #include <linux/delay.h>
  93. #include <linux/slab.h>
  94. #include <linux/version.h>
  95. #include <linux/init.h>
  96. #include <linux/wait.h>
  97. #include <linux/poll.h>
  98. #include <asm/irq.h>
  99. #include <asm/io.h>
  100. #include <asm/bitops.h>
  101. #include <asm/uaccess.h>
  102. #include <linux/init.h>
  103. #include <linux/byteorder/swab.h>
  104. #include <dbox/avia_gt.h>
  105. #include <dbox/avia_gt_pcm.h>
  106. DECLARE_WAIT_QUEUE_HEAD(pcm_wait);
  107. typedef struct {
  108. struct list_head list;
  109. unsigned int offset;
  110. unsigned int sample_count;
  111. unsigned char queued;
  112. } sPcmBuffer;
  113. LIST_HEAD(pcm_busy_buffer_list);
  114. LIST_HEAD(pcm_free_buffer_list);
  115. spinlock_t busy_buffer_lock = SPIN_LOCK_UNLOCKED;
  116. spinlock_t free_buffer_lock = SPIN_LOCK_UNLOCKED;
  117. static sAviaGtInfo *gt_info = (sAviaGtInfo *)NULL;
  118. unsigned char swab_samples = (unsigned char)0;
  119. sPcmBuffer pcm_buffer_array[AVIA_GT_PCM_BUFFER_COUNT];
  120. unsigned char swab_buffer[AVIA_GT_PCM_BUFFER_SIZE] = { 0 };
  121. // Warning - result is _per_ channel
  122. unsigned int avia_gt_pcm_calc_sample_count(unsigned int buffer_size)
  123. {
  124. if (avia_gt_chip(ENX)) {
  125. if (enx_reg_s(PCMC)->W)
  126. buffer_size /= 2;
  127. if (enx_reg_s(PCMC)->C)
  128. buffer_size /= 2;
  129. } else if (avia_gt_chip(GTX)) {
  130. if (gtx_reg_s(PCMC)->W)
  131. buffer_size /= 2;
  132. if (gtx_reg_s(PCMC)->C)
  133. buffer_size /= 2;
  134. }
  135. return buffer_size;
  136. }
  137. // Warning - if stereo result is for _both_ channels
  138. unsigned int avia_gt_pcm_calc_buffer_size(unsigned int sample_count)
  139. {
  140. if (avia_gt_chip(ENX)) {
  141. if (enx_reg_s(PCMC)->W)
  142. sample_count *= 2;
  143. if (enx_reg_s(PCMC)->C)
  144. sample_count *= 2;
  145. } else if (avia_gt_chip(GTX)) {
  146. if (gtx_reg_s(PCMC)->W)
  147. sample_count *= 2;
  148. if (gtx_reg_s(PCMC)->C)
  149. sample_count *= 2;
  150. }
  151. return sample_count;
  152. }
  153. void avia_gt_pcm_queue_buffer(void)
  154. {
  155. unsigned long flags = (unsigned long)0;
  156. sPcmBuffer *pcm_buffer = (sPcmBuffer *)NULL;
  157. struct list_head *ptr = (struct list_head *)NULL;
  158. if (avia_gt_chip(ENX)) {
  159. if (!enx_reg_s(PCMA)->W)
  160. return;
  161. } else if (avia_gt_chip(GTX)) {
  162. if (!gtx_reg_s(PCMA)->W)
  163. return;
  164. }
  165. spin_lock_irqsave(&busy_buffer_lock, flags);
  166. list_for_each(ptr, &pcm_busy_buffer_list) {
  167. pcm_buffer = list_entry(ptr, sPcmBuffer, list);
  168. if (!pcm_buffer->queued) {
  169. if (avia_gt_chip(ENX)) {
  170. enx_reg_set(PCMS, NSAMP, pcm_buffer->sample_count);
  171. enx_reg_set(PCMA, Addr, pcm_buffer->offset >> 1);
  172. enx_reg_set(PCMA, W, 0);
  173. } else if (avia_gt_chip(GTX)) {
  174. gtx_reg_set(PCMA, NSAMP, pcm_buffer->sample_count);
  175. gtx_reg_set(PCMA, Addr, pcm_buffer->offset >> 1);
  176. gtx_reg_set(PCMA, W, 0);
  177. }
  178. pcm_buffer->queued = 1;
  179. break;
  180. }
  181. }
  182. spin_unlock_irqrestore(&busy_buffer_lock, flags);
  183. }
  184. static void avia_gt_pcm_irq(unsigned short irq)
  185. {
  186. unsigned long flags = (unsigned long)0;
  187. sPcmBuffer *pcm_buffer = (sPcmBuffer *)NULL;
  188. //int i = 0;
  189. //struct list_head *ptr;
  190. spin_lock_irqsave(&busy_buffer_lock, flags);
  191. /*
  192. if ((irq == ENX_IRQ_PCM_AD) || (irq == GTX_IRQ_PCM_AD))
  193. printk("X");
  194. list_for_each(ptr, &pcm_busy_buffer_list) {
  195. i++;
  196. }
  197. printk("%d ", i);
  198. */
  199. if (!list_empty(&pcm_busy_buffer_list)) {
  200. pcm_buffer = list_entry(pcm_busy_buffer_list.next, sPcmBuffer, list);
  201. list_del(&pcm_buffer->list);
  202. pcm_buffer->queued = 0;
  203. spin_lock_irqsave(&free_buffer_lock, flags);
  204. list_add_tail(&pcm_buffer->list, &pcm_free_buffer_list);
  205. spin_unlock_irqrestore(&free_buffer_lock, flags);
  206. }
  207. spin_unlock_irqrestore(&busy_buffer_lock, flags);
  208. avia_gt_pcm_queue_buffer();
  209. wake_up_interruptible(&pcm_wait);
  210. }
  211. unsigned int avia_gt_pcm_get_block_size(void)
  212. {
  213. return avia_gt_pcm_calc_buffer_size(AVIA_GT_PCM_MAX_SAMPLES);
  214. }
  215. void avia_gt_pcm_reset(unsigned char reenable)
  216. {
  217. if (avia_gt_chip(ENX)) {
  218. enx_reg_set(RSTR0, PCMA, 1);
  219. enx_reg_set(RSTR0, PCM, 1);
  220. } else if (avia_gt_chip(GTX)) {
  221. gtx_reg_set(RR0, ACLK, 1);
  222. gtx_reg_set(RR0, PCM, 1);
  223. }
  224. if (reenable) {
  225. if (avia_gt_chip(ENX)) {
  226. enx_reg_set(RSTR0, PCM, 0);
  227. enx_reg_set(RSTR0, PCMA, 0);
  228. } else if (avia_gt_chip(GTX)) {
  229. gtx_reg_set(RR0, PCM, 0);
  230. gtx_reg_set(RR0, ACLK, 0);
  231. }
  232. }
  233. }
  234. void avia_gt_pcm_set_mpeg_attenuation(unsigned char left, unsigned char right)
  235. {
  236. if (avia_gt_chip(ENX)) {
  237. enx_reg_set(PCMN, MPEGAL, left >> 1);
  238. enx_reg_set(PCMN, MPEGAR, right >> 1);
  239. } else if (avia_gt_chip(GTX)) {
  240. gtx_reg_set(PCMN, MPEGAL, left >> 1);
  241. gtx_reg_set(PCMN, MPEGAR, right >> 1);
  242. }
  243. }
  244. void avia_gt_pcm_set_pcm_attenuation(unsigned char left, unsigned char right)
  245. {
  246. if (avia_gt_chip(ENX)) {
  247. enx_reg_set(PCMN, PCMAL, left >> 1);
  248. enx_reg_set(PCMN, PCMAR, right >> 1);
  249. } else if (avia_gt_chip(GTX)) {
  250. gtx_reg_set(PCMN, PCMAL, left >> 1);
  251. gtx_reg_set(PCMN, PCMAR, right >> 1);
  252. }
  253. }
  254. int avia_gt_pcm_set_rate(unsigned short rate)
  255. {
  256. unsigned char divider_mode = 3;
  257. switch(rate) {
  258. case 48000:
  259. case 44100:
  260. divider_mode = 3;
  261. break;
  262. case 24000:
  263. case 22050:
  264. divider_mode = 2;
  265. break;
  266. case 12000:
  267. case 11025:
  268. divider_mode = 1;
  269. break;
  270. default:
  271. return -EINVAL;
  272. break;
  273. }
  274. if (avia_gt_chip(ENX))
  275. enx_reg_set(PCMC, R, divider_mode);
  276. else if (avia_gt_chip(GTX))
  277. gtx_reg_set(PCMC, R, divider_mode);
  278. return 0;
  279. }
  280. int avia_gt_pcm_set_width(unsigned char width)
  281. {
  282. if ((width == 8) || (width == 16)) {
  283. if (avia_gt_chip(ENX))
  284. enx_reg_set(PCMC, W, (width == 16));
  285. else if (avia_gt_chip(GTX))
  286. gtx_reg_set(PCMC, W, (width == 16));
  287. } else {
  288. return -EINVAL;
  289. }
  290. return 0;
  291. }
  292. int avia_gt_pcm_set_channels(unsigned char channels)
  293. {
  294. if ((channels == 1) || (channels == 2)) {
  295. if (avia_gt_chip(ENX))
  296. enx_reg_set(PCMC, C, (channels == 2));
  297. else if (avia_gt_chip(GTX))
  298. gtx_reg_set(PCMC, C, (channels == 2));
  299. } else {
  300. return -EINVAL;
  301. }
  302. return 0;
  303. }
  304. int avia_gt_pcm_set_signed(unsigned char signed_samples)
  305. {
  306. if ((signed_samples == 0) || (signed_samples == 1)) {
  307. if (avia_gt_chip(ENX))
  308. enx_reg_set(PCMC, S, (signed_samples == 1));
  309. else if (avia_gt_chip(GTX))
  310. gtx_reg_set(PCMC, S, (signed_samples == 1));
  311. } else {
  312. return -EINVAL;
  313. }
  314. return 0;
  315. }
  316. int avia_gt_pcm_set_endian(unsigned char be)
  317. {
  318. if ((be == 0) || (be == 1))
  319. swab_samples = (be == 0);
  320. else
  321. return -EINVAL;
  322. return 0;
  323. }
  324. int avia_gt_pcm_play_buffer(void *buffer, unsigned int buffer_size, unsigned char block) {
  325. unsigned char bps_16 = (char)'\0';
  326. unsigned long flags = (unsigned long)0;
  327. sPcmBuffer *pcm_buffer = (sPcmBuffer *)NULL;
  328. unsigned int sample_nr = (unsigned int)0;
  329. unsigned short *swab_dest = (unsigned short *)NULL;
  330. unsigned short *swab_src = (unsigned short *)NULL;
  331. unsigned int sample_count = (unsigned int)0;
  332. unsigned char stereo = (unsigned char)'\0';
  333. sample_count = avia_gt_pcm_calc_sample_count(buffer_size);
  334. if (sample_count > AVIA_GT_PCM_MAX_SAMPLES)
  335. sample_count = AVIA_GT_PCM_MAX_SAMPLES;
  336. if (avia_gt_chip(ENX)) {
  337. bps_16 = enx_reg_s(PCMC)->W;
  338. stereo = enx_reg_s(PCMC)->C;
  339. } else if (avia_gt_chip(GTX)) {
  340. bps_16 = gtx_reg_s(PCMC)->W;
  341. stereo = gtx_reg_s(PCMC)->C;
  342. }
  343. // If 8-bit mono then sample count has to be even
  344. if ((!bps_16) && (!stereo))
  345. sample_count &= ~1;
  346. while (list_empty(&pcm_free_buffer_list)) {
  347. if (block) {
  348. if (wait_event_interruptible(pcm_wait, !list_empty(&pcm_free_buffer_list)))
  349. return -ERESTARTSYS;
  350. } else {
  351. return -EWOULDBLOCK;
  352. }
  353. }
  354. spin_lock_irqsave(&free_buffer_lock, flags);
  355. pcm_buffer = list_entry(pcm_free_buffer_list.next, sPcmBuffer, list);
  356. list_del(&pcm_buffer->list);
  357. spin_unlock_irqrestore(&free_buffer_lock, flags);
  358. if ((bps_16) && (swab_samples)) {
  359. copy_from_user(swab_buffer, buffer, avia_gt_pcm_calc_buffer_size(sample_count));
  360. swab_dest = (unsigned short *)(gt_info->mem_addr + pcm_buffer->offset);
  361. swab_src = (unsigned short *)swab_buffer;
  362. for (sample_nr = 0; sample_nr < avia_gt_pcm_calc_buffer_size(sample_count) / 2; sample_nr++)
  363. swab_dest[sample_nr] = swab16(swab_src[sample_nr]);
  364. } else {
  365. copy_from_user(gt_info->mem_addr + pcm_buffer->offset, buffer, avia_gt_pcm_calc_buffer_size(sample_count));
  366. }
  367. pcm_buffer->sample_count = sample_count;
  368. spin_lock_irqsave(&busy_buffer_lock, flags);
  369. list_add_tail(&pcm_buffer->list, &pcm_busy_buffer_list);
  370. spin_unlock_irqrestore(&busy_buffer_lock, flags);
  371. avia_gt_pcm_queue_buffer();
  372. return avia_gt_pcm_calc_buffer_size(sample_count);
  373. }
  374. unsigned int avia_gt_pcm_poll(struct file *file, struct poll_table_struct *wait)
  375. {
  376. poll_wait(file, &pcm_wait, wait);
  377. if (!list_empty(&pcm_free_buffer_list))
  378. return POLLOUT|POLLWRNORM;
  379. return 0;
  380. }
  381. void avia_gt_pcm_stop(void)
  382. {
  383. /*
  384. if (avia_gt_chip(ENX))
  385. enx_reg_set(PCMC, T, 1);
  386. else if (avia_gt_chip(GTX))
  387. gtx_reg_set(PCMC, T, 1);
  388. */
  389. return;
  390. }
  391. int avia_gt_pcm_init(void)
  392. {
  393. unsigned char buf_nr = (unsigned char)'\0';
  394. unsigned short irq_ad = (unsigned short)0;
  395. unsigned short irq_pf = (unsigned short)0;
  396. printk("avia_gt_pcm: $Id: avia_gt_pcm.c,v 1.19 2002/10/03 11:12:42 thegoodguy Exp $\n");
  397. gt_info = avia_gt_get_info();
  398. if ((!gt_info) || ((!avia_gt_chip(ENX)) && (!avia_gt_chip(GTX)))) {
  399. printk("avia_gt_pcm: Unsupported chip type\n");
  400. return -EIO;
  401. }
  402. if (avia_gt_chip(ENX)) {
  403. irq_ad = ENX_IRQ_PCM_AD;
  404. irq_pf = ENX_IRQ_PCM_PF;
  405. } else if (avia_gt_chip(GTX)) {
  406. irq_ad = GTX_IRQ_PCM_AD;
  407. irq_pf = GTX_IRQ_PCM_PF;
  408. }
  409. if (avia_gt_alloc_irq(irq_ad, avia_gt_pcm_irq)) {
  410. printk("avia_gt_pcm: unable to get pcm-ad interrupt\n");
  411. return -EIO;
  412. }
  413. if (avia_gt_alloc_irq(irq_pf, avia_gt_pcm_irq)) {
  414. printk("avia_gt_pcm: unable to get pcm-pf interrupt\n");
  415. avia_gt_free_irq(irq_ad);
  416. return -EIO;
  417. }
  418. avia_gt_pcm_reset(1);
  419. for (buf_nr = 0; buf_nr < AVIA_GT_PCM_BUFFER_COUNT; buf_nr++) {
  420. pcm_buffer_array[buf_nr].offset = AVIA_GT_MEM_PCM_OFFS + (AVIA_GT_PCM_BUFFER_SIZE * buf_nr);
  421. pcm_buffer_array[buf_nr].queued = 0;
  422. list_add_tail(&pcm_buffer_array[buf_nr].list, &pcm_free_buffer_list);
  423. }
  424. // Use external clock from AViA 500/600
  425. if (avia_gt_chip(ENX))
  426. enx_reg_set(PCMC, I, 0);
  427. else if (avia_gt_chip(GTX))
  428. gtx_reg_set(PCMC, I, 0);
  429. // Pass through mpeg samples
  430. avia_gt_pcm_set_mpeg_attenuation(0x80, 0x80);
  431. // Set a default mode
  432. avia_gt_pcm_set_rate(44100);
  433. avia_gt_pcm_set_width(16);
  434. avia_gt_pcm_set_channels(2);
  435. avia_gt_pcm_set_signed(1);
  436. avia_gt_pcm_set_endian(1);
  437. return 0;
  438. }
  439. void avia_gt_pcm_exit(void)
  440. {
  441. if (avia_gt_chip(ENX)) {
  442. avia_gt_free_irq(ENX_IRQ_PCM_AD);
  443. avia_gt_free_irq(ENX_IRQ_PCM_PF);
  444. } else if (avia_gt_chip(GTX)) {
  445. avia_gt_free_irq(GTX_IRQ_PCM_AD);
  446. avia_gt_free_irq(GTX_IRQ_PCM_PF);
  447. }
  448. avia_gt_pcm_reset(0);
  449. }
  450. #ifdef MODULE
  451. EXPORT_SYMBOL(avia_gt_pcm_play_buffer);
  452. EXPORT_SYMBOL(avia_gt_pcm_stop);
  453. EXPORT_SYMBOL(avia_gt_pcm_set_signed);
  454. EXPORT_SYMBOL(avia_gt_pcm_set_endian);
  455. EXPORT_SYMBOL(avia_gt_pcm_set_rate);
  456. EXPORT_SYMBOL(avia_gt_pcm_set_width);
  457. EXPORT_SYMBOL(avia_gt_pcm_set_channels);
  458. EXPORT_SYMBOL(avia_gt_pcm_set_mpeg_attenuation);
  459. EXPORT_SYMBOL(avia_gt_pcm_set_pcm_attenuation);
  460. EXPORT_SYMBOL(avia_gt_pcm_get_block_size);
  461. EXPORT_SYMBOL(avia_gt_pcm_poll);
  462. #endif
  463. #if defined(MODULE) && defined(STANDALONE)
  464. module_init(avia_gt_pcm_init);
  465. module_exit(avia_gt_pcm_exit);
  466. #endif