Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * cs5530.c - Initialisation code for Cyrix/NatSemi VSA1 softaudio
0004  *
0005  *  (C) Copyright 2007 Ash Willis <ashwillis@programmer.net>
0006  *  (C) Copyright 2003 Red Hat Inc <alan@lxorguk.ukuu.org.uk>
0007  *
0008  * This driver was ported (shamelessly ripped ;) from oss/kahlua.c but I did
0009  * mess with it a bit. The chip seems to have to have trouble with full duplex
0010  * mode. If we're recording in 8bit 8000kHz, say, and we then attempt to
0011  * simultaneously play back audio at 16bit 44100kHz, the device actually plays
0012  * back in the same format in which it is capturing. By forcing the chip to
0013  * always play/capture in 16/44100, we can let alsa-lib convert the samples and
0014  * that way we can hack up some full duplex audio. 
0015  * 
0016  * XpressAudio(tm) is used on the Cyrix MediaGX (now NatSemi Geode) systems.
0017  * The older version (VSA1) provides fairly good soundblaster emulation
0018  * although there are a couple of bugs: large DMA buffers break record,
0019  * and the MPU event handling seems suspect. VSA2 allows the native driver
0020  * to control the AC97 audio engine directly and requires a different driver.
0021  *
0022  * Thanks to National Semiconductor for providing the needed information
0023  * on the XpressAudio(tm) internals.
0024  *
0025  * TO DO:
0026  *  Investigate whether we can portably support Cognac (5520) in the
0027  *  same manner.
0028  */
0029 
0030 #include <linux/delay.h>
0031 #include <linux/module.h>
0032 #include <linux/pci.h>
0033 #include <linux/slab.h>
0034 #include <sound/core.h>
0035 #include <sound/sb.h>
0036 #include <sound/initval.h>
0037 
0038 MODULE_AUTHOR("Ash Willis");
0039 MODULE_DESCRIPTION("CS5530 Audio");
0040 MODULE_LICENSE("GPL");
0041 
0042 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
0043 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
0044 static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
0045 
0046 module_param_array(index, int, NULL, 0444);
0047 MODULE_PARM_DESC(index, "Index value for CS5530 Audio driver.");
0048 module_param_array(id, charp, NULL, 0444);
0049 MODULE_PARM_DESC(id, "ID string for CS5530 Audio driver.");
0050 module_param_array(enable, bool, NULL, 0444);
0051 MODULE_PARM_DESC(enable, "Enable CS5530 Audio driver.");
0052 
0053 struct snd_cs5530 {
0054     struct snd_card *card;
0055     struct pci_dev *pci;
0056     struct snd_sb *sb;
0057     unsigned long pci_base;
0058 };
0059 
0060 static const struct pci_device_id snd_cs5530_ids[] = {
0061     {PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_AUDIO, PCI_ANY_ID,
0062                             PCI_ANY_ID, 0, 0},
0063     {0,}
0064 };
0065 
0066 MODULE_DEVICE_TABLE(pci, snd_cs5530_ids);
0067 
0068 static u8 snd_cs5530_mixer_read(unsigned long io, u8 reg)
0069 {
0070     outb(reg, io + 4);
0071     udelay(20);
0072     reg = inb(io + 5);
0073     udelay(20);
0074     return reg;
0075 }
0076 
0077 static int snd_cs5530_create(struct snd_card *card,
0078                  struct pci_dev *pci)
0079 {
0080     struct snd_cs5530 *chip = card->private_data;
0081     unsigned long sb_base;
0082     u8 irq, dma8, dma16 = 0;
0083     u16 map;
0084     void __iomem *mem;
0085     int err;
0086 
0087     err = pcim_enable_device(pci);
0088     if (err < 0)
0089         return err;
0090 
0091     chip->card = card;
0092     chip->pci = pci;
0093 
0094     err = pcim_iomap_regions(pci, 1 << 0, "CS5530");
0095     if (err < 0)
0096         return err;
0097     chip->pci_base = pci_resource_start(pci, 0);
0098     mem = pcim_iomap_table(pci)[0];
0099     map = readw(mem + 0x18);
0100 
0101     /* Map bits
0102         0:1 * 0x20 + 0x200 = sb base
0103         2   sb enable
0104         3   adlib enable
0105         5   MPU enable 0x330
0106         6   MPU enable 0x300
0107 
0108        The other bits may be used internally so must be masked */
0109 
0110     sb_base = 0x220 + 0x20 * (map & 3);
0111 
0112     if (map & (1<<2))
0113         dev_info(card->dev, "XpressAudio at 0x%lx\n", sb_base);
0114     else {
0115         dev_err(card->dev, "Could not find XpressAudio!\n");
0116         return -ENODEV;
0117     }
0118 
0119     if (map & (1<<5))
0120         dev_info(card->dev, "MPU at 0x300\n");
0121     else if (map & (1<<6))
0122         dev_info(card->dev, "MPU at 0x330\n");
0123 
0124     irq = snd_cs5530_mixer_read(sb_base, 0x80) & 0x0F;
0125     dma8 = snd_cs5530_mixer_read(sb_base, 0x81);
0126 
0127     if (dma8 & 0x20)
0128         dma16 = 5;
0129     else if (dma8 & 0x40)
0130         dma16 = 6;
0131     else if (dma8 & 0x80)
0132         dma16 = 7;
0133     else {
0134         dev_err(card->dev, "No 16bit DMA enabled\n");
0135         return -ENODEV;
0136     }
0137 
0138     if (dma8 & 0x01)
0139         dma8 = 0;
0140     else if (dma8 & 02)
0141         dma8 = 1;
0142     else if (dma8 & 0x08)
0143         dma8 = 3;
0144     else {
0145         dev_err(card->dev, "No 8bit DMA enabled\n");
0146         return -ENODEV;
0147     }
0148 
0149     if (irq & 1)
0150         irq = 9;
0151     else if (irq & 2)
0152         irq = 5;
0153     else if (irq & 4)
0154         irq = 7;
0155     else if (irq & 8)
0156         irq = 10;
0157     else {
0158         dev_err(card->dev, "SoundBlaster IRQ not set\n");
0159         return -ENODEV;
0160     }
0161 
0162     dev_info(card->dev, "IRQ: %d DMA8: %d DMA16: %d\n", irq, dma8, dma16);
0163 
0164     err = snd_sbdsp_create(card, sb_base, irq, snd_sb16dsp_interrupt, dma8,
0165                         dma16, SB_HW_CS5530, &chip->sb);
0166     if (err < 0) {
0167         dev_err(card->dev, "Could not create SoundBlaster\n");
0168         return err;
0169     }
0170 
0171     err = snd_sb16dsp_pcm(chip->sb, 0);
0172     if (err < 0) {
0173         dev_err(card->dev, "Could not create PCM\n");
0174         return err;
0175     }
0176 
0177     err = snd_sbmixer_new(chip->sb);
0178     if (err < 0) {
0179         dev_err(card->dev, "Could not create Mixer\n");
0180         return err;
0181     }
0182 
0183     return 0;
0184 }
0185 
0186 static int snd_cs5530_probe(struct pci_dev *pci,
0187                 const struct pci_device_id *pci_id)
0188 {
0189     static int dev;
0190     struct snd_card *card;
0191     struct snd_cs5530 *chip;
0192     int err;
0193 
0194     if (dev >= SNDRV_CARDS)
0195         return -ENODEV;
0196     if (!enable[dev]) {
0197         dev++;
0198         return -ENOENT;
0199     }
0200 
0201     err = snd_devm_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
0202                 sizeof(*chip), &card);
0203     if (err < 0)
0204         return err;
0205     chip = card->private_data;
0206 
0207     err = snd_cs5530_create(card, pci);
0208     if (err < 0)
0209         return err;
0210 
0211     strcpy(card->driver, "CS5530");
0212     strcpy(card->shortname, "CS5530 Audio");
0213     sprintf(card->longname, "%s at 0x%lx", card->shortname, chip->pci_base);
0214 
0215     err = snd_card_register(card);
0216     if (err < 0)
0217         return err;
0218     pci_set_drvdata(pci, card);
0219     dev++;
0220     return 0;
0221 }
0222 
0223 static struct pci_driver cs5530_driver = {
0224     .name = KBUILD_MODNAME,
0225     .id_table = snd_cs5530_ids,
0226     .probe = snd_cs5530_probe,
0227 };
0228 
0229 module_pci_driver(cs5530_driver);