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

gusextreme.c (10088B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *  Driver for Gravis UltraSound Extreme soundcards
      4 *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
      5 */
      6
      7#include <linux/init.h>
      8#include <linux/err.h>
      9#include <linux/isa.h>
     10#include <linux/delay.h>
     11#include <linux/time.h>
     12#include <linux/module.h>
     13#include <asm/dma.h>
     14#include <sound/core.h>
     15#include <sound/gus.h>
     16#include <sound/es1688.h>
     17#include <sound/mpu401.h>
     18#include <sound/opl3.h>
     19#define SNDRV_LEGACY_AUTO_PROBE
     20#define SNDRV_LEGACY_FIND_FREE_IRQ
     21#define SNDRV_LEGACY_FIND_FREE_DMA
     22#include <sound/initval.h>
     23
     24#define CRD_NAME "Gravis UltraSound Extreme"
     25#define DEV_NAME "gusextreme"
     26
     27MODULE_DESCRIPTION(CRD_NAME);
     28MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
     29MODULE_LICENSE("GPL");
     30
     31static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
     32static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
     33static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;	/* Enable this card */
     34static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* 0x220,0x240,0x260 */
     35static long gf1_port[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS) - 1] = -1}; /* 0x210,0x220,0x230,0x240,0x250,0x260,0x270 */
     36static long mpu_port[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS) - 1] = -1}; /* 0x300,0x310,0x320 */
     37static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* 5,7,9,10 */
     38static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* 5,7,9,10 */
     39static int gf1_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* 2,3,5,9,11,12,15 */
     40static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* 0,1,3 */
     41static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
     42static int joystick_dac[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 29};
     43				/* 0 to 31, (0.59V-4.52V or 0.389V-2.98V) */
     44static int channels[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 24};
     45static int pcm_channels[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2};
     46
     47module_param_array(index, int, NULL, 0444);
     48MODULE_PARM_DESC(index, "Index value for " CRD_NAME " soundcard.");
     49module_param_array(id, charp, NULL, 0444);
     50MODULE_PARM_DESC(id, "ID string for " CRD_NAME " soundcard.");
     51module_param_array(enable, bool, NULL, 0444);
     52MODULE_PARM_DESC(enable, "Enable " CRD_NAME " soundcard.");
     53module_param_hw_array(port, long, ioport, NULL, 0444);
     54MODULE_PARM_DESC(port, "Port # for " CRD_NAME " driver.");
     55module_param_hw_array(gf1_port, long, ioport, NULL, 0444);
     56MODULE_PARM_DESC(gf1_port, "GF1 port # for " CRD_NAME " driver (optional).");
     57module_param_hw_array(mpu_port, long, ioport, NULL, 0444);
     58MODULE_PARM_DESC(mpu_port, "MPU-401 port # for " CRD_NAME " driver.");
     59module_param_hw_array(irq, int, irq, NULL, 0444);
     60MODULE_PARM_DESC(irq, "IRQ # for " CRD_NAME " driver.");
     61module_param_hw_array(mpu_irq, int, irq, NULL, 0444);
     62MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for " CRD_NAME " driver.");
     63module_param_hw_array(gf1_irq, int, irq, NULL, 0444);
     64MODULE_PARM_DESC(gf1_irq, "GF1 IRQ # for " CRD_NAME " driver.");
     65module_param_hw_array(dma8, int, dma, NULL, 0444);
     66MODULE_PARM_DESC(dma8, "8-bit DMA # for " CRD_NAME " driver.");
     67module_param_hw_array(dma1, int, dma, NULL, 0444);
     68MODULE_PARM_DESC(dma1, "GF1 DMA # for " CRD_NAME " driver.");
     69module_param_array(joystick_dac, int, NULL, 0444);
     70MODULE_PARM_DESC(joystick_dac, "Joystick DAC level 0.59V-4.52V or 0.389V-2.98V for " CRD_NAME " driver.");
     71module_param_array(channels, int, NULL, 0444);
     72MODULE_PARM_DESC(channels, "GF1 channels for " CRD_NAME " driver.");
     73module_param_array(pcm_channels, int, NULL, 0444);
     74MODULE_PARM_DESC(pcm_channels, "Reserved PCM channels for " CRD_NAME " driver.");
     75
     76static int snd_gusextreme_match(struct device *dev, unsigned int n)
     77{
     78	return enable[n];
     79}
     80
     81static int snd_gusextreme_es1688_create(struct snd_card *card,
     82					struct snd_es1688 *chip,
     83					struct device *dev, unsigned int n)
     84{
     85	static const long possible_ports[] = {0x220, 0x240, 0x260};
     86	static const int possible_irqs[] = {5, 9, 10, 7, -1};
     87	static const int possible_dmas[] = {1, 3, 0, -1};
     88
     89	int i, error;
     90
     91	if (irq[n] == SNDRV_AUTO_IRQ) {
     92		irq[n] = snd_legacy_find_free_irq(possible_irqs);
     93		if (irq[n] < 0) {
     94			dev_err(dev, "unable to find a free IRQ for ES1688\n");
     95			return -EBUSY;
     96		}
     97	}
     98	if (dma8[n] == SNDRV_AUTO_DMA) {
     99		dma8[n] = snd_legacy_find_free_dma(possible_dmas);
    100		if (dma8[n] < 0) {
    101			dev_err(dev, "unable to find a free DMA for ES1688\n");
    102			return -EBUSY;
    103		}
    104	}
    105
    106	if (port[n] != SNDRV_AUTO_PORT)
    107		return snd_es1688_create(card, chip, port[n], mpu_port[n],
    108				irq[n], mpu_irq[n], dma8[n], ES1688_HW_1688);
    109
    110	i = 0;
    111	do {
    112		port[n] = possible_ports[i];
    113		error = snd_es1688_create(card, chip, port[n], mpu_port[n],
    114				irq[n], mpu_irq[n], dma8[n], ES1688_HW_1688);
    115	} while (error < 0 && ++i < ARRAY_SIZE(possible_ports));
    116
    117	return error;
    118}
    119
    120static int snd_gusextreme_gus_card_create(struct snd_card *card,
    121					  struct device *dev, unsigned int n,
    122					  struct snd_gus_card **rgus)
    123{
    124	static const int possible_irqs[] = {11, 12, 15, 9, 5, 7, 3, -1};
    125	static const int possible_dmas[] = {5, 6, 7, 3, 1, -1};
    126
    127	if (gf1_irq[n] == SNDRV_AUTO_IRQ) {
    128		gf1_irq[n] = snd_legacy_find_free_irq(possible_irqs);
    129		if (gf1_irq[n] < 0) {
    130			dev_err(dev, "unable to find a free IRQ for GF1\n");
    131			return -EBUSY;
    132		}
    133	}
    134	if (dma1[n] == SNDRV_AUTO_DMA) {
    135		dma1[n] = snd_legacy_find_free_dma(possible_dmas);
    136		if (dma1[n] < 0) {
    137			dev_err(dev, "unable to find a free DMA for GF1\n");
    138			return -EBUSY;
    139		}
    140	}
    141	return snd_gus_create(card, gf1_port[n], gf1_irq[n], dma1[n], -1,
    142			0, channels[n], pcm_channels[n], 0, rgus);
    143}
    144
    145static int snd_gusextreme_detect(struct snd_gus_card *gus,
    146				 struct snd_es1688 *es1688)
    147{
    148	unsigned long flags;
    149	unsigned char d;
    150
    151	/*
    152	 * This is main stuff - enable access to GF1 chip...
    153	 * I'm not sure, if this will work for card which have
    154	 * ES1688 chip in another place than 0x220.
    155         *
    156         * I used reverse-engineering in DOSEMU. [--jk]
    157	 *
    158	 * ULTRINIT.EXE:
    159	 * 0x230 = 0,2,3
    160	 * 0x240 = 2,0,1
    161	 * 0x250 = 2,0,3
    162	 * 0x260 = 2,2,1
    163	 */
    164
    165	spin_lock_irqsave(&es1688->mixer_lock, flags);
    166	snd_es1688_mixer_write(es1688, 0x40, 0x0b);	/* don't change!!! */
    167	spin_unlock_irqrestore(&es1688->mixer_lock, flags);
    168
    169	spin_lock_irqsave(&es1688->reg_lock, flags);
    170	outb(gus->gf1.port & 0x040 ? 2 : 0, ES1688P(es1688, INIT1));
    171	outb(0, 0x201);
    172	outb(gus->gf1.port & 0x020 ? 2 : 0, ES1688P(es1688, INIT1));
    173	outb(0, 0x201);
    174	outb(gus->gf1.port & 0x010 ? 3 : 1, ES1688P(es1688, INIT1));
    175	spin_unlock_irqrestore(&es1688->reg_lock, flags);
    176
    177	udelay(100);
    178
    179	snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 0);	/* reset GF1 */
    180	d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET);
    181	if ((d & 0x07) != 0) {
    182		snd_printdd("[0x%lx] check 1 failed - 0x%x\n", gus->gf1.port, d);
    183		return -EIO;
    184	}
    185	udelay(160);
    186	snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 1);	/* release reset */
    187	udelay(160);
    188	d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET);
    189	if ((d & 0x07) != 1) {
    190		snd_printdd("[0x%lx] check 2 failed - 0x%x\n", gus->gf1.port, d);
    191		return -EIO;
    192	}
    193
    194	return 0;
    195}
    196
    197static int snd_gusextreme_mixer(struct snd_card *card)
    198{
    199	struct snd_ctl_elem_id id1, id2;
    200	int error;
    201
    202	memset(&id1, 0, sizeof(id1));
    203	memset(&id2, 0, sizeof(id2));
    204	id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
    205
    206	/* reassign AUX to SYNTHESIZER */
    207	strcpy(id1.name, "Aux Playback Volume");
    208	strcpy(id2.name, "Synth Playback Volume");
    209	error = snd_ctl_rename_id(card, &id1, &id2);
    210	if (error < 0)
    211		return error;
    212
    213	/* reassign Master Playback Switch to Synth Playback Switch */
    214	strcpy(id1.name, "Master Playback Switch");
    215	strcpy(id2.name, "Synth Playback Switch");
    216	error = snd_ctl_rename_id(card, &id1, &id2);
    217	if (error < 0)
    218		return error;
    219
    220	return 0;
    221}
    222
    223static int snd_gusextreme_probe(struct device *dev, unsigned int n)
    224{
    225	struct snd_card *card;
    226	struct snd_gus_card *gus;
    227	struct snd_es1688 *es1688;
    228	struct snd_opl3 *opl3;
    229	int error;
    230
    231	error = snd_devm_card_new(dev, index[n], id[n], THIS_MODULE,
    232				  sizeof(struct snd_es1688), &card);
    233	if (error < 0)
    234		return error;
    235
    236	es1688 = card->private_data;
    237
    238	if (mpu_port[n] == SNDRV_AUTO_PORT)
    239		mpu_port[n] = 0;
    240
    241	if (mpu_irq[n] > 15)
    242		mpu_irq[n] = -1;
    243
    244	error = snd_gusextreme_es1688_create(card, es1688, dev, n);
    245	if (error < 0)
    246		return error;
    247
    248	if (gf1_port[n] < 0)
    249		gf1_port[n] = es1688->port + 0x20;
    250
    251	error = snd_gusextreme_gus_card_create(card, dev, n, &gus);
    252	if (error < 0)
    253		return error;
    254
    255	error = snd_gusextreme_detect(gus, es1688);
    256	if (error < 0)
    257		return error;
    258
    259	gus->joystick_dac = joystick_dac[n];
    260
    261	error = snd_gus_initialize(gus);
    262	if (error < 0)
    263		return error;
    264
    265	error = -ENODEV;
    266	if (!gus->ess_flag) {
    267		dev_err(dev, "GUS Extreme soundcard was not "
    268			"detected at 0x%lx\n", gus->gf1.port);
    269		return error;
    270	}
    271	gus->codec_flag = 1;
    272
    273	error = snd_es1688_pcm(card, es1688, 0);
    274	if (error < 0)
    275		return error;
    276
    277	error = snd_es1688_mixer(card, es1688);
    278	if (error < 0)
    279		return error;
    280
    281	snd_component_add(card, "ES1688");
    282
    283	if (pcm_channels[n] > 0) {
    284		error = snd_gf1_pcm_new(gus, 1, 1);
    285		if (error < 0)
    286			return error;
    287	}
    288
    289	error = snd_gf1_new_mixer(gus);
    290	if (error < 0)
    291		return error;
    292
    293	error = snd_gusextreme_mixer(card);
    294	if (error < 0)
    295		return error;
    296
    297	if (snd_opl3_create(card, es1688->port, es1688->port + 2,
    298			OPL3_HW_OPL3, 0, &opl3) < 0)
    299		dev_warn(dev, "opl3 not detected at 0x%lx\n", es1688->port);
    300	else {
    301		error = snd_opl3_hwdep_new(opl3, 0, 2, NULL);
    302		if (error < 0)
    303			return error;
    304	}
    305
    306	if (es1688->mpu_port >= 0x300) {
    307		error = snd_mpu401_uart_new(card, 0, MPU401_HW_ES1688,
    308				es1688->mpu_port, 0, mpu_irq[n], NULL);
    309		if (error < 0)
    310			return error;
    311	}
    312
    313	sprintf(card->longname, "Gravis UltraSound Extreme at 0x%lx, "
    314		"irq %i&%i, dma %i&%i", es1688->port,
    315		gus->gf1.irq, es1688->irq, gus->gf1.dma1, es1688->dma8);
    316
    317	error = snd_card_register(card);
    318	if (error < 0)
    319		return error;
    320
    321	dev_set_drvdata(dev, card);
    322	return 0;
    323}
    324
    325static struct isa_driver snd_gusextreme_driver = {
    326	.match		= snd_gusextreme_match,
    327	.probe		= snd_gusextreme_probe,
    328#if 0	/* FIXME */
    329	.suspend	= snd_gusextreme_suspend,
    330	.resume		= snd_gusextreme_resume,
    331#endif
    332	.driver		= {
    333		.name	= DEV_NAME
    334	}
    335};
    336
    337module_isa_driver(snd_gusextreme_driver, SNDRV_CARDS);