source: GPL/alsa-kernel/pci/emu10k1/p16v.c@ 1

Last change on this file since 1 was 1, checked in by vladest, 20 years ago

initial import

File size: 37.1 KB
Line 
1/*
2 * Copyright (c) by James Courtier-Dutton <James@superbug.demon.co.uk>
3 * Driver p16v chips
4 * Version: 0.25
5 *
6 * FEATURES currently supported:
7 * Output fixed at S32_LE, 2 channel to hw:0,0
8 * Rates: 44.1, 48, 96, 192.
9 *
10 * Changelog:
11 * 0.8
12 * Use separate card based buffer for periods table.
13 * 0.9
14 * Use 2 channel output streams instead of 8 channel.
15 * (8 channel output streams might be good for ASIO type output)
16 * Corrected speaker output, so Front -> Front etc.
17 * 0.10
18 * Fixed missed interrupts.
19 * 0.11
20 * Add Sound card model number and names.
21 * Add Analog volume controls.
22 * 0.12
23 * Corrected playback interrupts. Now interrupt per period, instead of half period.
24 * 0.13
25 * Use single trigger for multichannel.
26 * 0.14
27 * Mic capture now works at fixed: S32_LE, 96000Hz, Stereo.
28 * 0.15
29 * Force buffer_size / period_size == INTEGER.
30 * 0.16
31 * Update p16v.c to work with changed alsa api.
32 * 0.17
33 * Update p16v.c to work with changed alsa api. Removed boot_devs.
34 * 0.18
35 * Merging with snd-emu10k1 driver.
36 * 0.19
37 * One stereo channel at 24bit now works.
38 * 0.20
39 * Added better register defines.
40 * 0.21
41 * Integrated with snd-emu10k1 driver.
42 * 0.22
43 * Removed #if 0 ... #endif
44 * 0.23
45 * Implement different capture rates.
46 * 0.24
47 * Implement different capture source channels.
48 * e.g. When HD Capture source is set to SPDIF,
49 * setting HD Capture channel to 0 captures from CDROM digital input.
50 * setting HD Capture channel to 1 captures from SPDIF in.
51 * 0.25
52 * Include capture buffer sizes.
53 *
54 * BUGS:
55 * Some stability problems when unloading the snd-p16v kernel module.
56 * --
57 *
58 * TODO:
59 * SPDIF out.
60 * Find out how to change capture sample rates. E.g. To record SPDIF at 48000Hz.
61 * Currently capture fixed at 48000Hz.
62 *
63 * --
64 * GENERAL INFO:
65 * Model: SB0240
66 * P16V Chip: CA0151-DBS
67 * Audigy 2 Chip: CA0102-IAT
68 * AC97 Codec: STAC 9721
69 * ADC: Philips 1361T (Stereo 24bit)
70 * DAC: CS4382-K (8-channel, 24bit, 192Khz)
71 *
72 * This code was initally based on code from ALSA's emu10k1x.c which is:
73 * Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com>
74 *
75 * This program is free software; you can redistribute it and/or modify
76 * it under the terms of the GNU General Public License as published by
77 * the Free Software Foundation; either version 2 of the License, or
78 * (at your option) any later version.
79 *
80 * This program is distributed in the hope that it will be useful,
81 * but WITHOUT ANY WARRANTY; without even the implied warranty of
82 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
83 * GNU General Public License for more details.
84 *
85 * You should have received a copy of the GNU General Public License
86 * along with this program; if not, write to the Free Software
87 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
88 *
89 */
90#include <sound/driver.h>
91#include <linux/delay.h>
92#include <linux/init.h>
93#include <linux/interrupt.h>
94#include <linux/pci.h>
95#include <linux/slab.h>
96#include <linux/moduleparam.h>
97#include <sound/core.h>
98#include <sound/initval.h>
99#include <sound/pcm.h>
100#include <sound/ac97_codec.h>
101#include <sound/info.h>
102#include <sound/emu10k1.h>
103#include "p16v.h"
104
105#define SET_CHANNEL 0 /* Testing channel outputs 0=Front, 1=Center/LFE, 2=Unknown, 3=Rear */
106#define PCM_FRONT_CHANNEL 0
107#define PCM_REAR_CHANNEL 1
108#define PCM_CENTER_LFE_CHANNEL 2
109#define PCM_UNKNOWN_CHANNEL 3
110#define CONTROL_FRONT_CHANNEL 0
111#define CONTROL_REAR_CHANNEL 3
112#define CONTROL_CENTER_LFE_CHANNEL 1
113#define CONTROL_UNKNOWN_CHANNEL 2
114
115/* Card IDs:
116 * Class 0401: 1102:0004 (rev 04) Subsystem: 1102:2002 -> Audigy2 ZS 7.1 Model:SB0350
117 * Class 0401: 1102:0004 (rev 04) Subsystem: 1102:1007 -> Audigy2 6.1 Model:SB0240
118 * Class 0401: 1102:0004 (rev 04) Subsystem: 1102:1002 -> Audigy2 Platinum Model:SB msb0240230009266
119 * Class 0401: 1102:0004 (rev 04) Subsystem: 1102:2007 -> Audigy4 Pro Model:SB0380 M1SB0380472001901E
120 *
121 */
122
123/* hardware definition */
124static snd_pcm_hardware_t snd_p16v_playback_hw = {
125 /*.info = */ (SNDRV_PCM_INFO_MMAP |
126 SNDRV_PCM_INFO_INTERLEAVED |
127 SNDRV_PCM_INFO_BLOCK_TRANSFER |
128 SNDRV_PCM_INFO_MMAP_VALID),
129 /* .formats = */ SNDRV_PCM_FMTBIT_S32_LE, /* Only supports 24-bit samples padded to 32 bits. */
130 /* .rates = */ SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100,
131 /* .rate_min = */ 44100,
132 /* .rate_max = */ 192000,
133 /* .channels_min = */ 8,
134 /* .channels_max = */ 8,
135 /* .buffer_bytes_max =*/ ((65536 - 64) * 8),
136 /* .period_bytes_min =*/ 64,
137 /* .period_bytes_max =*/ (65536 - 64),
138 /* .periods_min = */ 2,
139 /* .periods_max = */ 8,
140 /* .fifo_size = */ 0
141};
142
143static snd_pcm_hardware_t snd_p16v_capture_hw = {
144 /*.info = */ (SNDRV_PCM_INFO_MMAP |
145 SNDRV_PCM_INFO_INTERLEAVED |
146 SNDRV_PCM_INFO_BLOCK_TRANSFER |
147 SNDRV_PCM_INFO_MMAP_VALID),
148 /* .formats = */ SNDRV_PCM_FMTBIT_S32_LE,
149 /* .rates = */ SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100,
150 /* .rate_min = */ 44100,
151 /* .rate_max = */ 192000,
152 /* .channels_min = */ 2,
153 /* .channels_max = */ 2,
154 /* .buffer_bytes_max = */ (65536 - 64),
155 /* .period_bytes_min = */ 64,
156 /* .period_bytes_max = */ (65536 - 128) >> 1, /* size has to be N*64 bytes */
157 /* .periods_min = */ 2,
158 /* .periods_max = */ 2,
159 /* .fifo_size = */ 0
160};
161
162static void snd_p16v_pcm_free_substream(snd_pcm_runtime_t *runtime)
163{
164 emu10k1_pcm_t *epcm = runtime->private_data;
165
166 if (epcm) {
167 //snd_printk("epcm free: %p\n", epcm);
168 kfree(epcm);
169 }
170}
171
172/* open_playback callback */
173static int snd_p16v_pcm_open_playback_channel(snd_pcm_substream_t *substream, int channel_id)
174{
175 emu10k1_t *emu = snd_pcm_substream_chip(substream);
176 emu10k1_voice_t *channel = &(emu->p16v_voices[channel_id]);
177 emu10k1_pcm_t *epcm;
178 snd_pcm_runtime_t *runtime = substream->runtime;
179 int err;
180
181 epcm = kzalloc(sizeof(*epcm), GFP_KERNEL);
182 //snd_printk("epcm kcalloc: %p\n", epcm);
183
184 if (epcm == NULL)
185 return -ENOMEM;
186 epcm->emu = emu;
187 epcm->substream = substream;
188 //snd_printk("epcm device=%d, channel_id=%d\n", substream->pcm->device, channel_id);
189
190 runtime->private_data = epcm;
191 runtime->private_free = snd_p16v_pcm_free_substream;
192
193 runtime->hw = snd_p16v_playback_hw;
194
195 channel->emu = emu;
196 channel->number = channel_id;
197
198 channel->use=1;
199 //snd_printk("p16v: open channel_id=%d, channel=%p, use=0x%x\n", channel_id, channel, channel->use);
200 //printk("open:channel_id=%d, chip=%p, channel=%p\n",channel_id, chip, channel);
201 //channel->interrupt = snd_p16v_pcm_channel_interrupt;
202 channel->epcm=epcm;
203 if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
204 return err;
205
206 return 0;
207}
208
209/* open_capture callback */
210static int snd_p16v_pcm_open_capture_channel(snd_pcm_substream_t *substream, int channel_id)
211{
212 emu10k1_t *emu = snd_pcm_substream_chip(substream);
213 emu10k1_voice_t *channel = &(emu->p16v_capture_voice);
214 emu10k1_pcm_t *epcm;
215 snd_pcm_runtime_t *runtime = substream->runtime;
216 int err;
217
218 epcm = kzalloc(sizeof(*epcm), GFP_KERNEL);
219 //snd_printk("epcm kcalloc: %p\n", epcm);
220
221 if (epcm == NULL)
222 return -ENOMEM;
223 epcm->emu = emu;
224 epcm->substream = substream;
225 //snd_printk("epcm device=%d, channel_id=%d\n", substream->pcm->device, channel_id);
226
227 runtime->private_data = epcm;
228 runtime->private_free = snd_p16v_pcm_free_substream;
229
230 runtime->hw = snd_p16v_capture_hw;
231
232 channel->emu = emu;
233 channel->number = channel_id;
234
235 channel->use=1;
236 //snd_printk("p16v: open channel_id=%d, channel=%p, use=0x%x\n", channel_id, channel, channel->use);
237 //printk("open:channel_id=%d, chip=%p, channel=%p\n",channel_id, chip, channel);
238 //channel->interrupt = snd_p16v_pcm_channel_interrupt;
239 channel->epcm=epcm;
240 if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
241 return err;
242
243 return 0;
244}
245
246
247/* close callback */
248static int snd_p16v_pcm_close_playback(snd_pcm_substream_t *substream)
249{
250 emu10k1_t *emu = snd_pcm_substream_chip(substream);
251 //snd_pcm_runtime_t *runtime = substream->runtime;
252 //emu10k1_pcm_t *epcm = runtime->private_data;
253 emu->p16v_voices[substream->pcm->device - emu->p16v_device_offset].use=0;
254 /* FIXME: maybe zero others */
255 return 0;
256}
257
258/* close callback */
259static int snd_p16v_pcm_close_capture(snd_pcm_substream_t *substream)
260{
261 emu10k1_t *emu = snd_pcm_substream_chip(substream);
262 //snd_pcm_runtime_t *runtime = substream->runtime;
263 //emu10k1_pcm_t *epcm = runtime->private_data;
264 emu->p16v_capture_voice.use=0;
265 /* FIXME: maybe zero others */
266 return 0;
267}
268
269static int snd_p16v_pcm_open_playback_front(snd_pcm_substream_t *substream)
270{
271 return snd_p16v_pcm_open_playback_channel(substream, PCM_FRONT_CHANNEL);
272}
273
274static int snd_p16v_pcm_open_capture(snd_pcm_substream_t *substream)
275{
276 // Only using channel 0 for now, but the card has 2 channels.
277 return snd_p16v_pcm_open_capture_channel(substream, 0);
278}
279
280/* hw_params callback */
281static int snd_p16v_pcm_hw_params_playback(snd_pcm_substream_t *substream,
282 snd_pcm_hw_params_t * hw_params)
283{
284 int result;
285 result = snd_pcm_lib_malloc_pages(substream,
286 params_buffer_bytes(hw_params));
287 return result;
288}
289
290/* hw_params callback */
291static int snd_p16v_pcm_hw_params_capture(snd_pcm_substream_t *substream,
292 snd_pcm_hw_params_t * hw_params)
293{
294 int result;
295 result = snd_pcm_lib_malloc_pages(substream,
296 params_buffer_bytes(hw_params));
297 return result;
298}
299
300
301/* hw_free callback */
302static int snd_p16v_pcm_hw_free_playback(snd_pcm_substream_t *substream)
303{
304 int result;
305 result = snd_pcm_lib_free_pages(substream);
306 return result;
307}
308
309/* hw_free callback */
310static int snd_p16v_pcm_hw_free_capture(snd_pcm_substream_t *substream)
311{
312 int result;
313 result = snd_pcm_lib_free_pages(substream);
314 return result;
315}
316
317
318/* prepare playback callback */
319static int snd_p16v_pcm_prepare_playback(snd_pcm_substream_t *substream)
320{
321 emu10k1_t *emu = snd_pcm_substream_chip(substream);
322 snd_pcm_runtime_t *runtime = substream->runtime;
323 int channel = substream->pcm->device - emu->p16v_device_offset;
324 u32 *table_base = (u32 *)(emu->p16v_buffer.area+(8*16*channel));
325 u32 period_size_bytes = frames_to_bytes(runtime, runtime->period_size);
326 int i;
327 u32 tmp;
328
329 //snd_printk("prepare:channel_number=%d, rate=%d, format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, periods=%u, frames_to_bytes=%d\n",channel, runtime->rate, runtime->format, runtime->channels, runtime->buffer_size, runtime->period_size, runtime->periods, frames_to_bytes(runtime, 1));
330 //snd_printk("dma_addr=%x, dma_area=%p, table_base=%p\n",runtime->dma_addr, runtime->dma_area, table_base);
331 //snd_printk("dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n",emu->p16v_buffer.addr, emu->p16v_buffer.area, emu->p16v_buffer.bytes);
332 tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, channel);
333 switch (runtime->rate) {
334 case 44100:
335 snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe0e0) | 0x8080);
336 break;
337 case 96000:
338 snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe0e0) | 0x4040);
339 break;
340 case 192000:
341 snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe0e0) | 0x2020);
342 break;
343 case 48000:
344 default:
345 snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe0e0) | 0x0000);
346 break;
347 }
348 /* FIXME: Check emu->buffer.size before actually writing to it. */
349 for(i=0; i < runtime->periods; i++) {
350 table_base[i*2]=runtime->dma_addr+(i*period_size_bytes);
351 table_base[(i*2)+1]=period_size_bytes<<16;
352 }
353
354 snd_emu10k1_ptr20_write(emu, PLAYBACK_LIST_ADDR, channel, emu->p16v_buffer.addr+(8*16*channel));
355 snd_emu10k1_ptr20_write(emu, PLAYBACK_LIST_SIZE, channel, (runtime->periods - 1) << 19);
356 snd_emu10k1_ptr20_write(emu, PLAYBACK_LIST_PTR, channel, 0);
357 snd_emu10k1_ptr20_write(emu, PLAYBACK_DMA_ADDR, channel, runtime->dma_addr);
358 //snd_emu10k1_ptr20_write(emu, PLAYBACK_PERIOD_SIZE, channel, frames_to_bytes(runtime, runtime->period_size)<<16); // buffer size in bytes
359 snd_emu10k1_ptr20_write(emu, PLAYBACK_PERIOD_SIZE, channel, 0); // buffer size in bytes
360 snd_emu10k1_ptr20_write(emu, PLAYBACK_POINTER, channel, 0);
361 snd_emu10k1_ptr20_write(emu, 0x07, channel, 0x0);
362 snd_emu10k1_ptr20_write(emu, 0x08, channel, 0);
363
364 return 0;
365}
366
367/* prepare capture callback */
368static int snd_p16v_pcm_prepare_capture(snd_pcm_substream_t *substream)
369{
370 emu10k1_t *emu = snd_pcm_substream_chip(substream);
371 snd_pcm_runtime_t *runtime = substream->runtime;
372 int channel = substream->pcm->device - emu->p16v_device_offset;
373 u32 tmp;
374 //printk("prepare capture: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));
375 tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, channel);
376 switch (runtime->rate) {
377 case 44100:
378 snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0x0e00) | 0x0800);
379 break;
380 case 96000:
381 snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0x0e00) | 0x0400);
382 break;
383 case 192000:
384 snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0x0e00) | 0x0200);
385 break;
386 case 48000:
387 default:
388 snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0x0e00) | 0x0000);
389 break;
390 }
391 /* FIXME: Check emu->buffer.size before actually writing to it. */
392 snd_emu10k1_ptr20_write(emu, 0x13, channel, 0);
393 snd_emu10k1_ptr20_write(emu, CAPTURE_DMA_ADDR, channel, runtime->dma_addr);
394 snd_emu10k1_ptr20_write(emu, CAPTURE_BUFFER_SIZE, channel, frames_to_bytes(runtime, runtime->buffer_size)<<16); // buffer size in bytes
395 snd_emu10k1_ptr20_write(emu, CAPTURE_POINTER, channel, 0);
396 //snd_emu10k1_ptr20_write(emu, CAPTURE_SOURCE, 0x0, 0x333300e4); /* Select MIC or Line in */
397 //snd_emu10k1_ptr20_write(emu, EXTENDED_INT_MASK, 0, snd_emu10k1_ptr20_read(emu, EXTENDED_INT_MASK, 0) | (0x110000<<channel));
398
399 return 0;
400}
401
402static void snd_p16v_intr_enable(emu10k1_t *emu, unsigned int intrenb)
403{
404 unsigned long flags;
405 unsigned int enable;
406
407 spin_lock_irqsave(&emu->emu_lock, flags);
408 enable = inl(emu->port + INTE2) | intrenb;
409 outl(enable, emu->port + INTE2);
410 spin_unlock_irqrestore(&emu->emu_lock, flags);
411}
412
413static void snd_p16v_intr_disable(emu10k1_t *emu, unsigned int intrenb)
414{
415 unsigned long flags;
416 unsigned int disable;
417
418 spin_lock_irqsave(&emu->emu_lock, flags);
419 disable = inl(emu->port + INTE2) & (~intrenb);
420 outl(disable, emu->port + INTE2);
421 spin_unlock_irqrestore(&emu->emu_lock, flags);
422}
423
424/* trigger_playback callback */
425static int snd_p16v_pcm_trigger_playback(snd_pcm_substream_t *substream,
426 int cmd)
427{
428 emu10k1_t *emu = snd_pcm_substream_chip(substream);
429 snd_pcm_runtime_t *runtime;
430 emu10k1_pcm_t *epcm;
431 int channel;
432 int result = 0;
433 struct list_head *pos;
434 snd_pcm_substream_t *s;
435 u32 basic = 0;
436 u32 inte = 0;
437 int running=0;
438
439 switch (cmd) {
440 case SNDRV_PCM_TRIGGER_START:
441 running=1;
442 break;
443 case SNDRV_PCM_TRIGGER_STOP:
444 default:
445 running=0;
446 break;
447 }
448 snd_pcm_group_for_each(pos, substream) {
449 s = snd_pcm_group_substream_entry(pos);
450 runtime = s->runtime;
451 epcm = runtime->private_data;
452 channel = substream->pcm->device-emu->p16v_device_offset;
453 //snd_printk("p16v channel=%d\n",channel);
454 epcm->running = running;
455 basic |= (0x1<<channel);
456 inte |= (INTE2_PLAYBACK_CH_0_LOOP<<channel);
457 snd_pcm_trigger_done(s, substream);
458 }
459 //snd_printk("basic=0x%x, inte=0x%x\n",basic, inte);
460
461 switch (cmd) {
462 case SNDRV_PCM_TRIGGER_START:
463 snd_p16v_intr_enable(emu, inte);
464 snd_emu10k1_ptr20_write(emu, BASIC_INTERRUPT, 0, snd_emu10k1_ptr20_read(emu, BASIC_INTERRUPT, 0)| (basic));
465 break;
466 case SNDRV_PCM_TRIGGER_STOP:
467 snd_emu10k1_ptr20_write(emu, BASIC_INTERRUPT, 0, snd_emu10k1_ptr20_read(emu, BASIC_INTERRUPT, 0) & ~(basic));
468 snd_p16v_intr_disable(emu, inte);
469 break;
470 default:
471 result = -EINVAL;
472 break;
473 }
474 return result;
475}
476
477/* trigger_capture callback */
478static int snd_p16v_pcm_trigger_capture(snd_pcm_substream_t *substream,
479 int cmd)
480{
481 emu10k1_t *emu = snd_pcm_substream_chip(substream);
482 snd_pcm_runtime_t *runtime = substream->runtime;
483 emu10k1_pcm_t *epcm = runtime->private_data;
484 int channel = 0;
485 int result = 0;
486 u32 inte = INTE2_CAPTURE_CH_0_LOOP | INTE2_CAPTURE_CH_0_HALF_LOOP;
487
488 switch (cmd) {
489 case SNDRV_PCM_TRIGGER_START:
490 snd_p16v_intr_enable(emu, inte);
491 snd_emu10k1_ptr20_write(emu, BASIC_INTERRUPT, 0, snd_emu10k1_ptr20_read(emu, BASIC_INTERRUPT, 0)|(0x100<<channel));
492 epcm->running = 1;
493 break;
494 case SNDRV_PCM_TRIGGER_STOP:
495 snd_emu10k1_ptr20_write(emu, BASIC_INTERRUPT, 0, snd_emu10k1_ptr20_read(emu, BASIC_INTERRUPT, 0) & ~(0x100<<channel));
496 snd_p16v_intr_disable(emu, inte);
497 //snd_emu10k1_ptr20_write(emu, EXTENDED_INT_MASK, 0, snd_emu10k1_ptr20_read(emu, EXTENDED_INT_MASK, 0) & ~(0x110000<<channel));
498 epcm->running = 0;
499 break;
500 default:
501 result = -EINVAL;
502 break;
503 }
504 return result;
505}
506
507/* pointer_playback callback */
508static snd_pcm_uframes_t
509snd_p16v_pcm_pointer_playback(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,ptr3,ptr4 = 0;
515 int channel = substream->pcm->device - emu->p16v_device_offset;
516 if (!epcm->running)
517 return 0;
518
519 ptr3 = snd_emu10k1_ptr20_read(emu, PLAYBACK_LIST_PTR, channel);
520 ptr1 = snd_emu10k1_ptr20_read(emu, PLAYBACK_POINTER, channel);
521 ptr4 = snd_emu10k1_ptr20_read(emu, PLAYBACK_LIST_PTR, channel);
522 if (ptr3 != ptr4) ptr1 = snd_emu10k1_ptr20_read(emu, PLAYBACK_POINTER, channel);
523 ptr2 = bytes_to_frames(runtime, ptr1);
524 ptr2+= (ptr4 >> 3) * runtime->period_size;
525 ptr=ptr2;
526 if (ptr >= runtime->buffer_size)
527 ptr -= runtime->buffer_size;
528
529 return ptr;
530}
531
532/* pointer_capture callback */
533static snd_pcm_uframes_t
534snd_p16v_pcm_pointer_capture(snd_pcm_substream_t *substream)
535{
536 emu10k1_t *emu = snd_pcm_substream_chip(substream);
537 snd_pcm_runtime_t *runtime = substream->runtime;
538 emu10k1_pcm_t *epcm = runtime->private_data;
539 snd_pcm_uframes_t ptr, ptr1, ptr2 = 0;
540 int channel = 0;
541
542 if (!epcm->running)
543 return 0;
544
545 ptr1 = snd_emu10k1_ptr20_read(emu, CAPTURE_POINTER, channel);
546 ptr2 = bytes_to_frames(runtime, ptr1);
547 ptr=ptr2;
548 if (ptr >= runtime->buffer_size) {
549 ptr -= runtime->buffer_size;
550 printk("buffer capture limited!\n");
551 }
552 //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);
553
554 return ptr;
555}
556
557/* operators */
558static snd_pcm_ops_t snd_p16v_playback_front_ops = {
559 /*.open = */snd_p16v_pcm_open_playback_front,
560 /*.close = */snd_p16v_pcm_close_playback,
561 /*.ioctl = */snd_pcm_lib_ioctl,
562 /*.hw_params = */snd_p16v_pcm_hw_params_playback,
563 /*.hw_free = */snd_p16v_pcm_hw_free_playback,
564 /*.prepare = */snd_p16v_pcm_prepare_playback,
565 /*.trigger = */snd_p16v_pcm_trigger_playback,
566 /*.pointer = */snd_p16v_pcm_pointer_playback,
567 0,0,0,0
568};
569
570static snd_pcm_ops_t snd_p16v_capture_ops = {
571 /*.open = */snd_p16v_pcm_open_capture,
572 /*.close = */snd_p16v_pcm_close_capture,
573 /*.ioctl = */snd_pcm_lib_ioctl,
574 /*.hw_params = */snd_p16v_pcm_hw_params_capture,
575 /*.hw_free = */snd_p16v_pcm_hw_free_capture,
576 /*.prepare = */snd_p16v_pcm_prepare_capture,
577 /*.trigger = */snd_p16v_pcm_trigger_capture,
578 /*.pointer = */snd_p16v_pcm_pointer_capture,
579 0,0,0,0
580};
581
582int snd_p16v_free(emu10k1_t *chip)
583{
584 // release the data
585 if (chip->p16v_buffer.area) {
586 snd_dma_free_pages(&chip->p16v_buffer);
587 //snd_printk("period lables free: %p\n", &chip->p16v_buffer);
588 }
589 return 0;
590}
591
592static void snd_p16v_pcm_free(snd_pcm_t *pcm)
593{
594 emu10k1_t *emu = pcm->private_data;
595 //snd_printk("snd_p16v_pcm_free pcm: called\n");
596 snd_pcm_lib_preallocate_free_for_all(pcm);
597 emu->pcm = NULL;
598}
599
600int snd_p16v_pcm(emu10k1_t *emu, int device, snd_pcm_t **rpcm)
601{
602 snd_pcm_t *pcm;
603 snd_pcm_substream_t *substream;
604 int err;
605 int capture=1;
606
607 //snd_printk("snd_p16v_pcm called. device=%d\n", device);
608 emu->p16v_device_offset = device;
609 if (rpcm)
610 *rpcm = NULL;
611 if ((err = snd_pcm_new(emu->card, "p16v", device, 1, capture, &pcm)) < 0)
612 return err;
613
614 pcm->private_data = emu;
615 pcm->private_free = snd_p16v_pcm_free;
616 // Single playback 8 channel device.
617 // Single capture 2 channel device.
618 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_p16v_playback_front_ops);
619 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_p16v_capture_ops);
620
621 pcm->info_flags = 0;
622 pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;
623 strcpy(pcm->name, "p16v");
624 emu->pcm = pcm;
625
626 for(substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
627 substream;
628 substream = substream->next) {
629 if ((err = snd_pcm_lib_preallocate_pages(substream,
630 SNDRV_DMA_TYPE_DEV,
631 snd_dma_pci_data(emu->pci),
632 ((65536 - 64) * 8), ((65536 - 64) * 8))) < 0)
633 return err;
634 //snd_printk("preallocate playback substream: err=%d\n", err);
635 }
636
637 for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
638 substream;
639 substream = substream->next) {
640 if ((err = snd_pcm_lib_preallocate_pages(substream,
641 SNDRV_DMA_TYPE_DEV,
642 snd_dma_pci_data(emu->pci),
643 65536 - 64, 65536 - 64)) < 0)
644 return err;
645 //snd_printk("preallocate capture substream: err=%d\n", err);
646 }
647
648 if (rpcm)
649 *rpcm = pcm;
650
651 return 0;
652}
653
654static int snd_p16v_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
655{
656 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
657 uinfo->count = 2;
658 uinfo->value.integer.min = 0;
659 uinfo->value.integer.max = 255;
660 return 0;
661}
662
663static int snd_p16v_volume_get(snd_kcontrol_t * kcontrol,
664 snd_ctl_elem_value_t * ucontrol, int reg, int high_low)
665{
666 emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
667 u32 value;
668
669 value = snd_emu10k1_ptr20_read(emu, reg, high_low);
670 if (high_low == 1) {
671 ucontrol->value.integer.value[0] = 0xff - ((value >> 24) & 0xff); /* Left */
672 ucontrol->value.integer.value[1] = 0xff - ((value >> 16) & 0xff); /* Right */
673 } else {
674 ucontrol->value.integer.value[0] = 0xff - ((value >> 8) & 0xff); /* Left */
675 ucontrol->value.integer.value[1] = 0xff - ((value >> 0) & 0xff); /* Right */
676 }
677 return 0;
678}
679
680static int snd_p16v_volume_get_spdif_front(snd_kcontrol_t * kcontrol,
681 snd_ctl_elem_value_t * ucontrol)
682{
683 int high_low = 0;
684 int reg = PLAYBACK_VOLUME_MIXER7;
685 return snd_p16v_volume_get(kcontrol, ucontrol, reg, high_low);
686}
687
688static int snd_p16v_volume_get_spdif_center_lfe(snd_kcontrol_t * kcontrol,
689 snd_ctl_elem_value_t * ucontrol)
690{
691 int high_low = 1;
692 int reg = PLAYBACK_VOLUME_MIXER7;
693 return snd_p16v_volume_get(kcontrol, ucontrol, reg, high_low);
694}
695static int snd_p16v_volume_get_spdif_unknown(snd_kcontrol_t * kcontrol,
696 snd_ctl_elem_value_t * ucontrol)
697{
698 int high_low = 0;
699 int reg = PLAYBACK_VOLUME_MIXER8;
700 return snd_p16v_volume_get(kcontrol, ucontrol, reg, high_low);
701}
702static int snd_p16v_volume_get_spdif_rear(snd_kcontrol_t * kcontrol,
703 snd_ctl_elem_value_t * ucontrol)
704{
705 int high_low = 1;
706 int reg = PLAYBACK_VOLUME_MIXER8;
707 return snd_p16v_volume_get(kcontrol, ucontrol, reg, high_low);
708}
709
710static int snd_p16v_volume_get_analog_front(snd_kcontrol_t * kcontrol,
711 snd_ctl_elem_value_t * ucontrol)
712{
713 int high_low = 0;
714 int reg = PLAYBACK_VOLUME_MIXER9;
715 return snd_p16v_volume_get(kcontrol, ucontrol, reg, high_low);
716}
717
718static int snd_p16v_volume_get_analog_center_lfe(snd_kcontrol_t * kcontrol,
719 snd_ctl_elem_value_t * ucontrol)
720{
721 int high_low = 1;
722 int reg = PLAYBACK_VOLUME_MIXER9;
723 return snd_p16v_volume_get(kcontrol, ucontrol, reg, high_low);
724}
725static int snd_p16v_volume_get_analog_rear(snd_kcontrol_t * kcontrol,
726 snd_ctl_elem_value_t * ucontrol)
727{
728 int high_low = 1;
729 int reg = PLAYBACK_VOLUME_MIXER10;
730 return snd_p16v_volume_get(kcontrol, ucontrol, reg, high_low);
731}
732
733static int snd_p16v_volume_get_analog_unknown(snd_kcontrol_t * kcontrol,
734 snd_ctl_elem_value_t * ucontrol)
735{
736 int high_low = 0;
737 int reg = PLAYBACK_VOLUME_MIXER10;
738 return snd_p16v_volume_get(kcontrol, ucontrol, reg, high_low);
739}
740
741static int snd_p16v_volume_put(snd_kcontrol_t * kcontrol,
742 snd_ctl_elem_value_t * ucontrol, int reg, int high_low)
743{
744 emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
745 u32 value;
746 value = snd_emu10k1_ptr20_read(emu, reg, 0);
747 //value = value & 0xffff;
748 if (high_low == 1) {
749 value &= 0xffff;
750 value = value | ((0xff - ucontrol->value.integer.value[0]) << 24) | ((0xff - ucontrol->value.integer.value[1]) << 16);
751 } else {
752 value &= 0xffff0000;
753 value = value | ((0xff - ucontrol->value.integer.value[0]) << 8) | ((0xff - ucontrol->value.integer.value[1]) );
754 }
755 snd_emu10k1_ptr20_write(emu, reg, 0, value);
756 return 1;
757}
758
759static int snd_p16v_volume_put_spdif_front(snd_kcontrol_t * kcontrol,
760 snd_ctl_elem_value_t * ucontrol)
761{
762 int high_low = 0;
763 int reg = PLAYBACK_VOLUME_MIXER7;
764 return snd_p16v_volume_put(kcontrol, ucontrol, reg, high_low);
765}
766
767static int snd_p16v_volume_put_spdif_center_lfe(snd_kcontrol_t * kcontrol,
768 snd_ctl_elem_value_t * ucontrol)
769{
770 int high_low = 1;
771 int reg = PLAYBACK_VOLUME_MIXER7;
772 return snd_p16v_volume_put(kcontrol, ucontrol, reg, high_low);
773}
774
775static int snd_p16v_volume_put_spdif_unknown(snd_kcontrol_t * kcontrol,
776 snd_ctl_elem_value_t * ucontrol)
777{
778 int high_low = 0;
779 int reg = PLAYBACK_VOLUME_MIXER8;
780 return snd_p16v_volume_put(kcontrol, ucontrol, reg, high_low);
781}
782
783static int snd_p16v_volume_put_spdif_rear(snd_kcontrol_t * kcontrol,
784 snd_ctl_elem_value_t * ucontrol)
785{
786 int high_low = 1;
787 int reg = PLAYBACK_VOLUME_MIXER8;
788 return snd_p16v_volume_put(kcontrol, ucontrol, reg, high_low);
789}
790
791static int snd_p16v_volume_put_analog_front(snd_kcontrol_t * kcontrol,
792 snd_ctl_elem_value_t * ucontrol)
793{
794 int high_low = 0;
795 int reg = PLAYBACK_VOLUME_MIXER9;
796 return snd_p16v_volume_put(kcontrol, ucontrol, reg, high_low);
797}
798
799static int snd_p16v_volume_put_analog_center_lfe(snd_kcontrol_t * kcontrol,
800 snd_ctl_elem_value_t * ucontrol)
801{
802 int high_low = 1;
803 int reg = PLAYBACK_VOLUME_MIXER9;
804 return snd_p16v_volume_put(kcontrol, ucontrol, reg, high_low);
805}
806
807static int snd_p16v_volume_put_analog_rear(snd_kcontrol_t * kcontrol,
808 snd_ctl_elem_value_t * ucontrol)
809{
810 int high_low = 1;
811 int reg = PLAYBACK_VOLUME_MIXER10;
812 return snd_p16v_volume_put(kcontrol, ucontrol, reg, high_low);
813}
814
815static int snd_p16v_volume_put_analog_unknown(snd_kcontrol_t * kcontrol,
816 snd_ctl_elem_value_t * ucontrol)
817{
818 int high_low = 0;
819 int reg = PLAYBACK_VOLUME_MIXER10;
820 return snd_p16v_volume_put(kcontrol, ucontrol, reg, high_low);
821}
822
823static snd_kcontrol_new_t snd_p16v_volume_control_analog_front =
824{
825 SNDRV_CTL_ELEM_IFACE_MIXER,0,0,
826 "HD Analog Front Playback Volume",0,0,0,
827 snd_p16v_volume_info,
828 snd_p16v_volume_get_analog_front,
829 snd_p16v_volume_put_analog_front,0
830};
831
832static snd_kcontrol_new_t snd_p16v_volume_control_analog_center_lfe =
833{
834 SNDRV_CTL_ELEM_IFACE_MIXER,0,0,
835 "HD Analog Center/LFE Playback Volume",0,0,0,
836 snd_p16v_volume_info,
837 snd_p16v_volume_get_analog_center_lfe,
838 snd_p16v_volume_put_analog_center_lfe
839};
840
841static snd_kcontrol_new_t snd_p16v_volume_control_analog_unknown =
842{
843 SNDRV_CTL_ELEM_IFACE_MIXER,0,0,
844 "HD Analog Unknown Playback Volume",0,0,0,
845 snd_p16v_volume_info,
846 snd_p16v_volume_get_analog_unknown,
847 snd_p16v_volume_put_analog_unknown,0
848};
849
850static snd_kcontrol_new_t snd_p16v_volume_control_analog_rear =
851{
852 SNDRV_CTL_ELEM_IFACE_MIXER,0,0,
853 "HD Analog Rear Playback Volume",0,0,0,
854 snd_p16v_volume_info,
855 snd_p16v_volume_get_analog_rear,
856 snd_p16v_volume_put_analog_rear,0
857};
858
859static snd_kcontrol_new_t snd_p16v_volume_control_spdif_front =
860{
861 SNDRV_CTL_ELEM_IFACE_MIXER,0,0,
862 "HD SPDIF Front Playback Volume",0,0,0,
863 snd_p16v_volume_info,
864 snd_p16v_volume_get_spdif_front,
865 snd_p16v_volume_put_spdif_front,0
866};
867
868static snd_kcontrol_new_t snd_p16v_volume_control_spdif_center_lfe =
869{
870 SNDRV_CTL_ELEM_IFACE_MIXER,0,0,
871 "HD SPDIF Center/LFE Playback Volume",0,0,0,
872 snd_p16v_volume_info,
873 snd_p16v_volume_get_spdif_center_lfe,
874 snd_p16v_volume_put_spdif_center_lfe,0
875};
876
877static snd_kcontrol_new_t snd_p16v_volume_control_spdif_unknown =
878{
879 SNDRV_CTL_ELEM_IFACE_MIXER,0,0,
880 "HD SPDIF Unknown Playback Volume",0,0,0,
881 snd_p16v_volume_info,
882 snd_p16v_volume_get_spdif_unknown,
883 snd_p16v_volume_put_spdif_unknown,0
884};
885
886static snd_kcontrol_new_t snd_p16v_volume_control_spdif_rear =
887{
888 SNDRV_CTL_ELEM_IFACE_MIXER,0,0,
889 "HD SPDIF Rear Playback Volume",0,0,0,
890 snd_p16v_volume_info,
891 snd_p16v_volume_get_spdif_rear,
892 snd_p16v_volume_put_spdif_rear,0
893};
894
895static int snd_p16v_capture_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
896{
897 static char *texts[8] = { "SPDIF", "I2S", "SRC48", "SRCMulti_SPDIF", "SRCMulti_I2S", "CDIF", "FX", "AC97" };
898
899 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
900 uinfo->count = 1;
901 uinfo->value.enumerated.items = 8;
902 if (uinfo->value.enumerated.item > 7)
903 uinfo->value.enumerated.item = 7;
904 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
905 return 0;
906}
907
908static int snd_p16v_capture_source_get(snd_kcontrol_t * kcontrol,
909 snd_ctl_elem_value_t * ucontrol)
910{
911 emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
912
913 ucontrol->value.enumerated.item[0] = emu->p16v_capture_source;
914 return 0;
915}
916
917static int snd_p16v_capture_source_put(snd_kcontrol_t * kcontrol,
918 snd_ctl_elem_value_t * ucontrol)
919{
920 emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
921 unsigned int val;
922 int change = 0;
923 u32 mask;
924 u32 source;
925
926 val = ucontrol->value.enumerated.item[0] ;
927 change = (emu->p16v_capture_source != val);
928 if (change) {
929 emu->p16v_capture_source = val;
930 source = (val << 28) | (val << 24) | (val << 20) | (val << 16);
931 mask = snd_emu10k1_ptr20_read(emu, BASIC_INTERRUPT, 0) & 0xffff;
932 snd_emu10k1_ptr20_write(emu, BASIC_INTERRUPT, 0, source | mask);
933 }
934 return change;
935}
936
937static snd_kcontrol_new_t snd_p16v_capture_source __devinitdata =
938{
939 SNDRV_CTL_ELEM_IFACE_MIXER,0,0,
940 "HD source Capture",0,0,0,
941 snd_p16v_capture_source_info,
942 snd_p16v_capture_source_get,
943 snd_p16v_capture_source_put,0
944};
945
946static int snd_p16v_capture_channel_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
947{
948 static char *texts[4] = { "0", "1", "2", "3", };
949
950 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
951 uinfo->count = 1;
952 uinfo->value.enumerated.items = 4;
953 if (uinfo->value.enumerated.item > 3)
954 uinfo->value.enumerated.item = 3;
955 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
956 return 0;
957}
958
959static int snd_p16v_capture_channel_get(snd_kcontrol_t * kcontrol,
960 snd_ctl_elem_value_t * ucontrol)
961{
962 emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
963
964 ucontrol->value.enumerated.item[0] = emu->p16v_capture_channel;
965 return 0;
966}
967
968static int snd_p16v_capture_channel_put(snd_kcontrol_t * kcontrol,
969 snd_ctl_elem_value_t * ucontrol)
970{
971 emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
972 unsigned int val;
973 int change = 0;
974 u32 tmp;
975
976 val = ucontrol->value.enumerated.item[0] ;
977 change = (emu->p16v_capture_channel != val);
978 if (change) {
979 emu->p16v_capture_channel = val;
980 tmp = snd_emu10k1_ptr20_read(emu, CAPTURE_P16V_SOURCE, 0) & 0xfffc;
981 snd_emu10k1_ptr20_write(emu, CAPTURE_P16V_SOURCE, 0, tmp | val);
982 }
983 return change;
984}
985
986static snd_kcontrol_new_t snd_p16v_capture_channel __devinitdata =
987{
988 SNDRV_CTL_ELEM_IFACE_MIXER,0,0,
989 "HD channel Capture",0,0,0,
990 snd_p16v_capture_channel_info,
991 snd_p16v_capture_channel_get,
992 snd_p16v_capture_channel_put,0
993};
994
995int snd_p16v_mixer(emu10k1_t *emu)
996{
997 int err;
998 snd_kcontrol_t *kctl;
999 snd_card_t *card = emu->card;
1000 if ((kctl = snd_ctl_new1(&snd_p16v_volume_control_analog_front, emu)) == NULL)
1001 return -ENOMEM;
1002 if ((err = snd_ctl_add(card, kctl)))
1003 return err;
1004 if ((kctl = snd_ctl_new1(&snd_p16v_volume_control_analog_rear, emu)) == NULL)
1005 return -ENOMEM;
1006 if ((err = snd_ctl_add(card, kctl)))
1007 return err;
1008 if ((kctl = snd_ctl_new1(&snd_p16v_volume_control_analog_center_lfe, emu)) == NULL)
1009 return -ENOMEM;
1010 if ((err = snd_ctl_add(card, kctl)))
1011 return err;
1012 if ((kctl = snd_ctl_new1(&snd_p16v_volume_control_analog_unknown, emu)) == NULL)
1013 return -ENOMEM;
1014 if ((err = snd_ctl_add(card, kctl)))
1015 return err;
1016 if ((kctl = snd_ctl_new1(&snd_p16v_volume_control_spdif_front, emu)) == NULL)
1017 return -ENOMEM;
1018 if ((err = snd_ctl_add(card, kctl)))
1019 return err;
1020 if ((kctl = snd_ctl_new1(&snd_p16v_volume_control_spdif_rear, emu)) == NULL)
1021 return -ENOMEM;
1022 if ((err = snd_ctl_add(card, kctl)))
1023 return err;
1024 if ((kctl = snd_ctl_new1(&snd_p16v_volume_control_spdif_center_lfe, emu)) == NULL)
1025 return -ENOMEM;
1026 if ((err = snd_ctl_add(card, kctl)))
1027 return err;
1028 if ((kctl = snd_ctl_new1(&snd_p16v_volume_control_spdif_unknown, emu)) == NULL)
1029 return -ENOMEM;
1030 if ((err = snd_ctl_add(card, kctl)))
1031 return err;
1032 if ((kctl = snd_ctl_new1(&snd_p16v_capture_source, emu)) == NULL)
1033 return -ENOMEM;
1034 if ((err = snd_ctl_add(card, kctl)))
1035 return err;
1036 if ((kctl = snd_ctl_new1(&snd_p16v_capture_channel, emu)) == NULL)
1037 return -ENOMEM;
1038 if ((err = snd_ctl_add(card, kctl)))
1039 return err;
1040 return 0;
1041}
1042
Note: See TracBrowser for help on using the repository browser.