[PATCH] gfp_t: sound
[linux-2.6] / sound / core / seq / instr / ainstr_simple.c
1 /*
2  *   Simple (MOD player) - Instrument routines
3  *   Copyright (c) 1999 by Jaroslav Kysela <perex@suse.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/sched.h>
24 #include <linux/slab.h>
25 #include <sound/core.h>
26 #include <sound/ainstr_simple.h>
27 #include <sound/initval.h>
28 #include <asm/uaccess.h>
29
30 MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
31 MODULE_DESCRIPTION("Advanced Linux Sound Architecture Simple Instrument support.");
32 MODULE_LICENSE("GPL");
33
34 static unsigned int snd_seq_simple_size(unsigned int size, unsigned int format)
35 {
36         unsigned int result = size;
37         
38         if (format & SIMPLE_WAVE_16BIT)
39                 result <<= 1;
40         if (format & SIMPLE_WAVE_STEREO)
41                 result <<= 1;
42         return result;
43 }
44
45 static void snd_seq_simple_instr_free(snd_simple_ops_t *ops,
46                                       simple_instrument_t *ip,
47                                       int atomic)
48 {
49         if (ops->remove_sample)
50                 ops->remove_sample(ops->private_data, ip, atomic);
51 }
52
53 static int snd_seq_simple_put(void *private_data, snd_seq_kinstr_t *instr,
54                               char __user *instr_data, long len,
55                               int atomic, int cmd)
56 {
57         snd_simple_ops_t *ops = (snd_simple_ops_t *)private_data;
58         simple_instrument_t *ip;
59         simple_xinstrument_t ix;
60         int err;
61         gfp_t gfp_mask;
62         unsigned int real_size;
63
64         if (cmd != SNDRV_SEQ_INSTR_PUT_CMD_CREATE)
65                 return -EINVAL;
66         gfp_mask = atomic ? GFP_ATOMIC : GFP_KERNEL;
67         /* copy instrument data */
68         if (len < (long)sizeof(ix))
69                 return -EINVAL;
70         if (copy_from_user(&ix, instr_data, sizeof(ix)))
71                 return -EFAULT;
72         if (ix.stype != SIMPLE_STRU_INSTR)
73                 return -EINVAL;
74         instr_data += sizeof(ix);
75         len -= sizeof(ix);
76         ip = (simple_instrument_t *)KINSTR_DATA(instr);
77         ip->share_id[0] = le32_to_cpu(ix.share_id[0]);
78         ip->share_id[1] = le32_to_cpu(ix.share_id[1]);
79         ip->share_id[2] = le32_to_cpu(ix.share_id[2]);
80         ip->share_id[3] = le32_to_cpu(ix.share_id[3]);
81         ip->format = le32_to_cpu(ix.format);
82         ip->size = le32_to_cpu(ix.size);
83         ip->start = le32_to_cpu(ix.start);
84         ip->loop_start = le32_to_cpu(ix.loop_start);
85         ip->loop_end = le32_to_cpu(ix.loop_end);
86         ip->loop_repeat = le16_to_cpu(ix.loop_repeat);
87         ip->effect1 = ix.effect1;
88         ip->effect1_depth = ix.effect1_depth;
89         ip->effect2 = ix.effect2;
90         ip->effect2_depth = ix.effect2_depth;
91         real_size = snd_seq_simple_size(ip->size, ip->format);
92         if (len < (long)real_size)
93                 return -EINVAL;
94         if (ops->put_sample) {
95                 err = ops->put_sample(ops->private_data, ip,
96                                       instr_data, real_size, atomic);
97                 if (err < 0)
98                         return err;
99         }
100         return 0;
101 }
102
103 static int snd_seq_simple_get(void *private_data, snd_seq_kinstr_t *instr,
104                               char __user *instr_data, long len,
105                               int atomic, int cmd)
106 {
107         snd_simple_ops_t *ops = (snd_simple_ops_t *)private_data;
108         simple_instrument_t *ip;
109         simple_xinstrument_t ix;
110         int err;
111         unsigned int real_size;
112         
113         if (cmd != SNDRV_SEQ_INSTR_GET_CMD_FULL)
114                 return -EINVAL;
115         if (len < (long)sizeof(ix))
116                 return -ENOMEM;
117         memset(&ix, 0, sizeof(ix));
118         ip = (simple_instrument_t *)KINSTR_DATA(instr);
119         ix.stype = SIMPLE_STRU_INSTR;
120         ix.share_id[0] = cpu_to_le32(ip->share_id[0]);
121         ix.share_id[1] = cpu_to_le32(ip->share_id[1]);
122         ix.share_id[2] = cpu_to_le32(ip->share_id[2]);
123         ix.share_id[3] = cpu_to_le32(ip->share_id[3]);
124         ix.format = cpu_to_le32(ip->format);
125         ix.size = cpu_to_le32(ip->size);
126         ix.start = cpu_to_le32(ip->start);
127         ix.loop_start = cpu_to_le32(ip->loop_start);
128         ix.loop_end = cpu_to_le32(ip->loop_end);
129         ix.loop_repeat = cpu_to_le32(ip->loop_repeat);
130         ix.effect1 = cpu_to_le16(ip->effect1);
131         ix.effect1_depth = cpu_to_le16(ip->effect1_depth);
132         ix.effect2 = ip->effect2;
133         ix.effect2_depth = ip->effect2_depth;
134         if (copy_to_user(instr_data, &ix, sizeof(ix)))
135                 return -EFAULT;
136         instr_data += sizeof(ix);
137         len -= sizeof(ix);
138         real_size = snd_seq_simple_size(ip->size, ip->format);
139         if (len < (long)real_size)
140                 return -ENOMEM;
141         if (ops->get_sample) {
142                 err = ops->get_sample(ops->private_data, ip,
143                                       instr_data, real_size, atomic);
144                 if (err < 0)
145                         return err;
146         }
147         return 0;
148 }
149
150 static int snd_seq_simple_get_size(void *private_data, snd_seq_kinstr_t *instr,
151                                    long *size)
152 {
153         simple_instrument_t *ip;
154
155         ip = (simple_instrument_t *)KINSTR_DATA(instr);
156         *size = sizeof(simple_xinstrument_t) + snd_seq_simple_size(ip->size, ip->format);
157         return 0;
158 }
159
160 static int snd_seq_simple_remove(void *private_data,
161                                  snd_seq_kinstr_t *instr,
162                                  int atomic)
163 {
164         snd_simple_ops_t *ops = (snd_simple_ops_t *)private_data;
165         simple_instrument_t *ip;
166
167         ip = (simple_instrument_t *)KINSTR_DATA(instr);
168         snd_seq_simple_instr_free(ops, ip, atomic);
169         return 0;
170 }
171
172 static void snd_seq_simple_notify(void *private_data,
173                                   snd_seq_kinstr_t *instr,
174                                   int what)
175 {
176         snd_simple_ops_t *ops = (snd_simple_ops_t *)private_data;
177
178         if (ops->notify)
179                 ops->notify(ops->private_data, instr, what);
180 }
181
182 int snd_seq_simple_init(snd_simple_ops_t *ops,
183                         void *private_data,
184                         snd_seq_kinstr_ops_t *next)
185 {
186         memset(ops, 0, sizeof(*ops));
187         ops->private_data = private_data;
188         ops->kops.private_data = ops;
189         ops->kops.add_len = sizeof(simple_instrument_t);
190         ops->kops.instr_type = SNDRV_SEQ_INSTR_ID_SIMPLE;
191         ops->kops.put = snd_seq_simple_put;
192         ops->kops.get = snd_seq_simple_get;
193         ops->kops.get_size = snd_seq_simple_get_size;
194         ops->kops.remove = snd_seq_simple_remove;
195         ops->kops.notify = snd_seq_simple_notify;
196         ops->kops.next = next;
197         return 0;
198 }
199
200 /*
201  *  Init part
202  */
203
204 static int __init alsa_ainstr_simple_init(void)
205 {
206         return 0;
207 }
208
209 static void __exit alsa_ainstr_simple_exit(void)
210 {
211 }
212
213 module_init(alsa_ainstr_simple_init)
214 module_exit(alsa_ainstr_simple_exit)
215
216 EXPORT_SYMBOL(snd_seq_simple_init);