1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#include <linux/io.h>
21#include <linux/delay.h>
22#include <linux/init.h>
23#include <linux/time.h>
24#include <linux/wait.h>
25#include <linux/pnp.h>
26#include <linux/module.h>
27#include <sound/core.h>
28#include <sound/initval.h>
29#include <sound/wss.h>
30#include <sound/mpu401.h>
31#include <sound/opl3.h>
32
33#define PFX "azt2320: "
34
35MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>");
36MODULE_DESCRIPTION("Aztech Systems AZT2320");
37MODULE_LICENSE("GPL");
38
39static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
40static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
41static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP;
42static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
43static long wss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
44static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
45static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
46static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
47static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
48static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
49static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
50
51module_param_array(index, int, NULL, 0444);
52MODULE_PARM_DESC(index, "Index value for azt2320 based soundcard.");
53module_param_array(id, charp, NULL, 0444);
54MODULE_PARM_DESC(id, "ID string for azt2320 based soundcard.");
55module_param_array(enable, bool, NULL, 0444);
56MODULE_PARM_DESC(enable, "Enable azt2320 based soundcard.");
57
58struct snd_card_azt2320 {
59 int dev_no;
60 struct pnp_dev *dev;
61 struct pnp_dev *devmpu;
62 struct snd_wss *chip;
63};
64
65static const struct pnp_card_device_id snd_azt2320_pnpids[] = {
66
67 { .id = "AZT1008", .devs = { { "AZT1008" }, { "AZT2001" }, } },
68
69 { .id = "AZT2320", .devs = { { "AZT0001" }, { "AZT0002" }, } },
70
71 { .id = "AZT3000", .devs = { { "AZT1003" }, { "AZT2001" }, } },
72
73 { .id = "AZT3002", .devs = { { "AZT1004" }, { "AZT2001" }, } },
74
75 { .id = "AZT3005", .devs = { { "AZT1003" }, { "AZT2001" }, } },
76
77 { .id = "AZT3011", .devs = { { "AZT1003" }, { "AZT2001" }, } },
78 { .id = "" }
79};
80
81MODULE_DEVICE_TABLE(pnp_card, snd_azt2320_pnpids);
82
83#define DRIVER_NAME "snd-card-azt2320"
84
85static int snd_card_azt2320_pnp(int dev, struct snd_card_azt2320 *acard,
86 struct pnp_card_link *card,
87 const struct pnp_card_device_id *id)
88{
89 struct pnp_dev *pdev;
90 int err;
91
92 acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
93 if (acard->dev == NULL)
94 return -ENODEV;
95
96 acard->devmpu = pnp_request_card_device(card, id->devs[1].id, NULL);
97
98 pdev = acard->dev;
99
100 err = pnp_activate_dev(pdev);
101 if (err < 0) {
102 snd_printk(KERN_ERR PFX "AUDIO pnp configure failure\n");
103 return err;
104 }
105 port[dev] = pnp_port_start(pdev, 0);
106 fm_port[dev] = pnp_port_start(pdev, 1);
107 wss_port[dev] = pnp_port_start(pdev, 2);
108 dma1[dev] = pnp_dma(pdev, 0);
109 dma2[dev] = pnp_dma(pdev, 1);
110 irq[dev] = pnp_irq(pdev, 0);
111
112 pdev = acard->devmpu;
113 if (pdev != NULL) {
114 err = pnp_activate_dev(pdev);
115 if (err < 0)
116 goto __mpu_error;
117 mpu_port[dev] = pnp_port_start(pdev, 0);
118 mpu_irq[dev] = pnp_irq(pdev, 0);
119 } else {
120 __mpu_error:
121 if (pdev) {
122 pnp_release_card_device(pdev);
123 snd_printk(KERN_ERR PFX "MPU401 pnp configure failure, skipping\n");
124 }
125 acard->devmpu = NULL;
126 mpu_port[dev] = -1;
127 }
128
129 return 0;
130}
131
132
133static int snd_card_azt2320_command(unsigned long port, unsigned char val)
134{
135 int i;
136 unsigned long limit;
137
138 limit = jiffies + HZ / 10;
139 for (i = 50000; i && time_after(limit, jiffies); i--)
140 if (!(inb(port + 0x0c) & 0x80)) {
141 outb(val, port + 0x0c);
142 return 0;
143 }
144 return -EBUSY;
145}
146
147static int snd_card_azt2320_enable_wss(unsigned long port)
148{
149 int error;
150
151 error = snd_card_azt2320_command(port, 0x09);
152 if (error)
153 return error;
154 error = snd_card_azt2320_command(port, 0x00);
155 if (error)
156 return error;
157
158 mdelay(5);
159 return 0;
160}
161
162static int snd_card_azt2320_probe(int dev,
163 struct pnp_card_link *pcard,
164 const struct pnp_card_device_id *pid)
165{
166 int error;
167 struct snd_card *card;
168 struct snd_card_azt2320 *acard;
169 struct snd_wss *chip;
170 struct snd_opl3 *opl3;
171
172 error = snd_devm_card_new(&pcard->card->dev,
173 index[dev], id[dev], THIS_MODULE,
174 sizeof(struct snd_card_azt2320), &card);
175 if (error < 0)
176 return error;
177 acard = card->private_data;
178
179 error = snd_card_azt2320_pnp(dev, acard, pcard, pid);
180 if (error)
181 return error;
182
183 error = snd_card_azt2320_enable_wss(port[dev]);
184 if (error)
185 return error;
186
187 error = snd_wss_create(card, wss_port[dev], -1,
188 irq[dev],
189 dma1[dev], dma2[dev],
190 WSS_HW_DETECT, 0, &chip);
191 if (error < 0)
192 return error;
193
194 strcpy(card->driver, "AZT2320");
195 strcpy(card->shortname, "Aztech AZT2320");
196 sprintf(card->longname, "%s, WSS at 0x%lx, irq %i, dma %i&%i",
197 card->shortname, chip->port, irq[dev], dma1[dev], dma2[dev]);
198
199 error = snd_wss_pcm(chip, 0);
200 if (error < 0)
201 return error;
202 error = snd_wss_mixer(chip);
203 if (error < 0)
204 return error;
205 error = snd_wss_timer(chip, 0);
206 if (error < 0)
207 return error;
208
209 if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) {
210 if (snd_mpu401_uart_new(card, 0, MPU401_HW_AZT2320,
211 mpu_port[dev], 0,
212 mpu_irq[dev], NULL) < 0)
213 snd_printk(KERN_ERR PFX "no MPU-401 device at 0x%lx\n", mpu_port[dev]);
214 }
215
216 if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) {
217 if (snd_opl3_create(card,
218 fm_port[dev], fm_port[dev] + 2,
219 OPL3_HW_AUTO, 0, &opl3) < 0) {
220 snd_printk(KERN_ERR PFX "no OPL device at 0x%lx-0x%lx\n",
221 fm_port[dev], fm_port[dev] + 2);
222 } else {
223 error = snd_opl3_timer_new(opl3, 1, 2);
224 if (error < 0)
225 return error;
226 error = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
227 if (error < 0)
228 return error;
229 }
230 }
231
232 error = snd_card_register(card);
233 if (error < 0)
234 return error;
235 pnp_set_card_drvdata(pcard, card);
236 return 0;
237}
238
239static unsigned int azt2320_devices;
240
241static int snd_azt2320_pnp_detect(struct pnp_card_link *card,
242 const struct pnp_card_device_id *id)
243{
244 static int dev;
245 int res;
246
247 for ( ; dev < SNDRV_CARDS; dev++) {
248 if (!enable[dev])
249 continue;
250 res = snd_card_azt2320_probe(dev, card, id);
251 if (res < 0)
252 return res;
253 dev++;
254 azt2320_devices++;
255 return 0;
256 }
257 return -ENODEV;
258}
259
260#ifdef CONFIG_PM
261static int snd_azt2320_pnp_suspend(struct pnp_card_link *pcard, pm_message_t state)
262{
263 struct snd_card *card = pnp_get_card_drvdata(pcard);
264 struct snd_card_azt2320 *acard = card->private_data;
265 struct snd_wss *chip = acard->chip;
266
267 snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
268 chip->suspend(chip);
269 return 0;
270}
271
272static int snd_azt2320_pnp_resume(struct pnp_card_link *pcard)
273{
274 struct snd_card *card = pnp_get_card_drvdata(pcard);
275 struct snd_card_azt2320 *acard = card->private_data;
276 struct snd_wss *chip = acard->chip;
277
278 chip->resume(chip);
279 snd_power_change_state(card, SNDRV_CTL_POWER_D0);
280 return 0;
281}
282#endif
283
284static struct pnp_card_driver azt2320_pnpc_driver = {
285 .flags = PNP_DRIVER_RES_DISABLE,
286 .name = "azt2320",
287 .id_table = snd_azt2320_pnpids,
288 .probe = snd_azt2320_pnp_detect,
289#ifdef CONFIG_PM
290 .suspend = snd_azt2320_pnp_suspend,
291 .resume = snd_azt2320_pnp_resume,
292#endif
293};
294
295static int __init alsa_card_azt2320_init(void)
296{
297 int err;
298
299 err = pnp_register_card_driver(&azt2320_pnpc_driver);
300 if (err)
301 return err;
302
303 if (!azt2320_devices) {
304 pnp_unregister_card_driver(&azt2320_pnpc_driver);
305#ifdef MODULE
306 snd_printk(KERN_ERR "no AZT2320 based soundcards found\n");
307#endif
308 return -ENODEV;
309 }
310 return 0;
311}
312
313static void __exit alsa_card_azt2320_exit(void)
314{
315 pnp_unregister_card_driver(&azt2320_pnpc_driver);
316}
317
318module_init(alsa_card_azt2320_init)
319module_exit(alsa_card_azt2320_exit)
320