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

gus_main.c (12525B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *  Routines for Gravis UltraSound soundcards
      4 *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
      5 */
      6
      7#include <linux/init.h>
      8#include <linux/interrupt.h>
      9#include <linux/delay.h>
     10#include <linux/slab.h>
     11#include <linux/ioport.h>
     12#include <linux/module.h>
     13#include <sound/core.h>
     14#include <sound/gus.h>
     15#include <sound/control.h>
     16
     17#include <asm/dma.h>
     18
     19MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
     20MODULE_DESCRIPTION("Routines for Gravis UltraSound soundcards");
     21MODULE_LICENSE("GPL");
     22
     23static int snd_gus_init_dma_irq(struct snd_gus_card * gus, int latches);
     24
     25int snd_gus_use_inc(struct snd_gus_card * gus)
     26{
     27	if (!try_module_get(gus->card->module))
     28		return 0;
     29	return 1;
     30}
     31
     32void snd_gus_use_dec(struct snd_gus_card * gus)
     33{
     34	module_put(gus->card->module);
     35}
     36
     37static int snd_gus_joystick_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
     38{
     39	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
     40	uinfo->count = 1;
     41	uinfo->value.integer.min = 0;
     42	uinfo->value.integer.max = 31;
     43	return 0;
     44}
     45
     46static int snd_gus_joystick_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
     47{
     48	struct snd_gus_card *gus = snd_kcontrol_chip(kcontrol);
     49	
     50	ucontrol->value.integer.value[0] = gus->joystick_dac & 31;
     51	return 0;
     52}
     53
     54static int snd_gus_joystick_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
     55{
     56	struct snd_gus_card *gus = snd_kcontrol_chip(kcontrol);
     57	unsigned long flags;
     58	int change;
     59	unsigned char nval;
     60	
     61	nval = ucontrol->value.integer.value[0] & 31;
     62	spin_lock_irqsave(&gus->reg_lock, flags);
     63	change = gus->joystick_dac != nval;
     64	gus->joystick_dac = nval;
     65	snd_gf1_write8(gus, SNDRV_GF1_GB_JOYSTICK_DAC_LEVEL, gus->joystick_dac);
     66	spin_unlock_irqrestore(&gus->reg_lock, flags);
     67	return change;
     68}
     69
     70static const struct snd_kcontrol_new snd_gus_joystick_control = {
     71	.iface = SNDRV_CTL_ELEM_IFACE_CARD,
     72	.name = "Joystick Speed",
     73	.info = snd_gus_joystick_info,
     74	.get = snd_gus_joystick_get,
     75	.put = snd_gus_joystick_put
     76};
     77
     78static void snd_gus_init_control(struct snd_gus_card *gus)
     79{
     80	if (!gus->ace_flag)
     81		snd_ctl_add(gus->card, snd_ctl_new1(&snd_gus_joystick_control, gus));
     82}
     83
     84/*
     85 *
     86 */
     87
     88static int snd_gus_free(struct snd_gus_card *gus)
     89{
     90	if (gus->gf1.res_port2 == NULL)
     91		goto __hw_end;
     92	snd_gf1_stop(gus);
     93	snd_gus_init_dma_irq(gus, 0);
     94      __hw_end:
     95	release_and_free_resource(gus->gf1.res_port1);
     96	release_and_free_resource(gus->gf1.res_port2);
     97	if (gus->gf1.irq >= 0)
     98		free_irq(gus->gf1.irq, (void *) gus);
     99	if (gus->gf1.dma1 >= 0) {
    100		disable_dma(gus->gf1.dma1);
    101		free_dma(gus->gf1.dma1);
    102	}
    103	if (!gus->equal_dma && gus->gf1.dma2 >= 0) {
    104		disable_dma(gus->gf1.dma2);
    105		free_dma(gus->gf1.dma2);
    106	}
    107	kfree(gus);
    108	return 0;
    109}
    110
    111static int snd_gus_dev_free(struct snd_device *device)
    112{
    113	struct snd_gus_card *gus = device->device_data;
    114	return snd_gus_free(gus);
    115}
    116
    117int snd_gus_create(struct snd_card *card,
    118		   unsigned long port,
    119		   int irq, int dma1, int dma2,
    120		   int timer_dev,
    121		   int voices,
    122		   int pcm_channels,
    123		   int effect,
    124		   struct snd_gus_card **rgus)
    125{
    126	struct snd_gus_card *gus;
    127	int err;
    128	static const struct snd_device_ops ops = {
    129		.dev_free =	snd_gus_dev_free,
    130	};
    131
    132	*rgus = NULL;
    133	gus = kzalloc(sizeof(*gus), GFP_KERNEL);
    134	if (gus == NULL)
    135		return -ENOMEM;
    136	spin_lock_init(&gus->reg_lock);
    137	spin_lock_init(&gus->voice_alloc);
    138	spin_lock_init(&gus->active_voice_lock);
    139	spin_lock_init(&gus->event_lock);
    140	spin_lock_init(&gus->dma_lock);
    141	spin_lock_init(&gus->pcm_volume_level_lock);
    142	spin_lock_init(&gus->uart_cmd_lock);
    143	mutex_init(&gus->dma_mutex);
    144	gus->gf1.irq = -1;
    145	gus->gf1.dma1 = -1;
    146	gus->gf1.dma2 = -1;
    147	gus->card = card;
    148	gus->gf1.port = port;
    149	/* fill register variables for speedup */
    150	gus->gf1.reg_page = GUSP(gus, GF1PAGE);
    151	gus->gf1.reg_regsel = GUSP(gus, GF1REGSEL);
    152	gus->gf1.reg_data8 = GUSP(gus, GF1DATAHIGH);
    153	gus->gf1.reg_data16 = GUSP(gus, GF1DATALOW);
    154	gus->gf1.reg_irqstat = GUSP(gus, IRQSTAT);
    155	gus->gf1.reg_dram = GUSP(gus, DRAM);
    156	gus->gf1.reg_timerctrl = GUSP(gus, TIMERCNTRL);
    157	gus->gf1.reg_timerdata = GUSP(gus, TIMERDATA);
    158	/* allocate resources */
    159	gus->gf1.res_port1 = request_region(port, 16, "GUS GF1 (Adlib/SB)");
    160	if (!gus->gf1.res_port1) {
    161		snd_printk(KERN_ERR "gus: can't grab SB port 0x%lx\n", port);
    162		snd_gus_free(gus);
    163		return -EBUSY;
    164	}
    165	gus->gf1.res_port2 = request_region(port + 0x100, 12, "GUS GF1 (Synth)");
    166	if (!gus->gf1.res_port2) {
    167		snd_printk(KERN_ERR "gus: can't grab synth port 0x%lx\n", port + 0x100);
    168		snd_gus_free(gus);
    169		return -EBUSY;
    170	}
    171	if (irq >= 0 && request_irq(irq, snd_gus_interrupt, 0, "GUS GF1", (void *) gus)) {
    172		snd_printk(KERN_ERR "gus: can't grab irq %d\n", irq);
    173		snd_gus_free(gus);
    174		return -EBUSY;
    175	}
    176	gus->gf1.irq = irq;
    177	card->sync_irq = irq;
    178	if (request_dma(dma1, "GUS - 1")) {
    179		snd_printk(KERN_ERR "gus: can't grab DMA1 %d\n", dma1);
    180		snd_gus_free(gus);
    181		return -EBUSY;
    182	}
    183	gus->gf1.dma1 = dma1;
    184	if (dma2 >= 0 && dma1 != dma2) {
    185		if (request_dma(dma2, "GUS - 2")) {
    186			snd_printk(KERN_ERR "gus: can't grab DMA2 %d\n", dma2);
    187			snd_gus_free(gus);
    188			return -EBUSY;
    189		}
    190		gus->gf1.dma2 = dma2;
    191	} else {
    192		gus->gf1.dma2 = gus->gf1.dma1;
    193		gus->equal_dma = 1;
    194	}
    195	gus->timer_dev = timer_dev;
    196	if (voices < 14)
    197		voices = 14;
    198	if (voices > 32)
    199		voices = 32;
    200	if (pcm_channels < 0)
    201		pcm_channels = 0;
    202	if (pcm_channels > 8)
    203		pcm_channels = 8;
    204	pcm_channels++;
    205	pcm_channels &= ~1;
    206	gus->gf1.effect = effect ? 1 : 0;
    207	gus->gf1.active_voices = voices;
    208	gus->gf1.pcm_channels = pcm_channels;
    209	gus->gf1.volume_ramp = 25;
    210	gus->gf1.smooth_pan = 1;
    211	err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, gus, &ops);
    212	if (err < 0) {
    213		snd_gus_free(gus);
    214		return err;
    215	}
    216	*rgus = gus;
    217	return 0;
    218}
    219
    220/*
    221 *  Memory detection routine for plain GF1 soundcards
    222 */
    223
    224static int snd_gus_detect_memory(struct snd_gus_card * gus)
    225{
    226	int l, idx, local;
    227	unsigned char d;
    228
    229	snd_gf1_poke(gus, 0L, 0xaa);
    230	snd_gf1_poke(gus, 1L, 0x55);
    231	if (snd_gf1_peek(gus, 0L) != 0xaa || snd_gf1_peek(gus, 1L) != 0x55) {
    232		snd_printk(KERN_ERR "plain GF1 card at 0x%lx without onboard DRAM?\n", gus->gf1.port);
    233		return -ENOMEM;
    234	}
    235	for (idx = 1, d = 0xab; idx < 4; idx++, d++) {
    236		local = idx << 18;
    237		snd_gf1_poke(gus, local, d);
    238		snd_gf1_poke(gus, local + 1, d + 1);
    239		if (snd_gf1_peek(gus, local) != d ||
    240		    snd_gf1_peek(gus, local + 1) != d + 1 ||
    241		    snd_gf1_peek(gus, 0L) != 0xaa)
    242			break;
    243	}
    244#if 1
    245	gus->gf1.memory = idx << 18;
    246#else
    247	gus->gf1.memory = 256 * 1024;
    248#endif
    249	for (l = 0, local = gus->gf1.memory; l < 4; l++, local -= 256 * 1024) {
    250		gus->gf1.mem_alloc.banks_8[l].address =
    251		    gus->gf1.mem_alloc.banks_8[l].size = 0;
    252		gus->gf1.mem_alloc.banks_16[l].address = l << 18;
    253		gus->gf1.mem_alloc.banks_16[l].size = local > 0 ? 256 * 1024 : 0;
    254	}
    255	gus->gf1.mem_alloc.banks_8[0].size = gus->gf1.memory;
    256	return 0;		/* some memory were detected */
    257}
    258
    259static int snd_gus_init_dma_irq(struct snd_gus_card * gus, int latches)
    260{
    261	struct snd_card *card;
    262	unsigned long flags;
    263	int irq, dma1, dma2;
    264	static const unsigned char irqs[16] =
    265		{0, 0, 1, 3, 0, 2, 0, 4, 0, 1, 0, 5, 6, 0, 0, 7};
    266	static const unsigned char dmas[8] =
    267		{6, 1, 0, 2, 0, 3, 4, 5};
    268
    269	if (snd_BUG_ON(!gus))
    270		return -EINVAL;
    271	card = gus->card;
    272	if (snd_BUG_ON(!card))
    273		return -EINVAL;
    274
    275	gus->mix_cntrl_reg &= 0xf8;
    276	gus->mix_cntrl_reg |= 0x01;	/* disable MIC, LINE IN, enable LINE OUT */
    277	if (gus->codec_flag || gus->ess_flag) {
    278		gus->mix_cntrl_reg &= ~1;	/* enable LINE IN */
    279		gus->mix_cntrl_reg |= 4;	/* enable MIC */
    280	}
    281	dma1 = gus->gf1.dma1;
    282	dma1 = abs(dma1);
    283	dma1 = dmas[dma1 & 7];
    284	dma2 = gus->gf1.dma2;
    285	dma2 = abs(dma2);
    286	dma2 = dmas[dma2 & 7];
    287	dma1 |= gus->equal_dma ? 0x40 : (dma2 << 3);
    288
    289	if ((dma1 & 7) == 0 || (dma2 & 7) == 0) {
    290		snd_printk(KERN_ERR "Error! DMA isn't defined.\n");
    291		return -EINVAL;
    292	}
    293	irq = gus->gf1.irq;
    294	irq = abs(irq);
    295	irq = irqs[irq & 0x0f];
    296	if (irq == 0) {
    297		snd_printk(KERN_ERR "Error! IRQ isn't defined.\n");
    298		return -EINVAL;
    299	}
    300	irq |= 0x40;
    301#if 0
    302	card->mixer.mix_ctrl_reg |= 0x10;
    303#endif
    304
    305	spin_lock_irqsave(&gus->reg_lock, flags);
    306	outb(5, GUSP(gus, REGCNTRLS));
    307	outb(gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG));
    308	outb(0x00, GUSP(gus, IRQDMACNTRLREG));
    309	outb(0, GUSP(gus, REGCNTRLS));
    310	spin_unlock_irqrestore(&gus->reg_lock, flags);
    311
    312	udelay(100);
    313
    314	spin_lock_irqsave(&gus->reg_lock, flags);
    315	outb(0x00 | gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG));
    316	outb(dma1, GUSP(gus, IRQDMACNTRLREG));
    317	if (latches) {
    318		outb(0x40 | gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG));
    319		outb(irq, GUSP(gus, IRQDMACNTRLREG));
    320	}
    321	spin_unlock_irqrestore(&gus->reg_lock, flags);
    322
    323	udelay(100);
    324
    325	spin_lock_irqsave(&gus->reg_lock, flags);
    326	outb(0x00 | gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG));
    327	outb(dma1, GUSP(gus, IRQDMACNTRLREG));
    328	if (latches) {
    329		outb(0x40 | gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG));
    330		outb(irq, GUSP(gus, IRQDMACNTRLREG));
    331	}
    332	spin_unlock_irqrestore(&gus->reg_lock, flags);
    333
    334	snd_gf1_delay(gus);
    335
    336	if (latches)
    337		gus->mix_cntrl_reg |= 0x08;	/* enable latches */
    338	else
    339		gus->mix_cntrl_reg &= ~0x08;	/* disable latches */
    340	spin_lock_irqsave(&gus->reg_lock, flags);
    341	outb(gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG));
    342	outb(0, GUSP(gus, GF1PAGE));
    343	spin_unlock_irqrestore(&gus->reg_lock, flags);
    344
    345	return 0;
    346}
    347
    348static int snd_gus_check_version(struct snd_gus_card * gus)
    349{
    350	unsigned long flags;
    351	unsigned char val, rev;
    352	struct snd_card *card;
    353
    354	card = gus->card;
    355	spin_lock_irqsave(&gus->reg_lock, flags);
    356	outb(0x20, GUSP(gus, REGCNTRLS));
    357	val = inb(GUSP(gus, REGCNTRLS));
    358	rev = inb(GUSP(gus, BOARDVERSION));
    359	spin_unlock_irqrestore(&gus->reg_lock, flags);
    360	snd_printdd("GF1 [0x%lx] init - val = 0x%x, rev = 0x%x\n", gus->gf1.port, val, rev);
    361	strcpy(card->driver, "GUS");
    362	strcpy(card->longname, "Gravis UltraSound Classic (2.4)");
    363	if ((val != 255 && (val & 0x06)) || (rev >= 5 && rev != 255)) {
    364		if (rev >= 5 && rev <= 9) {
    365			gus->ics_flag = 1;
    366			if (rev == 5)
    367				gus->ics_flipped = 1;
    368			card->longname[27] = '3';
    369			card->longname[29] = rev == 5 ? '5' : '7';
    370		}
    371		if (rev >= 10 && rev != 255) {
    372			if (rev >= 10 && rev <= 11) {
    373				strcpy(card->driver, "GUS MAX");
    374				strcpy(card->longname, "Gravis UltraSound MAX");
    375				gus->max_flag = 1;
    376			} else if (rev == 0x30) {
    377				strcpy(card->driver, "GUS ACE");
    378				strcpy(card->longname, "Gravis UltraSound Ace");
    379				gus->ace_flag = 1;
    380			} else if (rev == 0x50) {
    381				strcpy(card->driver, "GUS Extreme");
    382				strcpy(card->longname, "Gravis UltraSound Extreme");
    383				gus->ess_flag = 1;
    384			} else {
    385				snd_printk(KERN_ERR "unknown GF1 revision number at 0x%lx - 0x%x (0x%x)\n", gus->gf1.port, rev, val);
    386				snd_printk(KERN_ERR "  please - report to <perex@perex.cz>\n");
    387			}
    388		}
    389	}
    390	strscpy(card->shortname, card->longname, sizeof(card->shortname));
    391	gus->uart_enable = 1;	/* standard GUSes doesn't have midi uart trouble */
    392	snd_gus_init_control(gus);
    393	return 0;
    394}
    395
    396int snd_gus_initialize(struct snd_gus_card *gus)
    397{
    398	int err;
    399
    400	if (!gus->interwave) {
    401		err = snd_gus_check_version(gus);
    402		if (err < 0) {
    403			snd_printk(KERN_ERR "version check failed\n");
    404			return err;
    405		}
    406		err = snd_gus_detect_memory(gus);
    407		if (err < 0)
    408			return err;
    409	}
    410	err = snd_gus_init_dma_irq(gus, 1);
    411	if (err < 0)
    412		return err;
    413	snd_gf1_start(gus);
    414	gus->initialized = 1;
    415	return 0;
    416}
    417
    418  /* gus_io.c */
    419EXPORT_SYMBOL(snd_gf1_delay);
    420EXPORT_SYMBOL(snd_gf1_write8);
    421EXPORT_SYMBOL(snd_gf1_look8);
    422EXPORT_SYMBOL(snd_gf1_write16);
    423EXPORT_SYMBOL(snd_gf1_look16);
    424EXPORT_SYMBOL(snd_gf1_i_write8);
    425EXPORT_SYMBOL(snd_gf1_i_look8);
    426EXPORT_SYMBOL(snd_gf1_i_look16);
    427EXPORT_SYMBOL(snd_gf1_dram_addr);
    428EXPORT_SYMBOL(snd_gf1_write_addr);
    429EXPORT_SYMBOL(snd_gf1_poke);
    430EXPORT_SYMBOL(snd_gf1_peek);
    431  /* gus_reset.c */
    432EXPORT_SYMBOL(snd_gf1_alloc_voice);
    433EXPORT_SYMBOL(snd_gf1_free_voice);
    434EXPORT_SYMBOL(snd_gf1_ctrl_stop);
    435EXPORT_SYMBOL(snd_gf1_stop_voice);
    436  /* gus_mixer.c */
    437EXPORT_SYMBOL(snd_gf1_new_mixer);
    438  /* gus_pcm.c */
    439EXPORT_SYMBOL(snd_gf1_pcm_new);
    440  /* gus.c */
    441EXPORT_SYMBOL(snd_gus_use_inc);
    442EXPORT_SYMBOL(snd_gus_use_dec);
    443EXPORT_SYMBOL(snd_gus_create);
    444EXPORT_SYMBOL(snd_gus_initialize);
    445  /* gus_irq.c */
    446EXPORT_SYMBOL(snd_gus_interrupt);
    447  /* gus_uart.c */
    448EXPORT_SYMBOL(snd_gf1_rawmidi_new);
    449  /* gus_dram.c */
    450EXPORT_SYMBOL(snd_gus_dram_write);
    451EXPORT_SYMBOL(snd_gus_dram_read);
    452  /* gus_volume.c */
    453EXPORT_SYMBOL(snd_gf1_lvol_to_gvol_raw);
    454EXPORT_SYMBOL(snd_gf1_translate_freq);
    455  /* gus_mem.c */
    456EXPORT_SYMBOL(snd_gf1_mem_alloc);
    457EXPORT_SYMBOL(snd_gf1_mem_xfree);
    458EXPORT_SYMBOL(snd_gf1_mem_free);
    459EXPORT_SYMBOL(snd_gf1_mem_lock);