cs5530.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  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 <[email protected]>
  6. * (C) Copyright 2003 Red Hat Inc <[email protected]>
  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. #include <linux/delay.h>
  30. #include <linux/module.h>
  31. #include <linux/pci.h>
  32. #include <linux/slab.h>
  33. #include <sound/core.h>
  34. #include <sound/sb.h>
  35. #include <sound/initval.h>
  36. MODULE_AUTHOR("Ash Willis");
  37. MODULE_DESCRIPTION("CS5530 Audio");
  38. MODULE_LICENSE("GPL");
  39. static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
  40. static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
  41. static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
  42. module_param_array(index, int, NULL, 0444);
  43. MODULE_PARM_DESC(index, "Index value for CS5530 Audio driver.");
  44. module_param_array(id, charp, NULL, 0444);
  45. MODULE_PARM_DESC(id, "ID string for CS5530 Audio driver.");
  46. module_param_array(enable, bool, NULL, 0444);
  47. MODULE_PARM_DESC(enable, "Enable CS5530 Audio driver.");
  48. struct snd_cs5530 {
  49. struct snd_card *card;
  50. struct pci_dev *pci;
  51. struct snd_sb *sb;
  52. unsigned long pci_base;
  53. };
  54. static const struct pci_device_id snd_cs5530_ids[] = {
  55. {PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_AUDIO, PCI_ANY_ID,
  56. PCI_ANY_ID, 0, 0},
  57. {0,}
  58. };
  59. MODULE_DEVICE_TABLE(pci, snd_cs5530_ids);
  60. static u8 snd_cs5530_mixer_read(unsigned long io, u8 reg)
  61. {
  62. outb(reg, io + 4);
  63. udelay(20);
  64. reg = inb(io + 5);
  65. udelay(20);
  66. return reg;
  67. }
  68. static int snd_cs5530_create(struct snd_card *card,
  69. struct pci_dev *pci)
  70. {
  71. struct snd_cs5530 *chip = card->private_data;
  72. unsigned long sb_base;
  73. u8 irq, dma8, dma16 = 0;
  74. u16 map;
  75. void __iomem *mem;
  76. int err;
  77. err = pcim_enable_device(pci);
  78. if (err < 0)
  79. return err;
  80. chip->card = card;
  81. chip->pci = pci;
  82. err = pcim_iomap_regions(pci, 1 << 0, "CS5530");
  83. if (err < 0)
  84. return err;
  85. chip->pci_base = pci_resource_start(pci, 0);
  86. mem = pcim_iomap_table(pci)[0];
  87. map = readw(mem + 0x18);
  88. /* Map bits
  89. 0:1 * 0x20 + 0x200 = sb base
  90. 2 sb enable
  91. 3 adlib enable
  92. 5 MPU enable 0x330
  93. 6 MPU enable 0x300
  94. The other bits may be used internally so must be masked */
  95. sb_base = 0x220 + 0x20 * (map & 3);
  96. if (map & (1<<2))
  97. dev_info(card->dev, "XpressAudio at 0x%lx\n", sb_base);
  98. else {
  99. dev_err(card->dev, "Could not find XpressAudio!\n");
  100. return -ENODEV;
  101. }
  102. if (map & (1<<5))
  103. dev_info(card->dev, "MPU at 0x300\n");
  104. else if (map & (1<<6))
  105. dev_info(card->dev, "MPU at 0x330\n");
  106. irq = snd_cs5530_mixer_read(sb_base, 0x80) & 0x0F;
  107. dma8 = snd_cs5530_mixer_read(sb_base, 0x81);
  108. if (dma8 & 0x20)
  109. dma16 = 5;
  110. else if (dma8 & 0x40)
  111. dma16 = 6;
  112. else if (dma8 & 0x80)
  113. dma16 = 7;
  114. else {
  115. dev_err(card->dev, "No 16bit DMA enabled\n");
  116. return -ENODEV;
  117. }
  118. if (dma8 & 0x01)
  119. dma8 = 0;
  120. else if (dma8 & 02)
  121. dma8 = 1;
  122. else if (dma8 & 0x08)
  123. dma8 = 3;
  124. else {
  125. dev_err(card->dev, "No 8bit DMA enabled\n");
  126. return -ENODEV;
  127. }
  128. if (irq & 1)
  129. irq = 9;
  130. else if (irq & 2)
  131. irq = 5;
  132. else if (irq & 4)
  133. irq = 7;
  134. else if (irq & 8)
  135. irq = 10;
  136. else {
  137. dev_err(card->dev, "SoundBlaster IRQ not set\n");
  138. return -ENODEV;
  139. }
  140. dev_info(card->dev, "IRQ: %d DMA8: %d DMA16: %d\n", irq, dma8, dma16);
  141. err = snd_sbdsp_create(card, sb_base, irq, snd_sb16dsp_interrupt, dma8,
  142. dma16, SB_HW_CS5530, &chip->sb);
  143. if (err < 0) {
  144. dev_err(card->dev, "Could not create SoundBlaster\n");
  145. return err;
  146. }
  147. err = snd_sb16dsp_pcm(chip->sb, 0);
  148. if (err < 0) {
  149. dev_err(card->dev, "Could not create PCM\n");
  150. return err;
  151. }
  152. err = snd_sbmixer_new(chip->sb);
  153. if (err < 0) {
  154. dev_err(card->dev, "Could not create Mixer\n");
  155. return err;
  156. }
  157. return 0;
  158. }
  159. static int snd_cs5530_probe(struct pci_dev *pci,
  160. const struct pci_device_id *pci_id)
  161. {
  162. static int dev;
  163. struct snd_card *card;
  164. struct snd_cs5530 *chip;
  165. int err;
  166. if (dev >= SNDRV_CARDS)
  167. return -ENODEV;
  168. if (!enable[dev]) {
  169. dev++;
  170. return -ENOENT;
  171. }
  172. err = snd_devm_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
  173. sizeof(*chip), &card);
  174. if (err < 0)
  175. return err;
  176. chip = card->private_data;
  177. err = snd_cs5530_create(card, pci);
  178. if (err < 0)
  179. return err;
  180. strcpy(card->driver, "CS5530");
  181. strcpy(card->shortname, "CS5530 Audio");
  182. sprintf(card->longname, "%s at 0x%lx", card->shortname, chip->pci_base);
  183. err = snd_card_register(card);
  184. if (err < 0)
  185. return err;
  186. pci_set_drvdata(pci, card);
  187. dev++;
  188. return 0;
  189. }
  190. static struct pci_driver cs5530_driver = {
  191. .name = KBUILD_MODNAME,
  192. .id_table = snd_cs5530_ids,
  193. .probe = snd_cs5530_probe,
  194. };
  195. module_pci_driver(cs5530_driver);