]> git.proxmox.com Git - mirror_ubuntu-focal-kernel.git/blame - sound/pci/emu10k1/emu10k1_patch.c
treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 156
[mirror_ubuntu-focal-kernel.git] / sound / pci / emu10k1 / emu10k1_patch.c
CommitLineData
1a59d1b8 1// SPDX-License-Identifier: GPL-2.0-or-later
1da177e4
LT
2/*
3 * Patch transfer callback for Emu10k1
4 *
5 * Copyright (C) 2000 Takashi iwai <tiwai@suse.de>
1da177e4
LT
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 32
20
21/*
22 * allocate a sample block and copy data from userspace
23 */
24int
eb4698f3
TI
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)
1da177e4
LT
28{
29 int offset;
30 int truesize, size, loopsize, blocksize;
31 int loopend, sampleend;
32 unsigned int start_addr;
eb4698f3 33 struct snd_emu10k1 *emu;
1da177e4
LT
34
35 emu = rec->hw;
da3cec35
TI
36 if (snd_BUG_ON(!sp || !hdr))
37 return -EINVAL;
1da177e4
LT
38
39 if (sp->v.size == 0) {
6f002b02
TI
40 dev_dbg(emu->card->dev,
41 "emu: rom font for sample %d\n", sp->v.sample);
1da177e4
LT
42 return 0;
43 }
44
45 /* recalculate address offset */
46 sp->v.end -= sp->v.start;
47 sp->v.loopstart -= sp->v.start;
48 sp->v.loopend -= sp->v.start;
49 sp->v.start = 0;
50
51 /* some samples have invalid data. the addresses are corrected in voice info */
52 sampleend = sp->v.end;
53 if (sampleend > sp->v.size)
54 sampleend = sp->v.size;
55 loopend = sp->v.loopend;
56 if (loopend > sampleend)
57 loopend = sampleend;
58
59 /* be sure loop points start < end */
e2d2f240
GS
60 if (sp->v.loopstart >= sp->v.loopend)
61 swap(sp->v.loopstart, sp->v.loopend);
1da177e4
LT
62
63 /* compute true data size to be loaded */
64 truesize = sp->v.size + BLANK_HEAD_SIZE;
65 loopsize = 0;
66#if 0 /* not supported */
67 if (sp->v.mode_flags & (SNDRV_SFNT_SAMPLE_BIDIR_LOOP|SNDRV_SFNT_SAMPLE_REVERSE_LOOP))
68 loopsize = sp->v.loopend - sp->v.loopstart;
69 truesize += loopsize;
70#endif
71 if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_NO_BLANK)
72 truesize += BLANK_LOOP_SIZE;
73
74 /* try to allocate a memory block */
75 blocksize = truesize;
76 if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
77 blocksize *= 2;
78 sp->block = snd_emu10k1_synth_alloc(emu, blocksize);
79 if (sp->block == NULL) {
6f002b02
TI
80 dev_dbg(emu->card->dev,
81 "synth malloc failed (size=%d)\n", blocksize);
1da177e4
LT
82 /* not ENOMEM (for compatibility with OSS) */
83 return -ENOSPC;
84 }
85 /* set the total size */
86 sp->v.truesize = blocksize;
87
88 /* write blank samples at head */
89 offset = 0;
90 size = BLANK_HEAD_SIZE;
91 if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
92 size *= 2;
da3cec35
TI
93 if (offset + size > blocksize)
94 return -EINVAL;
1da177e4
LT
95 snd_emu10k1_synth_bzero(emu, sp->block, offset, size);
96 offset += size;
97
98 /* copy start->loopend */
99 size = loopend;
100 if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
101 size *= 2;
da3cec35
TI
102 if (offset + size > blocksize)
103 return -EINVAL;
1da177e4
LT
104 if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size)) {
105 snd_emu10k1_synth_free(emu, sp->block);
106 sp->block = NULL;
107 return -EFAULT;
108 }
109 offset += size;
110 data += size;
111
d7558148 112#if 0 /* not supported yet */
1da177e4
LT
113 /* handle reverse (or bidirectional) loop */
114 if (sp->v.mode_flags & (SNDRV_SFNT_SAMPLE_BIDIR_LOOP|SNDRV_SFNT_SAMPLE_REVERSE_LOOP)) {
115 /* copy loop in reverse */
116 if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) {
117 int woffset;
118 unsigned short *wblock = (unsigned short*)block;
119 woffset = offset / 2;
da3cec35
TI
120 if (offset + loopsize * 2 > blocksize)
121 return -EINVAL;
1da177e4
LT
122 for (i = 0; i < loopsize; i++)
123 wblock[woffset + i] = wblock[woffset - i -1];
124 offset += loopsize * 2;
125 } else {
da3cec35
TI
126 if (offset + loopsize > blocksize)
127 return -EINVAL;
1da177e4
LT
128 for (i = 0; i < loopsize; i++)
129 block[offset + i] = block[offset - i -1];
130 offset += loopsize;
131 }
132
133 /* modify loop pointers */
134 if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_BIDIR_LOOP) {
135 sp->v.loopend += loopsize;
136 } else {
137 sp->v.loopstart += loopsize;
138 sp->v.loopend += loopsize;
139 }
140 /* add sample pointer */
141 sp->v.end += loopsize;
142 }
143#endif
144
145 /* loopend -> sample end */
146 size = sp->v.size - loopend;
da3cec35
TI
147 if (size < 0)
148 return -EINVAL;
1da177e4
LT
149 if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
150 size *= 2;
151 if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size)) {
152 snd_emu10k1_synth_free(emu, sp->block);
153 sp->block = NULL;
154 return -EFAULT;
155 }
156 offset += size;
157
158 /* clear rest of samples (if any) */
159 if (offset < blocksize)
160 snd_emu10k1_synth_bzero(emu, sp->block, offset, blocksize - offset);
161
162 if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_NO_BLANK) {
163 /* if no blank loop is attached in the sample, add it */
164 if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_SINGLESHOT) {
165 sp->v.loopstart = sp->v.end + BLANK_LOOP_START;
166 sp->v.loopend = sp->v.end + BLANK_LOOP_END;
167 }
168 }
169
170#if 0 /* not supported yet */
171 if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_UNSIGNED) {
172 /* unsigned -> signed */
173 if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) {
174 unsigned short *wblock = (unsigned short*)block;
175 for (i = 0; i < truesize; i++)
176 wblock[i] ^= 0x8000;
177 } else {
178 for (i = 0; i < truesize; i++)
179 block[i] ^= 0x80;
180 }
181 }
182#endif
183
184 /* recalculate offset */
185 start_addr = BLANK_HEAD_SIZE * 2;
186 if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
187 start_addr >>= 1;
188 sp->v.start += start_addr;
189 sp->v.end += start_addr;
190 sp->v.loopstart += start_addr;
191 sp->v.loopend += start_addr;
192
193 return 0;
194}
195
196/*
197 * free a sample block
198 */
199int
eb4698f3
TI
200snd_emu10k1_sample_free(struct snd_emux *rec, struct snd_sf_sample *sp,
201 struct snd_util_memhdr *hdr)
1da177e4 202{
eb4698f3 203 struct snd_emu10k1 *emu;
1da177e4
LT
204
205 emu = rec->hw;
da3cec35
TI
206 if (snd_BUG_ON(!sp || !hdr))
207 return -EINVAL;
1da177e4
LT
208
209 if (sp->block) {
210 snd_emu10k1_synth_free(emu, sp->block);
211 sp->block = NULL;
212 }
213 return 0;
214}
215