2 * Routines for Trident 4DWave NX/DX soundcards - Synthesizer
3 * Copyright (c) by Scott McNab <jedi@tartarus.uwa.edu.au>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include <sound/driver.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>
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");
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
46 #define LOG_TABLE_SIZE 386
48 /* Linear half-attenuation to log conversion table in the format:
49 * {linear volume, logarithmic attenuation equivalent}, ...
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:
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.
66 * Thus this routine provides a linear->log conversion for a range of
67 * [0,16384] using only 386 table entries
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.
74 static unsigned short log_table[LOG_TABLE_SIZE*2] =
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
156 static unsigned short lookup_volume_table( unsigned short value )
158 /* This code is an optimised version of:
160 * while( volume_table[i*2] < value )
162 * return volume_table[i*2+1];
164 unsigned short *ptr = log_table;
165 while( *ptr < value )
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 )
177 unsigned short result = 0;
179 for( c = 0, v = 8192; c < 14; c++, v >>= 1 ) {
181 result += lookup_volume_table( (value - v) << c );
184 result += 0x0605; /* 6.0205 (result of -20*log10(0.5)) */
191 * Sample handling operations
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);
202 static snd_trident_sample_ops_t sample_ops =
213 static void snd_trident_simple_init(snd_trident_voice_t * voice)
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;
222 static void sample_start(trident_t * trident, snd_trident_voice_t * voice, snd_seq_position_t position)
224 simple_instrument_t *simple;
225 snd_seq_kinstr_t *instr;
227 unsigned int loop_start, loop_end, sample_start, sample_end, start_offset;
229 unsigned int shift = 0;
231 instr = snd_seq_instr_find(trident->synth.ilist, &voice->instr, 0, 1);
234 voice->instr = instr->instr; /* copy ID to speedup aliases */
235 simple = KINSTR_DATA(instr);
237 spin_lock_irqsave(&trident->reg_lock, flags);
239 if (trident->device == TRIDENT_DEVICE_ID_SI7018)
240 voice->GVSel = 1; /* route to Wave volume */
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;
254 if (simple->format & SIMPLE_WAVE_16BIT) {
258 if (simple->format & SIMPLE_WAVE_STEREO) {
262 if (!(simple->format & SIMPLE_WAVE_UNSIGNED))
265 voice->LBA = simple->address.memory;
267 if (simple->format & SIMPLE_WAVE_LOOP) {
269 voice->LBA += loop_start << shift;
270 if( start_offset >= loop_start ) {
271 voice->CSO = start_offset - loop_start;
274 voice->CSO = loop_start - start_offset;
277 voice->ESO = loop_end - loop_start - 1;
279 voice->LBA += start_offset << shift;
280 voice->CSO = sample_start;
281 voice->ESO = sample_end - 1;
285 if (voice->flags & SNDRV_TRIDENT_VFLG_RUNNING) {
286 snd_trident_stop_voice(trident, voice->number);
287 voice->flags &= ~SNDRV_TRIDENT_VFLG_RUNNING;
291 value = inl(TRID_REG(trident, T4D_SIGN_CSO_A));
292 if( voice->negCSO ) {
293 value |= 1 << (voice->number&31);
295 value &= ~(1 << (voice->number&31));
297 outl(value,TRID_REG(trident, T4D_SIGN_CSO_A));
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);
307 static void sample_stop(trident_t * trident, snd_trident_voice_t * voice, snd_seq_stop_mode_t mode)
311 if (!(voice->flags & SNDRV_TRIDENT_VFLG_RUNNING))
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);
321 case SAMPLE_STOP_LOOP: /* disable loop only */
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);
331 static void sample_freq(trident_t * trident, snd_trident_voice_t * voice, snd_seq_frequency_t freq)
336 spin_lock_irqsave(&trident->reg_lock, flags);
338 voice->Delta = 0xeb3;
339 else if (freq == 8000)
340 voice->Delta = 0x2ab;
341 else if (freq == 48000)
342 voice->Delta = 0x1000;
344 voice->Delta = (((freq << 12) + freq) / 48000) & 0x0000ffff;
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));
351 outw((unsigned short) voice->Delta, TRID_REG(trident, CH_DX_ESO_DELTA));
354 spin_unlock_irqrestore(&trident->reg_lock, flags);
357 static void sample_volume(trident_t * trident, snd_trident_voice_t * voice, snd_seq_ev_volume_t * volume)
360 unsigned short value;
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 */
372 value = log_from_linear( volume->volume );
374 voice->EC = (value & 0x3fff) >> 2;
375 if (value > 0x3fff) {
378 voice->Vol = ((value >> 8) - 0x3f) << 5;
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] )
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] )
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);
409 static void sample_loop(trident_t * trident, snd_trident_voice_t * voice, snd_seq_ev_loop_t * loop)
412 simple_instrument_t *simple;
413 snd_seq_kinstr_t *instr;
414 unsigned int loop_start, loop_end;
416 instr = snd_seq_instr_find(trident->synth.ilist, &voice->instr, 0, 1);
419 voice->instr = instr->instr; /* copy ID to speedup aliases */
420 simple = KINSTR_DATA(instr);
422 loop_start = loop->start >> 4;
423 loop_end = loop->end >> 4;
425 spin_lock_irqsave(&trident->reg_lock, flags);
427 voice->LBA = simple->address.memory + loop_start;
429 voice->ESO = loop_end - loop_start - 1;
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));
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));
444 spin_unlock_irqrestore(&trident->reg_lock, flags);
445 snd_seq_instr_free_use(trident->synth.ilist, instr);
448 static void sample_pos(trident_t * trident, snd_trident_voice_t * voice, snd_seq_position_t position)
451 simple_instrument_t *simple;
452 snd_seq_kinstr_t *instr;
455 instr = snd_seq_instr_find(trident->synth.ilist, &voice->instr, 0, 1);
458 voice->instr = instr->instr; /* copy ID to speedup aliases */
459 simple = KINSTR_DATA(instr);
461 spin_lock_irqsave(&trident->reg_lock, flags);
463 if (simple->format & SIMPLE_WAVE_LOOP) {
464 if( position >= simple->loop_start ) {
465 voice->CSO = (position - simple->loop_start) >> 4;
468 voice->CSO = (simple->loop_start - position) >> 4;
472 voice->CSO = position >> 4;
477 value = inl(TRID_REG(trident, T4D_SIGN_CSO_A));
478 if( voice->negCSO ) {
479 value |= 1 << (voice->number&31);
481 value &= ~(1 << (voice->number&31));
483 outl(value,TRID_REG(trident, T4D_SIGN_CSO_A));
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));
491 outw((voice->CSO & 0xffff), TRID_REG(trident, CH_DX_CSO_ALPHA_FMS) + 2);
494 spin_unlock_irqrestore(&trident->reg_lock, flags);
495 snd_seq_instr_free_use(trident->synth.ilist, instr);
498 static void sample_private1(trident_t * trident, snd_trident_voice_t * voice, unsigned char *data)
503 * Memory management / sample loading
506 static int snd_trident_simple_put_sample(void *private_data, simple_instrument_t * instr,
507 char *data, long len, int atomic)
509 trident_t *trident = snd_magic_cast(trident_t, private_data, return -ENXIO);
510 int size = instr->size;
513 if (instr->format & SIMPLE_WAVE_BACKWARD ||
514 instr->format & SIMPLE_WAVE_BIDIR ||
515 instr->format & SIMPLE_WAVE_ULAW)
516 return -EINVAL; /* not supported */
518 if (instr->format & SIMPLE_WAVE_16BIT)
520 if (instr->format & SIMPLE_WAVE_STEREO)
524 if (trident->synth.current_size + size > trident->synth.max_size)
527 if (verify_area(VERIFY_READ, data, size))
530 if (trident->tlb.entries) {
531 snd_util_memblk_t *memblk;
532 memblk = snd_trident_synth_alloc(trident, size);
535 if (snd_trident_synth_copy_from_user(trident, memblk, 0, data, size) ) {
536 snd_trident_synth_free(trident, memblk);
539 instr->address.ptr = (unsigned char*)memblk;
540 instr->address.memory = memblk->offset;
542 struct snd_dma_buffer dmab;
544 if (snd_dma_alloc_pages(&trident->dma_dev, size, &dmab) < 0)
547 if (copy_from_user(dmab.area, data, size)) {
548 snd_dma_free_pages(&trident->dma_dev, &dmab);
551 instr->address.ptr = dmab.area;
552 instr->address.memory = dmab.addr;
555 trident->synth.current_size += size;
559 static int snd_trident_simple_get_sample(void *private_data, simple_instrument_t * instr,
560 char *data, long len, int atomic)
562 //trident_t *trident = snd_magic_cast(trident_t, private_data, return -ENXIO);
563 int size = instr->size;
566 if (instr->format & SIMPLE_WAVE_16BIT)
568 if (instr->format & SIMPLE_WAVE_STEREO)
572 if (verify_area(VERIFY_WRITE, data, size))
575 /* FIXME: not implemented yet */
580 static int snd_trident_simple_remove_sample(void *private_data, simple_instrument_t * instr,
583 trident_t *trident = snd_magic_cast(trident_t, private_data, return -ENXIO);
584 int size = instr->size;
586 if (trident->tlb.entries) {
587 snd_util_memblk_t *memblk = (snd_util_memblk_t*)instr->address.ptr;
589 snd_trident_synth_free(trident, memblk);
593 kfree(instr->address.ptr);
596 if (instr->format & SIMPLE_WAVE_16BIT)
598 if (instr->format & SIMPLE_WAVE_STEREO)
601 trident->synth.current_size -= size;
602 if (trident->synth.current_size < 0) /* shouldn't need this check... */
603 trident->synth.current_size = 0;
608 static void select_instrument(trident_t * trident, snd_trident_voice_t * v)
610 snd_seq_kinstr_t *instr;
611 instr = snd_seq_instr_find(trident->synth.ilist, &v->instr, 0, 1);
614 if (instr->ops->instr_type == snd_seq_simple_id)
615 snd_trident_simple_init(v);
617 snd_seq_instr_free_use(trident->synth.ilist, instr);
625 static void event_sample(snd_seq_event_t * ev, snd_trident_port_t * p, snd_trident_voice_t * v)
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;
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);
639 static void event_cluster(snd_seq_event_t * ev, snd_trident_port_t * p, snd_trident_voice_t * v)
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);
647 static void event_start(snd_seq_event_t * ev, snd_trident_port_t * p, snd_trident_voice_t * v)
649 if (v->sample_ops && v->sample_ops->sample_start)
650 v->sample_ops->sample_start(p->trident, v, ev->data.sample.param.position);
653 static void event_stop(snd_seq_event_t * ev, snd_trident_port_t * p, snd_trident_voice_t * v)
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);
659 static void event_freq(snd_seq_event_t * ev, snd_trident_port_t * p, snd_trident_voice_t * v)
661 if (v->sample_ops && v->sample_ops->sample_freq)
662 v->sample_ops->sample_freq(p->trident, v, ev->data.sample.param.frequency);
665 static void event_volume(snd_seq_event_t * ev, snd_trident_port_t * p, snd_trident_voice_t * v)
667 if (v->sample_ops && v->sample_ops->sample_volume)
668 v->sample_ops->sample_volume(p->trident, v, &ev->data.sample.param.volume);
671 static void event_loop(snd_seq_event_t * ev, snd_trident_port_t * p, snd_trident_voice_t * v)
673 if (v->sample_ops && v->sample_ops->sample_loop)
674 v->sample_ops->sample_loop(p->trident, v, &ev->data.sample.param.loop);
677 static void event_position(snd_seq_event_t * ev, snd_trident_port_t * p, snd_trident_voice_t * v)
679 if (v->sample_ops && v->sample_ops->sample_pos)
680 v->sample_ops->sample_pos(p->trident, v, ev->data.sample.param.position);
683 static void event_private1(snd_seq_event_t * ev, snd_trident_port_t * p, snd_trident_voice_t * v)
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);
689 typedef void (trident_sample_event_handler_t) (snd_seq_event_t * ev, snd_trident_port_t * p, snd_trident_voice_t * v);
691 static trident_sample_event_handler_t *trident_sample_event_handlers[9] =
704 static void snd_trident_sample_event(snd_seq_event_t * ev, snd_trident_port_t * p)
707 trident_t *trident = p->trident;
708 snd_trident_voice_t *v;
711 idx = ev->type - SNDRV_SEQ_EVENT_SAMPLE;
712 if (idx < 0 || idx > 8)
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);
731 static void snd_trident_synth_free_voices(trident_t * trident, int client, int port)
734 snd_trident_voice_t *voice;
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);
743 static int snd_trident_synth_use(void *private_data, snd_seq_port_subscribe_t * info)
745 snd_trident_port_t *port = (snd_trident_port_t *) private_data;
746 trident_t *trident = port->trident;
747 snd_trident_voice_t *voice;
751 if (info->voices > 32)
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);
757 snd_trident_synth_free_voices(trident, info->sender.client, info->sender.port);
758 spin_unlock_irqrestore(&trident->reg_lock, flags);
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);
770 snd_trident_synth_free_voices(trident, info->sender.client, info->sender.port);
771 spin_unlock_irqrestore(&trident->reg_lock, flags);
778 spin_unlock_irqrestore(&trident->reg_lock, flags);
782 static int snd_trident_synth_unuse(void *private_data, snd_seq_port_subscribe_t * info)
784 snd_trident_port_t *port = (snd_trident_port_t *) private_data;
785 trident_t *trident = port->trident;
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);
798 static void snd_trident_synth_free_private_instruments(snd_trident_port_t * p, int client)
800 snd_seq_instr_header_t ifree;
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);
807 int snd_trident_synth_event_input(snd_seq_event_t * ev, int direct, void *private_data, int atomic, int hop)
809 snd_trident_port_t *p = (snd_trident_port_t *) private_data;
813 if (ev->type >= SNDRV_SEQ_EVENT_SAMPLE &&
814 ev->type <= SNDRV_SEQ_EVENT_SAMPLE_PRIVATE1) {
815 snd_trident_sample_event(ev, p);
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);
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);
836 static void snd_trident_synth_instr_notify(void *private_data,
837 snd_seq_kinstr_t * instr,
841 trident_t *trident = snd_magic_cast(trident_t, private_data, return);
842 snd_trident_voice_t *pvoice;
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);
852 snd_trident_stop_voice(trident, pvoice->number);
853 pvoice->flags &= ~SNDRV_TRIDENT_VFLG_RUNNING;
857 spin_unlock_irqrestore(&trident->event_lock, flags);
864 static void snd_trident_synth_free_port(void *private_data)
866 snd_trident_port_t *p = (snd_trident_port_t *) private_data;
869 snd_midi_channel_free_set(p->chset);
872 static int snd_trident_synth_create_port(trident_t * trident, int idx)
874 snd_trident_port_t *p;
875 snd_seq_port_callback_t callbacks;
880 p = &trident->synth.seq_ports[idx];
881 p->chset = snd_midi_channel_alloc_set(16);
882 if (p->chset == NULL)
884 p->chset->private_data = p;
885 p->trident = trident;
886 p->client = trident->synth.seq_client;
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;
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;
902 sprintf(name, "%s port %i", str, idx);
903 p->chset->port = snd_seq_event_port_attach(trident->synth.seq_client,
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,
910 if (p->chset->port < 0) {
911 result = p->chset->port;
912 snd_trident_synth_free_port(p);
915 p->port = p->chset->port;
923 static int snd_trident_synth_new_device(snd_seq_device_t *dev)
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;
933 trident = *(trident_t **)SNDRV_SEQ_DEVICE_ARGPTR(dev);
937 trident->synth.seq_client = -1;
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);
948 /* change name of client */
949 memset(&cinfo, 0, sizeof(cinfo));
950 cinfo.client = client;
951 cinfo.type = KERNEL_CLIENT;
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;
958 sprintf(cinfo.name, str);
959 snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, &cinfo);
961 for (i = 0; i < 4; i++)
962 snd_trident_synth_create_port(trident, i);
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;
970 trident->synth.ilist->flags = SNDRV_SEQ_INSTR_FLG_DIRECT;
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;
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;
984 snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &sub);
989 static int snd_trident_synth_delete_device(snd_seq_device_t *dev)
993 trident = *(trident_t **)SNDRV_SEQ_DEVICE_ARGPTR(dev);
997 if (trident->synth.seq_client >= 0) {
998 snd_seq_delete_kernel_client(trident->synth.seq_client);
999 trident->synth.seq_client = -1;
1001 if (trident->synth.ilist)
1002 snd_seq_instr_list_free(&trident->synth.ilist);
1006 static int __init alsa_trident_synth_init(void)
1008 static snd_seq_dev_ops_t ops =
1010 snd_trident_synth_new_device,
1011 snd_trident_synth_delete_device
1014 return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_TRIDENT, &ops,
1015 sizeof(trident_t*));
1018 static void __exit alsa_trident_synth_exit(void)
1020 snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_TRIDENT);
1023 module_init(alsa_trident_synth_init)
1024 module_exit(alsa_trident_synth_exit)