diff options
author | James Courtier-Dutton <James@superbug.co.uk> | 2005-03-26 13:35:29 -0500 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2005-05-29 03:00:24 -0400 |
commit | 6e4abc40fc125b1dcc2792eacac17606a4d86043 (patch) | |
tree | 4b06290dd6a43d809b8762752166ea9b854b6f5f /sound/pci | |
parent | d05b2817d859a2a2f2c3d5c056b688559fdbcc2b (diff) |
[ALSA] Adds Capture to P16V chip.
EMU10K1/EMU10K2 driver
One can select which capture source, but one cannot yet set volumes.
Signed-off-by: James Courtier-Dutton <James@superbug.co.uk>
Diffstat (limited to 'sound/pci')
-rw-r--r-- | sound/pci/emu10k1/irq.c | 46 | ||||
-rw-r--r-- | sound/pci/emu10k1/p16v.c | 257 |
2 files changed, 271 insertions, 32 deletions
diff --git a/sound/pci/emu10k1/irq.c b/sound/pci/emu10k1/irq.c index b81a7cafff39..cd8460d56752 100644 --- a/sound/pci/emu10k1/irq.c +++ b/sound/pci/emu10k1/irq.c | |||
@@ -37,7 +37,7 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
37 | int handled = 0; | 37 | int handled = 0; |
38 | 38 | ||
39 | while ((status = inl(emu->port + IPR)) != 0) { | 39 | while ((status = inl(emu->port + IPR)) != 0) { |
40 | // printk("irq - status = 0x%x\n", status); | 40 | //printk("emu10k1 irq - status = 0x%x\n", status); |
41 | orig_status = status; | 41 | orig_status = status; |
42 | handled = 1; | 42 | handled = 1; |
43 | if (status & IPR_PCIERROR) { | 43 | if (status & IPR_PCIERROR) { |
@@ -147,9 +147,36 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
147 | snd_emu10k1_intr_disable(emu, INTE_FXDSPENABLE); | 147 | snd_emu10k1_intr_disable(emu, INTE_FXDSPENABLE); |
148 | status &= ~IPR_FXDSP; | 148 | status &= ~IPR_FXDSP; |
149 | } | 149 | } |
150 | if (status & IPR_P16V) { | ||
151 | while ((status2 = inl(emu->port + IPR2)) != 0) { | ||
152 | u32 mask = INTE2_PLAYBACK_CH_0_LOOP; /* Full Loop */ | ||
153 | emu10k1_voice_t *pvoice = &(emu->p16v_voices[0]); | ||
154 | emu10k1_voice_t *cvoice = &(emu->p16v_capture_voice); | ||
155 | |||
156 | //printk(KERN_INFO "status2=0x%x\n", status2); | ||
157 | orig_status2 = status2; | ||
158 | if(status2 & mask) { | ||
159 | if(pvoice->use) { | ||
160 | snd_pcm_period_elapsed(pvoice->epcm->substream); | ||
161 | } else { | ||
162 | snd_printk(KERN_ERR "p16v: status: 0x%08x, mask=0x%08x, pvoice=%p, use=%d\n", status2, mask, pvoice, pvoice->use); | ||
163 | } | ||
164 | } | ||
165 | if(status2 & 0x110000) { | ||
166 | //printk(KERN_INFO "capture int found\n"); | ||
167 | if(cvoice->use) { | ||
168 | //printk(KERN_INFO "capture period_elapsed\n"); | ||
169 | snd_pcm_period_elapsed(cvoice->epcm->substream); | ||
170 | } | ||
171 | } | ||
172 | outl(orig_status2, emu->port + IPR2); /* ack all */ | ||
173 | } | ||
174 | status &= ~IPR_P16V; | ||
175 | } | ||
176 | |||
150 | if (status) { | 177 | if (status) { |
151 | unsigned int bits; | 178 | unsigned int bits; |
152 | //snd_printk(KERN_ERR "emu10k1: unhandled interrupt: 0x%08x\n", status); | 179 | snd_printk(KERN_ERR "emu10k1: unhandled interrupt: 0x%08x\n", status); |
153 | //make sure any interrupts we don't handle are disabled: | 180 | //make sure any interrupts we don't handle are disabled: |
154 | bits = INTE_FXDSPENABLE | | 181 | bits = INTE_FXDSPENABLE | |
155 | INTE_PCIERRORENABLE | | 182 | INTE_PCIERRORENABLE | |
@@ -170,20 +197,5 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
170 | } | 197 | } |
171 | outl(orig_status, emu->port + IPR); /* ack all */ | 198 | outl(orig_status, emu->port + IPR); /* ack all */ |
172 | } | 199 | } |
173 | if (emu->audigy && emu->revision == 4) { /* P16V */ | ||
174 | while ((status2 = inl(emu->port + IPR2)) != 0) { | ||
175 | u32 mask = INTE2_PLAYBACK_CH_0_LOOP; /* Full Loop */ | ||
176 | emu10k1_voice_t *pvoice = &(emu->p16v_voices[0]); | ||
177 | orig_status2 = status2; | ||
178 | if(status2 & mask) { | ||
179 | if(pvoice->use) { | ||
180 | snd_pcm_period_elapsed(pvoice->epcm->substream); | ||
181 | } else { | ||
182 | snd_printk(KERN_ERR "p16v: status: 0x%08x, mask=0x%08x, pvoice=%p, use=%d\n", status2, mask, pvoice, pvoice->use); | ||
183 | } | ||
184 | } | ||
185 | outl(orig_status2, emu->port + IPR2); /* ack all */ | ||
186 | } | ||
187 | } | ||
188 | return IRQ_RETVAL(handled); | 200 | return IRQ_RETVAL(handled); |
189 | } | 201 | } |
diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index d03cb2fefc9e..dd6ce9927e10 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c | |||
@@ -132,9 +132,29 @@ static snd_pcm_hardware_t snd_p16v_playback_hw = { | |||
132 | .fifo_size = 0, | 132 | .fifo_size = 0, |
133 | }; | 133 | }; |
134 | 134 | ||
135 | static snd_pcm_hardware_t snd_p16v_capture_hw = { | ||
136 | .info = (SNDRV_PCM_INFO_MMAP | | ||
137 | SNDRV_PCM_INFO_INTERLEAVED | | ||
138 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
139 | SNDRV_PCM_INFO_MMAP_VALID), | ||
140 | .formats = SNDRV_PCM_FMTBIT_S32_LE, | ||
141 | .rates = SNDRV_PCM_RATE_48000, | ||
142 | .rate_min = 48000, | ||
143 | .rate_max = 48000, | ||
144 | .channels_min = 2, | ||
145 | .channels_max = 2, | ||
146 | .buffer_bytes_max = (32*1024), | ||
147 | .period_bytes_min = 64, | ||
148 | .period_bytes_max = (16*1024), | ||
149 | .periods_min = 2, | ||
150 | .periods_max = 2, | ||
151 | .fifo_size = 0, | ||
152 | }; | ||
153 | |||
154 | |||
135 | static void snd_p16v_pcm_free_substream(snd_pcm_runtime_t *runtime) | 155 | static void snd_p16v_pcm_free_substream(snd_pcm_runtime_t *runtime) |
136 | { | 156 | { |
137 | snd_pcm_t *epcm = runtime->private_data; | 157 | emu10k1_pcm_t *epcm = runtime->private_data; |
138 | 158 | ||
139 | if (epcm) { | 159 | if (epcm) { |
140 | //snd_printk("epcm free: %p\n", epcm); | 160 | //snd_printk("epcm free: %p\n", epcm); |
@@ -178,15 +198,63 @@ static int snd_p16v_pcm_open_playback_channel(snd_pcm_substream_t *substream, in | |||
178 | 198 | ||
179 | return 0; | 199 | return 0; |
180 | } | 200 | } |
201 | /* open_capture callback */ | ||
202 | static int snd_p16v_pcm_open_capture_channel(snd_pcm_substream_t *substream, int channel_id) | ||
203 | { | ||
204 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | ||
205 | emu10k1_voice_t *channel = &(emu->p16v_capture_voice); | ||
206 | emu10k1_pcm_t *epcm; | ||
207 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
208 | int err; | ||
209 | |||
210 | epcm = kcalloc(1, sizeof(*epcm), GFP_KERNEL); | ||
211 | //snd_printk("epcm kcalloc: %p\n", epcm); | ||
212 | |||
213 | if (epcm == NULL) | ||
214 | return -ENOMEM; | ||
215 | epcm->emu = emu; | ||
216 | epcm->substream = substream; | ||
217 | //snd_printk("epcm device=%d, channel_id=%d\n", substream->pcm->device, channel_id); | ||
218 | |||
219 | runtime->private_data = epcm; | ||
220 | runtime->private_free = snd_p16v_pcm_free_substream; | ||
221 | |||
222 | runtime->hw = snd_p16v_capture_hw; | ||
223 | |||
224 | channel->emu = emu; | ||
225 | channel->number = channel_id; | ||
226 | |||
227 | channel->use=1; | ||
228 | //snd_printk("p16v: open channel_id=%d, channel=%p, use=0x%x\n", channel_id, channel, channel->use); | ||
229 | //printk("open:channel_id=%d, chip=%p, channel=%p\n",channel_id, chip, channel); | ||
230 | //channel->interrupt = snd_p16v_pcm_channel_interrupt; | ||
231 | channel->epcm=epcm; | ||
232 | if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) | ||
233 | return err; | ||
234 | |||
235 | return 0; | ||
236 | } | ||
237 | |||
181 | 238 | ||
182 | /* close callback */ | 239 | /* close callback */ |
183 | static int snd_p16v_pcm_close_playback(snd_pcm_substream_t *substream) | 240 | static int snd_p16v_pcm_close_playback(snd_pcm_substream_t *substream) |
184 | { | 241 | { |
185 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | 242 | emu10k1_t *emu = snd_pcm_substream_chip(substream); |
186 | //snd_pcm_runtime_t *runtime = substream->runtime; | 243 | //snd_pcm_runtime_t *runtime = substream->runtime; |
187 | //emu10k1_pcm_t *epcm = runtime->private_data; | 244 | //emu10k1_pcm_t *epcm = runtime->private_data; |
188 | emu->p16v_voices[substream->pcm->device - emu->p16v_device_offset].use=0; | 245 | emu->p16v_voices[substream->pcm->device - emu->p16v_device_offset].use=0; |
189 | /* FIXME: maybe zero others */ | 246 | /* FIXME: maybe zero others */ |
247 | return 0; | ||
248 | } | ||
249 | |||
250 | /* close callback */ | ||
251 | static int snd_p16v_pcm_close_capture(snd_pcm_substream_t *substream) | ||
252 | { | ||
253 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | ||
254 | //snd_pcm_runtime_t *runtime = substream->runtime; | ||
255 | //emu10k1_pcm_t *epcm = runtime->private_data; | ||
256 | emu->p16v_capture_voice.use=0; | ||
257 | /* FIXME: maybe zero others */ | ||
190 | return 0; | 258 | return 0; |
191 | } | 259 | } |
192 | 260 | ||
@@ -195,36 +263,55 @@ static int snd_p16v_pcm_open_playback_front(snd_pcm_substream_t *substream) | |||
195 | return snd_p16v_pcm_open_playback_channel(substream, PCM_FRONT_CHANNEL); | 263 | return snd_p16v_pcm_open_playback_channel(substream, PCM_FRONT_CHANNEL); |
196 | } | 264 | } |
197 | 265 | ||
266 | static int snd_p16v_pcm_open_capture(snd_pcm_substream_t *substream) | ||
267 | { | ||
268 | // Only using channel 0 for now, but the card has 2 channels. | ||
269 | return snd_p16v_pcm_open_capture_channel(substream, 0); | ||
270 | } | ||
271 | |||
198 | /* hw_params callback */ | 272 | /* hw_params callback */ |
199 | static int snd_p16v_pcm_hw_params_playback(snd_pcm_substream_t *substream, | 273 | static int snd_p16v_pcm_hw_params_playback(snd_pcm_substream_t *substream, |
200 | snd_pcm_hw_params_t * hw_params) | 274 | snd_pcm_hw_params_t * hw_params) |
201 | { | 275 | { |
202 | int result; | 276 | int result; |
203 | //snd_printk("hw_params alloc: substream=%p\n", substream); | ||
204 | result = snd_pcm_lib_malloc_pages(substream, | 277 | result = snd_pcm_lib_malloc_pages(substream, |
205 | params_buffer_bytes(hw_params)); | 278 | params_buffer_bytes(hw_params)); |
206 | //snd_printk("hw_params alloc: result=%d\n", result); | ||
207 | //dump_stack(); | ||
208 | return result; | 279 | return result; |
209 | } | 280 | } |
210 | 281 | ||
282 | /* hw_params callback */ | ||
283 | static int snd_p16v_pcm_hw_params_capture(snd_pcm_substream_t *substream, | ||
284 | snd_pcm_hw_params_t * hw_params) | ||
285 | { | ||
286 | int result; | ||
287 | result = snd_pcm_lib_malloc_pages(substream, | ||
288 | params_buffer_bytes(hw_params)); | ||
289 | return result; | ||
290 | } | ||
291 | |||
292 | |||
211 | /* hw_free callback */ | 293 | /* hw_free callback */ |
212 | static int snd_p16v_pcm_hw_free_playback(snd_pcm_substream_t *substream) | 294 | static int snd_p16v_pcm_hw_free_playback(snd_pcm_substream_t *substream) |
213 | { | 295 | { |
214 | int result; | 296 | int result; |
215 | //snd_printk("hw_params free: substream=%p\n", substream); | ||
216 | result = snd_pcm_lib_free_pages(substream); | 297 | result = snd_pcm_lib_free_pages(substream); |
217 | //snd_printk("hw_params free: result=%d\n", result); | ||
218 | //dump_stack(); | ||
219 | return result; | 298 | return result; |
220 | } | 299 | } |
221 | 300 | ||
301 | /* hw_free callback */ | ||
302 | static int snd_p16v_pcm_hw_free_capture(snd_pcm_substream_t *substream) | ||
303 | { | ||
304 | int result; | ||
305 | result = snd_pcm_lib_free_pages(substream); | ||
306 | return result; | ||
307 | } | ||
308 | |||
309 | |||
222 | /* prepare playback callback */ | 310 | /* prepare playback callback */ |
223 | static int snd_p16v_pcm_prepare_playback(snd_pcm_substream_t *substream) | 311 | static int snd_p16v_pcm_prepare_playback(snd_pcm_substream_t *substream) |
224 | { | 312 | { |
225 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | 313 | emu10k1_t *emu = snd_pcm_substream_chip(substream); |
226 | snd_pcm_runtime_t *runtime = substream->runtime; | 314 | snd_pcm_runtime_t *runtime = substream->runtime; |
227 | //emu10k1_pcm_t *epcm = runtime->private_data; | ||
228 | int channel = substream->pcm->device - emu->p16v_device_offset; | 315 | int channel = substream->pcm->device - emu->p16v_device_offset; |
229 | u32 *table_base = (u32 *)(emu->p16v_buffer.area+(8*16*channel)); | 316 | u32 *table_base = (u32 *)(emu->p16v_buffer.area+(8*16*channel)); |
230 | u32 period_size_bytes = frames_to_bytes(runtime, runtime->period_size); | 317 | u32 period_size_bytes = frames_to_bytes(runtime, runtime->period_size); |
@@ -253,7 +340,7 @@ static int snd_p16v_pcm_prepare_playback(snd_pcm_substream_t *substream) | |||
253 | break; | 340 | break; |
254 | } | 341 | } |
255 | /* FIXME: Check emu->buffer.size before actually writing to it. */ | 342 | /* FIXME: Check emu->buffer.size before actually writing to it. */ |
256 | for(i=0; i < runtime->periods; i++) { | 343 | for(i=0; i < runtime->periods; i++) { |
257 | table_base[i*2]=runtime->dma_addr+(i*period_size_bytes); | 344 | table_base[i*2]=runtime->dma_addr+(i*period_size_bytes); |
258 | table_base[(i*2)+1]=period_size_bytes<<16; | 345 | table_base[(i*2)+1]=period_size_bytes<<16; |
259 | } | 346 | } |
@@ -270,6 +357,23 @@ static int snd_p16v_pcm_prepare_playback(snd_pcm_substream_t *substream) | |||
270 | return 0; | 357 | return 0; |
271 | } | 358 | } |
272 | 359 | ||
360 | /* prepare capture callback */ | ||
361 | static int snd_p16v_pcm_prepare_capture(snd_pcm_substream_t *substream) | ||
362 | { | ||
363 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | ||
364 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
365 | int channel = substream->pcm->device - emu->p16v_device_offset; | ||
366 | //printk("prepare:channel_number=%d, rate=%d, format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, frames_to_bytes=%d\n",channel, runtime->rate, runtime->format, runtime->channels, runtime->buffer_size, runtime->period_size, frames_to_bytes(runtime, 1)); | ||
367 | snd_emu10k1_ptr20_write(emu, 0x13, channel, 0); | ||
368 | snd_emu10k1_ptr20_write(emu, CAPTURE_DMA_ADDR, channel, runtime->dma_addr); | ||
369 | snd_emu10k1_ptr20_write(emu, CAPTURE_BUFFER_SIZE, channel, frames_to_bytes(runtime, runtime->buffer_size)<<16); // buffer size in bytes | ||
370 | snd_emu10k1_ptr20_write(emu, CAPTURE_POINTER, channel, 0); | ||
371 | //snd_emu10k1_ptr20_write(emu, CAPTURE_SOURCE, 0x0, 0x333300e4); /* Select MIC or Line in */ | ||
372 | //snd_emu10k1_ptr20_write(emu, EXTENDED_INT_MASK, 0, snd_emu10k1_ptr20_read(emu, EXTENDED_INT_MASK, 0) | (0x110000<<channel)); | ||
373 | |||
374 | return 0; | ||
375 | } | ||
376 | |||
273 | static void snd_p16v_intr_enable(emu10k1_t *emu, unsigned int intrenb) | 377 | static void snd_p16v_intr_enable(emu10k1_t *emu, unsigned int intrenb) |
274 | { | 378 | { |
275 | unsigned long flags; | 379 | unsigned long flags; |
@@ -345,6 +449,36 @@ static int snd_p16v_pcm_trigger_playback(snd_pcm_substream_t *substream, | |||
345 | return result; | 449 | return result; |
346 | } | 450 | } |
347 | 451 | ||
452 | /* trigger_capture callback */ | ||
453 | static int snd_p16v_pcm_trigger_capture(snd_pcm_substream_t *substream, | ||
454 | int cmd) | ||
455 | { | ||
456 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | ||
457 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
458 | emu10k1_pcm_t *epcm = runtime->private_data; | ||
459 | int channel = 0; | ||
460 | int result = 0; | ||
461 | u32 inte = INTE2_CAPTURE_CH_0_LOOP | INTE2_CAPTURE_CH_0_HALF_LOOP; | ||
462 | |||
463 | switch (cmd) { | ||
464 | case SNDRV_PCM_TRIGGER_START: | ||
465 | snd_p16v_intr_enable(emu, inte); | ||
466 | snd_emu10k1_ptr20_write(emu, BASIC_INTERRUPT, 0, snd_emu10k1_ptr20_read(emu, BASIC_INTERRUPT, 0)|(0x100<<channel)); | ||
467 | epcm->running = 1; | ||
468 | break; | ||
469 | case SNDRV_PCM_TRIGGER_STOP: | ||
470 | snd_emu10k1_ptr20_write(emu, BASIC_INTERRUPT, 0, snd_emu10k1_ptr20_read(emu, BASIC_INTERRUPT, 0) & ~(0x100<<channel)); | ||
471 | snd_p16v_intr_disable(emu, inte); | ||
472 | //snd_emu10k1_ptr20_write(emu, EXTENDED_INT_MASK, 0, snd_emu10k1_ptr20_read(emu, EXTENDED_INT_MASK, 0) & ~(0x110000<<channel)); | ||
473 | epcm->running = 0; | ||
474 | break; | ||
475 | default: | ||
476 | result = -EINVAL; | ||
477 | break; | ||
478 | } | ||
479 | return result; | ||
480 | } | ||
481 | |||
348 | /* pointer_playback callback */ | 482 | /* pointer_playback callback */ |
349 | static snd_pcm_uframes_t | 483 | static snd_pcm_uframes_t |
350 | snd_p16v_pcm_pointer_playback(snd_pcm_substream_t *substream) | 484 | snd_p16v_pcm_pointer_playback(snd_pcm_substream_t *substream) |
@@ -370,6 +504,31 @@ snd_p16v_pcm_pointer_playback(snd_pcm_substream_t *substream) | |||
370 | return ptr; | 504 | return ptr; |
371 | } | 505 | } |
372 | 506 | ||
507 | /* pointer_capture callback */ | ||
508 | static snd_pcm_uframes_t | ||
509 | snd_p16v_pcm_pointer_capture(snd_pcm_substream_t *substream) | ||
510 | { | ||
511 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | ||
512 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
513 | emu10k1_pcm_t *epcm = runtime->private_data; | ||
514 | snd_pcm_uframes_t ptr, ptr1, ptr2 = 0; | ||
515 | int channel = 0; | ||
516 | |||
517 | if (!epcm->running) | ||
518 | return 0; | ||
519 | |||
520 | ptr1 = snd_emu10k1_ptr20_read(emu, CAPTURE_POINTER, channel); | ||
521 | ptr2 = bytes_to_frames(runtime, ptr1); | ||
522 | ptr=ptr2; | ||
523 | if (ptr >= runtime->buffer_size) { | ||
524 | ptr -= runtime->buffer_size; | ||
525 | printk("buffer capture limited!\n"); | ||
526 | } | ||
527 | //printk("ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n", ptr1, ptr2, ptr, (int)runtime->buffer_size, (int)runtime->period_size, (int)runtime->frame_bits, (int)runtime->rate); | ||
528 | |||
529 | return ptr; | ||
530 | } | ||
531 | |||
373 | /* operators */ | 532 | /* operators */ |
374 | static snd_pcm_ops_t snd_p16v_playback_front_ops = { | 533 | static snd_pcm_ops_t snd_p16v_playback_front_ops = { |
375 | .open = snd_p16v_pcm_open_playback_front, | 534 | .open = snd_p16v_pcm_open_playback_front, |
@@ -382,6 +541,18 @@ static snd_pcm_ops_t snd_p16v_playback_front_ops = { | |||
382 | .pointer = snd_p16v_pcm_pointer_playback, | 541 | .pointer = snd_p16v_pcm_pointer_playback, |
383 | }; | 542 | }; |
384 | 543 | ||
544 | static snd_pcm_ops_t snd_p16v_capture_ops = { | ||
545 | .open = snd_p16v_pcm_open_capture, | ||
546 | .close = snd_p16v_pcm_close_capture, | ||
547 | .ioctl = snd_pcm_lib_ioctl, | ||
548 | .hw_params = snd_p16v_pcm_hw_params_capture, | ||
549 | .hw_free = snd_p16v_pcm_hw_free_capture, | ||
550 | .prepare = snd_p16v_pcm_prepare_capture, | ||
551 | .trigger = snd_p16v_pcm_trigger_capture, | ||
552 | .pointer = snd_p16v_pcm_pointer_capture, | ||
553 | }; | ||
554 | |||
555 | |||
385 | int snd_p16v_free(emu10k1_t *chip) | 556 | int snd_p16v_free(emu10k1_t *chip) |
386 | { | 557 | { |
387 | // release the data | 558 | // release the data |
@@ -405,20 +576,22 @@ int snd_p16v_pcm(emu10k1_t *emu, int device, snd_pcm_t **rpcm) | |||
405 | snd_pcm_t *pcm; | 576 | snd_pcm_t *pcm; |
406 | snd_pcm_substream_t *substream; | 577 | snd_pcm_substream_t *substream; |
407 | int err; | 578 | int err; |
408 | int capture=0; | 579 | int capture=1; |
409 | 580 | ||
410 | //snd_printk("snd_p16v_pcm called. device=%d\n", device); | 581 | //snd_printk("snd_p16v_pcm called. device=%d\n", device); |
411 | emu->p16v_device_offset = device; | 582 | emu->p16v_device_offset = device; |
412 | if (rpcm) | 583 | if (rpcm) |
413 | *rpcm = NULL; | 584 | *rpcm = NULL; |
414 | //if (device == 0) capture=1; | 585 | |
415 | if ((err = snd_pcm_new(emu->card, "p16v", device, 1, capture, &pcm)) < 0) | 586 | if ((err = snd_pcm_new(emu->card, "p16v", device, 1, capture, &pcm)) < 0) |
416 | return err; | 587 | return err; |
417 | 588 | ||
418 | pcm->private_data = emu; | 589 | pcm->private_data = emu; |
419 | pcm->private_free = snd_p16v_pcm_free; | 590 | pcm->private_free = snd_p16v_pcm_free; |
420 | 591 | // Single playback 8 channel device. | |
592 | // Single capture 2 channel device. | ||
421 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_p16v_playback_front_ops); | 593 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_p16v_playback_front_ops); |
594 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_p16v_capture_ops); | ||
422 | 595 | ||
423 | pcm->info_flags = 0; | 596 | pcm->info_flags = 0; |
424 | pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; | 597 | pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; |
@@ -694,6 +867,56 @@ static snd_kcontrol_new_t snd_p16v_volume_control_spdif_rear = | |||
694 | .put = snd_p16v_volume_put_spdif_rear | 867 | .put = snd_p16v_volume_put_spdif_rear |
695 | }; | 868 | }; |
696 | 869 | ||
870 | static int snd_p16v_capture_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) | ||
871 | { | ||
872 | static char *texts[8] = { "SPDIF", "I2S", "SRC48", "SRCMulti_SPDIF", "SRCMulti_I2S", "CDIF", "FX", "AC97" }; | ||
873 | |||
874 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
875 | uinfo->count = 1; | ||
876 | uinfo->value.enumerated.items = 8; | ||
877 | if (uinfo->value.enumerated.item > 7) | ||
878 | uinfo->value.enumerated.item = 7; | ||
879 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
880 | return 0; | ||
881 | } | ||
882 | |||
883 | static int snd_p16v_capture_source_get(snd_kcontrol_t * kcontrol, | ||
884 | snd_ctl_elem_value_t * ucontrol) | ||
885 | { | ||
886 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol); | ||
887 | |||
888 | ucontrol->value.enumerated.item[0] = emu->p16v_capture_source; | ||
889 | return 0; | ||
890 | } | ||
891 | |||
892 | static int snd_p16v_capture_source_put(snd_kcontrol_t * kcontrol, | ||
893 | snd_ctl_elem_value_t * ucontrol) | ||
894 | { | ||
895 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol); | ||
896 | unsigned int val; | ||
897 | int change = 0; | ||
898 | u32 mask; | ||
899 | u32 source; | ||
900 | |||
901 | val = ucontrol->value.enumerated.item[0] ; | ||
902 | change = (emu->p16v_capture_source != val); | ||
903 | if (change) { | ||
904 | emu->p16v_capture_source = val; | ||
905 | source = (val << 28) | (val << 24) | (val << 20) | (val << 16); | ||
906 | mask = snd_emu10k1_ptr20_read(emu, BASIC_INTERRUPT, 0) & 0xffff; | ||
907 | snd_emu10k1_ptr20_write(emu, BASIC_INTERRUPT, 0, source | mask); | ||
908 | } | ||
909 | return change; | ||
910 | } | ||
911 | |||
912 | static snd_kcontrol_new_t snd_p16v_capture_source __devinitdata = | ||
913 | { | ||
914 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
915 | .name = "HD Capture source", | ||
916 | .info = snd_p16v_capture_source_info, | ||
917 | .get = snd_p16v_capture_source_get, | ||
918 | .put = snd_p16v_capture_source_put | ||
919 | }; | ||
697 | int snd_p16v_mixer(emu10k1_t *emu) | 920 | int snd_p16v_mixer(emu10k1_t *emu) |
698 | { | 921 | { |
699 | int err; | 922 | int err; |
@@ -731,6 +954,10 @@ int snd_p16v_mixer(emu10k1_t *emu) | |||
731 | return -ENOMEM; | 954 | return -ENOMEM; |
732 | if ((err = snd_ctl_add(card, kctl))) | 955 | if ((err = snd_ctl_add(card, kctl))) |
733 | return err; | 956 | return err; |
957 | if ((kctl = snd_ctl_new1(&snd_p16v_capture_source, emu)) == NULL) | ||
958 | return -ENOMEM; | ||
959 | if ((err = snd_ctl_add(card, kctl))) | ||
960 | return err; | ||
734 | return 0; | 961 | return 0; |
735 | } | 962 | } |
736 | 963 | ||