[PATCH] w1: Added default generic read/write operations.
[linux-2.6/verdex.git] / sound / pci / emu10k1 / emu10k1_patch.c
blob42bae6f7e9a4c61458c96dab0cc89d5c2fa0252c
1 /*
2 * Patch transfer callback for Emu10k1
4 * Copyright (C) 2000 Takashi iwai <tiwai@suse.de>
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.
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.
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
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.
25 #include "emu10k1_synth_local.h"
29 #define BLANK_LOOP_START 4
30 #define BLANK_LOOP_END 8
31 #define BLANK_LOOP_SIZE 12
32 #define BLANK_HEAD_SIZE 32
35 * allocate a sample block and copy data from userspace
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)
42 int offset;
43 int truesize, size, loopsize, blocksize;
44 int loopend, sampleend;
45 unsigned int start_addr;
46 struct snd_emu10k1 *emu;
48 emu = rec->hw;
49 snd_assert(sp != NULL, return -EINVAL);
50 snd_assert(hdr != NULL, return -EINVAL);
52 if (sp->v.size == 0) {
53 snd_printd("emu: rom font for sample %d\n", sp->v.sample);
54 return 0;
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;
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;
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;
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;
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;
99 /* set the total size */
100 sp->v.truesize = blocksize;
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 snd_assert(offset + size <= blocksize, return -EINVAL);
108 snd_emu10k1_synth_bzero(emu, sp->block, offset, size);
109 offset += size;
111 /* copy start->loopend */
112 size = loopend;
113 if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
114 size *= 2;
115 snd_assert(offset + size <= blocksize, return -EINVAL);
116 if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size)) {
117 snd_emu10k1_synth_free(emu, sp->block);
118 sp->block = NULL;
119 return -EFAULT;
121 offset += size;
122 data += size;
124 #if 0 /* not suppported yet */
125 /* handle reverse (or bidirectional) loop */
126 if (sp->v.mode_flags & (SNDRV_SFNT_SAMPLE_BIDIR_LOOP|SNDRV_SFNT_SAMPLE_REVERSE_LOOP)) {
127 /* copy loop in reverse */
128 if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) {
129 int woffset;
130 unsigned short *wblock = (unsigned short*)block;
131 woffset = offset / 2;
132 snd_assert(offset + loopsize*2 <= blocksize, return -EINVAL);
133 for (i = 0; i < loopsize; i++)
134 wblock[woffset + i] = wblock[woffset - i -1];
135 offset += loopsize * 2;
136 } else {
137 snd_assert(offset + loopsize <= blocksize, return -EINVAL);
138 for (i = 0; i < loopsize; i++)
139 block[offset + i] = block[offset - i -1];
140 offset += loopsize;
143 /* modify loop pointers */
144 if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_BIDIR_LOOP) {
145 sp->v.loopend += loopsize;
146 } else {
147 sp->v.loopstart += loopsize;
148 sp->v.loopend += loopsize;
150 /* add sample pointer */
151 sp->v.end += loopsize;
153 #endif
155 /* loopend -> sample end */
156 size = sp->v.size - loopend;
157 snd_assert(size >= 0, return -EINVAL);
158 if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
159 size *= 2;
160 if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size)) {
161 snd_emu10k1_synth_free(emu, sp->block);
162 sp->block = NULL;
163 return -EFAULT;
165 offset += size;
167 /* clear rest of samples (if any) */
168 if (offset < blocksize)
169 snd_emu10k1_synth_bzero(emu, sp->block, offset, blocksize - offset);
171 if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_NO_BLANK) {
172 /* if no blank loop is attached in the sample, add it */
173 if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_SINGLESHOT) {
174 sp->v.loopstart = sp->v.end + BLANK_LOOP_START;
175 sp->v.loopend = sp->v.end + BLANK_LOOP_END;
179 #if 0 /* not supported yet */
180 if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_UNSIGNED) {
181 /* unsigned -> signed */
182 if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) {
183 unsigned short *wblock = (unsigned short*)block;
184 for (i = 0; i < truesize; i++)
185 wblock[i] ^= 0x8000;
186 } else {
187 for (i = 0; i < truesize; i++)
188 block[i] ^= 0x80;
191 #endif
193 /* recalculate offset */
194 start_addr = BLANK_HEAD_SIZE * 2;
195 if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
196 start_addr >>= 1;
197 sp->v.start += start_addr;
198 sp->v.end += start_addr;
199 sp->v.loopstart += start_addr;
200 sp->v.loopend += start_addr;
202 return 0;
206 * free a sample block
209 snd_emu10k1_sample_free(struct snd_emux *rec, struct snd_sf_sample *sp,
210 struct snd_util_memhdr *hdr)
212 struct snd_emu10k1 *emu;
214 emu = rec->hw;
215 snd_assert(sp != NULL, return -EINVAL);
216 snd_assert(hdr != NULL, return -EINVAL);
218 if (sp->block) {
219 snd_emu10k1_synth_free(emu, sp->block);
220 sp->block = NULL;
222 return 0;