xref: /linux/sound/pci/emu10k1/emu10k1_patch.c (revision 36ec807b627b4c0a0a382f0ae48eac7187d14b2b)
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  */
24 int
25 snd_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 		printk(KERN_WARNING "Emu10k1 wavetable patch %d with unsupported loop feature\n",
44 		       sp->v.sample);
45 	}
46 
47 	if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS) {
48 		shift = 0;
49 		fill = 0x80;
50 		xor = (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_UNSIGNED) ? 0 : 0x80808080;
51 	} else {
52 		shift = 1;
53 		fill = 0;
54 		xor = (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_UNSIGNED) ? 0x80008000 : 0;
55 	}
56 
57 	/* compute true data size to be loaded */
58 	truesize = sp->v.size + BLANK_HEAD_SIZE;
59 	if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_NO_BLANK) {
60 		truesize += BLANK_LOOP_SIZE;
61 		/* if no blank loop is attached in the sample, add it */
62 		if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_SINGLESHOT) {
63 			sp->v.loopstart = sp->v.end + BLANK_LOOP_START;
64 			sp->v.loopend = sp->v.end + BLANK_LOOP_END;
65 		}
66 	}
67 
68 	loop_start = sp->v.loopstart;
69 	loop_end = sp->v.loopend;
70 	loop_size = loop_end - loop_start;
71 	if (!loop_size)
72 		return -EINVAL;
73 	data_end = sp->v.end;
74 
75 	/* recalculate offset */
76 	sp->v.start += BLANK_HEAD_SIZE;
77 	sp->v.end += BLANK_HEAD_SIZE;
78 	sp->v.loopstart += BLANK_HEAD_SIZE;
79 	sp->v.loopend += BLANK_HEAD_SIZE;
80 
81 	// Automatic pre-filling of the cache does not work in the presence
82 	// of loops (*), and we don't want to fill it manually, as that is
83 	// fiddly and slow. So we unroll the loop until the loop end is
84 	// beyond the cache size.
85 	// (*) Strictly speaking, a single iteration is supported (that's
86 	// how it works when the playback engine runs), but handling this
87 	// special case is not worth it.
88 	unroll = 0;
89 	while (sp->v.loopend < 64) {
90 		truesize += loop_size;
91 		sp->v.loopstart += loop_size;
92 		sp->v.loopend += loop_size;
93 		sp->v.end += loop_size;
94 		unroll++;
95 	}
96 
97 	/* try to allocate a memory block */
98 	blocksize = truesize << shift;
99 	sp->block = snd_emu10k1_synth_alloc(emu, blocksize);
100 	if (sp->block == NULL) {
101 		dev_dbg(emu->card->dev,
102 			"synth malloc failed (size=%d)\n", blocksize);
103 		/* not ENOMEM (for compatibility with OSS) */
104 		return -ENOSPC;
105 	}
106 	/* set the total size */
107 	sp->v.truesize = blocksize;
108 
109 	/* write blank samples at head */
110 	offset = 0;
111 	size = BLANK_HEAD_SIZE << shift;
112 	snd_emu10k1_synth_memset(emu, sp->block, offset, size, fill);
113 	offset += size;
114 
115 	/* copy provided samples */
116 	if (unroll && loop_end <= data_end) {
117 		size = loop_end << shift;
118 		if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size, xor))
119 			goto faulty;
120 		offset += size;
121 
122 		data += loop_start << shift;
123 		while (--unroll > 0) {
124 			size = loop_size << shift;
125 			if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size, xor))
126 				goto faulty;
127 			offset += size;
128 		}
129 
130 		size = (data_end - loop_start) << shift;
131 	} else {
132 		size = data_end << shift;
133 	}
134 	if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size, xor))
135 		goto faulty;
136 	offset += size;
137 
138 	/* clear rest of samples (if any) */
139 	if (offset < blocksize)
140 		snd_emu10k1_synth_memset(emu, sp->block, offset, blocksize - offset, fill);
141 
142 	return 0;
143 
144 faulty:
145 	snd_emu10k1_synth_free(emu, sp->block);
146 	sp->block = NULL;
147 	return -EFAULT;
148 }
149 
150 /*
151  * free a sample block
152  */
153 int
154 snd_emu10k1_sample_free(struct snd_emux *rec, struct snd_sf_sample *sp,
155 			struct snd_util_memhdr *hdr)
156 {
157 	struct snd_emu10k1 *emu;
158 
159 	emu = rec->hw;
160 	if (snd_BUG_ON(!sp || !hdr))
161 		return -EINVAL;
162 
163 	if (sp->block) {
164 		snd_emu10k1_synth_free(emu, sp->block);
165 		sp->block = NULL;
166 	}
167 	return 0;
168 }
169 
170