diff options
Diffstat (limited to 'sound')
-rw-r--r-- | sound/core/seq/Makefile | 8 | ||||
-rw-r--r-- | sound/core/seq/instr/Makefile | 23 | ||||
-rw-r--r-- | sound/core/seq/instr/ainstr_fm.c | 155 | ||||
-rw-r--r-- | sound/core/seq/instr/ainstr_gf1.c | 359 | ||||
-rw-r--r-- | sound/core/seq/instr/ainstr_iw.c | 623 | ||||
-rw-r--r-- | sound/core/seq/instr/ainstr_simple.c | 215 | ||||
-rw-r--r-- | sound/core/seq/seq_clientmgr.c | 3 | ||||
-rw-r--r-- | sound/core/seq/seq_instr.c | 655 | ||||
-rw-r--r-- | sound/core/seq/seq_midi_emul.c | 7 | ||||
-rw-r--r-- | sound/isa/gus/Makefile | 12 | ||||
-rw-r--r-- | sound/isa/gus/gus_main.c | 23 | ||||
-rw-r--r-- | sound/isa/gus/gus_sample.c | 165 | ||||
-rw-r--r-- | sound/isa/gus/gus_simple.c | 634 | ||||
-rw-r--r-- | sound/isa/gus/gus_synth.c | 314 | ||||
-rw-r--r-- | sound/pci/trident/Makefile | 10 | ||||
-rw-r--r-- | sound/pci/trident/trident.c | 7 | ||||
-rw-r--r-- | sound/pci/trident/trident_main.c | 28 | ||||
-rw-r--r-- | sound/pci/trident/trident_synth.c | 1024 |
18 files changed, 3 insertions, 4262 deletions
diff --git a/sound/core/seq/Makefile b/sound/core/seq/Makefile index ceef14afee30..069593717fba 100644 --- a/sound/core/seq/Makefile +++ b/sound/core/seq/Makefile | |||
@@ -3,7 +3,6 @@ | |||
3 | # Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz> | 3 | # Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz> |
4 | # | 4 | # |
5 | 5 | ||
6 | obj-$(CONFIG_SND) += instr/ | ||
7 | ifeq ($(CONFIG_SND_SEQUENCER_OSS),y) | 6 | ifeq ($(CONFIG_SND_SEQUENCER_OSS),y) |
8 | obj-$(CONFIG_SND_SEQUENCER) += oss/ | 7 | obj-$(CONFIG_SND_SEQUENCER) += oss/ |
9 | endif | 8 | endif |
@@ -15,7 +14,6 @@ snd-seq-objs := seq.o seq_lock.o seq_clientmgr.o seq_memory.o seq_queue.o \ | |||
15 | snd-seq-midi-objs := seq_midi.o | 14 | snd-seq-midi-objs := seq_midi.o |
16 | snd-seq-midi-emul-objs := seq_midi_emul.o | 15 | snd-seq-midi-emul-objs := seq_midi_emul.o |
17 | snd-seq-midi-event-objs := seq_midi_event.o | 16 | snd-seq-midi-event-objs := seq_midi_event.o |
18 | snd-seq-instr-objs := seq_instr.o | ||
19 | snd-seq-dummy-objs := seq_dummy.o | 17 | snd-seq-dummy-objs := seq_dummy.o |
20 | snd-seq-virmidi-objs := seq_virmidi.o | 18 | snd-seq-virmidi-objs := seq_virmidi.o |
21 | 19 | ||
@@ -36,9 +34,7 @@ obj-$(CONFIG_SND_SEQ_DUMMY) += snd-seq-dummy.o | |||
36 | # Toplevel Module Dependency | 34 | # Toplevel Module Dependency |
37 | obj-$(CONFIG_SND_VIRMIDI) += snd-seq-virmidi.o snd-seq-midi-event.o | 35 | obj-$(CONFIG_SND_VIRMIDI) += snd-seq-virmidi.o snd-seq-midi-event.o |
38 | obj-$(call sequencer,$(CONFIG_SND_RAWMIDI)) += snd-seq-midi.o snd-seq-midi-event.o | 36 | obj-$(call sequencer,$(CONFIG_SND_RAWMIDI)) += snd-seq-midi.o snd-seq-midi-event.o |
39 | obj-$(call sequencer,$(CONFIG_SND_OPL3_LIB)) += snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o | 37 | obj-$(call sequencer,$(CONFIG_SND_OPL3_LIB)) += snd-seq-midi-event.o snd-seq-midi-emul.o |
40 | obj-$(call sequencer,$(CONFIG_SND_OPL4_LIB)) += snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o | 38 | obj-$(call sequencer,$(CONFIG_SND_OPL4_LIB)) += snd-seq-midi-event.o snd-seq-midi-emul.o |
41 | obj-$(call sequencer,$(CONFIG_SND_GUS_SYNTH)) += snd-seq-midi-emul.o snd-seq-instr.o | ||
42 | obj-$(call sequencer,$(CONFIG_SND_SBAWE)) += snd-seq-midi-emul.o snd-seq-virmidi.o | 39 | obj-$(call sequencer,$(CONFIG_SND_SBAWE)) += snd-seq-midi-emul.o snd-seq-virmidi.o |
43 | obj-$(call sequencer,$(CONFIG_SND_EMU10K1)) += snd-seq-midi-emul.o snd-seq-virmidi.o | 40 | obj-$(call sequencer,$(CONFIG_SND_EMU10K1)) += snd-seq-midi-emul.o snd-seq-virmidi.o |
44 | obj-$(call sequencer,$(CONFIG_SND_TRIDENT)) += snd-seq-midi-emul.o snd-seq-instr.o | ||
diff --git a/sound/core/seq/instr/Makefile b/sound/core/seq/instr/Makefile deleted file mode 100644 index 608960364813..000000000000 --- a/sound/core/seq/instr/Makefile +++ /dev/null | |||
@@ -1,23 +0,0 @@ | |||
1 | # | ||
2 | # Makefile for ALSA | ||
3 | # Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz> | ||
4 | # | ||
5 | |||
6 | snd-ainstr-fm-objs := ainstr_fm.o | ||
7 | snd-ainstr-simple-objs := ainstr_simple.o | ||
8 | snd-ainstr-gf1-objs := ainstr_gf1.o | ||
9 | snd-ainstr-iw-objs := ainstr_iw.o | ||
10 | |||
11 | # | ||
12 | # this function returns: | ||
13 | # "m" - CONFIG_SND_SEQUENCER is m | ||
14 | # <empty string> - CONFIG_SND_SEQUENCER is undefined | ||
15 | # otherwise parameter #1 value | ||
16 | # | ||
17 | sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1))) | ||
18 | |||
19 | # Toplevel Module Dependency | ||
20 | obj-$(call sequencer,$(CONFIG_SND_OPL3_LIB)) += snd-ainstr-fm.o | ||
21 | obj-$(call sequencer,$(CONFIG_SND_OPL4_LIB)) += snd-ainstr-fm.o | ||
22 | obj-$(call sequencer,$(CONFIG_SND_GUS_SYNTH)) += snd-ainstr-gf1.o snd-ainstr-simple.o snd-ainstr-iw.o | ||
23 | obj-$(call sequencer,$(CONFIG_SND_TRIDENT)) += snd-ainstr-simple.o | ||
diff --git a/sound/core/seq/instr/ainstr_fm.c b/sound/core/seq/instr/ainstr_fm.c deleted file mode 100644 index f80fab8f2ed1..000000000000 --- a/sound/core/seq/instr/ainstr_fm.c +++ /dev/null | |||
@@ -1,155 +0,0 @@ | |||
1 | /* | ||
2 | * FM (OPL2/3) Instrument routines | ||
3 | * Copyright (c) 2000 Uros Bizjak <uros@kss-loka.si> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | #include <sound/driver.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <sound/core.h> | ||
24 | #include <sound/ainstr_fm.h> | ||
25 | #include <sound/initval.h> | ||
26 | #include <asm/uaccess.h> | ||
27 | |||
28 | MODULE_AUTHOR("Uros Bizjak <uros@kss-loka.si>"); | ||
29 | MODULE_DESCRIPTION("Advanced Linux Sound Architecture FM Instrument support."); | ||
30 | MODULE_LICENSE("GPL"); | ||
31 | |||
32 | static int snd_seq_fm_put(void *private_data, struct snd_seq_kinstr *instr, | ||
33 | char __user *instr_data, long len, int atomic, int cmd) | ||
34 | { | ||
35 | struct fm_instrument *ip; | ||
36 | struct fm_xinstrument ix; | ||
37 | int idx; | ||
38 | |||
39 | if (cmd != SNDRV_SEQ_INSTR_PUT_CMD_CREATE) | ||
40 | return -EINVAL; | ||
41 | /* copy instrument data */ | ||
42 | if (len < (long)sizeof(ix)) | ||
43 | return -EINVAL; | ||
44 | if (copy_from_user(&ix, instr_data, sizeof(ix))) | ||
45 | return -EFAULT; | ||
46 | if (ix.stype != FM_STRU_INSTR) | ||
47 | return -EINVAL; | ||
48 | ip = (struct fm_instrument *)KINSTR_DATA(instr); | ||
49 | ip->share_id[0] = le32_to_cpu(ix.share_id[0]); | ||
50 | ip->share_id[1] = le32_to_cpu(ix.share_id[1]); | ||
51 | ip->share_id[2] = le32_to_cpu(ix.share_id[2]); | ||
52 | ip->share_id[3] = le32_to_cpu(ix.share_id[3]); | ||
53 | ip->type = ix.type; | ||
54 | for (idx = 0; idx < 4; idx++) { | ||
55 | ip->op[idx].am_vib = ix.op[idx].am_vib; | ||
56 | ip->op[idx].ksl_level = ix.op[idx].ksl_level; | ||
57 | ip->op[idx].attack_decay = ix.op[idx].attack_decay; | ||
58 | ip->op[idx].sustain_release = ix.op[idx].sustain_release; | ||
59 | ip->op[idx].wave_select = ix.op[idx].wave_select; | ||
60 | } | ||
61 | for (idx = 0; idx < 2; idx++) { | ||
62 | ip->feedback_connection[idx] = ix.feedback_connection[idx]; | ||
63 | } | ||
64 | ip->echo_delay = ix.echo_delay; | ||
65 | ip->echo_atten = ix.echo_atten; | ||
66 | ip->chorus_spread = ix.chorus_spread; | ||
67 | ip->trnsps = ix.trnsps; | ||
68 | ip->fix_dur = ix.fix_dur; | ||
69 | ip->modes = ix.modes; | ||
70 | ip->fix_key = ix.fix_key; | ||
71 | return 0; | ||
72 | } | ||
73 | |||
74 | static int snd_seq_fm_get(void *private_data, struct snd_seq_kinstr *instr, | ||
75 | char __user *instr_data, long len, int atomic, | ||
76 | int cmd) | ||
77 | { | ||
78 | struct fm_instrument *ip; | ||
79 | struct fm_xinstrument ix; | ||
80 | int idx; | ||
81 | |||
82 | if (cmd != SNDRV_SEQ_INSTR_GET_CMD_FULL) | ||
83 | return -EINVAL; | ||
84 | if (len < (long)sizeof(ix)) | ||
85 | return -ENOMEM; | ||
86 | memset(&ix, 0, sizeof(ix)); | ||
87 | ip = (struct fm_instrument *)KINSTR_DATA(instr); | ||
88 | ix.stype = FM_STRU_INSTR; | ||
89 | ix.share_id[0] = cpu_to_le32(ip->share_id[0]); | ||
90 | ix.share_id[1] = cpu_to_le32(ip->share_id[1]); | ||
91 | ix.share_id[2] = cpu_to_le32(ip->share_id[2]); | ||
92 | ix.share_id[3] = cpu_to_le32(ip->share_id[3]); | ||
93 | ix.type = ip->type; | ||
94 | for (idx = 0; idx < 4; idx++) { | ||
95 | ix.op[idx].am_vib = ip->op[idx].am_vib; | ||
96 | ix.op[idx].ksl_level = ip->op[idx].ksl_level; | ||
97 | ix.op[idx].attack_decay = ip->op[idx].attack_decay; | ||
98 | ix.op[idx].sustain_release = ip->op[idx].sustain_release; | ||
99 | ix.op[idx].wave_select = ip->op[idx].wave_select; | ||
100 | } | ||
101 | for (idx = 0; idx < 2; idx++) { | ||
102 | ix.feedback_connection[idx] = ip->feedback_connection[idx]; | ||
103 | } | ||
104 | if (copy_to_user(instr_data, &ix, sizeof(ix))) | ||
105 | return -EFAULT; | ||
106 | ix.echo_delay = ip->echo_delay; | ||
107 | ix.echo_atten = ip->echo_atten; | ||
108 | ix.chorus_spread = ip->chorus_spread; | ||
109 | ix.trnsps = ip->trnsps; | ||
110 | ix.fix_dur = ip->fix_dur; | ||
111 | ix.modes = ip->modes; | ||
112 | ix.fix_key = ip->fix_key; | ||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | static int snd_seq_fm_get_size(void *private_data, struct snd_seq_kinstr *instr, | ||
117 | long *size) | ||
118 | { | ||
119 | *size = sizeof(struct fm_xinstrument); | ||
120 | return 0; | ||
121 | } | ||
122 | |||
123 | int snd_seq_fm_init(struct snd_seq_kinstr_ops *ops, | ||
124 | struct snd_seq_kinstr_ops *next) | ||
125 | { | ||
126 | memset(ops, 0, sizeof(*ops)); | ||
127 | // ops->private_data = private_data; | ||
128 | ops->add_len = sizeof(struct fm_instrument); | ||
129 | ops->instr_type = SNDRV_SEQ_INSTR_ID_OPL2_3; | ||
130 | ops->put = snd_seq_fm_put; | ||
131 | ops->get = snd_seq_fm_get; | ||
132 | ops->get_size = snd_seq_fm_get_size; | ||
133 | // ops->remove = snd_seq_fm_remove; | ||
134 | // ops->notify = snd_seq_fm_notify; | ||
135 | ops->next = next; | ||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | /* | ||
140 | * Init part | ||
141 | */ | ||
142 | |||
143 | static int __init alsa_ainstr_fm_init(void) | ||
144 | { | ||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | static void __exit alsa_ainstr_fm_exit(void) | ||
149 | { | ||
150 | } | ||
151 | |||
152 | module_init(alsa_ainstr_fm_init) | ||
153 | module_exit(alsa_ainstr_fm_exit) | ||
154 | |||
155 | EXPORT_SYMBOL(snd_seq_fm_init); | ||
diff --git a/sound/core/seq/instr/ainstr_gf1.c b/sound/core/seq/instr/ainstr_gf1.c deleted file mode 100644 index 49400262b1eb..000000000000 --- a/sound/core/seq/instr/ainstr_gf1.c +++ /dev/null | |||
@@ -1,359 +0,0 @@ | |||
1 | /* | ||
2 | * GF1 (GUS) Patch - Instrument routines | ||
3 | * Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | #include <sound/driver.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <sound/core.h> | ||
25 | #include <sound/ainstr_gf1.h> | ||
26 | #include <sound/initval.h> | ||
27 | #include <asm/uaccess.h> | ||
28 | |||
29 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); | ||
30 | MODULE_DESCRIPTION("Advanced Linux Sound Architecture GF1 (GUS) Patch support."); | ||
31 | MODULE_LICENSE("GPL"); | ||
32 | |||
33 | static unsigned int snd_seq_gf1_size(unsigned int size, unsigned int format) | ||
34 | { | ||
35 | unsigned int result = size; | ||
36 | |||
37 | if (format & GF1_WAVE_16BIT) | ||
38 | result <<= 1; | ||
39 | if (format & GF1_WAVE_STEREO) | ||
40 | result <<= 1; | ||
41 | return format; | ||
42 | } | ||
43 | |||
44 | static int snd_seq_gf1_copy_wave_from_stream(struct snd_gf1_ops *ops, | ||
45 | struct gf1_instrument *ip, | ||
46 | char __user **data, | ||
47 | long *len, | ||
48 | int atomic) | ||
49 | { | ||
50 | struct gf1_wave *wp, *prev; | ||
51 | struct gf1_xwave xp; | ||
52 | int err; | ||
53 | gfp_t gfp_mask; | ||
54 | unsigned int real_size; | ||
55 | |||
56 | gfp_mask = atomic ? GFP_ATOMIC : GFP_KERNEL; | ||
57 | if (*len < (long)sizeof(xp)) | ||
58 | return -EINVAL; | ||
59 | if (copy_from_user(&xp, *data, sizeof(xp))) | ||
60 | return -EFAULT; | ||
61 | *data += sizeof(xp); | ||
62 | *len -= sizeof(xp); | ||
63 | wp = kzalloc(sizeof(*wp), gfp_mask); | ||
64 | if (wp == NULL) | ||
65 | return -ENOMEM; | ||
66 | wp->share_id[0] = le32_to_cpu(xp.share_id[0]); | ||
67 | wp->share_id[1] = le32_to_cpu(xp.share_id[1]); | ||
68 | wp->share_id[2] = le32_to_cpu(xp.share_id[2]); | ||
69 | wp->share_id[3] = le32_to_cpu(xp.share_id[3]); | ||
70 | wp->format = le32_to_cpu(xp.format); | ||
71 | wp->size = le32_to_cpu(xp.size); | ||
72 | wp->start = le32_to_cpu(xp.start); | ||
73 | wp->loop_start = le32_to_cpu(xp.loop_start); | ||
74 | wp->loop_end = le32_to_cpu(xp.loop_end); | ||
75 | wp->loop_repeat = le16_to_cpu(xp.loop_repeat); | ||
76 | wp->flags = xp.flags; | ||
77 | wp->sample_rate = le32_to_cpu(xp.sample_rate); | ||
78 | wp->low_frequency = le32_to_cpu(xp.low_frequency); | ||
79 | wp->high_frequency = le32_to_cpu(xp.high_frequency); | ||
80 | wp->root_frequency = le32_to_cpu(xp.root_frequency); | ||
81 | wp->tune = le16_to_cpu(xp.tune); | ||
82 | wp->balance = xp.balance; | ||
83 | memcpy(wp->envelope_rate, xp.envelope_rate, 6); | ||
84 | memcpy(wp->envelope_offset, xp.envelope_offset, 6); | ||
85 | wp->tremolo_sweep = xp.tremolo_sweep; | ||
86 | wp->tremolo_rate = xp.tremolo_rate; | ||
87 | wp->tremolo_depth = xp.tremolo_depth; | ||
88 | wp->vibrato_sweep = xp.vibrato_sweep; | ||
89 | wp->vibrato_rate = xp.vibrato_rate; | ||
90 | wp->vibrato_depth = xp.vibrato_depth; | ||
91 | wp->scale_frequency = le16_to_cpu(xp.scale_frequency); | ||
92 | wp->scale_factor = le16_to_cpu(xp.scale_factor); | ||
93 | real_size = snd_seq_gf1_size(wp->size, wp->format); | ||
94 | if ((long)real_size > *len) { | ||
95 | kfree(wp); | ||
96 | return -ENOMEM; | ||
97 | } | ||
98 | if (ops->put_sample) { | ||
99 | err = ops->put_sample(ops->private_data, wp, | ||
100 | *data, real_size, atomic); | ||
101 | if (err < 0) { | ||
102 | kfree(wp); | ||
103 | return err; | ||
104 | } | ||
105 | } | ||
106 | *data += real_size; | ||
107 | *len -= real_size; | ||
108 | prev = ip->wave; | ||
109 | if (prev) { | ||
110 | while (prev->next) prev = prev->next; | ||
111 | prev->next = wp; | ||
112 | } else { | ||
113 | ip->wave = wp; | ||
114 | } | ||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | static void snd_seq_gf1_wave_free(struct snd_gf1_ops *ops, | ||
119 | struct gf1_wave *wave, | ||
120 | int atomic) | ||
121 | { | ||
122 | if (ops->remove_sample) | ||
123 | ops->remove_sample(ops->private_data, wave, atomic); | ||
124 | kfree(wave); | ||
125 | } | ||
126 | |||
127 | static void snd_seq_gf1_instr_free(struct snd_gf1_ops *ops, | ||
128 | struct gf1_instrument *ip, | ||
129 | int atomic) | ||
130 | { | ||
131 | struct gf1_wave *wave; | ||
132 | |||
133 | while ((wave = ip->wave) != NULL) { | ||
134 | ip->wave = wave->next; | ||
135 | snd_seq_gf1_wave_free(ops, wave, atomic); | ||
136 | } | ||
137 | } | ||
138 | |||
139 | static int snd_seq_gf1_put(void *private_data, struct snd_seq_kinstr *instr, | ||
140 | char __user *instr_data, long len, int atomic, | ||
141 | int cmd) | ||
142 | { | ||
143 | struct snd_gf1_ops *ops = private_data; | ||
144 | struct gf1_instrument *ip; | ||
145 | struct gf1_xinstrument ix; | ||
146 | int err; | ||
147 | gfp_t gfp_mask; | ||
148 | |||
149 | if (cmd != SNDRV_SEQ_INSTR_PUT_CMD_CREATE) | ||
150 | return -EINVAL; | ||
151 | gfp_mask = atomic ? GFP_ATOMIC : GFP_KERNEL; | ||
152 | /* copy instrument data */ | ||
153 | if (len < (long)sizeof(ix)) | ||
154 | return -EINVAL; | ||
155 | if (copy_from_user(&ix, instr_data, sizeof(ix))) | ||
156 | return -EFAULT; | ||
157 | if (ix.stype != GF1_STRU_INSTR) | ||
158 | return -EINVAL; | ||
159 | instr_data += sizeof(ix); | ||
160 | len -= sizeof(ix); | ||
161 | ip = (struct gf1_instrument *)KINSTR_DATA(instr); | ||
162 | ip->exclusion = le16_to_cpu(ix.exclusion); | ||
163 | ip->exclusion_group = le16_to_cpu(ix.exclusion_group); | ||
164 | ip->effect1 = ix.effect1; | ||
165 | ip->effect1_depth = ix.effect1_depth; | ||
166 | ip->effect2 = ix.effect2; | ||
167 | ip->effect2_depth = ix.effect2_depth; | ||
168 | /* copy layers */ | ||
169 | while (len > (long)sizeof(__u32)) { | ||
170 | __u32 stype; | ||
171 | |||
172 | if (copy_from_user(&stype, instr_data, sizeof(stype))) | ||
173 | return -EFAULT; | ||
174 | if (stype != GF1_STRU_WAVE) { | ||
175 | snd_seq_gf1_instr_free(ops, ip, atomic); | ||
176 | return -EINVAL; | ||
177 | } | ||
178 | err = snd_seq_gf1_copy_wave_from_stream(ops, | ||
179 | ip, | ||
180 | &instr_data, | ||
181 | &len, | ||
182 | atomic); | ||
183 | if (err < 0) { | ||
184 | snd_seq_gf1_instr_free(ops, ip, atomic); | ||
185 | return err; | ||
186 | } | ||
187 | } | ||
188 | return 0; | ||
189 | } | ||
190 | |||
191 | static int snd_seq_gf1_copy_wave_to_stream(struct snd_gf1_ops *ops, | ||
192 | struct gf1_instrument *ip, | ||
193 | char __user **data, | ||
194 | long *len, | ||
195 | int atomic) | ||
196 | { | ||
197 | struct gf1_wave *wp; | ||
198 | struct gf1_xwave xp; | ||
199 | int err; | ||
200 | unsigned int real_size; | ||
201 | |||
202 | for (wp = ip->wave; wp; wp = wp->next) { | ||
203 | if (*len < (long)sizeof(xp)) | ||
204 | return -ENOMEM; | ||
205 | memset(&xp, 0, sizeof(xp)); | ||
206 | xp.stype = GF1_STRU_WAVE; | ||
207 | xp.share_id[0] = cpu_to_le32(wp->share_id[0]); | ||
208 | xp.share_id[1] = cpu_to_le32(wp->share_id[1]); | ||
209 | xp.share_id[2] = cpu_to_le32(wp->share_id[2]); | ||
210 | xp.share_id[3] = cpu_to_le32(wp->share_id[3]); | ||
211 | xp.format = cpu_to_le32(wp->format); | ||
212 | xp.size = cpu_to_le32(wp->size); | ||
213 | xp.start = cpu_to_le32(wp->start); | ||
214 | xp.loop_start = cpu_to_le32(wp->loop_start); | ||
215 | xp.loop_end = cpu_to_le32(wp->loop_end); | ||
216 | xp.loop_repeat = cpu_to_le32(wp->loop_repeat); | ||
217 | xp.flags = wp->flags; | ||
218 | xp.sample_rate = cpu_to_le32(wp->sample_rate); | ||
219 | xp.low_frequency = cpu_to_le32(wp->low_frequency); | ||
220 | xp.high_frequency = cpu_to_le32(wp->high_frequency); | ||
221 | xp.root_frequency = cpu_to_le32(wp->root_frequency); | ||
222 | xp.tune = cpu_to_le16(wp->tune); | ||
223 | xp.balance = wp->balance; | ||
224 | memcpy(xp.envelope_rate, wp->envelope_rate, 6); | ||
225 | memcpy(xp.envelope_offset, wp->envelope_offset, 6); | ||
226 | xp.tremolo_sweep = wp->tremolo_sweep; | ||
227 | xp.tremolo_rate = wp->tremolo_rate; | ||
228 | xp.tremolo_depth = wp->tremolo_depth; | ||
229 | xp.vibrato_sweep = wp->vibrato_sweep; | ||
230 | xp.vibrato_rate = wp->vibrato_rate; | ||
231 | xp.vibrato_depth = wp->vibrato_depth; | ||
232 | xp.scale_frequency = cpu_to_le16(wp->scale_frequency); | ||
233 | xp.scale_factor = cpu_to_le16(wp->scale_factor); | ||
234 | if (copy_to_user(*data, &xp, sizeof(xp))) | ||
235 | return -EFAULT; | ||
236 | *data += sizeof(xp); | ||
237 | *len -= sizeof(xp); | ||
238 | real_size = snd_seq_gf1_size(wp->size, wp->format); | ||
239 | if (*len < (long)real_size) | ||
240 | return -ENOMEM; | ||
241 | if (ops->get_sample) { | ||
242 | err = ops->get_sample(ops->private_data, wp, | ||
243 | *data, real_size, atomic); | ||
244 | if (err < 0) | ||
245 | return err; | ||
246 | } | ||
247 | *data += wp->size; | ||
248 | *len -= wp->size; | ||
249 | } | ||
250 | return 0; | ||
251 | } | ||
252 | |||
253 | static int snd_seq_gf1_get(void *private_data, struct snd_seq_kinstr *instr, | ||
254 | char __user *instr_data, long len, int atomic, | ||
255 | int cmd) | ||
256 | { | ||
257 | struct snd_gf1_ops *ops = private_data; | ||
258 | struct gf1_instrument *ip; | ||
259 | struct gf1_xinstrument ix; | ||
260 | |||
261 | if (cmd != SNDRV_SEQ_INSTR_GET_CMD_FULL) | ||
262 | return -EINVAL; | ||
263 | if (len < (long)sizeof(ix)) | ||
264 | return -ENOMEM; | ||
265 | memset(&ix, 0, sizeof(ix)); | ||
266 | ip = (struct gf1_instrument *)KINSTR_DATA(instr); | ||
267 | ix.stype = GF1_STRU_INSTR; | ||
268 | ix.exclusion = cpu_to_le16(ip->exclusion); | ||
269 | ix.exclusion_group = cpu_to_le16(ip->exclusion_group); | ||
270 | ix.effect1 = cpu_to_le16(ip->effect1); | ||
271 | ix.effect1_depth = cpu_to_le16(ip->effect1_depth); | ||
272 | ix.effect2 = ip->effect2; | ||
273 | ix.effect2_depth = ip->effect2_depth; | ||
274 | if (copy_to_user(instr_data, &ix, sizeof(ix))) | ||
275 | return -EFAULT; | ||
276 | instr_data += sizeof(ix); | ||
277 | len -= sizeof(ix); | ||
278 | return snd_seq_gf1_copy_wave_to_stream(ops, | ||
279 | ip, | ||
280 | &instr_data, | ||
281 | &len, | ||
282 | atomic); | ||
283 | } | ||
284 | |||
285 | static int snd_seq_gf1_get_size(void *private_data, struct snd_seq_kinstr *instr, | ||
286 | long *size) | ||
287 | { | ||
288 | long result; | ||
289 | struct gf1_instrument *ip; | ||
290 | struct gf1_wave *wp; | ||
291 | |||
292 | *size = 0; | ||
293 | ip = (struct gf1_instrument *)KINSTR_DATA(instr); | ||
294 | result = sizeof(struct gf1_xinstrument); | ||
295 | for (wp = ip->wave; wp; wp = wp->next) { | ||
296 | result += sizeof(struct gf1_xwave); | ||
297 | result += wp->size; | ||
298 | } | ||
299 | *size = result; | ||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | static int snd_seq_gf1_remove(void *private_data, | ||
304 | struct snd_seq_kinstr *instr, | ||
305 | int atomic) | ||
306 | { | ||
307 | struct snd_gf1_ops *ops = private_data; | ||
308 | struct gf1_instrument *ip; | ||
309 | |||
310 | ip = (struct gf1_instrument *)KINSTR_DATA(instr); | ||
311 | snd_seq_gf1_instr_free(ops, ip, atomic); | ||
312 | return 0; | ||
313 | } | ||
314 | |||
315 | static void snd_seq_gf1_notify(void *private_data, | ||
316 | struct snd_seq_kinstr *instr, | ||
317 | int what) | ||
318 | { | ||
319 | struct snd_gf1_ops *ops = private_data; | ||
320 | |||
321 | if (ops->notify) | ||
322 | ops->notify(ops->private_data, instr, what); | ||
323 | } | ||
324 | |||
325 | int snd_seq_gf1_init(struct snd_gf1_ops *ops, | ||
326 | void *private_data, | ||
327 | struct snd_seq_kinstr_ops *next) | ||
328 | { | ||
329 | memset(ops, 0, sizeof(*ops)); | ||
330 | ops->private_data = private_data; | ||
331 | ops->kops.private_data = ops; | ||
332 | ops->kops.add_len = sizeof(struct gf1_instrument); | ||
333 | ops->kops.instr_type = SNDRV_SEQ_INSTR_ID_GUS_PATCH; | ||
334 | ops->kops.put = snd_seq_gf1_put; | ||
335 | ops->kops.get = snd_seq_gf1_get; | ||
336 | ops->kops.get_size = snd_seq_gf1_get_size; | ||
337 | ops->kops.remove = snd_seq_gf1_remove; | ||
338 | ops->kops.notify = snd_seq_gf1_notify; | ||
339 | ops->kops.next = next; | ||
340 | return 0; | ||
341 | } | ||
342 | |||
343 | /* | ||
344 | * Init part | ||
345 | */ | ||
346 | |||
347 | static int __init alsa_ainstr_gf1_init(void) | ||
348 | { | ||
349 | return 0; | ||
350 | } | ||
351 | |||
352 | static void __exit alsa_ainstr_gf1_exit(void) | ||
353 | { | ||
354 | } | ||
355 | |||
356 | module_init(alsa_ainstr_gf1_init) | ||
357 | module_exit(alsa_ainstr_gf1_exit) | ||
358 | |||
359 | EXPORT_SYMBOL(snd_seq_gf1_init); | ||
diff --git a/sound/core/seq/instr/ainstr_iw.c b/sound/core/seq/instr/ainstr_iw.c deleted file mode 100644 index 6c40eb73fa9f..000000000000 --- a/sound/core/seq/instr/ainstr_iw.c +++ /dev/null | |||
@@ -1,623 +0,0 @@ | |||
1 | /* | ||
2 | * IWFFFF - AMD InterWave (tm) - Instrument routines | ||
3 | * Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | #include <sound/driver.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <sound/core.h> | ||
25 | #include <sound/ainstr_iw.h> | ||
26 | #include <sound/initval.h> | ||
27 | #include <asm/uaccess.h> | ||
28 | |||
29 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); | ||
30 | MODULE_DESCRIPTION("Advanced Linux Sound Architecture IWFFFF support."); | ||
31 | MODULE_LICENSE("GPL"); | ||
32 | |||
33 | static unsigned int snd_seq_iwffff_size(unsigned int size, unsigned int format) | ||
34 | { | ||
35 | unsigned int result = size; | ||
36 | |||
37 | if (format & IWFFFF_WAVE_16BIT) | ||
38 | result <<= 1; | ||
39 | if (format & IWFFFF_WAVE_STEREO) | ||
40 | result <<= 1; | ||
41 | return result; | ||
42 | } | ||
43 | |||
44 | static void snd_seq_iwffff_copy_lfo_from_stream(struct iwffff_lfo *fp, | ||
45 | struct iwffff_xlfo *fx) | ||
46 | { | ||
47 | fp->freq = le16_to_cpu(fx->freq); | ||
48 | fp->depth = le16_to_cpu(fx->depth); | ||
49 | fp->sweep = le16_to_cpu(fx->sweep); | ||
50 | fp->shape = fx->shape; | ||
51 | fp->delay = fx->delay; | ||
52 | } | ||
53 | |||
54 | static int snd_seq_iwffff_copy_env_from_stream(__u32 req_stype, | ||
55 | struct iwffff_layer *lp, | ||
56 | struct iwffff_env *ep, | ||
57 | struct iwffff_xenv *ex, | ||
58 | char __user **data, | ||
59 | long *len, | ||
60 | gfp_t gfp_mask) | ||
61 | { | ||
62 | __u32 stype; | ||
63 | struct iwffff_env_record *rp, *rp_last; | ||
64 | struct iwffff_xenv_record rx; | ||
65 | struct iwffff_env_point *pp; | ||
66 | struct iwffff_xenv_point px; | ||
67 | int points_size, idx; | ||
68 | |||
69 | ep->flags = ex->flags; | ||
70 | ep->mode = ex->mode; | ||
71 | ep->index = ex->index; | ||
72 | rp_last = NULL; | ||
73 | while (1) { | ||
74 | if (*len < (long)sizeof(__u32)) | ||
75 | return -EINVAL; | ||
76 | if (copy_from_user(&stype, *data, sizeof(stype))) | ||
77 | return -EFAULT; | ||
78 | if (stype == IWFFFF_STRU_WAVE) | ||
79 | return 0; | ||
80 | if (req_stype != stype) { | ||
81 | if (stype == IWFFFF_STRU_ENV_RECP || | ||
82 | stype == IWFFFF_STRU_ENV_RECV) | ||
83 | return 0; | ||
84 | } | ||
85 | if (*len < (long)sizeof(rx)) | ||
86 | return -EINVAL; | ||
87 | if (copy_from_user(&rx, *data, sizeof(rx))) | ||
88 | return -EFAULT; | ||
89 | *data += sizeof(rx); | ||
90 | *len -= sizeof(rx); | ||
91 | points_size = (le16_to_cpu(rx.nattack) + le16_to_cpu(rx.nrelease)) * 2 * sizeof(__u16); | ||
92 | if (points_size > *len) | ||
93 | return -EINVAL; | ||
94 | rp = kzalloc(sizeof(*rp) + points_size, gfp_mask); | ||
95 | if (rp == NULL) | ||
96 | return -ENOMEM; | ||
97 | rp->nattack = le16_to_cpu(rx.nattack); | ||
98 | rp->nrelease = le16_to_cpu(rx.nrelease); | ||
99 | rp->sustain_offset = le16_to_cpu(rx.sustain_offset); | ||
100 | rp->sustain_rate = le16_to_cpu(rx.sustain_rate); | ||
101 | rp->release_rate = le16_to_cpu(rx.release_rate); | ||
102 | rp->hirange = rx.hirange; | ||
103 | pp = (struct iwffff_env_point *)(rp + 1); | ||
104 | for (idx = 0; idx < rp->nattack + rp->nrelease; idx++) { | ||
105 | if (copy_from_user(&px, *data, sizeof(px))) | ||
106 | return -EFAULT; | ||
107 | *data += sizeof(px); | ||
108 | *len -= sizeof(px); | ||
109 | pp->offset = le16_to_cpu(px.offset); | ||
110 | pp->rate = le16_to_cpu(px.rate); | ||
111 | } | ||
112 | if (ep->record == NULL) { | ||
113 | ep->record = rp; | ||
114 | } else { | ||
115 | rp_last = rp; | ||
116 | } | ||
117 | rp_last = rp; | ||
118 | } | ||
119 | return 0; | ||
120 | } | ||
121 | |||
122 | static int snd_seq_iwffff_copy_wave_from_stream(struct snd_iwffff_ops *ops, | ||
123 | struct iwffff_layer *lp, | ||
124 | char __user **data, | ||
125 | long *len, | ||
126 | int atomic) | ||
127 | { | ||
128 | struct iwffff_wave *wp, *prev; | ||
129 | struct iwffff_xwave xp; | ||
130 | int err; | ||
131 | gfp_t gfp_mask; | ||
132 | unsigned int real_size; | ||
133 | |||
134 | gfp_mask = atomic ? GFP_ATOMIC : GFP_KERNEL; | ||
135 | if (*len < (long)sizeof(xp)) | ||
136 | return -EINVAL; | ||
137 | if (copy_from_user(&xp, *data, sizeof(xp))) | ||
138 | return -EFAULT; | ||
139 | *data += sizeof(xp); | ||
140 | *len -= sizeof(xp); | ||
141 | wp = kzalloc(sizeof(*wp), gfp_mask); | ||
142 | if (wp == NULL) | ||
143 | return -ENOMEM; | ||
144 | wp->share_id[0] = le32_to_cpu(xp.share_id[0]); | ||
145 | wp->share_id[1] = le32_to_cpu(xp.share_id[1]); | ||
146 | wp->share_id[2] = le32_to_cpu(xp.share_id[2]); | ||
147 | wp->share_id[3] = le32_to_cpu(xp.share_id[3]); | ||
148 | wp->format = le32_to_cpu(xp.format); | ||
149 | wp->address.memory = le32_to_cpu(xp.offset); | ||
150 | wp->size = le32_to_cpu(xp.size); | ||
151 | wp->start = le32_to_cpu(xp.start); | ||
152 | wp->loop_start = le32_to_cpu(xp.loop_start); | ||
153 | wp->loop_end = le32_to_cpu(xp.loop_end); | ||
154 | wp->loop_repeat = le16_to_cpu(xp.loop_repeat); | ||
155 | wp->sample_ratio = le32_to_cpu(xp.sample_ratio); | ||
156 | wp->attenuation = xp.attenuation; | ||
157 | wp->low_note = xp.low_note; | ||
158 | wp->high_note = xp.high_note; | ||
159 | real_size = snd_seq_iwffff_size(wp->size, wp->format); | ||
160 | if (!(wp->format & IWFFFF_WAVE_ROM)) { | ||
161 | if ((long)real_size > *len) { | ||
162 | kfree(wp); | ||
163 | return -ENOMEM; | ||
164 | } | ||
165 | } | ||
166 | if (ops->put_sample) { | ||
167 | err = ops->put_sample(ops->private_data, wp, | ||
168 | *data, real_size, atomic); | ||
169 | if (err < 0) { | ||
170 | kfree(wp); | ||
171 | return err; | ||
172 | } | ||
173 | } | ||
174 | if (!(wp->format & IWFFFF_WAVE_ROM)) { | ||
175 | *data += real_size; | ||
176 | *len -= real_size; | ||
177 | } | ||
178 | prev = lp->wave; | ||
179 | if (prev) { | ||
180 | while (prev->next) prev = prev->next; | ||
181 | prev->next = wp; | ||
182 | } else { | ||
183 | lp->wave = wp; | ||
184 | } | ||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | static void snd_seq_iwffff_env_free(struct snd_iwffff_ops *ops, | ||
189 | struct iwffff_env *env, | ||
190 | int atomic) | ||
191 | { | ||
192 | struct iwffff_env_record *rec; | ||
193 | |||
194 | while ((rec = env->record) != NULL) { | ||
195 | env->record = rec->next; | ||
196 | kfree(rec); | ||
197 | } | ||
198 | } | ||
199 | |||
200 | static void snd_seq_iwffff_wave_free(struct snd_iwffff_ops *ops, | ||
201 | struct iwffff_wave *wave, | ||
202 | int atomic) | ||
203 | { | ||
204 | if (ops->remove_sample) | ||
205 | ops->remove_sample(ops->private_data, wave, atomic); | ||
206 | kfree(wave); | ||
207 | } | ||
208 | |||
209 | static void snd_seq_iwffff_instr_free(struct snd_iwffff_ops *ops, | ||
210 | struct iwffff_instrument *ip, | ||
211 | int atomic) | ||
212 | { | ||
213 | struct iwffff_layer *layer; | ||
214 | struct iwffff_wave *wave; | ||
215 | |||
216 | while ((layer = ip->layer) != NULL) { | ||
217 | ip->layer = layer->next; | ||
218 | snd_seq_iwffff_env_free(ops, &layer->penv, atomic); | ||
219 | snd_seq_iwffff_env_free(ops, &layer->venv, atomic); | ||
220 | while ((wave = layer->wave) != NULL) { | ||
221 | layer->wave = wave->next; | ||
222 | snd_seq_iwffff_wave_free(ops, wave, atomic); | ||
223 | } | ||
224 | kfree(layer); | ||
225 | } | ||
226 | } | ||
227 | |||
228 | static int snd_seq_iwffff_put(void *private_data, struct snd_seq_kinstr *instr, | ||
229 | char __user *instr_data, long len, int atomic, | ||
230 | int cmd) | ||
231 | { | ||
232 | struct snd_iwffff_ops *ops = private_data; | ||
233 | struct iwffff_instrument *ip; | ||
234 | struct iwffff_xinstrument ix; | ||
235 | struct iwffff_layer *lp, *prev_lp; | ||
236 | struct iwffff_xlayer lx; | ||
237 | int err; | ||
238 | gfp_t gfp_mask; | ||
239 | |||
240 | if (cmd != SNDRV_SEQ_INSTR_PUT_CMD_CREATE) | ||
241 | return -EINVAL; | ||
242 | gfp_mask = atomic ? GFP_ATOMIC : GFP_KERNEL; | ||
243 | /* copy instrument data */ | ||
244 | if (len < (long)sizeof(ix)) | ||
245 | return -EINVAL; | ||
246 | if (copy_from_user(&ix, instr_data, sizeof(ix))) | ||
247 | return -EFAULT; | ||
248 | if (ix.stype != IWFFFF_STRU_INSTR) | ||
249 | return -EINVAL; | ||
250 | instr_data += sizeof(ix); | ||
251 | len -= sizeof(ix); | ||
252 | ip = (struct iwffff_instrument *)KINSTR_DATA(instr); | ||
253 | ip->exclusion = le16_to_cpu(ix.exclusion); | ||
254 | ip->layer_type = le16_to_cpu(ix.layer_type); | ||
255 | ip->exclusion_group = le16_to_cpu(ix.exclusion_group); | ||
256 | ip->effect1 = ix.effect1; | ||
257 | ip->effect1_depth = ix.effect1_depth; | ||
258 | ip->effect2 = ix.effect2; | ||
259 | ip->effect2_depth = ix.effect2_depth; | ||
260 | /* copy layers */ | ||
261 | prev_lp = NULL; | ||
262 | while (len > 0) { | ||
263 | if (len < (long)sizeof(struct iwffff_xlayer)) { | ||
264 | snd_seq_iwffff_instr_free(ops, ip, atomic); | ||
265 | return -EINVAL; | ||
266 | } | ||
267 | if (copy_from_user(&lx, instr_data, sizeof(lx))) | ||
268 | return -EFAULT; | ||
269 | instr_data += sizeof(lx); | ||
270 | len -= sizeof(lx); | ||
271 | if (lx.stype != IWFFFF_STRU_LAYER) { | ||
272 | snd_seq_iwffff_instr_free(ops, ip, atomic); | ||
273 | return -EINVAL; | ||
274 | } | ||
275 | lp = kzalloc(sizeof(*lp), gfp_mask); | ||
276 | if (lp == NULL) { | ||
277 | snd_seq_iwffff_instr_free(ops, ip, atomic); | ||
278 | return -ENOMEM; | ||
279 | } | ||
280 | if (prev_lp) { | ||
281 | prev_lp->next = lp; | ||
282 | } else { | ||
283 | ip->layer = lp; | ||
284 | } | ||
285 | prev_lp = lp; | ||
286 | lp->flags = lx.flags; | ||
287 | lp->velocity_mode = lx.velocity_mode; | ||
288 | lp->layer_event = lx.layer_event; | ||
289 | lp->low_range = lx.low_range; | ||
290 | lp->high_range = lx.high_range; | ||
291 | lp->pan = lx.pan; | ||
292 | lp->pan_freq_scale = lx.pan_freq_scale; | ||
293 | lp->attenuation = lx.attenuation; | ||
294 | snd_seq_iwffff_copy_lfo_from_stream(&lp->tremolo, &lx.tremolo); | ||
295 | snd_seq_iwffff_copy_lfo_from_stream(&lp->vibrato, &lx.vibrato); | ||
296 | lp->freq_scale = le16_to_cpu(lx.freq_scale); | ||
297 | lp->freq_center = lx.freq_center; | ||
298 | err = snd_seq_iwffff_copy_env_from_stream(IWFFFF_STRU_ENV_RECP, | ||
299 | lp, | ||
300 | &lp->penv, &lx.penv, | ||
301 | &instr_data, &len, | ||
302 | gfp_mask); | ||
303 | if (err < 0) { | ||
304 | snd_seq_iwffff_instr_free(ops, ip, atomic); | ||
305 | return err; | ||
306 | } | ||
307 | err = snd_seq_iwffff_copy_env_from_stream(IWFFFF_STRU_ENV_RECV, | ||
308 | lp, | ||
309 | &lp->venv, &lx.venv, | ||
310 | &instr_data, &len, | ||
311 | gfp_mask); | ||
312 | if (err < 0) { | ||
313 | snd_seq_iwffff_instr_free(ops, ip, atomic); | ||
314 | return err; | ||
315 | } | ||
316 | while (len > (long)sizeof(__u32)) { | ||
317 | __u32 stype; | ||
318 | |||
319 | if (copy_from_user(&stype, instr_data, sizeof(stype))) | ||
320 | return -EFAULT; | ||
321 | if (stype != IWFFFF_STRU_WAVE) | ||
322 | break; | ||
323 | err = snd_seq_iwffff_copy_wave_from_stream(ops, | ||
324 | lp, | ||
325 | &instr_data, | ||
326 | &len, | ||
327 | atomic); | ||
328 | if (err < 0) { | ||
329 | snd_seq_iwffff_instr_free(ops, ip, atomic); | ||
330 | return err; | ||
331 | } | ||
332 | } | ||
333 | } | ||
334 | return 0; | ||
335 | } | ||
336 | |||
337 | static void snd_seq_iwffff_copy_lfo_to_stream(struct iwffff_xlfo *fx, | ||
338 | struct iwffff_lfo *fp) | ||
339 | { | ||
340 | fx->freq = cpu_to_le16(fp->freq); | ||
341 | fx->depth = cpu_to_le16(fp->depth); | ||
342 | fx->sweep = cpu_to_le16(fp->sweep); | ||
343 | fp->shape = fx->shape; | ||
344 | fp->delay = fx->delay; | ||
345 | } | ||
346 | |||
347 | static int snd_seq_iwffff_copy_env_to_stream(__u32 req_stype, | ||
348 | struct iwffff_layer *lp, | ||
349 | struct iwffff_xenv *ex, | ||
350 | struct iwffff_env *ep, | ||
351 | char __user **data, | ||
352 | long *len) | ||
353 | { | ||
354 | struct iwffff_env_record *rp; | ||
355 | struct iwffff_xenv_record rx; | ||
356 | struct iwffff_env_point *pp; | ||
357 | struct iwffff_xenv_point px; | ||
358 | int points_size, idx; | ||
359 | |||
360 | ex->flags = ep->flags; | ||
361 | ex->mode = ep->mode; | ||
362 | ex->index = ep->index; | ||
363 | for (rp = ep->record; rp; rp = rp->next) { | ||
364 | if (*len < (long)sizeof(rx)) | ||
365 | return -ENOMEM; | ||
366 | memset(&rx, 0, sizeof(rx)); | ||
367 | rx.stype = req_stype; | ||
368 | rx.nattack = cpu_to_le16(rp->nattack); | ||
369 | rx.nrelease = cpu_to_le16(rp->nrelease); | ||
370 | rx.sustain_offset = cpu_to_le16(rp->sustain_offset); | ||
371 | rx.sustain_rate = cpu_to_le16(rp->sustain_rate); | ||
372 | rx.release_rate = cpu_to_le16(rp->release_rate); | ||
373 | rx.hirange = cpu_to_le16(rp->hirange); | ||
374 | if (copy_to_user(*data, &rx, sizeof(rx))) | ||
375 | return -EFAULT; | ||
376 | *data += sizeof(rx); | ||
377 | *len -= sizeof(rx); | ||
378 | points_size = (rp->nattack + rp->nrelease) * 2 * sizeof(__u16); | ||
379 | if (*len < points_size) | ||
380 | return -ENOMEM; | ||
381 | pp = (struct iwffff_env_point *)(rp + 1); | ||
382 | for (idx = 0; idx < rp->nattack + rp->nrelease; idx++) { | ||
383 | px.offset = cpu_to_le16(pp->offset); | ||
384 | px.rate = cpu_to_le16(pp->rate); | ||
385 | if (copy_to_user(*data, &px, sizeof(px))) | ||
386 | return -EFAULT; | ||
387 | *data += sizeof(px); | ||
388 | *len -= sizeof(px); | ||
389 | } | ||
390 | } | ||
391 | return 0; | ||
392 | } | ||
393 | |||
394 | static int snd_seq_iwffff_copy_wave_to_stream(struct snd_iwffff_ops *ops, | ||
395 | struct iwffff_layer *lp, | ||
396 | char __user **data, | ||
397 | long *len, | ||
398 | int atomic) | ||
399 | { | ||
400 | struct iwffff_wave *wp; | ||
401 | struct iwffff_xwave xp; | ||
402 | int err; | ||
403 | unsigned int real_size; | ||
404 | |||
405 | for (wp = lp->wave; wp; wp = wp->next) { | ||
406 | if (*len < (long)sizeof(xp)) | ||
407 | return -ENOMEM; | ||
408 | memset(&xp, 0, sizeof(xp)); | ||
409 | xp.stype = IWFFFF_STRU_WAVE; | ||
410 | xp.share_id[0] = cpu_to_le32(wp->share_id[0]); | ||
411 | xp.share_id[1] = cpu_to_le32(wp->share_id[1]); | ||
412 | xp.share_id[2] = cpu_to_le32(wp->share_id[2]); | ||
413 | xp.share_id[3] = cpu_to_le32(wp->share_id[3]); | ||
414 | xp.format = cpu_to_le32(wp->format); | ||
415 | if (wp->format & IWFFFF_WAVE_ROM) | ||
416 | xp.offset = cpu_to_le32(wp->address.memory); | ||
417 | xp.size = cpu_to_le32(wp->size); | ||
418 | xp.start = cpu_to_le32(wp->start); | ||
419 | xp.loop_start = cpu_to_le32(wp->loop_start); | ||
420 | xp.loop_end = cpu_to_le32(wp->loop_end); | ||
421 | xp.loop_repeat = cpu_to_le32(wp->loop_repeat); | ||
422 | xp.sample_ratio = cpu_to_le32(wp->sample_ratio); | ||
423 | xp.attenuation = wp->attenuation; | ||
424 | xp.low_note = wp->low_note; | ||
425 | xp.high_note = wp->high_note; | ||
426 | if (copy_to_user(*data, &xp, sizeof(xp))) | ||
427 | return -EFAULT; | ||
428 | *data += sizeof(xp); | ||
429 | *len -= sizeof(xp); | ||
430 | real_size = snd_seq_iwffff_size(wp->size, wp->format); | ||
431 | if (!(wp->format & IWFFFF_WAVE_ROM)) { | ||
432 | if (*len < (long)real_size) | ||
433 | return -ENOMEM; | ||
434 | } | ||
435 | if (ops->get_sample) { | ||
436 | err = ops->get_sample(ops->private_data, wp, | ||
437 | *data, real_size, atomic); | ||
438 | if (err < 0) | ||
439 | return err; | ||
440 | } | ||
441 | if (!(wp->format & IWFFFF_WAVE_ROM)) { | ||
442 | *data += real_size; | ||
443 | *len -= real_size; | ||
444 | } | ||
445 | } | ||
446 | return 0; | ||
447 | } | ||
448 | |||
449 | static int snd_seq_iwffff_get(void *private_data, struct snd_seq_kinstr *instr, | ||
450 | char __user *instr_data, long len, int atomic, int cmd) | ||
451 | { | ||
452 | struct snd_iwffff_ops *ops = private_data; | ||
453 | struct iwffff_instrument *ip; | ||
454 | struct iwffff_xinstrument ix; | ||
455 | struct iwffff_layer *lp; | ||
456 | struct iwffff_xlayer lx; | ||
457 | char __user *layer_instr_data; | ||
458 | int err; | ||
459 | |||
460 | if (cmd != SNDRV_SEQ_INSTR_GET_CMD_FULL) | ||
461 | return -EINVAL; | ||
462 | if (len < (long)sizeof(ix)) | ||
463 | return -ENOMEM; | ||
464 | memset(&ix, 0, sizeof(ix)); | ||
465 | ip = (struct iwffff_instrument *)KINSTR_DATA(instr); | ||
466 | ix.stype = IWFFFF_STRU_INSTR; | ||
467 | ix.exclusion = cpu_to_le16(ip->exclusion); | ||
468 | ix.layer_type = cpu_to_le16(ip->layer_type); | ||
469 | ix.exclusion_group = cpu_to_le16(ip->exclusion_group); | ||
470 | ix.effect1 = cpu_to_le16(ip->effect1); | ||
471 | ix.effect1_depth = cpu_to_le16(ip->effect1_depth); | ||
472 | ix.effect2 = ip->effect2; | ||
473 | ix.effect2_depth = ip->effect2_depth; | ||
474 | if (copy_to_user(instr_data, &ix, sizeof(ix))) | ||
475 | return -EFAULT; | ||
476 | instr_data += sizeof(ix); | ||
477 | len -= sizeof(ix); | ||
478 | for (lp = ip->layer; lp; lp = lp->next) { | ||
479 | if (len < (long)sizeof(lx)) | ||
480 | return -ENOMEM; | ||
481 | memset(&lx, 0, sizeof(lx)); | ||
482 | lx.stype = IWFFFF_STRU_LAYER; | ||
483 | lx.flags = lp->flags; | ||
484 | lx.velocity_mode = lp->velocity_mode; | ||
485 | lx.layer_event = lp->layer_event; | ||
486 | lx.low_range = lp->low_range; | ||
487 | lx.high_range = lp->high_range; | ||
488 | lx.pan = lp->pan; | ||
489 | lx.pan_freq_scale = lp->pan_freq_scale; | ||
490 | lx.attenuation = lp->attenuation; | ||
491 | snd_seq_iwffff_copy_lfo_to_stream(&lx.tremolo, &lp->tremolo); | ||
492 | snd_seq_iwffff_copy_lfo_to_stream(&lx.vibrato, &lp->vibrato); | ||
493 | layer_instr_data = instr_data; | ||
494 | instr_data += sizeof(lx); | ||
495 | len -= sizeof(lx); | ||
496 | err = snd_seq_iwffff_copy_env_to_stream(IWFFFF_STRU_ENV_RECP, | ||
497 | lp, | ||
498 | &lx.penv, &lp->penv, | ||
499 | &instr_data, &len); | ||
500 | if (err < 0) | ||
501 | return err; | ||
502 | err = snd_seq_iwffff_copy_env_to_stream(IWFFFF_STRU_ENV_RECV, | ||
503 | lp, | ||
504 | &lx.venv, &lp->venv, | ||
505 | &instr_data, &len); | ||
506 | if (err < 0) | ||
507 | return err; | ||
508 | /* layer structure updating is now finished */ | ||
509 | if (copy_to_user(layer_instr_data, &lx, sizeof(lx))) | ||
510 | return -EFAULT; | ||
511 | err = snd_seq_iwffff_copy_wave_to_stream(ops, | ||
512 | lp, | ||
513 | &instr_data, | ||
514 | &len, | ||
515 | atomic); | ||
516 | if (err < 0) | ||
517 | return err; | ||
518 | } | ||
519 | return 0; | ||
520 | } | ||
521 | |||
522 | static long snd_seq_iwffff_env_size_in_stream(struct iwffff_env *ep) | ||
523 | { | ||
524 | long result = 0; | ||
525 | struct iwffff_env_record *rp; | ||
526 | |||
527 | for (rp = ep->record; rp; rp = rp->next) { | ||
528 | result += sizeof(struct iwffff_xenv_record); | ||
529 | result += (rp->nattack + rp->nrelease) * 2 * sizeof(__u16); | ||
530 | } | ||
531 | return 0; | ||
532 | } | ||
533 | |||
534 | static long snd_seq_iwffff_wave_size_in_stream(struct iwffff_layer *lp) | ||
535 | { | ||
536 | long result = 0; | ||
537 | struct iwffff_wave *wp; | ||
538 | |||
539 | for (wp = lp->wave; wp; wp = wp->next) { | ||
540 | result += sizeof(struct iwffff_xwave); | ||
541 | if (!(wp->format & IWFFFF_WAVE_ROM)) | ||
542 | result += wp->size; | ||
543 | } | ||
544 | return result; | ||
545 | } | ||
546 | |||
547 | static int snd_seq_iwffff_get_size(void *private_data, struct snd_seq_kinstr *instr, | ||
548 | long *size) | ||
549 | { | ||
550 | long result; | ||
551 | struct iwffff_instrument *ip; | ||
552 | struct iwffff_layer *lp; | ||
553 | |||
554 | *size = 0; | ||
555 | ip = (struct iwffff_instrument *)KINSTR_DATA(instr); | ||
556 | result = sizeof(struct iwffff_xinstrument); | ||
557 | for (lp = ip->layer; lp; lp = lp->next) { | ||
558 | result += sizeof(struct iwffff_xlayer); | ||
559 | result += snd_seq_iwffff_env_size_in_stream(&lp->penv); | ||
560 | result += snd_seq_iwffff_env_size_in_stream(&lp->venv); | ||
561 | result += snd_seq_iwffff_wave_size_in_stream(lp); | ||
562 | } | ||
563 | *size = result; | ||
564 | return 0; | ||
565 | } | ||
566 | |||
567 | static int snd_seq_iwffff_remove(void *private_data, | ||
568 | struct snd_seq_kinstr *instr, | ||
569 | int atomic) | ||
570 | { | ||
571 | struct snd_iwffff_ops *ops = private_data; | ||
572 | struct iwffff_instrument *ip; | ||
573 | |||
574 | ip = (struct iwffff_instrument *)KINSTR_DATA(instr); | ||
575 | snd_seq_iwffff_instr_free(ops, ip, atomic); | ||
576 | return 0; | ||
577 | } | ||
578 | |||
579 | static void snd_seq_iwffff_notify(void *private_data, | ||
580 | struct snd_seq_kinstr *instr, | ||
581 | int what) | ||
582 | { | ||
583 | struct snd_iwffff_ops *ops = private_data; | ||
584 | |||
585 | if (ops->notify) | ||
586 | ops->notify(ops->private_data, instr, what); | ||
587 | } | ||
588 | |||
589 | int snd_seq_iwffff_init(struct snd_iwffff_ops *ops, | ||
590 | void *private_data, | ||
591 | struct snd_seq_kinstr_ops *next) | ||
592 | { | ||
593 | memset(ops, 0, sizeof(*ops)); | ||
594 | ops->private_data = private_data; | ||
595 | ops->kops.private_data = ops; | ||
596 | ops->kops.add_len = sizeof(struct iwffff_instrument); | ||
597 | ops->kops.instr_type = SNDRV_SEQ_INSTR_ID_INTERWAVE; | ||
598 | ops->kops.put = snd_seq_iwffff_put; | ||
599 | ops->kops.get = snd_seq_iwffff_get; | ||
600 | ops->kops.get_size = snd_seq_iwffff_get_size; | ||
601 | ops->kops.remove = snd_seq_iwffff_remove; | ||
602 | ops->kops.notify = snd_seq_iwffff_notify; | ||
603 | ops->kops.next = next; | ||
604 | return 0; | ||
605 | } | ||
606 | |||
607 | /* | ||
608 | * Init part | ||
609 | */ | ||
610 | |||
611 | static int __init alsa_ainstr_iw_init(void) | ||
612 | { | ||
613 | return 0; | ||
614 | } | ||
615 | |||
616 | static void __exit alsa_ainstr_iw_exit(void) | ||
617 | { | ||
618 | } | ||
619 | |||
620 | module_init(alsa_ainstr_iw_init) | ||
621 | module_exit(alsa_ainstr_iw_exit) | ||
622 | |||
623 | EXPORT_SYMBOL(snd_seq_iwffff_init); | ||
diff --git a/sound/core/seq/instr/ainstr_simple.c b/sound/core/seq/instr/ainstr_simple.c deleted file mode 100644 index 78f68bee24fe..000000000000 --- a/sound/core/seq/instr/ainstr_simple.c +++ /dev/null | |||
@@ -1,215 +0,0 @@ | |||
1 | /* | ||
2 | * Simple (MOD player) - Instrument routines | ||
3 | * Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | #include <sound/driver.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <sound/core.h> | ||
25 | #include <sound/ainstr_simple.h> | ||
26 | #include <sound/initval.h> | ||
27 | #include <asm/uaccess.h> | ||
28 | |||
29 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); | ||
30 | MODULE_DESCRIPTION("Advanced Linux Sound Architecture Simple Instrument support."); | ||
31 | MODULE_LICENSE("GPL"); | ||
32 | |||
33 | static unsigned int snd_seq_simple_size(unsigned int size, unsigned int format) | ||
34 | { | ||
35 | unsigned int result = size; | ||
36 | |||
37 | if (format & SIMPLE_WAVE_16BIT) | ||
38 | result <<= 1; | ||
39 | if (format & SIMPLE_WAVE_STEREO) | ||
40 | result <<= 1; | ||
41 | return result; | ||
42 | } | ||
43 | |||
44 | static void snd_seq_simple_instr_free(struct snd_simple_ops *ops, | ||
45 | struct simple_instrument *ip, | ||
46 | int atomic) | ||
47 | { | ||
48 | if (ops->remove_sample) | ||
49 | ops->remove_sample(ops->private_data, ip, atomic); | ||
50 | } | ||
51 | |||
52 | static int snd_seq_simple_put(void *private_data, struct snd_seq_kinstr *instr, | ||
53 | char __user *instr_data, long len, | ||
54 | int atomic, int cmd) | ||
55 | { | ||
56 | struct snd_simple_ops *ops = private_data; | ||
57 | struct simple_instrument *ip; | ||
58 | struct simple_xinstrument ix; | ||
59 | int err; | ||
60 | gfp_t gfp_mask; | ||
61 | unsigned int real_size; | ||
62 | |||
63 | if (cmd != SNDRV_SEQ_INSTR_PUT_CMD_CREATE) | ||
64 | return -EINVAL; | ||
65 | gfp_mask = atomic ? GFP_ATOMIC : GFP_KERNEL; | ||
66 | /* copy instrument data */ | ||
67 | if (len < (long)sizeof(ix)) | ||
68 | return -EINVAL; | ||
69 | if (copy_from_user(&ix, instr_data, sizeof(ix))) | ||
70 | return -EFAULT; | ||
71 | if (ix.stype != SIMPLE_STRU_INSTR) | ||
72 | return -EINVAL; | ||
73 | instr_data += sizeof(ix); | ||
74 | len -= sizeof(ix); | ||
75 | ip = (struct simple_instrument *)KINSTR_DATA(instr); | ||
76 | ip->share_id[0] = le32_to_cpu(ix.share_id[0]); | ||
77 | ip->share_id[1] = le32_to_cpu(ix.share_id[1]); | ||
78 | ip->share_id[2] = le32_to_cpu(ix.share_id[2]); | ||
79 | ip->share_id[3] = le32_to_cpu(ix.share_id[3]); | ||
80 | ip->format = le32_to_cpu(ix.format); | ||
81 | ip->size = le32_to_cpu(ix.size); | ||
82 | ip->start = le32_to_cpu(ix.start); | ||
83 | ip->loop_start = le32_to_cpu(ix.loop_start); | ||
84 | ip->loop_end = le32_to_cpu(ix.loop_end); | ||
85 | ip->loop_repeat = le16_to_cpu(ix.loop_repeat); | ||
86 | ip->effect1 = ix.effect1; | ||
87 | ip->effect1_depth = ix.effect1_depth; | ||
88 | ip->effect2 = ix.effect2; | ||
89 | ip->effect2_depth = ix.effect2_depth; | ||
90 | real_size = snd_seq_simple_size(ip->size, ip->format); | ||
91 | if (len < (long)real_size) | ||
92 | return -EINVAL; | ||
93 | if (ops->put_sample) { | ||
94 | err = ops->put_sample(ops->private_data, ip, | ||
95 | instr_data, real_size, atomic); | ||
96 | if (err < 0) | ||
97 | return err; | ||
98 | } | ||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | static int snd_seq_simple_get(void *private_data, struct snd_seq_kinstr *instr, | ||
103 | char __user *instr_data, long len, | ||
104 | int atomic, int cmd) | ||
105 | { | ||
106 | struct snd_simple_ops *ops = private_data; | ||
107 | struct simple_instrument *ip; | ||
108 | struct simple_xinstrument ix; | ||
109 | int err; | ||
110 | unsigned int real_size; | ||
111 | |||
112 | if (cmd != SNDRV_SEQ_INSTR_GET_CMD_FULL) | ||
113 | return -EINVAL; | ||
114 | if (len < (long)sizeof(ix)) | ||
115 | return -ENOMEM; | ||
116 | memset(&ix, 0, sizeof(ix)); | ||
117 | ip = (struct simple_instrument *)KINSTR_DATA(instr); | ||
118 | ix.stype = SIMPLE_STRU_INSTR; | ||
119 | ix.share_id[0] = cpu_to_le32(ip->share_id[0]); | ||
120 | ix.share_id[1] = cpu_to_le32(ip->share_id[1]); | ||
121 | ix.share_id[2] = cpu_to_le32(ip->share_id[2]); | ||
122 | ix.share_id[3] = cpu_to_le32(ip->share_id[3]); | ||
123 | ix.format = cpu_to_le32(ip->format); | ||
124 | ix.size = cpu_to_le32(ip->size); | ||
125 | ix.start = cpu_to_le32(ip->start); | ||
126 | ix.loop_start = cpu_to_le32(ip->loop_start); | ||
127 | ix.loop_end = cpu_to_le32(ip->loop_end); | ||
128 | ix.loop_repeat = cpu_to_le32(ip->loop_repeat); | ||
129 | ix.effect1 = cpu_to_le16(ip->effect1); | ||
130 | ix.effect1_depth = cpu_to_le16(ip->effect1_depth); | ||
131 | ix.effect2 = ip->effect2; | ||
132 | ix.effect2_depth = ip->effect2_depth; | ||
133 | if (copy_to_user(instr_data, &ix, sizeof(ix))) | ||
134 | return -EFAULT; | ||
135 | instr_data += sizeof(ix); | ||
136 | len -= sizeof(ix); | ||
137 | real_size = snd_seq_simple_size(ip->size, ip->format); | ||
138 | if (len < (long)real_size) | ||
139 | return -ENOMEM; | ||
140 | if (ops->get_sample) { | ||
141 | err = ops->get_sample(ops->private_data, ip, | ||
142 | instr_data, real_size, atomic); | ||
143 | if (err < 0) | ||
144 | return err; | ||
145 | } | ||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | static int snd_seq_simple_get_size(void *private_data, struct snd_seq_kinstr *instr, | ||
150 | long *size) | ||
151 | { | ||
152 | struct simple_instrument *ip; | ||
153 | |||
154 | ip = (struct simple_instrument *)KINSTR_DATA(instr); | ||
155 | *size = sizeof(struct simple_xinstrument) + snd_seq_simple_size(ip->size, ip->format); | ||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | static int snd_seq_simple_remove(void *private_data, | ||
160 | struct snd_seq_kinstr *instr, | ||
161 | int atomic) | ||
162 | { | ||
163 | struct snd_simple_ops *ops = private_data; | ||
164 | struct simple_instrument *ip; | ||
165 | |||
166 | ip = (struct simple_instrument *)KINSTR_DATA(instr); | ||
167 | snd_seq_simple_instr_free(ops, ip, atomic); | ||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | static void snd_seq_simple_notify(void *private_data, | ||
172 | struct snd_seq_kinstr *instr, | ||
173 | int what) | ||
174 | { | ||
175 | struct snd_simple_ops *ops = private_data; | ||
176 | |||
177 | if (ops->notify) | ||
178 | ops->notify(ops->private_data, instr, what); | ||
179 | } | ||
180 | |||
181 | int snd_seq_simple_init(struct snd_simple_ops *ops, | ||
182 | void *private_data, | ||
183 | struct snd_seq_kinstr_ops *next) | ||
184 | { | ||
185 | memset(ops, 0, sizeof(*ops)); | ||
186 | ops->private_data = private_data; | ||
187 | ops->kops.private_data = ops; | ||
188 | ops->kops.add_len = sizeof(struct simple_instrument); | ||
189 | ops->kops.instr_type = SNDRV_SEQ_INSTR_ID_SIMPLE; | ||
190 | ops->kops.put = snd_seq_simple_put; | ||
191 | ops->kops.get = snd_seq_simple_get; | ||
192 | ops->kops.get_size = snd_seq_simple_get_size; | ||
193 | ops->kops.remove = snd_seq_simple_remove; | ||
194 | ops->kops.notify = snd_seq_simple_notify; | ||
195 | ops->kops.next = next; | ||
196 | return 0; | ||
197 | } | ||
198 | |||
199 | /* | ||
200 | * Init part | ||
201 | */ | ||
202 | |||
203 | static int __init alsa_ainstr_simple_init(void) | ||
204 | { | ||
205 | return 0; | ||
206 | } | ||
207 | |||
208 | static void __exit alsa_ainstr_simple_exit(void) | ||
209 | { | ||
210 | } | ||
211 | |||
212 | module_init(alsa_ainstr_simple_init) | ||
213 | module_exit(alsa_ainstr_simple_exit) | ||
214 | |||
215 | EXPORT_SYMBOL(snd_seq_simple_init); | ||
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 2e3fa25ab19f..69421ca68167 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c | |||
@@ -966,8 +966,7 @@ static int check_event_type_and_length(struct snd_seq_event *ev) | |||
966 | return -EINVAL; | 966 | return -EINVAL; |
967 | break; | 967 | break; |
968 | case SNDRV_SEQ_EVENT_LENGTH_VARUSR: | 968 | case SNDRV_SEQ_EVENT_LENGTH_VARUSR: |
969 | if (! snd_seq_ev_is_instr_type(ev) || | 969 | if (! snd_seq_ev_is_direct(ev)) |
970 | ! snd_seq_ev_is_direct(ev)) | ||
971 | return -EINVAL; | 970 | return -EINVAL; |
972 | break; | 971 | break; |
973 | } | 972 | } |
diff --git a/sound/core/seq/seq_instr.c b/sound/core/seq/seq_instr.c deleted file mode 100644 index 9a6fd56c9109..000000000000 --- a/sound/core/seq/seq_instr.c +++ /dev/null | |||
@@ -1,655 +0,0 @@ | |||
1 | /* | ||
2 | * Generic Instrument routines for ALSA sequencer | ||
3 | * Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | #include <sound/driver.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <sound/core.h> | ||
25 | #include "seq_clientmgr.h" | ||
26 | #include <sound/seq_instr.h> | ||
27 | #include <sound/initval.h> | ||
28 | |||
29 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); | ||
30 | MODULE_DESCRIPTION("Advanced Linux Sound Architecture sequencer instrument library."); | ||
31 | MODULE_LICENSE("GPL"); | ||
32 | |||
33 | |||
34 | static void snd_instr_lock_ops(struct snd_seq_kinstr_list *list) | ||
35 | { | ||
36 | if (!(list->flags & SNDRV_SEQ_INSTR_FLG_DIRECT)) { | ||
37 | spin_lock_irqsave(&list->ops_lock, list->ops_flags); | ||
38 | } else { | ||
39 | mutex_lock(&list->ops_mutex); | ||
40 | } | ||
41 | } | ||
42 | |||
43 | static void snd_instr_unlock_ops(struct snd_seq_kinstr_list *list) | ||
44 | { | ||
45 | if (!(list->flags & SNDRV_SEQ_INSTR_FLG_DIRECT)) { | ||
46 | spin_unlock_irqrestore(&list->ops_lock, list->ops_flags); | ||
47 | } else { | ||
48 | mutex_unlock(&list->ops_mutex); | ||
49 | } | ||
50 | } | ||
51 | |||
52 | static struct snd_seq_kinstr *snd_seq_instr_new(int add_len, int atomic) | ||
53 | { | ||
54 | struct snd_seq_kinstr *instr; | ||
55 | |||
56 | instr = kzalloc(sizeof(struct snd_seq_kinstr) + add_len, atomic ? GFP_ATOMIC : GFP_KERNEL); | ||
57 | if (instr == NULL) | ||
58 | return NULL; | ||
59 | instr->add_len = add_len; | ||
60 | return instr; | ||
61 | } | ||
62 | |||
63 | static int snd_seq_instr_free(struct snd_seq_kinstr *instr, int atomic) | ||
64 | { | ||
65 | int result = 0; | ||
66 | |||
67 | if (instr == NULL) | ||
68 | return -EINVAL; | ||
69 | if (instr->ops && instr->ops->remove) | ||
70 | result = instr->ops->remove(instr->ops->private_data, instr, 1); | ||
71 | if (!result) | ||
72 | kfree(instr); | ||
73 | return result; | ||
74 | } | ||
75 | |||
76 | struct snd_seq_kinstr_list *snd_seq_instr_list_new(void) | ||
77 | { | ||
78 | struct snd_seq_kinstr_list *list; | ||
79 | |||
80 | list = kzalloc(sizeof(struct snd_seq_kinstr_list), GFP_KERNEL); | ||
81 | if (list == NULL) | ||
82 | return NULL; | ||
83 | spin_lock_init(&list->lock); | ||
84 | spin_lock_init(&list->ops_lock); | ||
85 | mutex_init(&list->ops_mutex); | ||
86 | list->owner = -1; | ||
87 | return list; | ||
88 | } | ||
89 | |||
90 | void snd_seq_instr_list_free(struct snd_seq_kinstr_list **list_ptr) | ||
91 | { | ||
92 | struct snd_seq_kinstr_list *list; | ||
93 | struct snd_seq_kinstr *instr; | ||
94 | struct snd_seq_kcluster *cluster; | ||
95 | int idx; | ||
96 | unsigned long flags; | ||
97 | |||
98 | if (list_ptr == NULL) | ||
99 | return; | ||
100 | list = *list_ptr; | ||
101 | *list_ptr = NULL; | ||
102 | if (list == NULL) | ||
103 | return; | ||
104 | |||
105 | for (idx = 0; idx < SNDRV_SEQ_INSTR_HASH_SIZE; idx++) { | ||
106 | while ((instr = list->hash[idx]) != NULL) { | ||
107 | list->hash[idx] = instr->next; | ||
108 | list->count--; | ||
109 | spin_lock_irqsave(&list->lock, flags); | ||
110 | while (instr->use) { | ||
111 | spin_unlock_irqrestore(&list->lock, flags); | ||
112 | schedule_timeout_uninterruptible(1); | ||
113 | spin_lock_irqsave(&list->lock, flags); | ||
114 | } | ||
115 | spin_unlock_irqrestore(&list->lock, flags); | ||
116 | if (snd_seq_instr_free(instr, 0)<0) | ||
117 | snd_printk(KERN_WARNING "instrument free problem\n"); | ||
118 | } | ||
119 | while ((cluster = list->chash[idx]) != NULL) { | ||
120 | list->chash[idx] = cluster->next; | ||
121 | list->ccount--; | ||
122 | kfree(cluster); | ||
123 | } | ||
124 | } | ||
125 | kfree(list); | ||
126 | } | ||
127 | |||
128 | static int instr_free_compare(struct snd_seq_kinstr *instr, | ||
129 | struct snd_seq_instr_header *ifree, | ||
130 | unsigned int client) | ||
131 | { | ||
132 | switch (ifree->cmd) { | ||
133 | case SNDRV_SEQ_INSTR_FREE_CMD_ALL: | ||
134 | /* all, except private for other clients */ | ||
135 | if ((instr->instr.std & 0xff000000) == 0) | ||
136 | return 0; | ||
137 | if (((instr->instr.std >> 24) & 0xff) == client) | ||
138 | return 0; | ||
139 | return 1; | ||
140 | case SNDRV_SEQ_INSTR_FREE_CMD_PRIVATE: | ||
141 | /* all my private instruments */ | ||
142 | if ((instr->instr.std & 0xff000000) == 0) | ||
143 | return 1; | ||
144 | if (((instr->instr.std >> 24) & 0xff) == client) | ||
145 | return 0; | ||
146 | return 1; | ||
147 | case SNDRV_SEQ_INSTR_FREE_CMD_CLUSTER: | ||
148 | /* all my private instruments */ | ||
149 | if ((instr->instr.std & 0xff000000) == 0) { | ||
150 | if (instr->instr.cluster == ifree->id.cluster) | ||
151 | return 0; | ||
152 | return 1; | ||
153 | } | ||
154 | if (((instr->instr.std >> 24) & 0xff) == client) { | ||
155 | if (instr->instr.cluster == ifree->id.cluster) | ||
156 | return 0; | ||
157 | } | ||
158 | return 1; | ||
159 | } | ||
160 | return 1; | ||
161 | } | ||
162 | |||
163 | int snd_seq_instr_list_free_cond(struct snd_seq_kinstr_list *list, | ||
164 | struct snd_seq_instr_header *ifree, | ||
165 | int client, | ||
166 | int atomic) | ||
167 | { | ||
168 | struct snd_seq_kinstr *instr, *prev, *next, *flist; | ||
169 | int idx; | ||
170 | unsigned long flags; | ||
171 | |||
172 | snd_instr_lock_ops(list); | ||
173 | for (idx = 0; idx < SNDRV_SEQ_INSTR_HASH_SIZE; idx++) { | ||
174 | spin_lock_irqsave(&list->lock, flags); | ||
175 | instr = list->hash[idx]; | ||
176 | prev = flist = NULL; | ||
177 | while (instr) { | ||
178 | while (instr && instr_free_compare(instr, ifree, (unsigned int)client)) { | ||
179 | prev = instr; | ||
180 | instr = instr->next; | ||
181 | } | ||
182 | if (instr == NULL) | ||
183 | continue; | ||
184 | if (instr->ops && instr->ops->notify) | ||
185 | instr->ops->notify(instr->ops->private_data, instr, SNDRV_SEQ_INSTR_NOTIFY_REMOVE); | ||
186 | next = instr->next; | ||
187 | if (prev == NULL) { | ||
188 | list->hash[idx] = next; | ||
189 | } else { | ||
190 | prev->next = next; | ||
191 | } | ||
192 | list->count--; | ||
193 | instr->next = flist; | ||
194 | flist = instr; | ||
195 | instr = next; | ||
196 | } | ||
197 | spin_unlock_irqrestore(&list->lock, flags); | ||
198 | while (flist) { | ||
199 | instr = flist; | ||
200 | flist = instr->next; | ||
201 | while (instr->use) { | ||
202 | schedule_timeout_uninterruptible(1); | ||
203 | barrier(); | ||
204 | } | ||
205 | if (snd_seq_instr_free(instr, atomic)<0) | ||
206 | snd_printk(KERN_WARNING "instrument free problem\n"); | ||
207 | instr = next; | ||
208 | } | ||
209 | } | ||
210 | snd_instr_unlock_ops(list); | ||
211 | return 0; | ||
212 | } | ||
213 | |||
214 | static int compute_hash_instr_key(struct snd_seq_instr *instr) | ||
215 | { | ||
216 | int result; | ||
217 | |||
218 | result = instr->bank | (instr->prg << 16); | ||
219 | result += result >> 24; | ||
220 | result += result >> 16; | ||
221 | result += result >> 8; | ||
222 | return result & (SNDRV_SEQ_INSTR_HASH_SIZE-1); | ||
223 | } | ||
224 | |||
225 | #if 0 | ||
226 | static int compute_hash_cluster_key(snd_seq_instr_cluster_t cluster) | ||
227 | { | ||
228 | int result; | ||
229 | |||
230 | result = cluster; | ||
231 | result += result >> 24; | ||
232 | result += result >> 16; | ||
233 | result += result >> 8; | ||
234 | return result & (SNDRV_SEQ_INSTR_HASH_SIZE-1); | ||
235 | } | ||
236 | #endif | ||
237 | |||
238 | static int compare_instr(struct snd_seq_instr *i1, struct snd_seq_instr *i2, int exact) | ||
239 | { | ||
240 | if (exact) { | ||
241 | if (i1->cluster != i2->cluster || | ||
242 | i1->bank != i2->bank || | ||
243 | i1->prg != i2->prg) | ||
244 | return 1; | ||
245 | if ((i1->std & 0xff000000) != (i2->std & 0xff000000)) | ||
246 | return 1; | ||
247 | if (!(i1->std & i2->std)) | ||
248 | return 1; | ||
249 | return 0; | ||
250 | } else { | ||
251 | unsigned int client_check; | ||
252 | |||
253 | if (i2->cluster && i1->cluster != i2->cluster) | ||
254 | return 1; | ||
255 | client_check = i2->std & 0xff000000; | ||
256 | if (client_check) { | ||
257 | if ((i1->std & 0xff000000) != client_check) | ||
258 | return 1; | ||
259 | } else { | ||
260 | if ((i1->std & i2->std) != i2->std) | ||
261 | return 1; | ||
262 | } | ||
263 | return i1->bank != i2->bank || i1->prg != i2->prg; | ||
264 | } | ||
265 | } | ||
266 | |||
267 | struct snd_seq_kinstr *snd_seq_instr_find(struct snd_seq_kinstr_list *list, | ||
268 | struct snd_seq_instr *instr, | ||
269 | int exact, | ||
270 | int follow_alias) | ||
271 | { | ||
272 | unsigned long flags; | ||
273 | int depth = 0; | ||
274 | struct snd_seq_kinstr *result; | ||
275 | |||
276 | if (list == NULL || instr == NULL) | ||
277 | return NULL; | ||
278 | spin_lock_irqsave(&list->lock, flags); | ||
279 | __again: | ||
280 | result = list->hash[compute_hash_instr_key(instr)]; | ||
281 | while (result) { | ||
282 | if (!compare_instr(&result->instr, instr, exact)) { | ||
283 | if (follow_alias && (result->type == SNDRV_SEQ_INSTR_ATYPE_ALIAS)) { | ||
284 | instr = (struct snd_seq_instr *)KINSTR_DATA(result); | ||
285 | if (++depth > 10) | ||
286 | goto __not_found; | ||
287 | goto __again; | ||
288 | } | ||
289 | result->use++; | ||
290 | spin_unlock_irqrestore(&list->lock, flags); | ||
291 | return result; | ||
292 | } | ||
293 | result = result->next; | ||
294 | } | ||
295 | __not_found: | ||
296 | spin_unlock_irqrestore(&list->lock, flags); | ||
297 | return NULL; | ||
298 | } | ||
299 | |||
300 | void snd_seq_instr_free_use(struct snd_seq_kinstr_list *list, | ||
301 | struct snd_seq_kinstr *instr) | ||
302 | { | ||
303 | unsigned long flags; | ||
304 | |||
305 | if (list == NULL || instr == NULL) | ||
306 | return; | ||
307 | spin_lock_irqsave(&list->lock, flags); | ||
308 | if (instr->use <= 0) { | ||
309 | snd_printk(KERN_ERR "free_use: fatal!!! use = %i, name = '%s'\n", instr->use, instr->name); | ||
310 | } else { | ||
311 | instr->use--; | ||
312 | } | ||
313 | spin_unlock_irqrestore(&list->lock, flags); | ||
314 | } | ||
315 | |||
316 | static struct snd_seq_kinstr_ops *instr_ops(struct snd_seq_kinstr_ops *ops, | ||
317 | char *instr_type) | ||
318 | { | ||
319 | while (ops) { | ||
320 | if (!strcmp(ops->instr_type, instr_type)) | ||
321 | return ops; | ||
322 | ops = ops->next; | ||
323 | } | ||
324 | return NULL; | ||
325 | } | ||
326 | |||
327 | static int instr_result(struct snd_seq_event *ev, | ||
328 | int type, int result, | ||
329 | int atomic) | ||
330 | { | ||
331 | struct snd_seq_event sev; | ||
332 | |||
333 | memset(&sev, 0, sizeof(sev)); | ||
334 | sev.type = SNDRV_SEQ_EVENT_RESULT; | ||
335 | sev.flags = SNDRV_SEQ_TIME_STAMP_REAL | SNDRV_SEQ_EVENT_LENGTH_FIXED | | ||
336 | SNDRV_SEQ_PRIORITY_NORMAL; | ||
337 | sev.source = ev->dest; | ||
338 | sev.dest = ev->source; | ||
339 | sev.data.result.event = type; | ||
340 | sev.data.result.result = result; | ||
341 | #if 0 | ||
342 | printk("instr result - type = %i, result = %i, queue = %i, source.client:port = %i:%i, dest.client:port = %i:%i\n", | ||
343 | type, result, | ||
344 | sev.queue, | ||
345 | sev.source.client, sev.source.port, | ||
346 | sev.dest.client, sev.dest.port); | ||
347 | #endif | ||
348 | return snd_seq_kernel_client_dispatch(sev.source.client, &sev, atomic, 0); | ||
349 | } | ||
350 | |||
351 | static int instr_begin(struct snd_seq_kinstr_ops *ops, | ||
352 | struct snd_seq_kinstr_list *list, | ||
353 | struct snd_seq_event *ev, | ||
354 | int atomic, int hop) | ||
355 | { | ||
356 | unsigned long flags; | ||
357 | |||
358 | spin_lock_irqsave(&list->lock, flags); | ||
359 | if (list->owner >= 0 && list->owner != ev->source.client) { | ||
360 | spin_unlock_irqrestore(&list->lock, flags); | ||
361 | return instr_result(ev, SNDRV_SEQ_EVENT_INSTR_BEGIN, -EBUSY, atomic); | ||
362 | } | ||
363 | list->owner = ev->source.client; | ||
364 | spin_unlock_irqrestore(&list->lock, flags); | ||
365 | return instr_result(ev, SNDRV_SEQ_EVENT_INSTR_BEGIN, 0, atomic); | ||
366 | } | ||
367 | |||
368 | static int instr_end(struct snd_seq_kinstr_ops *ops, | ||
369 | struct snd_seq_kinstr_list *list, | ||
370 | struct snd_seq_event *ev, | ||
371 | int atomic, int hop) | ||
372 | { | ||
373 | unsigned long flags; | ||
374 | |||
375 | /* TODO: timeout handling */ | ||
376 | spin_lock_irqsave(&list->lock, flags); | ||
377 | if (list->owner == ev->source.client) { | ||
378 | list->owner = -1; | ||
379 | spin_unlock_irqrestore(&list->lock, flags); | ||
380 | return instr_result(ev, SNDRV_SEQ_EVENT_INSTR_END, 0, atomic); | ||
381 | } | ||
382 | spin_unlock_irqrestore(&list->lock, flags); | ||
383 | return instr_result(ev, SNDRV_SEQ_EVENT_INSTR_END, -EINVAL, atomic); | ||
384 | } | ||
385 | |||
386 | static int instr_info(struct snd_seq_kinstr_ops *ops, | ||
387 | struct snd_seq_kinstr_list *list, | ||
388 | struct snd_seq_event *ev, | ||
389 | int atomic, int hop) | ||
390 | { | ||
391 | return -ENXIO; | ||
392 | } | ||
393 | |||
394 | static int instr_format_info(struct snd_seq_kinstr_ops *ops, | ||
395 | struct snd_seq_kinstr_list *list, | ||
396 | struct snd_seq_event *ev, | ||
397 | int atomic, int hop) | ||
398 | { | ||
399 | return -ENXIO; | ||
400 | } | ||
401 | |||
402 | static int instr_reset(struct snd_seq_kinstr_ops *ops, | ||
403 | struct snd_seq_kinstr_list *list, | ||
404 | struct snd_seq_event *ev, | ||
405 | int atomic, int hop) | ||
406 | { | ||
407 | return -ENXIO; | ||
408 | } | ||
409 | |||
410 | static int instr_status(struct snd_seq_kinstr_ops *ops, | ||
411 | struct snd_seq_kinstr_list *list, | ||
412 | struct snd_seq_event *ev, | ||
413 | int atomic, int hop) | ||
414 | { | ||
415 | return -ENXIO; | ||
416 | } | ||
417 | |||
418 | static int instr_put(struct snd_seq_kinstr_ops *ops, | ||
419 | struct snd_seq_kinstr_list *list, | ||
420 | struct snd_seq_event *ev, | ||
421 | int atomic, int hop) | ||
422 | { | ||
423 | unsigned long flags; | ||
424 | struct snd_seq_instr_header put; | ||
425 | struct snd_seq_kinstr *instr; | ||
426 | int result = -EINVAL, len, key; | ||
427 | |||
428 | if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARUSR) | ||
429 | goto __return; | ||
430 | |||
431 | if (ev->data.ext.len < sizeof(struct snd_seq_instr_header)) | ||
432 | goto __return; | ||
433 | if (copy_from_user(&put, (void __user *)ev->data.ext.ptr, | ||
434 | sizeof(struct snd_seq_instr_header))) { | ||
435 | result = -EFAULT; | ||
436 | goto __return; | ||
437 | } | ||
438 | snd_instr_lock_ops(list); | ||
439 | if (put.id.instr.std & 0xff000000) { /* private instrument */ | ||
440 | put.id.instr.std &= 0x00ffffff; | ||
441 | put.id.instr.std |= (unsigned int)ev->source.client << 24; | ||
442 | } | ||
443 | if ((instr = snd_seq_instr_find(list, &put.id.instr, 1, 0))) { | ||
444 | snd_seq_instr_free_use(list, instr); | ||
445 | snd_instr_unlock_ops(list); | ||
446 | result = -EBUSY; | ||
447 | goto __return; | ||
448 | } | ||
449 | ops = instr_ops(ops, put.data.data.format); | ||
450 | if (ops == NULL) { | ||
451 | snd_instr_unlock_ops(list); | ||
452 | goto __return; | ||
453 | } | ||
454 | len = ops->add_len; | ||
455 | if (put.data.type == SNDRV_SEQ_INSTR_ATYPE_ALIAS) | ||
456 | len = sizeof(struct snd_seq_instr); | ||
457 | instr = snd_seq_instr_new(len, atomic); | ||
458 | if (instr == NULL) { | ||
459 | snd_instr_unlock_ops(list); | ||
460 | result = -ENOMEM; | ||
461 | goto __return; | ||
462 | } | ||
463 | instr->ops = ops; | ||
464 | instr->instr = put.id.instr; | ||
465 | strlcpy(instr->name, put.data.name, sizeof(instr->name)); | ||
466 | instr->type = put.data.type; | ||
467 | if (instr->type == SNDRV_SEQ_INSTR_ATYPE_DATA) { | ||
468 | result = ops->put(ops->private_data, | ||
469 | instr, | ||
470 | (void __user *)ev->data.ext.ptr + sizeof(struct snd_seq_instr_header), | ||
471 | ev->data.ext.len - sizeof(struct snd_seq_instr_header), | ||
472 | atomic, | ||
473 | put.cmd); | ||
474 | if (result < 0) { | ||
475 | snd_seq_instr_free(instr, atomic); | ||
476 | snd_instr_unlock_ops(list); | ||
477 | goto __return; | ||
478 | } | ||
479 | } | ||
480 | key = compute_hash_instr_key(&instr->instr); | ||
481 | spin_lock_irqsave(&list->lock, flags); | ||
482 | instr->next = list->hash[key]; | ||
483 | list->hash[key] = instr; | ||
484 | list->count++; | ||
485 | spin_unlock_irqrestore(&list->lock, flags); | ||
486 | snd_instr_unlock_ops(list); | ||
487 | result = 0; | ||
488 | __return: | ||
489 | instr_result(ev, SNDRV_SEQ_EVENT_INSTR_PUT, result, atomic); | ||
490 | return result; | ||
491 | } | ||
492 | |||
493 | static int instr_get(struct snd_seq_kinstr_ops *ops, | ||
494 | struct snd_seq_kinstr_list *list, | ||
495 | struct snd_seq_event *ev, | ||
496 | int atomic, int hop) | ||
497 | { | ||
498 | return -ENXIO; | ||
499 | } | ||
500 | |||
501 | static int instr_free(struct snd_seq_kinstr_ops *ops, | ||
502 | struct snd_seq_kinstr_list *list, | ||
503 | struct snd_seq_event *ev, | ||
504 | int atomic, int hop) | ||
505 | { | ||
506 | struct snd_seq_instr_header ifree; | ||
507 | struct snd_seq_kinstr *instr, *prev; | ||
508 | int result = -EINVAL; | ||
509 | unsigned long flags; | ||
510 | unsigned int hash; | ||
511 | |||
512 | if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARUSR) | ||
513 | goto __return; | ||
514 | |||
515 | if (ev->data.ext.len < sizeof(struct snd_seq_instr_header)) | ||
516 | goto __return; | ||
517 | if (copy_from_user(&ifree, (void __user *)ev->data.ext.ptr, | ||
518 | sizeof(struct snd_seq_instr_header))) { | ||
519 | result = -EFAULT; | ||
520 | goto __return; | ||
521 | } | ||
522 | if (ifree.cmd == SNDRV_SEQ_INSTR_FREE_CMD_ALL || | ||
523 | ifree.cmd == SNDRV_SEQ_INSTR_FREE_CMD_PRIVATE || | ||
524 | ifree.cmd == SNDRV_SEQ_INSTR_FREE_CMD_CLUSTER) { | ||
525 | result = snd_seq_instr_list_free_cond(list, &ifree, ev->dest.client, atomic); | ||
526 | goto __return; | ||
527 | } | ||
528 | if (ifree.cmd == SNDRV_SEQ_INSTR_FREE_CMD_SINGLE) { | ||
529 | if (ifree.id.instr.std & 0xff000000) { | ||
530 | ifree.id.instr.std &= 0x00ffffff; | ||
531 | ifree.id.instr.std |= (unsigned int)ev->source.client << 24; | ||
532 | } | ||
533 | hash = compute_hash_instr_key(&ifree.id.instr); | ||
534 | snd_instr_lock_ops(list); | ||
535 | spin_lock_irqsave(&list->lock, flags); | ||
536 | instr = list->hash[hash]; | ||
537 | prev = NULL; | ||
538 | while (instr) { | ||
539 | if (!compare_instr(&instr->instr, &ifree.id.instr, 1)) | ||
540 | goto __free_single; | ||
541 | prev = instr; | ||
542 | instr = instr->next; | ||
543 | } | ||
544 | result = -ENOENT; | ||
545 | spin_unlock_irqrestore(&list->lock, flags); | ||
546 | snd_instr_unlock_ops(list); | ||
547 | goto __return; | ||
548 | |||
549 | __free_single: | ||
550 | if (prev) { | ||
551 | prev->next = instr->next; | ||
552 | } else { | ||
553 | list->hash[hash] = instr->next; | ||
554 | } | ||
555 | if (instr->ops && instr->ops->notify) | ||
556 | instr->ops->notify(instr->ops->private_data, instr, | ||
557 | SNDRV_SEQ_INSTR_NOTIFY_REMOVE); | ||
558 | while (instr->use) { | ||
559 | spin_unlock_irqrestore(&list->lock, flags); | ||
560 | schedule_timeout_uninterruptible(1); | ||
561 | spin_lock_irqsave(&list->lock, flags); | ||
562 | } | ||
563 | spin_unlock_irqrestore(&list->lock, flags); | ||
564 | result = snd_seq_instr_free(instr, atomic); | ||
565 | snd_instr_unlock_ops(list); | ||
566 | goto __return; | ||
567 | } | ||
568 | |||
569 | __return: | ||
570 | instr_result(ev, SNDRV_SEQ_EVENT_INSTR_FREE, result, atomic); | ||
571 | return result; | ||
572 | } | ||
573 | |||
574 | static int instr_list(struct snd_seq_kinstr_ops *ops, | ||
575 | struct snd_seq_kinstr_list *list, | ||
576 | struct snd_seq_event *ev, | ||
577 | int atomic, int hop) | ||
578 | { | ||
579 | return -ENXIO; | ||
580 | } | ||
581 | |||
582 | static int instr_cluster(struct snd_seq_kinstr_ops *ops, | ||
583 | struct snd_seq_kinstr_list *list, | ||
584 | struct snd_seq_event *ev, | ||
585 | int atomic, int hop) | ||
586 | { | ||
587 | return -ENXIO; | ||
588 | } | ||
589 | |||
590 | int snd_seq_instr_event(struct snd_seq_kinstr_ops *ops, | ||
591 | struct snd_seq_kinstr_list *list, | ||
592 | struct snd_seq_event *ev, | ||
593 | int client, | ||
594 | int atomic, | ||
595 | int hop) | ||
596 | { | ||
597 | int direct = 0; | ||
598 | |||
599 | snd_assert(ops != NULL && list != NULL && ev != NULL, return -EINVAL); | ||
600 | if (snd_seq_ev_is_direct(ev)) { | ||
601 | direct = 1; | ||
602 | switch (ev->type) { | ||
603 | case SNDRV_SEQ_EVENT_INSTR_BEGIN: | ||
604 | return instr_begin(ops, list, ev, atomic, hop); | ||
605 | case SNDRV_SEQ_EVENT_INSTR_END: | ||
606 | return instr_end(ops, list, ev, atomic, hop); | ||
607 | } | ||
608 | } | ||
609 | if ((list->flags & SNDRV_SEQ_INSTR_FLG_DIRECT) && !direct) | ||
610 | return -EINVAL; | ||
611 | switch (ev->type) { | ||
612 | case SNDRV_SEQ_EVENT_INSTR_INFO: | ||
613 | return instr_info(ops, list, ev, atomic, hop); | ||
614 | case SNDRV_SEQ_EVENT_INSTR_FINFO: | ||
615 | return instr_format_info(ops, list, ev, atomic, hop); | ||
616 | case SNDRV_SEQ_EVENT_INSTR_RESET: | ||
617 | return instr_reset(ops, list, ev, atomic, hop); | ||
618 | case SNDRV_SEQ_EVENT_INSTR_STATUS: | ||
619 | return instr_status(ops, list, ev, atomic, hop); | ||
620 | case SNDRV_SEQ_EVENT_INSTR_PUT: | ||
621 | return instr_put(ops, list, ev, atomic, hop); | ||
622 | case SNDRV_SEQ_EVENT_INSTR_GET: | ||
623 | return instr_get(ops, list, ev, atomic, hop); | ||
624 | case SNDRV_SEQ_EVENT_INSTR_FREE: | ||
625 | return instr_free(ops, list, ev, atomic, hop); | ||
626 | case SNDRV_SEQ_EVENT_INSTR_LIST: | ||
627 | return instr_list(ops, list, ev, atomic, hop); | ||
628 | case SNDRV_SEQ_EVENT_INSTR_CLUSTER: | ||
629 | return instr_cluster(ops, list, ev, atomic, hop); | ||
630 | } | ||
631 | return -EINVAL; | ||
632 | } | ||
633 | |||
634 | /* | ||
635 | * Init part | ||
636 | */ | ||
637 | |||
638 | static int __init alsa_seq_instr_init(void) | ||
639 | { | ||
640 | return 0; | ||
641 | } | ||
642 | |||
643 | static void __exit alsa_seq_instr_exit(void) | ||
644 | { | ||
645 | } | ||
646 | |||
647 | module_init(alsa_seq_instr_init) | ||
648 | module_exit(alsa_seq_instr_exit) | ||
649 | |||
650 | EXPORT_SYMBOL(snd_seq_instr_list_new); | ||
651 | EXPORT_SYMBOL(snd_seq_instr_list_free); | ||
652 | EXPORT_SYMBOL(snd_seq_instr_list_free_cond); | ||
653 | EXPORT_SYMBOL(snd_seq_instr_find); | ||
654 | EXPORT_SYMBOL(snd_seq_instr_free_use); | ||
655 | EXPORT_SYMBOL(snd_seq_instr_event); | ||
diff --git a/sound/core/seq/seq_midi_emul.c b/sound/core/seq/seq_midi_emul.c index 17b3e6f13ca3..6645fc544621 100644 --- a/sound/core/seq/seq_midi_emul.c +++ b/sound/core/seq/seq_midi_emul.c | |||
@@ -229,13 +229,6 @@ snd_midi_process_event(struct snd_midi_op *ops, | |||
229 | case SNDRV_SEQ_EVENT_PORT_START: | 229 | case SNDRV_SEQ_EVENT_PORT_START: |
230 | case SNDRV_SEQ_EVENT_PORT_EXIT: | 230 | case SNDRV_SEQ_EVENT_PORT_EXIT: |
231 | case SNDRV_SEQ_EVENT_PORT_CHANGE: | 231 | case SNDRV_SEQ_EVENT_PORT_CHANGE: |
232 | case SNDRV_SEQ_EVENT_SAMPLE: | ||
233 | case SNDRV_SEQ_EVENT_SAMPLE_START: | ||
234 | case SNDRV_SEQ_EVENT_SAMPLE_STOP: | ||
235 | case SNDRV_SEQ_EVENT_SAMPLE_FREQ: | ||
236 | case SNDRV_SEQ_EVENT_SAMPLE_VOLUME: | ||
237 | case SNDRV_SEQ_EVENT_SAMPLE_LOOP: | ||
238 | case SNDRV_SEQ_EVENT_SAMPLE_POSITION: | ||
239 | case SNDRV_SEQ_EVENT_ECHO: | 232 | case SNDRV_SEQ_EVENT_ECHO: |
240 | not_yet: | 233 | not_yet: |
241 | default: | 234 | default: |
diff --git a/sound/isa/gus/Makefile b/sound/isa/gus/Makefile index df3d59f25f5e..6cd4ee03754a 100644 --- a/sound/isa/gus/Makefile +++ b/sound/isa/gus/Makefile | |||
@@ -9,7 +9,6 @@ snd-gus-lib-objs := gus_main.o \ | |||
9 | gus_pcm.o gus_mixer.o \ | 9 | gus_pcm.o gus_mixer.o \ |
10 | gus_uart.o \ | 10 | gus_uart.o \ |
11 | gus_reset.o | 11 | gus_reset.o |
12 | snd-gus-synth-objs := gus_synth.o gus_sample.o gus_simple.o gus_instr.o | ||
13 | 12 | ||
14 | snd-gusclassic-objs := gusclassic.o | 13 | snd-gusclassic-objs := gusclassic.o |
15 | snd-gusextreme-objs := gusextreme.o | 14 | snd-gusextreme-objs := gusextreme.o |
@@ -17,20 +16,9 @@ snd-gusmax-objs := gusmax.o | |||
17 | snd-interwave-objs := interwave.o | 16 | snd-interwave-objs := interwave.o |
18 | snd-interwave-stb-objs := interwave-stb.o | 17 | snd-interwave-stb-objs := interwave-stb.o |
19 | 18 | ||
20 | # | ||
21 | # this function returns: | ||
22 | # "m" - CONFIG_SND_SEQUENCER is m | ||
23 | # <empty string> - CONFIG_SND_SEQUENCER is undefined | ||
24 | # otherwise parameter #1 value | ||
25 | # | ||
26 | sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1))) | ||
27 | |||
28 | # Toplevel Module Dependency | 19 | # Toplevel Module Dependency |
29 | obj-$(CONFIG_SND_GUSCLASSIC) += snd-gusclassic.o snd-gus-lib.o | 20 | obj-$(CONFIG_SND_GUSCLASSIC) += snd-gusclassic.o snd-gus-lib.o |
30 | obj-$(CONFIG_SND_GUSMAX) += snd-gusmax.o snd-gus-lib.o | 21 | obj-$(CONFIG_SND_GUSMAX) += snd-gusmax.o snd-gus-lib.o |
31 | obj-$(CONFIG_SND_GUSEXTREME) += snd-gusextreme.o snd-gus-lib.o | 22 | obj-$(CONFIG_SND_GUSEXTREME) += snd-gusextreme.o snd-gus-lib.o |
32 | obj-$(CONFIG_SND_INTERWAVE) += snd-interwave.o snd-gus-lib.o | 23 | obj-$(CONFIG_SND_INTERWAVE) += snd-interwave.o snd-gus-lib.o |
33 | obj-$(CONFIG_SND_INTERWAVE_STB) += snd-interwave-stb.o snd-gus-lib.o | 24 | obj-$(CONFIG_SND_INTERWAVE_STB) += snd-interwave-stb.o snd-gus-lib.o |
34 | obj-$(call sequencer,$(CONFIG_SND_GUS_SYNTH)) += snd-gus-synth.o | ||
35 | |||
36 | obj-m := $(sort $(obj-m)) | ||
diff --git a/sound/isa/gus/gus_main.c b/sound/isa/gus/gus_main.c index b14d5d6d9a32..e4453e5e5c23 100644 --- a/sound/isa/gus/gus_main.c +++ b/sound/isa/gus/gus_main.c | |||
@@ -104,12 +104,6 @@ static int snd_gus_free(struct snd_gus_card *gus) | |||
104 | { | 104 | { |
105 | if (gus->gf1.res_port2 == NULL) | 105 | if (gus->gf1.res_port2 == NULL) |
106 | goto __hw_end; | 106 | goto __hw_end; |
107 | #if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE)) | ||
108 | if (gus->seq_dev) { | ||
109 | snd_device_free(gus->card, gus->seq_dev); | ||
110 | gus->seq_dev = NULL; | ||
111 | } | ||
112 | #endif | ||
113 | snd_gf1_stop(gus); | 107 | snd_gf1_stop(gus); |
114 | snd_gus_init_dma_irq(gus, 0); | 108 | snd_gus_init_dma_irq(gus, 0); |
115 | __hw_end: | 109 | __hw_end: |
@@ -408,14 +402,6 @@ static int snd_gus_check_version(struct snd_gus_card * gus) | |||
408 | return 0; | 402 | return 0; |
409 | } | 403 | } |
410 | 404 | ||
411 | #if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE)) | ||
412 | static void snd_gus_seq_dev_free(struct snd_seq_device *seq_dev) | ||
413 | { | ||
414 | struct snd_gus_card *gus = seq_dev->private_data; | ||
415 | gus->seq_dev = NULL; | ||
416 | } | ||
417 | #endif | ||
418 | |||
419 | int snd_gus_initialize(struct snd_gus_card *gus) | 405 | int snd_gus_initialize(struct snd_gus_card *gus) |
420 | { | 406 | { |
421 | int err; | 407 | int err; |
@@ -430,15 +416,6 @@ int snd_gus_initialize(struct snd_gus_card *gus) | |||
430 | } | 416 | } |
431 | if ((err = snd_gus_init_dma_irq(gus, 1)) < 0) | 417 | if ((err = snd_gus_init_dma_irq(gus, 1)) < 0) |
432 | return err; | 418 | return err; |
433 | #if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE)) | ||
434 | if (snd_seq_device_new(gus->card, 1, SNDRV_SEQ_DEV_ID_GUS, | ||
435 | sizeof(struct snd_gus_card *), &gus->seq_dev) >= 0) { | ||
436 | strcpy(gus->seq_dev->name, "GUS"); | ||
437 | *(struct snd_gus_card **)SNDRV_SEQ_DEVICE_ARGPTR(gus->seq_dev) = gus; | ||
438 | gus->seq_dev->private_data = gus; | ||
439 | gus->seq_dev->private_free = snd_gus_seq_dev_free; | ||
440 | } | ||
441 | #endif | ||
442 | snd_gf1_start(gus); | 419 | snd_gf1_start(gus); |
443 | gus->initialized = 1; | 420 | gus->initialized = 1; |
444 | return 0; | 421 | return 0; |
diff --git a/sound/isa/gus/gus_sample.c b/sound/isa/gus/gus_sample.c deleted file mode 100644 index cba0829a7106..000000000000 --- a/sound/isa/gus/gus_sample.c +++ /dev/null | |||
@@ -1,165 +0,0 @@ | |||
1 | /* | ||
2 | * Routines for Gravis UltraSound soundcards - Sample support | ||
3 | * Copyright (c) by Jaroslav Kysela <perex@perex.cz> | ||
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 <linux/time.h> | ||
24 | #include <sound/core.h> | ||
25 | #include <sound/gus.h> | ||
26 | |||
27 | /* | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | static void select_instrument(struct snd_gus_card * gus, struct snd_gus_voice * v) | ||
32 | { | ||
33 | struct snd_seq_kinstr *instr; | ||
34 | |||
35 | #if 0 | ||
36 | printk("select instrument: cluster = %li, std = 0x%x, bank = %i, prg = %i\n", | ||
37 | v->instr.cluster, | ||
38 | v->instr.std, | ||
39 | v->instr.bank, | ||
40 | v->instr.prg); | ||
41 | #endif | ||
42 | instr = snd_seq_instr_find(gus->gf1.ilist, &v->instr, 0, 1); | ||
43 | if (instr != NULL) { | ||
44 | if (instr->ops) { | ||
45 | if (!strcmp(instr->ops->instr_type, SNDRV_SEQ_INSTR_ID_SIMPLE)) | ||
46 | snd_gf1_simple_init(v); | ||
47 | } | ||
48 | snd_seq_instr_free_use(gus->gf1.ilist, instr); | ||
49 | } | ||
50 | } | ||
51 | |||
52 | /* | ||
53 | * | ||
54 | */ | ||
55 | |||
56 | static void event_sample(struct snd_seq_event *ev, struct snd_gus_port *p, | ||
57 | struct snd_gus_voice *v) | ||
58 | { | ||
59 | if (v->sample_ops && v->sample_ops->sample_stop) | ||
60 | v->sample_ops->sample_stop(p->gus, v, SAMPLE_STOP_IMMEDIATELY); | ||
61 | v->instr.std = ev->data.sample.param.sample.std; | ||
62 | if (v->instr.std & 0xff000000) { /* private instrument */ | ||
63 | v->instr.std &= 0x00ffffff; | ||
64 | v->instr.std |= (unsigned int)ev->source.client << 24; | ||
65 | } | ||
66 | v->instr.bank = ev->data.sample.param.sample.bank; | ||
67 | v->instr.prg = ev->data.sample.param.sample.prg; | ||
68 | select_instrument(p->gus, v); | ||
69 | } | ||
70 | |||
71 | static void event_cluster(struct snd_seq_event *ev, struct snd_gus_port *p, | ||
72 | struct snd_gus_voice *v) | ||
73 | { | ||
74 | if (v->sample_ops && v->sample_ops->sample_stop) | ||
75 | v->sample_ops->sample_stop(p->gus, v, SAMPLE_STOP_IMMEDIATELY); | ||
76 | v->instr.cluster = ev->data.sample.param.cluster.cluster; | ||
77 | select_instrument(p->gus, v); | ||
78 | } | ||
79 | |||
80 | static void event_start(struct snd_seq_event *ev, struct snd_gus_port *p, | ||
81 | struct snd_gus_voice *v) | ||
82 | { | ||
83 | if (v->sample_ops && v->sample_ops->sample_start) | ||
84 | v->sample_ops->sample_start(p->gus, v, ev->data.sample.param.position); | ||
85 | } | ||
86 | |||
87 | static void event_stop(struct snd_seq_event *ev, struct snd_gus_port *p, | ||
88 | struct snd_gus_voice *v) | ||
89 | { | ||
90 | if (v->sample_ops && v->sample_ops->sample_stop) | ||
91 | v->sample_ops->sample_stop(p->gus, v, ev->data.sample.param.stop_mode); | ||
92 | } | ||
93 | |||
94 | static void event_freq(struct snd_seq_event *ev, struct snd_gus_port *p, | ||
95 | struct snd_gus_voice *v) | ||
96 | { | ||
97 | if (v->sample_ops && v->sample_ops->sample_freq) | ||
98 | v->sample_ops->sample_freq(p->gus, v, ev->data.sample.param.frequency); | ||
99 | } | ||
100 | |||
101 | static void event_volume(struct snd_seq_event *ev, struct snd_gus_port *p, | ||
102 | struct snd_gus_voice *v) | ||
103 | { | ||
104 | if (v->sample_ops && v->sample_ops->sample_volume) | ||
105 | v->sample_ops->sample_volume(p->gus, v, &ev->data.sample.param.volume); | ||
106 | } | ||
107 | |||
108 | static void event_loop(struct snd_seq_event *ev, struct snd_gus_port *p, | ||
109 | struct snd_gus_voice *v) | ||
110 | { | ||
111 | if (v->sample_ops && v->sample_ops->sample_loop) | ||
112 | v->sample_ops->sample_loop(p->gus, v, &ev->data.sample.param.loop); | ||
113 | } | ||
114 | |||
115 | static void event_position(struct snd_seq_event *ev, struct snd_gus_port *p, | ||
116 | struct snd_gus_voice *v) | ||
117 | { | ||
118 | if (v->sample_ops && v->sample_ops->sample_pos) | ||
119 | v->sample_ops->sample_pos(p->gus, v, ev->data.sample.param.position); | ||
120 | } | ||
121 | |||
122 | static void event_private1(struct snd_seq_event *ev, struct snd_gus_port *p, | ||
123 | struct snd_gus_voice *v) | ||
124 | { | ||
125 | if (v->sample_ops && v->sample_ops->sample_private1) | ||
126 | v->sample_ops->sample_private1(p->gus, v, (unsigned char *)&ev->data.sample.param.raw8); | ||
127 | } | ||
128 | |||
129 | typedef void (gus_sample_event_handler_t)(struct snd_seq_event *ev, | ||
130 | struct snd_gus_port *p, | ||
131 | struct snd_gus_voice *v); | ||
132 | static gus_sample_event_handler_t *gus_sample_event_handlers[9] = { | ||
133 | event_sample, | ||
134 | event_cluster, | ||
135 | event_start, | ||
136 | event_stop, | ||
137 | event_freq, | ||
138 | event_volume, | ||
139 | event_loop, | ||
140 | event_position, | ||
141 | event_private1 | ||
142 | }; | ||
143 | |||
144 | void snd_gus_sample_event(struct snd_seq_event *ev, struct snd_gus_port *p) | ||
145 | { | ||
146 | int idx, voice; | ||
147 | struct snd_gus_card *gus = p->gus; | ||
148 | struct snd_gus_voice *v; | ||
149 | unsigned long flags; | ||
150 | |||
151 | idx = ev->type - SNDRV_SEQ_EVENT_SAMPLE; | ||
152 | if (idx < 0 || idx > 8) | ||
153 | return; | ||
154 | for (voice = 0; voice < 32; voice++) { | ||
155 | v = &gus->gf1.voices[voice]; | ||
156 | if (v->use && v->client == ev->source.client && | ||
157 | v->port == ev->source.port && | ||
158 | v->index == ev->data.sample.channel) { | ||
159 | spin_lock_irqsave(&gus->event_lock, flags); | ||
160 | gus_sample_event_handlers[idx](ev, p, v); | ||
161 | spin_unlock_irqrestore(&gus->event_lock, flags); | ||
162 | return; | ||
163 | } | ||
164 | } | ||
165 | } | ||
diff --git a/sound/isa/gus/gus_simple.c b/sound/isa/gus/gus_simple.c deleted file mode 100644 index 39d121e2c8c4..000000000000 --- a/sound/isa/gus/gus_simple.c +++ /dev/null | |||
@@ -1,634 +0,0 @@ | |||
1 | /* | ||
2 | * Routines for Gravis UltraSound soundcards - Simple instrument handlers | ||
3 | * Copyright (c) by Jaroslav Kysela <perex@perex.cz> | ||
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 <linux/time.h> | ||
24 | #include <sound/core.h> | ||
25 | #include <sound/gus.h> | ||
26 | #include "gus_tables.h" | ||
27 | |||
28 | /* | ||
29 | * | ||
30 | */ | ||
31 | |||
32 | static void interrupt_wave(struct snd_gus_card *gus, struct snd_gus_voice *voice); | ||
33 | static void interrupt_volume(struct snd_gus_card *gus, struct snd_gus_voice *voice); | ||
34 | static void interrupt_effect(struct snd_gus_card *gus, struct snd_gus_voice *voice); | ||
35 | |||
36 | static void sample_start(struct snd_gus_card *gus, struct snd_gus_voice *voice, snd_seq_position_t position); | ||
37 | static void sample_stop(struct snd_gus_card *gus, struct snd_gus_voice *voice, int mode); | ||
38 | static void sample_freq(struct snd_gus_card *gus, struct snd_gus_voice *voice, snd_seq_frequency_t freq); | ||
39 | static void sample_volume(struct snd_gus_card *card, struct snd_gus_voice *voice, struct snd_seq_ev_volume *volume); | ||
40 | static void sample_loop(struct snd_gus_card *card, struct snd_gus_voice *voice, struct snd_seq_ev_loop *loop); | ||
41 | static void sample_pos(struct snd_gus_card *card, struct snd_gus_voice *voice, snd_seq_position_t position); | ||
42 | static void sample_private1(struct snd_gus_card *card, struct snd_gus_voice *voice, unsigned char *data); | ||
43 | |||
44 | static struct snd_gus_sample_ops sample_ops = { | ||
45 | sample_start, | ||
46 | sample_stop, | ||
47 | sample_freq, | ||
48 | sample_volume, | ||
49 | sample_loop, | ||
50 | sample_pos, | ||
51 | sample_private1 | ||
52 | }; | ||
53 | |||
54 | #if 0 | ||
55 | |||
56 | static void note_stop(struct snd_gus_card *gus, struct snd_gus_voice *voice, int wait); | ||
57 | static void note_wait(struct snd_gus_card *gus, struct snd_gus_voice *voice); | ||
58 | static void note_off(struct snd_gus_card *gus, struct snd_gus_voice *voice); | ||
59 | static void note_volume(struct snd_gus_card *card, struct snd_gus_voice *voice); | ||
60 | static void note_pitchbend(struct snd_gus_card *card, struct snd_gus_voice *voice); | ||
61 | static void note_vibrato(struct snd_gus_card *card, struct snd_gus_voice *voice); | ||
62 | static void note_tremolo(struct snd_gus_card *card, struct snd_gus_voice *voice); | ||
63 | |||
64 | static struct snd_gus_note_handlers note_commands = { | ||
65 | note_stop, | ||
66 | note_wait, | ||
67 | note_off, | ||
68 | note_volume, | ||
69 | note_pitchbend, | ||
70 | note_vibrato, | ||
71 | note_tremolo | ||
72 | }; | ||
73 | |||
74 | static void chn_trigger_down(struct snd_gus_card *card, ultra_channel_t *channel, ultra_instrument_t *instrument, unsigned char note, unsigned char velocity, unsigned char priority ); | ||
75 | static void chn_trigger_up( ultra_card_t *card, ultra_note_t *note ); | ||
76 | static void chn_control( ultra_card_t *card, ultra_channel_t *channel, unsigned short p1, unsigned short p2 ); | ||
77 | |||
78 | static struct ULTRA_STRU_INSTRUMENT_CHANNEL_COMMANDS channel_commands = { | ||
79 | chn_trigger_down, | ||
80 | chn_trigger_up, | ||
81 | chn_control | ||
82 | }; | ||
83 | |||
84 | #endif | ||
85 | |||
86 | static void do_volume_envelope(struct snd_gus_card *card, struct snd_gus_voice *voice); | ||
87 | static void do_pan_envelope(struct snd_gus_card *card, struct snd_gus_voice *voice); | ||
88 | |||
89 | /* | ||
90 | * | ||
91 | */ | ||
92 | |||
93 | static void interrupt_wave(struct snd_gus_card *gus, struct snd_gus_voice *voice) | ||
94 | { | ||
95 | spin_lock(&gus->event_lock); | ||
96 | snd_gf1_stop_voice(gus, voice->number); | ||
97 | spin_lock(&gus->reg_lock); | ||
98 | snd_gf1_select_voice(gus, voice->number); | ||
99 | snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, 0); | ||
100 | spin_unlock(&gus->reg_lock); | ||
101 | voice->flags &= ~SNDRV_GF1_VFLG_RUNNING; | ||
102 | spin_unlock(&gus->event_lock); | ||
103 | } | ||
104 | |||
105 | static void interrupt_volume(struct snd_gus_card *gus, struct snd_gus_voice *voice) | ||
106 | { | ||
107 | spin_lock(&gus->event_lock); | ||
108 | if (voice->flags & SNDRV_GF1_VFLG_RUNNING) | ||
109 | do_volume_envelope(gus, voice); | ||
110 | else | ||
111 | snd_gf1_stop_voice(gus, voice->number); | ||
112 | spin_unlock(&gus->event_lock); | ||
113 | } | ||
114 | |||
115 | static void interrupt_effect(struct snd_gus_card *gus, struct snd_gus_voice *voice) | ||
116 | { | ||
117 | spin_lock(&gus->event_lock); | ||
118 | if ((voice->flags & (SNDRV_GF1_VFLG_RUNNING|SNDRV_GF1_VFLG_EFFECT_TIMER1)) == | ||
119 | (SNDRV_GF1_VFLG_RUNNING|SNDRV_GF1_VFLG_EFFECT_TIMER1)) | ||
120 | do_pan_envelope(gus, voice); | ||
121 | spin_unlock(&gus->event_lock); | ||
122 | } | ||
123 | |||
124 | /* | ||
125 | * | ||
126 | */ | ||
127 | |||
128 | static void do_volume_envelope(struct snd_gus_card *gus, struct snd_gus_voice *voice) | ||
129 | { | ||
130 | unsigned short next, rate, old_volume; | ||
131 | int program_next_ramp; | ||
132 | unsigned long flags; | ||
133 | |||
134 | if (!gus->gf1.volume_ramp) { | ||
135 | spin_lock_irqsave(&gus->reg_lock, flags); | ||
136 | snd_gf1_select_voice(gus, voice->number); | ||
137 | snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL); | ||
138 | snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, voice->gf1_volume); | ||
139 | /* printk("gf1_volume = 0x%x\n", voice->gf1_volume); */ | ||
140 | spin_unlock_irqrestore(&gus->reg_lock, flags); | ||
141 | return; | ||
142 | } | ||
143 | program_next_ramp = 0; | ||
144 | rate = next = 0; | ||
145 | while (1) { | ||
146 | program_next_ramp = 0; | ||
147 | rate = next = 0; | ||
148 | switch (voice->venv_state) { | ||
149 | case VENV_BEFORE: | ||
150 | voice->venv_state = VENV_ATTACK; | ||
151 | voice->venv_value_next = 0; | ||
152 | spin_lock_irqsave(&gus->reg_lock, flags); | ||
153 | snd_gf1_select_voice(gus, voice->number); | ||
154 | snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL); | ||
155 | snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, SNDRV_GF1_MIN_VOLUME); | ||
156 | spin_unlock_irqrestore(&gus->reg_lock, flags); | ||
157 | break; | ||
158 | case VENV_ATTACK: | ||
159 | voice->venv_state = VENV_SUSTAIN; | ||
160 | program_next_ramp++; | ||
161 | next = 255; | ||
162 | rate = gus->gf1.volume_ramp; | ||
163 | break; | ||
164 | case VENV_SUSTAIN: | ||
165 | voice->venv_state = VENV_RELEASE; | ||
166 | spin_lock_irqsave(&gus->reg_lock, flags); | ||
167 | snd_gf1_select_voice(gus, voice->number); | ||
168 | snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL); | ||
169 | snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, ((int)voice->gf1_volume * (int)voice->venv_value_next) / 255); | ||
170 | spin_unlock_irqrestore(&gus->reg_lock, flags); | ||
171 | return; | ||
172 | case VENV_RELEASE: | ||
173 | voice->venv_state = VENV_DONE; | ||
174 | program_next_ramp++; | ||
175 | next = 0; | ||
176 | rate = gus->gf1.volume_ramp; | ||
177 | break; | ||
178 | case VENV_DONE: | ||
179 | snd_gf1_stop_voice(gus, voice->number); | ||
180 | voice->flags &= ~SNDRV_GF1_VFLG_RUNNING; | ||
181 | return; | ||
182 | case VENV_VOLUME: | ||
183 | program_next_ramp++; | ||
184 | next = voice->venv_value_next; | ||
185 | rate = gus->gf1.volume_ramp; | ||
186 | voice->venv_state = voice->venv_state_prev; | ||
187 | break; | ||
188 | } | ||
189 | voice->venv_value_next = next; | ||
190 | if (!program_next_ramp) | ||
191 | continue; | ||
192 | spin_lock_irqsave(&gus->reg_lock, flags); | ||
193 | snd_gf1_select_voice(gus, voice->number); | ||
194 | snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL); | ||
195 | old_volume = snd_gf1_read16(gus, SNDRV_GF1_VW_VOLUME) >> 8; | ||
196 | if (!rate) { | ||
197 | spin_unlock_irqrestore(&gus->reg_lock, flags); | ||
198 | continue; | ||
199 | } | ||
200 | next = (((int)voice->gf1_volume * (int)next) / 255) >> 8; | ||
201 | if (old_volume < SNDRV_GF1_MIN_OFFSET) | ||
202 | old_volume = SNDRV_GF1_MIN_OFFSET; | ||
203 | if (next < SNDRV_GF1_MIN_OFFSET) | ||
204 | next = SNDRV_GF1_MIN_OFFSET; | ||
205 | if (next > SNDRV_GF1_MAX_OFFSET) | ||
206 | next = SNDRV_GF1_MAX_OFFSET; | ||
207 | if (old_volume == next) { | ||
208 | spin_unlock_irqrestore(&gus->reg_lock, flags); | ||
209 | continue; | ||
210 | } | ||
211 | voice->volume_control &= ~0xc3; | ||
212 | voice->volume_control |= 0x20; | ||
213 | if (old_volume > next) { | ||
214 | snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_START, next); | ||
215 | snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_END, old_volume); | ||
216 | voice->volume_control |= 0x40; | ||
217 | } else { | ||
218 | snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_START, old_volume); | ||
219 | snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_END, next); | ||
220 | } | ||
221 | snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_RATE, rate); | ||
222 | snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_CONTROL, voice->volume_control); | ||
223 | if (!gus->gf1.enh_mode) { | ||
224 | snd_gf1_delay(gus); | ||
225 | snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_CONTROL, voice->volume_control); | ||
226 | } | ||
227 | spin_unlock_irqrestore(&gus->reg_lock, flags); | ||
228 | return; | ||
229 | } | ||
230 | } | ||
231 | |||
232 | static void do_pan_envelope(struct snd_gus_card *gus, struct snd_gus_voice *voice) | ||
233 | { | ||
234 | unsigned long flags; | ||
235 | unsigned char old_pan; | ||
236 | |||
237 | #if 0 | ||
238 | snd_gf1_select_voice(gus, voice->number); | ||
239 | printk(" -%i- do_pan_envelope - flags = 0x%x (0x%x -> 0x%x)\n", | ||
240 | voice->number, | ||
241 | voice->flags, | ||
242 | voice->gf1_pan, | ||
243 | snd_gf1_i_read8(gus, SNDRV_GF1_VB_PAN) & 0x0f); | ||
244 | #endif | ||
245 | if (gus->gf1.enh_mode) { | ||
246 | voice->flags &= ~(SNDRV_GF1_VFLG_EFFECT_TIMER1|SNDRV_GF1_VFLG_PAN); | ||
247 | return; | ||
248 | } | ||
249 | if (!gus->gf1.smooth_pan) { | ||
250 | spin_lock_irqsave(&gus->reg_lock, flags); | ||
251 | snd_gf1_select_voice(gus, voice->number); | ||
252 | snd_gf1_write8(gus, SNDRV_GF1_VB_PAN, voice->gf1_pan); | ||
253 | spin_unlock_irqrestore(&gus->reg_lock, flags); | ||
254 | return; | ||
255 | } | ||
256 | if (!(voice->flags & SNDRV_GF1_VFLG_PAN)) /* before */ | ||
257 | voice->flags |= SNDRV_GF1_VFLG_EFFECT_TIMER1|SNDRV_GF1_VFLG_PAN; | ||
258 | spin_lock_irqsave(&gus->reg_lock, flags); | ||
259 | snd_gf1_select_voice(gus, voice->number); | ||
260 | old_pan = snd_gf1_read8(gus, SNDRV_GF1_VB_PAN) & 0x0f; | ||
261 | if (old_pan > voice->gf1_pan ) | ||
262 | old_pan--; | ||
263 | if (old_pan < voice->gf1_pan) | ||
264 | old_pan++; | ||
265 | snd_gf1_write8(gus, SNDRV_GF1_VB_PAN, old_pan); | ||
266 | spin_unlock_irqrestore(&gus->reg_lock, flags); | ||
267 | if (old_pan == voice->gf1_pan) /* the goal was reached */ | ||
268 | voice->flags &= ~(SNDRV_GF1_VFLG_EFFECT_TIMER1|SNDRV_GF1_VFLG_PAN); | ||
269 | #if 0 | ||
270 | snd_gf1_select_voice(gus, voice->number); | ||
271 | printk(" -%i- (1) do_pan_envelope - flags = 0x%x (0x%x -> 0x%x)\n", | ||
272 | voice->number, | ||
273 | voice->flags, | ||
274 | voice->gf1_pan, | ||
275 | snd_gf1_i_read8(gus, GF1_VB_PAN) & 0x0f); | ||
276 | #endif | ||
277 | } | ||
278 | |||
279 | static void set_enhanced_pan(struct snd_gus_card *gus, struct snd_gus_voice *voice, unsigned short pan) | ||
280 | { | ||
281 | unsigned long flags; | ||
282 | unsigned short vlo, vro; | ||
283 | |||
284 | vlo = SNDRV_GF1_ATTEN((SNDRV_GF1_ATTEN_TABLE_SIZE-1) - pan); | ||
285 | vro = SNDRV_GF1_ATTEN(pan); | ||
286 | if (pan != SNDRV_GF1_ATTEN_TABLE_SIZE - 1 && pan != 0) { | ||
287 | vlo >>= 1; | ||
288 | vro >>= 1; | ||
289 | } | ||
290 | vlo <<= 4; | ||
291 | vro <<= 4; | ||
292 | #if 0 | ||
293 | printk("vlo = 0x%x (0x%x), vro = 0x%x (0x%x)\n", | ||
294 | vlo, snd_gf1_i_read16(gus, GF1_VW_OFFSET_LEFT), | ||
295 | vro, snd_gf1_i_read16(gus, GF1_VW_OFFSET_RIGHT)); | ||
296 | #endif | ||
297 | spin_lock_irqsave(&gus->reg_lock, flags); | ||
298 | snd_gf1_select_voice(gus, voice->number); | ||
299 | snd_gf1_write16(gus, SNDRV_GF1_VW_OFFSET_LEFT_FINAL, vlo); | ||
300 | snd_gf1_write16(gus, SNDRV_GF1_VW_OFFSET_RIGHT_FINAL, vro); | ||
301 | spin_unlock_irqrestore(&gus->reg_lock, flags); | ||
302 | voice->vlo = vlo; | ||
303 | voice->vro = vro; | ||
304 | } | ||
305 | |||
306 | /* | ||
307 | * | ||
308 | */ | ||
309 | |||
310 | static void sample_start(struct snd_gus_card *gus, struct snd_gus_voice *voice, snd_seq_position_t position) | ||
311 | { | ||
312 | unsigned long flags; | ||
313 | unsigned int begin, addr, addr_end, addr_start; | ||
314 | int w_16; | ||
315 | struct simple_instrument *simple; | ||
316 | struct snd_seq_kinstr *instr; | ||
317 | |||
318 | instr = snd_seq_instr_find(gus->gf1.ilist, &voice->instr, 0, 1); | ||
319 | if (instr == NULL) | ||
320 | return; | ||
321 | voice->instr = instr->instr; /* copy ID to speedup aliases */ | ||
322 | simple = KINSTR_DATA(instr); | ||
323 | begin = simple->address.memory << 4; | ||
324 | w_16 = simple->format & SIMPLE_WAVE_16BIT ? 0x04 : 0; | ||
325 | addr_start = simple->loop_start; | ||
326 | if (simple->format & SIMPLE_WAVE_LOOP) { | ||
327 | addr_end = simple->loop_end; | ||
328 | } else { | ||
329 | addr_end = (simple->size << 4) - (w_16 ? 40 : 24); | ||
330 | } | ||
331 | if (simple->format & SIMPLE_WAVE_BACKWARD) { | ||
332 | addr = simple->loop_end; | ||
333 | if (position < simple->loop_end) | ||
334 | addr -= position; | ||
335 | } else { | ||
336 | addr = position; | ||
337 | } | ||
338 | voice->control = 0x00; | ||
339 | voice->mode = 0x20; /* enable offset registers */ | ||
340 | if (simple->format & SIMPLE_WAVE_16BIT) | ||
341 | voice->control |= 0x04; | ||
342 | if (simple->format & SIMPLE_WAVE_BACKWARD) | ||
343 | voice->control |= 0x40; | ||
344 | if (simple->format & SIMPLE_WAVE_LOOP) { | ||
345 | voice->control |= 0x08; | ||
346 | } else { | ||
347 | voice->control |= 0x20; | ||
348 | } | ||
349 | if (simple->format & SIMPLE_WAVE_BIDIR) | ||
350 | voice->control |= 0x10; | ||
351 | if (simple->format & SIMPLE_WAVE_ULAW) | ||
352 | voice->mode |= 0x40; | ||
353 | if (w_16) { | ||
354 | addr = ((addr << 1) & ~0x1f) | (addr & 0x0f); | ||
355 | addr_start = ((addr_start << 1) & ~0x1f) | (addr_start & 0x0f); | ||
356 | addr_end = ((addr_end << 1) & ~0x1f) | (addr_end & 0x0f); | ||
357 | } | ||
358 | addr += begin; | ||
359 | addr_start += begin; | ||
360 | addr_end += begin; | ||
361 | snd_gf1_stop_voice(gus, voice->number); | ||
362 | spin_lock_irqsave(&gus->reg_lock, flags); | ||
363 | snd_gf1_select_voice(gus, voice->number); | ||
364 | snd_gf1_write16(gus, SNDRV_GF1_VW_FREQUENCY, voice->fc_register + voice->fc_lfo); | ||
365 | voice->venv_state = VENV_BEFORE; | ||
366 | voice->volume_control = 0x03; | ||
367 | snd_gf1_write_addr(gus, SNDRV_GF1_VA_START, addr_start, w_16); | ||
368 | snd_gf1_write_addr(gus, SNDRV_GF1_VA_END, addr_end, w_16); | ||
369 | snd_gf1_write_addr(gus, SNDRV_GF1_VA_CURRENT, addr, w_16); | ||
370 | if (!gus->gf1.enh_mode) { | ||
371 | snd_gf1_write8(gus, SNDRV_GF1_VB_PAN, voice->gf1_pan); | ||
372 | } else { | ||
373 | snd_gf1_write16(gus, SNDRV_GF1_VW_OFFSET_LEFT, voice->vlo); | ||
374 | snd_gf1_write16(gus, SNDRV_GF1_VW_OFFSET_LEFT_FINAL, voice->vlo); | ||
375 | snd_gf1_write16(gus, SNDRV_GF1_VW_OFFSET_RIGHT, voice->vro); | ||
376 | snd_gf1_write16(gus, SNDRV_GF1_VW_OFFSET_RIGHT_FINAL, voice->vro); | ||
377 | snd_gf1_write8(gus, SNDRV_GF1_VB_ACCUMULATOR, voice->effect_accumulator); | ||
378 | snd_gf1_write16(gus, SNDRV_GF1_VW_EFFECT_VOLUME, voice->gf1_effect_volume); | ||
379 | snd_gf1_write16(gus, SNDRV_GF1_VW_EFFECT_VOLUME_FINAL, voice->gf1_effect_volume); | ||
380 | } | ||
381 | spin_unlock_irqrestore(&gus->reg_lock, flags); | ||
382 | do_volume_envelope(gus, voice); | ||
383 | spin_lock_irqsave(&gus->reg_lock, flags); | ||
384 | snd_gf1_select_voice(gus, voice->number); | ||
385 | if (gus->gf1.enh_mode) | ||
386 | snd_gf1_write8(gus, SNDRV_GF1_VB_MODE, voice->mode); | ||
387 | snd_gf1_write8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL, voice->control); | ||
388 | if (!gus->gf1.enh_mode) { | ||
389 | snd_gf1_delay(gus); | ||
390 | snd_gf1_write8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL, voice->control ); | ||
391 | } | ||
392 | spin_unlock_irqrestore(&gus->reg_lock, flags); | ||
393 | #if 0 | ||
394 | snd_gf1_print_voice_registers(gus); | ||
395 | #endif | ||
396 | voice->flags |= SNDRV_GF1_VFLG_RUNNING; | ||
397 | snd_seq_instr_free_use(gus->gf1.ilist, instr); | ||
398 | } | ||
399 | |||
400 | static void sample_stop(struct snd_gus_card *gus, struct snd_gus_voice *voice, int mode) | ||
401 | { | ||
402 | unsigned char control; | ||
403 | unsigned long flags; | ||
404 | |||
405 | if (!(voice->flags & SNDRV_GF1_VFLG_RUNNING)) | ||
406 | return; | ||
407 | switch (mode) { | ||
408 | default: | ||
409 | if (gus->gf1.volume_ramp > 0) { | ||
410 | if (voice->venv_state < VENV_RELEASE) { | ||
411 | voice->venv_state = VENV_RELEASE; | ||
412 | do_volume_envelope(gus, voice); | ||
413 | } | ||
414 | } | ||
415 | if (mode != SAMPLE_STOP_VENVELOPE) { | ||
416 | snd_gf1_stop_voice(gus, voice->number); | ||
417 | spin_lock_irqsave(&gus->reg_lock, flags); | ||
418 | snd_gf1_select_voice(gus, voice->number); | ||
419 | snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, SNDRV_GF1_MIN_VOLUME); | ||
420 | spin_unlock_irqrestore(&gus->reg_lock, flags); | ||
421 | voice->flags &= ~SNDRV_GF1_VFLG_RUNNING; | ||
422 | } | ||
423 | break; | ||
424 | case SAMPLE_STOP_LOOP: /* disable loop only */ | ||
425 | spin_lock_irqsave(&gus->reg_lock, flags); | ||
426 | snd_gf1_select_voice(gus, voice->number); | ||
427 | control = snd_gf1_read8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL); | ||
428 | control &= ~(0x83 | 0x04); | ||
429 | control |= 0x20; | ||
430 | snd_gf1_write8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL, control); | ||
431 | spin_unlock_irqrestore(&gus->reg_lock, flags); | ||
432 | break; | ||
433 | } | ||
434 | } | ||
435 | |||
436 | static void sample_freq(struct snd_gus_card *gus, struct snd_gus_voice *voice, snd_seq_frequency_t freq) | ||
437 | { | ||
438 | unsigned long flags; | ||
439 | |||
440 | spin_lock_irqsave(&gus->reg_lock, flags); | ||
441 | voice->fc_register = snd_gf1_translate_freq(gus, freq); | ||
442 | snd_gf1_select_voice(gus, voice->number); | ||
443 | snd_gf1_write16(gus, SNDRV_GF1_VW_FREQUENCY, voice->fc_register + voice->fc_lfo); | ||
444 | spin_unlock_irqrestore(&gus->reg_lock, flags); | ||
445 | } | ||
446 | |||
447 | static void sample_volume(struct snd_gus_card *gus, struct snd_gus_voice *voice, struct snd_seq_ev_volume *volume) | ||
448 | { | ||
449 | if (volume->volume >= 0) { | ||
450 | volume->volume &= 0x3fff; | ||
451 | voice->gf1_volume = snd_gf1_lvol_to_gvol_raw(volume->volume << 2) << 4; | ||
452 | voice->venv_state_prev = VENV_SUSTAIN; | ||
453 | voice->venv_state = VENV_VOLUME; | ||
454 | do_volume_envelope(gus, voice); | ||
455 | } | ||
456 | if (volume->lr >= 0) { | ||
457 | volume->lr &= 0x3fff; | ||
458 | if (!gus->gf1.enh_mode) { | ||
459 | voice->gf1_pan = (volume->lr >> 10) & 15; | ||
460 | if (!gus->gf1.full_range_pan) { | ||
461 | if (voice->gf1_pan == 0) | ||
462 | voice->gf1_pan++; | ||
463 | if (voice->gf1_pan == 15) | ||
464 | voice->gf1_pan--; | ||
465 | } | ||
466 | voice->flags &= ~SNDRV_GF1_VFLG_PAN; /* before */ | ||
467 | do_pan_envelope(gus, voice); | ||
468 | } else { | ||
469 | set_enhanced_pan(gus, voice, volume->lr >> 7); | ||
470 | } | ||
471 | } | ||
472 | } | ||
473 | |||
474 | static void sample_loop(struct snd_gus_card *gus, struct snd_gus_voice *voice, struct snd_seq_ev_loop *loop) | ||
475 | { | ||
476 | unsigned long flags; | ||
477 | int w_16 = voice->control & 0x04; | ||
478 | unsigned int begin, addr_start, addr_end; | ||
479 | struct simple_instrument *simple; | ||
480 | struct snd_seq_kinstr *instr; | ||
481 | |||
482 | #if 0 | ||
483 | printk("voice_loop: start = 0x%x, end = 0x%x\n", loop->start, loop->end); | ||
484 | #endif | ||
485 | instr = snd_seq_instr_find(gus->gf1.ilist, &voice->instr, 0, 1); | ||
486 | if (instr == NULL) | ||
487 | return; | ||
488 | voice->instr = instr->instr; /* copy ID to speedup aliases */ | ||
489 | simple = KINSTR_DATA(instr); | ||
490 | begin = simple->address.memory; | ||
491 | addr_start = loop->start; | ||
492 | addr_end = loop->end; | ||
493 | addr_start = (((addr_start << 1) & ~0x1f) | (addr_start & 0x0f)) + begin; | ||
494 | addr_end = (((addr_end << 1) & ~0x1f) | (addr_end & 0x0f)) + begin; | ||
495 | spin_lock_irqsave(&gus->reg_lock, flags); | ||
496 | snd_gf1_select_voice(gus, voice->number); | ||
497 | snd_gf1_write_addr(gus, SNDRV_GF1_VA_START, addr_start, w_16); | ||
498 | snd_gf1_write_addr(gus, SNDRV_GF1_VA_END, addr_end, w_16); | ||
499 | spin_unlock_irqrestore(&gus->reg_lock, flags); | ||
500 | snd_seq_instr_free_use(gus->gf1.ilist, instr); | ||
501 | } | ||
502 | |||
503 | static void sample_pos(struct snd_gus_card *gus, struct snd_gus_voice *voice, snd_seq_position_t position) | ||
504 | { | ||
505 | unsigned long flags; | ||
506 | int w_16 = voice->control & 0x04; | ||
507 | unsigned int begin, addr; | ||
508 | struct simple_instrument *simple; | ||
509 | struct snd_seq_kinstr *instr; | ||
510 | |||
511 | #if 0 | ||
512 | printk("voice_loop: start = 0x%x, end = 0x%x\n", loop->start, loop->end); | ||
513 | #endif | ||
514 | instr = snd_seq_instr_find(gus->gf1.ilist, &voice->instr, 0, 1); | ||
515 | if (instr == NULL) | ||
516 | return; | ||
517 | voice->instr = instr->instr; /* copy ID to speedup aliases */ | ||
518 | simple = KINSTR_DATA(instr); | ||
519 | begin = simple->address.memory; | ||
520 | addr = (((position << 1) & ~0x1f) | (position & 0x0f)) + begin; | ||
521 | spin_lock_irqsave(&gus->reg_lock, flags); | ||
522 | snd_gf1_select_voice(gus, voice->number); | ||
523 | snd_gf1_write_addr(gus, SNDRV_GF1_VA_CURRENT, addr, w_16); | ||
524 | spin_unlock_irqrestore(&gus->reg_lock, flags); | ||
525 | snd_seq_instr_free_use(gus->gf1.ilist, instr); | ||
526 | } | ||
527 | |||
528 | #if 0 | ||
529 | |||
530 | static unsigned char get_effects_mask( ultra_card_t *card, int value ) | ||
531 | { | ||
532 | if ( value > 7 ) return 0; | ||
533 | if ( card -> gf1.effects && card -> gf1.effects -> chip_type == ULTRA_EFFECT_CHIP_INTERWAVE ) | ||
534 | return card -> gf1.effects -> chip.interwave.voice_output[ value ]; | ||
535 | return 0; | ||
536 | } | ||
537 | |||
538 | #endif | ||
539 | |||
540 | static void sample_private1(struct snd_gus_card *card, struct snd_gus_voice *voice, unsigned char *data) | ||
541 | { | ||
542 | #if 0 | ||
543 | unsigned long flags; | ||
544 | unsigned char uc; | ||
545 | |||
546 | switch ( *data ) { | ||
547 | case ULTRA_PRIV1_IW_EFFECT: | ||
548 | uc = get_effects_mask( card, ultra_get_byte( data, 4 ) ); | ||
549 | uc |= get_effects_mask( card, ultra_get_byte( data, 4 ) >> 4 ); | ||
550 | uc |= get_effects_mask( card, ultra_get_byte( data, 5 ) ); | ||
551 | uc |= get_effects_mask( card, ultra_get_byte( data, 5 ) >> 4 ); | ||
552 | voice -> data.simple.effect_accumulator = uc; | ||
553 | voice -> data.simple.effect_volume = ultra_translate_voice_volume( card, ultra_get_word( data, 2 ) ) << 4; | ||
554 | if ( !card -> gf1.enh_mode ) return; | ||
555 | if ( voice -> flags & VFLG_WAIT_FOR_START ) return; | ||
556 | if ( voice -> flags & VFLG_RUNNING ) | ||
557 | { | ||
558 | CLI( &flags ); | ||
559 | gf1_select_voice( card, voice -> number ); | ||
560 | ultra_write8( card, GF1_VB_ACCUMULATOR, voice -> data.simple.effect_accumulator ); | ||
561 | ultra_write16( card, GF1_VW_EFFECT_VOLUME_FINAL, voice -> data.simple.effect_volume ); | ||
562 | STI( &flags ); | ||
563 | } | ||
564 | break; | ||
565 | case ULTRA_PRIV1_IW_LFO: | ||
566 | ultra_lfo_command( card, voice -> number, data ); | ||
567 | } | ||
568 | #endif | ||
569 | } | ||
570 | |||
571 | #if 0 | ||
572 | |||
573 | /* | ||
574 | * | ||
575 | */ | ||
576 | |||
577 | static void note_stop( ultra_card_t *card, ultra_voice_t *voice, int wait ) | ||
578 | { | ||
579 | } | ||
580 | |||
581 | static void note_wait( ultra_card_t *card, ultra_voice_t *voice ) | ||
582 | { | ||
583 | } | ||
584 | |||
585 | static void note_off( ultra_card_t *card, ultra_voice_t *voice ) | ||
586 | { | ||
587 | } | ||
588 | |||
589 | static void note_volume( ultra_card_t *card, ultra_voice_t *voice ) | ||
590 | { | ||
591 | } | ||
592 | |||
593 | static void note_pitchbend( ultra_card_t *card, ultra_voice_t *voice ) | ||
594 | { | ||
595 | } | ||
596 | |||
597 | static void note_vibrato( ultra_card_t *card, ultra_voice_t *voice ) | ||
598 | { | ||
599 | } | ||
600 | |||
601 | static void note_tremolo( ultra_card_t *card, ultra_voice_t *voice ) | ||
602 | { | ||
603 | } | ||
604 | |||
605 | /* | ||
606 | * | ||
607 | */ | ||
608 | |||
609 | static void chn_trigger_down( ultra_card_t *card, ultra_channel_t *channel, ultra_instrument_t *instrument, unsigned char note, unsigned char velocity, unsigned char priority ) | ||
610 | { | ||
611 | } | ||
612 | |||
613 | static void chn_trigger_up( ultra_card_t *card, ultra_note_t *note ) | ||
614 | { | ||
615 | } | ||
616 | |||
617 | static void chn_control( ultra_card_t *card, ultra_channel_t *channel, unsigned short p1, unsigned short p2 ) | ||
618 | { | ||
619 | } | ||
620 | |||
621 | /* | ||
622 | * | ||
623 | */ | ||
624 | |||
625 | #endif | ||
626 | |||
627 | void snd_gf1_simple_init(struct snd_gus_voice *voice) | ||
628 | { | ||
629 | voice->handler_wave = interrupt_wave; | ||
630 | voice->handler_volume = interrupt_volume; | ||
631 | voice->handler_effect = interrupt_effect; | ||
632 | voice->volume_change = NULL; | ||
633 | voice->sample_ops = &sample_ops; | ||
634 | } | ||
diff --git a/sound/isa/gus/gus_synth.c b/sound/isa/gus/gus_synth.c deleted file mode 100644 index 2c2051782aa2..000000000000 --- a/sound/isa/gus/gus_synth.c +++ /dev/null | |||
@@ -1,314 +0,0 @@ | |||
1 | /* | ||
2 | * Routines for Gravis UltraSound soundcards - Synthesizer | ||
3 | * Copyright (c) by Jaroslav Kysela <perex@perex.cz> | ||
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 <linux/init.h> | ||
24 | #include <linux/time.h> | ||
25 | #include <sound/core.h> | ||
26 | #include <sound/gus.h> | ||
27 | #include <sound/seq_device.h> | ||
28 | |||
29 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); | ||
30 | MODULE_DESCRIPTION("Routines for Gravis UltraSound soundcards - Synthesizer"); | ||
31 | MODULE_LICENSE("GPL"); | ||
32 | |||
33 | /* | ||
34 | * | ||
35 | */ | ||
36 | |||
37 | static void snd_gus_synth_free_voices(struct snd_gus_card * gus, int client, int port) | ||
38 | { | ||
39 | int idx; | ||
40 | struct snd_gus_voice * voice; | ||
41 | |||
42 | for (idx = 0; idx < 32; idx++) { | ||
43 | voice = &gus->gf1.voices[idx]; | ||
44 | if (voice->use && voice->client == client && voice->port == port) | ||
45 | snd_gf1_free_voice(gus, voice); | ||
46 | } | ||
47 | } | ||
48 | |||
49 | static int snd_gus_synth_use(void *private_data, struct snd_seq_port_subscribe *info) | ||
50 | { | ||
51 | struct snd_gus_port * port = private_data; | ||
52 | struct snd_gus_card * gus = port->gus; | ||
53 | struct snd_gus_voice * voice; | ||
54 | unsigned int idx; | ||
55 | |||
56 | if (info->voices > 32) | ||
57 | return -EINVAL; | ||
58 | mutex_lock(&gus->register_mutex); | ||
59 | if (!snd_gus_use_inc(gus)) { | ||
60 | mutex_unlock(&gus->register_mutex); | ||
61 | return -EFAULT; | ||
62 | } | ||
63 | for (idx = 0; idx < info->voices; idx++) { | ||
64 | voice = snd_gf1_alloc_voice(gus, SNDRV_GF1_VOICE_TYPE_SYNTH, info->sender.client, info->sender.port); | ||
65 | if (voice == NULL) { | ||
66 | snd_gus_synth_free_voices(gus, info->sender.client, info->sender.port); | ||
67 | snd_gus_use_dec(gus); | ||
68 | mutex_unlock(&gus->register_mutex); | ||
69 | return -EBUSY; | ||
70 | } | ||
71 | voice->index = idx; | ||
72 | } | ||
73 | mutex_unlock(&gus->register_mutex); | ||
74 | return 0; | ||
75 | } | ||
76 | |||
77 | static int snd_gus_synth_unuse(void *private_data, struct snd_seq_port_subscribe *info) | ||
78 | { | ||
79 | struct snd_gus_port * port = private_data; | ||
80 | struct snd_gus_card * gus = port->gus; | ||
81 | |||
82 | mutex_lock(&gus->register_mutex); | ||
83 | snd_gus_synth_free_voices(gus, info->sender.client, info->sender.port); | ||
84 | snd_gus_use_dec(gus); | ||
85 | mutex_unlock(&gus->register_mutex); | ||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | /* | ||
90 | * | ||
91 | */ | ||
92 | |||
93 | static void snd_gus_synth_free_private_instruments(struct snd_gus_port *p, int client) | ||
94 | { | ||
95 | struct snd_seq_instr_header ifree; | ||
96 | |||
97 | memset(&ifree, 0, sizeof(ifree)); | ||
98 | ifree.cmd = SNDRV_SEQ_INSTR_FREE_CMD_PRIVATE; | ||
99 | snd_seq_instr_list_free_cond(p->gus->gf1.ilist, &ifree, client, 0); | ||
100 | } | ||
101 | |||
102 | static int snd_gus_synth_event_input(struct snd_seq_event *ev, int direct, | ||
103 | void *private_data, int atomic, int hop) | ||
104 | { | ||
105 | struct snd_gus_port * p = private_data; | ||
106 | |||
107 | snd_assert(p != NULL, return -EINVAL); | ||
108 | if (ev->type >= SNDRV_SEQ_EVENT_SAMPLE && | ||
109 | ev->type <= SNDRV_SEQ_EVENT_SAMPLE_PRIVATE1) { | ||
110 | snd_gus_sample_event(ev, p); | ||
111 | return 0; | ||
112 | } | ||
113 | if (ev->source.client == SNDRV_SEQ_CLIENT_SYSTEM && | ||
114 | ev->source.port == SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE) { | ||
115 | if (ev->type == SNDRV_SEQ_EVENT_CLIENT_EXIT) { | ||
116 | snd_gus_synth_free_private_instruments(p, ev->data.addr.client); | ||
117 | return 0; | ||
118 | } | ||
119 | } | ||
120 | if (direct) { | ||
121 | if (ev->type >= SNDRV_SEQ_EVENT_INSTR_BEGIN) { | ||
122 | snd_seq_instr_event(&p->gus->gf1.iwffff_ops.kops, | ||
123 | p->gus->gf1.ilist, | ||
124 | ev, | ||
125 | p->gus->gf1.seq_client, | ||
126 | atomic, hop); | ||
127 | return 0; | ||
128 | } | ||
129 | } | ||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | static void snd_gus_synth_instr_notify(void *private_data, | ||
134 | struct snd_seq_kinstr *instr, | ||
135 | int what) | ||
136 | { | ||
137 | unsigned int idx; | ||
138 | struct snd_gus_card *gus = private_data; | ||
139 | struct snd_gus_voice *pvoice; | ||
140 | unsigned long flags; | ||
141 | |||
142 | spin_lock_irqsave(&gus->event_lock, flags); | ||
143 | for (idx = 0; idx < 32; idx++) { | ||
144 | pvoice = &gus->gf1.voices[idx]; | ||
145 | if (pvoice->use && !memcmp(&pvoice->instr, &instr->instr, sizeof(pvoice->instr))) { | ||
146 | if (pvoice->sample_ops && pvoice->sample_ops->sample_stop) { | ||
147 | pvoice->sample_ops->sample_stop(gus, pvoice, SAMPLE_STOP_IMMEDIATELY); | ||
148 | } else { | ||
149 | snd_gf1_stop_voice(gus, pvoice->number); | ||
150 | pvoice->flags &= ~SNDRV_GF1_VFLG_RUNNING; | ||
151 | } | ||
152 | } | ||
153 | } | ||
154 | spin_unlock_irqrestore(&gus->event_lock, flags); | ||
155 | } | ||
156 | |||
157 | /* | ||
158 | * | ||
159 | */ | ||
160 | |||
161 | static void snd_gus_synth_free_port(void *private_data) | ||
162 | { | ||
163 | struct snd_gus_port * p = private_data; | ||
164 | |||
165 | if (p) | ||
166 | snd_midi_channel_free_set(p->chset); | ||
167 | } | ||
168 | |||
169 | static int snd_gus_synth_create_port(struct snd_gus_card * gus, int idx) | ||
170 | { | ||
171 | struct snd_gus_port * p; | ||
172 | struct snd_seq_port_callback callbacks; | ||
173 | char name[32]; | ||
174 | int result; | ||
175 | |||
176 | p = &gus->gf1.seq_ports[idx]; | ||
177 | p->chset = snd_midi_channel_alloc_set(16); | ||
178 | if (p->chset == NULL) | ||
179 | return -ENOMEM; | ||
180 | p->chset->private_data = p; | ||
181 | p->gus = gus; | ||
182 | p->client = gus->gf1.seq_client; | ||
183 | |||
184 | memset(&callbacks, 0, sizeof(callbacks)); | ||
185 | callbacks.owner = THIS_MODULE; | ||
186 | callbacks.use = snd_gus_synth_use; | ||
187 | callbacks.unuse = snd_gus_synth_unuse; | ||
188 | callbacks.event_input = snd_gus_synth_event_input; | ||
189 | callbacks.private_free = snd_gus_synth_free_port; | ||
190 | callbacks.private_data = p; | ||
191 | |||
192 | sprintf(name, "%s port %i", gus->interwave ? "AMD InterWave" : "GF1", idx); | ||
193 | p->chset->port = snd_seq_event_port_attach(gus->gf1.seq_client, | ||
194 | &callbacks, | ||
195 | SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE, | ||
196 | SNDRV_SEQ_PORT_TYPE_DIRECT_SAMPLE | | ||
197 | SNDRV_SEQ_PORT_TYPE_SYNTH | | ||
198 | SNDRV_SEQ_PORT_TYPE_HARDWARE | | ||
199 | SNDRV_SEQ_PORT_TYPE_SYNTHESIZER, | ||
200 | 16, 0, | ||
201 | name); | ||
202 | if (p->chset->port < 0) { | ||
203 | result = p->chset->port; | ||
204 | snd_gus_synth_free_port(p); | ||
205 | return result; | ||
206 | } | ||
207 | p->port = p->chset->port; | ||
208 | return 0; | ||
209 | } | ||
210 | |||
211 | /* | ||
212 | * | ||
213 | */ | ||
214 | |||
215 | static int snd_gus_synth_new_device(struct snd_seq_device *dev) | ||
216 | { | ||
217 | struct snd_gus_card *gus; | ||
218 | int client, i; | ||
219 | struct snd_seq_port_subscribe sub; | ||
220 | struct snd_iwffff_ops *iwops; | ||
221 | struct snd_gf1_ops *gf1ops; | ||
222 | struct snd_simple_ops *simpleops; | ||
223 | |||
224 | gus = *(struct snd_gus_card **)SNDRV_SEQ_DEVICE_ARGPTR(dev); | ||
225 | if (gus == NULL) | ||
226 | return -EINVAL; | ||
227 | |||
228 | mutex_init(&gus->register_mutex); | ||
229 | gus->gf1.seq_client = -1; | ||
230 | |||
231 | /* allocate new client */ | ||
232 | client = gus->gf1.seq_client = | ||
233 | snd_seq_create_kernel_client(gus->card, 1, gus->interwave ? | ||
234 | "AMD InterWave" : "GF1"); | ||
235 | if (client < 0) | ||
236 | return client; | ||
237 | |||
238 | for (i = 0; i < 4; i++) | ||
239 | snd_gus_synth_create_port(gus, i); | ||
240 | |||
241 | gus->gf1.ilist = snd_seq_instr_list_new(); | ||
242 | if (gus->gf1.ilist == NULL) { | ||
243 | snd_seq_delete_kernel_client(client); | ||
244 | gus->gf1.seq_client = -1; | ||
245 | return -ENOMEM; | ||
246 | } | ||
247 | gus->gf1.ilist->flags = SNDRV_SEQ_INSTR_FLG_DIRECT; | ||
248 | |||
249 | simpleops = &gus->gf1.simple_ops; | ||
250 | snd_seq_simple_init(simpleops, gus, NULL); | ||
251 | simpleops->put_sample = snd_gus_simple_put_sample; | ||
252 | simpleops->get_sample = snd_gus_simple_get_sample; | ||
253 | simpleops->remove_sample = snd_gus_simple_remove_sample; | ||
254 | simpleops->notify = snd_gus_synth_instr_notify; | ||
255 | |||
256 | gf1ops = &gus->gf1.gf1_ops; | ||
257 | snd_seq_gf1_init(gf1ops, gus, &simpleops->kops); | ||
258 | gf1ops->put_sample = snd_gus_gf1_put_sample; | ||
259 | gf1ops->get_sample = snd_gus_gf1_get_sample; | ||
260 | gf1ops->remove_sample = snd_gus_gf1_remove_sample; | ||
261 | gf1ops->notify = snd_gus_synth_instr_notify; | ||
262 | |||
263 | iwops = &gus->gf1.iwffff_ops; | ||
264 | snd_seq_iwffff_init(iwops, gus, &gf1ops->kops); | ||
265 | iwops->put_sample = snd_gus_iwffff_put_sample; | ||
266 | iwops->get_sample = snd_gus_iwffff_get_sample; | ||
267 | iwops->remove_sample = snd_gus_iwffff_remove_sample; | ||
268 | iwops->notify = snd_gus_synth_instr_notify; | ||
269 | |||
270 | memset(&sub, 0, sizeof(sub)); | ||
271 | sub.sender.client = SNDRV_SEQ_CLIENT_SYSTEM; | ||
272 | sub.sender.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE; | ||
273 | sub.dest.client = client; | ||
274 | sub.dest.port = 0; | ||
275 | snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &sub); | ||
276 | |||
277 | return 0; | ||
278 | } | ||
279 | |||
280 | static int snd_gus_synth_delete_device(struct snd_seq_device *dev) | ||
281 | { | ||
282 | struct snd_gus_card *gus; | ||
283 | |||
284 | gus = *(struct snd_gus_card **)SNDRV_SEQ_DEVICE_ARGPTR(dev); | ||
285 | if (gus == NULL) | ||
286 | return -EINVAL; | ||
287 | |||
288 | if (gus->gf1.seq_client >= 0) { | ||
289 | snd_seq_delete_kernel_client(gus->gf1.seq_client); | ||
290 | gus->gf1.seq_client = -1; | ||
291 | } | ||
292 | if (gus->gf1.ilist) | ||
293 | snd_seq_instr_list_free(&gus->gf1.ilist); | ||
294 | return 0; | ||
295 | } | ||
296 | |||
297 | static int __init alsa_gus_synth_init(void) | ||
298 | { | ||
299 | static struct snd_seq_dev_ops ops = { | ||
300 | snd_gus_synth_new_device, | ||
301 | snd_gus_synth_delete_device | ||
302 | }; | ||
303 | |||
304 | return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_GUS, &ops, | ||
305 | sizeof(struct snd_gus_card *)); | ||
306 | } | ||
307 | |||
308 | static void __exit alsa_gus_synth_exit(void) | ||
309 | { | ||
310 | snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_GUS); | ||
311 | } | ||
312 | |||
313 | module_init(alsa_gus_synth_init) | ||
314 | module_exit(alsa_gus_synth_exit) | ||
diff --git a/sound/pci/trident/Makefile b/sound/pci/trident/Makefile index 65f2c218324c..88676b50f385 100644 --- a/sound/pci/trident/Makefile +++ b/sound/pci/trident/Makefile | |||
@@ -4,16 +4,6 @@ | |||
4 | # | 4 | # |
5 | 5 | ||
6 | snd-trident-objs := trident.o trident_main.o trident_memory.o | 6 | snd-trident-objs := trident.o trident_main.o trident_memory.o |
7 | snd-trident-synth-objs := trident_synth.o | ||
8 | |||
9 | # | ||
10 | # this function returns: | ||
11 | # "m" - CONFIG_SND_SEQUENCER is m | ||
12 | # <empty string> - CONFIG_SND_SEQUENCER is undefined | ||
13 | # otherwise parameter #1 value | ||
14 | # | ||
15 | sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1))) | ||
16 | 7 | ||
17 | # Toplevel Module Dependency | 8 | # Toplevel Module Dependency |
18 | obj-$(CONFIG_SND_TRIDENT) += snd-trident.o | 9 | obj-$(CONFIG_SND_TRIDENT) += snd-trident.o |
19 | obj-$(call sequencer,$(CONFIG_SND_TRIDENT)) += snd-trident-synth.o | ||
diff --git a/sound/pci/trident/trident.c b/sound/pci/trident/trident.c index 84884567df6a..6193c7e4d798 100644 --- a/sound/pci/trident/trident.c +++ b/sound/pci/trident/trident.c | |||
@@ -155,13 +155,6 @@ static int __devinit snd_trident_probe(struct pci_dev *pci, | |||
155 | return err; | 155 | return err; |
156 | } | 156 | } |
157 | 157 | ||
158 | #if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE)) | ||
159 | if ((err = snd_trident_attach_synthesizer(trident)) < 0) { | ||
160 | snd_card_free(card); | ||
161 | return err; | ||
162 | } | ||
163 | #endif | ||
164 | |||
165 | snd_trident_create_gameport(trident); | 158 | snd_trident_create_gameport(trident); |
166 | 159 | ||
167 | if ((err = snd_card_register(card)) < 0) { | 160 | if ((err = snd_card_register(card)) < 0) { |
diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c index a235e034a690..59a319568ae5 100644 --- a/sound/pci/trident/trident_main.c +++ b/sound/pci/trident/trident_main.c | |||
@@ -3313,12 +3313,6 @@ static void snd_trident_proc_read(struct snd_info_entry *entry, | |||
3313 | snd_iprintf(buffer, "Memory Free : %d\n", snd_util_mem_avail(trident->tlb.memhdr)); | 3313 | snd_iprintf(buffer, "Memory Free : %d\n", snd_util_mem_avail(trident->tlb.memhdr)); |
3314 | } | 3314 | } |
3315 | } | 3315 | } |
3316 | #if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE)) | ||
3317 | snd_iprintf(buffer,"\nWavetable Synth\n"); | ||
3318 | snd_iprintf(buffer, "Memory Maximum : %d\n", trident->synth.max_size); | ||
3319 | snd_iprintf(buffer, "Memory Used : %d\n", trident->synth.current_size); | ||
3320 | snd_iprintf(buffer, "Memory Free : %d\n", (trident->synth.max_size-trident->synth.current_size)); | ||
3321 | #endif | ||
3322 | } | 3316 | } |
3323 | 3317 | ||
3324 | static void __devinit snd_trident_proc_init(struct snd_trident * trident) | 3318 | static void __devinit snd_trident_proc_init(struct snd_trident * trident) |
@@ -3815,28 +3809,6 @@ static irqreturn_t snd_trident_interrupt(int irq, void *dev_id) | |||
3815 | return IRQ_HANDLED; | 3809 | return IRQ_HANDLED; |
3816 | } | 3810 | } |
3817 | 3811 | ||
3818 | /*--------------------------------------------------------------------------- | ||
3819 | snd_trident_attach_synthesizer | ||
3820 | |||
3821 | Description: Attach synthesizer hooks | ||
3822 | |||
3823 | Paramters: trident - device specific private data for 4DWave card | ||
3824 | |||
3825 | Returns: None. | ||
3826 | |||
3827 | ---------------------------------------------------------------------------*/ | ||
3828 | int snd_trident_attach_synthesizer(struct snd_trident *trident) | ||
3829 | { | ||
3830 | #if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE)) | ||
3831 | if (snd_seq_device_new(trident->card, 1, SNDRV_SEQ_DEV_ID_TRIDENT, | ||
3832 | sizeof(struct snd_trident *), &trident->seq_dev) >= 0) { | ||
3833 | strcpy(trident->seq_dev->name, "4DWave"); | ||
3834 | *(struct snd_trident **)SNDRV_SEQ_DEVICE_ARGPTR(trident->seq_dev) = trident; | ||
3835 | } | ||
3836 | #endif | ||
3837 | return 0; | ||
3838 | } | ||
3839 | |||
3840 | struct snd_trident_voice *snd_trident_alloc_voice(struct snd_trident * trident, int type, int client, int port) | 3812 | struct snd_trident_voice *snd_trident_alloc_voice(struct snd_trident * trident, int type, int client, int port) |
3841 | { | 3813 | { |
3842 | struct snd_trident_voice *pvoice; | 3814 | struct snd_trident_voice *pvoice; |
diff --git a/sound/pci/trident/trident_synth.c b/sound/pci/trident/trident_synth.c deleted file mode 100644 index 9b7dee84743b..000000000000 --- a/sound/pci/trident/trident_synth.c +++ /dev/null | |||
@@ -1,1024 +0,0 @@ | |||
1 | /* | ||
2 | * Routines for Trident 4DWave NX/DX soundcards - Synthesizer | ||
3 | * Copyright (c) by Scott McNab <jedi@tartarus.uwa.edu.au> | ||
4 | * | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include <sound/driver.h> | ||
23 | #include <asm/io.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <linux/pci.h> | ||
27 | #include <sound/core.h> | ||
28 | #include <sound/trident.h> | ||
29 | #include <sound/seq_device.h> | ||
30 | |||
31 | MODULE_AUTHOR("Scott McNab <jedi@tartarus.uwa.edu.au>"); | ||
32 | MODULE_DESCRIPTION("Routines for Trident 4DWave NX/DX soundcards - Synthesizer"); | ||
33 | MODULE_LICENSE("GPL"); | ||
34 | |||
35 | /* linear to log pan conversion table (4.2 channel attenuation format) */ | ||
36 | static unsigned int pan_table[63] = { | ||
37 | 7959, 7733, 7514, 7301, 7093, 6892, 6697, 6507, | ||
38 | 6322, 6143, 5968, 5799, 5634, 5475, 5319, 5168, | ||
39 | 5022, 4879, 4741, 4606, 4475, 4349, 4225, 4105, | ||
40 | 3989, 3876, 3766, 3659, 3555, 3454, 3356, 3261, | ||
41 | 3168, 3078, 2991, 2906, 2824, 2744, 2666, 2590, | ||
42 | 2517, 2445, 2376, 2308, 2243, 2179, 2117, 2057, | ||
43 | 1999, 1942, 1887, 1833, 1781, 1731, 1682, 1634, | ||
44 | 1588, 1543, 1499, 1456, 1415, 1375, 1336 | ||
45 | }; | ||
46 | |||
47 | #define LOG_TABLE_SIZE 386 | ||
48 | |||
49 | /* Linear half-attenuation to log conversion table in the format: | ||
50 | * {linear volume, logarithmic attenuation equivalent}, ... | ||
51 | * | ||
52 | * Provides conversion from a linear half-volume value in the range | ||
53 | * [0,8192] to a logarithmic attenuation value in the range 0 to 6.02dB. | ||
54 | * Halving the linear volume is equivalent to an additional 6dB of | ||
55 | * logarithmic attenuation. The algorithm used in log_from_linear() | ||
56 | * therefore uses this table as follows: | ||
57 | * | ||
58 | * - loop and for every time the volume is less than half the maximum | ||
59 | * volume (16384), add another 6dB and halve the maximum value used | ||
60 | * for this comparison. | ||
61 | * - when the volume is greater than half the maximum volume, take | ||
62 | * the difference of the volume to half volume (in the range [0,8192]) | ||
63 | * and look up the log_table[] to find the nearest entry. | ||
64 | * - take the logarithic component of this entry and add it to the | ||
65 | * resulting attenuation. | ||
66 | * | ||
67 | * Thus this routine provides a linear->log conversion for a range of | ||
68 | * [0,16384] using only 386 table entries | ||
69 | * | ||
70 | * Note: although this table stores log attenuation in 8.8 format, values | ||
71 | * were only calculated for 6 bits fractional precision, since that is | ||
72 | * the most precision offered by the trident hardware. | ||
73 | */ | ||
74 | |||
75 | static unsigned short log_table[LOG_TABLE_SIZE*2] = | ||
76 | { | ||
77 | 4, 0x0604, 19, 0x0600, 34, 0x05fc, | ||
78 | 49, 0x05f8, 63, 0x05f4, 78, 0x05f0, 93, 0x05ec, 108, 0x05e8, | ||
79 | 123, 0x05e4, 138, 0x05e0, 153, 0x05dc, 168, 0x05d8, 183, 0x05d4, | ||
80 | 198, 0x05d0, 213, 0x05cc, 228, 0x05c8, 244, 0x05c4, 259, 0x05c0, | ||
81 | 274, 0x05bc, 289, 0x05b8, 304, 0x05b4, 320, 0x05b0, 335, 0x05ac, | ||
82 | 350, 0x05a8, 366, 0x05a4, 381, 0x05a0, 397, 0x059c, 412, 0x0598, | ||
83 | 428, 0x0594, 443, 0x0590, 459, 0x058c, 474, 0x0588, 490, 0x0584, | ||
84 | 506, 0x0580, 521, 0x057c, 537, 0x0578, 553, 0x0574, 568, 0x0570, | ||
85 | 584, 0x056c, 600, 0x0568, 616, 0x0564, 632, 0x0560, 647, 0x055c, | ||
86 | 663, 0x0558, 679, 0x0554, 695, 0x0550, 711, 0x054c, 727, 0x0548, | ||
87 | 743, 0x0544, 759, 0x0540, 776, 0x053c, 792, 0x0538, 808, 0x0534, | ||
88 | 824, 0x0530, 840, 0x052c, 857, 0x0528, 873, 0x0524, 889, 0x0520, | ||
89 | 906, 0x051c, 922, 0x0518, 938, 0x0514, 955, 0x0510, 971, 0x050c, | ||
90 | 988, 0x0508, 1004, 0x0504, 1021, 0x0500, 1037, 0x04fc, 1054, 0x04f8, | ||
91 | 1071, 0x04f4, 1087, 0x04f0, 1104, 0x04ec, 1121, 0x04e8, 1138, 0x04e4, | ||
92 | 1154, 0x04e0, 1171, 0x04dc, 1188, 0x04d8, 1205, 0x04d4, 1222, 0x04d0, | ||
93 | 1239, 0x04cc, 1256, 0x04c8, 1273, 0x04c4, 1290, 0x04c0, 1307, 0x04bc, | ||
94 | 1324, 0x04b8, 1341, 0x04b4, 1358, 0x04b0, 1376, 0x04ac, 1393, 0x04a8, | ||
95 | 1410, 0x04a4, 1427, 0x04a0, 1445, 0x049c, 1462, 0x0498, 1479, 0x0494, | ||
96 | 1497, 0x0490, 1514, 0x048c, 1532, 0x0488, 1549, 0x0484, 1567, 0x0480, | ||
97 | 1584, 0x047c, 1602, 0x0478, 1620, 0x0474, 1637, 0x0470, 1655, 0x046c, | ||
98 | 1673, 0x0468, 1690, 0x0464, 1708, 0x0460, 1726, 0x045c, 1744, 0x0458, | ||
99 | 1762, 0x0454, 1780, 0x0450, 1798, 0x044c, 1816, 0x0448, 1834, 0x0444, | ||
100 | 1852, 0x0440, 1870, 0x043c, 1888, 0x0438, 1906, 0x0434, 1924, 0x0430, | ||
101 | 1943, 0x042c, 1961, 0x0428, 1979, 0x0424, 1997, 0x0420, 2016, 0x041c, | ||
102 | 2034, 0x0418, 2053, 0x0414, 2071, 0x0410, 2089, 0x040c, 2108, 0x0408, | ||
103 | 2127, 0x0404, 2145, 0x0400, 2164, 0x03fc, 2182, 0x03f8, 2201, 0x03f4, | ||
104 | 2220, 0x03f0, 2239, 0x03ec, 2257, 0x03e8, 2276, 0x03e4, 2295, 0x03e0, | ||
105 | 2314, 0x03dc, 2333, 0x03d8, 2352, 0x03d4, 2371, 0x03d0, 2390, 0x03cc, | ||
106 | 2409, 0x03c8, 2428, 0x03c4, 2447, 0x03c0, 2466, 0x03bc, 2485, 0x03b8, | ||
107 | 2505, 0x03b4, 2524, 0x03b0, 2543, 0x03ac, 2562, 0x03a8, 2582, 0x03a4, | ||
108 | 2601, 0x03a0, 2621, 0x039c, 2640, 0x0398, 2660, 0x0394, 2679, 0x0390, | ||
109 | 2699, 0x038c, 2718, 0x0388, 2738, 0x0384, 2758, 0x0380, 2777, 0x037c, | ||
110 | 2797, 0x0378, 2817, 0x0374, 2837, 0x0370, 2857, 0x036c, 2876, 0x0368, | ||
111 | 2896, 0x0364, 2916, 0x0360, 2936, 0x035c, 2956, 0x0358, 2976, 0x0354, | ||
112 | 2997, 0x0350, 3017, 0x034c, 3037, 0x0348, 3057, 0x0344, 3077, 0x0340, | ||
113 | 3098, 0x033c, 3118, 0x0338, 3138, 0x0334, 3159, 0x0330, 3179, 0x032c, | ||
114 | 3200, 0x0328, 3220, 0x0324, 3241, 0x0320, 3261, 0x031c, 3282, 0x0318, | ||
115 | 3303, 0x0314, 3323, 0x0310, 3344, 0x030c, 3365, 0x0308, 3386, 0x0304, | ||
116 | 3406, 0x0300, 3427, 0x02fc, 3448, 0x02f8, 3469, 0x02f4, 3490, 0x02f0, | ||
117 | 3511, 0x02ec, 3532, 0x02e8, 3553, 0x02e4, 3575, 0x02e0, 3596, 0x02dc, | ||
118 | 3617, 0x02d8, 3638, 0x02d4, 3660, 0x02d0, 3681, 0x02cc, 3702, 0x02c8, | ||
119 | 3724, 0x02c4, 3745, 0x02c0, 3767, 0x02bc, 3788, 0x02b8, 3810, 0x02b4, | ||
120 | 3831, 0x02b0, 3853, 0x02ac, 3875, 0x02a8, 3896, 0x02a4, 3918, 0x02a0, | ||
121 | 3940, 0x029c, 3962, 0x0298, 3984, 0x0294, 4006, 0x0290, 4028, 0x028c, | ||
122 | 4050, 0x0288, 4072, 0x0284, 4094, 0x0280, 4116, 0x027c, 4138, 0x0278, | ||
123 | 4160, 0x0274, 4182, 0x0270, 4205, 0x026c, 4227, 0x0268, 4249, 0x0264, | ||
124 | 4272, 0x0260, 4294, 0x025c, 4317, 0x0258, 4339, 0x0254, 4362, 0x0250, | ||
125 | 4384, 0x024c, 4407, 0x0248, 4430, 0x0244, 4453, 0x0240, 4475, 0x023c, | ||
126 | 4498, 0x0238, 4521, 0x0234, 4544, 0x0230, 4567, 0x022c, 4590, 0x0228, | ||
127 | 4613, 0x0224, 4636, 0x0220, 4659, 0x021c, 4682, 0x0218, 4705, 0x0214, | ||
128 | 4728, 0x0210, 4752, 0x020c, 4775, 0x0208, 4798, 0x0204, 4822, 0x0200, | ||
129 | 4845, 0x01fc, 4869, 0x01f8, 4892, 0x01f4, 4916, 0x01f0, 4939, 0x01ec, | ||
130 | 4963, 0x01e8, 4987, 0x01e4, 5010, 0x01e0, 5034, 0x01dc, 5058, 0x01d8, | ||
131 | 5082, 0x01d4, 5106, 0x01d0, 5130, 0x01cc, 5154, 0x01c8, 5178, 0x01c4, | ||
132 | 5202, 0x01c0, 5226, 0x01bc, 5250, 0x01b8, 5274, 0x01b4, 5299, 0x01b0, | ||
133 | 5323, 0x01ac, 5347, 0x01a8, 5372, 0x01a4, 5396, 0x01a0, 5420, 0x019c, | ||
134 | 5445, 0x0198, 5469, 0x0194, 5494, 0x0190, 5519, 0x018c, 5543, 0x0188, | ||
135 | 5568, 0x0184, 5593, 0x0180, 5618, 0x017c, 5643, 0x0178, 5668, 0x0174, | ||
136 | 5692, 0x0170, 5717, 0x016c, 5743, 0x0168, 5768, 0x0164, 5793, 0x0160, | ||
137 | 5818, 0x015c, 5843, 0x0158, 5868, 0x0154, 5894, 0x0150, 5919, 0x014c, | ||
138 | 5945, 0x0148, 5970, 0x0144, 5995, 0x0140, 6021, 0x013c, 6047, 0x0138, | ||
139 | 6072, 0x0134, 6098, 0x0130, 6124, 0x012c, 6149, 0x0128, 6175, 0x0124, | ||
140 | 6201, 0x0120, 6227, 0x011c, 6253, 0x0118, 6279, 0x0114, 6305, 0x0110, | ||
141 | 6331, 0x010c, 6357, 0x0108, 6384, 0x0104, 6410, 0x0100, 6436, 0x00fc, | ||
142 | 6462, 0x00f8, 6489, 0x00f4, 6515, 0x00f0, 6542, 0x00ec, 6568, 0x00e8, | ||
143 | 6595, 0x00e4, 6621, 0x00e0, 6648, 0x00dc, 6675, 0x00d8, 6702, 0x00d4, | ||
144 | 6728, 0x00d0, 6755, 0x00cc, 6782, 0x00c8, 6809, 0x00c4, 6836, 0x00c0, | ||
145 | 6863, 0x00bc, 6890, 0x00b8, 6917, 0x00b4, 6945, 0x00b0, 6972, 0x00ac, | ||
146 | 6999, 0x00a8, 7027, 0x00a4, 7054, 0x00a0, 7081, 0x009c, 7109, 0x0098, | ||
147 | 7136, 0x0094, 7164, 0x0090, 7192, 0x008c, 7219, 0x0088, 7247, 0x0084, | ||
148 | 7275, 0x0080, 7303, 0x007c, 7331, 0x0078, 7359, 0x0074, 7387, 0x0070, | ||
149 | 7415, 0x006c, 7443, 0x0068, 7471, 0x0064, 7499, 0x0060, 7527, 0x005c, | ||
150 | 7556, 0x0058, 7584, 0x0054, 7613, 0x0050, 7641, 0x004c, 7669, 0x0048, | ||
151 | 7698, 0x0044, 7727, 0x0040, 7755, 0x003c, 7784, 0x0038, 7813, 0x0034, | ||
152 | 7842, 0x0030, 7870, 0x002c, 7899, 0x0028, 7928, 0x0024, 7957, 0x0020, | ||
153 | 7986, 0x001c, 8016, 0x0018, 8045, 0x0014, 8074, 0x0010, 8103, 0x000c, | ||
154 | 8133, 0x0008, 8162, 0x0004, 8192, 0x0000 | ||
155 | }; | ||
156 | |||
157 | static unsigned short lookup_volume_table( unsigned short value ) | ||
158 | { | ||
159 | /* This code is an optimised version of: | ||
160 | * int i = 0; | ||
161 | * while( volume_table[i*2] < value ) | ||
162 | * i++; | ||
163 | * return volume_table[i*2+1]; | ||
164 | */ | ||
165 | unsigned short *ptr = log_table; | ||
166 | while( *ptr < value ) | ||
167 | ptr += 2; | ||
168 | return *(ptr+1); | ||
169 | } | ||
170 | |||
171 | /* this function calculates a 8.8 fixed point logarithmic attenuation | ||
172 | * value from a linear volume value in the range 0 to 16384 */ | ||
173 | static unsigned short log_from_linear( unsigned short value ) | ||
174 | { | ||
175 | if (value >= 16384) | ||
176 | return 0x0000; | ||
177 | if (value) { | ||
178 | unsigned short result = 0; | ||
179 | int v, c; | ||
180 | for( c = 0, v = 8192; c < 14; c++, v >>= 1 ) { | ||
181 | if( value >= v ) { | ||
182 | result += lookup_volume_table( (value - v) << c ); | ||
183 | return result; | ||
184 | } | ||
185 | result += 0x0605; /* 6.0205 (result of -20*log10(0.5)) */ | ||
186 | } | ||
187 | } | ||
188 | return 0xffff; | ||
189 | } | ||
190 | |||
191 | /* | ||
192 | * Sample handling operations | ||
193 | */ | ||
194 | |||
195 | static void sample_start(struct snd_trident * trident, struct snd_trident_voice * voice, snd_seq_position_t position); | ||
196 | static void sample_stop(struct snd_trident * trident, struct snd_trident_voice * voice, int mode); | ||
197 | static void sample_freq(struct snd_trident * trident, struct snd_trident_voice * voice, snd_seq_frequency_t freq); | ||
198 | static void sample_volume(struct snd_trident * trident, struct snd_trident_voice * voice, struct snd_seq_ev_volume * volume); | ||
199 | static void sample_loop(struct snd_trident * trident, struct snd_trident_voice * voice, struct snd_seq_ev_loop * loop); | ||
200 | static void sample_pos(struct snd_trident * trident, struct snd_trident_voice * voice, snd_seq_position_t position); | ||
201 | static void sample_private1(struct snd_trident * trident, struct snd_trident_voice * voice, unsigned char *data); | ||
202 | |||
203 | static struct snd_trident_sample_ops sample_ops = | ||
204 | { | ||
205 | sample_start, | ||
206 | sample_stop, | ||
207 | sample_freq, | ||
208 | sample_volume, | ||
209 | sample_loop, | ||
210 | sample_pos, | ||
211 | sample_private1 | ||
212 | }; | ||
213 | |||
214 | static void snd_trident_simple_init(struct snd_trident_voice * voice) | ||
215 | { | ||
216 | //voice->handler_wave = interrupt_wave; | ||
217 | //voice->handler_volume = interrupt_volume; | ||
218 | //voice->handler_effect = interrupt_effect; | ||
219 | //voice->volume_change = NULL; | ||
220 | voice->sample_ops = &sample_ops; | ||
221 | } | ||
222 | |||
223 | static void sample_start(struct snd_trident * trident, struct snd_trident_voice * voice, snd_seq_position_t position) | ||
224 | { | ||
225 | struct simple_instrument *simple; | ||
226 | struct snd_seq_kinstr *instr; | ||
227 | unsigned long flags; | ||
228 | unsigned int loop_start, loop_end, sample_start, sample_end, start_offset; | ||
229 | unsigned int value; | ||
230 | unsigned int shift = 0; | ||
231 | |||
232 | instr = snd_seq_instr_find(trident->synth.ilist, &voice->instr, 0, 1); | ||
233 | if (instr == NULL) | ||
234 | return; | ||
235 | voice->instr = instr->instr; /* copy ID to speedup aliases */ | ||
236 | simple = KINSTR_DATA(instr); | ||
237 | |||
238 | spin_lock_irqsave(&trident->reg_lock, flags); | ||
239 | |||
240 | if (trident->device == TRIDENT_DEVICE_ID_SI7018) | ||
241 | voice->GVSel = 1; /* route to Wave volume */ | ||
242 | |||
243 | voice->CTRL = 0; | ||
244 | voice->Alpha = 0; | ||
245 | voice->FMS = 0; | ||
246 | |||
247 | loop_start = simple->loop_start >> 4; | ||
248 | loop_end = simple->loop_end >> 4; | ||
249 | sample_start = (simple->start + position) >> 4; | ||
250 | if( sample_start >= simple->size ) | ||
251 | sample_start = simple->start >> 4; | ||
252 | sample_end = simple->size; | ||
253 | start_offset = position >> 4; | ||
254 | |||
255 | if (simple->format & SIMPLE_WAVE_16BIT) { | ||
256 | voice->CTRL |= 8; | ||
257 | shift++; | ||
258 | } | ||
259 | if (simple->format & SIMPLE_WAVE_STEREO) { | ||
260 | voice->CTRL |= 4; | ||
261 | shift++; | ||
262 | } | ||
263 | if (!(simple->format & SIMPLE_WAVE_UNSIGNED)) | ||
264 | voice->CTRL |= 2; | ||
265 | |||
266 | voice->LBA = simple->address.memory; | ||
267 | |||
268 | if (simple->format & SIMPLE_WAVE_LOOP) { | ||
269 | voice->CTRL |= 1; | ||
270 | voice->LBA += loop_start << shift; | ||
271 | if( start_offset >= loop_start ) { | ||
272 | voice->CSO = start_offset - loop_start; | ||
273 | voice->negCSO = 0; | ||
274 | } else { | ||
275 | voice->CSO = loop_start - start_offset; | ||
276 | voice->negCSO = 1; | ||
277 | } | ||
278 | voice->ESO = loop_end - loop_start - 1; | ||
279 | } else { | ||
280 | voice->LBA += start_offset << shift; | ||
281 | voice->CSO = sample_start; | ||
282 | voice->ESO = sample_end - 1; | ||
283 | voice->negCSO = 0; | ||
284 | } | ||
285 | |||
286 | if (voice->flags & SNDRV_TRIDENT_VFLG_RUNNING) { | ||
287 | snd_trident_stop_voice(trident, voice->number); | ||
288 | voice->flags &= ~SNDRV_TRIDENT_VFLG_RUNNING; | ||
289 | } | ||
290 | |||
291 | /* set CSO sign */ | ||
292 | value = inl(TRID_REG(trident, T4D_SIGN_CSO_A)); | ||
293 | if( voice->negCSO ) { | ||
294 | value |= 1 << (voice->number&31); | ||
295 | } else { | ||
296 | value &= ~(1 << (voice->number&31)); | ||
297 | } | ||
298 | outl(value,TRID_REG(trident, T4D_SIGN_CSO_A)); | ||
299 | |||
300 | voice->Attribute = 0; | ||
301 | snd_trident_write_voice_regs(trident, voice); | ||
302 | snd_trident_start_voice(trident, voice->number); | ||
303 | voice->flags |= SNDRV_TRIDENT_VFLG_RUNNING; | ||
304 | spin_unlock_irqrestore(&trident->reg_lock, flags); | ||
305 | snd_seq_instr_free_use(trident->synth.ilist, instr); | ||
306 | } | ||
307 | |||
308 | static void sample_stop(struct snd_trident * trident, struct snd_trident_voice * voice, int mode) | ||
309 | { | ||
310 | unsigned long flags; | ||
311 | |||
312 | if (!(voice->flags & SNDRV_TRIDENT_VFLG_RUNNING)) | ||
313 | return; | ||
314 | |||
315 | switch (mode) { | ||
316 | default: | ||
317 | spin_lock_irqsave(&trident->reg_lock, flags); | ||
318 | snd_trident_stop_voice(trident, voice->number); | ||
319 | voice->flags &= ~SNDRV_TRIDENT_VFLG_RUNNING; | ||
320 | spin_unlock_irqrestore(&trident->reg_lock, flags); | ||
321 | break; | ||
322 | case SAMPLE_STOP_LOOP: /* disable loop only */ | ||
323 | voice->CTRL &= ~1; | ||
324 | spin_lock_irqsave(&trident->reg_lock, flags); | ||
325 | outb((unsigned char) voice->number, TRID_REG(trident, T4D_LFO_GC_CIR)); | ||
326 | outw((((voice->CTRL << 12) | (voice->EC & 0x0fff)) & 0xffff), CH_GVSEL_PAN_VOL_CTRL_EC); | ||
327 | spin_unlock_irqrestore(&trident->reg_lock, flags); | ||
328 | break; | ||
329 | } | ||
330 | } | ||
331 | |||
332 | static void sample_freq(struct snd_trident * trident, struct snd_trident_voice * voice, snd_seq_frequency_t freq) | ||
333 | { | ||
334 | unsigned long flags; | ||
335 | freq >>= 4; | ||
336 | |||
337 | spin_lock_irqsave(&trident->reg_lock, flags); | ||
338 | if (freq == 44100) | ||
339 | voice->Delta = 0xeb3; | ||
340 | else if (freq == 8000) | ||
341 | voice->Delta = 0x2ab; | ||
342 | else if (freq == 48000) | ||
343 | voice->Delta = 0x1000; | ||
344 | else | ||
345 | voice->Delta = (((freq << 12) + freq) / 48000) & 0x0000ffff; | ||
346 | |||
347 | outb((unsigned char) voice->number, TRID_REG(trident, T4D_LFO_GC_CIR)); | ||
348 | if (trident->device == TRIDENT_DEVICE_ID_NX) { | ||
349 | outb((unsigned char) voice->Delta, TRID_REG(trident, CH_NX_DELTA_CSO + 3)); | ||
350 | outb((unsigned char) (voice->Delta >> 8), TRID_REG(trident, CH_NX_DELTA_ESO + 3)); | ||
351 | } else { | ||
352 | outw((unsigned short) voice->Delta, TRID_REG(trident, CH_DX_ESO_DELTA)); | ||
353 | } | ||
354 | |||
355 | spin_unlock_irqrestore(&trident->reg_lock, flags); | ||
356 | } | ||
357 | |||
358 | static void sample_volume(struct snd_trident * trident, struct snd_trident_voice * voice, struct snd_seq_ev_volume * volume) | ||
359 | { | ||
360 | unsigned long flags; | ||
361 | unsigned short value; | ||
362 | |||
363 | spin_lock_irqsave(&trident->reg_lock, flags); | ||
364 | voice->GVSel = 0; /* use global music volume */ | ||
365 | voice->FMC = 0x03; /* fixme: can we do something useful with FMC? */ | ||
366 | if (volume->volume >= 0) { | ||
367 | volume->volume &= 0x3fff; | ||
368 | /* linear volume -> logarithmic attenuation conversion | ||
369 | * uses EC register for greater resolution (6.6 bits) than Vol register (5.3 bits) | ||
370 | * Vol register used when additional attenuation is required */ | ||
371 | voice->RVol = 0; | ||
372 | voice->CVol = 0; | ||
373 | value = log_from_linear( volume->volume ); | ||
374 | voice->Vol = 0; | ||
375 | voice->EC = (value & 0x3fff) >> 2; | ||
376 | if (value > 0x3fff) { | ||
377 | voice->EC |= 0xfc0; | ||
378 | if (value < 0x5f00 ) | ||
379 | voice->Vol = ((value >> 8) - 0x3f) << 5; | ||
380 | else { | ||
381 | voice->Vol = 0x3ff; | ||
382 | voice->EC = 0xfff; | ||
383 | } | ||
384 | } | ||
385 | } | ||
386 | if (volume->lr >= 0) { | ||
387 | volume->lr &= 0x3fff; | ||
388 | /* approximate linear pan by attenuating channels */ | ||
389 | if (volume->lr >= 0x2000) { /* attenuate left (pan right) */ | ||
390 | value = 0x3fff - volume->lr; | ||
391 | for (voice->Pan = 0; voice->Pan < 63; voice->Pan++ ) | ||
392 | if (value >= pan_table[voice->Pan] ) | ||
393 | break; | ||
394 | } else { /* attenuate right (pan left) */ | ||
395 | for (voice->Pan = 0; voice->Pan < 63; voice->Pan++ ) | ||
396 | if ((unsigned int)volume->lr >= pan_table[voice->Pan] ) | ||
397 | break; | ||
398 | voice->Pan |= 0x40; | ||
399 | } | ||
400 | } | ||
401 | outb((unsigned char) voice->number, TRID_REG(trident, T4D_LFO_GC_CIR)); | ||
402 | outl((voice->GVSel << 31) | ((voice->Pan & 0x0000007f) << 24) | | ||
403 | ((voice->Vol & 0x000000ff) << 16) | ((voice->CTRL & 0x0000000f) << 12) | | ||
404 | (voice->EC & 0x00000fff), TRID_REG(trident, CH_GVSEL_PAN_VOL_CTRL_EC)); | ||
405 | value = ((voice->FMC & 0x03) << 14) | ((voice->RVol & 0x7f) << 7) | (voice->CVol & 0x7f); | ||
406 | outw(value, TRID_REG(trident, CH_DX_FMC_RVOL_CVOL)); | ||
407 | spin_unlock_irqrestore(&trident->reg_lock, flags); | ||
408 | } | ||
409 | |||
410 | static void sample_loop(struct snd_trident * trident, struct snd_trident_voice * voice, struct snd_seq_ev_loop * loop) | ||
411 | { | ||
412 | unsigned long flags; | ||
413 | struct simple_instrument *simple; | ||
414 | struct snd_seq_kinstr *instr; | ||
415 | unsigned int loop_start, loop_end; | ||
416 | |||
417 | instr = snd_seq_instr_find(trident->synth.ilist, &voice->instr, 0, 1); | ||
418 | if (instr == NULL) | ||
419 | return; | ||
420 | voice->instr = instr->instr; /* copy ID to speedup aliases */ | ||
421 | simple = KINSTR_DATA(instr); | ||
422 | |||
423 | loop_start = loop->start >> 4; | ||
424 | loop_end = loop->end >> 4; | ||
425 | |||
426 | spin_lock_irqsave(&trident->reg_lock, flags); | ||
427 | |||
428 | voice->LBA = simple->address.memory + loop_start; | ||
429 | voice->CSO = 0; | ||
430 | voice->ESO = loop_end - loop_start - 1; | ||
431 | |||
432 | outb((unsigned char) voice->number, TRID_REG(trident, T4D_LFO_GC_CIR)); | ||
433 | outb((voice->LBA >> 16), TRID_REG(trident, CH_LBA + 2)); | ||
434 | outw((voice->LBA & 0xffff), TRID_REG(trident, CH_LBA)); | ||
435 | if (trident->device == TRIDENT_DEVICE_ID_NX) { | ||
436 | outb((voice->ESO >> 16), TRID_REG(trident, CH_NX_DELTA_ESO + 2)); | ||
437 | outw((voice->ESO & 0xffff), TRID_REG(trident, CH_NX_DELTA_ESO)); | ||
438 | outb((voice->CSO >> 16), TRID_REG(trident, CH_NX_DELTA_CSO + 2)); | ||
439 | outw((voice->CSO & 0xffff), TRID_REG(trident, CH_NX_DELTA_CSO)); | ||
440 | } else { | ||
441 | outw((voice->ESO & 0xffff), TRID_REG(trident, CH_DX_ESO_DELTA + 2)); | ||
442 | outw((voice->CSO & 0xffff), TRID_REG(trident, CH_DX_CSO_ALPHA_FMS + 2)); | ||
443 | } | ||
444 | |||
445 | spin_unlock_irqrestore(&trident->reg_lock, flags); | ||
446 | snd_seq_instr_free_use(trident->synth.ilist, instr); | ||
447 | } | ||
448 | |||
449 | static void sample_pos(struct snd_trident * trident, struct snd_trident_voice * voice, snd_seq_position_t position) | ||
450 | { | ||
451 | unsigned long flags; | ||
452 | struct simple_instrument *simple; | ||
453 | struct snd_seq_kinstr *instr; | ||
454 | unsigned int value; | ||
455 | |||
456 | instr = snd_seq_instr_find(trident->synth.ilist, &voice->instr, 0, 1); | ||
457 | if (instr == NULL) | ||
458 | return; | ||
459 | voice->instr = instr->instr; /* copy ID to speedup aliases */ | ||
460 | simple = KINSTR_DATA(instr); | ||
461 | |||
462 | spin_lock_irqsave(&trident->reg_lock, flags); | ||
463 | |||
464 | if (simple->format & SIMPLE_WAVE_LOOP) { | ||
465 | if( position >= simple->loop_start ) { | ||
466 | voice->CSO = (position - simple->loop_start) >> 4; | ||
467 | voice->negCSO = 0; | ||
468 | } else { | ||
469 | voice->CSO = (simple->loop_start - position) >> 4; | ||
470 | voice->negCSO = 1; | ||
471 | } | ||
472 | } else { | ||
473 | voice->CSO = position >> 4; | ||
474 | voice->negCSO = 0; | ||
475 | } | ||
476 | |||
477 | /* set CSO sign */ | ||
478 | value = inl(TRID_REG(trident, T4D_SIGN_CSO_A)); | ||
479 | if( voice->negCSO ) { | ||
480 | value |= 1 << (voice->number&31); | ||
481 | } else { | ||
482 | value &= ~(1 << (voice->number&31)); | ||
483 | } | ||
484 | outl(value,TRID_REG(trident, T4D_SIGN_CSO_A)); | ||
485 | |||
486 | |||
487 | outb((unsigned char) voice->number, TRID_REG(trident, T4D_LFO_GC_CIR)); | ||
488 | if (trident->device == TRIDENT_DEVICE_ID_NX) { | ||
489 | outw((voice->CSO & 0xffff), TRID_REG(trident, CH_NX_DELTA_CSO)); | ||
490 | outb((voice->CSO >> 16), TRID_REG(trident, CH_NX_DELTA_CSO + 2)); | ||
491 | } else { | ||
492 | outw((voice->CSO & 0xffff), TRID_REG(trident, CH_DX_CSO_ALPHA_FMS) + 2); | ||
493 | } | ||
494 | |||
495 | spin_unlock_irqrestore(&trident->reg_lock, flags); | ||
496 | snd_seq_instr_free_use(trident->synth.ilist, instr); | ||
497 | } | ||
498 | |||
499 | static void sample_private1(struct snd_trident * trident, struct snd_trident_voice * voice, unsigned char *data) | ||
500 | { | ||
501 | } | ||
502 | |||
503 | /* | ||
504 | * Memory management / sample loading | ||
505 | */ | ||
506 | |||
507 | static int snd_trident_simple_put_sample(void *private_data, | ||
508 | struct simple_instrument * instr, | ||
509 | char __user *data, long len, int atomic) | ||
510 | { | ||
511 | struct snd_trident *trident = private_data; | ||
512 | int size = instr->size; | ||
513 | int shift = 0; | ||
514 | |||
515 | if (instr->format & SIMPLE_WAVE_BACKWARD || | ||
516 | instr->format & SIMPLE_WAVE_BIDIR || | ||
517 | instr->format & SIMPLE_WAVE_ULAW) | ||
518 | return -EINVAL; /* not supported */ | ||
519 | |||
520 | if (instr->format & SIMPLE_WAVE_16BIT) | ||
521 | shift++; | ||
522 | if (instr->format & SIMPLE_WAVE_STEREO) | ||
523 | shift++; | ||
524 | size <<= shift; | ||
525 | |||
526 | if (trident->synth.current_size + size > trident->synth.max_size) | ||
527 | return -ENOMEM; | ||
528 | |||
529 | if (!access_ok(VERIFY_READ, data, size)) | ||
530 | return -EFAULT; | ||
531 | |||
532 | if (trident->tlb.entries) { | ||
533 | struct snd_util_memblk *memblk; | ||
534 | memblk = snd_trident_synth_alloc(trident, size); | ||
535 | if (memblk == NULL) | ||
536 | return -ENOMEM; | ||
537 | if (snd_trident_synth_copy_from_user(trident, memblk, 0, data, size) ) { | ||
538 | snd_trident_synth_free(trident, memblk); | ||
539 | return -EFAULT; | ||
540 | } | ||
541 | instr->address.ptr = (unsigned char*)memblk; | ||
542 | instr->address.memory = memblk->offset; | ||
543 | } else { | ||
544 | struct snd_dma_buffer dmab; | ||
545 | if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(trident->pci), | ||
546 | size, &dmab) < 0) | ||
547 | return -ENOMEM; | ||
548 | |||
549 | if (copy_from_user(dmab.area, data, size)) { | ||
550 | snd_dma_free_pages(&dmab); | ||
551 | return -EFAULT; | ||
552 | } | ||
553 | instr->address.ptr = dmab.area; | ||
554 | instr->address.memory = dmab.addr; | ||
555 | } | ||
556 | |||
557 | trident->synth.current_size += size; | ||
558 | return 0; | ||
559 | } | ||
560 | |||
561 | static int snd_trident_simple_get_sample(void *private_data, | ||
562 | struct simple_instrument * instr, | ||
563 | char __user *data, long len, int atomic) | ||
564 | { | ||
565 | //struct snd_trident *trident = private_data; | ||
566 | int size = instr->size; | ||
567 | int shift = 0; | ||
568 | |||
569 | if (instr->format & SIMPLE_WAVE_16BIT) | ||
570 | shift++; | ||
571 | if (instr->format & SIMPLE_WAVE_STEREO) | ||
572 | shift++; | ||
573 | size <<= shift; | ||
574 | |||
575 | if (!access_ok(VERIFY_WRITE, data, size)) | ||
576 | return -EFAULT; | ||
577 | |||
578 | /* FIXME: not implemented yet */ | ||
579 | |||
580 | return -EBUSY; | ||
581 | } | ||
582 | |||
583 | static int snd_trident_simple_remove_sample(void *private_data, | ||
584 | struct simple_instrument * instr, | ||
585 | int atomic) | ||
586 | { | ||
587 | struct snd_trident *trident = private_data; | ||
588 | int size = instr->size; | ||
589 | |||
590 | if (instr->format & SIMPLE_WAVE_16BIT) | ||
591 | size <<= 1; | ||
592 | if (instr->format & SIMPLE_WAVE_STEREO) | ||
593 | size <<= 1; | ||
594 | |||
595 | if (trident->tlb.entries) { | ||
596 | struct snd_util_memblk *memblk = (struct snd_util_memblk *)instr->address.ptr; | ||
597 | if (memblk) | ||
598 | snd_trident_synth_free(trident, memblk); | ||
599 | else | ||
600 | return -EFAULT; | ||
601 | } else { | ||
602 | struct snd_dma_buffer dmab; | ||
603 | dmab.dev.type = SNDRV_DMA_TYPE_DEV; | ||
604 | dmab.dev.dev = snd_dma_pci_data(trident->pci); | ||
605 | dmab.area = instr->address.ptr; | ||
606 | dmab.addr = instr->address.memory; | ||
607 | dmab.bytes = size; | ||
608 | snd_dma_free_pages(&dmab); | ||
609 | } | ||
610 | |||
611 | trident->synth.current_size -= size; | ||
612 | if (trident->synth.current_size < 0) /* shouldn't need this check... */ | ||
613 | trident->synth.current_size = 0; | ||
614 | |||
615 | return 0; | ||
616 | } | ||
617 | |||
618 | static void select_instrument(struct snd_trident * trident, struct snd_trident_voice * v) | ||
619 | { | ||
620 | struct snd_seq_kinstr *instr; | ||
621 | instr = snd_seq_instr_find(trident->synth.ilist, &v->instr, 0, 1); | ||
622 | if (instr != NULL) { | ||
623 | if (instr->ops) { | ||
624 | if (!strcmp(instr->ops->instr_type, SNDRV_SEQ_INSTR_ID_SIMPLE)) | ||
625 | snd_trident_simple_init(v); | ||
626 | } | ||
627 | snd_seq_instr_free_use(trident->synth.ilist, instr); | ||
628 | } | ||
629 | } | ||
630 | |||
631 | /* | ||
632 | |||
633 | */ | ||
634 | |||
635 | static void event_sample(struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v) | ||
636 | { | ||
637 | if (v->sample_ops && v->sample_ops->sample_stop) | ||
638 | v->sample_ops->sample_stop(p->trident, v, SAMPLE_STOP_IMMEDIATELY); | ||
639 | v->instr.std = ev->data.sample.param.sample.std; | ||
640 | if (v->instr.std & 0xff000000) { /* private instrument */ | ||
641 | v->instr.std &= 0x00ffffff; | ||
642 | v->instr.std |= (unsigned int)ev->source.client << 24; | ||
643 | } | ||
644 | v->instr.bank = ev->data.sample.param.sample.bank; | ||
645 | v->instr.prg = ev->data.sample.param.sample.prg; | ||
646 | select_instrument(p->trident, v); | ||
647 | } | ||
648 | |||
649 | static void event_cluster(struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v) | ||
650 | { | ||
651 | if (v->sample_ops && v->sample_ops->sample_stop) | ||
652 | v->sample_ops->sample_stop(p->trident, v, SAMPLE_STOP_IMMEDIATELY); | ||
653 | v->instr.cluster = ev->data.sample.param.cluster.cluster; | ||
654 | select_instrument(p->trident, v); | ||
655 | } | ||
656 | |||
657 | static void event_start(struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v) | ||
658 | { | ||
659 | if (v->sample_ops && v->sample_ops->sample_start) | ||
660 | v->sample_ops->sample_start(p->trident, v, ev->data.sample.param.position); | ||
661 | } | ||
662 | |||
663 | static void event_stop(struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v) | ||
664 | { | ||
665 | if (v->sample_ops && v->sample_ops->sample_stop) | ||
666 | v->sample_ops->sample_stop(p->trident, v, ev->data.sample.param.stop_mode); | ||
667 | } | ||
668 | |||
669 | static void event_freq(struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v) | ||
670 | { | ||
671 | if (v->sample_ops && v->sample_ops->sample_freq) | ||
672 | v->sample_ops->sample_freq(p->trident, v, ev->data.sample.param.frequency); | ||
673 | } | ||
674 | |||
675 | static void event_volume(struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v) | ||
676 | { | ||
677 | if (v->sample_ops && v->sample_ops->sample_volume) | ||
678 | v->sample_ops->sample_volume(p->trident, v, &ev->data.sample.param.volume); | ||
679 | } | ||
680 | |||
681 | static void event_loop(struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v) | ||
682 | { | ||
683 | if (v->sample_ops && v->sample_ops->sample_loop) | ||
684 | v->sample_ops->sample_loop(p->trident, v, &ev->data.sample.param.loop); | ||
685 | } | ||
686 | |||
687 | static void event_position(struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v) | ||
688 | { | ||
689 | if (v->sample_ops && v->sample_ops->sample_pos) | ||
690 | v->sample_ops->sample_pos(p->trident, v, ev->data.sample.param.position); | ||
691 | } | ||
692 | |||
693 | static void event_private1(struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v) | ||
694 | { | ||
695 | if (v->sample_ops && v->sample_ops->sample_private1) | ||
696 | v->sample_ops->sample_private1(p->trident, v, (unsigned char *) &ev->data.sample.param.raw8); | ||
697 | } | ||
698 | |||
699 | typedef void (trident_sample_event_handler_t) (struct snd_seq_event * ev, struct snd_trident_port * p, struct snd_trident_voice * v); | ||
700 | |||
701 | static trident_sample_event_handler_t *trident_sample_event_handlers[9] = | ||
702 | { | ||
703 | event_sample, | ||
704 | event_cluster, | ||
705 | event_start, | ||
706 | event_stop, | ||
707 | event_freq, | ||
708 | event_volume, | ||
709 | event_loop, | ||
710 | event_position, | ||
711 | event_private1 | ||
712 | }; | ||
713 | |||
714 | static void snd_trident_sample_event(struct snd_seq_event * ev, struct snd_trident_port * p) | ||
715 | { | ||
716 | int idx, voice; | ||
717 | struct snd_trident *trident = p->trident; | ||
718 | struct snd_trident_voice *v; | ||
719 | unsigned long flags; | ||
720 | |||
721 | idx = ev->type - SNDRV_SEQ_EVENT_SAMPLE; | ||
722 | if (idx < 0 || idx > 8) | ||
723 | return; | ||
724 | for (voice = 0; voice < 64; voice++) { | ||
725 | v = &trident->synth.voices[voice]; | ||
726 | if (v->use && v->client == ev->source.client && | ||
727 | v->port == ev->source.port && | ||
728 | v->index == ev->data.sample.channel) { | ||
729 | spin_lock_irqsave(&trident->event_lock, flags); | ||
730 | trident_sample_event_handlers[idx] (ev, p, v); | ||
731 | spin_unlock_irqrestore(&trident->event_lock, flags); | ||
732 | return; | ||
733 | } | ||
734 | } | ||
735 | } | ||
736 | |||
737 | /* | ||
738 | |||
739 | */ | ||
740 | |||
741 | static void snd_trident_synth_free_voices(struct snd_trident * trident, int client, int port) | ||
742 | { | ||
743 | int idx; | ||
744 | struct snd_trident_voice *voice; | ||
745 | |||
746 | for (idx = 0; idx < 32; idx++) { | ||
747 | voice = &trident->synth.voices[idx]; | ||
748 | if (voice->use && voice->client == client && voice->port == port) | ||
749 | snd_trident_free_voice(trident, voice); | ||
750 | } | ||
751 | } | ||
752 | |||
753 | static int snd_trident_synth_use(void *private_data, struct snd_seq_port_subscribe * info) | ||
754 | { | ||
755 | struct snd_trident_port *port = private_data; | ||
756 | struct snd_trident *trident = port->trident; | ||
757 | struct snd_trident_voice *voice; | ||
758 | unsigned int idx; | ||
759 | unsigned long flags; | ||
760 | |||
761 | if (info->voices > 32) | ||
762 | return -EINVAL; | ||
763 | spin_lock_irqsave(&trident->reg_lock, flags); | ||
764 | for (idx = 0; idx < info->voices; idx++) { | ||
765 | voice = snd_trident_alloc_voice(trident, SNDRV_TRIDENT_VOICE_TYPE_SYNTH, info->sender.client, info->sender.port); | ||
766 | if (voice == NULL) { | ||
767 | snd_trident_synth_free_voices(trident, info->sender.client, info->sender.port); | ||
768 | spin_unlock_irqrestore(&trident->reg_lock, flags); | ||
769 | return -EBUSY; | ||
770 | } | ||
771 | voice->index = idx; | ||
772 | voice->Vol = 0x3ff; | ||
773 | voice->EC = 0x0fff; | ||
774 | } | ||
775 | #if 0 | ||
776 | for (idx = 0; idx < info->midi_voices; idx++) { | ||
777 | port->midi_has_voices = 1; | ||
778 | voice = snd_trident_alloc_voice(trident, SNDRV_TRIDENT_VOICE_TYPE_MIDI, info->sender.client, info->sender.port); | ||
779 | if (voice == NULL) { | ||
780 | snd_trident_synth_free_voices(trident, info->sender.client, info->sender.port); | ||
781 | spin_unlock_irqrestore(&trident->reg_lock, flags); | ||
782 | return -EBUSY; | ||
783 | } | ||
784 | voice->Vol = 0x3ff; | ||
785 | voice->EC = 0x0fff; | ||
786 | } | ||
787 | #endif | ||
788 | spin_unlock_irqrestore(&trident->reg_lock, flags); | ||
789 | return 0; | ||
790 | } | ||
791 | |||
792 | static int snd_trident_synth_unuse(void *private_data, struct snd_seq_port_subscribe * info) | ||
793 | { | ||
794 | struct snd_trident_port *port = private_data; | ||
795 | struct snd_trident *trident = port->trident; | ||
796 | unsigned long flags; | ||
797 | |||
798 | spin_lock_irqsave(&trident->reg_lock, flags); | ||
799 | snd_trident_synth_free_voices(trident, info->sender.client, info->sender.port); | ||
800 | spin_unlock_irqrestore(&trident->reg_lock, flags); | ||
801 | return 0; | ||
802 | } | ||
803 | |||
804 | /* | ||
805 | |||
806 | */ | ||
807 | |||
808 | static void snd_trident_synth_free_private_instruments(struct snd_trident_port * p, int client) | ||
809 | { | ||
810 | struct snd_seq_instr_header ifree; | ||
811 | |||
812 | memset(&ifree, 0, sizeof(ifree)); | ||
813 | ifree.cmd = SNDRV_SEQ_INSTR_FREE_CMD_PRIVATE; | ||
814 | snd_seq_instr_list_free_cond(p->trident->synth.ilist, &ifree, client, 0); | ||
815 | } | ||
816 | |||
817 | static int snd_trident_synth_event_input(struct snd_seq_event * ev, int direct, void *private_data, int atomic, int hop) | ||
818 | { | ||
819 | struct snd_trident_port *p = (struct snd_trident_port *) private_data; | ||
820 | |||
821 | if (p == NULL) | ||
822 | return -EINVAL; | ||
823 | if (ev->type >= SNDRV_SEQ_EVENT_SAMPLE && | ||
824 | ev->type <= SNDRV_SEQ_EVENT_SAMPLE_PRIVATE1) { | ||
825 | snd_trident_sample_event(ev, p); | ||
826 | return 0; | ||
827 | } | ||
828 | if (ev->source.client == SNDRV_SEQ_CLIENT_SYSTEM && | ||
829 | ev->source.port == SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE) { | ||
830 | if (ev->type == SNDRV_SEQ_EVENT_CLIENT_EXIT) { | ||
831 | snd_trident_synth_free_private_instruments(p, ev->data.addr.client); | ||
832 | return 0; | ||
833 | } | ||
834 | } | ||
835 | if (direct) { | ||
836 | if (ev->type >= SNDRV_SEQ_EVENT_INSTR_BEGIN) { | ||
837 | snd_seq_instr_event(&p->trident->synth.simple_ops.kops, | ||
838 | p->trident->synth.ilist, ev, | ||
839 | p->trident->synth.seq_client, atomic, hop); | ||
840 | return 0; | ||
841 | } | ||
842 | } | ||
843 | return 0; | ||
844 | } | ||
845 | |||
846 | static void snd_trident_synth_instr_notify(void *private_data, | ||
847 | struct snd_seq_kinstr * instr, | ||
848 | int what) | ||
849 | { | ||
850 | int idx; | ||
851 | struct snd_trident *trident = private_data; | ||
852 | struct snd_trident_voice *pvoice; | ||
853 | unsigned long flags; | ||
854 | |||
855 | spin_lock_irqsave(&trident->event_lock, flags); | ||
856 | for (idx = 0; idx < 64; idx++) { | ||
857 | pvoice = &trident->synth.voices[idx]; | ||
858 | if (pvoice->use && !memcmp(&pvoice->instr, &instr->instr, sizeof(pvoice->instr))) { | ||
859 | if (pvoice->sample_ops && pvoice->sample_ops->sample_stop) { | ||
860 | pvoice->sample_ops->sample_stop(trident, pvoice, SAMPLE_STOP_IMMEDIATELY); | ||
861 | } else { | ||
862 | snd_trident_stop_voice(trident, pvoice->number); | ||
863 | pvoice->flags &= ~SNDRV_TRIDENT_VFLG_RUNNING; | ||
864 | } | ||
865 | } | ||
866 | } | ||
867 | spin_unlock_irqrestore(&trident->event_lock, flags); | ||
868 | } | ||
869 | |||
870 | /* | ||
871 | |||
872 | */ | ||
873 | |||
874 | static void snd_trident_synth_free_port(void *private_data) | ||
875 | { | ||
876 | struct snd_trident_port *p = (struct snd_trident_port *) private_data; | ||
877 | |||
878 | if (p) | ||
879 | snd_midi_channel_free_set(p->chset); | ||
880 | } | ||
881 | |||
882 | static int snd_trident_synth_create_port(struct snd_trident * trident, int idx) | ||
883 | { | ||
884 | struct snd_trident_port *p; | ||
885 | struct snd_seq_port_callback callbacks; | ||
886 | char name[32]; | ||
887 | char *str; | ||
888 | int result; | ||
889 | |||
890 | p = &trident->synth.seq_ports[idx]; | ||
891 | p->chset = snd_midi_channel_alloc_set(16); | ||
892 | if (p->chset == NULL) | ||
893 | return -ENOMEM; | ||
894 | p->chset->private_data = p; | ||
895 | p->trident = trident; | ||
896 | p->client = trident->synth.seq_client; | ||
897 | |||
898 | memset(&callbacks, 0, sizeof(callbacks)); | ||
899 | callbacks.owner = THIS_MODULE; | ||
900 | callbacks.use = snd_trident_synth_use; | ||
901 | callbacks.unuse = snd_trident_synth_unuse; | ||
902 | callbacks.event_input = snd_trident_synth_event_input; | ||
903 | callbacks.private_free = snd_trident_synth_free_port; | ||
904 | callbacks.private_data = p; | ||
905 | |||
906 | str = "???"; | ||
907 | switch (trident->device) { | ||
908 | case TRIDENT_DEVICE_ID_DX: str = "Trident 4DWave-DX"; break; | ||
909 | case TRIDENT_DEVICE_ID_NX: str = "Trident 4DWave-NX"; break; | ||
910 | case TRIDENT_DEVICE_ID_SI7018: str = "SiS 7018"; break; | ||
911 | } | ||
912 | sprintf(name, "%s port %i", str, idx); | ||
913 | p->chset->port = snd_seq_event_port_attach(trident->synth.seq_client, | ||
914 | &callbacks, | ||
915 | SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE, | ||
916 | SNDRV_SEQ_PORT_TYPE_DIRECT_SAMPLE | | ||
917 | SNDRV_SEQ_PORT_TYPE_SYNTH | | ||
918 | SNDRV_SEQ_PORT_TYPE_HARDWARE | | ||
919 | SNDRV_SEQ_PORT_TYPE_SYNTHESIZER, | ||
920 | 16, 0, | ||
921 | name); | ||
922 | if (p->chset->port < 0) { | ||
923 | result = p->chset->port; | ||
924 | snd_trident_synth_free_port(p); | ||
925 | return result; | ||
926 | } | ||
927 | p->port = p->chset->port; | ||
928 | return 0; | ||
929 | } | ||
930 | |||
931 | /* | ||
932 | |||
933 | */ | ||
934 | |||
935 | static int snd_trident_synth_new_device(struct snd_seq_device *dev) | ||
936 | { | ||
937 | struct snd_trident *trident; | ||
938 | int client, i; | ||
939 | struct snd_seq_port_subscribe sub; | ||
940 | struct snd_simple_ops *simpleops; | ||
941 | char *str; | ||
942 | |||
943 | trident = *(struct snd_trident **)SNDRV_SEQ_DEVICE_ARGPTR(dev); | ||
944 | if (trident == NULL) | ||
945 | return -EINVAL; | ||
946 | |||
947 | trident->synth.seq_client = -1; | ||
948 | |||
949 | /* allocate new client */ | ||
950 | str = "???"; | ||
951 | switch (trident->device) { | ||
952 | case TRIDENT_DEVICE_ID_DX: str = "Trident 4DWave-DX"; break; | ||
953 | case TRIDENT_DEVICE_ID_NX: str = "Trident 4DWave-NX"; break; | ||
954 | case TRIDENT_DEVICE_ID_SI7018: str = "SiS 7018"; break; | ||
955 | } | ||
956 | client = trident->synth.seq_client = | ||
957 | snd_seq_create_kernel_client(trident->card, 1, str); | ||
958 | if (client < 0) | ||
959 | return client; | ||
960 | |||
961 | for (i = 0; i < 4; i++) | ||
962 | snd_trident_synth_create_port(trident, i); | ||
963 | |||
964 | trident->synth.ilist = snd_seq_instr_list_new(); | ||
965 | if (trident->synth.ilist == NULL) { | ||
966 | snd_seq_delete_kernel_client(client); | ||
967 | trident->synth.seq_client = -1; | ||
968 | return -ENOMEM; | ||
969 | } | ||
970 | trident->synth.ilist->flags = SNDRV_SEQ_INSTR_FLG_DIRECT; | ||
971 | |||
972 | simpleops = &trident->synth.simple_ops; | ||
973 | snd_seq_simple_init(simpleops, trident, NULL); | ||
974 | simpleops->put_sample = snd_trident_simple_put_sample; | ||
975 | simpleops->get_sample = snd_trident_simple_get_sample; | ||
976 | simpleops->remove_sample = snd_trident_simple_remove_sample; | ||
977 | simpleops->notify = snd_trident_synth_instr_notify; | ||
978 | |||
979 | memset(&sub, 0, sizeof(sub)); | ||
980 | sub.sender.client = SNDRV_SEQ_CLIENT_SYSTEM; | ||
981 | sub.sender.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE; | ||
982 | sub.dest.client = client; | ||
983 | sub.dest.port = 0; | ||
984 | snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &sub); | ||
985 | |||
986 | return 0; | ||
987 | } | ||
988 | |||
989 | static int snd_trident_synth_delete_device(struct snd_seq_device *dev) | ||
990 | { | ||
991 | struct snd_trident *trident; | ||
992 | |||
993 | trident = *(struct snd_trident **)SNDRV_SEQ_DEVICE_ARGPTR(dev); | ||
994 | if (trident == NULL) | ||
995 | return -EINVAL; | ||
996 | |||
997 | if (trident->synth.seq_client >= 0) { | ||
998 | snd_seq_delete_kernel_client(trident->synth.seq_client); | ||
999 | trident->synth.seq_client = -1; | ||
1000 | } | ||
1001 | if (trident->synth.ilist) | ||
1002 | snd_seq_instr_list_free(&trident->synth.ilist); | ||
1003 | return 0; | ||
1004 | } | ||
1005 | |||
1006 | static int __init alsa_trident_synth_init(void) | ||
1007 | { | ||
1008 | static struct snd_seq_dev_ops ops = | ||
1009 | { | ||
1010 | snd_trident_synth_new_device, | ||
1011 | snd_trident_synth_delete_device | ||
1012 | }; | ||
1013 | |||
1014 | return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_TRIDENT, &ops, | ||
1015 | sizeof(struct snd_trident *)); | ||
1016 | } | ||
1017 | |||
1018 | static void __exit alsa_trident_synth_exit(void) | ||
1019 | { | ||
1020 | snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_TRIDENT); | ||
1021 | } | ||
1022 | |||
1023 | module_init(alsa_trident_synth_init) | ||
1024 | module_exit(alsa_trident_synth_exit) | ||