Linux-2.6.12-rc2
[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 <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(trident_t * trident, snd_trident_voice_t * voice, snd_seq_position_t position);
196 static void sample_stop(trident_t * trident, snd_trident_voice_t * voice, snd_seq_stop_mode_t mode);
197 static void sample_freq(trident_t * trident, snd_trident_voice_t * voice, snd_seq_frequency_t freq);
198 static void sample_volume(trident_t * trident, snd_trident_voice_t * voice, snd_seq_ev_volume_t * volume);
199 static void sample_loop(trident_t * trident, snd_trident_voice_t * voice, snd_seq_ev_loop_t * loop);
200 static void sample_pos(trident_t * trident, snd_trident_voice_t * voice, snd_seq_position_t position);
201 static void sample_private1(trident_t * trident, snd_trident_voice_t * voice, unsigned char *data);
202
203 static snd_trident_sample_ops_t 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(snd_trident_voice_t * 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(trident_t * trident, snd_trident_voice_t * voice, snd_seq_position_t position)
224 {
225         simple_instrument_t *simple;
226         snd_seq_kinstr_t *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(trident_t * trident, snd_trident_voice_t * voice, snd_seq_stop_mode_t 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(trident_t * trident, snd_trident_voice_t * 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(trident_t * trident, snd_trident_voice_t * voice, snd_seq_ev_volume_t * 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(trident_t * trident, snd_trident_voice_t * voice, snd_seq_ev_loop_t * loop)
411 {
412         unsigned long flags;
413         simple_instrument_t *simple;
414         snd_seq_kinstr_t *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(trident_t * trident, snd_trident_voice_t * voice, snd_seq_position_t position)
450 {
451         unsigned long flags;
452         simple_instrument_t *simple;
453         snd_seq_kinstr_t *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(trident_t * trident, snd_trident_voice_t * 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, simple_instrument_t * instr,
508                                          char __user *data, long len, int atomic)
509 {
510         trident_t *trident = private_data;
511         int size = instr->size;
512         int shift = 0;
513
514         if (instr->format & SIMPLE_WAVE_BACKWARD ||
515             instr->format & SIMPLE_WAVE_BIDIR ||
516             instr->format & SIMPLE_WAVE_ULAW) 
517                 return -EINVAL; /* not supported */
518
519         if (instr->format & SIMPLE_WAVE_16BIT)
520                 shift++;
521         if (instr->format & SIMPLE_WAVE_STEREO)
522                 shift++;
523         size <<= shift;
524
525         if (trident->synth.current_size + size > trident->synth.max_size)
526                 return -ENOMEM;
527
528         if (!access_ok(VERIFY_READ, data, size))
529                 return -EFAULT;
530
531         if (trident->tlb.entries) {
532                 snd_util_memblk_t *memblk;
533                 memblk = snd_trident_synth_alloc(trident, size); 
534                 if (memblk == NULL)
535                         return -ENOMEM;
536                 if (snd_trident_synth_copy_from_user(trident, memblk, 0, data, size) ) {
537                         snd_trident_synth_free(trident, memblk);
538                         return -EFAULT;
539                 }
540                 instr->address.ptr = (unsigned char*)memblk;
541                 instr->address.memory = memblk->offset;
542         } else {
543                 struct snd_dma_buffer dmab;
544                 if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(trident->pci),
545                                         size, &dmab) < 0)
546                         return -ENOMEM;
547
548                 if (copy_from_user(dmab.area, data, size)) {
549                         snd_dma_free_pages(&dmab);
550                         return -EFAULT;
551                 }
552                 instr->address.ptr = dmab.area;
553                 instr->address.memory = dmab.addr;
554         }
555
556         trident->synth.current_size += size;
557         return 0;
558 }
559
560 static int snd_trident_simple_get_sample(void *private_data, simple_instrument_t * instr,
561                                          char __user *data, long len, int atomic)
562 {
563         //trident_t *trident = private_data;
564         int size = instr->size;
565         int shift = 0;
566
567         if (instr->format & SIMPLE_WAVE_16BIT)
568                 shift++;
569         if (instr->format & SIMPLE_WAVE_STEREO)
570                 shift++;
571         size <<= shift;
572
573         if (!access_ok(VERIFY_WRITE, data, size))
574                 return -EFAULT;
575
576         /* FIXME: not implemented yet */
577
578         return -EBUSY;
579 }
580
581 static int snd_trident_simple_remove_sample(void *private_data, simple_instrument_t * instr,
582                                             int atomic)
583 {
584         trident_t *trident = private_data;
585         int size = instr->size;
586
587         if (instr->format & SIMPLE_WAVE_16BIT)
588                 size <<= 1;
589         if (instr->format & SIMPLE_WAVE_STEREO)
590                 size <<= 1;
591
592         if (trident->tlb.entries) {
593                 snd_util_memblk_t *memblk = (snd_util_memblk_t*)instr->address.ptr;
594                 if (memblk)
595                         snd_trident_synth_free(trident, memblk);
596                 else
597                         return -EFAULT;
598         } else {
599                 struct snd_dma_buffer dmab;
600                 dmab.dev.type = SNDRV_DMA_TYPE_DEV;
601                 dmab.dev.dev = snd_dma_pci_data(trident->pci);
602                 dmab.area = instr->address.ptr;
603                 dmab.addr = instr->address.memory;
604                 dmab.bytes = size;
605                 snd_dma_free_pages(&dmab);
606         }
607
608         trident->synth.current_size -= size;
609         if (trident->synth.current_size < 0)    /* shouldn't need this check... */
610                 trident->synth.current_size = 0;
611
612         return 0;
613 }
614
615 static void select_instrument(trident_t * trident, snd_trident_voice_t * v)
616 {
617         snd_seq_kinstr_t *instr;
618         instr = snd_seq_instr_find(trident->synth.ilist, &v->instr, 0, 1);
619         if (instr != NULL) {
620                 if (instr->ops) {
621                         if (!strcmp(instr->ops->instr_type, SNDRV_SEQ_INSTR_ID_SIMPLE))
622                                 snd_trident_simple_init(v);
623                 }
624                 snd_seq_instr_free_use(trident->synth.ilist, instr);
625         }
626 }
627
628 /*
629
630  */
631
632 static void event_sample(snd_seq_event_t * ev, snd_trident_port_t * p, snd_trident_voice_t * v)
633 {
634         if (v->sample_ops && v->sample_ops->sample_stop)
635                 v->sample_ops->sample_stop(p->trident, v, SAMPLE_STOP_IMMEDIATELY);
636         v->instr.std = ev->data.sample.param.sample.std;
637         if (v->instr.std & 0xff000000) {        /* private instrument */
638                 v->instr.std &= 0x00ffffff;
639                 v->instr.std |= (unsigned int)ev->source.client << 24;
640         }
641         v->instr.bank = ev->data.sample.param.sample.bank;
642         v->instr.prg = ev->data.sample.param.sample.prg;
643         select_instrument(p->trident, v);
644 }
645
646 static void event_cluster(snd_seq_event_t * ev, snd_trident_port_t * p, snd_trident_voice_t * v)
647 {
648         if (v->sample_ops && v->sample_ops->sample_stop)
649                 v->sample_ops->sample_stop(p->trident, v, SAMPLE_STOP_IMMEDIATELY);
650         v->instr.cluster = ev->data.sample.param.cluster.cluster;
651         select_instrument(p->trident, v);
652 }
653
654 static void event_start(snd_seq_event_t * ev, snd_trident_port_t * p, snd_trident_voice_t * v)
655 {
656         if (v->sample_ops && v->sample_ops->sample_start)
657                 v->sample_ops->sample_start(p->trident, v, ev->data.sample.param.position);
658 }
659
660 static void event_stop(snd_seq_event_t * ev, snd_trident_port_t * p, snd_trident_voice_t * v)
661 {
662         if (v->sample_ops && v->sample_ops->sample_stop)
663                 v->sample_ops->sample_stop(p->trident, v, ev->data.sample.param.stop_mode);
664 }
665
666 static void event_freq(snd_seq_event_t * ev, snd_trident_port_t * p, snd_trident_voice_t * v)
667 {
668         if (v->sample_ops && v->sample_ops->sample_freq)
669                 v->sample_ops->sample_freq(p->trident, v, ev->data.sample.param.frequency);
670 }
671
672 static void event_volume(snd_seq_event_t * ev, snd_trident_port_t * p, snd_trident_voice_t * v)
673 {
674         if (v->sample_ops && v->sample_ops->sample_volume)
675                 v->sample_ops->sample_volume(p->trident, v, &ev->data.sample.param.volume);
676 }
677
678 static void event_loop(snd_seq_event_t * ev, snd_trident_port_t * p, snd_trident_voice_t * v)
679 {
680         if (v->sample_ops && v->sample_ops->sample_loop)
681                 v->sample_ops->sample_loop(p->trident, v, &ev->data.sample.param.loop);
682 }
683
684 static void event_position(snd_seq_event_t * ev, snd_trident_port_t * p, snd_trident_voice_t * v)
685 {
686         if (v->sample_ops && v->sample_ops->sample_pos)
687                 v->sample_ops->sample_pos(p->trident, v, ev->data.sample.param.position);
688 }
689
690 static void event_private1(snd_seq_event_t * ev, snd_trident_port_t * p, snd_trident_voice_t * v)
691 {
692         if (v->sample_ops && v->sample_ops->sample_private1)
693                 v->sample_ops->sample_private1(p->trident, v, (unsigned char *) &ev->data.sample.param.raw8);
694 }
695
696 typedef void (trident_sample_event_handler_t) (snd_seq_event_t * ev, snd_trident_port_t * p, snd_trident_voice_t * v);
697
698 static trident_sample_event_handler_t *trident_sample_event_handlers[9] =
699 {
700         event_sample,
701         event_cluster,
702         event_start,
703         event_stop,
704         event_freq,
705         event_volume,
706         event_loop,
707         event_position,
708         event_private1
709 };
710
711 static void snd_trident_sample_event(snd_seq_event_t * ev, snd_trident_port_t * p)
712 {
713         int idx, voice;
714         trident_t *trident = p->trident;
715         snd_trident_voice_t *v;
716         unsigned long flags;
717
718         idx = ev->type - SNDRV_SEQ_EVENT_SAMPLE;
719         if (idx < 0 || idx > 8)
720                 return;
721         for (voice = 0; voice < 64; voice++) {
722                 v = &trident->synth.voices[voice];
723                 if (v->use && v->client == ev->source.client &&
724                     v->port == ev->source.port &&
725                     v->index == ev->data.sample.channel) {
726                         spin_lock_irqsave(&trident->event_lock, flags);
727                         trident_sample_event_handlers[idx] (ev, p, v);
728                         spin_unlock_irqrestore(&trident->event_lock, flags);
729                         return;
730                 }
731         }
732 }
733
734 /*
735
736  */
737
738 static void snd_trident_synth_free_voices(trident_t * trident, int client, int port)
739 {
740         int idx;
741         snd_trident_voice_t *voice;
742
743         for (idx = 0; idx < 32; idx++) {
744                 voice = &trident->synth.voices[idx];
745                 if (voice->use && voice->client == client && voice->port == port)
746                         snd_trident_free_voice(trident, voice);
747         }
748 }
749
750 static int snd_trident_synth_use(void *private_data, snd_seq_port_subscribe_t * info)
751 {
752         snd_trident_port_t *port = (snd_trident_port_t *) private_data;
753         trident_t *trident = port->trident;
754         snd_trident_voice_t *voice;
755         unsigned int idx;
756         unsigned long flags;
757
758         if (info->voices > 32)
759                 return -EINVAL;
760         spin_lock_irqsave(&trident->reg_lock, flags);
761         for (idx = 0; idx < info->voices; idx++) {
762                 voice = snd_trident_alloc_voice(trident, SNDRV_TRIDENT_VOICE_TYPE_SYNTH, info->sender.client, info->sender.port);
763                 if (voice == NULL) {
764                         snd_trident_synth_free_voices(trident, info->sender.client, info->sender.port);
765                         spin_unlock_irqrestore(&trident->reg_lock, flags);
766                         return -EBUSY;
767                 }
768                 voice->index = idx;
769                 voice->Vol = 0x3ff;
770                 voice->EC = 0x0fff;
771         }
772 #if 0
773         for (idx = 0; idx < info->midi_voices; idx++) {
774                 port->midi_has_voices = 1;
775                 voice = snd_trident_alloc_voice(trident, SNDRV_TRIDENT_VOICE_TYPE_MIDI, info->sender.client, info->sender.port);
776                 if (voice == NULL) {
777                         snd_trident_synth_free_voices(trident, info->sender.client, info->sender.port);
778                         spin_unlock_irqrestore(&trident->reg_lock, flags);
779                         return -EBUSY;
780                 }
781                 voice->Vol = 0x3ff;
782                 voice->EC = 0x0fff;
783         }
784 #endif
785         spin_unlock_irqrestore(&trident->reg_lock, flags);
786         return 0;
787 }
788
789 static int snd_trident_synth_unuse(void *private_data, snd_seq_port_subscribe_t * info)
790 {
791         snd_trident_port_t *port = (snd_trident_port_t *) private_data;
792         trident_t *trident = port->trident;
793         unsigned long flags;
794
795         spin_lock_irqsave(&trident->reg_lock, flags);
796         snd_trident_synth_free_voices(trident, info->sender.client, info->sender.port);
797         spin_unlock_irqrestore(&trident->reg_lock, flags);
798         return 0;
799 }
800
801 /*
802
803  */
804
805 static void snd_trident_synth_free_private_instruments(snd_trident_port_t * p, int client)
806 {
807         snd_seq_instr_header_t ifree;
808
809         memset(&ifree, 0, sizeof(ifree));
810         ifree.cmd = SNDRV_SEQ_INSTR_FREE_CMD_PRIVATE;
811         snd_seq_instr_list_free_cond(p->trident->synth.ilist, &ifree, client, 0);
812 }
813
814 static int snd_trident_synth_event_input(snd_seq_event_t * ev, int direct, void *private_data, int atomic, int hop)
815 {
816         snd_trident_port_t *p = (snd_trident_port_t *) private_data;
817
818         if (p == NULL)
819                 return -EINVAL;
820         if (ev->type >= SNDRV_SEQ_EVENT_SAMPLE &&
821             ev->type <= SNDRV_SEQ_EVENT_SAMPLE_PRIVATE1) {
822                 snd_trident_sample_event(ev, p);
823                 return 0;
824         }
825         if (ev->source.client == SNDRV_SEQ_CLIENT_SYSTEM &&
826             ev->source.port == SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE) {
827                 if (ev->type == SNDRV_SEQ_EVENT_CLIENT_EXIT) {
828                         snd_trident_synth_free_private_instruments(p, ev->data.addr.client);
829                         return 0;
830                 }
831         }
832         if (direct) {
833                 if (ev->type >= SNDRV_SEQ_EVENT_INSTR_BEGIN) {
834                         snd_seq_instr_event(&p->trident->synth.simple_ops.kops,
835                                             p->trident->synth.ilist, ev,
836                                             p->trident->synth.seq_client, atomic, hop);
837                         return 0;
838                 }
839         }
840         return 0;
841 }
842
843 static void snd_trident_synth_instr_notify(void *private_data,
844                                            snd_seq_kinstr_t * instr,
845                                            int what)
846 {
847         int idx;
848         trident_t *trident = private_data;
849         snd_trident_voice_t *pvoice;
850         unsigned long flags;
851
852         spin_lock_irqsave(&trident->event_lock, flags);
853         for (idx = 0; idx < 64; idx++) {
854                 pvoice = &trident->synth.voices[idx];
855                 if (pvoice->use && !memcmp(&pvoice->instr, &instr->instr, sizeof(pvoice->instr))) {
856                         if (pvoice->sample_ops && pvoice->sample_ops->sample_stop) {
857                                 pvoice->sample_ops->sample_stop(trident, pvoice, SAMPLE_STOP_IMMEDIATELY);
858                         } else {
859                                 snd_trident_stop_voice(trident, pvoice->number);
860                                 pvoice->flags &= ~SNDRV_TRIDENT_VFLG_RUNNING;
861                         }
862                 }
863         }
864         spin_unlock_irqrestore(&trident->event_lock, flags);
865 }
866
867 /*
868
869  */
870
871 static void snd_trident_synth_free_port(void *private_data)
872 {
873         snd_trident_port_t *p = (snd_trident_port_t *) private_data;
874
875         if (p)
876                 snd_midi_channel_free_set(p->chset);
877 }
878
879 static int snd_trident_synth_create_port(trident_t * trident, int idx)
880 {
881         snd_trident_port_t *p;
882         snd_seq_port_callback_t callbacks;
883         char name[32];
884         char *str;
885         int result;
886
887         p = &trident->synth.seq_ports[idx];
888         p->chset = snd_midi_channel_alloc_set(16);
889         if (p->chset == NULL)
890                 return -ENOMEM;
891         p->chset->private_data = p;
892         p->trident = trident;
893         p->client = trident->synth.seq_client;
894
895         memset(&callbacks, 0, sizeof(callbacks));
896         callbacks.owner = THIS_MODULE;
897         callbacks.use = snd_trident_synth_use;
898         callbacks.unuse = snd_trident_synth_unuse;
899         callbacks.event_input = snd_trident_synth_event_input;
900         callbacks.private_free = snd_trident_synth_free_port;
901         callbacks.private_data = p;
902
903         str = "???";
904         switch (trident->device) {
905         case TRIDENT_DEVICE_ID_DX:      str = "Trident 4DWave-DX"; break;
906         case TRIDENT_DEVICE_ID_NX:      str = "Trident 4DWave-NX"; break;
907         case TRIDENT_DEVICE_ID_SI7018:  str = "SiS 7018"; break;
908         }
909         sprintf(name, "%s port %i", str, idx);
910         p->chset->port = snd_seq_event_port_attach(trident->synth.seq_client,
911                                                    &callbacks,
912                                                    SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE,
913                                                    SNDRV_SEQ_PORT_TYPE_DIRECT_SAMPLE |
914                                                    SNDRV_SEQ_PORT_TYPE_SYNTH,
915                                                    16, 0,
916                                                    name);
917         if (p->chset->port < 0) {
918                 result = p->chset->port;
919                 snd_trident_synth_free_port(p);
920                 return result;
921         }
922         p->port = p->chset->port;
923         return 0;
924 }
925
926 /*
927
928  */
929
930 static int snd_trident_synth_new_device(snd_seq_device_t *dev)
931 {
932         trident_t *trident;
933         int client, i;
934         snd_seq_client_callback_t callbacks;
935         snd_seq_client_info_t cinfo;
936         snd_seq_port_subscribe_t sub;
937         snd_simple_ops_t *simpleops;
938         char *str;
939
940         trident = *(trident_t **)SNDRV_SEQ_DEVICE_ARGPTR(dev);
941         if (trident == NULL)
942                 return -EINVAL;
943
944         trident->synth.seq_client = -1;
945
946         /* allocate new client */
947         memset(&callbacks, 0, sizeof(callbacks));
948         callbacks.private_data = trident;
949         callbacks.allow_output = callbacks.allow_input = 1;
950         client = trident->synth.seq_client =
951             snd_seq_create_kernel_client(trident->card, 1, &callbacks);
952         if (client < 0)
953                 return client;
954
955         /* change name of client */
956         memset(&cinfo, 0, sizeof(cinfo));
957         cinfo.client = client;
958         cinfo.type = KERNEL_CLIENT;
959         str = "???";
960         switch (trident->device) {
961         case TRIDENT_DEVICE_ID_DX:      str = "Trident 4DWave-DX"; break;
962         case TRIDENT_DEVICE_ID_NX:      str = "Trident 4DWave-NX"; break;
963         case TRIDENT_DEVICE_ID_SI7018:  str = "SiS 7018"; break;
964         }
965         sprintf(cinfo.name, str);
966         snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, &cinfo);
967
968         for (i = 0; i < 4; i++)
969                 snd_trident_synth_create_port(trident, i);
970
971         trident->synth.ilist = snd_seq_instr_list_new();
972         if (trident->synth.ilist == NULL) {
973                 snd_seq_delete_kernel_client(client);
974                 trident->synth.seq_client = -1;
975                 return -ENOMEM;
976         }
977         trident->synth.ilist->flags = SNDRV_SEQ_INSTR_FLG_DIRECT;
978
979         simpleops = &trident->synth.simple_ops;
980         snd_seq_simple_init(simpleops, trident, NULL);
981         simpleops->put_sample = snd_trident_simple_put_sample;
982         simpleops->get_sample = snd_trident_simple_get_sample;
983         simpleops->remove_sample = snd_trident_simple_remove_sample;
984         simpleops->notify = snd_trident_synth_instr_notify;
985
986         memset(&sub, 0, sizeof(sub));
987         sub.sender.client = SNDRV_SEQ_CLIENT_SYSTEM;
988         sub.sender.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE;
989         sub.dest.client = client;
990         sub.dest.port = 0;
991         snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &sub);
992
993         return 0;
994 }
995
996 static int snd_trident_synth_delete_device(snd_seq_device_t *dev)
997 {
998         trident_t *trident;
999
1000         trident = *(trident_t **)SNDRV_SEQ_DEVICE_ARGPTR(dev);
1001         if (trident == NULL)
1002                 return -EINVAL;
1003
1004         if (trident->synth.seq_client >= 0) {
1005                 snd_seq_delete_kernel_client(trident->synth.seq_client);
1006                 trident->synth.seq_client = -1;
1007         }
1008         if (trident->synth.ilist)
1009                 snd_seq_instr_list_free(&trident->synth.ilist);
1010         return 0;
1011 }
1012
1013 static int __init alsa_trident_synth_init(void)
1014 {
1015         static snd_seq_dev_ops_t ops =
1016         {
1017                 snd_trident_synth_new_device,
1018                 snd_trident_synth_delete_device
1019         };
1020
1021         return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_TRIDENT, &ops,
1022                                               sizeof(trident_t*));
1023 }
1024
1025 static void __exit alsa_trident_synth_exit(void)
1026 {
1027         snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_TRIDENT);
1028 }
1029
1030 module_init(alsa_trident_synth_init)
1031 module_exit(alsa_trident_synth_exit)