dmasound_q40.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:14k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  *  linux/drivers/sound/dmasound/dmasound_q40.c
  3.  *
  4.  *  Q40 DMA Sound Driver
  5.  *
  6.  *  See linux/drivers/sound/dmasound/dmasound_core.c for copyright and credits
  7.  *  prior to 28/01/2001
  8.  *
  9.  *  28/01/2001 [0.1] Iain Sandoe
  10.  *      - added versioning
  11.  *      - put in and populated the hardware_afmts field.
  12.  *             [0.2] - put in SNDCTL_DSP_GETCAPS value.
  13.  *        [0.3] - put in default hard/soft settings.
  14.  */
  15. #include <linux/module.h>
  16. #include <linux/init.h>
  17. #include <linux/slab.h>
  18. #include <linux/soundcard.h>
  19. #include <asm/uaccess.h>
  20. #include <asm/q40ints.h>
  21. #include <asm/q40_master.h>
  22. #include "dmasound.h"
  23. #define DMASOUND_Q40_REVISION 0
  24. #define DMASOUND_Q40_EDITION 3
  25. static int expand_bal; /* Balance factor for expanding (not volume!) */
  26. static int expand_data; /* Data for expanding */
  27. /*** Low level stuff *********************************************************/
  28. static void Q40Open(void);
  29. static void Q40Release(void);
  30. static void *Q40Alloc(unsigned int size, int flags);
  31. static void Q40Free(void *, unsigned int);
  32. static int Q40IrqInit(void);
  33. #ifdef MODULE
  34. static void Q40IrqCleanUp(void);
  35. #endif
  36. static void Q40Silence(void);
  37. static void Q40Init(void);
  38. static int Q40SetFormat(int format);
  39. static int Q40SetVolume(int volume);
  40. static void Q40PlayNextFrame(int index);
  41. static void Q40Play(void);
  42. static void Q40StereoInterrupt(int irq, void *dummy, struct pt_regs *fp);
  43. static void Q40MonoInterrupt(int irq, void *dummy, struct pt_regs *fp);
  44. static void Q40Interrupt(void);
  45. /*** Mid level stuff *********************************************************/
  46. /* userCount, frameUsed, frameLeft == byte counts */
  47. static ssize_t q40_ct_law(const u_char *userPtr, size_t userCount,
  48.    u_char frame[], ssize_t *frameUsed,
  49.    ssize_t frameLeft)
  50. {
  51. char *table = dmasound.soft.format == AFMT_MU_LAW ? dmasound_ulaw2dma8: dmasound_alaw2dma8;
  52. ssize_t count, used;
  53. u_char *p = (u_char *) &frame[*frameUsed];
  54. used = count = min_t(size_t, userCount, frameLeft);
  55. if (copy_from_user(p,userPtr,count))
  56.   return -EFAULT;
  57. while (count > 0) {
  58. *p = table[*p]+128;
  59. p++;
  60. count--;
  61. }
  62. *frameUsed += used ;
  63. return used;
  64. }
  65. static ssize_t q40_ct_s8(const u_char *userPtr, size_t userCount,
  66.   u_char frame[], ssize_t *frameUsed,
  67.   ssize_t frameLeft)
  68. {
  69. ssize_t count, used;
  70. u_char *p = (u_char *) &frame[*frameUsed];
  71. used = count = min_t(size_t, userCount, frameLeft);
  72. if (copy_from_user(p,userPtr,count))
  73.   return -EFAULT;
  74. while (count > 0) {
  75. *p = *p + 128;
  76. p++;
  77. count--;
  78. }
  79. *frameUsed += used;
  80. return used;
  81. }
  82. static ssize_t q40_ct_u8(const u_char *userPtr, size_t userCount,
  83.   u_char frame[], ssize_t *frameUsed,
  84.   ssize_t frameLeft)
  85. {
  86. ssize_t count, used;
  87. u_char *p = (u_char *) &frame[*frameUsed];
  88. used = count = min_t(size_t, userCount, frameLeft);
  89. if (copy_from_user(p,userPtr,count))
  90.   return -EFAULT;
  91. *frameUsed += used;
  92. return used;
  93. }
  94. /* a bit too complicated to optimise right now ..*/
  95. static ssize_t q40_ctx_law(const u_char *userPtr, size_t userCount,
  96.     u_char frame[], ssize_t *frameUsed,
  97.     ssize_t frameLeft)
  98. {
  99. unsigned char *table = (unsigned char *)
  100. (dmasound.soft.format == AFMT_MU_LAW ? dmasound_ulaw2dma8: dmasound_alaw2dma8);
  101. unsigned int data = expand_data;
  102. u_char *p = (u_char *) &frame[*frameUsed];
  103. int bal = expand_bal;
  104. int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
  105. int utotal, ftotal;
  106. ftotal = frameLeft;
  107. utotal = userCount;
  108. while (frameLeft) {
  109. u_char c;
  110. if (bal < 0) {
  111. if (userCount == 0)
  112. break;
  113. if (get_user(c, userPtr++))
  114. return -EFAULT;
  115. data = table[c];
  116. data += 0x80;
  117. userCount--;
  118. bal += hSpeed;
  119. }
  120. *p++ = data;
  121. frameLeft--;
  122. bal -= sSpeed;
  123. }
  124. expand_bal = bal;
  125. expand_data = data;
  126. *frameUsed += (ftotal - frameLeft);
  127. utotal -= userCount;
  128. return utotal;
  129. }
  130. static ssize_t q40_ctx_s8(const u_char *userPtr, size_t userCount,
  131.    u_char frame[], ssize_t *frameUsed,
  132.    ssize_t frameLeft)
  133. {
  134. u_char *p = (u_char *) &frame[*frameUsed];
  135. unsigned int data = expand_data;
  136. int bal = expand_bal;
  137. int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
  138. int utotal, ftotal;
  139. ftotal = frameLeft;
  140. utotal = userCount;
  141. while (frameLeft) {
  142. u_char c;
  143. if (bal < 0) {
  144. if (userCount == 0)
  145. break;
  146. if (get_user(c, userPtr++))
  147. return -EFAULT;
  148. data = c ;
  149. data += 0x80;
  150. userCount--;
  151. bal += hSpeed;
  152. }
  153. *p++ = data;
  154. frameLeft--;
  155. bal -= sSpeed;
  156. }
  157. expand_bal = bal;
  158. expand_data = data;
  159. *frameUsed += (ftotal - frameLeft);
  160. utotal -= userCount;
  161. return utotal;
  162. }
  163. static ssize_t q40_ctx_u8(const u_char *userPtr, size_t userCount,
  164.    u_char frame[], ssize_t *frameUsed,
  165.    ssize_t frameLeft)
  166. {
  167. u_char *p = (u_char *) &frame[*frameUsed];
  168. unsigned int data = expand_data;
  169. int bal = expand_bal;
  170. int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
  171. int utotal, ftotal;
  172. ftotal = frameLeft;
  173. utotal = userCount;
  174. while (frameLeft) {
  175. u_char c;
  176. if (bal < 0) {
  177. if (userCount == 0)
  178. break;
  179. if (get_user(c, userPtr++))
  180. return -EFAULT;
  181. data = c ;
  182. userCount--;
  183. bal += hSpeed;
  184. }
  185. *p++ = data;
  186. frameLeft--;
  187. bal -= sSpeed;
  188. }
  189. expand_bal = bal;
  190. expand_data = data;
  191. *frameUsed += (ftotal - frameLeft) ;
  192. utotal -= userCount;
  193. return utotal;
  194. }
  195. /* compressing versions */
  196. static ssize_t q40_ctc_law(const u_char *userPtr, size_t userCount,
  197.     u_char frame[], ssize_t *frameUsed,
  198.     ssize_t frameLeft)
  199. {
  200. unsigned char *table = (unsigned char *)
  201. (dmasound.soft.format == AFMT_MU_LAW ? dmasound_ulaw2dma8: dmasound_alaw2dma8);
  202. unsigned int data = expand_data;
  203. u_char *p = (u_char *) &frame[*frameUsed];
  204. int bal = expand_bal;
  205. int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
  206. int utotal, ftotal;
  207.  
  208. ftotal = frameLeft;
  209. utotal = userCount;
  210. while (frameLeft) {
  211. u_char c;
  212. while(bal<0) {
  213. if (userCount == 0)
  214. goto lout;
  215. if (!(bal<(-hSpeed))) {
  216. if (get_user(c, userPtr))
  217. return -EFAULT;
  218. data = 0x80 + table[c];
  219. }
  220. userPtr++;
  221. userCount--;
  222. bal += hSpeed;
  223. }
  224. *p++ = data;
  225. frameLeft--;
  226. bal -= sSpeed;
  227. }
  228.  lout:
  229. expand_bal = bal;
  230. expand_data = data;
  231. *frameUsed += (ftotal - frameLeft);
  232. utotal -= userCount;
  233. return utotal;
  234. }
  235. static ssize_t q40_ctc_s8(const u_char *userPtr, size_t userCount,
  236.    u_char frame[], ssize_t *frameUsed,
  237.    ssize_t frameLeft)
  238. {
  239. u_char *p = (u_char *) &frame[*frameUsed];
  240. unsigned int data = expand_data;
  241. int bal = expand_bal;
  242. int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
  243. int utotal, ftotal;
  244. ftotal = frameLeft;
  245. utotal = userCount;
  246. while (frameLeft) {
  247. u_char c;
  248. while (bal < 0) {
  249. if (userCount == 0)
  250. goto lout;
  251. if (!(bal<(-hSpeed))) {
  252. if (get_user(c, userPtr))
  253. return -EFAULT;
  254. data = c + 0x80;
  255. }
  256. userPtr++;
  257. userCount--;
  258. bal += hSpeed;
  259. }
  260. *p++ = data;
  261. frameLeft--;
  262. bal -= sSpeed;
  263. }
  264.  lout:
  265. expand_bal = bal;
  266. expand_data = data;
  267. *frameUsed += (ftotal - frameLeft);
  268. utotal -= userCount;
  269. return utotal;
  270. }
  271. static ssize_t q40_ctc_u8(const u_char *userPtr, size_t userCount,
  272.    u_char frame[], ssize_t *frameUsed,
  273.    ssize_t frameLeft)
  274. {
  275. u_char *p = (u_char *) &frame[*frameUsed];
  276. unsigned int data = expand_data;
  277. int bal = expand_bal;
  278. int hSpeed = dmasound.hard.speed, sSpeed = dmasound.soft.speed;
  279. int utotal, ftotal;
  280. ftotal = frameLeft;
  281. utotal = userCount;
  282. while (frameLeft) {
  283. u_char c;
  284. while (bal < 0) {
  285. if (userCount == 0)
  286. goto lout;
  287. if (!(bal<(-hSpeed))) {
  288. if (get_user(c, userPtr))
  289. return -EFAULT;
  290. data = c ;
  291. }
  292. userPtr++;
  293. userCount--;
  294. bal += hSpeed;
  295. }
  296. *p++ = data;
  297. frameLeft--;
  298. bal -= sSpeed;
  299. }
  300.  lout:
  301. expand_bal = bal;
  302. expand_data = data;
  303. *frameUsed += (ftotal - frameLeft) ;
  304. utotal -= userCount;
  305. return utotal;
  306. }
  307. static TRANS transQ40Normal = {
  308. q40_ct_law, q40_ct_law, q40_ct_s8, q40_ct_u8, NULL, NULL, NULL, NULL
  309. };
  310. static TRANS transQ40Expanding = {
  311. q40_ctx_law, q40_ctx_law, q40_ctx_s8, q40_ctx_u8, NULL, NULL, NULL, NULL
  312. };
  313. static TRANS transQ40Compressing = {
  314. q40_ctc_law, q40_ctc_law, q40_ctc_s8, q40_ctc_u8, NULL, NULL, NULL, NULL
  315. };
  316. /*** Low level stuff *********************************************************/
  317. static void Q40Open(void)
  318. {
  319. MOD_INC_USE_COUNT;
  320. }
  321. static void Q40Release(void)
  322. {
  323. MOD_DEC_USE_COUNT;
  324. }
  325. static void *Q40Alloc(unsigned int size, int flags)
  326. {
  327.          return kmalloc(size, flags); /* change to vmalloc */
  328. }
  329. static void Q40Free(void *ptr, unsigned int size)
  330. {
  331. kfree(ptr);
  332. }
  333. static int __init Q40IrqInit(void)
  334. {
  335. /* Register interrupt handler. */
  336. request_irq(Q40_IRQ_SAMPLE, Q40StereoInterrupt, 0,
  337.     "DMA sound", Q40Interrupt);
  338. return(1);
  339. }
  340. #ifdef MODULE
  341. static void Q40IrqCleanUp(void)
  342. {
  343.         master_outb(0,SAMPLE_ENABLE_REG);
  344. free_irq(Q40_IRQ_SAMPLE, Q40Interrupt);
  345. }
  346. #endif /* MODULE */
  347. static void Q40Silence(void)
  348. {
  349.         master_outb(0,SAMPLE_ENABLE_REG);
  350. *DAC_LEFT=*DAC_RIGHT=127;
  351. }
  352. static char *q40_pp=NULL;
  353. static unsigned int q40_sc=0;
  354. static void Q40PlayNextFrame(int index)
  355. {
  356. u_char *start;
  357. u_long size;
  358. u_char speed;
  359. /* used by Q40Play() if all doubts whether there really is something
  360.  * to be played are already wiped out.
  361.  */
  362. start = write_sq.buffers[write_sq.front];
  363. size = (write_sq.count == index ? write_sq.rear_size : write_sq.block_size);
  364. q40_pp=start;
  365. q40_sc=size;
  366. write_sq.front = (write_sq.front+1) % write_sq.max_count;
  367. write_sq.active++;
  368. speed=(dmasound.hard.speed==10000 ? 0 : 1);
  369. master_outb( 0,SAMPLE_ENABLE_REG);
  370. free_irq(Q40_IRQ_SAMPLE, Q40Interrupt);
  371. if (dmasound.soft.stereo)
  372.    request_irq(Q40_IRQ_SAMPLE, Q40StereoInterrupt, 0,
  373.     "Q40 sound", Q40Interrupt);
  374.   else
  375.         request_irq(Q40_IRQ_SAMPLE, Q40MonoInterrupt, 0,
  376.     "Q40 sound", Q40Interrupt);
  377. master_outb( speed, SAMPLE_RATE_REG);
  378. master_outb( 1,SAMPLE_CLEAR_REG);
  379. master_outb( 1,SAMPLE_ENABLE_REG);
  380. }
  381. static void Q40Play(void)
  382. {
  383.         unsigned long flags;
  384. if (write_sq.active || write_sq.count<=0 ) {
  385. /* There's already a frame loaded */
  386. return;
  387. }
  388. /* nothing in the queue */
  389. if (write_sq.count <= 1 && write_sq.rear_size < write_sq.block_size && !write_sq.syncing) {
  390.          /* hmmm, the only existing frame is not
  391.   * yet filled and we're not syncing?
  392.   */
  393.          return;
  394. }
  395. save_flags(flags); cli();
  396. Q40PlayNextFrame(1);
  397. restore_flags(flags);
  398. }
  399. static void Q40StereoInterrupt(int irq, void *dummy, struct pt_regs *fp)
  400. {
  401.         if (q40_sc>1){
  402.             *DAC_LEFT=*q40_pp++;
  403.     *DAC_RIGHT=*q40_pp++;
  404.     q40_sc -=2;
  405.     master_outb(1,SAMPLE_CLEAR_REG);
  406. }else Q40Interrupt();
  407. }
  408. static void Q40MonoInterrupt(int irq, void *dummy, struct pt_regs *fp)
  409. {
  410.         if (q40_sc>0){
  411.             *DAC_LEFT=*q40_pp;
  412.     *DAC_RIGHT=*q40_pp++;
  413.     q40_sc --;
  414.     master_outb(1,SAMPLE_CLEAR_REG);
  415. }else Q40Interrupt();
  416. }
  417. static void Q40Interrupt(void)
  418. {
  419. if (!write_sq.active) {
  420.           /* playing was interrupted and sq_reset() has already cleared
  421.    * the sq variables, so better don't do anything here.
  422.    */
  423.            WAKE_UP(write_sq.sync_queue);
  424.    master_outb(0,SAMPLE_ENABLE_REG); /* better safe */
  425.    goto exit;
  426. } else write_sq.active=0;
  427. write_sq.count--;
  428. Q40Play();
  429. if (q40_sc<2)
  430.       { /* there was nothing to play, disable irq */
  431. master_outb(0,SAMPLE_ENABLE_REG);
  432. *DAC_LEFT=*DAC_RIGHT=127;
  433.       }
  434. WAKE_UP(write_sq.action_queue);
  435.  exit:
  436. master_outb(1,SAMPLE_CLEAR_REG);
  437. }
  438. static void Q40Init(void)
  439. {
  440. int i, idx;
  441. const int freq[] = {10000, 20000};
  442. /* search a frequency that fits into the allowed error range */
  443. idx = -1;
  444. for (i = 0; i < 2; i++)
  445. if ((100 * abs(dmasound.soft.speed - freq[i]) / freq[i]) <= catchRadius)
  446. idx = i;
  447. dmasound.hard = dmasound.soft;
  448. /*sound.hard.stereo=1;*/ /* no longer true */
  449. dmasound.hard.size=8;
  450. if (idx > -1) {
  451. dmasound.soft.speed = freq[idx];
  452. dmasound.trans_write = &transQ40Normal;
  453. } else
  454. dmasound.trans_write = &transQ40Expanding;
  455. Q40Silence();
  456. if (dmasound.hard.speed > 20200) {
  457. /* squeeze the sound, we do that */
  458. dmasound.hard.speed = 20000;
  459. dmasound.trans_write = &transQ40Compressing;
  460. } else if (dmasound.hard.speed > 10000) {
  461. dmasound.hard.speed = 20000;
  462. } else {
  463. dmasound.hard.speed = 10000;
  464. }
  465. expand_bal = -dmasound.soft.speed;
  466. }
  467. static int Q40SetFormat(int format)
  468. {
  469. /* Q40 sound supports only 8bit modes */
  470. switch (format) {
  471. case AFMT_QUERY:
  472. return(dmasound.soft.format);
  473. case AFMT_MU_LAW:
  474. case AFMT_A_LAW:
  475. case AFMT_S8:
  476. case AFMT_U8:
  477. break;
  478. default:
  479. format = AFMT_S8;
  480. }
  481. dmasound.soft.format = format;
  482. dmasound.soft.size = 8;
  483. if (dmasound.minDev == SND_DEV_DSP) {
  484. dmasound.dsp.format = format;
  485. dmasound.dsp.size = 8;
  486. }
  487. Q40Init();
  488. return(format);
  489. }
  490. static int Q40SetVolume(int volume)
  491. {
  492.     return 0;
  493. }
  494. /*** Machine definitions *****************************************************/
  495. static SETTINGS def_hard = {
  496. format: AFMT_U8,
  497. stereo: 0,
  498. size: 8,
  499. speed: 10000
  500. } ;
  501. static SETTINGS def_soft = {
  502. format: AFMT_U8,
  503. stereo: 0,
  504. size: 8,
  505. speed: 8000
  506. } ;
  507. static MACHINE machQ40 = {
  508. name: "Q40",
  509. name2: "Q40",
  510. open: Q40Open,
  511. release: Q40Release,
  512. dma_alloc: Q40Alloc,
  513. dma_free: Q40Free,
  514. irqinit: Q40IrqInit,
  515. #ifdef MODULE
  516. irqcleanup: Q40IrqCleanUp,
  517. #endif /* MODULE */
  518. init: Q40Init,
  519. silence: Q40Silence,
  520. setFormat: Q40SetFormat,
  521. setVolume: Q40SetVolume,
  522. play: Q40Play,
  523.   min_dsp_speed: 10000,
  524. version: ((DMASOUND_Q40_REVISION<<8) | DMASOUND_Q40_EDITION),
  525. hardware_afmts: AFMT_U8, /* h'ware-supported formats *only* here */
  526.         capabilities: DSP_CAP_BATCH  /* As per SNDCTL_DSP_GETCAPS */
  527. };
  528. /*** Config & Setup **********************************************************/
  529. int __init dmasound_q40_init(void)
  530. {
  531. if (MACH_IS_Q40) {
  532.     dmasound.mach = machQ40;
  533.     dmasound.mach.default_hard = def_hard ;
  534.     dmasound.mach.default_soft = def_soft ;
  535.     return dmasound_init();
  536. } else
  537.     return -ENODEV;
  538. }
  539. static void __exit dmasound_q40_cleanup(void)
  540. {
  541. dmasound_deinit();
  542. }
  543. module_init(dmasound_q40_init);
  544. module_exit(dmasound_q40_cleanup);
  545. MODULE_DESCRIPTION("Q40/Q60 sound driver");
  546. MODULE_LICENSE("GPL");