static int insert_queue(struct seq_oss_devinfo *dp, union evrec *rec, struct file *opt) { int rc = 0; struct snd_seq_event event; /* if this is a timing event, process the current time */ if (snd_seq_oss_process_timer_event(dp->timer, rec)) return 0; /* no need to insert queue */ /* parse this event */ memset(&event, 0, sizeof(event)); /* set dummy -- to be sure */ event.type = SNDRV_SEQ_EVENT_NOTEOFF; snd_seq_oss_fill_addr(dp, &event, dp->addr.port, dp->addr.client); if (snd_seq_oss_process_event(dp, rec, &event)) return 0; /* invalid event - no need to insert queue */ event.time.tick = snd_seq_oss_timer_cur_tick(dp->timer); if (dp->timer->realtime || !dp->timer->running) { snd_seq_oss_dispatch(dp, &event, 0, 0); } else { if (is_nonblock_mode(dp->file_mode)) rc = snd_seq_kernel_client_enqueue(dp->cseq, &event, 0, 0); else rc = snd_seq_kernel_client_enqueue_blocking(dp->cseq, &event, opt, 0, 0); } return rc; }
/* * fill the event source/destination addresses */ int snd_seq_oss_synth_addr(seq_oss_devinfo_t *dp, int dev, snd_seq_event_t *ev) { if (! snd_seq_oss_synth_is_valid(dp, dev)) return -EINVAL; snd_seq_oss_fill_addr(dp, ev, dp->synths[dev].arg.addr.client, dp->synths[dev].arg.addr.port); return 0; }
/* * create an echo event */ static int set_echo_event(seq_oss_devinfo_t *dp, evrec_t *rec, snd_seq_event_t *ev) { ev->type = SNDRV_SEQ_EVENT_ECHO; /* echo back to itself */ snd_seq_oss_fill_addr(dp, ev, dp->addr.client, dp->addr.port); memcpy(&ev->data, rec, LONG_EVENT_SIZE); return 0; }
/* * wait until the write buffer has enough room */ int snd_seq_oss_writeq_sync(seq_oss_writeq_t *q) { seq_oss_devinfo_t *dp = q->dp; abstime_t time; unsigned long flags; time = snd_seq_oss_timer_cur_tick(dp->timer); if (q->sync_time >= time) return 0; /* already finished */ if (! q->sync_event_put) { snd_seq_event_t ev; evrec_t *rec; /* put echoback event */ memset(&ev, 0, sizeof(ev)); ev.flags = 0; ev.type = SNDRV_SEQ_EVENT_ECHO; ev.time.tick = time; /* echo back to itself */ snd_seq_oss_fill_addr(dp, &ev, dp->addr.client, dp->addr.port); rec = (evrec_t*)&ev.data; rec->t.code = SEQ_SYNCTIMER; rec->t.time = time; q->sync_event_put = 1; snd_seq_kernel_client_enqueue_blocking(dp->cseq, &ev, NULL, 0, 0); } spin_lock_irqsave(&q->sync_lock, flags); if (! q->sync_event_put) { /* echoback event has been received */ spin_unlock_irqrestore(&q->sync_lock, flags); return 0; } /* wait for echo event */ spin_unlock(&q->sync_lock); interruptible_sleep_on_timeout(&q->sync_sleep, HZ); spin_lock(&q->sync_lock); if (signal_pending(current)) { /* interrupted - return 0 to finish sync */ q->sync_event_put = 0; spin_unlock_irqrestore(&q->sync_lock, flags); return 0; } spin_unlock_irqrestore(&q->sync_lock, flags); if (q->sync_time >= time) return 0; else return 1; }
/* * reset synth device: * call reset callback. if no callback is defined, send a heartbeat * event to the corresponding port. */ void snd_seq_oss_synth_reset(seq_oss_devinfo_t *dp, int dev) { seq_oss_synth_t *rec; seq_oss_synthinfo_t *info; snd_assert(dev >= 0 && dev < dp->max_synthdev, return); info = &dp->synths[dev]; if (! info->opened) return; if (info->sysex) info->sysex->len = 0; /* reset sysex */ reset_channels(info); if (info->is_midi) { if (midi_synth_dev.opened <= 0) return; snd_seq_oss_midi_reset(dp, info->midi_mapped); /* reopen the device */ snd_seq_oss_midi_close(dp, dev); if (snd_seq_oss_midi_open(dp, info->midi_mapped, dp->file_mode) < 0) { midi_synth_dev.opened--; info->opened = 0; if (info->sysex) { kfree(info->sysex); info->sysex = NULL; } if (info->ch) { kfree(info->ch); info->ch = NULL; } } return; } rec = get_sdev(dev); if (rec == NULL) return; if (rec->oper.reset) { rec->oper.reset(&info->arg); } else { snd_seq_event_t ev; memset(&ev, 0, sizeof(ev)); snd_seq_oss_fill_addr(dp, &ev, info->arg.addr.client, info->arg.addr.port); ev.type = SNDRV_SEQ_EVENT_RESET; snd_seq_oss_dispatch(dp, &ev, 0, 0); } snd_use_lock_free(&rec->use_lock); }
static int snd_seq_oss_oob_user(struct seq_oss_devinfo *dp, void __user *arg) { unsigned char ev[8]; struct snd_seq_event tmpev; if (copy_from_user(ev, arg, 8)) return -EFAULT; memset(&tmpev, 0, sizeof(tmpev)); snd_seq_oss_fill_addr(dp, &tmpev, dp->addr.port, dp->addr.client); tmpev.time.tick = 0; if (! snd_seq_oss_process_event(dp, (union evrec *)ev, &tmpev)) { snd_seq_oss_dispatch(dp, &tmpev, 0, 0); } return 0; }
/* * dump midi data * return 0 : enqueued * non-zero : invalid - ignored */ int snd_seq_oss_midi_putc(struct seq_oss_devinfo *dp, int dev, unsigned char c, struct snd_seq_event *ev) { struct seq_oss_midi *mdev; if ((mdev = get_mididev(dp, dev)) == NULL) return -ENODEV; if (snd_midi_event_encode_byte(mdev->coder, c, ev) > 0) { snd_seq_oss_fill_addr(dp, ev, mdev->client, mdev->port); snd_use_lock_free(&mdev->use_lock); return 0; } snd_use_lock_free(&mdev->use_lock); return -EINVAL; }
/* * wait until the write buffer has enough room */ int snd_seq_oss_writeq_sync(struct seq_oss_writeq *q) { struct seq_oss_devinfo *dp = q->dp; abstime_t time; time = snd_seq_oss_timer_cur_tick(dp->timer); if (q->sync_time >= time) return 0; /* already finished */ if (! q->sync_event_put) { struct snd_seq_event ev; union evrec *rec; /* put echoback event */ memset(&ev, 0, sizeof(ev)); ev.flags = 0; ev.type = SNDRV_SEQ_EVENT_ECHO; ev.time.tick = time; /* echo back to itself */ snd_seq_oss_fill_addr(dp, &ev, dp->addr.client, dp->addr.port); rec = (union evrec *)&ev.data; rec->t.code = SEQ_SYNCTIMER; rec->t.time = time; q->sync_event_put = 1; snd_seq_kernel_client_enqueue_blocking(dp->cseq, &ev, NULL, 0, 0); } wait_event_interruptible_timeout(q->sync_sleep, ! q->sync_event_put, HZ); if (signal_pending(current)) /* interrupted - return 0 to finish sync */ q->sync_event_put = 0; if (! q->sync_event_put || q->sync_time >= time) return 0; return 1; }