passthrough.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. /*
  2. **********************************************************************
  3. * passthrough.c -- Emu10k1 digital passthrough
  4. * Copyright (C) 2001 Juha Yrjölä <jyrjola@cc.hut.fi>
  5. *
  6. **********************************************************************
  7. *
  8. * Date Author Summary of changes
  9. * ---- ------ ------------------
  10. * May 15, 2001 Juha Yrjölä base code release
  11. *
  12. **********************************************************************
  13. *
  14. * This program is free software; you can redistribute it and/or
  15. * modify it under the terms of the GNU General Public License as
  16. * published by the Free Software Foundation; either version 2 of
  17. * the License, or (at your option) any later version.
  18. *
  19. * This program is distributed in the hope that it will be useful,
  20. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22. * GNU General Public License for more details.
  23. *
  24. * You should have received a copy of the GNU General Public
  25. * License along with this program; if not, write to the Free
  26. * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
  27. * USA.
  28. *
  29. **********************************************************************
  30. */
  31. #include <linux/module.h>
  32. #include <linux/poll.h>
  33. #include <linux/slab.h>
  34. #include <linux/bitops.h>
  35. #include <asm/io.h>
  36. #include <linux/sched.h>
  37. #include <linux/smp_lock.h>
  38. #include "hwaccess.h"
  39. #include "cardwo.h"
  40. #include "cardwi.h"
  41. #include "recmgr.h"
  42. #include "irqmgr.h"
  43. #include "audio.h"
  44. #include "8010.h"
  45. static void pt_putsamples(struct pt_data *pt, u16 *ptr, u16 left, u16 right)
  46. {
  47. unsigned int idx;
  48. ptr[pt->copyptr] = left;
  49. idx = pt->copyptr + PT_SAMPLES/2;
  50. idx %= PT_SAMPLES;
  51. ptr[idx] = right;
  52. }
  53. static inline int pt_can_write(struct pt_data *pt)
  54. {
  55. return pt->blocks_copied < pt->blocks_played + 8;
  56. }
  57. static int pt_wait_for_write(struct emu10k1_wavedevice *wavedev, int nonblock)
  58. {
  59. struct emu10k1_card *card = wavedev->card;
  60. struct pt_data *pt = &card->pt;
  61. if (nonblock && !pt_can_write(pt))
  62. return -EAGAIN;
  63. while (!pt_can_write(pt) && pt->state != PT_STATE_INACTIVE) {
  64. interruptible_sleep_on(&pt->wait);
  65. if (signal_pending(current))
  66. return -ERESTARTSYS;
  67. }
  68. if (pt->state == PT_STATE_INACTIVE)
  69. return -EAGAIN;
  70. return 0;
  71. }
  72. static int pt_putblock(struct emu10k1_wavedevice *wave_dev, u16 *block, int nonblock)
  73. {
  74. struct woinst *woinst = wave_dev->woinst;
  75. struct emu10k1_card *card = wave_dev->card;
  76. struct pt_data *pt = &card->pt;
  77. u16 *ptr = (u16 *) card->tankmem.addr;
  78. int i = 0, r;
  79. unsigned long flags;
  80. r = pt_wait_for_write(wave_dev, nonblock);
  81. if (r < 0)
  82. return r;
  83. spin_lock_irqsave(&card->pt.lock, flags);
  84. while (i < PT_BLOCKSAMPLES) {
  85. pt_putsamples(pt, ptr, block[2*i], block[2*i+1]);
  86. if (pt->copyptr == 0)
  87. pt->copyptr = PT_SAMPLES;
  88. pt->copyptr--;
  89. i++;
  90. }
  91. woinst->total_copied += PT_BLOCKSIZE;
  92. pt->blocks_copied++;
  93. if (pt->blocks_copied >= 4 && pt->state != PT_STATE_PLAYING) {
  94. DPF(2, "activating digital pass-through playback\n");
  95. sblive_writeptr(card, GPR_BASE + pt->enable_gpr, 0, 1);
  96. pt->state = PT_STATE_PLAYING;
  97. }
  98. spin_unlock_irqrestore(&card->pt.lock, flags);
  99. return 0;
  100. }
  101. int emu10k1_pt_setup(struct emu10k1_wavedevice *wave_dev)
  102. {
  103. u32 bits;
  104. struct emu10k1_card *card = wave_dev->card;
  105. struct pt_data *pt = &card->pt;
  106. int i;
  107. for (i = 0; i < 3; i++) {
  108. pt->old_spcs[i] = sblive_readptr(card, SPCS0 + i, 0);
  109. if (pt->spcs_to_use & (1 << i)) {
  110. DPD(2, "using S/PDIF port %d\n", i);
  111. bits = SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 |
  112. SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS |
  113. 0x00001200 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT;
  114. if (pt->ac3data)
  115. bits |= SPCS_NOTAUDIODATA;
  116. sblive_writeptr(card, SPCS0 + i, 0, bits);
  117. }
  118. }
  119. return 0;
  120. }
  121. ssize_t emu10k1_pt_write(struct file *file, const char __user *buffer, size_t count)
  122. {
  123. struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data;
  124. struct emu10k1_card *card = wave_dev->card;
  125. struct pt_data *pt = &card->pt;
  126. int nonblock, i, r, blocks, blocks_copied, bytes_copied = 0;
  127. DPD(3, "emu10k1_pt_write(): %d bytes\n", count);
  128. nonblock = file->f_flags & O_NONBLOCK;
  129. if (card->tankmem.size < PT_SAMPLES*2)
  130. return -EFAULT;
  131. if (pt->state == PT_STATE_INACTIVE) {
  132. DPF(2, "bufptr init\n");
  133. pt->playptr = PT_SAMPLES-1;
  134. pt->copyptr = PT_INITPTR;
  135. pt->blocks_played = pt->blocks_copied = 0;
  136. memset(card->tankmem.addr, 0, card->tankmem.size);
  137. pt->state = PT_STATE_ACTIVATED;
  138. pt->buf = kmalloc(PT_BLOCKSIZE, GFP_KERNEL);
  139. pt->prepend_size = 0;
  140. if (pt->buf == NULL)
  141. return -ENOMEM;
  142. emu10k1_pt_setup(wave_dev);
  143. }
  144. if (pt->prepend_size) {
  145. int needed = PT_BLOCKSIZE - pt->prepend_size;
  146. DPD(3, "prepend size %d, prepending %d bytes\n", pt->prepend_size, needed);
  147. if (count < needed) {
  148. if (copy_from_user(pt->buf + pt->prepend_size,
  149. buffer, count))
  150. return -EFAULT;
  151. pt->prepend_size += count;
  152. DPD(3, "prepend size now %d\n", pt->prepend_size);
  153. return count;
  154. }
  155. if (copy_from_user(pt->buf + pt->prepend_size, buffer, needed))
  156. return -EFAULT;
  157. r = pt_putblock(wave_dev, (u16 *) pt->buf, nonblock);
  158. if (r)
  159. return r;
  160. bytes_copied += needed;
  161. pt->prepend_size = 0;
  162. }
  163. blocks = (count-bytes_copied)/PT_BLOCKSIZE;
  164. blocks_copied = 0;
  165. while (blocks > 0) {
  166. u16 __user *bufptr = (u16 __user *) buffer + (bytes_copied/2);
  167. if (copy_from_user(pt->buf, bufptr, PT_BLOCKSIZE))
  168. return -EFAULT;
  169. r = pt_putblock(wave_dev, (u16 *)pt->buf, nonblock);
  170. if (r) {
  171. if (bytes_copied)
  172. return bytes_copied;
  173. else
  174. return r;
  175. }
  176. bytes_copied += PT_BLOCKSIZE;
  177. blocks--;
  178. blocks_copied++;
  179. }
  180. i = count - bytes_copied;
  181. if (i) {
  182. pt->prepend_size = i;
  183. if (copy_from_user(pt->buf, buffer + bytes_copied, i))
  184. return -EFAULT;
  185. bytes_copied += i;
  186. DPD(3, "filling prepend buffer with %d bytes", i);
  187. }
  188. return bytes_copied;
  189. }
  190. void emu10k1_pt_stop(struct emu10k1_card *card)
  191. {
  192. struct pt_data *pt = &card->pt;
  193. int i;
  194. if (pt->state != PT_STATE_INACTIVE) {
  195. DPF(2, "digital pass-through stopped\n");
  196. sblive_writeptr(card, (card->is_audigy ? A_GPR_BASE : GPR_BASE) + pt->enable_gpr, 0, 0);
  197. for (i = 0; i < 3; i++) {
  198. if (pt->spcs_to_use & (1 << i))
  199. sblive_writeptr(card, SPCS0 + i, 0, pt->old_spcs[i]);
  200. }
  201. pt->state = PT_STATE_INACTIVE;
  202. kfree(pt->buf);
  203. }
  204. }
  205. void emu10k1_pt_waveout_update(struct emu10k1_wavedevice *wave_dev)
  206. {
  207. struct woinst *woinst = wave_dev->woinst;
  208. struct pt_data *pt = &wave_dev->card->pt;
  209. u32 pos;
  210. if (pt->state == PT_STATE_PLAYING && pt->pos_gpr >= 0) {
  211. pos = sblive_readptr(wave_dev->card, GPR_BASE + pt->pos_gpr, 0);
  212. if (pos > PT_BLOCKSAMPLES)
  213. pos = PT_BLOCKSAMPLES;
  214. pos = 4 * (PT_BLOCKSAMPLES - pos);
  215. } else
  216. pos = 0;
  217. woinst->total_played = pt->blocks_played * woinst->buffer.fragment_size + pos;
  218. woinst->buffer.hw_pos = pos;
  219. }