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
snd_emu10k1_sample_new(struct snd_emux * rec,struct snd_sf_sample * sp,struct snd_util_memhdr * hdr,const void __user * data,long count)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 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
145 faulty:
146 snd_emu10k1_synth_free(emu, sp->block);
147 sp->block = NULL;
148 return -EFAULT;
149 }
150
151 /*
152 * free a sample block
153 */
154 int
snd_emu10k1_sample_free(struct snd_emux * rec,struct snd_sf_sample * sp,struct snd_util_memhdr * hdr)155 snd_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