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

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  *  linux/drivers/misc/ucb1x00-audio.c
  3.  *
  4.  *  Copyright (C) 2001 Russell King, All Rights Reserved.
  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. #include <linux/module.h>
  11. #include <linux/init.h>
  12. #include <linux/fs.h>
  13. #include <linux/errno.h>
  14. #include <linux/slab.h>
  15. #include <linux/sound.h>
  16. #include <linux/soundcard.h>
  17. #include <linux/list.h>
  18. #include <asm/dma.h>
  19. #include <asm/hardware.h>
  20. #include <asm/semaphore.h>
  21. #include <asm/uaccess.h>
  22. #include "ucb1x00.h"
  23. #include "../drivers/sound/sa1100-audio.h"
  24. #define MAGIC 0x41544154
  25. struct ucb1x00_audio {
  26. struct file_operations fops;
  27. struct file_operations mops;
  28. struct ucb1x00 *ucb;
  29. audio_stream_t output_stream;
  30. audio_stream_t input_stream;
  31. audio_state_t state;
  32. unsigned int rate;
  33. int dev_id;
  34. int mix_id;
  35. unsigned int daa_oh_bit;
  36. unsigned int telecom;
  37. unsigned int magic;
  38. unsigned int ctrl_a;
  39. unsigned int ctrl_b;
  40. /* mixer info */
  41. unsigned int mod_cnt;
  42. unsigned short output_level;
  43. unsigned short input_level;
  44. };
  45. #define REC_MASK (SOUND_MASK_VOLUME | SOUND_MASK_MIC)
  46. #define DEV_MASK REC_MASK
  47. static int
  48. ucb1x00_mixer_ioctl(struct inode *ino, struct file *filp, uint cmd, ulong arg)
  49. {
  50. struct ucb1x00_audio *ucba;
  51. unsigned int val, gain;
  52. int ret = 0;
  53. ucba = list_entry(filp->f_op, struct ucb1x00_audio, mops);
  54. if (_IOC_TYPE(cmd) != 'M')
  55. return -EINVAL;
  56. if (cmd == SOUND_MIXER_INFO) {
  57. struct mixer_info mi;
  58. strncpy(mi.id, "UCB1x00", sizeof(mi.id));
  59. strncpy(mi.name, "Philips UCB1x00", sizeof(mi.name));
  60. mi.modify_counter = ucba->mod_cnt;
  61. return copy_to_user(arg, &mi, sizeof(mi)) ? -EFAULT : 0;
  62. }
  63. if (_IOC_DIR(cmd) == _IOC_WRITE) {
  64. unsigned int left, right;
  65. ret = get_user(val, (unsigned int *)arg);
  66. if (ret)
  67. goto out;
  68. left  = val & 255;
  69. right = val >> 8;
  70. if (left > 100)
  71. left = 100;
  72. if (right > 100)
  73. right = 100;
  74. gain = (left + right) / 2;
  75. ret = -EINVAL;
  76. if (!ucba->telecom) {
  77. switch(_IOC_NR(cmd)) {
  78. case SOUND_MIXER_VOLUME:
  79. ucba->output_level = gain | gain << 8;
  80. ucba->mod_cnt++;
  81. ucba->ctrl_b = (ucba->ctrl_b & 0xff00) |
  82.        ((gain * 31) / 100);
  83. ucb1x00_reg_write(ucba->ucb, UCB_AC_B,
  84.   ucba->ctrl_b);
  85. ret = 0;
  86. break;
  87. case SOUND_MIXER_MIC:
  88. ucba->input_level = gain | gain << 8;
  89. ucba->mod_cnt++;
  90. ucba->ctrl_a = (ucba->ctrl_a & 0x7f) |
  91.        ((gain * 31) / 100);
  92. ucb1x00_reg_write(ucba->ucb, UCB_AC_A,
  93.   ucba->ctrl_a);
  94. ret = 0;
  95. break;
  96. }
  97. }
  98. }
  99. if (ret == 0 && _IOC_DIR(cmd) & _IOC_READ) {
  100. switch (_IOC_NR(cmd)) {
  101. case SOUND_MIXER_VOLUME:
  102. val = ucba->output_level;
  103. break;
  104. case SOUND_MIXER_MIC:
  105. val = ucba->input_level;
  106. break;
  107. case SOUND_MIXER_RECSRC:
  108. case SOUND_MIXER_RECMASK:
  109. val = ucba->telecom ? 0 : REC_MASK;
  110. break;
  111. case SOUND_MIXER_DEVMASK:
  112. val = ucba->telecom ? 0 : DEV_MASK;
  113. break;
  114. case SOUND_MIXER_CAPS:
  115. case SOUND_MIXER_STEREODEVS:
  116. val = 0;
  117. break;
  118. default:
  119. val = 0;
  120. ret = -EINVAL;
  121. break;
  122. }
  123. if (ret == 0)
  124. ret = put_user(val, (int *)arg);
  125. }
  126.  out:
  127. return ret;
  128. }
  129. static int ucb1x00_audio_setrate(struct ucb1x00_audio *ucba, int rate)
  130. {
  131. unsigned int div_rate = ucb1x00_clkrate(ucba->ucb) / 32;
  132. unsigned int div;
  133. div = (div_rate + (rate / 2)) / rate;
  134. if (div < 6)
  135. div = 6;
  136. if (div > 127)
  137. div = 127;
  138. ucba->ctrl_a = (ucba->ctrl_a & ~0x7f) | div;
  139. if (ucba->telecom) {
  140. ucb1x00_reg_write(ucba->ucb, UCB_TC_B, 0);
  141. ucb1x00_set_telecom_divisor(ucba->ucb, div * 32);
  142. ucb1x00_reg_write(ucba->ucb, UCB_TC_A, ucba->ctrl_a);
  143. ucb1x00_reg_write(ucba->ucb, UCB_TC_B, ucba->ctrl_b);
  144. } else {
  145. ucb1x00_reg_write(ucba->ucb, UCB_AC_B, 0);
  146. ucb1x00_set_audio_divisor(ucba->ucb, div * 32);
  147. ucb1x00_reg_write(ucba->ucb, UCB_AC_A, ucba->ctrl_a);
  148. ucb1x00_reg_write(ucba->ucb, UCB_AC_B, ucba->ctrl_b);
  149. }
  150. ucba->rate = div_rate / div;
  151. return ucba->rate;
  152. }
  153. static int ucb1x00_audio_getrate(struct ucb1x00_audio *ucba)
  154. {
  155. return ucba->rate;
  156. }
  157. static void ucb1x00_audio_startup(void *data)
  158. {
  159. struct ucb1x00_audio *ucba = data;
  160. ucb1x00_enable(ucba->ucb);
  161. ucb1x00_audio_setrate(ucba, ucba->rate);
  162. ucb1x00_reg_write(ucba->ucb, UCB_MODE, UCB_MODE_DYN_VFLAG_ENA);
  163. /*
  164.  * Take off-hook
  165.  */
  166. if (ucba->daa_oh_bit)
  167. ucb1x00_io_write(ucba->ucb, 0, ucba->daa_oh_bit);
  168. }
  169. static void ucb1x00_audio_shutdown(void *data)
  170. {
  171. struct ucb1x00_audio *ucba = data;
  172. /*
  173.  * Place on-hook
  174.  */
  175. if (ucba->daa_oh_bit)
  176. ucb1x00_io_write(ucba->ucb, ucba->daa_oh_bit, 0);
  177. ucb1x00_reg_write(ucba->ucb, ucba->telecom ? UCB_TC_B : UCB_AC_B, 0);
  178. ucb1x00_disable(ucba->ucb);
  179. }
  180. static int
  181. ucb1x00_audio_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
  182. {
  183. struct ucb1x00_audio *ucba;
  184. int val, ret = 0;
  185. ucba = list_entry(file->f_op, struct ucb1x00_audio, fops);
  186. /*
  187.  * Make sure we have our magic number
  188.  */
  189. if (ucba->magic != MAGIC)
  190. return -ENODEV;
  191. switch (cmd) {
  192. case SNDCTL_DSP_STEREO:
  193. ret = get_user(val, (int *)arg);
  194. if (ret)
  195. return ret;
  196. if (val != 0)
  197. return -EINVAL;
  198. val = 0;
  199. break;
  200. case SNDCTL_DSP_CHANNELS:
  201. case SOUND_PCM_READ_CHANNELS:
  202. val = 1;
  203. break;
  204. case SNDCTL_DSP_SPEED:
  205. ret = get_user(val, (int *)arg);
  206. if (ret)
  207. return ret;
  208. val = ucb1x00_audio_setrate(ucba, val);
  209. break;
  210. case SOUND_PCM_READ_RATE:
  211. val = ucb1x00_audio_getrate(ucba);
  212. break;
  213. case SNDCTL_DSP_SETFMT:
  214. case SNDCTL_DSP_GETFMTS:
  215. val = AFMT_S16_LE;
  216. break;
  217. default:
  218. return ucb1x00_mixer_ioctl(inode, file, cmd, arg);
  219. }
  220. return put_user(val, (int *)arg);
  221. }
  222. static int ucb1x00_audio_open(struct inode *inode, struct file *file)
  223. {
  224. struct ucb1x00_audio *ucba;
  225. ucba = list_entry(file->f_op, struct ucb1x00_audio, fops);
  226. return sa1100_audio_attach(inode, file, &ucba->state);
  227. }
  228. static struct ucb1x00_audio *ucb1x00_audio_alloc(struct ucb1x00 *ucb)
  229. {
  230. struct ucb1x00_audio *ucba;
  231. ucba = kmalloc(sizeof(*ucba), GFP_KERNEL);
  232. if (ucba) {
  233. memset(ucba, 0, sizeof(*ucba));
  234. ucba->magic = MAGIC;
  235. ucba->ucb = ucb;
  236. ucba->fops.owner = THIS_MODULE;
  237. ucba->fops.open  = ucb1x00_audio_open;
  238. ucba->mops.owner = THIS_MODULE;
  239. ucba->mops.ioctl = ucb1x00_mixer_ioctl;
  240. ucba->state.output_stream = &ucba->output_stream;
  241. ucba->state.input_stream = &ucba->input_stream;
  242. ucba->state.data = ucba;
  243. ucba->state.hw_init = ucb1x00_audio_startup;
  244. ucba->state.hw_shutdown = ucb1x00_audio_shutdown;
  245. ucba->state.client_ioctl = ucb1x00_audio_ioctl;
  246. init_MUTEX(&ucba->state.sem);
  247. ucba->rate = 8000;
  248. }
  249. return ucba;
  250. }
  251. static struct ucb1x00_audio *audio, *telecom;
  252. static int __init ucb1x00_audio_init(void)
  253. {
  254. struct ucb1x00 *ucb = ucb1x00_get();
  255. struct ucb1x00_audio *a;
  256. if (!ucb)
  257. return -ENODEV;
  258. a = ucb1x00_audio_alloc(ucb);
  259. if (a) {
  260. a->state.input_dma  = ucb->mcp->dma_audio_rd;
  261. a->state.input_id   = "UCB1x00 audio in";
  262. a->state.output_dma = ucb->mcp->dma_audio_wr;
  263. a->state.output_id  = "UCB1x00 audio out";
  264. a->dev_id = register_sound_dsp(&a->fops, -1);
  265. a->mix_id = register_sound_mixer(&a->mops, -1);
  266. a->ctrl_a = 0;
  267. a->ctrl_b = UCB_AC_B_IN_ENA|UCB_AC_B_OUT_ENA;
  268. audio = a;
  269. }
  270. a = ucb1x00_audio_alloc(ucb);
  271. if (a) {
  272. #if 0
  273. a->daa_oh_bit = UCB_IO_8;
  274. ucb1x00_enable(ucb);
  275. ucb1x00_io_write(ucb, a->daa_oh_bit, 0);
  276. ucb1x00_io_set_dir(ucb, UCB_IO_7 | UCB_IO_6, a->daa_oh_bit);
  277. ucb1x00_disable(ucb);
  278. #endif
  279. a->telecom = 1;
  280. a->state.input_dma  = ucb->mcp->dma_telco_rd;
  281. a->state.input_id   = "UCB1x00 telco in";
  282. a->state.output_dma = ucb->mcp->dma_telco_wr;
  283. a->state.output_id  = "UCB1x00 telco out";
  284. a->dev_id = register_sound_dsp(&a->fops, -1);
  285. a->mix_id = register_sound_mixer(&a->mops, -1);
  286. a->ctrl_a = 0;
  287. a->ctrl_b = UCB_TC_B_IN_ENA|UCB_TC_B_OUT_ENA;
  288. telecom = a;
  289. }
  290. return 0;
  291. }
  292. static void __exit ucb1x00_audio_exit(void)
  293. {
  294. unregister_sound_dsp(telecom->dev_id);
  295. unregister_sound_dsp(audio->dev_id);
  296. }
  297. module_init(ucb1x00_audio_init);
  298. module_exit(ucb1x00_audio_exit);
  299. MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
  300. MODULE_DESCRIPTION("UCB1x00 telecom/audio driver");
  301. MODULE_LICENSE("GPL");