Merge git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86
[sfrench/cifs-2.6.git] / sound / pci / trident / trident_synth.c
1 /*
2  *  Routines for Trident 4DWave NX/DX soundcards - Synthesizer
3  *  Copyright (c) by Scott McNab <jedi@tartarus.uwa.edu.au>
4  *
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
22 #include <sound/driver.h>
23 #include <asm/io.h>
24 #include <linux/init.h>
25 #include <linux/slab.h>
26 #include <linux/pci.h>
27 #include <sound/core.h>
28 #include <sound/trident.h>
29 #include <sound/seq_device.h>
30
31 MODULE_AUTHOR("Scott McNab <jedi@tartarus.uwa.edu.au>");
32 MODULE_DESCRIPTION("Routines for Trident 4DWave NX/DX soundcards - Synthesizer");
33 MODULE_LICENSE("GPL");
34
35 /* linear to log pan conversion table (4.2 channel attenuation format) */
36 static unsigned int pan_table[63] = {
37         7959, 7733, 7514, 7301, 7093, 6892, 6697, 6507, 
38         6322, 6143, 5968, 5799, 5634, 5475, 5319, 5168, 
39         5022, 4879, 4741, 4606, 4475, 4349, 4225, 4105, 
40         3989, 3876, 3766, 3659, 3555, 3454, 3356, 3261, 
41         3168, 3078, 2991, 2906, 2824, 2744, 2666, 2590, 
42         2517, 2445, 2376, 2308, 2243, 2179, 2117, 2057, 
43         1999, 1942, 1887, 1833, 1781, 1731, 1682, 1634, 
44         1588, 1543, 1499, 1456, 1415, 1375, 1336
45 };
46
47 #define LOG_TABLE_SIZE 386
48
49 /* Linear half-attenuation to log conversion table in the format:
50  *   {linear volume, logarithmic attenuation equivalent}, ...
51  *
52  * Provides conversion from a linear half-volume value in the range
53  * [0,8192] to a logarithmic attenuation value in the range 0 to 6.02dB.
54  * Halving the linear volume is equivalent to an additional 6dB of 
55  * logarithmic attenuation. The algorithm used in log_from_linear()
56  * therefore uses this table as follows:
57  * 
58  * - loop and for every time the volume is less than half the maximum 
59  *   volume (16384), add another 6dB and halve the maximum value used
60  *   for this comparison.
61  * - when the volume is greater than half the maximum volume, take
62  *   the difference of the volume to half volume (in the range [0,8192])
63  *   and look up the log_table[] to find the nearest entry.
64  * - take the logarithic component of this entry and add it to the 
65  *   resulting attenuation.
66  *
67  * Thus this routine provides a linear->log conversion for a range of
68  * [0,16384] using only 386 table entries
69  *
70  * Note: although this table stores log attenuation in 8.8 format, values
71  * were only calculated for 6 bits fractional precision, since that is
72  * the most precision offered by the trident hardware.
73  */
74
75 static unsigned short log_table[LOG_TABLE_SIZE*2] =
76 {
77         4, 0x0604, 19, 0x0600, 34, 0x05fc, 
78         49, 0x05f8, 63, 0x05f4, 78, 0x05f0, 93, 0x05ec, 108, 0x05e8, 
79         123, 0x05e4, 138, 0x05e0, 153, 0x05dc, 168, 0x05d8, 183, 0x05d4, 
80         198, 0x05d0, 213, 0x05cc, 228, 0x05c8, 244, 0x05c4, 259, 0x05c0, 
81         274, 0x05bc, 289, 0x05b8, 304, 0x05b4, 320, 0x05b0, 335, 0x05ac, 
82         350, 0x05a8, 366, 0x05a4, 381, 0x05a0, 397, 0x059c, 412, 0x0598, 
83         428, 0x0594, 443, 0x0590, 459, 0x058c, 474, 0x0588, 490, 0x0584, 
84         506, 0x0580, 521, 0x057c, 537, 0x0578, 553, 0x0574, 568, 0x0570, 
85         584, 0x056c, 600, 0x0568, 616, 0x0564, 632, 0x0560, 647, 0x055c, 
86         663, 0x0558, 679, 0x0554, 695, 0x0550, 711, 0x054c, 727, 0x0548, 
87         743, 0x0544, 759, 0x0540, 776, 0x053c, 792, 0x0538, 808, 0x0534, 
88         824, 0x0530, 840, 0x052c, 857, 0x0528, 873, 0x0524, 889, 0x0520, 
89         906, 0x051c, 922, 0x0518, 938, 0x0514, 955, 0x0510, 971, 0x050c, 
90         988, 0x0508, 1004, 0x0504, 1021, 0x0500, 1037, 0x04fc, 1054, 0x04f8, 
91         1071, 0x04f4, 1087, 0x04f0, 1104, 0x04ec, 1121, 0x04e8, 1138, 0x04e4, 
92         1154, 0x04e0, 1171, 0x04dc, 1188, 0x04d8, 1205, 0x04d4, 1222, 0x04d0, 
93         1239, 0x04cc, 1256, 0x04c8, 1273, 0x04c4, 1290, 0x04c0, 1307, 0x04bc, 
94         1324, 0x04b8, 1341, 0x04b4, 1358, 0x04b0, 1376, 0x04ac, 1393, 0x04a8, 
95         1410, 0x04a4, 1427, 0x04a0, 1445, 0x049c, 1462, 0x0498, 1479, 0x0494, 
96         1497, 0x0490, 1514, 0x048c, 1532, 0x0488, 1549, 0x0484, 1567, 0x0480, 
97         1584, 0x047c, 1602, 0x0478, 1620, 0x0474, 1637, 0x0470, 1655, 0x046c, 
98         1673, 0x0468, 1690, 0x0464, 1708, 0x0460, 1726, 0x045c, 1744, 0x0458, 
99         1762, 0x0454, 1780, 0x0450, 1798, 0x044c, 1816, 0x0448, 1834, 0x0444, 
100         1852, 0x0440, 1870, 0x043c, 1888, 0x0438, 1906, 0x0434, 1924, 0x0430, 
101         1943, 0x042c, 1961, 0x0428, 1979, 0x0424, 1997, 0x0420, 2016, 0x041c, 
102         2034, 0x0418, 2053, 0x0414, 2071, 0x0410, 2089, 0x040c, 2108, 0x0408, 
103         2127, 0x0404, 2145, 0x0400, 2164, 0x03fc, 2182, 0x03f8, 2201, 0x03f4, 
104         2220, 0x03f0, 2239, 0x03ec, 2257, 0x03e8, 2276, 0x03e4, 2295, 0x03e0, 
105         2314, 0x03dc, 2333, 0x03d8, 2352, 0x03d4, 2371, 0x03d0, 2390, 0x03cc, 
106         2409, 0x03c8, 2428, 0x03c4, 2447, 0x03c0, 2466, 0x03bc, 2485, 0x03b8, 
107         2505, 0x03b4, 2524, 0x03b0, 2543, 0x03ac, 2562, 0x03a8, 2582, 0x03a4, 
108         2601, 0x03a0, 2621, 0x039c, 2640, 0x0398, 2660, 0x0394, 2679, 0x0390, 
109         2699, 0x038c, 2718, 0x0388, 2738, 0x0384, 2758, 0x0380, 2777, 0x037c, 
110         2797, 0x0378, 2817, 0x0374, 2837, 0x0370, 2857, 0x036c, 2876, 0x0368, 
111         2896, 0x0364, 2916, 0x0360, 2936, 0x035c, 2956, 0x0358, 2976, 0x0354, 
112         2997, 0x0350, 3017, 0x034c, 3037, 0x0348, 3057, 0x0344, 3077, 0x0340, 
113         3098, 0x033c, 3118, 0x0338, 3138, 0x0334, 3159, 0x0330, 3179, 0x032c, 
114         3200, 0x0328, 3220, 0x0324, 3241, 0x0320, 3261, 0x031c, 3282, 0x0318, 
115         3303, 0x0314, 3323, 0x0310, 3344, 0x030c, 3365, 0x0308, 3386, 0x0304, 
116         3406, 0x0300, 3427, 0x02fc, 3448, 0x02f8, 3469, 0x02f4, 3490, 0x02f0, 
117         3511, 0x02ec, 3532, 0x02e8, 3553, 0x02e4, 3575, 0x02e0, 3596, 0x02dc, 
118         3617, 0x02d8, 3638, 0x02d4, 3660, 0x02d0, 3681, 0x02cc, 3702, 0x02c8, 
119         3724, 0x02c4, 3745, 0x02c0, 3767, 0x02bc, 3788, 0x02b8, 3810, 0x02b4, 
120         3831, 0x02b0, 3853, 0x02ac, 3875, 0x02a8, 3896, 0x02a4, 3918, 0x02a0, 
121         3940, 0x029c, 3962, 0x0298, 3984, 0x0294, 4006, 0x0290, 4028, 0x028c, 
122         4050, 0x0288, 4072, 0x0284, 4094, 0x0280, 4116, 0x027c, 4138, 0x0278, 
123         4160, 0x0274, 4182, 0x0270, 4205, 0x026c, 4227, 0x0268, 4249, 0x0264, 
124         4272, 0x0260, 4294, 0x025c, 4317, 0x0258, 4339, 0x0254, 4362, 0x0250, 
125         4384, 0x024c, 4407, 0x0248, 4430, 0x0244, 4453, 0x0240, 4475, 0x023c, 
126         4498, 0x0238, 4521, 0x0234, 4544, 0x0230, 4567, 0x022c, 4590, 0x0228, 
127         4613, 0x0224, 4636, 0x0220, 4659, 0x021c, 4682, 0x0218, 4705, 0x0214, 
128         4728, 0x0210, 4752, 0x020c, 4775, 0x0208, 4798, 0x0204, 4822, 0x0200, 
129         4845, 0x01fc, 4869, 0x01f8, 4892, 0x01f4, 4916, 0x01f0, 4939, 0x01ec, 
130         4963, 0x01e8, 4987, 0x01e4, 5010, 0x01e0, 5034, 0x01dc, 5058, 0x01d8, 
131         5082, 0x01d4, 5106, 0x01d0, 5130, 0x01cc, 5154, 0x01c8, 5178, 0x01c4, 
132         5202, 0x01c0, 5226, 0x01bc, 5250, 0x01b8, 5274, 0x01b4, 5299, 0x01b0, 
133         5323, 0x01ac, 5347, 0x01a8, 5372, 0x01a4, 5396, 0x01a0, 5420, 0x019c, 
134         5445, 0x0198, 5469, 0x0194, 5494, 0x0190, 5519, 0x018c, 5543, 0x0188, 
135         5568, 0x0184, 5593, 0x0180, 5618, 0x017c, 5643, 0x0178, 5668, 0x0174, 
136         5692, 0x0170, 5717, 0x016c, 5743, 0x0168, 5768, 0x0164, 5793, 0x0160, 
137         5818, 0x015c, 5843, 0x0158, 5868, 0x0154, 5894, 0x0150, 5919, 0x014c, 
138         5945, 0x0148, 5970, 0x0144, 5995, 0x0140, 6021, 0x013c, 6047, 0x0138, 
139         6072, 0x0134, 6098, 0x0130, 6124, 0x012c, 6149, 0x0128, 6175, 0x0124, 
140         6201, 0x0120, 6227, 0x011c, 6253, 0x0118, 6279, 0x0114, 6305, 0x0110, 
141         6331, 0x010c, 6357, 0x0108, 6384, 0x0104, 6410, 0x0100, 6436, 0x00fc, 
142         6462, 0x00f8, 6489, 0x00f4, 6515, 0x00f0, 6542, 0x00ec, 6568, 0x00e8, 
143         6595, 0x00e4, 6621, 0x00e0, 6648, 0x00dc, 6675, 0x00d8, 6702, 0x00d4, 
144         6728, 0x00d0, 6755, 0x00cc, 6782, 0x00c8, 6809, 0x00c4, 6836, 0x00c0, 
145         6863, 0x00bc, 6890, 0x00b8, 6917, 0x00b4, 6945, 0x00b0, 6972, 0x00ac, 
146         6999, 0x00a8, 7027, 0x00a4, 7054, 0x00a0, 7081, 0x009c, 7109, 0x0098, 
147         7136, 0x0094, 7164, 0x0090, 7192, 0x008c, 7219, 0x0088, 7247, 0x0084, 
148         7275, 0x0080, 7303, 0x007c, 7331, 0x0078, 7359, 0x0074, 7387, 0x0070, 
149         7415, 0x006c, 7443, 0x0068, 7471, 0x0064, 7499, 0x0060, 7527, 0x005c, 
150         7556, 0x0058, 7584, 0x0054, 7613, 0x0050, 7641, 0x004c, 7669, 0x0048, 
151         7698, 0x0044, 7727, 0x0040, 7755, 0x003c, 7784, 0x0038, 7813, 0x0034, 
152         7842, 0x0030, 7870, 0x002c, 7899, 0x0028, 7928, 0x0024, 7957, 0x0020, 
153         7986, 0x001c, 8016, 0x0018, 8045, 0x0014, 8074, 0x0010, 8103, 0x000c, 
154         8133, 0x0008, 8162, 0x0004, 8192, 0x0000
155 };
156
157 static unsigned short lookup_volume_table( unsigned short value )
158 {
159         /* This code is an optimised version of:
160          *   int i = 0;
161          *   while( volume_table[i*2] < value )
162          *       i++;
163          *   return volume_table[i*2+1];
164          */
165         unsigned short *ptr = log_table;
166         while( *ptr < value )
167                 ptr += 2;
168         return *(ptr+1);
169 }
170
171 /* this function calculates a 8.8 fixed point logarithmic attenuation
172  * value from a linear volume value in the range 0 to 16384 */
173 static unsigned short log_from_linear( unsigned short value )
174 {
175         if (value >= 16384)
176                 return 0x0000;
177         if (value) {
178                 unsigned short result = 0;
179                 int v, c;
180                 for( c = 0, v = 8192; c < 14; c++, v >>= 1 ) {
181                         if( value >= v ) {
182                                 result += lookup_volume_table( (value - v) << c );
183                                 return result;
184                         }
185                         result += 0x0605;       /* 6.0205 (result of -20*log10(0.5)) */
186                 }
187         }
188         return 0xffff;
189 }
190
191 /*
192  * Sample handling operations
193  */
194
195 static void sample_start(struct snd_trident * trident, struct snd_trident_voice * voice, snd_seq_position_t position);
196 static void sample_stop(struct snd_trident * trident, struct snd_trident_voice * voice, int mode);
197 static void sample_freq(struct snd_trident * trident, struct snd_trident_voice * voice, snd_seq_frequency_t freq);
198 static void sample_volume(struct snd_trident * trident, struct snd_trident_voice * voice, struct snd_seq_ev_volume * volume);
199 static void sample_loop(struct snd_trident * trident, struct snd_trident_voice * voice, struct snd_seq_ev_loop * loop);
200 static void sample_pos(struct snd_trident * trident, struct snd_trident_voice * voice, snd_seq_position_t position);
201 static void sample_private1(struct snd_trident * trident, struct snd_trident_voice * voice, unsigned char *data);
202
203 static struct snd_trident_sample_ops sample_ops =
204 {
205         sample_start,
206         sample_stop,
207         sample_freq,
208         sample_volume,
209         sample_loop,
210         sample_pos,
211         sample_private1
212 };
213
214 static void snd_trident_simple_init(struct snd_trident_voice * voice)
215 {
216         //voice->handler_wave = interrupt_wave;
217         //voice->handler_volume = interrupt_volume;
218         //voice->handler_effect = interrupt_effect;
219         //voice->volume_change = NULL;
220         voice->sample_ops = &sample_ops;
221 }
222
223 static void sample_start(struct snd_trident * trident, struct snd_trident_voice * voice, snd_seq_position_t position)
224 {
225         struct simple_instrument *simple;
226         struct snd_seq_kinstr *instr;
227         unsigned long flags;
228         unsigned int loop_start, loop_end, sample_start, sample_end, start_offset;
229         unsigned int value;
230         unsigned int shift = 0;
231
232         instr = snd_seq_instr_find(trident->synth.ilist, &voice->instr, 0, 1);
233         if (instr == NULL)
234                 return;
235         voice->instr = instr->instr;    /* copy ID to speedup aliases */
236         simple = KINSTR_DATA(instr);
237
238         spin_lock_irqsave(&trident->reg_lock, flags);
239
240         if (trident->device == TRIDENT_DEVICE_ID_SI7018)
241                 voice->GVSel = 1;       /* route to Wave volume */
242
243         voice->CTRL = 0;
244         voice->Alpha = 0;
245         voice->FMS = 0;
246
247         loop_start = simple->loop_start >> 4;
248         loop_end = simple->loop_end >> 4;
249         sample_start = (simple->start + position) >> 4;
250         if( sample_start >= simple->size )
251                 sample_start = simple->start >> 4;
252         sample_end = simple->size;
253         start_offset = position >> 4;
254
255         if (simple->format & SIMPLE_WAVE_16BIT) {
256                 voice->CTRL |= 8;
257                 shift++;
258         }
259         if (simple->format & SIMPLE_WAVE_STEREO) {
260                 voice->CTRL |= 4;
261                 shift++;
262         }
263         if (!(simple->format & SIMPLE_WAVE_UNSIGNED))
264                 voice->CTRL |= 2;
265
266         voice->LBA = simple->address.memory;
267
268         if (simple->format & SIMPLE_WAVE_LOOP) {
269                 voice->CTRL |= 1;
270                 voice->LBA += loop_start << shift;
271                 if( start_offset >= loop_start ) {
272                         voice->CSO = start_offset - loop_start;
273                         voice->negCSO = 0;
274                 } else {
275                         voice->CSO = loop_start - start_offset;
276                         voice->negCSO = 1;
277                 }
278                 voice->ESO = loop_end - loop_start - 1;
279         } else {
280                 voice->LBA += start_offset << shift;
281                 voice->CSO = sample_start;
282                 voice->ESO = sample_end - 1;
283                 voice->negCSO = 0;
284         }
285
286         if (voice->flags & SNDRV_TRIDENT_VFLG_RUNNING) {
287                 snd_trident_stop_voice(trident, voice->number);
288                 voice->flags &= ~SNDRV_TRIDENT_VFLG_RUNNING;
289         }
290
291         /* set CSO sign */
292         value = inl(TRID_REG(trident, T4D_SIGN_CSO_A));
293         if( voice->negCSO ) {
294                 value |= 1 << (voice->number&31);
295         } else {
296                 value &= ~(1 << (voice->number&31));
297         }
298         outl(value,TRID_REG(trident, T4D_SIGN_CSO_A));
299
300         voice->Attribute = 0;   
301         snd_trident_write_voice_regs(trident, voice);
302         snd_trident_start_voice(trident, voice->number);
303         voice->flags |= SNDRV_TRIDENT_VFLG_RUNNING;
304         spin_unlock_irqrestore(&trident->reg_lock, flags);
305         snd_seq_instr_free_use(trident->synth.ilist, instr);
306 }
307
308 static void sample_stop(struct snd_trident * trident, struct snd_trident_voice * voice, int mode)
309 {
310         unsigned long flags;
311
312         if (!(voice->flags & SNDRV_TRIDENT_VFLG_RUNNING))
313                 return;
314
315         switch (mode) {
316         default:
317                 spin_lock_irqsave(&trident->reg_lock, flags);
318                 snd_trident_stop_voice(trident, voice->number);
319                 voice->flags &= ~SNDRV_TRIDENT_VFLG_RUNNING;
320                 spin_unlock_irqrestore(&trident->reg_lock, flags);
321                 break;
322         case SAMPLE_STOP_LOOP:  /* disable loop only */
323                 voice->CTRL &= ~1;
324                 spin_lock_irqsave(&trident->reg_lock, flags);
325                 outb((unsigned char) voice->number, TRID_REG(trident, T4D_LFO_GC_CIR));
326                 outw((((voice->CTRL << 12) | (voice->EC & 0x0fff)) & 0xffff), CH_GVSEL_PAN_VOL_CTRL_EC);
327                 spin_unlock_irqrestore(&trident->reg_lock, flags);
328                 break;
329         }
330 }
331
332 static void sample_freq(struct snd_trident * trident, struct snd_trident_voice * voice, snd_seq_frequency_t freq)
333 {
334         unsigned long flags;
335         freq >>= 4;
336
337         spin_lock_irqsave(&trident->reg_lock, flags);
338         if (freq == 44100)
339                 voice->Delta = 0xeb3;
340         else if (freq == 8000)
341                 voice->Delta = 0x2ab;
342         else if (freq == 48000)
343                 voice->Delta = 0x1000;
344         else
345                 voice->Delta = (((freq << 12) + freq) / 48000) & 0x0000ffff;
346
347         outb((unsigned char) voice->number, TRID_REG(trident, T4D_LFO_GC_CIR));
348         if (trident->device == TRIDENT_DEVICE_ID_NX) {
349                 outb((unsigned char) voice->Delta, TRID_REG(trident, CH_NX_DELTA_CSO + 3));
350                 outb((unsigned char) (voice->Delta >> 8), TRID_REG(trident, CH_NX_DELTA_ESO + 3));
351         } else {
352                 outw((unsigned short) voice->Delta, TRID_REG(trident, CH_DX_ESO_DELTA));
353         }
354
355         spin_unlock_irqrestore(&trident->reg_lock, flags);
356 }
357
358 static void sample_volume(struct snd_trident * trident, struct snd_trident_voice * voice, struct snd_seq_ev_volume * volume)
359 {
360         unsigned long flags;
361         unsigned short value;
362
363         spin_lock_irqsave(&trident->reg_lock, flags);
364         voice->GVSel = 0;       /* use global music volume */
365         voice->FMC = 0x03;      /* fixme: can we do something useful with FMC? */
366         if (volume->volume >= 0) {
367                 volume->volume &= 0x3fff;
368                 /* linear volume -> logarithmic attenuation conversion
369                  * uses EC register for greater resolution (6.6 bits) than Vol register (5.3 bits)
370                  * Vol register used when additional attenuation is required */
371                 voice->RVol = 0;
372                 voice->CVol = 0;
373                 value = log_from_linear( volume->volume );
374                 voice->Vol = 0;
375                 voice->EC = (value & 0x3fff) >> 2;
376                 if (value > 0x3fff) {
377                         voice->EC |= 0xfc0;
378                         if (value < 0x5f00 )
379                                 voice->Vol = ((value >> 8) - 0x3f) << 5;
380                         else {
381                                 voice->Vol = 0x3ff;
382                                 voice->EC = 0xfff;
383                         }
384                 }
385         }
386         if (volume->lr >= 0) {
387                 volume->lr &= 0x3fff;
388                 /* approximate linear pan by attenuating channels */
389                 if (volume->lr >= 0x2000) {     /* attenuate left (pan right) */
390                         value = 0x3fff - volume->lr;
391                         for (voice->Pan = 0; voice->Pan < 63; voice->Pan++ ) 
392                                 if (value >= pan_table[voice->Pan] )
393                                         break;
394                 } else {                        /* attenuate right (pan left) */
395                         for (voice->Pan = 0; voice->Pan < 63; voice->Pan++ ) 
396                                 if ((unsigned int)volume->lr >= pan_table[voice->Pan] )
397                                         break;
398                         voice->Pan |= 0x40;
399                 }
400         }
401         outb((unsigned char) voice->number, TRID_REG(trident, T4D_LFO_GC_CIR));
402         outl((voice->GVSel << 31) | ((voice->Pan & 0x0000007f) << 24) |
403                  ((voice->Vol & 0x000000ff) << 16) | ((voice->CTRL & 0x0000000f) << 12) |
404                  (voice->EC & 0x00000fff), TRID_REG(trident, CH_GVSEL_PAN_VOL_CTRL_EC));
405         value = ((voice->FMC & 0x03) << 14) | ((voice->RVol & 0x7f) << 7) | (voice->CVol & 0x7f);
406         outw(value, TRID_REG(trident, CH_DX_FMC_RVOL_CVOL));
407         spin_unlock_irqrestore(&trident->reg_lock, flags);
408 }
409
410 static void sample_loop(struct snd_trident * trident, struct snd_trident_voice * voice, struct snd_seq_ev_loop * loop)
411 {
412         unsigned long flags;
413         struct simple_instrument *simple;
414         struct snd_seq_kinstr *instr;
415         unsigned int loop_start, loop_end;
416
417         instr = snd_seq_instr_find(trident->synth.ilist, &voice->instr, 0, 1);
418         if (instr == NULL)
419                 return;
420         voice->instr = instr->instr;    /* copy ID to speedup aliases */
421         simple = KINSTR_DATA(instr);
422
423         loop_start = loop->start >> 4;
424         loop_end = loop->end >> 4;
425
426         spin_lock_irqsave(&trident->reg_lock, flags);
427
428         voice->LBA = simple->address.memory + loop_start;
429         voice->CSO = 0;
430         voice->ESO = loop_end - loop_start - 1;
431
432         outb((unsigned char) voice->number, TRID_REG(trident, T4D_LFO_GC_CIR));
433         outb((voice->LBA >> 16), TRID_REG(trident, CH_LBA + 2));
434         outw((voice->LBA & 0xffff), TRID_REG(trident, CH_LBA));
435         if (trident->device == TRIDENT_DEVICE_ID_NX) {
436                 outb((voice->ESO >> 16), TRID_REG(trident, CH_NX_DELTA_ESO + 2));
437                 outw((voice->ESO & 0xffff), TRID_REG(trident, CH_NX_DELTA_ESO));
438                 outb((voice->CSO >> 16), TRID_REG(trident, CH_NX_DELTA_CSO + 2));
439                 outw((voice->CSO & 0xffff), TRID_REG(trident, CH_NX_DELTA_CSO));
440         } else {
441                 outw((voice->ESO & 0xffff), TRID_REG(trident, CH_DX_ESO_DELTA + 2));
442                 outw((voice->CSO & 0xffff), TRID_REG(trident, CH_DX_CSO_ALPHA_FMS + 2));
443         }
444
445         spin_unlock_irqrestore(&trident->reg_lock, flags);
446         snd_seq_instr_free_use(trident->synth.ilist, instr);
447 }
448
449 static void sample_pos(struct snd_trident * trident, struct snd_trident_voice * voice, snd_seq_position_t position)
450 {
451         unsigned long flags;
452         struct simple_instrument *simple;
453         struct snd_seq_kinstr *instr;
454         unsigned int value;
455
456         instr = snd_seq_instr_find(trident->synth.ilist, &voice->instr, 0, 1);
457         if (instr == NULL)
458                 return;
459         voice->instr = instr->instr;    /* copy ID to speedup aliases */
460         simple = KINSTR_DATA(instr);
461
462         spin_lock_irqsave(&trident->reg_lock, flags);
463
464         if (simple->format & SIMPLE_WAVE_LOOP) {
465                 if( position >= simple->loop_start ) {
466                         voice->CSO = (position - simple->loop_start) >> 4;
467                         voice->negCSO = 0;
468                 } else {
469                         voice->CSO = (simple->loop_start - position) >> 4;
470                         voice->negCSO = 1;
471                 }
472         } else {
473                 voice->CSO = position >> 4;
474                 voice->negCSO = 0;
475         }
476
477         /* set CSO sign */
478         value = inl(TRID_REG(trident, T4D_SIGN_CSO_A));
479         if( voice->negCSO ) {
480                 value |= 1 << (voice->number&31);
481         } else {
482                 value &= ~(1 << (voice->number&31));
483         }
484         outl(value,TRID_REG(trident, T4D_SIGN_CSO_A));
485         
486
487         outb((unsigned char) voice->number, TRID_REG(trident, T4D_LFO_GC_CIR));
488         if (trident->device == TRIDENT_DEVICE_ID_NX) {
489                 outw((voice->CSO & 0xffff), TRID_REG(trident, CH_NX_DELTA_CSO));
490                 outb((voice->CSO >> 16), TRID_REG(trident, CH_NX_DELTA_CSO + 2));
491         } else {
492                 outw((voice->CSO & 0xffff), TRID_REG(trident, CH_DX_CSO_ALPHA_FMS) + 2);
493         }
494
495         spin_unlock_irqrestore(&trident->reg_lock, flags);
496         snd_seq_instr_free_use(trident->synth.ilist, instr);
497 }
498
499 static void sample_private1(struct snd_trident * trident, struct snd_trident_voice * voice, unsigned char *data)
500 {
501 }
502
503 /*
504  * Memory management / sample loading
505  */
506
507 static int snd_trident_simple_put_sample(void *private_data,
508                                          struct simple_instrument * instr,
509                                          char __user *data, long len, int atomic)
510 {
511         struct snd_trident *trident = private_data;
512         int size = instr->size;
513         int shift = 0;
514
515         if (instr->format & SIMPLE_WAVE_BACKWARD ||
516             instr->format & SIMPLE_WAVE_BIDIR ||
517             instr->format & SIMPLE_WAVE_ULAW) 
518                 return -EINVAL; /* not supported */
519
520         if (instr->format & SIMPLE_WAVE_16BIT)
521                 shift++;
522         if (instr->format & SIMPLE_WAVE_STEREO)
523                 shift++;
524         size <<= shift;
525
526         if (trident->synth.current_size + size > trident->synth.max_size)
527                 return -ENOMEM;
528
529         if (!access_ok(VERIFY_READ, data, size))
530                 return -EFAULT;
531
532         if (trident->tlb.entries) {
533                 struct snd_util_memblk *memblk;
534                 memblk = snd_trident_synth_alloc(trident, size); 
535                 if (memblk == NULL)
536                         return -ENOMEM;
537                 if (snd_trident_synth_copy_from_user(trident, memblk, 0, data, size) ) {
538                         snd_trident_synth_free(trident, memblk);
539                         return -EFAULT;
540                 }
541                 instr->address.ptr = (unsigned char*)memblk;
542                 instr->address.memory = memblk->offset;
543         } else {
544                 struct snd_dma_buffer dmab;
545                 if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(trident->pci),
546                                         size, &dmab) < 0)
547                         return -ENOMEM;
548
549                 if (copy_from_user(dmab.area, data, size)) {
550                         snd_dma_free_pages(&dmab);
551                         return -EFAULT;
552                 }
553                 instr->address.ptr = dmab.area;
554                 instr->address.memory = dmab.addr;
555         }
556
557         trident->synth.current_size += size;
558         return 0;
559 }
560
561 static int snd_trident_simple_get_sample(void *private_data,
562                                          struct simple_instrument * instr,
563                                          char __user *data, long len, int atomic)
564 {
565         //struct snd_trident *trident = private_data;
566         int size = instr->size;
567         int shift = 0;
568
569         if (instr->format & SIMPLE_WAVE_16BIT)
570                 shift++;
571         if (instr->format & SIMPLE_WAVE_STEREO)
572                 shift++;
573         size <<= shift;
574
575         if (!access_ok(VERIFY_WRITE, data, size))
576                 return -EFAULT;
577
578         /* FIXME: not implemented yet */
579
580         return -EBUSY;
581 }
582
583 static int snd_trident_simple_remove_sample(void *private_data,
584                                             struct simple_instrument * instr,
585                                             int atomic)
586 {
587         struct snd_trident *trident = private_data;
588         int size = instr->size;
589
590         if (instr->format & SIMPLE_WAVE_16BIT)
591                 size <<= 1;
592         if (instr->format & SIMPLE_WAVE_STEREO)
593                 size <<= 1;
594
595         if (trident->tlb.entries) {
596                 struct snd_util_memblk *memblk = (struct snd_util_memblk *)instr->address.ptr;
597                 if (memblk)
598                         snd_trident_synth_free(trident, memblk);
599                 else
600                         return -EFAULT;
601         } else {
602                 struct snd_dma_buffer dmab;
603                 dmab.dev.type = SNDRV_DMA_TYPE_DEV;
604                 dmab.dev.dev = snd_dma_pci_data(trident->pci);
605                 dmab.area = instr->address.ptr;
606                 dmab.addr = instr->address.memory;
607                 dmab.bytes = size;
608                 snd_dma_free_pages(&dmab);
609         }
610
611         trident->synth.current_size -= size;
612         if (trident->synth.current_size < 0)    /* shouldn't need this check... */
613                 trident->synth.current_size = 0;
614
615         return 0;
616 }
617
618 static void select_instrument(struct snd_trident * trident, struct snd_trident_voice * v)
619 {
620         struct snd_seq_kinstr *instr;
621         instr = snd_seq_instr_find(trident->synth.ilist, &v->instr, 0, 1);
622         if (instr != NULL) {
623                 if (instr->ops) {
624                         if (!strcmp(instr->ops->instr_type, SNDRV_SEQ_INSTR_ID_SIMPLE))
625                                 snd_trident_simple_init(v);
626                 }
627                 snd_seq_instr_free_use(trident->synth.ilist, instr);
628         }
629 }
630
631 /*
632
633  */
634
635 static void event_sample(struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v)
636 {
637         if (v->sample_ops && v->sample_ops->sample_stop)
638                 v->sample_ops->sample_stop(p->trident, v, SAMPLE_STOP_IMMEDIATELY);
639         v->instr.std = ev->data.sample.param.sample.std;
640         if (v->instr.std & 0xff000000) {        /* private instrument */
641                 v->instr.std &= 0x00ffffff;
642                 v->instr.std |= (unsigned int)ev->source.client << 24;
643         }
644         v->instr.bank = ev->data.sample.param.sample.bank;
645         v->instr.prg = ev->data.sample.param.sample.prg;
646         select_instrument(p->trident, v);
647 }
648
649 static void event_cluster(struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v)
650 {
651         if (v->sample_ops && v->sample_ops->sample_stop)
652                 v->sample_ops->sample_stop(p->trident, v, SAMPLE_STOP_IMMEDIATELY);
653         v->instr.cluster = ev->data.sample.param.cluster.cluster;
654         select_instrument(p->trident, v);
655 }
656
657 static void event_start(struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v)
658 {
659         if (v->sample_ops && v->sample_ops->sample_start)
660                 v->sample_ops->sample_start(p->trident, v, ev->data.sample.param.position);
661 }
662
663 static void event_stop(struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v)
664 {
665         if (v->sample_ops && v->sample_ops->sample_stop)
666                 v->sample_ops->sample_stop(p->trident, v, ev->data.sample.param.stop_mode);
667 }
668
669 static void event_freq(struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v)
670 {
671         if (v->sample_ops && v->sample_ops->sample_freq)
672                 v->sample_ops->sample_freq(p->trident, v, ev->data.sample.param.frequency);
673 }
674
675 static void event_volume(struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v)
676 {
677         if (v->sample_ops && v->sample_ops->sample_volume)
678                 v->sample_ops->sample_volume(p->trident, v, &ev->data.sample.param.volume);
679 }
680
681 static void event_loop(struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v)
682 {
683         if (v->sample_ops && v->sample_ops->sample_loop)
684                 v->sample_ops->sample_loop(p->trident, v, &ev->data.sample.param.loop);
685 }
686
687 static void event_position(struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v)
688 {
689         if (v->sample_ops && v->sample_ops->sample_pos)
690                 v->sample_ops->sample_pos(p->trident, v, ev->data.sample.param.position);
691 }
692
693 static void event_private1(struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v)
694 {
695         if (v->sample_ops && v->sample_ops->sample_private1)
696                 v->sample_ops->sample_private1(p->trident, v, (unsigned char *) &ev->data.sample.param.raw8);
697 }
698
699 typedef void (trident_sample_event_handler_t) (struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v);
700
701 static trident_sample_event_handler_t *trident_sample_event_handlers[9] =
702 {
703         event_sample,
704         event_cluster,
705         event_start,
706         event_stop,
707         event_freq,
708         event_volume,
709         event_loop,
710         event_position,
711         event_private1
712 };
713
714 static void snd_trident_sample_event(struct snd_seq_event * ev, struct snd_trident_port * p)
715 {
716         int idx, voice;
717         struct snd_trident *trident = p->trident;
718         struct snd_trident_voice *v;
719         unsigned long flags;
720
721         idx = ev->type - SNDRV_SEQ_EVENT_SAMPLE;
722         if (idx < 0 || idx > 8)
723                 return;
724         for (voice = 0; voice < 64; voice++) {
725                 v = &trident->synth.voices[voice];
726                 if (v->use && v->client == ev->source.client &&
727                     v->port == ev->source.port &&
728                     v->index == ev->data.sample.channel) {
729                         spin_lock_irqsave(&trident->event_lock, flags);
730                         trident_sample_event_handlers[idx] (ev, p, v);
731                         spin_unlock_irqrestore(&trident->event_lock, flags);
732                         return;
733                 }
734         }
735 }
736
737 /*
738
739  */
740
741 static void snd_trident_synth_free_voices(struct snd_trident * trident, int client, int port)
742 {
743         int idx;
744         struct snd_trident_voice *voice;
745
746         for (idx = 0; idx < 32; idx++) {
747                 voice = &trident->synth.voices[idx];
748                 if (voice->use && voice->client == client && voice->port == port)
749                         snd_trident_free_voice(trident, voice);
750         }
751 }
752
753 static int snd_trident_synth_use(void *private_data, struct snd_seq_port_subscribe * info)
754 {
755         struct snd_trident_port *port = private_data;
756         struct snd_trident *trident = port->trident;
757         struct snd_trident_voice *voice;
758         unsigned int idx;
759         unsigned long flags;
760
761         if (info->voices > 32)
762                 return -EINVAL;
763         spin_lock_irqsave(&trident->reg_lock, flags);
764         for (idx = 0; idx < info->voices; idx++) {
765                 voice = snd_trident_alloc_voice(trident, SNDRV_TRIDENT_VOICE_TYPE_SYNTH, info->sender.client, info->sender.port);
766                 if (voice == NULL) {
767                         snd_trident_synth_free_voices(trident, info->sender.client, info->sender.port);
768                         spin_unlock_irqrestore(&trident->reg_lock, flags);
769                         return -EBUSY;
770                 }
771                 voice->index = idx;
772                 voice->Vol = 0x3ff;
773                 voice->EC = 0x0fff;
774         }
775 #if 0
776         for (idx = 0; idx < info->midi_voices; idx++) {
777                 port->midi_has_voices = 1;
778                 voice = snd_trident_alloc_voice(trident, SNDRV_TRIDENT_VOICE_TYPE_MIDI, info->sender.client, info->sender.port);
779                 if (voice == NULL) {
780                         snd_trident_synth_free_voices(trident, info->sender.client, info->sender.port);
781                         spin_unlock_irqrestore(&trident->reg_lock, flags);
782                         return -EBUSY;
783                 }
784                 voice->Vol = 0x3ff;
785                 voice->EC = 0x0fff;
786         }
787 #endif
788         spin_unlock_irqrestore(&trident->reg_lock, flags);
789         return 0;
790 }
791
792 static int snd_trident_synth_unuse(void *private_data, struct snd_seq_port_subscribe * info)
793 {
794         struct snd_trident_port *port = private_data;
795         struct snd_trident *trident = port->trident;
796         unsigned long flags;
797
798         spin_lock_irqsave(&trident->reg_lock, flags);
799         snd_trident_synth_free_voices(trident, info->sender.client, info->sender.port);
800         spin_unlock_irqrestore(&trident->reg_lock, flags);
801         return 0;
802 }
803
804 /*
805
806  */
807
808 static void snd_trident_synth_free_private_instruments(struct snd_trident_port * p, int client)
809 {
810         struct snd_seq_instr_header ifree;
811
812         memset(&ifree, 0, sizeof(ifree));
813         ifree.cmd = SNDRV_SEQ_INSTR_FREE_CMD_PRIVATE;
814         snd_seq_instr_list_free_cond(p->trident->synth.ilist, &ifree, client, 0);
815 }
816
817 static int snd_trident_synth_event_input(struct snd_seq_event * ev, int direct, void *private_data, int atomic, int hop)
818 {
819         struct snd_trident_port *p = (struct snd_trident_port *) private_data;
820
821         if (p == NULL)
822                 return -EINVAL;
823         if (ev->type >= SNDRV_SEQ_EVENT_SAMPLE &&
824             ev->type <= SNDRV_SEQ_EVENT_SAMPLE_PRIVATE1) {
825                 snd_trident_sample_event(ev, p);
826                 return 0;
827         }
828         if (ev->source.client == SNDRV_SEQ_CLIENT_SYSTEM &&
829             ev->source.port == SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE) {
830                 if (ev->type == SNDRV_SEQ_EVENT_CLIENT_EXIT) {
831                         snd_trident_synth_free_private_instruments(p, ev->data.addr.client);
832                         return 0;
833                 }
834         }
835         if (direct) {
836                 if (ev->type >= SNDRV_SEQ_EVENT_INSTR_BEGIN) {
837                         snd_seq_instr_event(&p->trident->synth.simple_ops.kops,
838                                             p->trident->synth.ilist, ev,
839                                             p->trident->synth.seq_client, atomic, hop);
840                         return 0;
841                 }
842         }
843         return 0;
844 }
845
846 static void snd_trident_synth_instr_notify(void *private_data,
847                                            struct snd_seq_kinstr * instr,
848                                            int what)
849 {
850         int idx;
851         struct snd_trident *trident = private_data;
852         struct snd_trident_voice *pvoice;
853         unsigned long flags;
854
855         spin_lock_irqsave(&trident->event_lock, flags);
856         for (idx = 0; idx < 64; idx++) {
857                 pvoice = &trident->synth.voices[idx];
858                 if (pvoice->use && !memcmp(&pvoice->instr, &instr->instr, sizeof(pvoice->instr))) {
859                         if (pvoice->sample_ops && pvoice->sample_ops->sample_stop) {
860                                 pvoice->sample_ops->sample_stop(trident, pvoice, SAMPLE_STOP_IMMEDIATELY);
861                         } else {
862                                 snd_trident_stop_voice(trident, pvoice->number);
863                                 pvoice->flags &= ~SNDRV_TRIDENT_VFLG_RUNNING;
864                         }
865                 }
866         }
867         spin_unlock_irqrestore(&trident->event_lock, flags);
868 }
869
870 /*
871
872  */
873
874 static void snd_trident_synth_free_port(void *private_data)
875 {
876         struct snd_trident_port *p = (struct snd_trident_port *) private_data;
877
878         if (p)
879                 snd_midi_channel_free_set(p->chset);
880 }
881
882 static int snd_trident_synth_create_port(struct snd_trident * trident, int idx)
883 {
884         struct snd_trident_port *p;
885         struct snd_seq_port_callback callbacks;
886         char name[32];
887         char *str;
888         int result;
889
890         p = &trident->synth.seq_ports[idx];
891         p->chset = snd_midi_channel_alloc_set(16);
892         if (p->chset == NULL)
893                 return -ENOMEM;
894         p->chset->private_data = p;
895         p->trident = trident;
896         p->client = trident->synth.seq_client;
897
898         memset(&callbacks, 0, sizeof(callbacks));
899         callbacks.owner = THIS_MODULE;
900         callbacks.use = snd_trident_synth_use;
901         callbacks.unuse = snd_trident_synth_unuse;
902         callbacks.event_input = snd_trident_synth_event_input;
903         callbacks.private_free = snd_trident_synth_free_port;
904         callbacks.private_data = p;
905
906         str = "???";
907         switch (trident->device) {
908         case TRIDENT_DEVICE_ID_DX:      str = "Trident 4DWave-DX"; break;
909         case TRIDENT_DEVICE_ID_NX:      str = "Trident 4DWave-NX"; break;
910         case TRIDENT_DEVICE_ID_SI7018:  str = "SiS 7018"; break;
911         }
912         sprintf(name, "%s port %i", str, idx);
913         p->chset->port = snd_seq_event_port_attach(trident->synth.seq_client,
914                                                    &callbacks,
915                                                    SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE,
916                                                    SNDRV_SEQ_PORT_TYPE_DIRECT_SAMPLE |
917                                                    SNDRV_SEQ_PORT_TYPE_SYNTH |
918                                                    SNDRV_SEQ_PORT_TYPE_HARDWARE |
919                                                    SNDRV_SEQ_PORT_TYPE_SYNTHESIZER,
920                                                    16, 0,
921                                                    name);
922         if (p->chset->port < 0) {
923                 result = p->chset->port;
924                 snd_trident_synth_free_port(p);
925                 return result;
926         }
927         p->port = p->chset->port;
928         return 0;
929 }
930
931 /*
932
933  */
934
935 static int snd_trident_synth_new_device(struct snd_seq_device *dev)
936 {
937         struct snd_trident *trident;
938         int client, i;
939         struct snd_seq_port_subscribe sub;
940         struct snd_simple_ops *simpleops;
941         char *str;
942
943         trident = *(struct snd_trident **)SNDRV_SEQ_DEVICE_ARGPTR(dev);
944         if (trident == NULL)
945                 return -EINVAL;
946
947         trident->synth.seq_client = -1;
948
949         /* allocate new client */
950         str = "???";
951         switch (trident->device) {
952         case TRIDENT_DEVICE_ID_DX:      str = "Trident 4DWave-DX"; break;
953         case TRIDENT_DEVICE_ID_NX:      str = "Trident 4DWave-NX"; break;
954         case TRIDENT_DEVICE_ID_SI7018:  str = "SiS 7018"; break;
955         }
956         client = trident->synth.seq_client =
957                 snd_seq_create_kernel_client(trident->card, 1, str);
958         if (client < 0)
959                 return client;
960
961         for (i = 0; i < 4; i++)
962                 snd_trident_synth_create_port(trident, i);
963
964         trident->synth.ilist = snd_seq_instr_list_new();
965         if (trident->synth.ilist == NULL) {
966                 snd_seq_delete_kernel_client(client);
967                 trident->synth.seq_client = -1;
968                 return -ENOMEM;
969         }
970         trident->synth.ilist->flags = SNDRV_SEQ_INSTR_FLG_DIRECT;
971
972         simpleops = &trident->synth.simple_ops;
973         snd_seq_simple_init(simpleops, trident, NULL);
974         simpleops->put_sample = snd_trident_simple_put_sample;
975         simpleops->get_sample = snd_trident_simple_get_sample;
976         simpleops->remove_sample = snd_trident_simple_remove_sample;
977         simpleops->notify = snd_trident_synth_instr_notify;
978
979         memset(&sub, 0, sizeof(sub));
980         sub.sender.client = SNDRV_SEQ_CLIENT_SYSTEM;
981         sub.sender.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE;
982         sub.dest.client = client;
983         sub.dest.port = 0;
984         snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &sub);
985
986         return 0;
987 }
988
989 static int snd_trident_synth_delete_device(struct snd_seq_device *dev)
990 {
991         struct snd_trident *trident;
992
993         trident = *(struct snd_trident **)SNDRV_SEQ_DEVICE_ARGPTR(dev);
994         if (trident == NULL)
995                 return -EINVAL;
996
997         if (trident->synth.seq_client >= 0) {
998                 snd_seq_delete_kernel_client(trident->synth.seq_client);
999                 trident->synth.seq_client = -1;
1000         }
1001         if (trident->synth.ilist)
1002                 snd_seq_instr_list_free(&trident->synth.ilist);
1003         return 0;
1004 }
1005
1006 static int __init alsa_trident_synth_init(void)
1007 {
1008         static struct snd_seq_dev_ops ops =
1009         {
1010                 snd_trident_synth_new_device,
1011                 snd_trident_synth_delete_device
1012         };
1013
1014         return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_TRIDENT, &ops,
1015                                               sizeof(struct snd_trident *));
1016 }
1017
1018 static void __exit alsa_trident_synth_exit(void)
1019 {
1020         snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_TRIDENT);
1021 }
1022
1023 module_init(alsa_trident_synth_init)
1024 module_exit(alsa_trident_synth_exit)