Linux Audio

Check our new training course

Linux debugging, profiling, tracing and performance analysis training

Apr 14-17, 2025
Register
Loading...
v6.2
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3    card-azt2320.c - driver for Aztech Systems AZT2320 based soundcards.
  4    Copyright (C) 1999-2000 by Massimo Piccioni <dafastidio@libero.it>
  5
  6*/
  7
  8/*
  9    This driver should provide support for most Aztech AZT2320 based cards.
 10    Several AZT2316 chips are also supported/tested, but autoprobe doesn't
 11    work: all module option have to be set.
 12
 13    No docs available for us at Aztech headquarters !!!   Unbelievable ...
 14    No other help obtained.
 15
 16    Thanks to Rainer Wiesner <rainer.wiesner@01019freenet.de> for the WSS
 17    activation method (full-duplex audio!).
 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;	/* Index 0-MAX */
 40static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
 41static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */
 42static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* PnP setup */
 43static long wss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* PnP setup */
 44static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* PnP setup */
 45static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* PnP setup */
 46static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* Pnp setup */
 47static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* Pnp setup */
 48static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* PnP setup */
 49static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* PnP setup */
 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	/* PRO16V */
 67	{ .id = "AZT1008", .devs = { { "AZT1008" }, { "AZT2001" }, } },
 68	/* Aztech Sound Galaxy 16 */
 69	{ .id = "AZT2320", .devs = { { "AZT0001" }, { "AZT0002" }, } },
 70	/* Packard Bell Sound III 336 AM/SP */
 71	{ .id = "AZT3000", .devs = { { "AZT1003" }, { "AZT2001" }, } },
 72	/* AT3300 */
 73	{ .id = "AZT3002", .devs = { { "AZT1004" }, { "AZT2001" }, } },
 74	/* --- */
 75	{ .id = "AZT3005", .devs = { { "AZT1003" }, { "AZT2001" }, } },
 76	/* --- */
 77	{ .id = "AZT3011", .devs = { { "AZT1003" }, { "AZT2001" }, } },
 78	{ .id = "" }	/* end */
 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/* same of snd_sbdsp_command by Jaroslav Kysela */
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)
v5.4
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3    card-azt2320.c - driver for Aztech Systems AZT2320 based soundcards.
  4    Copyright (C) 1999-2000 by Massimo Piccioni <dafastidio@libero.it>
  5
  6*/
  7
  8/*
  9    This driver should provide support for most Aztech AZT2320 based cards.
 10    Several AZT2316 chips are also supported/tested, but autoprobe doesn't
 11    work: all module option have to be set.
 12
 13    No docs available for us at Aztech headquarters !!!   Unbelievable ...
 14    No other help obtained.
 15
 16    Thanks to Rainer Wiesner <rainer.wiesner@01019freenet.de> for the WSS
 17    activation method (full-duplex audio!).
 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");
 38MODULE_SUPPORTED_DEVICE("{{Aztech Systems,PRO16V},"
 39		"{Aztech Systems,AZT2320},"
 40		"{Aztech Systems,AZT3300},"
 41		"{Aztech Systems,AZT2320},"
 42		"{Aztech Systems,AZT3000}}");
 43
 44static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
 45static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
 46static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */
 47static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* PnP setup */
 48static long wss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* PnP setup */
 49static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* PnP setup */
 50static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* PnP setup */
 51static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* Pnp setup */
 52static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* Pnp setup */
 53static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* PnP setup */
 54static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* PnP setup */
 55
 56module_param_array(index, int, NULL, 0444);
 57MODULE_PARM_DESC(index, "Index value for azt2320 based soundcard.");
 58module_param_array(id, charp, NULL, 0444);
 59MODULE_PARM_DESC(id, "ID string for azt2320 based soundcard.");
 60module_param_array(enable, bool, NULL, 0444);
 61MODULE_PARM_DESC(enable, "Enable azt2320 based soundcard.");
 62
 63struct snd_card_azt2320 {
 64	int dev_no;
 65	struct pnp_dev *dev;
 66	struct pnp_dev *devmpu;
 67	struct snd_wss *chip;
 68};
 69
 70static const struct pnp_card_device_id snd_azt2320_pnpids[] = {
 71	/* PRO16V */
 72	{ .id = "AZT1008", .devs = { { "AZT1008" }, { "AZT2001" }, } },
 73	/* Aztech Sound Galaxy 16 */
 74	{ .id = "AZT2320", .devs = { { "AZT0001" }, { "AZT0002" }, } },
 75	/* Packard Bell Sound III 336 AM/SP */
 76	{ .id = "AZT3000", .devs = { { "AZT1003" }, { "AZT2001" }, } },
 77	/* AT3300 */
 78	{ .id = "AZT3002", .devs = { { "AZT1004" }, { "AZT2001" }, } },
 79	/* --- */
 80	{ .id = "AZT3005", .devs = { { "AZT1003" }, { "AZT2001" }, } },
 81	/* --- */
 82	{ .id = "AZT3011", .devs = { { "AZT1003" }, { "AZT2001" }, } },
 83	{ .id = "" }	/* end */
 84};
 85
 86MODULE_DEVICE_TABLE(pnp_card, snd_azt2320_pnpids);
 87
 88#define	DRIVER_NAME	"snd-card-azt2320"
 89
 90static int snd_card_azt2320_pnp(int dev, struct snd_card_azt2320 *acard,
 91				struct pnp_card_link *card,
 92				const struct pnp_card_device_id *id)
 93{
 94	struct pnp_dev *pdev;
 95	int err;
 96
 97	acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
 98	if (acard->dev == NULL)
 99		return -ENODEV;
100
101	acard->devmpu = pnp_request_card_device(card, id->devs[1].id, NULL);
102
103	pdev = acard->dev;
104
105	err = pnp_activate_dev(pdev);
106	if (err < 0) {
107		snd_printk(KERN_ERR PFX "AUDIO pnp configure failure\n");
108		return err;
109	}
110	port[dev] = pnp_port_start(pdev, 0);
111	fm_port[dev] = pnp_port_start(pdev, 1);
112	wss_port[dev] = pnp_port_start(pdev, 2);
113	dma1[dev] = pnp_dma(pdev, 0);
114	dma2[dev] = pnp_dma(pdev, 1);
115	irq[dev] = pnp_irq(pdev, 0);
116
117	pdev = acard->devmpu;
118	if (pdev != NULL) {
119		err = pnp_activate_dev(pdev);
120		if (err < 0)
121			goto __mpu_error;
122		mpu_port[dev] = pnp_port_start(pdev, 0);
123		mpu_irq[dev] = pnp_irq(pdev, 0);
124	} else {
125	     __mpu_error:
126	     	if (pdev) {
127		     	pnp_release_card_device(pdev);
128	     		snd_printk(KERN_ERR PFX "MPU401 pnp configure failure, skipping\n");
129	     	}
130	     	acard->devmpu = NULL;
131	     	mpu_port[dev] = -1;
132	}
133
134	return 0;
135}
136
137/* same of snd_sbdsp_command by Jaroslav Kysela */
138static int snd_card_azt2320_command(unsigned long port, unsigned char val)
139{
140	int i;
141	unsigned long limit;
142
143	limit = jiffies + HZ / 10;
144	for (i = 50000; i && time_after(limit, jiffies); i--)
145		if (!(inb(port + 0x0c) & 0x80)) {
146			outb(val, port + 0x0c);
147			return 0;
148		}
149	return -EBUSY;
150}
151
152static int snd_card_azt2320_enable_wss(unsigned long port)
153{
154	int error;
155
156	if ((error = snd_card_azt2320_command(port, 0x09)))
 
157		return error;
158	if ((error = snd_card_azt2320_command(port, 0x00)))
 
159		return error;
160
161	mdelay(5);
162	return 0;
163}
164
165static int snd_card_azt2320_probe(int dev,
166				  struct pnp_card_link *pcard,
167				  const struct pnp_card_device_id *pid)
168{
169	int error;
170	struct snd_card *card;
171	struct snd_card_azt2320 *acard;
172	struct snd_wss *chip;
173	struct snd_opl3 *opl3;
174
175	error = snd_card_new(&pcard->card->dev,
176			     index[dev], id[dev], THIS_MODULE,
177			     sizeof(struct snd_card_azt2320), &card);
178	if (error < 0)
179		return error;
180	acard = card->private_data;
181
182	if ((error = snd_card_azt2320_pnp(dev, acard, pcard, pid))) {
183		snd_card_free(card);
184		return error;
185	}
186
187	if ((error = snd_card_azt2320_enable_wss(port[dev]))) {
188		snd_card_free(card);
189		return error;
190	}
191
192	error = snd_wss_create(card, wss_port[dev], -1,
193			       irq[dev],
194			       dma1[dev], dma2[dev],
195			       WSS_HW_DETECT, 0, &chip);
196	if (error < 0) {
197		snd_card_free(card);
198		return error;
199	}
200
201	strcpy(card->driver, "AZT2320");
202	strcpy(card->shortname, "Aztech AZT2320");
203	sprintf(card->longname, "%s, WSS at 0x%lx, irq %i, dma %i&%i",
204		card->shortname, chip->port, irq[dev], dma1[dev], dma2[dev]);
205
206	error = snd_wss_pcm(chip, 0);
207	if (error < 0) {
208		snd_card_free(card);
209		return error;
210	}
211	error = snd_wss_mixer(chip);
212	if (error < 0) {
213		snd_card_free(card);
214		return error;
215	}
216	error = snd_wss_timer(chip, 0);
217	if (error < 0) {
218		snd_card_free(card);
219		return error;
220	}
221
222	if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) {
223		if (snd_mpu401_uart_new(card, 0, MPU401_HW_AZT2320,
224				mpu_port[dev], 0,
225				mpu_irq[dev], NULL) < 0)
226			snd_printk(KERN_ERR PFX "no MPU-401 device at 0x%lx\n", mpu_port[dev]);
227	}
228
229	if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) {
230		if (snd_opl3_create(card,
231				    fm_port[dev], fm_port[dev] + 2,
232				    OPL3_HW_AUTO, 0, &opl3) < 0) {
233			snd_printk(KERN_ERR PFX "no OPL device at 0x%lx-0x%lx\n",
234				   fm_port[dev], fm_port[dev] + 2);
235		} else {
236			if ((error = snd_opl3_timer_new(opl3, 1, 2)) < 0) {
237				snd_card_free(card);
238				return error;
239			}
240			if ((error = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) {
241				snd_card_free(card);
242				return error;
243			}
244		}
245	}
246
247	if ((error = snd_card_register(card)) < 0) {
248		snd_card_free(card);
249		return error;
250	}
251	pnp_set_card_drvdata(pcard, card);
252	return 0;
253}
254
255static unsigned int azt2320_devices;
256
257static int snd_azt2320_pnp_detect(struct pnp_card_link *card,
258				  const struct pnp_card_device_id *id)
259{
260	static int dev;
261	int res;
262
263	for ( ; dev < SNDRV_CARDS; dev++) {
264		if (!enable[dev])
265			continue;
266		res = snd_card_azt2320_probe(dev, card, id);
267		if (res < 0)
268			return res;
269		dev++;
270		azt2320_devices++;
271		return 0;
272	}
273        return -ENODEV;
274}
275
276static void snd_azt2320_pnp_remove(struct pnp_card_link *pcard)
277{
278	snd_card_free(pnp_get_card_drvdata(pcard));
279	pnp_set_card_drvdata(pcard, NULL);
280}
281
282#ifdef CONFIG_PM
283static int snd_azt2320_pnp_suspend(struct pnp_card_link *pcard, pm_message_t state)
284{
285	struct snd_card *card = pnp_get_card_drvdata(pcard);
286	struct snd_card_azt2320 *acard = card->private_data;
287	struct snd_wss *chip = acard->chip;
288
289	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
290	chip->suspend(chip);
291	return 0;
292}
293
294static int snd_azt2320_pnp_resume(struct pnp_card_link *pcard)
295{
296	struct snd_card *card = pnp_get_card_drvdata(pcard);
297	struct snd_card_azt2320 *acard = card->private_data;
298	struct snd_wss *chip = acard->chip;
299
300	chip->resume(chip);
301	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
302	return 0;
303}
304#endif
305
306static struct pnp_card_driver azt2320_pnpc_driver = {
307	.flags          = PNP_DRIVER_RES_DISABLE,
308	.name           = "azt2320",
309	.id_table       = snd_azt2320_pnpids,
310	.probe          = snd_azt2320_pnp_detect,
311	.remove         = snd_azt2320_pnp_remove,
312#ifdef CONFIG_PM
313	.suspend	= snd_azt2320_pnp_suspend,
314	.resume		= snd_azt2320_pnp_resume,
315#endif
316};
317
318static int __init alsa_card_azt2320_init(void)
319{
320	int err;
321
322	err = pnp_register_card_driver(&azt2320_pnpc_driver);
323	if (err)
324		return err;
325
326	if (!azt2320_devices) {
327		pnp_unregister_card_driver(&azt2320_pnpc_driver);
328#ifdef MODULE
329		snd_printk(KERN_ERR "no AZT2320 based soundcards found\n");
330#endif
331		return -ENODEV;
332	}
333	return 0;
334}
335
336static void __exit alsa_card_azt2320_exit(void)
337{
338	pnp_unregister_card_driver(&azt2320_pnpc_driver);
339}
340
341module_init(alsa_card_azt2320_init)
342module_exit(alsa_card_azt2320_exit)