Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/sound/pci/emu10k1/emu10k1_patch.c
10820 views
1
/*
2
* Patch transfer callback for Emu10k1
3
*
4
* Copyright (C) 2000 Takashi iwai <[email protected]>
5
*
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
10
*
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
15
*
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
*/
20
/*
21
* All the code for loading in a patch. There is very little that is
22
* chip specific here. Just the actual writing to the board.
23
*/
24
25
#include "emu10k1_synth_local.h"
26
27
/*
28
*/
29
#define BLANK_LOOP_START 4
30
#define BLANK_LOOP_END 8
31
#define BLANK_LOOP_SIZE 12
32
#define BLANK_HEAD_SIZE 32
33
34
/*
35
* allocate a sample block and copy data from userspace
36
*/
37
int
38
snd_emu10k1_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,
39
struct snd_util_memhdr *hdr,
40
const void __user *data, long count)
41
{
42
int offset;
43
int truesize, size, loopsize, blocksize;
44
int loopend, sampleend;
45
unsigned int start_addr;
46
struct snd_emu10k1 *emu;
47
48
emu = rec->hw;
49
if (snd_BUG_ON(!sp || !hdr))
50
return -EINVAL;
51
52
if (sp->v.size == 0) {
53
snd_printd("emu: rom font for sample %d\n", sp->v.sample);
54
return 0;
55
}
56
57
/* recalculate address offset */
58
sp->v.end -= sp->v.start;
59
sp->v.loopstart -= sp->v.start;
60
sp->v.loopend -= sp->v.start;
61
sp->v.start = 0;
62
63
/* some samples have invalid data. the addresses are corrected in voice info */
64
sampleend = sp->v.end;
65
if (sampleend > sp->v.size)
66
sampleend = sp->v.size;
67
loopend = sp->v.loopend;
68
if (loopend > sampleend)
69
loopend = sampleend;
70
71
/* be sure loop points start < end */
72
if (sp->v.loopstart >= sp->v.loopend) {
73
int tmp = sp->v.loopstart;
74
sp->v.loopstart = sp->v.loopend;
75
sp->v.loopend = tmp;
76
}
77
78
/* compute true data size to be loaded */
79
truesize = sp->v.size + BLANK_HEAD_SIZE;
80
loopsize = 0;
81
#if 0 /* not supported */
82
if (sp->v.mode_flags & (SNDRV_SFNT_SAMPLE_BIDIR_LOOP|SNDRV_SFNT_SAMPLE_REVERSE_LOOP))
83
loopsize = sp->v.loopend - sp->v.loopstart;
84
truesize += loopsize;
85
#endif
86
if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_NO_BLANK)
87
truesize += BLANK_LOOP_SIZE;
88
89
/* try to allocate a memory block */
90
blocksize = truesize;
91
if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
92
blocksize *= 2;
93
sp->block = snd_emu10k1_synth_alloc(emu, blocksize);
94
if (sp->block == NULL) {
95
snd_printd("emu10k1: synth malloc failed (size=%d)\n", blocksize);
96
/* not ENOMEM (for compatibility with OSS) */
97
return -ENOSPC;
98
}
99
/* set the total size */
100
sp->v.truesize = blocksize;
101
102
/* write blank samples at head */
103
offset = 0;
104
size = BLANK_HEAD_SIZE;
105
if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
106
size *= 2;
107
if (offset + size > blocksize)
108
return -EINVAL;
109
snd_emu10k1_synth_bzero(emu, sp->block, offset, size);
110
offset += size;
111
112
/* copy start->loopend */
113
size = loopend;
114
if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
115
size *= 2;
116
if (offset + size > blocksize)
117
return -EINVAL;
118
if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size)) {
119
snd_emu10k1_synth_free(emu, sp->block);
120
sp->block = NULL;
121
return -EFAULT;
122
}
123
offset += size;
124
data += size;
125
126
#if 0 /* not suppported yet */
127
/* handle reverse (or bidirectional) loop */
128
if (sp->v.mode_flags & (SNDRV_SFNT_SAMPLE_BIDIR_LOOP|SNDRV_SFNT_SAMPLE_REVERSE_LOOP)) {
129
/* copy loop in reverse */
130
if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) {
131
int woffset;
132
unsigned short *wblock = (unsigned short*)block;
133
woffset = offset / 2;
134
if (offset + loopsize * 2 > blocksize)
135
return -EINVAL;
136
for (i = 0; i < loopsize; i++)
137
wblock[woffset + i] = wblock[woffset - i -1];
138
offset += loopsize * 2;
139
} else {
140
if (offset + loopsize > blocksize)
141
return -EINVAL;
142
for (i = 0; i < loopsize; i++)
143
block[offset + i] = block[offset - i -1];
144
offset += loopsize;
145
}
146
147
/* modify loop pointers */
148
if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_BIDIR_LOOP) {
149
sp->v.loopend += loopsize;
150
} else {
151
sp->v.loopstart += loopsize;
152
sp->v.loopend += loopsize;
153
}
154
/* add sample pointer */
155
sp->v.end += loopsize;
156
}
157
#endif
158
159
/* loopend -> sample end */
160
size = sp->v.size - loopend;
161
if (size < 0)
162
return -EINVAL;
163
if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
164
size *= 2;
165
if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size)) {
166
snd_emu10k1_synth_free(emu, sp->block);
167
sp->block = NULL;
168
return -EFAULT;
169
}
170
offset += size;
171
172
/* clear rest of samples (if any) */
173
if (offset < blocksize)
174
snd_emu10k1_synth_bzero(emu, sp->block, offset, blocksize - offset);
175
176
if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_NO_BLANK) {
177
/* if no blank loop is attached in the sample, add it */
178
if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_SINGLESHOT) {
179
sp->v.loopstart = sp->v.end + BLANK_LOOP_START;
180
sp->v.loopend = sp->v.end + BLANK_LOOP_END;
181
}
182
}
183
184
#if 0 /* not supported yet */
185
if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_UNSIGNED) {
186
/* unsigned -> signed */
187
if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) {
188
unsigned short *wblock = (unsigned short*)block;
189
for (i = 0; i < truesize; i++)
190
wblock[i] ^= 0x8000;
191
} else {
192
for (i = 0; i < truesize; i++)
193
block[i] ^= 0x80;
194
}
195
}
196
#endif
197
198
/* recalculate offset */
199
start_addr = BLANK_HEAD_SIZE * 2;
200
if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
201
start_addr >>= 1;
202
sp->v.start += start_addr;
203
sp->v.end += start_addr;
204
sp->v.loopstart += start_addr;
205
sp->v.loopend += start_addr;
206
207
return 0;
208
}
209
210
/*
211
* free a sample block
212
*/
213
int
214
snd_emu10k1_sample_free(struct snd_emux *rec, struct snd_sf_sample *sp,
215
struct snd_util_memhdr *hdr)
216
{
217
struct snd_emu10k1 *emu;
218
219
emu = rec->hw;
220
if (snd_BUG_ON(!sp || !hdr))
221
return -EINVAL;
222
223
if (sp->block) {
224
snd_emu10k1_synth_free(emu, sp->block);
225
sp->block = NULL;
226
}
227
return 0;
228
}
229
230
231