brintos

brintos / linux-shallow public Read only

0
0
Text · 8.3 KiB · b937c91 Raw
318 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*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't11    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 WSS17    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	strcpy(card->driver, "AZT2320");193	strcpy(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_PM259static 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#endif281 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_PM288	.suspend	= snd_azt2320_pnp_suspend,289	.resume		= snd_azt2320_pnp_resume,290#endif291};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 MODULE304		pr_err("no AZT2320 based soundcards found\n");305#endif306		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)318