File Index
Files and directories
Sign in
FILE

azt2320.c

File preview with syntax highlighting.

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