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