Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  1 /*
  2  *  Interface for OSS sequencer emulation
  3  *
  4  *  Copyright (C) 1999 Takashi Iwai <tiwai@suse.de>
  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  * Changes
 21  * 19990227   Steve Ratcliffe   Made separate file and merged in latest
 22  *                              midi emulation.
 23  */
 24 
 25 
 26 #ifdef CONFIG_SND_SEQUENCER_OSS
 27 
 28 #include <asm/uaccess.h>
 29 #include <sound/core.h>
 30 #include "emux_voice.h"
 31 #include <sound/asoundef.h>
 32 
 33 static int snd_emux_open_seq_oss(struct snd_seq_oss_arg *arg, void *closure);
 34 static int snd_emux_close_seq_oss(struct snd_seq_oss_arg *arg);
 35 static int snd_emux_ioctl_seq_oss(struct snd_seq_oss_arg *arg, unsigned int cmd,
 36                                   unsigned long ioarg);
 37 static int snd_emux_load_patch_seq_oss(struct snd_seq_oss_arg *arg, int format,
 38                                        const char __user *buf, int offs, int count);
 39 static int snd_emux_reset_seq_oss(struct snd_seq_oss_arg *arg);
 40 static int snd_emux_event_oss_input(struct snd_seq_event *ev, int direct,
 41                                     void *private, int atomic, int hop);
 42 static void reset_port_mode(struct snd_emux_port *port, int midi_mode);
 43 static void emuspec_control(struct snd_emux *emu, struct snd_emux_port *port,
 44                             int cmd, unsigned char *event, int atomic, int hop);
 45 static void gusspec_control(struct snd_emux *emu, struct snd_emux_port *port,
 46                             int cmd, unsigned char *event, int atomic, int hop);
 47 static void fake_event(struct snd_emux *emu, struct snd_emux_port *port,
 48                        int ch, int param, int val, int atomic, int hop);
 49 
 50 /* operators */
 51 static struct snd_seq_oss_callback oss_callback = {
 52         .owner = THIS_MODULE,
 53         .open = snd_emux_open_seq_oss,
 54         .close = snd_emux_close_seq_oss,
 55         .ioctl = snd_emux_ioctl_seq_oss,
 56         .load_patch = snd_emux_load_patch_seq_oss,
 57         .reset = snd_emux_reset_seq_oss,
 58 };
 59 
 60 
 61 /*
 62  * register OSS synth
 63  */
 64 
 65 void
 66 snd_emux_init_seq_oss(struct snd_emux *emu)
 67 {
 68         struct snd_seq_oss_reg *arg;
 69         struct snd_seq_device *dev;
 70 
 71         if (snd_seq_device_new(emu->card, 0, SNDRV_SEQ_DEV_ID_OSS,
 72                                sizeof(struct snd_seq_oss_reg), &dev) < 0)
 73                 return;
 74 
 75         emu->oss_synth = dev;
 76         strcpy(dev->name, emu->name);
 77         arg = SNDRV_SEQ_DEVICE_ARGPTR(dev);
 78         arg->type = SYNTH_TYPE_SAMPLE;
 79         arg->subtype = SAMPLE_TYPE_AWE32;
 80         arg->nvoices = emu->max_voices;
 81         arg->oper = oss_callback;
 82         arg->private_data = emu;
 83 
 84         /* register to OSS synth table */
 85         snd_device_register(emu->card, dev);
 86 }
 87 
 88 
 89 /*
 90  * unregister
 91  */
 92 void
 93 snd_emux_detach_seq_oss(struct snd_emux *emu)
 94 {
 95         if (emu->oss_synth) {
 96                 snd_device_free(emu->card, emu->oss_synth);
 97                 emu->oss_synth = NULL;
 98         }
 99 }
