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

opl3_oss.c (6105B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *  Interface for OSS sequencer emulation
      4 *
      5 *  Copyright (C) 2000 Uros Bizjak <uros@kss-loka.si>
      6 */
      7
      8#include <linux/export.h>
      9#include "opl3_voice.h"
     10
     11static int snd_opl3_open_seq_oss(struct snd_seq_oss_arg *arg, void *closure);
     12static int snd_opl3_close_seq_oss(struct snd_seq_oss_arg *arg);
     13static int snd_opl3_ioctl_seq_oss(struct snd_seq_oss_arg *arg, unsigned int cmd, unsigned long ioarg);
     14static int snd_opl3_load_patch_seq_oss(struct snd_seq_oss_arg *arg, int format, const char __user *buf, int offs, int count);
     15static int snd_opl3_reset_seq_oss(struct snd_seq_oss_arg *arg);
     16
     17/* operators */
     18
     19static const struct snd_seq_oss_callback oss_callback = {
     20	.owner = 	THIS_MODULE,
     21	.open =		snd_opl3_open_seq_oss,
     22	.close =	snd_opl3_close_seq_oss,
     23	.ioctl =	snd_opl3_ioctl_seq_oss,
     24	.load_patch =	snd_opl3_load_patch_seq_oss,
     25	.reset =	snd_opl3_reset_seq_oss,
     26};
     27
     28static int snd_opl3_oss_event_input(struct snd_seq_event *ev, int direct,
     29				    void *private_data, int atomic, int hop)
     30{
     31	struct snd_opl3 *opl3 = private_data;
     32
     33	if (ev->type != SNDRV_SEQ_EVENT_OSS)
     34		snd_midi_process_event(&opl3_ops, ev, opl3->oss_chset);
     35	return 0;
     36}
     37
     38/* ------------------------------ */
     39
     40static void snd_opl3_oss_free_port(void *private_data)
     41{
     42	struct snd_opl3 *opl3 = private_data;
     43
     44	snd_midi_channel_free_set(opl3->oss_chset);
     45}
     46
     47static int snd_opl3_oss_create_port(struct snd_opl3 * opl3)
     48{
     49	struct snd_seq_port_callback callbacks;
     50	char name[32];
     51	int voices, opl_ver;
     52
     53	voices = (opl3->hardware < OPL3_HW_OPL3) ?
     54		MAX_OPL2_VOICES : MAX_OPL3_VOICES;
     55	opl3->oss_chset = snd_midi_channel_alloc_set(voices);
     56	if (opl3->oss_chset == NULL)
     57		return -ENOMEM;
     58	opl3->oss_chset->private_data = opl3;
     59
     60	memset(&callbacks, 0, sizeof(callbacks));
     61	callbacks.owner = THIS_MODULE;
     62	callbacks.event_input = snd_opl3_oss_event_input;
     63	callbacks.private_free = snd_opl3_oss_free_port;
     64	callbacks.private_data = opl3;
     65
     66	opl_ver = (opl3->hardware & OPL3_HW_MASK) >> 8;
     67	sprintf(name, "OPL%i OSS Port", opl_ver);
     68
     69	opl3->oss_chset->client = opl3->seq_client;
     70	opl3->oss_chset->port = snd_seq_event_port_attach(opl3->seq_client, &callbacks,
     71							  SNDRV_SEQ_PORT_CAP_WRITE,
     72							  SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC |
     73							  SNDRV_SEQ_PORT_TYPE_MIDI_GM |
     74							  SNDRV_SEQ_PORT_TYPE_HARDWARE |
     75							  SNDRV_SEQ_PORT_TYPE_SYNTHESIZER,
     76							  voices, voices,
     77							  name);
     78	if (opl3->oss_chset->port < 0) {
     79		int port;
     80		port = opl3->oss_chset->port;
     81		snd_midi_channel_free_set(opl3->oss_chset);
     82		return port;
     83	}
     84	return 0;
     85}
     86
     87/* ------------------------------ */
     88
     89/* register OSS synth */
     90void snd_opl3_init_seq_oss(struct snd_opl3 *opl3, char *name)
     91{
     92	struct snd_seq_oss_reg *arg;
     93	struct snd_seq_device *dev;
     94
     95	if (snd_seq_device_new(opl3->card, 0, SNDRV_SEQ_DEV_ID_OSS,
     96			       sizeof(struct snd_seq_oss_reg), &dev) < 0)
     97		return;
     98
     99	opl3->oss_seq_dev = dev;
    100	strscpy(dev->name, name, sizeof(dev->name));
    101	arg = SNDRV_SEQ_DEVICE_ARGPTR(dev);
    102	arg->type = SYNTH_TYPE_FM;
    103	if (opl3->hardware < OPL3_HW_OPL3) {
    104		arg->subtype = FM_TYPE_ADLIB;
    105		arg->nvoices = MAX_OPL2_VOICES;
    106	} else {
    107		arg->subtype = FM_TYPE_OPL3;
    108		arg->nvoices = MAX_OPL3_VOICES;
    109	}
    110	arg->oper = oss_callback;
    111	arg->private_data = opl3;
    112
    113	if (snd_opl3_oss_create_port(opl3)) {
    114		/* register to OSS synth table */
    115		snd_device_register(opl3->card, dev);
    116	}
    117}
    118
    119/* unregister */
    120void snd_opl3_free_seq_oss(struct snd_opl3 *opl3)
    121{
    122	if (opl3->oss_seq_dev) {
    123		/* The instance should have been released in prior */
    124		opl3->oss_seq_dev = NULL;
    125	}
    126}
    127
    128/* ------------------------------ */
    129
    130/* open OSS sequencer */
    131static int snd_opl3_open_seq_oss(struct snd_seq_oss_arg *arg, void *closure)
    132{
    133	struct snd_opl3 *opl3 = closure;
    134	int err;
    135
    136	if (snd_BUG_ON(!arg))
    137		return -ENXIO;
    138
    139	err = snd_opl3_synth_setup(opl3);
    140	if (err < 0)
    141		return err;
    142
    143	/* fill the argument data */
    144	arg->private_data = opl3;
    145	arg->addr.client = opl3->oss_chset->client;
    146	arg->addr.port = opl3->oss_chset->port;
    147
    148	err = snd_opl3_synth_use_inc(opl3);
    149	if (err < 0)
    150		return err;
    151
    152	opl3->synth_mode = SNDRV_OPL3_MODE_SYNTH;
    153	return 0;
    154}
    155
    156/* close OSS sequencer */
    157static int snd_opl3_close_seq_oss(struct snd_seq_oss_arg *arg)
    158{
    159	struct snd_opl3 *opl3;
    160
    161	if (snd_BUG_ON(!arg))
    162		return -ENXIO;
    163	opl3 = arg->private_data;
    164
    165	snd_opl3_synth_cleanup(opl3);
    166
    167	snd_opl3_synth_use_dec(opl3);
    168	return 0;
    169}
    170
    171/* load patch */
    172
    173/* from sound_config.h */
    174#define SBFM_MAXINSTR	256
    175
    176static int snd_opl3_load_patch_seq_oss(struct snd_seq_oss_arg *arg, int format,
    177				       const char __user *buf, int offs, int count)
    178{
    179	struct snd_opl3 *opl3;
    180	struct sbi_instrument sbi;
    181	char name[32];
    182	int err, type;
    183
    184	if (snd_BUG_ON(!arg))
    185		return -ENXIO;
    186	opl3 = arg->private_data;
    187
    188	if (format == FM_PATCH)
    189		type = FM_PATCH_OPL2;
    190	else if (format == OPL3_PATCH)
    191		type = FM_PATCH_OPL3;
    192	else
    193		return -EINVAL;
    194
    195	if (count < (int)sizeof(sbi)) {
    196		snd_printk(KERN_ERR "FM Error: Patch record too short\n");
    197		return -EINVAL;
    198	}
    199	if (copy_from_user(&sbi, buf, sizeof(sbi)))
    200		return -EFAULT;
    201
    202	if (sbi.channel < 0 || sbi.channel >= SBFM_MAXINSTR) {
    203		snd_printk(KERN_ERR "FM Error: Invalid instrument number %d\n",
    204			   sbi.channel);
    205		return -EINVAL;
    206	}
    207
    208	memset(name, 0, sizeof(name));
    209	sprintf(name, "Chan%d", sbi.channel);
    210
    211	err = snd_opl3_load_patch(opl3, sbi.channel, 127, type, name, NULL,
    212				  sbi.operators);
    213	if (err < 0)
    214		return err;
    215
    216	return sizeof(sbi);
    217}
    218
    219/* ioctl */
    220static int snd_opl3_ioctl_seq_oss(struct snd_seq_oss_arg *arg, unsigned int cmd,
    221				  unsigned long ioarg)
    222{
    223	if (snd_BUG_ON(!arg))
    224		return -ENXIO;
    225	switch (cmd) {
    226		case SNDCTL_FM_LOAD_INSTR:
    227			snd_printk(KERN_ERR "OPL3: "
    228				   "Obsolete ioctl(SNDCTL_FM_LOAD_INSTR) used. "
    229				   "Fix the program.\n");
    230			return -EINVAL;
    231
    232		case SNDCTL_SYNTH_MEMAVL:
    233			return 0x7fffffff;
    234
    235		case SNDCTL_FM_4OP_ENABLE:
    236			// handled automatically by OPL instrument type
    237			return 0;
    238
    239		default:
    240			return -EINVAL;
    241	}
    242	return 0;
    243}
    244
    245/* reset device */
    246static int snd_opl3_reset_seq_oss(struct snd_seq_oss_arg *arg)
    247{
    248	if (snd_BUG_ON(!arg))
    249		return -ENXIO;
    250
    251	return 0;
    252}