aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/emu10k1/p16v.c
diff options
context:
space:
mode:
authorJames Courtier-Dutton <James@superbug.co.uk>2005-03-26 13:35:29 -0500
committerJaroslav Kysela <perex@suse.cz>2005-05-29 03:00:24 -0400
commit6e4abc40fc125b1dcc2792eacac17606a4d86043 (patch)
tree4b06290dd6a43d809b8762752166ea9b854b6f5f /sound/pci/emu10k1/p16v.c
parentd05b2817d859a2a2f2c3d5c056b688559fdbcc2b (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/emu10k1/p16v.c')
-rw-r--r--sound/pci/emu10k1/p16v.c257
1 files changed, 242 insertions, 15 deletions
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
135static 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
135static void snd_p16v_pcm_free_substream(snd_pcm_runtime_t *runtime) 155static 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 */
202static 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 */
183static int snd_p16v_pcm_close_playback(snd_pcm_substream_t *substream) 240static 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 */
251static 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
266static 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 */
199static int snd_p16v_pcm_hw_params_playback(snd_pcm_substream_t *substream, 273static 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 */
283static 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 */
212static int snd_p16v_pcm_hw_free_playback(snd_pcm_substream_t *substream) 294static 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 */
302static 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 */
223static int snd_p16v_pcm_prepare_playback(snd_pcm_substream_t *substream) 311static 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 */
361static 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
273static void snd_p16v_intr_enable(emu10k1_t *emu, unsigned int intrenb) 377static 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 */
453static 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 */
349static snd_pcm_uframes_t 483static snd_pcm_uframes_t
350snd_p16v_pcm_pointer_playback(snd_pcm_substream_t *substream) 484snd_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 */
508static snd_pcm_uframes_t
509snd_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 */
374static snd_pcm_ops_t snd_p16v_playback_front_ops = { 533static 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
544static 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
385int snd_p16v_free(emu10k1_t *chip) 556int 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
870static 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
883static 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
892static 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
912static 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};
697int snd_p16v_mixer(emu10k1_t *emu) 920int 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