brintos

brintos / linux-shallow public Read only

0
0
Text · 6.5 KiB · aaa82ec Raw
275 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Driver for Sound Core PDAudioCF soundcards4 *5 * PCM part6 *7 * Copyright (c) 2003 by Jaroslav Kysela <perex@perex.cz>8 */9 10#include <linux/delay.h>11#include <sound/core.h>12#include <sound/asoundef.h>13#include "pdaudiocf.h"14 15 16/*17 * clear the SRAM contents18 */19static int pdacf_pcm_clear_sram(struct snd_pdacf *chip)20{21	int max_loop = 64 * 1024;22 23	while (inw(chip->port + PDAUDIOCF_REG_RDP) != inw(chip->port + PDAUDIOCF_REG_WDP)) {24		if (max_loop-- < 0)25			return -EIO;26		inw(chip->port + PDAUDIOCF_REG_MD);27	}28	return 0;29}30 31/*32 * pdacf_pcm_trigger - trigger callback for capture33 */34static int pdacf_pcm_trigger(struct snd_pcm_substream *subs, int cmd)35{36	struct snd_pdacf *chip = snd_pcm_substream_chip(subs);37	struct snd_pcm_runtime *runtime = subs->runtime;38	int inc, ret = 0, rate;39	unsigned short mask, val, tmp;40 41	if (chip->chip_status & PDAUDIOCF_STAT_IS_STALE)42		return -EBUSY;43 44	switch (cmd) {45	case SNDRV_PCM_TRIGGER_START:46		chip->pcm_hwptr = 0;47		chip->pcm_tdone = 0;48		fallthrough;49	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:50	case SNDRV_PCM_TRIGGER_RESUME:51		mask = 0;52		val = PDAUDIOCF_RECORD;53		inc = 1;54		rate = snd_ak4117_check_rate_and_errors(chip->ak4117, AK4117_CHECK_NO_STAT|AK4117_CHECK_NO_RATE);55		break;56	case SNDRV_PCM_TRIGGER_STOP:57	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:58	case SNDRV_PCM_TRIGGER_SUSPEND:59		mask = PDAUDIOCF_RECORD;60		val = 0;61		inc = -1;62		rate = 0;63		break;64	default:65		return -EINVAL;66	}67	mutex_lock(&chip->reg_lock);68	chip->pcm_running += inc;69	tmp = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR);70	if (chip->pcm_running) {71		if ((chip->ak4117->rcs0 & AK4117_UNLCK) || runtime->rate != rate) {72			chip->pcm_running -= inc;73			ret = -EIO;74			goto __end;75		}76	}77	tmp &= ~mask;78	tmp |= val;79	pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, tmp);80      __end:81	mutex_unlock(&chip->reg_lock);82	snd_ak4117_check_rate_and_errors(chip->ak4117, AK4117_CHECK_NO_RATE);83	return ret;84}85 86/*87 * pdacf_pcm_prepare - prepare callback for playback and capture88 */89static int pdacf_pcm_prepare(struct snd_pcm_substream *subs)90{91	struct snd_pdacf *chip = snd_pcm_substream_chip(subs);92	struct snd_pcm_runtime *runtime = subs->runtime;93	u16 val, nval, aval;94 95	if (chip->chip_status & PDAUDIOCF_STAT_IS_STALE)96		return -EBUSY;97 98	chip->pcm_channels = runtime->channels;99 100	chip->pcm_little = snd_pcm_format_little_endian(runtime->format) > 0;101#ifdef SNDRV_LITTLE_ENDIAN102	chip->pcm_swab = snd_pcm_format_big_endian(runtime->format) > 0;103#else104	chip->pcm_swab = chip->pcm_little;105#endif106 107	if (snd_pcm_format_unsigned(runtime->format))108		chip->pcm_xor = 0x80008000;109 110	if (pdacf_pcm_clear_sram(chip) < 0)111		return -EIO;112	113	val = nval = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR);114	nval &= ~(PDAUDIOCF_DATAFMT0|PDAUDIOCF_DATAFMT1);115	switch (runtime->format) {116	case SNDRV_PCM_FORMAT_S16_LE:117	case SNDRV_PCM_FORMAT_S16_BE:118		break;119	default: /* 24-bit */120		nval |= PDAUDIOCF_DATAFMT0 | PDAUDIOCF_DATAFMT1;121		break;122	}123	aval = 0;124	chip->pcm_sample = 4;125	switch (runtime->format) {126	case SNDRV_PCM_FORMAT_S16_LE:127	case SNDRV_PCM_FORMAT_S16_BE:128		aval = AK4117_DIF_16R;129		chip->pcm_frame = 2;130		chip->pcm_sample = 2;131		break;132	case SNDRV_PCM_FORMAT_S24_3LE:133	case SNDRV_PCM_FORMAT_S24_3BE:134		chip->pcm_sample = 3;135		fallthrough;136	default: /* 24-bit */137		aval = AK4117_DIF_24R;138		chip->pcm_frame = 3;139		chip->pcm_xor &= 0xffff0000;140		break;141	}142 143	if (val != nval) {144		snd_ak4117_reg_write(chip->ak4117, AK4117_REG_IO, AK4117_DIF2|AK4117_DIF1|AK4117_DIF0, aval);145		pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, nval);146	}147 148	val = pdacf_reg_read(chip,  PDAUDIOCF_REG_IER);149	val &= ~(PDAUDIOCF_IRQLVLEN1);150	val |= PDAUDIOCF_IRQLVLEN0;151	pdacf_reg_write(chip, PDAUDIOCF_REG_IER, val);152 153	chip->pcm_size = runtime->buffer_size;154	chip->pcm_period = runtime->period_size;155	chip->pcm_area = runtime->dma_area;156 157	return 0;158}159 160 161/*162 * capture hw information163 */164 165static const struct snd_pcm_hardware pdacf_pcm_capture_hw = {166	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |167				 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME |168				 SNDRV_PCM_INFO_MMAP_VALID |169				 SNDRV_PCM_INFO_BATCH),170	.formats =		SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |171				SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE |172				SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE,173	.rates =		SNDRV_PCM_RATE_32000 |174				SNDRV_PCM_RATE_44100 |175				SNDRV_PCM_RATE_48000 |176				SNDRV_PCM_RATE_88200 |177				SNDRV_PCM_RATE_96000 |178				SNDRV_PCM_RATE_176400 |179				SNDRV_PCM_RATE_192000,180	.rate_min =		32000,181	.rate_max =		192000,182	.channels_min =		1,183	.channels_max =		2,184	.buffer_bytes_max =	(512*1024),185	.period_bytes_min =	8*1024,186	.period_bytes_max =	(64*1024),187	.periods_min =		2,188	.periods_max =		128,189	.fifo_size =		0,190};191 192 193/*194 * pdacf_pcm_capture_open - open callback for capture195 */196static int pdacf_pcm_capture_open(struct snd_pcm_substream *subs)197{198	struct snd_pcm_runtime *runtime = subs->runtime;199	struct snd_pdacf *chip = snd_pcm_substream_chip(subs);200 201	if (chip->chip_status & PDAUDIOCF_STAT_IS_STALE)202		return -EBUSY;203 204	runtime->hw = pdacf_pcm_capture_hw;205	runtime->private_data = chip;206	chip->pcm_substream = subs;207 208	return 0;209}210 211/*212 * pdacf_pcm_capture_close - close callback for capture213 */214static int pdacf_pcm_capture_close(struct snd_pcm_substream *subs)215{216	struct snd_pdacf *chip = snd_pcm_substream_chip(subs);217 218	if (!chip)219		return -EINVAL;220	pdacf_reinit(chip, 0);221	chip->pcm_substream = NULL;222	return 0;223}224 225 226/*227 * pdacf_pcm_capture_pointer - pointer callback for capture228 */229static snd_pcm_uframes_t pdacf_pcm_capture_pointer(struct snd_pcm_substream *subs)230{231	struct snd_pdacf *chip = snd_pcm_substream_chip(subs);232	return chip->pcm_hwptr;233}234 235/*236 * operators for PCM capture237 */238static const struct snd_pcm_ops pdacf_pcm_capture_ops = {239	.open =		pdacf_pcm_capture_open,240	.close =	pdacf_pcm_capture_close,241	.prepare =	pdacf_pcm_prepare,242	.trigger =	pdacf_pcm_trigger,243	.pointer =	pdacf_pcm_capture_pointer,244};245 246 247/*248 * snd_pdacf_pcm_new - create and initialize a pcm249 */250int snd_pdacf_pcm_new(struct snd_pdacf *chip)251{252	struct snd_pcm *pcm;253	int err;254 255	err = snd_pcm_new(chip->card, "PDAudioCF", 0, 0, 1, &pcm);256	if (err < 0)257		return err;258		259	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pdacf_pcm_capture_ops);260	snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL,261				       0, 0);262 263	pcm->private_data = chip;264	pcm->info_flags = 0;265	pcm->nonatomic = true;266	strcpy(pcm->name, chip->card->shortname);267	chip->pcm = pcm;268	269	err = snd_ak4117_build(chip->ak4117, pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream);270	if (err < 0)271		return err;272 273	return 0;274}275