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

cs5530.c (5654B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * cs5530.c - Initialisation code for Cyrix/NatSemi VSA1 softaudio
      4 *
      5 * 	(C) Copyright 2007 Ash Willis <ashwillis@programmer.net>
      6 *	(C) Copyright 2003 Red Hat Inc <alan@lxorguk.ukuu.org.uk>
      7 *
      8 * This driver was ported (shamelessly ripped ;) from oss/kahlua.c but I did
      9 * mess with it a bit. The chip seems to have to have trouble with full duplex
     10 * mode. If we're recording in 8bit 8000kHz, say, and we then attempt to
     11 * simultaneously play back audio at 16bit 44100kHz, the device actually plays
     12 * back in the same format in which it is capturing. By forcing the chip to
     13 * always play/capture in 16/44100, we can let alsa-lib convert the samples and
     14 * that way we can hack up some full duplex audio. 
     15 * 
     16 * XpressAudio(tm) is used on the Cyrix MediaGX (now NatSemi Geode) systems.
     17 * The older version (VSA1) provides fairly good soundblaster emulation
     18 * although there are a couple of bugs: large DMA buffers break record,
     19 * and the MPU event handling seems suspect. VSA2 allows the native driver
     20 * to control the AC97 audio engine directly and requires a different driver.
     21 *
     22 * Thanks to National Semiconductor for providing the needed information
     23 * on the XpressAudio(tm) internals.
     24 *
     25 * TO DO:
     26 *	Investigate whether we can portably support Cognac (5520) in the
     27 *	same manner.
     28 */
     29
     30#include <linux/delay.h>
     31#include <linux/module.h>
     32#include <linux/pci.h>
     33#include <linux/slab.h>
     34#include <sound/core.h>
     35#include <sound/sb.h>
     36#include <sound/initval.h>
     37
     38MODULE_AUTHOR("Ash Willis");
     39MODULE_DESCRIPTION("CS5530 Audio");
     40MODULE_LICENSE("GPL");
     41
     42static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
     43static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
     44static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
     45
     46module_param_array(index, int, NULL, 0444);
     47MODULE_PARM_DESC(index, "Index value for CS5530 Audio driver.");
     48module_param_array(id, charp, NULL, 0444);
     49MODULE_PARM_DESC(id, "ID string for CS5530 Audio driver.");
     50module_param_array(enable, bool, NULL, 0444);
     51MODULE_PARM_DESC(enable, "Enable CS5530 Audio driver.");
     52
     53struct snd_cs5530 {
     54	struct snd_card *card;
     55	struct pci_dev *pci;
     56	struct snd_sb *sb;
     57	unsigned long pci_base;
     58};
     59
     60static const struct pci_device_id snd_cs5530_ids[] = {
     61	{PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_AUDIO, PCI_ANY_ID,
     62							PCI_ANY_ID, 0, 0},
     63	{0,}
     64};
     65
     66MODULE_DEVICE_TABLE(pci, snd_cs5530_ids);
     67
     68static u8 snd_cs5530_mixer_read(unsigned long io, u8 reg)
     69{
     70	outb(reg, io + 4);
     71	udelay(20);
     72	reg = inb(io + 5);
     73	udelay(20);
     74	return reg;
     75}
     76
     77static int snd_cs5530_create(struct snd_card *card,
     78			     struct pci_dev *pci)
     79{
     80	struct snd_cs5530 *chip = card->private_data;
     81	unsigned long sb_base;
     82	u8 irq, dma8, dma16 = 0;
     83	u16 map;
     84	void __iomem *mem;
     85	int err;
     86
     87	err = pcim_enable_device(pci);
     88 	if (err < 0)
     89		return err;
     90
     91	chip->card = card;
     92	chip->pci = pci;
     93
     94	err = pcim_iomap_regions(pci, 1 << 0, "CS5530");
     95	if (err < 0)
     96		return err;
     97	chip->pci_base = pci_resource_start(pci, 0);
     98	mem = pcim_iomap_table(pci)[0];
     99	map = readw(mem + 0x18);
    100
    101	/* Map bits
    102		0:1	* 0x20 + 0x200 = sb base
    103		2	sb enable
    104		3	adlib enable
    105		5	MPU enable 0x330
    106		6	MPU enable 0x300
    107
    108	   The other bits may be used internally so must be masked */
    109
    110	sb_base = 0x220 + 0x20 * (map & 3);
    111
    112	if (map & (1<<2))
    113		dev_info(card->dev, "XpressAudio at 0x%lx\n", sb_base);
    114	else {
    115		dev_err(card->dev, "Could not find XpressAudio!\n");
    116		return -ENODEV;
    117	}
    118
    119	if (map & (1<<5))
    120		dev_info(card->dev, "MPU at 0x300\n");
    121	else if (map & (1<<6))
    122		dev_info(card->dev, "MPU at 0x330\n");
    123
    124	irq = snd_cs5530_mixer_read(sb_base, 0x80) & 0x0F;
    125	dma8 = snd_cs5530_mixer_read(sb_base, 0x81);
    126
    127	if (dma8 & 0x20)
    128		dma16 = 5;
    129	else if (dma8 & 0x40)
    130		dma16 = 6;
    131	else if (dma8 & 0x80)
    132		dma16 = 7;
    133	else {
    134		dev_err(card->dev, "No 16bit DMA enabled\n");
    135		return -ENODEV;
    136	}
    137
    138	if (dma8 & 0x01)
    139		dma8 = 0;
    140	else if (dma8 & 02)
    141		dma8 = 1;
    142	else if (dma8 & 0x08)
    143		dma8 = 3;
    144	else {
    145		dev_err(card->dev, "No 8bit DMA enabled\n");
    146		return -ENODEV;
    147	}
    148
    149	if (irq & 1)
    150		irq = 9;
    151	else if (irq & 2)
    152		irq = 5;
    153	else if (irq & 4)
    154		irq = 7;
    155	else if (irq & 8)
    156		irq = 10;
    157	else {
    158		dev_err(card->dev, "SoundBlaster IRQ not set\n");
    159		return -ENODEV;
    160	}
    161
    162	dev_info(card->dev, "IRQ: %d DMA8: %d DMA16: %d\n", irq, dma8, dma16);
    163
    164	err = snd_sbdsp_create(card, sb_base, irq, snd_sb16dsp_interrupt, dma8,
    165						dma16, SB_HW_CS5530, &chip->sb);
    166	if (err < 0) {
    167		dev_err(card->dev, "Could not create SoundBlaster\n");
    168		return err;
    169	}
    170
    171	err = snd_sb16dsp_pcm(chip->sb, 0);
    172	if (err < 0) {
    173		dev_err(card->dev, "Could not create PCM\n");
    174		return err;
    175	}
    176
    177	err = snd_sbmixer_new(chip->sb);
    178	if (err < 0) {
    179		dev_err(card->dev, "Could not create Mixer\n");
    180		return err;
    181	}
    182
    183	return 0;
    184}
    185
    186static int snd_cs5530_probe(struct pci_dev *pci,
    187			    const struct pci_device_id *pci_id)
    188{
    189	static int dev;
    190	struct snd_card *card;
    191	struct snd_cs5530 *chip;
    192	int err;
    193
    194	if (dev >= SNDRV_CARDS)
    195		return -ENODEV;
    196	if (!enable[dev]) {
    197		dev++;
    198		return -ENOENT;
    199	}
    200
    201	err = snd_devm_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
    202				sizeof(*chip), &card);
    203	if (err < 0)
    204		return err;
    205	chip = card->private_data;
    206
    207	err = snd_cs5530_create(card, pci);
    208	if (err < 0)
    209		return err;
    210
    211	strcpy(card->driver, "CS5530");
    212	strcpy(card->shortname, "CS5530 Audio");
    213	sprintf(card->longname, "%s at 0x%lx", card->shortname, chip->pci_base);
    214
    215	err = snd_card_register(card);
    216	if (err < 0)
    217		return err;
    218	pci_set_drvdata(pci, card);
    219	dev++;
    220	return 0;
    221}
    222
    223static struct pci_driver cs5530_driver = {
    224	.name = KBUILD_MODNAME,
    225	.id_table = snd_cs5530_ids,
    226	.probe = snd_cs5530_probe,
    227};
    228
    229module_pci_driver(cs5530_driver);