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 38 MODULE_AUTHOR("Ash Willis"); 39 MODULE_DESCRIPTION("CS5530 Audio"); 40 MODULE_LICENSE("GPL"); 41 42 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; 43 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; 44 static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; 45 46 module_param_array(index, int, NULL, 0444); 47 MODULE_PARM_DESC(index, "Index value for CS5530 Audio driver."); 48 module_param_array(id, charp, NULL, 0444); 49 MODULE_PARM_DESC(id, "ID string for CS5530 Audio driver."); 50 module_param_array(enable, bool, NULL, 0444); 51 MODULE_PARM_DESC(enable, "Enable CS5530 Audio driver."); 52 53 struct snd_cs5530 { 54 struct snd_card *card; 55 struct pci_dev *pci; 56 struct snd_sb *sb; 57 unsigned long pci_base; 58 }; 59 60 static 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 66 MODULE_DEVICE_TABLE(pci, snd_cs5530_ids); 67 68 static int snd_cs5530_free(struct snd_cs5530 *chip) 69 { 70 pci_release_regions(chip->pci); 71 pci_disable_device(chip->pci); 72 kfree(chip); 73 return 0; 74 } 75 76 static int snd_cs5530_dev_free(struct snd_device *device) 77 { 78 struct snd_cs5530 *chip = device->device_data; 79 return snd_cs5530_free(chip); 80 } 81 82 static void snd_cs5530_remove(struct pci_dev *pci) 83 { 84 snd_card_free(pci_get_drvdata(pci)); 85 } 86 87 static u8 snd_cs5530_mixer_read(unsigned long io, u8 reg) 88 { 89 outb(reg, io + 4); 90 udelay(20); 91 reg = inb(io + 5); 92 udelay(20); 93 return reg; 94 } 95 96 static int snd_cs5530_create(struct snd_card *card, 97 struct pci_dev *pci, 98 struct snd_cs5530 **rchip) 99 { 100 struct snd_cs5530 *chip; 101 unsigned long sb_base; 102 u8 irq, dma8, dma16 = 0; 103 u16 map; 104 void __iomem *mem; 105 int err; 106 107 static const struct snd_device_ops ops = { 108 .dev_free = snd_cs5530_dev_free, 109 }; 110 *rchip = NULL; 111 112 err = pci_enable_device(pci); 113 if (err < 0) 114 return err; 115 116 chip = kzalloc(sizeof(*chip), GFP_KERNEL); 117 if (chip == NULL) { 118 pci_disable_device(pci); 119 return -ENOMEM; 120 } 121 122 chip->card = card; 123 chip->pci = pci; 124 125 err = pci_request_regions(pci, "CS5530"); 126 if (err < 0) { 127 kfree(chip); 128 pci_disable_device(pci); 129 return err; 130 } 131 chip->pci_base = pci_resource_start(pci, 0); 132 133 mem = pci_ioremap_bar(pci, 0); 134 if (mem == NULL) { 135 snd_cs5530_free(chip); 136 return -EBUSY; 137 } 138 139 map = readw(mem + 0x18); 140 iounmap(mem); 141 142 /* Map bits 143 0:1 * 0x20 + 0x200 = sb base 144 2 sb enable 145 3 adlib enable 146 5 MPU enable 0x330 147 6 MPU enable 0x300 148 149 The other bits may be used internally so must be masked */ 150 151 sb_base = 0x220 + 0x20 * (map & 3); 152 153 if (map & (1<<2)) 154 dev_info(card->dev, "XpressAudio at 0x%lx\n", sb_base); 155 else { 156 dev_err(card->dev, "Could not find XpressAudio!\n"); 157 snd_cs5530_free(chip); 158 return -ENODEV; 159 } 160 161 if (map & (1<<5)) 162 dev_info(card->dev, "MPU at 0x300\n"); 163 else if (map & (1<<6)) 164 dev_info(card->dev, "MPU at 0x330\n"); 165 166 irq = snd_cs5530_mixer_read(sb_base, 0x80) & 0x0F; 167 dma8 = snd_cs5530_mixer_read(sb_base, 0x81); 168 169 if (dma8 & 0x20) 170 dma16 = 5; 171 else if (dma8 & 0x40) 172 dma16 = 6; 173 else if (dma8 & 0x80) 174 dma16 = 7; 175 else { 176 dev_err(card->dev, "No 16bit DMA enabled\n"); 177 snd_cs5530_free(chip); 178 return -ENODEV; 179 } 180 181 if (dma8 & 0x01) 182 dma8 = 0; 183 else if (dma8 & 02) 184 dma8 = 1; 185 else if (dma8 & 0x08) 186 dma8 = 3; 187 else { 188 dev_err(card->dev, "No 8bit DMA enabled\n"); 189 snd_cs5530_free(chip); 190 return -ENODEV; 191 } 192 193 if (irq & 1) 194 irq = 9; 195 else if (irq & 2) 196 irq = 5; 197 else if (irq & 4) 198 irq = 7; 199 else if (irq & 8) 200 irq = 10; 201 else { 202 dev_err(card->dev, "SoundBlaster IRQ not set\n"); 203 snd_cs5530_free(chip); 204 return -ENODEV; 205 } 206 207 dev_info(card->dev, "IRQ: %d DMA8: %d DMA16: %d\n", irq, dma8, dma16); 208 209 err = snd_sbdsp_create(card, sb_base, irq, snd_sb16dsp_interrupt, dma8, 210 dma16, SB_HW_CS5530, &chip->sb); 211 if (err < 0) { 212 dev_err(card->dev, "Could not create SoundBlaster\n"); 213 snd_cs5530_free(chip); 214 return err; 215 } 216 217 err = snd_sb16dsp_pcm(chip->sb, 0); 218 if (err < 0) { 219 dev_err(card->dev, "Could not create PCM\n"); 220 snd_cs5530_free(chip); 221 return err; 222 } 223 224 err = snd_sbmixer_new(chip->sb); 225 if (err < 0) { 226 dev_err(card->dev, "Could not create Mixer\n"); 227 snd_cs5530_free(chip); 228 return err; 229 } 230 231 err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); 232 if (err < 0) { 233 snd_cs5530_free(chip); 234 return err; 235 } 236 237 *rchip = chip; 238 return 0; 239 } 240 241 static int snd_cs5530_probe(struct pci_dev *pci, 242 const struct pci_device_id *pci_id) 243 { 244 static int dev; 245 struct snd_card *card; 246 struct snd_cs5530 *chip = NULL; 247 int err; 248 249 if (dev >= SNDRV_CARDS) 250 return -ENODEV; 251 if (!enable[dev]) { 252 dev++; 253 return -ENOENT; 254 } 255 256 err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, 257 0, &card); 258 259 if (err < 0) 260 return err; 261 262 err = snd_cs5530_create(card, pci, &chip); 263 if (err < 0) { 264 snd_card_free(card); 265 return err; 266 } 267 268 strcpy(card->driver, "CS5530"); 269 strcpy(card->shortname, "CS5530 Audio"); 270 sprintf(card->longname, "%s at 0x%lx", card->shortname, chip->pci_base); 271 272 err = snd_card_register(card); 273 if (err < 0) { 274 snd_card_free(card); 275 return err; 276 } 277 pci_set_drvdata(pci, card); 278 dev++; 279 return 0; 280 } 281 282 static struct pci_driver cs5530_driver = { 283 .name = KBUILD_MODNAME, 284 .id_table = snd_cs5530_ids, 285 .probe = snd_cs5530_probe, 286 .remove = snd_cs5530_remove, 287 }; 288 289 module_pci_driver(cs5530_driver); 290