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

sb_common.c (5826B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
      4 *                   Uros Bizjak <uros@kss-loka.si>
      5 *
      6 *  Lowlevel routines for control of Sound Blaster cards
      7 */
      8
      9#include <linux/delay.h>
     10#include <linux/init.h>
     11#include <linux/interrupt.h>
     12#include <linux/slab.h>
     13#include <linux/ioport.h>
     14#include <linux/module.h>
     15#include <linux/io.h>
     16#include <sound/core.h>
     17#include <sound/sb.h>
     18#include <sound/initval.h>
     19
     20#include <asm/dma.h>
     21
     22MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
     23MODULE_DESCRIPTION("ALSA lowlevel driver for Sound Blaster cards");
     24MODULE_LICENSE("GPL");
     25
     26#define BUSY_LOOPS 100000
     27
     28#undef IO_DEBUG
     29
     30int snd_sbdsp_command(struct snd_sb *chip, unsigned char val)
     31{
     32	int i;
     33#ifdef IO_DEBUG
     34	snd_printk(KERN_DEBUG "command 0x%x\n", val);
     35#endif
     36	for (i = BUSY_LOOPS; i; i--)
     37		if ((inb(SBP(chip, STATUS)) & 0x80) == 0) {
     38			outb(val, SBP(chip, COMMAND));
     39			return 1;
     40		}
     41	snd_printd("%s [0x%lx]: timeout (0x%x)\n", __func__, chip->port, val);
     42	return 0;
     43}
     44
     45int snd_sbdsp_get_byte(struct snd_sb *chip)
     46{
     47	int val;
     48	int i;
     49	for (i = BUSY_LOOPS; i; i--) {
     50		if (inb(SBP(chip, DATA_AVAIL)) & 0x80) {
     51			val = inb(SBP(chip, READ));
     52#ifdef IO_DEBUG
     53			snd_printk(KERN_DEBUG "get_byte 0x%x\n", val);
     54#endif
     55			return val;
     56		}
     57	}
     58	snd_printd("%s [0x%lx]: timeout\n", __func__, chip->port);
     59	return -ENODEV;
     60}
     61
     62int snd_sbdsp_reset(struct snd_sb *chip)
     63{
     64	int i;
     65
     66	outb(1, SBP(chip, RESET));
     67	udelay(10);
     68	outb(0, SBP(chip, RESET));
     69	udelay(30);
     70	for (i = BUSY_LOOPS; i; i--)
     71		if (inb(SBP(chip, DATA_AVAIL)) & 0x80) {
     72			if (inb(SBP(chip, READ)) == 0xaa)
     73				return 0;
     74			else
     75				break;
     76		}
     77	snd_printdd("%s [0x%lx] failed...\n", __func__, chip->port);
     78	return -ENODEV;
     79}
     80
     81static int snd_sbdsp_version(struct snd_sb * chip)
     82{
     83	unsigned int result;
     84
     85	snd_sbdsp_command(chip, SB_DSP_GET_VERSION);
     86	result = (short) snd_sbdsp_get_byte(chip) << 8;
     87	result |= (short) snd_sbdsp_get_byte(chip);
     88	return result;
     89}
     90
     91static int snd_sbdsp_probe(struct snd_sb * chip)
     92{
     93	int version;
     94	int major, minor;
     95	char *str;
     96	unsigned long flags;
     97
     98	/*
     99	 *  initialization sequence
    100	 */
    101
    102	spin_lock_irqsave(&chip->reg_lock, flags);
    103	if (snd_sbdsp_reset(chip) < 0) {
    104		spin_unlock_irqrestore(&chip->reg_lock, flags);
    105		return -ENODEV;
    106	}
    107	version = snd_sbdsp_version(chip);
    108	if (version < 0) {
    109		spin_unlock_irqrestore(&chip->reg_lock, flags);
    110		return -ENODEV;
    111	}
    112	spin_unlock_irqrestore(&chip->reg_lock, flags);
    113	major = version >> 8;
    114	minor = version & 0xff;
    115	snd_printdd("SB [0x%lx]: DSP chip found, version = %i.%i\n",
    116		    chip->port, major, minor);
    117
    118	switch (chip->hardware) {
    119	case SB_HW_AUTO:
    120		switch (major) {
    121		case 1:
    122			chip->hardware = SB_HW_10;
    123			str = "1.0";
    124			break;
    125		case 2:
    126			if (minor) {
    127				chip->hardware = SB_HW_201;
    128				str = "2.01+";
    129			} else {
    130				chip->hardware = SB_HW_20;
    131				str = "2.0";
    132			}
    133			break;
    134		case 3:
    135			chip->hardware = SB_HW_PRO;
    136			str = "Pro";
    137			break;
    138		case 4:
    139			chip->hardware = SB_HW_16;
    140			str = "16";
    141			break;
    142		default:
    143			snd_printk(KERN_INFO "SB [0x%lx]: unknown DSP chip version %i.%i\n",
    144				   chip->port, major, minor);
    145			return -ENODEV;
    146		}
    147		break;
    148	case SB_HW_ALS100:
    149		str = "16 (ALS-100)";
    150		break;
    151	case SB_HW_ALS4000:
    152		str = "16 (ALS-4000)";
    153		break;
    154	case SB_HW_DT019X:
    155		str = "(DT019X/ALS007)";
    156		break;
    157	case SB_HW_CS5530:
    158		str = "16 (CS5530)";
    159		break;
    160	case SB_HW_JAZZ16:
    161		str = "Pro (Jazz16)";
    162		break;
    163	default:
    164		return -ENODEV;
    165	}
    166	sprintf(chip->name, "Sound Blaster %s", str);
    167	chip->version = (major << 8) | minor;
    168	return 0;
    169}
    170
    171int snd_sbdsp_create(struct snd_card *card,
    172		     unsigned long port,
    173		     int irq,
    174		     irq_handler_t irq_handler,
    175		     int dma8,
    176		     int dma16,
    177		     unsigned short hardware,
    178		     struct snd_sb **r_chip)
    179{
    180	struct snd_sb *chip;
    181	int err;
    182
    183	if (snd_BUG_ON(!r_chip))
    184		return -EINVAL;
    185	*r_chip = NULL;
    186	chip = devm_kzalloc(card->dev, sizeof(*chip), GFP_KERNEL);
    187	if (!chip)
    188		return -ENOMEM;
    189	spin_lock_init(&chip->reg_lock);
    190	spin_lock_init(&chip->open_lock);
    191	spin_lock_init(&chip->midi_input_lock);
    192	spin_lock_init(&chip->mixer_lock);
    193	chip->irq = -1;
    194	chip->dma8 = -1;
    195	chip->dma16 = -1;
    196	chip->port = port;
    197	
    198	if (devm_request_irq(card->dev, irq, irq_handler,
    199			     (hardware == SB_HW_ALS4000 ||
    200			      hardware == SB_HW_CS5530) ?
    201			     IRQF_SHARED : 0,
    202			     "SoundBlaster", (void *) chip)) {
    203		snd_printk(KERN_ERR "sb: can't grab irq %d\n", irq);
    204		return -EBUSY;
    205	}
    206	chip->irq = irq;
    207	card->sync_irq = chip->irq;
    208
    209	if (hardware == SB_HW_ALS4000)
    210		goto __skip_allocation;
    211	
    212	chip->res_port = devm_request_region(card->dev, port, 16,
    213					     "SoundBlaster");
    214	if (!chip->res_port) {
    215		snd_printk(KERN_ERR "sb: can't grab port 0x%lx\n", port);
    216		return -EBUSY;
    217	}
    218
    219#ifdef CONFIG_ISA
    220	if (dma8 >= 0 && snd_devm_request_dma(card->dev, dma8,
    221					      "SoundBlaster - 8bit")) {
    222		snd_printk(KERN_ERR "sb: can't grab DMA8 %d\n", dma8);
    223		return -EBUSY;
    224	}
    225	chip->dma8 = dma8;
    226	if (dma16 >= 0) {
    227		if (hardware != SB_HW_ALS100 && (dma16 < 5 || dma16 > 7)) {
    228			/* no duplex */
    229			dma16 = -1;
    230		} else if (snd_devm_request_dma(card->dev, dma16,
    231						"SoundBlaster - 16bit")) {
    232			snd_printk(KERN_ERR "sb: can't grab DMA16 %d\n", dma16);
    233			return -EBUSY;
    234		}
    235	}
    236	chip->dma16 = dma16;
    237#endif
    238
    239      __skip_allocation:
    240	chip->card = card;
    241	chip->hardware = hardware;
    242	err = snd_sbdsp_probe(chip);
    243	if (err < 0)
    244		return err;
    245	*r_chip = chip;
    246	return 0;
    247}
    248
    249EXPORT_SYMBOL(snd_sbdsp_command);
    250EXPORT_SYMBOL(snd_sbdsp_get_byte);
    251EXPORT_SYMBOL(snd_sbdsp_reset);
    252EXPORT_SYMBOL(snd_sbdsp_create);
    253/* sb_mixer.c */
    254EXPORT_SYMBOL(snd_sbmixer_write);
    255EXPORT_SYMBOL(snd_sbmixer_read);
    256EXPORT_SYMBOL(snd_sbmixer_new);
    257EXPORT_SYMBOL(snd_sbmixer_add_ctl);
    258#ifdef CONFIG_PM
    259EXPORT_SYMBOL(snd_sbmixer_suspend);
    260EXPORT_SYMBOL(snd_sbmixer_resume);
    261#endif