1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright (c) by James Courtier-Dutton <James@superbug.demon.co.uk> |
4 | * Driver p16v chips |
5 | * Version: 0.25 |
6 | * |
7 | * FEATURES currently supported: |
8 | * Output fixed at S32_LE, 2 channel to hw:0,0 |
9 | * Rates: 44.1, 48, 96, 192. |
10 | * |
11 | * Changelog: |
12 | * 0.8 |
13 | * Use separate card based buffer for periods table. |
14 | * 0.9 |
15 | * Use 2 channel output streams instead of 8 channel. |
16 | * (8 channel output streams might be good for ASIO type output) |
17 | * Corrected speaker output, so Front -> Front etc. |
18 | * 0.10 |
19 | * Fixed missed interrupts. |
20 | * 0.11 |
21 | * Add Sound card model number and names. |
22 | * Add Analog volume controls. |
23 | * 0.12 |
24 | * Corrected playback interrupts. Now interrupt per period, instead of half period. |
25 | * 0.13 |
26 | * Use single trigger for multichannel. |
27 | * 0.14 |
28 | * Mic capture now works at fixed: S32_LE, 96000Hz, Stereo. |
29 | * 0.15 |
30 | * Force buffer_size / period_size == INTEGER. |
31 | * 0.16 |
32 | * Update p16v.c to work with changed alsa api. |
33 | * 0.17 |
34 | * Update p16v.c to work with changed alsa api. Removed boot_devs. |
35 | * 0.18 |
36 | * Merging with snd-emu10k1 driver. |
37 | * 0.19 |
38 | * One stereo channel at 24bit now works. |
39 | * 0.20 |
40 | * Added better register defines. |
41 | * 0.21 |
42 | * Integrated with snd-emu10k1 driver. |
43 | * 0.22 |
44 | * Removed #if 0 ... #endif |
45 | * 0.23 |
46 | * Implement different capture rates. |
47 | * 0.24 |
48 | * Implement different capture source channels. |
49 | * e.g. When HD Capture source is set to SPDIF, |
50 | * setting HD Capture channel to 0 captures from CDROM digital input. |
51 | * setting HD Capture channel to 1 captures from SPDIF in. |
52 | * 0.25 |
53 | * Include capture buffer sizes. |
54 | * |
55 | * BUGS: |
56 | * Some stability problems when unloading the snd-p16v kernel module. |
57 | * -- |
58 | * |
59 | * TODO: |
60 | * SPDIF out. |
61 | * Find out how to change capture sample rates. E.g. To record SPDIF at 48000Hz. |
62 | * Currently capture fixed at 48000Hz. |
63 | * |
64 | * -- |
65 | * GENERAL INFO: |
66 | * Model: SB0240 |
67 | * P16V Chip: CA0151-DBS |
68 | * Audigy 2 Chip: CA0102-IAT |
69 | * AC97 Codec: STAC 9721 |
70 | * ADC: Philips 1361T (Stereo 24bit) |
71 | * DAC: CS4382-K (8-channel, 24bit, 192Khz) |
72 | * |
73 | * This code was initially based on code from ALSA's emu10k1x.c which is: |
74 | * Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com> |
75 | */ |
76 | #include <linux/delay.h> |
77 | #include <linux/init.h> |
78 | #include <linux/interrupt.h> |
79 | #include <linux/pci.h> |
80 | #include <linux/slab.h> |
81 | #include <linux/vmalloc.h> |
82 | #include <linux/moduleparam.h> |
83 | #include <sound/core.h> |
84 | #include <sound/initval.h> |
85 | #include <sound/pcm.h> |
86 | #include <sound/ac97_codec.h> |
87 | #include <sound/info.h> |
88 | #include <sound/tlv.h> |
89 | #include <sound/emu10k1.h> |
90 | #include "p16v.h" |
91 | |
92 | #define SET_CHANNEL 0 /* Testing channel outputs 0=Front, 1=Center/LFE, 2=Unknown, 3=Rear */ |
93 | #define PCM_FRONT_CHANNEL 0 |
94 | #define PCM_REAR_CHANNEL 1 |
95 | #define PCM_CENTER_LFE_CHANNEL 2 |
96 | #define PCM_SIDE_CHANNEL 3 |
97 | #define CONTROL_FRONT_CHANNEL 0 |
98 | #define CONTROL_REAR_CHANNEL 3 |
99 | #define CONTROL_CENTER_LFE_CHANNEL 1 |
100 | #define CONTROL_SIDE_CHANNEL 2 |
101 | |
102 | /* Card IDs: |
103 | * Class 0401: 1102:0004 (rev 04) Subsystem: 1102:2002 -> Audigy2 ZS 7.1 Model:SB0350 |
104 | * Class 0401: 1102:0004 (rev 04) Subsystem: 1102:1007 -> Audigy2 6.1 Model:SB0240 |
105 | * Class 0401: 1102:0004 (rev 04) Subsystem: 1102:1002 -> Audigy2 Platinum Model:SB msb0240230009266 |
106 | * Class 0401: 1102:0004 (rev 04) Subsystem: 1102:2007 -> Audigy4 Pro Model:SB0380 M1SB0380472001901E |
107 | * |
108 | */ |
109 | |
110 | /* hardware definition */ |
111 | static const struct snd_pcm_hardware snd_p16v_playback_hw = { |
112 | .info = SNDRV_PCM_INFO_MMAP | |
113 | SNDRV_PCM_INFO_INTERLEAVED | |
114 | SNDRV_PCM_INFO_BLOCK_TRANSFER | |
115 | SNDRV_PCM_INFO_RESUME | |
116 | SNDRV_PCM_INFO_MMAP_VALID | |
117 | SNDRV_PCM_INFO_SYNC_START, |
118 | .formats = SNDRV_PCM_FMTBIT_S32_LE, /* Only supports 24-bit samples padded to 32 bits. */ |
119 | .rates = SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100, |
120 | .rate_min = 44100, |
121 | .rate_max = 192000, |
122 | .channels_min = 8, |
123 | .channels_max = 8, |
124 | .buffer_bytes_max = ((65536 - 64) * 8), |
125 | .period_bytes_min = 64, |
126 | .period_bytes_max = (65536 - 64), |
127 | .periods_min = 2, |
128 | .periods_max = 8, |
129 | .fifo_size = 0, |
130 | }; |
131 | |
132 | static const struct snd_pcm_hardware snd_p16v_capture_hw = { |
133 | .info = (SNDRV_PCM_INFO_MMAP | |
134 | SNDRV_PCM_INFO_INTERLEAVED | |
135 | SNDRV_PCM_INFO_BLOCK_TRANSFER | |
136 | SNDRV_PCM_INFO_RESUME | |
137 | SNDRV_PCM_INFO_MMAP_VALID), |
138 | .formats = SNDRV_PCM_FMTBIT_S32_LE, |
139 | .rates = SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100, |
140 | .rate_min = 44100, |
141 | .rate_max = 192000, |
142 | .channels_min = 2, |
143 | .channels_max = 2, |
144 | .buffer_bytes_max = (65536 - 64), |
145 | .period_bytes_min = 64, |
146 | .period_bytes_max = (65536 - 128) >> 1, /* size has to be N*64 bytes */ |
147 | .periods_min = 2, |
148 | .periods_max = 2, |
149 | .fifo_size = 0, |
150 | }; |
151 | |
152 | /* open_playback callback */ |
153 | static int snd_p16v_pcm_open_playback_channel(struct snd_pcm_substream *substream, int channel_id) |
154 | { |
155 | struct snd_pcm_runtime *runtime = substream->runtime; |
156 | int err; |
157 | |
158 | /* |
159 | dev_dbg(emu->card->dev, "epcm device=%d, channel_id=%d\n", |
160 | substream->pcm->device, channel_id); |
161 | */ |
162 | |
163 | runtime->hw = snd_p16v_playback_hw; |
164 | |
165 | #if 0 /* debug */ |
166 | dev_dbg(emu->card->dev, |
167 | "p16v: open channel_id=%d, channel=%p, use=0x%x\n" , |
168 | channel_id, channel, channel->use); |
169 | dev_dbg(emu->card->dev, "open:channel_id=%d, chip=%p, channel=%p\n" , |
170 | channel_id, chip, channel); |
171 | #endif /* debug */ |
172 | /* channel->interrupt = snd_p16v_pcm_channel_interrupt; */ |
173 | err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); |
174 | if (err < 0) |
175 | return err; |
176 | |
177 | runtime->sync.id32[0] = substream->pcm->card->number; |
178 | runtime->sync.id32[1] = 'P'; |
179 | runtime->sync.id32[2] = 16; |
180 | runtime->sync.id32[3] = 'V'; |
181 | |
182 | return 0; |
183 | } |
184 | |
185 | /* open_capture callback */ |
186 | static int snd_p16v_pcm_open_capture_channel(struct snd_pcm_substream *substream, int channel_id) |
187 | { |
188 | struct snd_pcm_runtime *runtime = substream->runtime; |
189 | int err; |
190 | |
191 | /* |
192 | dev_dbg(emu->card->dev, "epcm device=%d, channel_id=%d\n", |
193 | substream->pcm->device, channel_id); |
194 | */ |
195 | |
196 | runtime->hw = snd_p16v_capture_hw; |
197 | |
198 | err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); |
199 | if (err < 0) |
200 | return err; |
201 | |
202 | return 0; |
203 | } |
204 | |
205 | |
206 | /* close callback */ |
207 | static int snd_p16v_pcm_close_playback(struct snd_pcm_substream *substream) |
208 | { |
209 | return 0; |
210 | } |
211 | |
212 | /* close callback */ |
213 | static int snd_p16v_pcm_close_capture(struct snd_pcm_substream *substream) |
214 | { |
215 | return 0; |
216 | } |
217 | |
218 | static int snd_p16v_pcm_open_playback_front(struct snd_pcm_substream *substream) |
219 | { |
220 | return snd_p16v_pcm_open_playback_channel(substream, PCM_FRONT_CHANNEL); |
221 | } |
222 | |
223 | static int snd_p16v_pcm_open_capture(struct snd_pcm_substream *substream) |
224 | { |
225 | // Only using channel 0 for now, but the card has 2 channels. |
226 | return snd_p16v_pcm_open_capture_channel(substream, channel_id: 0); |
227 | } |
228 | |
229 | /* prepare playback callback */ |
230 | static int snd_p16v_pcm_prepare_playback(struct snd_pcm_substream *substream) |
231 | { |
232 | struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); |
233 | struct snd_pcm_runtime *runtime = substream->runtime; |
234 | int channel = substream->pcm->device - emu->p16v_device_offset; |
235 | u32 *table_base = (u32 *)(emu->p16v_buffer->area+(8*16*channel)); |
236 | u32 period_size_bytes = frames_to_bytes(runtime, size: runtime->period_size); |
237 | int i; |
238 | u32 tmp; |
239 | |
240 | #if 0 /* debug */ |
241 | dev_dbg(emu->card->dev, |
242 | "prepare:channel_number=%d, rate=%d, " |
243 | "format=0x%x, channels=%d, buffer_size=%ld, " |
244 | "period_size=%ld, periods=%u, frames_to_bytes=%d\n" , |
245 | channel, runtime->rate, runtime->format, runtime->channels, |
246 | runtime->buffer_size, runtime->period_size, |
247 | runtime->periods, frames_to_bytes(runtime, 1)); |
248 | dev_dbg(emu->card->dev, |
249 | "dma_addr=%x, dma_area=%p, table_base=%p\n" , |
250 | runtime->dma_addr, runtime->dma_area, table_base); |
251 | dev_dbg(emu->card->dev, |
252 | "dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n" , |
253 | emu->p16v_buffer->addr, emu->p16v_buffer->area, |
254 | emu->p16v_buffer->bytes); |
255 | #endif /* debug */ |
256 | tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, chn: channel); |
257 | tmp &= ~(A_SPDIF_RATE_MASK | A_EHC_SRC48_MASK); |
258 | switch (runtime->rate) { |
259 | case 44100: |
260 | snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, chn: channel, |
261 | data: tmp | A_SPDIF_44100 | A_EHC_SRC48_44); |
262 | break; |
263 | case 96000: |
264 | snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, chn: channel, |
265 | data: tmp | A_SPDIF_96000 | A_EHC_SRC48_96); |
266 | break; |
267 | case 192000: |
268 | snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, chn: channel, |
269 | data: tmp | A_SPDIF_192000 | A_EHC_SRC48_192); |
270 | break; |
271 | case 48000: |
272 | default: |
273 | snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, chn: channel, |
274 | data: tmp | A_SPDIF_48000 | A_EHC_SRC48_BYPASS); |
275 | break; |
276 | } |
277 | /* FIXME: Check emu->buffer.size before actually writing to it. */ |
278 | for(i = 0; i < runtime->periods; i++) { |
279 | table_base[i*2]=runtime->dma_addr+(i*period_size_bytes); |
280 | table_base[(i*2)+1]=period_size_bytes<<16; |
281 | } |
282 | |
283 | snd_emu10k1_ptr20_write(emu, PLAYBACK_LIST_ADDR, chn: channel, data: emu->p16v_buffer->addr+(8*16*channel)); |
284 | snd_emu10k1_ptr20_write(emu, PLAYBACK_LIST_SIZE, chn: channel, data: (runtime->periods - 1) << 19); |
285 | snd_emu10k1_ptr20_write(emu, PLAYBACK_LIST_PTR, chn: channel, data: 0); |
286 | snd_emu10k1_ptr20_write(emu, PLAYBACK_DMA_ADDR, chn: channel, data: runtime->dma_addr); |
287 | //snd_emu10k1_ptr20_write(emu, PLAYBACK_PERIOD_SIZE, channel, frames_to_bytes(runtime, runtime->period_size)<<16); // buffer size in bytes |
288 | snd_emu10k1_ptr20_write(emu, PLAYBACK_PERIOD_SIZE, chn: channel, data: 0); // buffer size in bytes |
289 | snd_emu10k1_ptr20_write(emu, PLAYBACK_POINTER, chn: channel, data: 0); |
290 | snd_emu10k1_ptr20_write(emu, PLAYBACK_FIFO_END_ADDRESS, chn: channel, data: 0); |
291 | snd_emu10k1_ptr20_write(emu, PLAYBACK_FIFO_POINTER, chn: channel, data: 0); |
292 | |
293 | return 0; |
294 | } |
295 | |
296 | /* prepare capture callback */ |
297 | static int snd_p16v_pcm_prepare_capture(struct snd_pcm_substream *substream) |
298 | { |
299 | struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); |
300 | struct snd_pcm_runtime *runtime = substream->runtime; |
301 | int channel = substream->pcm->device - emu->p16v_device_offset; |
302 | |
303 | /* |
304 | dev_dbg(emu->card->dev, "prepare capture:channel_number=%d, rate=%d, " |
305 | "format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, " |
306 | "frames_to_bytes=%d\n", |
307 | channel, runtime->rate, runtime->format, runtime->channels, |
308 | runtime->buffer_size, runtime->period_size, |
309 | frames_to_bytes(runtime, 1)); |
310 | */ |
311 | switch (runtime->rate) { |
312 | case 44100: |
313 | snd_emu10k1_ptr_write(emu, reg: A_I2S_CAPTURE_RATE, chn: channel, A_I2S_CAPTURE_44100); |
314 | break; |
315 | case 96000: |
316 | snd_emu10k1_ptr_write(emu, reg: A_I2S_CAPTURE_RATE, chn: channel, A_I2S_CAPTURE_96000); |
317 | break; |
318 | case 192000: |
319 | snd_emu10k1_ptr_write(emu, reg: A_I2S_CAPTURE_RATE, chn: channel, A_I2S_CAPTURE_192000); |
320 | break; |
321 | case 48000: |
322 | default: |
323 | snd_emu10k1_ptr_write(emu, reg: A_I2S_CAPTURE_RATE, chn: channel, A_I2S_CAPTURE_48000); |
324 | break; |
325 | } |
326 | /* FIXME: Check emu->buffer.size before actually writing to it. */ |
327 | snd_emu10k1_ptr20_write(emu, CAPTURE_FIFO_POINTER, chn: channel, data: 0); |
328 | snd_emu10k1_ptr20_write(emu, CAPTURE_DMA_ADDR, chn: channel, data: runtime->dma_addr); |
329 | snd_emu10k1_ptr20_write(emu, CAPTURE_BUFFER_SIZE, chn: channel, data: frames_to_bytes(runtime, size: runtime->buffer_size) << 16); // buffer size in bytes |
330 | snd_emu10k1_ptr20_write(emu, CAPTURE_POINTER, chn: channel, data: 0); |
331 | //snd_emu10k1_ptr20_write(emu, CAPTURE_SOURCE, 0x0, 0x333300e4); /* Select MIC or Line in */ |
332 | //snd_emu10k1_ptr20_write(emu, EXTENDED_INT_MASK, 0, snd_emu10k1_ptr20_read(emu, EXTENDED_INT_MASK, 0) | (0x110000<<channel)); |
333 | |
334 | return 0; |
335 | } |
336 | |
337 | static void snd_p16v_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb) |
338 | { |
339 | unsigned long flags; |
340 | unsigned int enable; |
341 | |
342 | spin_lock_irqsave(&emu->emu_lock, flags); |
343 | enable = inl(port: emu->port + INTE2) | intrenb; |
344 | outl(value: enable, port: emu->port + INTE2); |
345 | spin_unlock_irqrestore(lock: &emu->emu_lock, flags); |
346 | } |
347 | |
348 | static void snd_p16v_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb) |
349 | { |
350 | unsigned long flags; |
351 | unsigned int disable; |
352 | |
353 | spin_lock_irqsave(&emu->emu_lock, flags); |
354 | disable = inl(port: emu->port + INTE2) & (~intrenb); |
355 | outl(value: disable, port: emu->port + INTE2); |
356 | spin_unlock_irqrestore(lock: &emu->emu_lock, flags); |
357 | } |
358 | |
359 | static void snd_p16v_interrupt(struct snd_emu10k1 *emu) |
360 | { |
361 | unsigned int status; |
362 | |
363 | while ((status = inl(port: emu->port + IPR2)) != 0) { |
364 | u32 mask = INTE2_PLAYBACK_CH_0_LOOP; /* Full Loop */ |
365 | |
366 | /* dev_dbg(emu->card->dev, "p16v status=0x%x\n", status); */ |
367 | if (status & mask) { |
368 | struct snd_pcm_substream *substream = |
369 | emu->pcm_p16v->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; |
370 | struct snd_pcm_runtime *runtime = substream->runtime; |
371 | |
372 | if (runtime && runtime->private_data) { |
373 | snd_pcm_period_elapsed(substream); |
374 | } else { |
375 | dev_err(emu->card->dev, |
376 | "p16v: status: 0x%08x, mask=0x%08x\n" , |
377 | status, mask); |
378 | } |
379 | } |
380 | if (status & 0x110000) { |
381 | struct snd_pcm_substream *substream = |
382 | emu->pcm_p16v->streams[SNDRV_PCM_STREAM_CAPTURE].substream; |
383 | struct snd_pcm_runtime *runtime = substream->runtime; |
384 | |
385 | /* dev_info(emu->card->dev, "capture int found\n"); */ |
386 | if (runtime && runtime->private_data) { |
387 | /* dev_info(emu->card->dev, "capture period_elapsed\n"); */ |
388 | snd_pcm_period_elapsed(substream); |
389 | } |
390 | } |
391 | outl(value: status, port: emu->port + IPR2); /* ack all */ |
392 | } |
393 | } |
394 | |
395 | /* trigger_playback callback */ |
396 | static int snd_p16v_pcm_trigger_playback(struct snd_pcm_substream *substream, |
397 | int cmd) |
398 | { |
399 | struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); |
400 | struct snd_pcm_runtime *runtime; |
401 | int channel; |
402 | int result = 0; |
403 | struct snd_pcm_substream *s; |
404 | u32 basic = 0; |
405 | u32 inte = 0; |
406 | int running = 0; |
407 | |
408 | switch (cmd) { |
409 | case SNDRV_PCM_TRIGGER_START: |
410 | running=1; |
411 | break; |
412 | case SNDRV_PCM_TRIGGER_STOP: |
413 | default: |
414 | running = 0; |
415 | break; |
416 | } |
417 | snd_pcm_group_for_each_entry(s, substream) { |
418 | if (snd_pcm_substream_chip(s) != emu || |
419 | s->stream != SNDRV_PCM_STREAM_PLAYBACK) |
420 | continue; |
421 | runtime = s->runtime; |
422 | channel = substream->pcm->device-emu->p16v_device_offset; |
423 | /* dev_dbg(emu->card->dev, "p16v channel=%d\n", channel); */ |
424 | runtime->private_data = (void *)(ptrdiff_t)running; |
425 | basic |= (0x1<<channel); |
426 | inte |= (INTE2_PLAYBACK_CH_0_LOOP<<channel); |
427 | snd_pcm_trigger_done(substream: s, master: substream); |
428 | } |
429 | /* dev_dbg(emu->card->dev, "basic=0x%x, inte=0x%x\n", basic, inte); */ |
430 | |
431 | switch (cmd) { |
432 | case SNDRV_PCM_TRIGGER_START: |
433 | snd_p16v_intr_enable(emu, intrenb: inte); |
434 | snd_emu10k1_ptr20_write(emu, BASIC_INTERRUPT, chn: 0, data: snd_emu10k1_ptr20_read(emu, BASIC_INTERRUPT, chn: 0)| (basic)); |
435 | break; |
436 | case SNDRV_PCM_TRIGGER_STOP: |
437 | snd_emu10k1_ptr20_write(emu, BASIC_INTERRUPT, chn: 0, data: snd_emu10k1_ptr20_read(emu, BASIC_INTERRUPT, chn: 0) & ~(basic)); |
438 | snd_p16v_intr_disable(emu, intrenb: inte); |
439 | break; |
440 | default: |
441 | result = -EINVAL; |
442 | break; |
443 | } |
444 | return result; |
445 | } |
446 | |
447 | /* trigger_capture callback */ |
448 | static int snd_p16v_pcm_trigger_capture(struct snd_pcm_substream *substream, |
449 | int cmd) |
450 | { |
451 | struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); |
452 | struct snd_pcm_runtime *runtime = substream->runtime; |
453 | int channel = 0; |
454 | int result = 0; |
455 | u32 inte = INTE2_CAPTURE_CH_0_LOOP | INTE2_CAPTURE_CH_0_HALF_LOOP; |
456 | |
457 | switch (cmd) { |
458 | case SNDRV_PCM_TRIGGER_START: |
459 | snd_p16v_intr_enable(emu, intrenb: inte); |
460 | snd_emu10k1_ptr20_write(emu, BASIC_INTERRUPT, chn: 0, data: snd_emu10k1_ptr20_read(emu, BASIC_INTERRUPT, chn: 0)|(0x100<<channel)); |
461 | runtime->private_data = (void *)1; |
462 | break; |
463 | case SNDRV_PCM_TRIGGER_STOP: |
464 | snd_emu10k1_ptr20_write(emu, BASIC_INTERRUPT, chn: 0, data: snd_emu10k1_ptr20_read(emu, BASIC_INTERRUPT, chn: 0) & ~(0x100<<channel)); |
465 | snd_p16v_intr_disable(emu, intrenb: inte); |
466 | //snd_emu10k1_ptr20_write(emu, EXTENDED_INT_MASK, 0, snd_emu10k1_ptr20_read(emu, EXTENDED_INT_MASK, 0) & ~(0x110000<<channel)); |
467 | runtime->private_data = NULL; |
468 | break; |
469 | default: |
470 | result = -EINVAL; |
471 | break; |
472 | } |
473 | return result; |
474 | } |
475 | |
476 | /* pointer_playback callback */ |
477 | static snd_pcm_uframes_t |
478 | snd_p16v_pcm_pointer_playback(struct snd_pcm_substream *substream) |
479 | { |
480 | struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); |
481 | struct snd_pcm_runtime *runtime = substream->runtime; |
482 | snd_pcm_uframes_t ptr, ptr1, ptr2,ptr3,ptr4 = 0; |
483 | int channel = substream->pcm->device - emu->p16v_device_offset; |
484 | |
485 | if (!runtime->private_data) |
486 | return 0; |
487 | |
488 | ptr3 = snd_emu10k1_ptr20_read(emu, PLAYBACK_LIST_PTR, chn: channel); |
489 | ptr1 = snd_emu10k1_ptr20_read(emu, PLAYBACK_POINTER, chn: channel); |
490 | ptr4 = snd_emu10k1_ptr20_read(emu, PLAYBACK_LIST_PTR, chn: channel); |
491 | if (ptr3 != ptr4) ptr1 = snd_emu10k1_ptr20_read(emu, PLAYBACK_POINTER, chn: channel); |
492 | ptr2 = bytes_to_frames(runtime, size: ptr1); |
493 | ptr2+= (ptr4 >> 3) * runtime->period_size; |
494 | ptr=ptr2; |
495 | if (ptr >= runtime->buffer_size) |
496 | ptr -= runtime->buffer_size; |
497 | |
498 | return ptr; |
499 | } |
500 | |
501 | /* pointer_capture callback */ |
502 | static snd_pcm_uframes_t |
503 | snd_p16v_pcm_pointer_capture(struct snd_pcm_substream *substream) |
504 | { |
505 | struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); |
506 | struct snd_pcm_runtime *runtime = substream->runtime; |
507 | snd_pcm_uframes_t ptr, ptr1, ptr2 = 0; |
508 | int channel = 0; |
509 | |
510 | if (!runtime->private_data) |
511 | return 0; |
512 | |
513 | ptr1 = snd_emu10k1_ptr20_read(emu, CAPTURE_POINTER, chn: channel); |
514 | ptr2 = bytes_to_frames(runtime, size: ptr1); |
515 | ptr=ptr2; |
516 | if (ptr >= runtime->buffer_size) { |
517 | ptr -= runtime->buffer_size; |
518 | dev_warn(emu->card->dev, "buffer capture limited!\n" ); |
519 | } |
520 | /* |
521 | dev_dbg(emu->card->dev, "ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, " |
522 | "buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n", |
523 | ptr1, ptr2, ptr, (int)runtime->buffer_size, |
524 | (int)runtime->period_size, (int)runtime->frame_bits, |
525 | (int)runtime->rate); |
526 | */ |
527 | return ptr; |
528 | } |
529 | |
530 | /* operators */ |
531 | static const struct snd_pcm_ops snd_p16v_playback_front_ops = { |
532 | .open = snd_p16v_pcm_open_playback_front, |
533 | .close = snd_p16v_pcm_close_playback, |
534 | .prepare = snd_p16v_pcm_prepare_playback, |
535 | .trigger = snd_p16v_pcm_trigger_playback, |
536 | .pointer = snd_p16v_pcm_pointer_playback, |
537 | }; |
538 | |
539 | static const struct snd_pcm_ops snd_p16v_capture_ops = { |
540 | .open = snd_p16v_pcm_open_capture, |
541 | .close = snd_p16v_pcm_close_capture, |
542 | .prepare = snd_p16v_pcm_prepare_capture, |
543 | .trigger = snd_p16v_pcm_trigger_capture, |
544 | .pointer = snd_p16v_pcm_pointer_capture, |
545 | }; |
546 | |
547 | int snd_p16v_pcm(struct snd_emu10k1 *emu, int device) |
548 | { |
549 | struct snd_pcm *pcm; |
550 | struct snd_pcm_substream *substream; |
551 | int err; |
552 | int capture=1; |
553 | |
554 | /* dev_dbg(emu->card->dev, "snd_p16v_pcm called. device=%d\n", device); */ |
555 | emu->p16v_device_offset = device; |
556 | |
557 | err = snd_pcm_new(card: emu->card, id: "p16v" , device, playback_count: 1, capture_count: capture, rpcm: &pcm); |
558 | if (err < 0) |
559 | return err; |
560 | |
561 | pcm->private_data = emu; |
562 | // Single playback 8 channel device. |
563 | // Single capture 2 channel device. |
564 | snd_pcm_set_ops(pcm, direction: SNDRV_PCM_STREAM_PLAYBACK, ops: &snd_p16v_playback_front_ops); |
565 | snd_pcm_set_ops(pcm, direction: SNDRV_PCM_STREAM_CAPTURE, ops: &snd_p16v_capture_ops); |
566 | |
567 | pcm->info_flags = 0; |
568 | pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; |
569 | strcpy(p: pcm->name, q: "p16v" ); |
570 | emu->pcm_p16v = pcm; |
571 | emu->p16v_interrupt = snd_p16v_interrupt; |
572 | |
573 | for(substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; |
574 | substream; |
575 | substream = substream->next) { |
576 | snd_pcm_set_managed_buffer(substream, SNDRV_DMA_TYPE_DEV, |
577 | data: &emu->pci->dev, |
578 | size: (65536 - 64) * 8, |
579 | max: (65536 - 64) * 8); |
580 | /* |
581 | dev_dbg(emu->card->dev, |
582 | "preallocate playback substream: err=%d\n", err); |
583 | */ |
584 | } |
585 | |
586 | for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; |
587 | substream; |
588 | substream = substream->next) { |
589 | snd_pcm_set_managed_buffer(substream, SNDRV_DMA_TYPE_DEV, |
590 | data: &emu->pci->dev, |
591 | size: 65536 - 64, max: 65536 - 64); |
592 | /* |
593 | dev_dbg(emu->card->dev, |
594 | "preallocate capture substream: err=%d\n", err); |
595 | */ |
596 | } |
597 | |
598 | return 0; |
599 | } |
600 | |
601 | static int snd_p16v_volume_info(struct snd_kcontrol *kcontrol, |
602 | struct snd_ctl_elem_info *uinfo) |
603 | { |
604 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
605 | uinfo->count = 2; |
606 | uinfo->value.integer.min = 0; |
607 | uinfo->value.integer.max = 255; |
608 | return 0; |
609 | } |
610 | |
611 | static int snd_p16v_volume_get(struct snd_kcontrol *kcontrol, |
612 | struct snd_ctl_elem_value *ucontrol) |
613 | { |
614 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); |
615 | int high_low = (kcontrol->private_value >> 8) & 0xff; |
616 | int reg = kcontrol->private_value & 0xff; |
617 | u32 value; |
618 | |
619 | value = snd_emu10k1_ptr20_read(emu, reg, chn: high_low); |
620 | if (high_low) { |
621 | ucontrol->value.integer.value[0] = 0xff - ((value >> 24) & 0xff); /* Left */ |
622 | ucontrol->value.integer.value[1] = 0xff - ((value >> 16) & 0xff); /* Right */ |
623 | } else { |
624 | ucontrol->value.integer.value[0] = 0xff - ((value >> 8) & 0xff); /* Left */ |
625 | ucontrol->value.integer.value[1] = 0xff - ((value >> 0) & 0xff); /* Right */ |
626 | } |
627 | return 0; |
628 | } |
629 | |
630 | static int snd_p16v_volume_put(struct snd_kcontrol *kcontrol, |
631 | struct snd_ctl_elem_value *ucontrol) |
632 | { |
633 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); |
634 | int high_low = (kcontrol->private_value >> 8) & 0xff; |
635 | int reg = kcontrol->private_value & 0xff; |
636 | u32 value, oval; |
637 | |
638 | oval = value = snd_emu10k1_ptr20_read(emu, reg, chn: 0); |
639 | if (high_low == 1) { |
640 | value &= 0xffff; |
641 | value |= ((0xff - ucontrol->value.integer.value[0]) << 24) | |
642 | ((0xff - ucontrol->value.integer.value[1]) << 16); |
643 | } else { |
644 | value &= 0xffff0000; |
645 | value |= ((0xff - ucontrol->value.integer.value[0]) << 8) | |
646 | ((0xff - ucontrol->value.integer.value[1]) ); |
647 | } |
648 | if (value != oval) { |
649 | snd_emu10k1_ptr20_write(emu, reg, chn: 0, data: value); |
650 | return 1; |
651 | } |
652 | return 0; |
653 | } |
654 | |
655 | static int snd_p16v_capture_source_info(struct snd_kcontrol *kcontrol, |
656 | struct snd_ctl_elem_info *uinfo) |
657 | { |
658 | static const char * const texts[8] = { |
659 | "SPDIF" , "I2S" , "SRC48" , "SRCMulti_SPDIF" , "SRCMulti_I2S" , |
660 | "CDIF" , "FX" , "AC97" |
661 | }; |
662 | |
663 | return snd_ctl_enum_info(info: uinfo, channels: 1, items: 8, names: texts); |
664 | } |
665 | |
666 | static int snd_p16v_capture_source_get(struct snd_kcontrol *kcontrol, |
667 | struct snd_ctl_elem_value *ucontrol) |
668 | { |
669 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); |
670 | |
671 | ucontrol->value.enumerated.item[0] = emu->p16v_capture_source; |
672 | return 0; |
673 | } |
674 | |
675 | static int snd_p16v_capture_source_put(struct snd_kcontrol *kcontrol, |
676 | struct snd_ctl_elem_value *ucontrol) |
677 | { |
678 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); |
679 | unsigned int val; |
680 | int change = 0; |
681 | u32 mask; |
682 | u32 source; |
683 | |
684 | val = ucontrol->value.enumerated.item[0] ; |
685 | if (val > 7) |
686 | return -EINVAL; |
687 | change = (emu->p16v_capture_source != val); |
688 | if (change) { |
689 | emu->p16v_capture_source = val; |
690 | source = (val << 28) | (val << 24) | (val << 20) | (val << 16); |
691 | mask = snd_emu10k1_ptr20_read(emu, BASIC_INTERRUPT, chn: 0) & 0xffff; |
692 | snd_emu10k1_ptr20_write(emu, BASIC_INTERRUPT, chn: 0, data: source | mask); |
693 | } |
694 | return change; |
695 | } |
696 | |
697 | static int snd_p16v_capture_channel_info(struct snd_kcontrol *kcontrol, |
698 | struct snd_ctl_elem_info *uinfo) |
699 | { |
700 | static const char * const texts[4] = { "0" , "1" , "2" , "3" , }; |
701 | |
702 | return snd_ctl_enum_info(info: uinfo, channels: 1, items: 4, names: texts); |
703 | } |
704 | |
705 | static int snd_p16v_capture_channel_get(struct snd_kcontrol *kcontrol, |
706 | struct snd_ctl_elem_value *ucontrol) |
707 | { |
708 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); |
709 | |
710 | ucontrol->value.enumerated.item[0] = emu->p16v_capture_channel; |
711 | return 0; |
712 | } |
713 | |
714 | static int snd_p16v_capture_channel_put(struct snd_kcontrol *kcontrol, |
715 | struct snd_ctl_elem_value *ucontrol) |
716 | { |
717 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); |
718 | unsigned int val; |
719 | int change = 0; |
720 | u32 tmp; |
721 | |
722 | val = ucontrol->value.enumerated.item[0] ; |
723 | if (val > 3) |
724 | return -EINVAL; |
725 | change = (emu->p16v_capture_channel != val); |
726 | if (change) { |
727 | emu->p16v_capture_channel = val; |
728 | tmp = snd_emu10k1_ptr20_read(emu, CAPTURE_P16V_SOURCE, chn: 0) & 0xfffc; |
729 | snd_emu10k1_ptr20_write(emu, CAPTURE_P16V_SOURCE, chn: 0, data: tmp | val); |
730 | } |
731 | return change; |
732 | } |
733 | static const DECLARE_TLV_DB_SCALE(snd_p16v_db_scale1, -5175, 25, 1); |
734 | |
735 | #define P16V_VOL(xname,xreg,xhl) { \ |
736 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
737 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ |
738 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ |
739 | .info = snd_p16v_volume_info, \ |
740 | .get = snd_p16v_volume_get, \ |
741 | .put = snd_p16v_volume_put, \ |
742 | .tlv = { .p = snd_p16v_db_scale1 }, \ |
743 | .private_value = ((xreg) | ((xhl) << 8)) \ |
744 | } |
745 | |
746 | static const struct snd_kcontrol_new p16v_mixer_controls[] = { |
747 | P16V_VOL("HD Analog Front Playback Volume" , PLAYBACK_VOLUME_MIXER9, 0), |
748 | P16V_VOL("HD Analog Rear Playback Volume" , PLAYBACK_VOLUME_MIXER10, 1), |
749 | P16V_VOL("HD Analog Center/LFE Playback Volume" , PLAYBACK_VOLUME_MIXER9, 1), |
750 | P16V_VOL("HD Analog Side Playback Volume" , PLAYBACK_VOLUME_MIXER10, 0), |
751 | P16V_VOL("HD SPDIF Front Playback Volume" , PLAYBACK_VOLUME_MIXER7, 0), |
752 | P16V_VOL("HD SPDIF Rear Playback Volume" , PLAYBACK_VOLUME_MIXER8, 1), |
753 | P16V_VOL("HD SPDIF Center/LFE Playback Volume" , PLAYBACK_VOLUME_MIXER7, 1), |
754 | P16V_VOL("HD SPDIF Side Playback Volume" , PLAYBACK_VOLUME_MIXER8, 0), |
755 | { |
756 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
757 | .name = "HD source Capture" , |
758 | .info = snd_p16v_capture_source_info, |
759 | .get = snd_p16v_capture_source_get, |
760 | .put = snd_p16v_capture_source_put |
761 | }, |
762 | { |
763 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
764 | .name = "HD channel Capture" , |
765 | .info = snd_p16v_capture_channel_info, |
766 | .get = snd_p16v_capture_channel_get, |
767 | .put = snd_p16v_capture_channel_put |
768 | }, |
769 | }; |
770 | |
771 | |
772 | int snd_p16v_mixer(struct snd_emu10k1 *emu) |
773 | { |
774 | int i, err; |
775 | struct snd_card *card = emu->card; |
776 | |
777 | for (i = 0; i < ARRAY_SIZE(p16v_mixer_controls); i++) { |
778 | err = snd_ctl_add(card, kcontrol: snd_ctl_new1(kcontrolnew: &p16v_mixer_controls[i], private_data: emu)); |
779 | if (err < 0) |
780 | return err; |
781 | } |
782 | return 0; |
783 | } |
784 | |
785 | #ifdef CONFIG_PM_SLEEP |
786 | |
787 | #define NUM_CHS 1 /* up to 4, but only first channel is used */ |
788 | |
789 | int snd_p16v_alloc_pm_buffer(struct snd_emu10k1 *emu) |
790 | { |
791 | emu->p16v_saved = vmalloc(array_size(NUM_CHS * 4, 0x80)); |
792 | if (! emu->p16v_saved) |
793 | return -ENOMEM; |
794 | return 0; |
795 | } |
796 | |
797 | void snd_p16v_free_pm_buffer(struct snd_emu10k1 *emu) |
798 | { |
799 | vfree(addr: emu->p16v_saved); |
800 | } |
801 | |
802 | void snd_p16v_suspend(struct snd_emu10k1 *emu) |
803 | { |
804 | int i, ch; |
805 | unsigned int *val; |
806 | |
807 | val = emu->p16v_saved; |
808 | for (ch = 0; ch < NUM_CHS; ch++) |
809 | for (i = 0; i < 0x80; i++, val++) |
810 | *val = snd_emu10k1_ptr20_read(emu, reg: i, chn: ch); |
811 | } |
812 | |
813 | void snd_p16v_resume(struct snd_emu10k1 *emu) |
814 | { |
815 | int i, ch; |
816 | unsigned int *val; |
817 | |
818 | val = emu->p16v_saved; |
819 | for (ch = 0; ch < NUM_CHS; ch++) |
820 | for (i = 0; i < 0x80; i++, val++) |
821 | snd_emu10k1_ptr20_write(emu, reg: i, chn: ch, data: *val); |
822 | } |
823 | #endif |
824 | |