1 | // SPDX-License-Identifier: GPL-2.0-or-later
|
---|
2 | /*
|
---|
3 | * The driver for the Cirrus Logic's Sound Fusion CS46XX based soundcards
|
---|
4 | * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
|
---|
5 | */
|
---|
6 |
|
---|
7 | /*
|
---|
8 | NOTES:
|
---|
9 | - sometimes the sound is metallic and sibilant, unloading and
|
---|
10 | reloading the module may solve this.
|
---|
11 | */
|
---|
12 |
|
---|
13 | #ifdef TARGET_OS2
|
---|
14 | #define KBUILD_MODNAME "cs46xx"
|
---|
15 | #endif
|
---|
16 | #include <linux/pci.h>
|
---|
17 | #include <linux/time.h>
|
---|
18 | #include <linux/init.h>
|
---|
19 | #include <linux/module.h>
|
---|
20 | #include <sound/core.h>
|
---|
21 | #include "cs46xx.h"
|
---|
22 | #include <sound/initval.h>
|
---|
23 |
|
---|
24 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
|
---|
25 | MODULE_DESCRIPTION("Cirrus Logic Sound Fusion CS46XX");
|
---|
26 | MODULE_LICENSE("GPL");
|
---|
27 |
|
---|
28 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
|
---|
29 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
|
---|
30 | static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */
|
---|
31 | static bool external_amp[SNDRV_CARDS];
|
---|
32 | static bool thinkpad[SNDRV_CARDS];
|
---|
33 | #ifndef TARGET_OS2
|
---|
34 | static bool mmap_valid[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
|
---|
35 | #else
|
---|
36 | static bool mmap_valid[SNDRV_CARDS] = {1,1,1,1,1,1,1,1};
|
---|
37 | #endif
|
---|
38 |
|
---|
39 | module_param_array(index, int, NULL, 0444);
|
---|
40 | MODULE_PARM_DESC(index, "Index value for the CS46xx soundcard.");
|
---|
41 | module_param_array(id, charp, NULL, 0444);
|
---|
42 | MODULE_PARM_DESC(id, "ID string for the CS46xx soundcard.");
|
---|
43 | module_param_array(enable, bool, NULL, 0444);
|
---|
44 | MODULE_PARM_DESC(enable, "Enable CS46xx soundcard.");
|
---|
45 | module_param_array(external_amp, bool, NULL, 0444);
|
---|
46 | MODULE_PARM_DESC(external_amp, "Force to enable external amplifier.");
|
---|
47 | module_param_array(thinkpad, bool, NULL, 0444);
|
---|
48 | MODULE_PARM_DESC(thinkpad, "Force to enable Thinkpad's CLKRUN control.");
|
---|
49 | module_param_array(mmap_valid, bool, NULL, 0444);
|
---|
50 | MODULE_PARM_DESC(mmap_valid, "Support OSS mmap.");
|
---|
51 |
|
---|
52 | static const struct pci_device_id snd_cs46xx_ids[] = {
|
---|
53 | { PCI_VDEVICE(CIRRUS, 0x6001), 0, }, /* CS4280 */
|
---|
54 | { PCI_VDEVICE(CIRRUS, 0x6003), 0, }, /* CS4612 */
|
---|
55 | { PCI_VDEVICE(CIRRUS, 0x6004), 0, }, /* CS4615 */
|
---|
56 | { 0, }
|
---|
57 | };
|
---|
58 |
|
---|
59 | MODULE_DEVICE_TABLE(pci, snd_cs46xx_ids);
|
---|
60 |
|
---|
61 | static int snd_card_cs46xx_probe(struct pci_dev *pci,
|
---|
62 | const struct pci_device_id *pci_id)
|
---|
63 | {
|
---|
64 | static int dev;
|
---|
65 | struct snd_card *card;
|
---|
66 | struct snd_cs46xx *chip;
|
---|
67 | int err;
|
---|
68 |
|
---|
69 | if (dev >= SNDRV_CARDS)
|
---|
70 | return -ENODEV;
|
---|
71 | if (!enable[dev]) {
|
---|
72 | dev++;
|
---|
73 | return -ENOENT;
|
---|
74 | }
|
---|
75 |
|
---|
76 | err = snd_devm_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
|
---|
77 | sizeof(*chip), &card);
|
---|
78 | if (err < 0)
|
---|
79 | return err;
|
---|
80 | chip = card->private_data;
|
---|
81 | err = snd_cs46xx_create(card, pci,
|
---|
82 | external_amp[dev], thinkpad[dev]);
|
---|
83 | if (err < 0)
|
---|
84 | goto error;
|
---|
85 | card->private_data = chip;
|
---|
86 | chip->accept_valid = mmap_valid[dev];
|
---|
87 | err = snd_cs46xx_pcm(chip, 0);
|
---|
88 | if (err < 0)
|
---|
89 | goto error;
|
---|
90 | #ifdef CONFIG_SND_CS46XX_NEW_DSP
|
---|
91 | err = snd_cs46xx_pcm_rear(chip, 1);
|
---|
92 | if (err < 0)
|
---|
93 | goto error;
|
---|
94 | err = snd_cs46xx_pcm_iec958(chip, 2);
|
---|
95 | if (err < 0)
|
---|
96 | goto error;
|
---|
97 | #endif
|
---|
98 | err = snd_cs46xx_mixer(chip, 2);
|
---|
99 | if (err < 0)
|
---|
100 | goto error;
|
---|
101 | #ifdef CONFIG_SND_CS46XX_NEW_DSP
|
---|
102 | if (chip->nr_ac97_codecs ==2) {
|
---|
103 | err = snd_cs46xx_pcm_center_lfe(chip, 3);
|
---|
104 | if (err < 0)
|
---|
105 | goto error;
|
---|
106 | }
|
---|
107 | #endif
|
---|
108 | err = snd_cs46xx_midi(chip, 0);
|
---|
109 | if (err < 0)
|
---|
110 | goto error;
|
---|
111 | err = snd_cs46xx_start_dsp(chip);
|
---|
112 | if (err < 0)
|
---|
113 | goto error;
|
---|
114 |
|
---|
115 | snd_cs46xx_gameport(chip);
|
---|
116 |
|
---|
117 | strcpy(card->driver, "CS46xx");
|
---|
118 | strcpy(card->shortname, "Sound Fusion CS46xx");
|
---|
119 | sprintf(card->longname, "%s at 0x%lx/0x%lx, irq %i",
|
---|
120 | card->shortname,
|
---|
121 | chip->ba0_addr,
|
---|
122 | chip->ba1_addr,
|
---|
123 | chip->irq);
|
---|
124 |
|
---|
125 | err = snd_card_register(card);
|
---|
126 | if (err < 0)
|
---|
127 | goto error;
|
---|
128 |
|
---|
129 | pci_set_drvdata(pci, card);
|
---|
130 | dev++;
|
---|
131 | return 0;
|
---|
132 |
|
---|
133 | error:
|
---|
134 | snd_card_free(card);
|
---|
135 | return err;
|
---|
136 | }
|
---|
137 |
|
---|
138 | static struct pci_driver cs46xx_driver = {
|
---|
139 | .name = KBUILD_MODNAME,
|
---|
140 | .id_table = snd_cs46xx_ids,
|
---|
141 | .probe = snd_card_cs46xx_probe,
|
---|
142 | #ifdef CONFIG_PM_SLEEP
|
---|
143 | .driver = {
|
---|
144 | .pm = &snd_cs46xx_pm,
|
---|
145 | },
|
---|
146 | #endif
|
---|
147 | };
|
---|
148 |
|
---|
149 | module_pci_driver(cs46xx_driver);
|
---|