brintos

brintos / linux-shallow public Read only

0
0
Text · 25.5 KiB · a9a7589 Raw
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