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

sb8.c (5825B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *  Driver for SoundBlaster 1.0/2.0/Pro soundcards and compatible
      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/ioport.h>
     11#include <linux/module.h>
     12#include <sound/core.h>
     13#include <sound/sb.h>
     14#include <sound/opl3.h>
     15#include <sound/initval.h>
     16
     17MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
     18MODULE_DESCRIPTION("Sound Blaster 1.0/2.0/Pro");
     19MODULE_LICENSE("GPL");
     20
     21static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
     22static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
     23static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;	/* Enable this card */
     24static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* 0x220,0x240,0x260 */
     25static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* 5,7,9,10 */
     26static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* 1,3 */
     27
     28module_param_array(index, int, NULL, 0444);
     29MODULE_PARM_DESC(index, "Index value for Sound Blaster soundcard.");
     30module_param_array(id, charp, NULL, 0444);
     31MODULE_PARM_DESC(id, "ID string for Sound Blaster soundcard.");
     32module_param_array(enable, bool, NULL, 0444);
     33MODULE_PARM_DESC(enable, "Enable Sound Blaster soundcard.");
     34module_param_hw_array(port, long, ioport, NULL, 0444);
     35MODULE_PARM_DESC(port, "Port # for SB8 driver.");
     36module_param_hw_array(irq, int, irq, NULL, 0444);
     37MODULE_PARM_DESC(irq, "IRQ # for SB8 driver.");
     38module_param_hw_array(dma8, int, dma, NULL, 0444);
     39MODULE_PARM_DESC(dma8, "8-bit DMA # for SB8 driver.");
     40
     41struct snd_sb8 {
     42	struct resource *fm_res;	/* used to block FM i/o region for legacy cards */
     43	struct snd_sb *chip;
     44};
     45
     46static irqreturn_t snd_sb8_interrupt(int irq, void *dev_id)
     47{
     48	struct snd_sb *chip = dev_id;
     49
     50	if (chip->open & SB_OPEN_PCM) {
     51		return snd_sb8dsp_interrupt(chip);
     52	} else {
     53		return snd_sb8dsp_midi_interrupt(chip);
     54	}
     55}
     56
     57static int snd_sb8_match(struct device *pdev, unsigned int dev)
     58{
     59	if (!enable[dev])
     60		return 0;
     61	if (irq[dev] == SNDRV_AUTO_IRQ) {
     62		dev_err(pdev, "please specify irq\n");
     63		return 0;
     64	}
     65	if (dma8[dev] == SNDRV_AUTO_DMA) {
     66		dev_err(pdev, "please specify dma8\n");
     67		return 0;
     68	}
     69	return 1;
     70}
     71
     72static int snd_sb8_probe(struct device *pdev, unsigned int dev)
     73{
     74	struct snd_sb *chip;
     75	struct snd_card *card;
     76	struct snd_sb8 *acard;
     77	struct snd_opl3 *opl3;
     78	int err;
     79
     80	err = snd_devm_card_new(pdev, index[dev], id[dev], THIS_MODULE,
     81				sizeof(struct snd_sb8), &card);
     82	if (err < 0)
     83		return err;
     84	acard = card->private_data;
     85
     86	/*
     87	 * Block the 0x388 port to avoid PnP conflicts.
     88	 * No need to check this value after request_region,
     89	 * as we never do anything with it.
     90	 */
     91	acard->fm_res = devm_request_region(card->dev, 0x388, 4,
     92					    "SoundBlaster FM");
     93
     94	if (port[dev] != SNDRV_AUTO_PORT) {
     95		err = snd_sbdsp_create(card, port[dev], irq[dev],
     96				       snd_sb8_interrupt, dma8[dev],
     97				       -1, SB_HW_AUTO, &chip);
     98		if (err < 0)
     99			return err;
    100	} else {
    101		/* auto-probe legacy ports */
    102		static const unsigned long possible_ports[] = {
    103			0x220, 0x240, 0x260,
    104		};
    105		int i;
    106		for (i = 0; i < ARRAY_SIZE(possible_ports); i++) {
    107			err = snd_sbdsp_create(card, possible_ports[i],
    108					       irq[dev],
    109					       snd_sb8_interrupt,
    110					       dma8[dev],
    111					       -1,
    112					       SB_HW_AUTO,
    113					       &chip);
    114			if (err >= 0) {
    115				port[dev] = possible_ports[i];
    116				break;
    117			}
    118		}
    119		if (i >= ARRAY_SIZE(possible_ports))
    120			return -EINVAL;
    121	}
    122	acard->chip = chip;
    123			
    124	if (chip->hardware >= SB_HW_16) {
    125		if (chip->hardware == SB_HW_ALS100)
    126			snd_printk(KERN_WARNING "ALS100 chip detected at 0x%lx, try snd-als100 module\n",
    127				    port[dev]);
    128		else
    129			snd_printk(KERN_WARNING "SB 16 chip detected at 0x%lx, try snd-sb16 module\n",
    130				   port[dev]);
    131		return -ENODEV;
    132	}
    133
    134	err = snd_sb8dsp_pcm(chip, 0);
    135	if (err < 0)
    136		return err;
    137
    138	err = snd_sbmixer_new(chip);
    139	if (err < 0)
    140		return err;
    141
    142	if (chip->hardware == SB_HW_10 || chip->hardware == SB_HW_20) {
    143		err = snd_opl3_create(card, chip->port + 8, 0,
    144				      OPL3_HW_AUTO, 1, &opl3);
    145		if (err < 0)
    146			snd_printk(KERN_WARNING "sb8: no OPL device at 0x%lx\n", chip->port + 8);
    147	} else {
    148		err = snd_opl3_create(card, chip->port, chip->port + 2,
    149				      OPL3_HW_AUTO, 1, &opl3);
    150		if (err < 0) {
    151			snd_printk(KERN_WARNING "sb8: no OPL device at 0x%lx-0x%lx\n",
    152				   chip->port, chip->port + 2);
    153		}
    154	}
    155	if (err >= 0) {
    156		err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
    157		if (err < 0)
    158			return err;
    159	}
    160
    161	err = snd_sb8dsp_midi(chip, 0);
    162	if (err < 0)
    163		return err;
    164
    165	strcpy(card->driver, chip->hardware == SB_HW_PRO ? "SB Pro" : "SB8");
    166	strcpy(card->shortname, chip->name);
    167	sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d",
    168		chip->name,
    169		chip->port,
    170		irq[dev], dma8[dev]);
    171
    172	err = snd_card_register(card);
    173	if (err < 0)
    174		return err;
    175
    176	dev_set_drvdata(pdev, card);
    177	return 0;
    178}
    179
    180#ifdef CONFIG_PM
    181static int snd_sb8_suspend(struct device *dev, unsigned int n,
    182			   pm_message_t state)
    183{
    184	struct snd_card *card = dev_get_drvdata(dev);
    185	struct snd_sb8 *acard = card->private_data;
    186	struct snd_sb *chip = acard->chip;
    187
    188	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
    189	snd_sbmixer_suspend(chip);
    190	return 0;
    191}
    192
    193static int snd_sb8_resume(struct device *dev, unsigned int n)
    194{
    195	struct snd_card *card = dev_get_drvdata(dev);
    196	struct snd_sb8 *acard = card->private_data;
    197	struct snd_sb *chip = acard->chip;
    198
    199	snd_sbdsp_reset(chip);
    200	snd_sbmixer_resume(chip);
    201	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
    202	return 0;
    203}
    204#endif
    205
    206#define DEV_NAME "sb8"
    207
    208static struct isa_driver snd_sb8_driver = {
    209	.match		= snd_sb8_match,
    210	.probe		= snd_sb8_probe,
    211#ifdef CONFIG_PM
    212	.suspend	= snd_sb8_suspend,
    213	.resume		= snd_sb8_resume,
    214#endif
    215	.driver		= {
    216		.name	= DEV_NAME 
    217	},
    218};
    219
    220module_isa_driver(snd_sb8_driver, SNDRV_CARDS);