cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

seq_oss_event.c (12410B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * OSS compatible sequencer driver
      4 *
      5 * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de>
      6 */
      7
      8#include "seq_oss_device.h"
      9#include "seq_oss_synth.h"
     10#include "seq_oss_midi.h"
     11#include "seq_oss_event.h"
     12#include "seq_oss_timer.h"
     13#include <sound/seq_oss_legacy.h>
     14#include "seq_oss_readq.h"
     15#include "seq_oss_writeq.h"
     16#include <linux/nospec.h>
     17
     18
     19/*
     20 * prototypes
     21 */
     22static int extended_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *ev);
     23static int chn_voice_event(struct seq_oss_devinfo *dp, union evrec *event_rec, struct snd_seq_event *ev);
     24static int chn_common_event(struct seq_oss_devinfo *dp, union evrec *event_rec, struct snd_seq_event *ev);
     25static int timing_event(struct seq_oss_devinfo *dp, union evrec *event_rec, struct snd_seq_event *ev);
     26static int local_event(struct seq_oss_devinfo *dp, union evrec *event_rec, struct snd_seq_event *ev);
     27static int old_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *ev);
     28static int note_on_event(struct seq_oss_devinfo *dp, int dev, int ch, int note, int vel, struct snd_seq_event *ev);
     29static int note_off_event(struct seq_oss_devinfo *dp, int dev, int ch, int note, int vel, struct snd_seq_event *ev);
     30static int set_note_event(struct seq_oss_devinfo *dp, int dev, int type, int ch, int note, int vel, struct snd_seq_event *ev);
     31static int set_control_event(struct seq_oss_devinfo *dp, int dev, int type, int ch, int param, int val, struct snd_seq_event *ev);
     32static int set_echo_event(struct seq_oss_devinfo *dp, union evrec *rec, struct snd_seq_event *ev);
     33
     34
     35/*
     36 * convert an OSS event to ALSA event
     37 * return 0 : enqueued
     38 *        non-zero : invalid - ignored
     39 */
     40
     41int
     42snd_seq_oss_process_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *ev)
     43{
     44	switch (q->s.code) {
     45	case SEQ_EXTENDED:
     46		return extended_event(dp, q, ev);
     47
     48	case EV_CHN_VOICE:
     49		return chn_voice_event(dp, q, ev);
     50
     51	case EV_CHN_COMMON:
     52		return chn_common_event(dp, q, ev);
     53
     54	case EV_TIMING:
     55		return timing_event(dp, q, ev);
     56
     57	case EV_SEQ_LOCAL:
     58		return local_event(dp, q, ev);
     59
     60	case EV_SYSEX:
     61		return snd_seq_oss_synth_sysex(dp, q->x.dev, q->x.buf, ev);
     62
     63	case SEQ_MIDIPUTC:
     64		if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC)
     65			return -EINVAL;
     66		/* put a midi byte */
     67		if (! is_write_mode(dp->file_mode))
     68			break;
     69		if (snd_seq_oss_midi_open(dp, q->s.dev, SNDRV_SEQ_OSS_FILE_WRITE))
     70			break;
     71		if (snd_seq_oss_midi_filemode(dp, q->s.dev) & SNDRV_SEQ_OSS_FILE_WRITE)
     72			return snd_seq_oss_midi_putc(dp, q->s.dev, q->s.parm1, ev);
     73		break;
     74
     75	case SEQ_ECHO:
     76		if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC)
     77			return -EINVAL;
     78		return set_echo_event(dp, q, ev);
     79
     80	case SEQ_PRIVATE:
     81		if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC)
     82			return -EINVAL;
     83		return snd_seq_oss_synth_raw_event(dp, q->c[1], q->c, ev);
     84
     85	default:
     86		if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC)
     87			return -EINVAL;
     88		return old_event(dp, q, ev);
     89	}
     90	return -EINVAL;
     91}
     92
     93/* old type events: mode1 only */
     94static int
     95old_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *ev)
     96{
     97	switch (q->s.code) {
     98	case SEQ_NOTEOFF:
     99		return note_off_event(dp, 0, q->n.chn, q->n.note, q->n.vel, ev);
    100
    101	case SEQ_NOTEON:
    102		return note_on_event(dp, 0, q->n.chn, q->n.note, q->n.vel, ev);
    103
    104	case SEQ_WAIT:
    105		/* skip */
    106		break;
    107
    108	case SEQ_PGMCHANGE:
    109		return set_control_event(dp, 0, SNDRV_SEQ_EVENT_PGMCHANGE,
    110					 q->n.chn, 0, q->n.note, ev);
    111
    112	case SEQ_SYNCTIMER:
    113		return snd_seq_oss_timer_reset(dp->timer);
    114	}
    115
    116	return -EINVAL;
    117}
    118
    119/* 8bytes extended event: mode1 only */
    120static int
    121extended_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *ev)
    122{
    123	int val;
    124
    125	switch (q->e.cmd) {
    126	case SEQ_NOTEOFF:
    127		return note_off_event(dp, q->e.dev, q->e.chn, q->e.p1, q->e.p2, ev);
    128
    129	case SEQ_NOTEON:
    130		return note_on_event(dp, q->e.dev, q->e.chn, q->e.p1, q->e.p2, ev);
    131
    132	case SEQ_PGMCHANGE:
    133		return set_control_event(dp, q->e.dev, SNDRV_SEQ_EVENT_PGMCHANGE,
    134					 q->e.chn, 0, q->e.p1, ev);
    135
    136	case SEQ_AFTERTOUCH:
    137		return set_control_event(dp, q->e.dev, SNDRV_SEQ_EVENT_CHANPRESS,
    138					 q->e.chn, 0, q->e.p1, ev);
    139
    140	case SEQ_BALANCE:
    141		/* convert -128:127 to 0:127 */
    142		val = (char)q->e.p1;
    143		val = (val + 128) / 2;
    144		return set_control_event(dp, q->e.dev, SNDRV_SEQ_EVENT_CONTROLLER,
    145					 q->e.chn, CTL_PAN, val, ev);
    146
    147	case SEQ_CONTROLLER:
    148		val = ((short)q->e.p3 << 8) | (short)q->e.p2;
    149		switch (q->e.p1) {
    150		case CTRL_PITCH_BENDER: /* SEQ1 V2 control */
    151			/* -0x2000:0x1fff */
    152			return set_control_event(dp, q->e.dev,
    153						 SNDRV_SEQ_EVENT_PITCHBEND,
    154						 q->e.chn, 0, val, ev);
    155		case CTRL_PITCH_BENDER_RANGE:
    156			/* conversion: 100/semitone -> 128/semitone */
    157			return set_control_event(dp, q->e.dev,
    158						 SNDRV_SEQ_EVENT_REGPARAM,
    159						 q->e.chn, 0, val*128/100, ev);
    160		default:
    161			return set_control_event(dp, q->e.dev,
    162						  SNDRV_SEQ_EVENT_CONTROL14,
    163						  q->e.chn, q->e.p1, val, ev);
    164		}
    165
    166	case SEQ_VOLMODE:
    167		return snd_seq_oss_synth_raw_event(dp, q->e.dev, q->c, ev);
    168
    169	}
    170	return -EINVAL;
    171}
    172
    173/* channel voice events: mode1 and 2 */
    174static int
    175chn_voice_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *ev)
    176{
    177	if (q->v.chn >= 32)
    178		return -EINVAL;
    179	switch (q->v.cmd) {
    180	case MIDI_NOTEON:
    181		return note_on_event(dp, q->v.dev, q->v.chn, q->v.note, q->v.parm, ev);
    182
    183	case MIDI_NOTEOFF:
    184		return note_off_event(dp, q->v.dev, q->v.chn, q->v.note, q->v.parm, ev);
    185
    186	case MIDI_KEY_PRESSURE:
    187		return set_note_event(dp, q->v.dev, SNDRV_SEQ_EVENT_KEYPRESS,
    188				       q->v.chn, q->v.note, q->v.parm, ev);
    189
    190	}
    191	return -EINVAL;
    192}
    193
    194/* channel common events: mode1 and 2 */
    195static int
    196chn_common_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *ev)
    197{
    198	if (q->l.chn >= 32)
    199		return -EINVAL;
    200	switch (q->l.cmd) {
    201	case MIDI_PGM_CHANGE:
    202		return set_control_event(dp, q->l.dev, SNDRV_SEQ_EVENT_PGMCHANGE,
    203					  q->l.chn, 0, q->l.p1, ev);
    204
    205	case MIDI_CTL_CHANGE:
    206		return set_control_event(dp, q->l.dev, SNDRV_SEQ_EVENT_CONTROLLER,
    207					  q->l.chn, q->l.p1, q->l.val, ev);
    208
    209	case MIDI_PITCH_BEND:
    210		/* conversion: 0:0x3fff -> -0x2000:0x1fff */
    211		return set_control_event(dp, q->l.dev, SNDRV_SEQ_EVENT_PITCHBEND,
    212					  q->l.chn, 0, q->l.val - 8192, ev);
    213		
    214	case MIDI_CHN_PRESSURE:
    215		return set_control_event(dp, q->l.dev, SNDRV_SEQ_EVENT_CHANPRESS,
    216					  q->l.chn, 0, q->l.val, ev);
    217	}
    218	return -EINVAL;
    219}
    220
    221/* timer events: mode1 and mode2 */
    222static int
    223timing_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *ev)
    224{
    225	switch (q->t.cmd) {
    226	case TMR_ECHO:
    227		if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC)
    228			return set_echo_event(dp, q, ev);
    229		else {
    230			union evrec tmp;
    231			memset(&tmp, 0, sizeof(tmp));
    232			/* XXX: only for little-endian! */
    233			tmp.echo = (q->t.time << 8) | SEQ_ECHO;
    234			return set_echo_event(dp, &tmp, ev);
    235		} 
    236
    237	case TMR_STOP:
    238		if (dp->seq_mode)
    239			return snd_seq_oss_timer_stop(dp->timer);
    240		return 0;
    241
    242	case TMR_CONTINUE:
    243		if (dp->seq_mode)
    244			return snd_seq_oss_timer_continue(dp->timer);
    245		return 0;
    246
    247	case TMR_TEMPO:
    248		if (dp->seq_mode)
    249			return snd_seq_oss_timer_tempo(dp->timer, q->t.time);
    250		return 0;
    251	}
    252
    253	return -EINVAL;
    254}
    255
    256/* local events: mode1 and 2 */
    257static int
    258local_event(struct seq_oss_devinfo *dp, union evrec *q, struct snd_seq_event *ev)
    259{
    260	return -EINVAL;
    261}
    262
    263/*
    264 * process note-on event for OSS synth
    265 * three different modes are available:
    266 * - SNDRV_SEQ_OSS_PROCESS_EVENTS  (for one-voice per channel mode)
    267 *	Accept note 255 as volume change.
    268 * - SNDRV_SEQ_OSS_PASS_EVENTS
    269 *	Pass all events to lowlevel driver anyway
    270 * - SNDRV_SEQ_OSS_PROCESS_KEYPRESS  (mostly for Emu8000)
    271 *	Use key-pressure if note >= 128
    272 */
    273static int
    274note_on_event(struct seq_oss_devinfo *dp, int dev, int ch, int note, int vel, struct snd_seq_event *ev)
    275{
    276	struct seq_oss_synthinfo *info;
    277
    278	info = snd_seq_oss_synth_info(dp, dev);
    279	if (!info)
    280		return -ENXIO;
    281
    282	switch (info->arg.event_passing) {
    283	case SNDRV_SEQ_OSS_PROCESS_EVENTS:
    284		if (! info->ch || ch < 0 || ch >= info->nr_voices) {
    285			/* pass directly */
    286			return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEON, ch, note, vel, ev);
    287		}
    288
    289		ch = array_index_nospec(ch, info->nr_voices);
    290		if (note == 255 && info->ch[ch].note >= 0) {
    291			/* volume control */
    292			int type;
    293			//if (! vel)
    294				/* set volume to zero -- note off */
    295			//	type = SNDRV_SEQ_EVENT_NOTEOFF;
    296			//else
    297				if (info->ch[ch].vel)
    298				/* sample already started -- volume change */
    299				type = SNDRV_SEQ_EVENT_KEYPRESS;
    300			else
    301				/* sample not started -- start now */
    302				type = SNDRV_SEQ_EVENT_NOTEON;
    303			info->ch[ch].vel = vel;
    304			return set_note_event(dp, dev, type, ch, info->ch[ch].note, vel, ev);
    305		} else if (note >= 128)
    306			return -EINVAL; /* invalid */
    307
    308		if (note != info->ch[ch].note && info->ch[ch].note >= 0)
    309			/* note changed - note off at beginning */
    310			set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEOFF, ch, info->ch[ch].note, 0, ev);
    311		/* set current status */
    312		info->ch[ch].note = note;
    313		info->ch[ch].vel = vel;
    314		if (vel) /* non-zero velocity - start the note now */
    315			return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEON, ch, note, vel, ev);
    316		return -EINVAL;
    317		
    318	case SNDRV_SEQ_OSS_PASS_EVENTS:
    319		/* pass the event anyway */
    320		return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEON, ch, note, vel, ev);
    321
    322	case SNDRV_SEQ_OSS_PROCESS_KEYPRESS:
    323		if (note >= 128) /* key pressure: shifted by 128 */
    324			return set_note_event(dp, dev, SNDRV_SEQ_EVENT_KEYPRESS, ch, note - 128, vel, ev);
    325		else /* normal note-on event */
    326			return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEON, ch, note, vel, ev);
    327	}
    328	return -EINVAL;
    329}
    330
    331/*
    332 * process note-off event for OSS synth
    333 */
    334static int
    335note_off_event(struct seq_oss_devinfo *dp, int dev, int ch, int note, int vel, struct snd_seq_event *ev)
    336{
    337	struct seq_oss_synthinfo *info;
    338
    339	info = snd_seq_oss_synth_info(dp, dev);
    340	if (!info)
    341		return -ENXIO;
    342
    343	switch (info->arg.event_passing) {
    344	case SNDRV_SEQ_OSS_PROCESS_EVENTS:
    345		if (! info->ch || ch < 0 || ch >= info->nr_voices) {
    346			/* pass directly */
    347			return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEON, ch, note, vel, ev);
    348		}
    349
    350		ch = array_index_nospec(ch, info->nr_voices);
    351		if (info->ch[ch].note >= 0) {
    352			note = info->ch[ch].note;
    353			info->ch[ch].vel = 0;
    354			info->ch[ch].note = -1;
    355			return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEOFF, ch, note, vel, ev);
    356		}
    357		return -EINVAL; /* invalid */
    358
    359	case SNDRV_SEQ_OSS_PASS_EVENTS:
    360	case SNDRV_SEQ_OSS_PROCESS_KEYPRESS:
    361		/* pass the event anyway */
    362		return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEOFF, ch, note, vel, ev);
    363
    364	}
    365	return -EINVAL;
    366}
    367
    368/*
    369 * create a note event
    370 */
    371static int
    372set_note_event(struct seq_oss_devinfo *dp, int dev, int type, int ch, int note, int vel, struct snd_seq_event *ev)
    373{
    374	if (!snd_seq_oss_synth_info(dp, dev))
    375		return -ENXIO;
    376	
    377	ev->type = type;
    378	snd_seq_oss_synth_addr(dp, dev, ev);
    379	ev->data.note.channel = ch;
    380	ev->data.note.note = note;
    381	ev->data.note.velocity = vel;
    382
    383	return 0;
    384}
    385
    386/*
    387 * create a control event
    388 */
    389static int
    390set_control_event(struct seq_oss_devinfo *dp, int dev, int type, int ch, int param, int val, struct snd_seq_event *ev)
    391{
    392	if (!snd_seq_oss_synth_info(dp, dev))
    393		return -ENXIO;
    394	
    395	ev->type = type;
    396	snd_seq_oss_synth_addr(dp, dev, ev);
    397	ev->data.control.channel = ch;
    398	ev->data.control.param = param;
    399	ev->data.control.value = val;
    400
    401	return 0;
    402}
    403
    404/*
    405 * create an echo event
    406 */
    407static int
    408set_echo_event(struct seq_oss_devinfo *dp, union evrec *rec, struct snd_seq_event *ev)
    409{
    410	ev->type = SNDRV_SEQ_EVENT_ECHO;
    411	/* echo back to itself */
    412	snd_seq_oss_fill_addr(dp, ev, dp->addr.client, dp->addr.port);
    413	memcpy(&ev->data, rec, LONG_EVENT_SIZE);
    414	return 0;
    415}
    416
    417/*
    418 * event input callback from ALSA sequencer:
    419 * the echo event is processed here.
    420 */
    421int
    422snd_seq_oss_event_input(struct snd_seq_event *ev, int direct, void *private_data,
    423			int atomic, int hop)
    424{
    425	struct seq_oss_devinfo *dp = (struct seq_oss_devinfo *)private_data;
    426	union evrec *rec;
    427
    428	if (ev->type != SNDRV_SEQ_EVENT_ECHO)
    429		return snd_seq_oss_midi_input(ev, direct, private_data);
    430
    431	if (ev->source.client != dp->cseq)
    432		return 0; /* ignored */
    433
    434	rec = (union evrec*)&ev->data;
    435	if (rec->s.code == SEQ_SYNCTIMER) {
    436		/* sync echo back */
    437		snd_seq_oss_writeq_wakeup(dp->writeq, rec->t.time);
    438		
    439	} else {
    440		/* echo back event */
    441		if (dp->readq == NULL)
    442			return 0;
    443		snd_seq_oss_readq_put_event(dp->readq, rec);
    444	}
    445	return 0;
    446}
    447