831 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (c) by James Courtier-Dutton <James@superbug.demon.co.uk>4 * Driver p16v chips5 * Version: 0.256 *7 * FEATURES currently supported:8 * Output fixed at S32_LE, 2 channel to hw:0,09 * Rates: 44.1, 48, 96, 192.10 *11 * Changelog:12 * 0.813 * Use separate card based buffer for periods table.14 * 0.915 * 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.1019 * Fixed missed interrupts.20 * 0.1121 * Add Sound card model number and names.22 * Add Analog volume controls.23 * 0.1224 * Corrected playback interrupts. Now interrupt per period, instead of half period.25 * 0.1326 * Use single trigger for multichannel.27 * 0.1428 * Mic capture now works at fixed: S32_LE, 96000Hz, Stereo.29 * 0.1530 * Force buffer_size / period_size == INTEGER.31 * 0.1632 * Update p16v.c to work with changed alsa api.33 * 0.1734 * Update p16v.c to work with changed alsa api. Removed boot_devs.35 * 0.1836 * Merging with snd-emu10k1 driver.37 * 0.1938 * One stereo channel at 24bit now works.39 * 0.2040 * Added better register defines.41 * 0.2142 * Integrated with snd-emu10k1 driver.43 * 0.2244 * Removed #if 0 ... #endif45 * 0.2346 * Implement different capture rates.47 * 0.2448 * 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.2553 * 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: SB024067 * P16V Chip: CA0151-DBS68 * Audigy 2 Chip: CA0102-IAT69 * AC97 Codec: STAC 972170 * 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 094#define PCM_REAR_CHANNEL 195#define PCM_CENTER_LFE_CHANNEL 296#define PCM_SIDE_CHANNEL 397#define CONTROL_FRONT_CHANNEL 098#define CONTROL_REAR_CHANNEL 399#define CONTROL_CENTER_LFE_CHANNEL 1100#define CONTROL_SIDE_CHANNEL 2101 102/* Card IDs:103 * Class 0401: 1102:0004 (rev 04) Subsystem: 1102:2002 -> Audigy2 ZS 7.1 Model:SB0350104 * Class 0401: 1102:0004 (rev 04) Subsystem: 1102:1007 -> Audigy2 6.1 Model:SB0240105 * Class 0401: 1102:0004 (rev 04) Subsystem: 1102:1002 -> Audigy2 Platinum Model:SB msb0240230009266106 * Class 0401: 1102:0004 (rev 04) Subsystem: 1102:2007 -> Audigy4 Pro Model:SB0380 M1SB0380472001901E107 *108 */109 110 /* hardware definition */111static 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 132static 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 */153static 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 return 0;178}179 180/* open_capture callback */181static int snd_p16v_pcm_open_capture_channel(struct snd_pcm_substream *substream, int channel_id)182{183 struct snd_pcm_runtime *runtime = substream->runtime;184 int err;185 186 /*187 dev_dbg(emu->card->dev, "epcm device=%d, channel_id=%d\n",188 substream->pcm->device, channel_id);189 */190 191 runtime->hw = snd_p16v_capture_hw;192 193 err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);194 if (err < 0)195 return err;196 197 return 0;198}199 200 201/* close callback */202static int snd_p16v_pcm_close_playback(struct snd_pcm_substream *substream)203{204 return 0;205}206 207/* close callback */208static int snd_p16v_pcm_close_capture(struct snd_pcm_substream *substream)209{210 return 0;211}212 213static int snd_p16v_pcm_open_playback_front(struct snd_pcm_substream *substream)214{215 return snd_p16v_pcm_open_playback_channel(substream, PCM_FRONT_CHANNEL);216}217 218static int snd_p16v_pcm_open_capture(struct snd_pcm_substream *substream)219{220 // Only using channel 0 for now, but the card has 2 channels.221 return snd_p16v_pcm_open_capture_channel(substream, 0);222}223 224static int snd_p16v_pcm_ioctl_playback(struct snd_pcm_substream *substream,225 unsigned int cmd, void *arg)226{227 if (cmd == SNDRV_PCM_IOCTL1_SYNC_ID) {228 static const unsigned char id[4] = { 'P', '1', '6', 'V' };229 snd_pcm_set_sync_per_card(substream, arg, id, 4);230 return 0;231 }232 return snd_pcm_lib_ioctl(substream, cmd, arg);233}234 235/* prepare playback callback */236static int snd_p16v_pcm_prepare_playback(struct snd_pcm_substream *substream)237{238 struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);239 struct snd_pcm_runtime *runtime = substream->runtime;240 int channel = substream->pcm->device - emu->p16v_device_offset;241 u32 *table_base = (u32 *)(emu->p16v_buffer->area+(8*16*channel));242 u32 period_size_bytes = frames_to_bytes(runtime, runtime->period_size);243 int i;244 u32 tmp;245 246#if 0 /* debug */247 dev_dbg(emu->card->dev,248 "prepare:channel_number=%d, rate=%d, "249 "format=0x%x, channels=%d, buffer_size=%ld, "250 "period_size=%ld, periods=%u, frames_to_bytes=%d\n",251 channel, runtime->rate, runtime->format, runtime->channels,252 runtime->buffer_size, runtime->period_size,253 runtime->periods, frames_to_bytes(runtime, 1));254 dev_dbg(emu->card->dev,255 "dma_addr=%x, dma_area=%p, table_base=%p\n",256 runtime->dma_addr, runtime->dma_area, table_base);257 dev_dbg(emu->card->dev,258 "dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n",259 emu->p16v_buffer->addr, emu->p16v_buffer->area,260 emu->p16v_buffer->bytes);261#endif /* debug */262 tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, channel);263 tmp &= ~(A_SPDIF_RATE_MASK | A_EHC_SRC48_MASK);264 switch (runtime->rate) {265 case 44100:266 snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel,267 tmp | A_SPDIF_44100 | A_EHC_SRC48_44);268 break;269 case 96000:270 snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel,271 tmp | A_SPDIF_96000 | A_EHC_SRC48_96);272 break;273 case 192000:274 snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel,275 tmp | A_SPDIF_192000 | A_EHC_SRC48_192);276 break;277 case 48000:278 default:279 snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel,280 tmp | A_SPDIF_48000 | A_EHC_SRC48_BYPASS);281 break;282 }283 /* FIXME: Check emu->buffer.size before actually writing to it. */284 for(i = 0; i < runtime->periods; i++) {285 table_base[i*2]=runtime->dma_addr+(i*period_size_bytes);286 table_base[(i*2)+1]=period_size_bytes<<16;287 }288 289 snd_emu10k1_ptr20_write(emu, PLAYBACK_LIST_ADDR, channel, emu->p16v_buffer->addr+(8*16*channel));290 snd_emu10k1_ptr20_write(emu, PLAYBACK_LIST_SIZE, channel, (runtime->periods - 1) << 19);291 snd_emu10k1_ptr20_write(emu, PLAYBACK_LIST_PTR, channel, 0);292 snd_emu10k1_ptr20_write(emu, PLAYBACK_DMA_ADDR, channel, runtime->dma_addr);293 //snd_emu10k1_ptr20_write(emu, PLAYBACK_PERIOD_SIZE, channel, frames_to_bytes(runtime, runtime->period_size)<<16); // buffer size in bytes294 snd_emu10k1_ptr20_write(emu, PLAYBACK_PERIOD_SIZE, channel, 0); // buffer size in bytes295 snd_emu10k1_ptr20_write(emu, PLAYBACK_POINTER, channel, 0);296 snd_emu10k1_ptr20_write(emu, PLAYBACK_FIFO_END_ADDRESS, channel, 0);297 snd_emu10k1_ptr20_write(emu, PLAYBACK_FIFO_POINTER, channel, 0);298 299 return 0;300}301 302/* prepare capture callback */303static int snd_p16v_pcm_prepare_capture(struct snd_pcm_substream *substream)304{305 struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);306 struct snd_pcm_runtime *runtime = substream->runtime;307 int channel = substream->pcm->device - emu->p16v_device_offset;308 309 /*310 dev_dbg(emu->card->dev, "prepare capture:channel_number=%d, rate=%d, "311 "format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, "312 "frames_to_bytes=%d\n",313 channel, runtime->rate, runtime->format, runtime->channels,314 runtime->buffer_size, runtime->period_size,315 frames_to_bytes(runtime, 1));316 */317 switch (runtime->rate) {318 case 44100:319 snd_emu10k1_ptr_write(emu, A_I2S_CAPTURE_RATE, channel, A_I2S_CAPTURE_44100);320 break;321 case 96000:322 snd_emu10k1_ptr_write(emu, A_I2S_CAPTURE_RATE, channel, A_I2S_CAPTURE_96000);323 break;324 case 192000:325 snd_emu10k1_ptr_write(emu, A_I2S_CAPTURE_RATE, channel, A_I2S_CAPTURE_192000);326 break;327 case 48000:328 default:329 snd_emu10k1_ptr_write(emu, A_I2S_CAPTURE_RATE, channel, A_I2S_CAPTURE_48000);330 break;331 }332 /* FIXME: Check emu->buffer.size before actually writing to it. */333 snd_emu10k1_ptr20_write(emu, CAPTURE_FIFO_POINTER, channel, 0);334 snd_emu10k1_ptr20_write(emu, CAPTURE_DMA_ADDR, channel, runtime->dma_addr);335 snd_emu10k1_ptr20_write(emu, CAPTURE_BUFFER_SIZE, channel, frames_to_bytes(runtime, runtime->buffer_size) << 16); // buffer size in bytes336 snd_emu10k1_ptr20_write(emu, CAPTURE_POINTER, channel, 0);337 //snd_emu10k1_ptr20_write(emu, CAPTURE_SOURCE, 0x0, 0x333300e4); /* Select MIC or Line in */338 //snd_emu10k1_ptr20_write(emu, EXTENDED_INT_MASK, 0, snd_emu10k1_ptr20_read(emu, EXTENDED_INT_MASK, 0) | (0x110000<<channel));339 340 return 0;341}342 343static void snd_p16v_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb)344{345 unsigned long flags;346 unsigned int enable;347 348 spin_lock_irqsave(&emu->emu_lock, flags);349 enable = inl(emu->port + INTE2) | intrenb;350 outl(enable, emu->port + INTE2);351 spin_unlock_irqrestore(&emu->emu_lock, flags);352}353 354static void snd_p16v_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb)355{356 unsigned long flags;357 unsigned int disable;358 359 spin_lock_irqsave(&emu->emu_lock, flags);360 disable = inl(emu->port + INTE2) & (~intrenb);361 outl(disable, emu->port + INTE2);362 spin_unlock_irqrestore(&emu->emu_lock, flags);363}364 365static void snd_p16v_interrupt(struct snd_emu10k1 *emu)366{367 unsigned int status;368 369 while ((status = inl(emu->port + IPR2)) != 0) {370 u32 mask = INTE2_PLAYBACK_CH_0_LOOP; /* Full Loop */371 372 /* dev_dbg(emu->card->dev, "p16v status=0x%x\n", status); */373 if (status & mask) {374 struct snd_pcm_substream *substream =375 emu->pcm_p16v->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;376 struct snd_pcm_runtime *runtime = substream->runtime;377 378 if (runtime && runtime->private_data) {379 snd_pcm_period_elapsed(substream);380 } else {381 dev_err(emu->card->dev,382 "p16v: status: 0x%08x, mask=0x%08x\n",383 status, mask);384 }385 }386 if (status & 0x110000) {387 struct snd_pcm_substream *substream =388 emu->pcm_p16v->streams[SNDRV_PCM_STREAM_CAPTURE].substream;389 struct snd_pcm_runtime *runtime = substream->runtime;390 391 /* dev_info(emu->card->dev, "capture int found\n"); */392 if (runtime && runtime->private_data) {393 /* dev_info(emu->card->dev, "capture period_elapsed\n"); */394 snd_pcm_period_elapsed(substream);395 }396 }397 outl(status, emu->port + IPR2); /* ack all */398 }399}400 401/* trigger_playback callback */402static int snd_p16v_pcm_trigger_playback(struct snd_pcm_substream *substream,403 int cmd)404{405 struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);406 struct snd_pcm_runtime *runtime;407 int channel;408 int result = 0;409 struct snd_pcm_substream *s;410 u32 basic = 0;411 u32 inte = 0;412 int running = 0;413 414 switch (cmd) {415 case SNDRV_PCM_TRIGGER_START:416 running=1;417 break;418 case SNDRV_PCM_TRIGGER_STOP:419 default:420 running = 0;421 break;422 }423 snd_pcm_group_for_each_entry(s, substream) {424 if (snd_pcm_substream_chip(s) != emu ||425 s->stream != SNDRV_PCM_STREAM_PLAYBACK)426 continue;427 runtime = s->runtime;428 channel = substream->pcm->device-emu->p16v_device_offset;429 /* dev_dbg(emu->card->dev, "p16v channel=%d\n", channel); */430 runtime->private_data = (void *)(ptrdiff_t)running;431 basic |= (0x1<<channel);432 inte |= (INTE2_PLAYBACK_CH_0_LOOP<<channel);433 snd_pcm_trigger_done(s, substream);434 }435 /* dev_dbg(emu->card->dev, "basic=0x%x, inte=0x%x\n", basic, inte); */436 437 switch (cmd) {438 case SNDRV_PCM_TRIGGER_START:439 snd_p16v_intr_enable(emu, inte);440 snd_emu10k1_ptr20_write(emu, BASIC_INTERRUPT, 0, snd_emu10k1_ptr20_read(emu, BASIC_INTERRUPT, 0)| (basic));441 break;442 case SNDRV_PCM_TRIGGER_STOP:443 snd_emu10k1_ptr20_write(emu, BASIC_INTERRUPT, 0, snd_emu10k1_ptr20_read(emu, BASIC_INTERRUPT, 0) & ~(basic));444 snd_p16v_intr_disable(emu, inte);445 break;446 default:447 result = -EINVAL;448 break;449 }450 return result;451}452 453/* trigger_capture callback */454static int snd_p16v_pcm_trigger_capture(struct snd_pcm_substream *substream,455 int cmd)456{457 struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);458 struct snd_pcm_runtime *runtime = substream->runtime;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 runtime->private_data = (void *)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 runtime->private_data = NULL;474 break;475 default:476 result = -EINVAL;477 break;478 }479 return result;480}481 482/* pointer_playback callback */483static snd_pcm_uframes_t484snd_p16v_pcm_pointer_playback(struct snd_pcm_substream *substream)485{486 struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);487 struct snd_pcm_runtime *runtime = substream->runtime;488 snd_pcm_uframes_t ptr, ptr1, ptr2,ptr3,ptr4 = 0;489 int channel = substream->pcm->device - emu->p16v_device_offset;490 491 if (!runtime->private_data)492 return 0;493 494 ptr3 = snd_emu10k1_ptr20_read(emu, PLAYBACK_LIST_PTR, channel);495 ptr1 = snd_emu10k1_ptr20_read(emu, PLAYBACK_POINTER, channel);496 ptr4 = snd_emu10k1_ptr20_read(emu, PLAYBACK_LIST_PTR, channel);497 if (ptr3 != ptr4) ptr1 = snd_emu10k1_ptr20_read(emu, PLAYBACK_POINTER, channel);498 ptr2 = bytes_to_frames(runtime, ptr1);499 ptr2+= (ptr4 >> 3) * runtime->period_size;500 ptr=ptr2;501 if (ptr >= runtime->buffer_size)502 ptr -= runtime->buffer_size;503 504 return ptr;505}506 507/* pointer_capture callback */508static snd_pcm_uframes_t509snd_p16v_pcm_pointer_capture(struct snd_pcm_substream *substream)510{511 struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream);512 struct snd_pcm_runtime *runtime = substream->runtime;513 snd_pcm_uframes_t ptr, ptr1, ptr2 = 0;514 int channel = 0;515 516 if (!runtime->private_data)517 return 0;518 519 ptr1 = snd_emu10k1_ptr20_read(emu, CAPTURE_POINTER, channel);520 ptr2 = bytes_to_frames(runtime, ptr1);521 ptr=ptr2;522 if (ptr >= runtime->buffer_size) {523 ptr -= runtime->buffer_size;524 dev_warn(emu->card->dev, "buffer capture limited!\n");525 }526 /*527 dev_dbg(emu->card->dev, "ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, "528 "buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n",529 ptr1, ptr2, ptr, (int)runtime->buffer_size,530 (int)runtime->period_size, (int)runtime->frame_bits,531 (int)runtime->rate);532 */533 return ptr;534}535 536/* operators */537static const struct snd_pcm_ops snd_p16v_playback_front_ops = {538 .open = snd_p16v_pcm_open_playback_front,539 .close = snd_p16v_pcm_close_playback,540 .ioctl = snd_p16v_pcm_ioctl_playback,541 .prepare = snd_p16v_pcm_prepare_playback,542 .trigger = snd_p16v_pcm_trigger_playback,543 .pointer = snd_p16v_pcm_pointer_playback,544};545 546static const struct snd_pcm_ops snd_p16v_capture_ops = {547 .open = snd_p16v_pcm_open_capture,548 .close = snd_p16v_pcm_close_capture,549 .prepare = snd_p16v_pcm_prepare_capture,550 .trigger = snd_p16v_pcm_trigger_capture,551 .pointer = snd_p16v_pcm_pointer_capture,552};553 554int snd_p16v_pcm(struct snd_emu10k1 *emu, int device)555{556 struct snd_pcm *pcm;557 struct snd_pcm_substream *substream;558 int err;559 int capture=1;560 561 /* dev_dbg(emu->card->dev, "snd_p16v_pcm called. device=%d\n", device); */562 emu->p16v_device_offset = device;563 564 err = snd_pcm_new(emu->card, "p16v", device, 1, capture, &pcm);565 if (err < 0)566 return err;567 568 pcm->private_data = emu;569 // Single playback 8 channel device.570 // Single capture 2 channel device.571 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_p16v_playback_front_ops);572 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_p16v_capture_ops);573 574 pcm->info_flags = 0;575 pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;576 strcpy(pcm->name, "p16v");577 emu->pcm_p16v = pcm;578 emu->p16v_interrupt = snd_p16v_interrupt;579 580 for(substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; 581 substream; 582 substream = substream->next) {583 snd_pcm_set_managed_buffer(substream, SNDRV_DMA_TYPE_DEV,584 &emu->pci->dev,585 (65536 - 64) * 8,586 (65536 - 64) * 8);587 /*588 dev_dbg(emu->card->dev,589 "preallocate playback substream: err=%d\n", err);590 */591 }592 593 for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; 594 substream; 595 substream = substream->next) {596 snd_pcm_set_managed_buffer(substream, SNDRV_DMA_TYPE_DEV,597 &emu->pci->dev,598 65536 - 64, 65536 - 64);599 /*600 dev_dbg(emu->card->dev,601 "preallocate capture substream: err=%d\n", err);602 */603 }604 605 return 0;606}607 608static int snd_p16v_volume_info(struct snd_kcontrol *kcontrol,609 struct snd_ctl_elem_info *uinfo)610{611 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;612 uinfo->count = 2;613 uinfo->value.integer.min = 0;614 uinfo->value.integer.max = 255;615 return 0;616}617 618static int snd_p16v_volume_get(struct snd_kcontrol *kcontrol,619 struct snd_ctl_elem_value *ucontrol)620{621 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);622 int high_low = (kcontrol->private_value >> 8) & 0xff;623 int reg = kcontrol->private_value & 0xff;624 u32 value;625 626 value = snd_emu10k1_ptr20_read(emu, reg, high_low);627 if (high_low) {628 ucontrol->value.integer.value[0] = 0xff - ((value >> 24) & 0xff); /* Left */629 ucontrol->value.integer.value[1] = 0xff - ((value >> 16) & 0xff); /* Right */630 } else {631 ucontrol->value.integer.value[0] = 0xff - ((value >> 8) & 0xff); /* Left */632 ucontrol->value.integer.value[1] = 0xff - ((value >> 0) & 0xff); /* Right */633 }634 return 0;635}636 637static int snd_p16v_volume_put(struct snd_kcontrol *kcontrol,638 struct snd_ctl_elem_value *ucontrol)639{640 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);641 int high_low = (kcontrol->private_value >> 8) & 0xff;642 int reg = kcontrol->private_value & 0xff;643 u32 value, oval;644 645 oval = value = snd_emu10k1_ptr20_read(emu, reg, 0);646 if (high_low == 1) {647 value &= 0xffff;648 value |= ((0xff - ucontrol->value.integer.value[0]) << 24) |649 ((0xff - ucontrol->value.integer.value[1]) << 16);650 } else {651 value &= 0xffff0000;652 value |= ((0xff - ucontrol->value.integer.value[0]) << 8) |653 ((0xff - ucontrol->value.integer.value[1]) );654 }655 if (value != oval) {656 snd_emu10k1_ptr20_write(emu, reg, 0, value);657 return 1;658 }659 return 0;660}661 662static int snd_p16v_capture_source_info(struct snd_kcontrol *kcontrol,663 struct snd_ctl_elem_info *uinfo)664{665 static const char * const texts[8] = {666 "SPDIF", "I2S", "SRC48", "SRCMulti_SPDIF", "SRCMulti_I2S",667 "CDIF", "FX", "AC97"668 };669 670 return snd_ctl_enum_info(uinfo, 1, 8, texts);671}672 673static int snd_p16v_capture_source_get(struct snd_kcontrol *kcontrol,674 struct snd_ctl_elem_value *ucontrol)675{676 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);677 678 ucontrol->value.enumerated.item[0] = emu->p16v_capture_source;679 return 0;680}681 682static int snd_p16v_capture_source_put(struct snd_kcontrol *kcontrol,683 struct snd_ctl_elem_value *ucontrol)684{685 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);686 unsigned int val;687 int change = 0;688 u32 mask;689 u32 source;690 691 val = ucontrol->value.enumerated.item[0] ;692 if (val > 7)693 return -EINVAL;694 change = (emu->p16v_capture_source != val);695 if (change) {696 emu->p16v_capture_source = val;697 source = (val << 28) | (val << 24) | (val << 20) | (val << 16);698 mask = snd_emu10k1_ptr20_read(emu, BASIC_INTERRUPT, 0) & 0xffff;699 snd_emu10k1_ptr20_write(emu, BASIC_INTERRUPT, 0, source | mask);700 }701 return change;702}703 704static int snd_p16v_capture_channel_info(struct snd_kcontrol *kcontrol,705 struct snd_ctl_elem_info *uinfo)706{707 static const char * const texts[4] = { "0", "1", "2", "3", };708 709 return snd_ctl_enum_info(uinfo, 1, 4, texts);710}711 712static int snd_p16v_capture_channel_get(struct snd_kcontrol *kcontrol,713 struct snd_ctl_elem_value *ucontrol)714{715 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);716 717 ucontrol->value.enumerated.item[0] = emu->p16v_capture_channel;718 return 0;719}720 721static int snd_p16v_capture_channel_put(struct snd_kcontrol *kcontrol,722 struct snd_ctl_elem_value *ucontrol)723{724 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);725 unsigned int val;726 int change = 0;727 u32 tmp;728 729 val = ucontrol->value.enumerated.item[0] ;730 if (val > 3)731 return -EINVAL;732 change = (emu->p16v_capture_channel != val);733 if (change) {734 emu->p16v_capture_channel = val;735 tmp = snd_emu10k1_ptr20_read(emu, CAPTURE_P16V_SOURCE, 0) & 0xfffc;736 snd_emu10k1_ptr20_write(emu, CAPTURE_P16V_SOURCE, 0, tmp | val);737 }738 return change;739}740static const DECLARE_TLV_DB_SCALE(snd_p16v_db_scale1, -5175, 25, 1);741 742#define P16V_VOL(xname,xreg,xhl) { \743 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \744 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \745 SNDRV_CTL_ELEM_ACCESS_TLV_READ, \746 .info = snd_p16v_volume_info, \747 .get = snd_p16v_volume_get, \748 .put = snd_p16v_volume_put, \749 .tlv = { .p = snd_p16v_db_scale1 }, \750 .private_value = ((xreg) | ((xhl) << 8)) \751}752 753static const struct snd_kcontrol_new p16v_mixer_controls[] = {754 P16V_VOL("HD Analog Front Playback Volume", PLAYBACK_VOLUME_MIXER9, 0),755 P16V_VOL("HD Analog Rear Playback Volume", PLAYBACK_VOLUME_MIXER10, 1),756 P16V_VOL("HD Analog Center/LFE Playback Volume", PLAYBACK_VOLUME_MIXER9, 1),757 P16V_VOL("HD Analog Side Playback Volume", PLAYBACK_VOLUME_MIXER10, 0),758 P16V_VOL("HD SPDIF Front Playback Volume", PLAYBACK_VOLUME_MIXER7, 0),759 P16V_VOL("HD SPDIF Rear Playback Volume", PLAYBACK_VOLUME_MIXER8, 1),760 P16V_VOL("HD SPDIF Center/LFE Playback Volume", PLAYBACK_VOLUME_MIXER7, 1),761 P16V_VOL("HD SPDIF Side Playback Volume", PLAYBACK_VOLUME_MIXER8, 0),762 {763 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,764 .name = "HD source Capture",765 .info = snd_p16v_capture_source_info,766 .get = snd_p16v_capture_source_get,767 .put = snd_p16v_capture_source_put768 },769 {770 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,771 .name = "HD channel Capture",772 .info = snd_p16v_capture_channel_info,773 .get = snd_p16v_capture_channel_get,774 .put = snd_p16v_capture_channel_put775 },776};777 778 779int snd_p16v_mixer(struct snd_emu10k1 *emu)780{781 int i, err;782 struct snd_card *card = emu->card;783 784 for (i = 0; i < ARRAY_SIZE(p16v_mixer_controls); i++) {785 err = snd_ctl_add(card, snd_ctl_new1(&p16v_mixer_controls[i], emu));786 if (err < 0)787 return err;788 }789 return 0;790}791 792#ifdef CONFIG_PM_SLEEP793 794#define NUM_CHS 1 /* up to 4, but only first channel is used */795 796int snd_p16v_alloc_pm_buffer(struct snd_emu10k1 *emu)797{798 emu->p16v_saved = vmalloc(array_size(NUM_CHS * 4, 0x80));799 if (! emu->p16v_saved)800 return -ENOMEM;801 return 0;802}803 804void snd_p16v_free_pm_buffer(struct snd_emu10k1 *emu)805{806 vfree(emu->p16v_saved);807}808 809void snd_p16v_suspend(struct snd_emu10k1 *emu)810{811 int i, ch;812 unsigned int *val;813 814 val = emu->p16v_saved;815 for (ch = 0; ch < NUM_CHS; ch++)816 for (i = 0; i < 0x80; i++, val++)817 *val = snd_emu10k1_ptr20_read(emu, i, ch);818}819 820void snd_p16v_resume(struct snd_emu10k1 *emu)821{822 int i, ch;823 unsigned int *val;824 825 val = emu->p16v_saved;826 for (ch = 0; ch < NUM_CHS; ch++)827 for (i = 0; i < 0x80; i++, val++)828 snd_emu10k1_ptr20_write(emu, i, ch, *val);829}830#endif831