[ALSA] Changed Jaroslav Kysela's e-mail from perex@suse.cz to perex@perex.cz
[linux-2.6.git] / sound / core / seq / instr / ainstr_simple.c
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);