vidc.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:12k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  *  linux/drivers/sound/vidc.c
  3.  *
  4.  *  Copyright (C) 1997-2000 by Russell King <rmk@arm.linux.org.uk>
  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 version 2 as
  8.  * published by the Free Software Foundation.
  9.  *
  10.  *  VIDC20 audio driver.
  11.  *
  12.  * The VIDC20 sound hardware consists of the VIDC20 itself, a DAC and a DMA
  13.  * engine.  The DMA transfers fixed-format (16-bit little-endian linear)
  14.  * samples to the VIDC20, which then transfers this data serially to the
  15.  * DACs.  The samplerate is controlled by the VIDC.
  16.  *
  17.  * We currently support a mixer device, but it is currently non-functional.
  18.  */
  19. #include <linux/config.h>
  20. #include <linux/init.h>
  21. #include <linux/module.h>
  22. #include <linux/kernel.h>
  23. #include <asm/hardware.h>
  24. #include <asm/dma.h>
  25. #include <asm/io.h>
  26. #include <asm/hardware/iomd.h>
  27. #include <asm/irq.h>
  28. #include <asm/system.h>
  29. #include "sound_config.h"
  30. #include "vidc.h"
  31. #ifndef _SIOC_TYPE
  32. #define _SIOC_TYPE(x) _IOC_TYPE(x)
  33. #endif
  34. #ifndef _SIOC_NR
  35. #define _SIOC_NR(x) _IOC_NR(x)
  36. #endif
  37. #define VIDC_SOUND_CLOCK (250000)
  38. /*
  39.  * When using SERIAL SOUND mode (external DAC), the number of physical
  40.  * channels is fixed at 2.
  41.  */
  42. static int vidc_busy;
  43. static int vidc_adev;
  44. static int vidc_audio_rate;
  45. static char vidc_audio_format;
  46. static char vidc_audio_channels;
  47. static unsigned char vidc_level_l[SOUND_MIXER_NRDEVICES] = {
  48. 85, /* master */
  49. 50, /* bass */
  50. 50, /* treble */
  51. 0, /* synth */
  52. 75, /* pcm */
  53. 0, /* speaker */
  54. 100, /* ext line */
  55. 0, /* mic */
  56. 100, /* CD */
  57. 0,
  58. };
  59. static unsigned char vidc_level_r[SOUND_MIXER_NRDEVICES] = {
  60. 85, /* master */
  61. 50, /* bass */
  62. 50, /* treble */
  63. 0, /* synth */
  64. 75, /* pcm */
  65. 0, /* speaker */
  66. 100, /* ext line */
  67. 0, /* mic */
  68. 100, /* CD */
  69. 0,
  70. };
  71. static unsigned int vidc_audio_volume_l; /* left PCM vol, 0 - 65536 */
  72. static unsigned int vidc_audio_volume_r; /* right PCM vol, 0 - 65536 */
  73. static void (*old_mksound)(unsigned int hz, unsigned int ticks);
  74. extern void (*kd_mksound)(unsigned int hz, unsigned int ticks);
  75. extern void vidc_update_filler(int bits, int channels);
  76. extern int softoss_dev;
  77. static void
  78. vidc_mksound(unsigned int hz, unsigned int ticks)
  79. {
  80. // printk("BEEP - %d %d!n", hz, ticks);
  81. }
  82. static void
  83. vidc_mixer_set(int mdev, unsigned int level)
  84. {
  85. unsigned int lev_l = level & 0x007f;
  86. unsigned int lev_r = (level & 0x7f00) >> 8;
  87. unsigned int mlev_l, mlev_r;
  88. if (lev_l > 100)
  89. lev_l = 100;
  90. if (lev_r > 100)
  91. lev_r = 100;
  92. #define SCALE(lev,master) ((lev) * (master) * 65536 / 10000)
  93. mlev_l = vidc_level_l[SOUND_MIXER_VOLUME];
  94. mlev_r = vidc_level_r[SOUND_MIXER_VOLUME];
  95. switch (mdev) {
  96. case SOUND_MIXER_VOLUME:
  97. case SOUND_MIXER_PCM:
  98. vidc_level_l[mdev] = lev_l;
  99. vidc_level_r[mdev] = lev_r;
  100. vidc_audio_volume_l = SCALE(lev_l, mlev_l);
  101. vidc_audio_volume_r = SCALE(lev_r, mlev_r);
  102. /*printk("VIDC: PCM vol %05X %05Xn", vidc_audio_volume_l, vidc_audio_volume_r);*/
  103. break;
  104. }
  105. #undef SCALE
  106. }
  107. static int vidc_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg)
  108. {
  109. unsigned int val;
  110. unsigned int mdev;
  111. if (_SIOC_TYPE(cmd) != 'M')
  112. return -EINVAL;
  113. mdev = _SIOC_NR(cmd);
  114. if (_SIOC_DIR(cmd) & _SIOC_WRITE) {
  115. if (get_user(val, (unsigned int *)arg))
  116. return -EFAULT;
  117. if (mdev < SOUND_MIXER_NRDEVICES)
  118. vidc_mixer_set(mdev, val);
  119. else
  120. return -EINVAL;
  121. }
  122. /*
  123.  * Return parameters
  124.  */
  125. switch (mdev) {
  126. case SOUND_MIXER_RECSRC:
  127. val = 0;
  128. break;
  129. case SOUND_MIXER_DEVMASK:
  130. val = SOUND_MASK_VOLUME | SOUND_MASK_PCM | SOUND_MASK_SYNTH;
  131. break;
  132. case SOUND_MIXER_STEREODEVS:
  133. val = SOUND_MASK_VOLUME | SOUND_MASK_PCM | SOUND_MASK_SYNTH;
  134. break;
  135. case SOUND_MIXER_RECMASK:
  136. val = 0;
  137. break;
  138. case SOUND_MIXER_CAPS:
  139. val = 0;
  140. break;
  141. default:
  142. if (mdev < SOUND_MIXER_NRDEVICES)
  143. val = vidc_level_l[mdev] | vidc_level_r[mdev] << 8;
  144. else
  145. return -EINVAL;
  146. }
  147. return put_user(val, (unsigned int *)arg) ? -EFAULT : 0;
  148. }
  149. static unsigned int vidc_audio_set_format(int dev, unsigned int fmt)
  150. {
  151. switch (fmt) {
  152. default:
  153. fmt = AFMT_S16_LE;
  154. case AFMT_U8:
  155. case AFMT_S8:
  156. case AFMT_S16_LE:
  157. vidc_audio_format = fmt;
  158. vidc_update_filler(vidc_audio_format, vidc_audio_channels);
  159. case AFMT_QUERY:
  160. break;
  161. }
  162. return vidc_audio_format;
  163. }
  164. static int vidc_audio_set_speed(int dev, int rate)
  165. {
  166. if (rate) {
  167. unsigned int hwctrl, hwrate;
  168. unsigned int newsize, new2size;
  169. /*
  170.  * If we have selected 44.1kHz, use the DAC clock.
  171.  */
  172. if (0 && rate == 44100) {
  173. hwctrl = 0x00000002;
  174. hwrate = 3;
  175. } else {
  176. hwctrl = 0x00000003;
  177. hwrate = (((VIDC_SOUND_CLOCK * 2) / rate) + 1) >> 1;
  178. if (hwrate < 3)
  179. hwrate = 3;
  180. if (hwrate > 255)
  181. hwrate = 255;
  182. rate = VIDC_SOUND_CLOCK / hwrate;
  183. }
  184. vidc_writel(0xb0000000 | (hwrate - 2));
  185. vidc_writel(0xb1000000 | hwctrl);
  186. newsize = (10000 / hwrate) & ~3;
  187. if (newsize < 208)
  188. newsize = 208;
  189. if (newsize > 4096)
  190. newsize = 4096;
  191. for (new2size = 128; new2size < newsize; new2size <<= 1);
  192. if (new2size - newsize > newsize - (new2size >> 1))
  193. new2size >>= 1;
  194. if (new2size > 4096) {
  195. printk(KERN_ERR "VIDC: error: dma buffer (%d) %d > 4Kn",
  196. newsize, new2size);
  197. new2size = 4096;
  198. }
  199. dma_bufsize = new2size;
  200. vidc_audio_rate = rate;
  201. }
  202. return vidc_audio_rate;
  203. }
  204. static short vidc_audio_set_channels(int dev, short channels)
  205. {
  206. switch (channels) {
  207. default:
  208. channels = 2;
  209. case 1:
  210. case 2:
  211. vidc_audio_channels = channels;
  212. vidc_update_filler(vidc_audio_format, vidc_audio_channels);
  213. case 0:
  214. break;
  215. }
  216. return vidc_audio_channels;
  217. }
  218. /*
  219.  * Open the device
  220.  */
  221. static int vidc_audio_open(int dev, int mode)
  222. {
  223. /* This audio device does not have recording capability */
  224. if (mode == OPEN_READ)
  225. return -EPERM;
  226. if (vidc_busy)
  227. return -EBUSY;
  228. vidc_busy = 1;
  229. return 0;
  230. }
  231. /*
  232.  * Close the device
  233.  */
  234. static void vidc_audio_close(int dev)
  235. {
  236. vidc_busy = 0;
  237. }
  238. /*
  239.  * Output a block via DMA to sound device.
  240.  *
  241.  * We just set the DMA start and count; the DMA interrupt routine
  242.  * will take care of formatting the samples (via the appropriate
  243.  * vidc_filler routine), and flag via vidc_audio_dma_interrupt when
  244.  * more data is required.
  245.  */
  246. static void
  247. vidc_audio_output_block(int dev, unsigned long buf, int total_count, int one)
  248. {
  249. struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
  250. unsigned long flags;
  251. local_irq_save(flags);
  252. dma_start = buf - (unsigned long)dmap->raw_buf_phys + (unsigned long)dmap->raw_buf;
  253. dma_count = total_count;
  254. local_irq_restore(flags);
  255. }
  256. static void
  257. vidc_audio_start_input(int dev, unsigned long buf, int count, int intrflag)
  258. {
  259. }
  260. static int vidc_audio_prepare_for_input(int dev, int bsize, int bcount)
  261. {
  262. return -EINVAL;
  263. }
  264. static void vidc_audio_dma_interrupt(void)
  265. {
  266. DMAbuf_outputintr(vidc_adev, 1);
  267. }
  268. /*
  269.  * Prepare for outputting samples.
  270.  *
  271.  * Each buffer that will be passed will be `bsize' bytes long,
  272.  * with a total of `bcount' buffers.
  273.  */
  274. static int vidc_audio_prepare_for_output(int dev, int bsize, int bcount)
  275. {
  276. struct audio_operations *adev = audio_devs[dev];
  277. dma_interrupt = NULL;
  278. adev->dmap_out->flags |= DMA_NODMA;
  279. return 0;
  280. }
  281. /*
  282.  * Stop our current operation.
  283.  */
  284. static void vidc_audio_reset(int dev)
  285. {
  286. dma_interrupt = NULL;
  287. }
  288. static int vidc_audio_local_qlen(int dev)
  289. {
  290. return /*dma_count !=*/ 0;
  291. }
  292. static void vidc_audio_trigger(int dev, int enable_bits)
  293. {
  294. struct audio_operations *adev = audio_devs[dev];
  295. if (enable_bits & PCM_ENABLE_OUTPUT) {
  296. if (!(adev->flags & DMA_ACTIVE)) {
  297. unsigned long flags;
  298. local_irq_save(flags);
  299. /* prevent recusion */
  300. adev->flags |= DMA_ACTIVE;
  301. dma_interrupt = vidc_audio_dma_interrupt;
  302. vidc_sound_dma_irq(0, NULL, NULL);
  303. iomd_writeb(DMA_CR_E | 0x10, IOMD_SD0CR);
  304. local_irq_restore(flags);
  305. }
  306. }
  307. }
  308. static struct audio_driver vidc_audio_driver =
  309. {
  310. owner: THIS_MODULE,
  311. open: vidc_audio_open,
  312. close: vidc_audio_close,
  313. output_block: vidc_audio_output_block,
  314. start_input: vidc_audio_start_input,
  315. prepare_for_input: vidc_audio_prepare_for_input,
  316. prepare_for_output: vidc_audio_prepare_for_output,
  317. halt_io: vidc_audio_reset,
  318. local_qlen: vidc_audio_local_qlen,
  319. trigger: vidc_audio_trigger,
  320. set_speed: vidc_audio_set_speed,
  321. set_bits: vidc_audio_set_format,
  322. set_channels: vidc_audio_set_channels
  323. };
  324. static struct mixer_operations vidc_mixer_operations = {
  325. owner: THIS_MODULE,
  326. id: "VIDC",
  327. name: "VIDCsound",
  328. ioctl: vidc_mixer_ioctl
  329. };
  330. void vidc_update_filler(int format, int channels)
  331. {
  332. #define TYPE(fmt,ch) (((fmt)<<2) | ((ch)&3))
  333. switch (TYPE(format, channels)) {
  334. default:
  335. case TYPE(AFMT_U8, 1):
  336. vidc_filler = vidc_fill_1x8_u;
  337. break;
  338. case TYPE(AFMT_U8, 2):
  339. vidc_filler = vidc_fill_2x8_u;
  340. break;
  341. case TYPE(AFMT_S8, 1):
  342. vidc_filler = vidc_fill_1x8_s;
  343. break;
  344. case TYPE(AFMT_S8, 2):
  345. vidc_filler = vidc_fill_2x8_s;
  346. break;
  347. case TYPE(AFMT_S16_LE, 1):
  348. vidc_filler = vidc_fill_1x16_s;
  349. break;
  350. case TYPE(AFMT_S16_LE, 2):
  351. vidc_filler = vidc_fill_2x16_s;
  352. break;
  353. }
  354. }
  355. static void __init attach_vidc(struct address_info *hw_config)
  356. {
  357. char name[32];
  358. int i, adev;
  359. sprintf(name, "VIDC %d-bit sound", hw_config->card_subtype);
  360. conf_printf(name, hw_config);
  361. memset(dma_buf, 0, sizeof(dma_buf));
  362. adev = sound_install_audiodrv(AUDIO_DRIVER_VERSION, name,
  363. &vidc_audio_driver, sizeof(vidc_audio_driver),
  364. DMA_AUTOMODE, AFMT_U8 | AFMT_S8 | AFMT_S16_LE,
  365. NULL, hw_config->dma, hw_config->dma2);
  366. if (adev < 0)
  367. goto audio_failed;
  368. /*
  369.  * 1024 bytes => 64 buffers
  370.  */
  371. audio_devs[adev]->min_fragment = 10;
  372. audio_devs[adev]->mixer_dev = num_mixers;
  373. audio_devs[adev]->mixer_dev =
  374. sound_install_mixer(MIXER_DRIVER_VERSION,
  375. name, &vidc_mixer_operations,
  376. sizeof(vidc_mixer_operations), NULL);
  377. if (audio_devs[adev]->mixer_dev < 0)
  378. goto mixer_failed;
  379. for (i = 0; i < 2; i++) {
  380. dma_buf[i] = get_free_page(GFP_KERNEL);
  381. if (!dma_buf[i]) {
  382. printk(KERN_ERR "%s: can't allocate required buffersn",
  383. name);
  384. goto mem_failed;
  385. }
  386. dma_pbuf[i] = virt_to_phys((void *)dma_buf[i]);
  387. }
  388. if (sound_alloc_dma(hw_config->dma, hw_config->name)) {
  389. printk(KERN_ERR "%s: DMA %d is in  usen", name, hw_config->dma);
  390. goto dma_failed;
  391. }
  392. if (request_irq(hw_config->irq, vidc_sound_dma_irq, 0,
  393. hw_config->name, &dma_start)) {
  394. printk(KERN_ERR "%s: IRQ %d is in usen", name, hw_config->irq);
  395. goto irq_failed;
  396. }
  397. old_mksound = kd_mksound;
  398. kd_mksound = vidc_mksound;
  399. vidc_adev = adev;
  400. vidc_mixer_set(SOUND_MIXER_VOLUME, (85 | 85 << 8));
  401. #if defined(CONFIG_SOUND_SOFTOSS) || defined(CONFIG_SOUND_SOFTOSS_MODULE)
  402. softoss_dev = adev;
  403. #endif
  404. return;
  405. irq_failed:
  406. sound_free_dma(hw_config->dma);
  407. dma_failed:
  408. mem_failed:
  409. for (i = 0; i < 2; i++)
  410. free_page(dma_buf[i]);
  411. sound_unload_mixerdev(audio_devs[adev]->mixer_dev);
  412. mixer_failed:
  413. sound_unload_audiodev(adev);
  414. audio_failed:
  415. return;
  416. }
  417. static int __init probe_vidc(struct address_info *hw_config)
  418. {
  419. hw_config->irq = IRQ_DMAS0;
  420. hw_config->dma = DMA_VIRTUAL_SOUND;
  421. hw_config->dma2 = -1;
  422. hw_config->card_subtype = 16;
  423. hw_config->name = "VIDC20";
  424. return 1;
  425. }
  426. static void __exit unload_vidc(struct address_info *hw_config)
  427. {
  428. int i, adev = vidc_adev;
  429. vidc_adev = -1;
  430. if (old_mksound)
  431. kd_mksound = old_mksound;
  432. free_irq(hw_config->irq, &dma_start);
  433. sound_free_dma(hw_config->dma);
  434. if (adev >= 0) {
  435. sound_unload_mixerdev(audio_devs[adev]->mixer_dev);
  436. sound_unload_audiodev(adev);
  437. for (i = 0; i < 2; i++)
  438. free_page(dma_buf[i]);
  439. }
  440. }
  441. static struct address_info cfg;
  442. static int __init init_vidc(void)
  443. {
  444. if (probe_vidc(&cfg) == 0)
  445. return -ENODEV;
  446. attach_vidc(&cfg);
  447. return 0;
  448. }
  449. static void __exit cleanup_vidc(void)
  450. {
  451. unload_vidc(&cfg);
  452. }
  453. module_init(init_vidc);
  454. module_exit(cleanup_vidc);
  455. MODULE_AUTHOR("Russell King");
  456. MODULE_DESCRIPTION("VIDC20 audio driver");
  457. MODULE_LICENSE("GPL");
  458. EXPORT_NO_SYMBOLS;