File Index
Files and directories
Sign in
FILE

emu10k1_patch.c

File preview with syntax highlighting.

linux-6.19.14/sound/pci/emu10k1/emu10k1_patch.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 *  Patch transfer callback for Emu10k1
  4 *
  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 is
  9 * 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	4
 17#define BLANK_LOOP_END		8
 18#define BLANK_LOOP_SIZE		12
 19#define BLANK_HEAD_SIZE		3
 20
 21/*
 22 * allocate a sample block and copy data from userspace
 23 */
 24int
 25snd_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 presence
 83	// of loops (*), and we don't want to fill it manually, as that is
 84	// fiddly and slow. So we unroll the loop until the loop end is
 85	// beyond the cache size.
 86	// (*) Strictly speaking, a single iteration is supported (that's
 87	// how it works when the playback engine runs), but handling this
 88	// 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 block
153 */
154int
155snd_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
~/ Read-only file preview.