brintos

brintos / linux-shallow public Read only

0
0
Text · 8.9 KiB · e70dbf0 Raw
339 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2 3/*4    card-als100.c - driver for Avance Logic ALS100 based soundcards.5    Copyright (C) 1999-2000 by Massimo Piccioni <dafastidio@libero.it>6    Copyright (C) 1999-2002 by Massimo Piccioni <dafastidio@libero.it>7 8    Thanks to Pierfrancesco 'qM2' Passerini.9 10    Generalised for soundcards based on DT-0196 and ALS-007 chips11    by Jonathan Woithe <jwoithe@just42.net>: June 2002.12 13*/14 15#include <linux/init.h>16#include <linux/wait.h>17#include <linux/time.h>18#include <linux/pnp.h>19#include <linux/module.h>20#include <sound/core.h>21#include <sound/initval.h>22#include <sound/mpu401.h>23#include <sound/opl3.h>24#include <sound/sb.h>25 26MODULE_DESCRIPTION("Avance Logic ALS007/ALS1X0");27MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>");28MODULE_LICENSE("GPL");29 30static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */31static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */32static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;	/* Enable this card */33static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* PnP setup */34static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* PnP setup */35static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* PnP setup */36static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* PnP setup */37static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* PnP setup */38static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* PnP setup */39static int dma16[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* PnP setup */40 41module_param_array(index, int, NULL, 0444);42MODULE_PARM_DESC(index, "Index value for Avance Logic based soundcard.");43module_param_array(id, charp, NULL, 0444);44MODULE_PARM_DESC(id, "ID string for Avance Logic based soundcard.");45module_param_array(enable, bool, NULL, 0444);46MODULE_PARM_DESC(enable, "Enable Avance Logic based soundcard.");47 48MODULE_ALIAS("snd-dt019x");49 50struct snd_card_als100 {51	struct pnp_dev *dev;52	struct pnp_dev *devmpu;53	struct pnp_dev *devopl;54	struct snd_sb *chip;55};56 57static const struct pnp_card_device_id snd_als100_pnpids[] = {58	/* DT197A30 */59	{ .id = "RWB1688",60	  .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } },61	  .driver_data = SB_HW_DT019X },62	/* DT0196 / ALS-007 */63	{ .id = "ALS0007",64	  .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } },65	  .driver_data = SB_HW_DT019X },66	/* ALS100 - PRO16PNP */67	{ .id = "ALS0001",68	  .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } },69	  .driver_data = SB_HW_ALS100 },70	/* ALS110 - MF1000 - Digimate 3D Sound */71	{ .id = "ALS0110",72	  .devs = { { "@@@1001" }, { "@X@1001" }, { "@H@1001" } },73	  .driver_data = SB_HW_ALS100 },74	/* ALS120 */75	{ .id = "ALS0120",76	  .devs = { { "@@@2001" }, { "@X@2001" }, { "@H@2001" } },77	  .driver_data = SB_HW_ALS100 },78	/* ALS200 */79	{ .id = "ALS0200",80	  .devs = { { "@@@0020" }, { "@X@0020" }, { "@H@0001" } },81	  .driver_data = SB_HW_ALS100 },82	/* ALS200 OEM */83	{ .id = "ALS0200",84	  .devs = { { "@@@0020" }, { "@X@0020" }, { "@H@0020" } },85	  .driver_data = SB_HW_ALS100 },86	/* RTL3000 */87	{ .id = "RTL3000",88	  .devs = { { "@@@2001" }, { "@X@2001" }, { "@H@2001" } },89	  .driver_data = SB_HW_ALS100 },90	{ .id = "" } /* end */91};92 93MODULE_DEVICE_TABLE(pnp_card, snd_als100_pnpids);94 95static int snd_card_als100_pnp(int dev, struct snd_card_als100 *acard,96			       struct pnp_card_link *card,97			       const struct pnp_card_device_id *id)98{99	struct pnp_dev *pdev;100	int err;101 102	acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL);103	if (acard->dev == NULL)104		return -ENODEV;105 106	acard->devmpu = pnp_request_card_device(card, id->devs[1].id, acard->dev);107	acard->devopl = pnp_request_card_device(card, id->devs[2].id, acard->dev);108 109	pdev = acard->dev;110 111	err = pnp_activate_dev(pdev);112	if (err < 0) {113		dev_err(&pdev->dev, "AUDIO pnp configure failure\n");114		return err;115	}116	port[dev] = pnp_port_start(pdev, 0);117	if (id->driver_data == SB_HW_DT019X)118		dma8[dev] = pnp_dma(pdev, 0);119	else {120		dma8[dev] = pnp_dma(pdev, 1);121		dma16[dev] = pnp_dma(pdev, 0);122	}123	irq[dev] = pnp_irq(pdev, 0);124 125	pdev = acard->devmpu;126	if (pdev != NULL) {127		err = pnp_activate_dev(pdev);128		if (err < 0)129			goto __mpu_error;130		mpu_port[dev] = pnp_port_start(pdev, 0);131		mpu_irq[dev] = pnp_irq(pdev, 0);132	} else {133	     __mpu_error:134	     	if (pdev) {135		     	pnp_release_card_device(pdev);136			dev_err(&pdev->dev, "MPU401 pnp configure failure, skipping\n");137	     	}138	     	acard->devmpu = NULL;139	     	mpu_port[dev] = -1;140	}141 142	pdev = acard->devopl;143	if (pdev != NULL) {144		err = pnp_activate_dev(pdev);145		if (err < 0)146			goto __fm_error;147		fm_port[dev] = pnp_port_start(pdev, 0);148	} else {149	      __fm_error:150	     	if (pdev) {151		     	pnp_release_card_device(pdev);152			dev_err(&pdev->dev, "OPL3 pnp configure failure, skipping\n");153	     	}154	     	acard->devopl = NULL;155	     	fm_port[dev] = -1;156	}157 158	return 0;159}160 161static int snd_card_als100_probe(int dev,162				 struct pnp_card_link *pcard,163				 const struct pnp_card_device_id *pid)164{165	int error;166	struct snd_sb *chip;167	struct snd_card *card;168	struct snd_card_als100 *acard;169	struct snd_opl3 *opl3;170 171	error = snd_devm_card_new(&pcard->card->dev,172				  index[dev], id[dev], THIS_MODULE,173				  sizeof(struct snd_card_als100), &card);174	if (error < 0)175		return error;176	acard = card->private_data;177 178	error = snd_card_als100_pnp(dev, acard, pcard, pid);179	if (error)180		return error;181 182	if (pid->driver_data == SB_HW_DT019X)183		dma16[dev] = -1;184 185	error = snd_sbdsp_create(card, port[dev], irq[dev],186				  snd_sb16dsp_interrupt,187				  dma8[dev], dma16[dev],188				  pid->driver_data,189				  &chip);190	if (error < 0)191		return error;192	acard->chip = chip;193 194	if (pid->driver_data == SB_HW_DT019X) {195		strcpy(card->driver, "DT-019X");196		strcpy(card->shortname, "Diamond Tech. DT-019X");197		snprintf(card->longname, sizeof(card->longname),198			 "Diamond Tech. DT-019X, %s at 0x%lx, irq %d, dma %d",199			 chip->name, chip->port, irq[dev], dma8[dev]);200	} else {201		strcpy(card->driver, "ALS100");202		strcpy(card->shortname, "Avance Logic ALS100");203		snprintf(card->longname, sizeof(card->longname),204			 "Avance Logic ALS100, %s at 0x%lx, irq %d, dma %d&%d",205			 chip->name, chip->port, irq[dev], dma8[dev],206			 dma16[dev]);207	}208 209	error = snd_sb16dsp_pcm(chip, 0);210	if (error < 0)211		return error;212 213	error = snd_sbmixer_new(chip);214	if (error < 0)215		return error;216 217	if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) {218		int mpu_type = MPU401_HW_ALS100;219 220		if (mpu_irq[dev] == SNDRV_AUTO_IRQ)221			mpu_irq[dev] = -1;222 223		if (pid->driver_data == SB_HW_DT019X)224			mpu_type = MPU401_HW_MPU401;225 226		if (snd_mpu401_uart_new(card, 0,227					mpu_type,228					mpu_port[dev], 0, 229					mpu_irq[dev],230					NULL) < 0)231			dev_err(card->dev, "no MPU-401 device at 0x%lx\n", mpu_port[dev]);232	}233 234	if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) {235		if (snd_opl3_create(card,236				    fm_port[dev], fm_port[dev] + 2,237				    OPL3_HW_AUTO, 0, &opl3) < 0) {238			dev_err(card->dev, "no OPL device at 0x%lx-0x%lx\n",239				fm_port[dev], fm_port[dev] + 2);240		} else {241			error = snd_opl3_timer_new(opl3, 0, 1);242			if (error < 0)243				return error;244			error = snd_opl3_hwdep_new(opl3, 0, 1, NULL);245			if (error < 0)246				return error;247		}248	}249 250	error = snd_card_register(card);251	if (error < 0)252		return error;253	pnp_set_card_drvdata(pcard, card);254	return 0;255}256 257static unsigned int als100_devices;258 259static int snd_als100_pnp_detect(struct pnp_card_link *card,260				 const struct pnp_card_device_id *id)261{262	static int dev;263	int res;264 265	for ( ; dev < SNDRV_CARDS; dev++) {266		if (!enable[dev])267			continue;268		res = snd_card_als100_probe(dev, card, id);269		if (res < 0)270			return res;271		dev++;272		als100_devices++;273		return 0;274	}275	return -ENODEV;276}277 278#ifdef CONFIG_PM279static int snd_als100_pnp_suspend(struct pnp_card_link *pcard, pm_message_t state)280{281	struct snd_card *card = pnp_get_card_drvdata(pcard);282	struct snd_card_als100 *acard = card->private_data;283	struct snd_sb *chip = acard->chip;284 285	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);286	snd_sbmixer_suspend(chip);287	return 0;288}289 290static int snd_als100_pnp_resume(struct pnp_card_link *pcard)291{292	struct snd_card *card = pnp_get_card_drvdata(pcard);293	struct snd_card_als100 *acard = card->private_data;294	struct snd_sb *chip = acard->chip;295 296	snd_sbdsp_reset(chip);297	snd_sbmixer_resume(chip);298	snd_power_change_state(card, SNDRV_CTL_POWER_D0);299	return 0;300}301#endif302 303static struct pnp_card_driver als100_pnpc_driver = {304	.flags          = PNP_DRIVER_RES_DISABLE,305	.name		= "als100",306        .id_table       = snd_als100_pnpids,307        .probe          = snd_als100_pnp_detect,308#ifdef CONFIG_PM309	.suspend	= snd_als100_pnp_suspend,310	.resume		= snd_als100_pnp_resume,311#endif312};313 314static int __init alsa_card_als100_init(void)315{316	int err;317 318	err = pnp_register_card_driver(&als100_pnpc_driver);319	if (err)320		return err;321 322	if (!als100_devices) {323		pnp_unregister_card_driver(&als100_pnpc_driver);324#ifdef MODULE325		pr_err("no Avance Logic based soundcards found\n");326#endif327		return -ENODEV;328	}329	return 0;330}331 332static void __exit alsa_card_als100_exit(void)333{334	pnp_unregister_card_driver(&als100_pnpc_driver);335}336 337module_init(alsa_card_als100_init)338module_exit(alsa_card_als100_exit)339