100 
101 
102 /* use port number as a unique soundfont client number */
103 #define SF_CLIENT_NO(p) ((p) + 0x1000)
104 
105 /*
106  * open port for OSS sequencer
107  */
108 static int
109 snd_emux_open_seq_oss(struct snd_seq_oss_arg *arg, void *closure)
110 {
111         struct snd_emux *emu;
112         struct snd_emux_port *p;
113         struct snd_seq_port_callback callback;
114         char tmpname[64];
115 
116         emu = closure;
117         if (snd_BUG_ON(!arg || !emu))
118                 return -ENXIO;
119 
120         mutex_lock(&emu->register_mutex);
121 
122         if (!snd_emux_inc_count(emu)) {
123                 mutex_unlock(&emu->register_mutex);
124                 return -EFAULT;
125         }
126 
127         memset(&callback, 0, sizeof(callback));
128         callback.owner = THIS_MODULE;
129         callback.event_input = snd_emux_event_oss_input;
130 
131         sprintf(tmpname, "%s OSS Port", emu->name);
132         p = snd_emux_create_port(emu, tmpname, 32,
133                                  1, &callback);
134         if (p == NULL) {
135                 snd_printk(KERN_ERR "can't create port\n");
136                 snd_emux_dec_count(emu);
137                 mutex_unlock(&emu->register_mutex);
138                 return -ENOMEM;
139         }
140 
141         /* fill the argument data */
142         arg->private_data = p;
143         arg->addr.client = p->chset.client;
144         arg->addr.port = p->chset.port;
145         p->oss_arg = arg;
146 
147         reset_port_mode(p, arg->seq_mode);
148 
149         snd_emux_reset_port(p);
150 
151         mutex_unlock(&emu->register_mutex);
152         return 0;
153 }
154 
155 
156 #define DEFAULT_DRUM_FLAGS      ((1<<9) | (1<<25))
157 
158 /*
159  * reset port mode
160  */
161 static void
162 reset_port_mode(struct snd_emux_port *port, int midi_mode)
163 {
164         if (midi_mode) {
165                 port->port_mode = SNDRV_EMUX_PORT_MODE_OSS_MIDI;
166                 port->drum_flags = DEFAULT_DRUM_FLAGS;
167                 port->volume_atten = 0;
168                 port->oss_arg->event_passing = SNDRV_SEQ_OSS_PROCESS_KEYPRESS;
169         } else {
170                 port->port_mode = SNDRV_EMUX_PORT_MODE_OSS_SYNTH;
171                 port->drum_flags = 0;
172                 port->volume_atten = 32;
173                 port->oss_arg->event_passing = SNDRV_SEQ_OSS_PROCESS_EVENTS;
174         }
175 }
176 
177 
178 /*
179  * close port
180  */
181 static int
182 snd_emux_close_seq_oss(struct snd_seq_oss_arg *arg)
183 {
184         struct snd_emux *emu;
185         struct snd_emux_port *p;
186 
187         if (snd_BUG_ON(!arg))
188                 return -ENXIO;
189         p = arg->private_data;
190         if (snd_BUG_ON(!p))
191                 return -ENXIO;
192 
193         emu = p->emu;
194         if (snd_BUG_ON(!emu))
195                 return -ENXIO;
196 
197         mutex_lock(&emu->register_mutex);
198         snd_emux_sounds_off_all(p);
199         snd_soundfont_close_check(emu->sflist, SF_CLIENT_NO(p->chset.port));
200         snd_seq_event_port_detach(p->chset.client, p->chset.port);
201         snd_emux_dec_count(emu);
202 
203         mutex_unlock(&emu->register_mutex);
204         return 0;
205 }
206 
207 
208 /*
209  * load patch
210  */
211 static int
212 snd_emux_load_patch_seq_oss(struct snd_seq_oss_arg *arg, int format,
213                             const char __user *buf, int offs, int count)
214 {
215         struct snd_emux *emu;
216         struct snd_emux_port *p;
217         int rc;
218 
219         if (snd_BUG_ON(!arg))
220                 return -ENXIO;
221         p = arg->private_data;
222         if (snd_BUG_ON(!p))
223                 return -ENXIO;
224 
225         emu = p->emu;
226         if (snd_BUG_ON(!emu))
227                 return -ENXIO;
228 
229         if (format == GUS_PATCH)
230                 rc = snd_soundfont_load_guspatch(emu->sflist, buf, count,
231                                                  SF_CLIENT_NO(p->chset.port));
232         else if (format == SNDRV_OSS_SOUNDFONT_PATCH) {
233                 struct soundfont_patch_info patch;
234                 if (count < (int)sizeof(patch))
235                         rc = -EINVAL;
236                 if (copy_from_user(&patch, buf, sizeof(patch)))
237                         rc = -EFAULT;
238                 if (patch.type >= SNDRV_SFNT_LOAD_INFO &&
239                     patch.type <= SNDRV_SFNT_PROBE_DATA)
240                         rc = snd_soundfont_load(emu->sflist, buf, count, SF_CLIENT_NO(p->chset.port));
241                 else {
242                         if (emu->ops.load_fx)
243                                 rc = emu->ops.load_fx(emu, patch.type, patch.optarg, buf, count);
244                         else
245                                 rc = -EINVAL;
246                 }
247         } else
248                 rc = 0;
249         return rc;
250 }
251 
252 
253 /*
254  * ioctl
255  */
256 static int
257 snd_emux_ioctl_seq_oss(struct snd_seq_oss_arg *arg, unsigned int cmd, unsigned long ioarg)
258 {
259         struct snd_emux_port *p;
260         struct snd_emux *emu;
261 
262         if (snd_BUG_ON(!arg))
263                 return -ENXIO;
264         p = arg->private_data;
265         if (snd_BUG_ON(!p))
266                 return -ENXIO;
267 
268         emu = p->emu;
269         if (snd_BUG_ON(!emu))
270                 return -ENXIO;
271 
272         switch (cmd) {
273         case SNDCTL_SEQ_RESETSAMPLES:
274                 snd_soundfont_remove_samples(emu->sflist);
275                 return 0;
276                         
277         case SNDCTL_SYNTH_MEMAVL:
278                 if (emu->memhdr)
279                         return snd_util_mem_avail(emu->memhdr);
280                 return 0;
281         }
282 
283         return 0;
284 }
285 
286 
287 /*
288  * reset device
289  */
290 static int
291 snd_emux_reset_seq_oss(struct snd_seq_oss_arg *arg)
292 {
293         struct snd_emux_port *p;
294 
295         if (snd_BUG_ON(!arg))
296                 return -ENXIO;
297         p = arg->private_data;
298         if (snd_BUG_ON(!p))
299                 return -ENXIO;
300         snd_emux_reset_port(p);
301         return 0;
302 }
303 
304 
305 /*
306  * receive raw events: only SEQ_PRIVATE is accepted.
307  */
308 static int
309 snd_emux_event_oss_input(struct snd_seq_event *ev, int direct, void *private_data,
310                          int atomic, int hop)
311 {
312         struct snd_emux *emu;
313         struct snd_emux_port *p;
314         unsigned char cmd, *data;
315 
316         p = private_data;
317         if (snd_BUG_ON(!p))
318                 return -EINVAL;
319         emu = p->emu;
320         if (snd_BUG_ON(!emu))
321                 return -EINVAL;
322         if (ev->type != SNDRV_SEQ_EVENT_OSS)
323                 return snd_emux_event_input(ev, direct, private_data, atomic, hop);
324 
325         data = ev->data.raw8.d;
326         /* only SEQ_PRIVATE is accepted */
327         if (data[0] != 0xfe)
328                 return 0;
329         cmd = data[2] & _EMUX_OSS_MODE_VALUE_MASK;
330         if (data[2] & _EMUX_OSS_MODE_FLAG)
331                 emuspec_control(emu, p, cmd, data, atomic, hop);
332         else
333                 gusspec_control(emu, p, cmd, data, atomic, hop);
334         return 0;
335 }
336 
337 
338 /*
339  * OSS/AWE driver specific h/w controls
340  */
341 static void
342 emuspec_control(struct snd_emux *emu, struct snd_emux_port *port, int cmd,
343                 unsigned char *event, int atomic, int hop)
344 {
345         int voice;
346         unsigned short p1;
347         short p2;
348         int i;
349         struct snd_midi_channel *chan;
350 
351         voice = event[3];
352         if (voice < 0 || voice >= port->chset.max_channels)
353                 chan = NULL;
354         else
355                 chan = &port->chset.channels[voice];
356 
357         p1 = *(unsigned short *) &event[4];
358         p2 = *(short *) &event[6];
359 
360         switch (cmd) {
361 #if 0 /* don't do this atomically */
362         case _EMUX_OSS_REMOVE_LAST_SAMPLES:
363                 snd_soundfont_remove_unlocked(emu->sflist);
364                 break;
365 #endif
366         case _EMUX_OSS_SEND_EFFECT:
367                 if (chan)
368                         snd_emux_send_effect_oss(port, chan, p1, p2);
369                 break;
370                 
371         case _EMUX_OSS_TERMINATE_ALL:
372                 snd_emux_terminate_all(emu);
373                 break;
374 
375         case _EMUX_OSS_TERMINATE_CHANNEL:
376                 /*snd_emux_mute_channel(emu, chan);*/
377                 break;
378         case _EMUX_OSS_RESET_CHANNEL:
379                 /*snd_emux_channel_init(chset, chan);*/
380                 break;
381 
382         case _EMUX_OSS_RELEASE_ALL:
383                 fake_event(emu, port, voice, MIDI_CTL_ALL_NOTES_OFF, 0, atomic, hop);
384                 break;
385         case _EMUX_OSS_NOTEOFF_ALL:
386                 fake_event(emu, port, voice, MIDI_CTL_ALL_SOUNDS_OFF, 0, atomic, hop);
387                 break;
388 
389         case _EMUX_OSS_INITIAL_VOLUME:
390                 if (p2) {
391                         port->volume_atten = (short)p1;
392                         snd_emux_update_port(port, SNDRV_EMUX_UPDATE_VOLUME);
393                 }
394                 break;
395 
396         case _EMUX_OSS_CHN_PRESSURE:
397                 if (chan) {
398                         chan->midi_pressure = p1;
399                         snd_emux_update_channel(port, chan, SNDRV_EMUX_UPDATE_FMMOD|SNDRV_EMUX_UPDATE_FM2FRQ2);
400                 }
401                 break;
402 
403         case _EMUX_OSS_CHANNEL_MODE:
404                 reset_port_mode(port, p1);
405                 snd_emux_reset_port(port);
406                 break;
407 
408         case _EMUX_OSS_DRUM_CHANNELS:
409                 port->drum_flags = *(unsigned int*)&event[4];
410                 for (i = 0; i < port->chset.max_channels; i++) {
411                         chan = &port->chset.channels[i];
412                         chan->drum_channel = ((port->drum_flags >> i) & 1) ? 1 : 0;
413                 }
414                 break;
415 
416         case _EMUX_OSS_MISC_MODE:
417                 if (p1 < EMUX_MD_END)
418                         port->ctrls[p1] = p2;
419                 break;
420         case _EMUX_OSS_DEBUG_MODE:
421                 break;
422 
423         default:
424                 if (emu->ops.oss_ioctl)
425                         emu->ops.oss_ioctl(emu, cmd, p1, p2);
426                 break;
427         }
428 }
429 
430 /*
431  * GUS specific h/w controls
432  */
433 
434 #include <linux/ultrasound.h>
435 
436 static void
437 gusspec_control(struct snd_emux *emu, struct snd_emux_port *port, int cmd,
438                 unsigned char *event, int atomic, int hop)
439 {
440         int voice;
441         unsigned short p1;
442         short p2;
443         int plong;
444         struct snd_midi_channel *chan;
445 
446         if (port->port_mode != SNDRV_EMUX_PORT_MODE_OSS_SYNTH)
447                 return;
448         if (cmd == _GUS_NUMVOICES)
449                 return;
450         voice = event[3];
451         if (voice < 0 || voice >= port->chset.max_channels)
452                 return;
453 
454         chan = &port->chset.channels[voice];
455 
456         p1 = *(unsigned short *) &event[4];
457         p2 = *(short *) &event[6];
458         plong = *(int*) &event[4];
459 
460         switch (cmd) {
461         case _GUS_VOICESAMPLE:
462                 chan->midi_program = p1;
463                 return;
464 
465         case _GUS_VOICEBALA:
466                 /* 0 to 15 --> 0 to 127 */
467                 chan->control[MIDI_CTL_MSB_PAN] = (int)p1 << 3;
468                 snd_emux_update_channel(port, chan, SNDRV_EMUX_UPDATE_PAN);
469                 return;
470 
471         case _GUS_VOICEVOL:
472         case _GUS_VOICEVOL2:
473                 /* not supported yet */
474                 return;
475 
476         case _GUS_RAMPRANGE:
477         case _GUS_RAMPRATE:
478         case _GUS_RAMPMODE:
479         case _GUS_RAMPON:
480         case _GUS_RAMPOFF:
481                 /* volume ramping not supported */
482                 return;
483 
484         case _GUS_VOLUME_SCALE:
485                 return;
486 
487         case _GUS_VOICE_POS:
488 #ifdef SNDRV_EMUX_USE_RAW_EFFECT
489                 snd_emux_send_effect(port, chan, EMUX_FX_SAMPLE_START,
490                                      (short)(plong & 0x7fff),
491                                      EMUX_FX_FLAG_SET);
492                 snd_emux_send_effect(port, chan, EMUX_FX_COARSE_SAMPLE_START,
493                                      (plong >> 15) & 0xffff,
494                                      EMUX_FX_FLAG_SET);
495 #endif
496                 return;
497         }
498 }
499 
500 
501 /*
502  * send an event to midi emulation
503  */
504 static void
505 fake_event(struct snd_emux *emu, struct snd_emux_port *port, int ch, int param, int val, int atomic, int hop)
506 {
507         struct snd_seq_event ev;
508         memset(&ev, 0, sizeof(ev));
509         ev.type = SNDRV_SEQ_EVENT_CONTROLLER;
510         ev.data.control.channel = ch;
511         ev.data.control.param = param;
512         ev.data.control.value = val;
513         snd_emux_event_input(&ev, 0, port, atomic, hop);
514 }
515 
516 #endif /* CONFIG_SND_SEQUENCER_OSS */
517 
  This page was automatically generated by the LXR engine.