brintos

brintos / linux-shallow public Read only

0
0
Text · 4.3 KiB · 806b4f9 Raw
171 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 *  Patch transfer callback for Emu10k14 *5 *  Copyright (C) 2000 Takashi iwai <tiwai@suse.de>6 */7/*8 * All the code for loading in a patch.  There is very little that is9 * chip specific here.  Just the actual writing to the board.10 */11 12#include "emu10k1_synth_local.h"13 14/*15 */16#define BLANK_LOOP_START	417#define BLANK_LOOP_END		818#define BLANK_LOOP_SIZE		1219#define BLANK_HEAD_SIZE		320 21/*22 * allocate a sample block and copy data from userspace23 */24int25snd_emu10k1_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,26		       struct snd_util_memhdr *hdr,27		       const void __user *data, long count)28{29	u8 fill;30	u32 xor;31	int shift;32	int offset;33	int truesize, size, blocksize;34	int loop_start, loop_end, loop_size, data_end, unroll;35	struct snd_emu10k1 *emu;36 37	emu = rec->hw;38	if (snd_BUG_ON(!sp || !hdr))39		return -EINVAL;40 41	if (sp->v.mode_flags & (SNDRV_SFNT_SAMPLE_BIDIR_LOOP | SNDRV_SFNT_SAMPLE_REVERSE_LOOP)) {42		/* should instead return -ENOTSUPP; but compatibility */43		dev_warn(emu->card->dev,44			 "Emu10k1 wavetable patch %d with unsupported loop feature\n",45			 sp->v.sample);46	}47 48	if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS) {49		shift = 0;50		fill = 0x80;51		xor = (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_UNSIGNED) ? 0 : 0x80808080;52	} else {53		shift = 1;54		fill = 0;55		xor = (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_UNSIGNED) ? 0x80008000 : 0;56	}57 58	/* compute true data size to be loaded */59	truesize = sp->v.size + BLANK_HEAD_SIZE;60	if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_NO_BLANK) {61		truesize += BLANK_LOOP_SIZE;62		/* if no blank loop is attached in the sample, add it */63		if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_SINGLESHOT) {64			sp->v.loopstart = sp->v.end + BLANK_LOOP_START;65			sp->v.loopend = sp->v.end + BLANK_LOOP_END;66		}67	}68 69	loop_start = sp->v.loopstart;70	loop_end = sp->v.loopend;71	loop_size = loop_end - loop_start;72	if (!loop_size)73		return -EINVAL;74	data_end = sp->v.end;75 76	/* recalculate offset */77	sp->v.start += BLANK_HEAD_SIZE;78	sp->v.end += BLANK_HEAD_SIZE;79	sp->v.loopstart += BLANK_HEAD_SIZE;80	sp->v.loopend += BLANK_HEAD_SIZE;81 82	// Automatic pre-filling of the cache does not work in the presence83	// of loops (*), and we don't want to fill it manually, as that is84	// fiddly and slow. So we unroll the loop until the loop end is85	// beyond the cache size.86	// (*) Strictly speaking, a single iteration is supported (that's87	// how it works when the playback engine runs), but handling this88	// special case is not worth it.89	unroll = 0;90	while (sp->v.loopend < 64) {91		truesize += loop_size;92		sp->v.loopstart += loop_size;93		sp->v.loopend += loop_size;94		sp->v.end += loop_size;95		unroll++;96	}97 98	/* try to allocate a memory block */99	blocksize = truesize << shift;100	sp->block = snd_emu10k1_synth_alloc(emu, blocksize);101	if (sp->block == NULL) {102		dev_dbg(emu->card->dev,103			"synth malloc failed (size=%d)\n", blocksize);104		/* not ENOMEM (for compatibility with OSS) */105		return -ENOSPC;106	}107	/* set the total size */108	sp->v.truesize = blocksize;109 110	/* write blank samples at head */111	offset = 0;112	size = BLANK_HEAD_SIZE << shift;113	snd_emu10k1_synth_memset(emu, sp->block, offset, size, fill);114	offset += size;115 116	/* copy provided samples */117	if (unroll && loop_end <= data_end) {118		size = loop_end << shift;119		if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size, xor))120			goto faulty;121		offset += size;122 123		data += loop_start << shift;124		while (--unroll > 0) {125			size = loop_size << shift;126			if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size, xor))127				goto faulty;128			offset += size;129		}130 131		size = (data_end - loop_start) << shift;132	} else {133		size = data_end << shift;134	}135	if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size, xor))136		goto faulty;137	offset += size;138 139	/* clear rest of samples (if any) */140	if (offset < blocksize)141		snd_emu10k1_synth_memset(emu, sp->block, offset, blocksize - offset, fill);142 143	return 0;144 145faulty:146	snd_emu10k1_synth_free(emu, sp->block);147	sp->block = NULL;148	return -EFAULT;149}150 151/*152 * free a sample block153 */154int155snd_emu10k1_sample_free(struct snd_emux *rec, struct snd_sf_sample *sp,156			struct snd_util_memhdr *hdr)157{158	struct snd_emu10k1 *emu;159 160	emu = rec->hw;161	if (snd_BUG_ON(!sp || !hdr))162		return -EINVAL;163 164	if (sp->block) {165		snd_emu10k1_synth_free(emu, sp->block);166		sp->block = NULL;167	}168	return 0;169}170 171