brintos

brintos / linux-shallow public Read only

0
0
Text · 28.9 KiB · 6354033 Raw
1171 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*********************************************************************3 *4 * Linux multisound pinnacle/fiji driver for ALSA.5 *6 * 2002/06/30 Karsten Wiese:7 *	for now this is only used to build a pinnacle / fiji driver.8 *	the OSS parent of this code is designed to also support9 *	the multisound classic via the file msnd_classic.c.10 *	to make it easier for some brave heart to implemt classic11 *	support in alsa, i left all the MSND_CLASSIC tokens in this file.12 *	but for now this untested & undone.13 *14 * ripped from linux kernel 2.4.18 by Karsten Wiese.15 *16 * the following is a copy of the 2.4.18 OSS FREE file-heading comment:17 *18 * Turtle Beach MultiSound Sound Card Driver for Linux19 * msnd_pinnacle.c / msnd_classic.c20 *21 * -- If MSND_CLASSIC is defined:22 *23 *     -> driver for Turtle Beach Classic/Monterey/Tahiti24 *25 * -- Else26 *27 *     -> driver for Turtle Beach Pinnacle/Fiji28 *29 * 12-3-2000  Modified IO port validation  Steve Sycamore30 *31 * Copyright (C) 1998 Andrew Veliath32 *33 ********************************************************************/34 35#include <linux/kernel.h>36#include <linux/module.h>37#include <linux/interrupt.h>38#include <linux/types.h>39#include <linux/delay.h>40#include <linux/ioport.h>41#include <linux/firmware.h>42#include <linux/isa.h>43#include <linux/isapnp.h>44#include <linux/irq.h>45#include <linux/io.h>46 47#include <sound/core.h>48#include <sound/initval.h>49#include <sound/asound.h>50#include <sound/pcm.h>51#include <sound/mpu401.h>52 53#ifdef MSND_CLASSIC54# ifndef __alpha__55#  define SLOWIO56# endif57#endif58#include "msnd.h"59#ifdef MSND_CLASSIC60#  include "msnd_classic.h"61#  define LOGNAME			"msnd_classic"62#  define DEV_NAME			"msnd-classic"63#else64#  include "msnd_pinnacle.h"65#  define LOGNAME			"snd_msnd_pinnacle"66#  define DEV_NAME			"msnd-pinnacle"67#endif68 69static void set_default_audio_parameters(struct snd_msnd *chip)70{71	chip->play_sample_size = snd_pcm_format_width(DEFSAMPLESIZE);72	chip->play_sample_rate = DEFSAMPLERATE;73	chip->play_channels = DEFCHANNELS;74	chip->capture_sample_size = snd_pcm_format_width(DEFSAMPLESIZE);75	chip->capture_sample_rate = DEFSAMPLERATE;76	chip->capture_channels = DEFCHANNELS;77}78 79static void snd_msnd_eval_dsp_msg(struct snd_msnd *chip, u16 wMessage)80{81	switch (HIBYTE(wMessage)) {82	case HIMT_PLAY_DONE: {83		if (chip->banksPlayed < 3)84			dev_dbg(chip->card->dev, "%08X: HIMT_PLAY_DONE: %i\n",85				(unsigned)jiffies, LOBYTE(wMessage));86 87		if (chip->last_playbank == LOBYTE(wMessage)) {88			dev_dbg(chip->card->dev,89				"chip.last_playbank == LOBYTE(wMessage)\n");90			break;91		}92		chip->banksPlayed++;93 94		if (test_bit(F_WRITING, &chip->flags))95			snd_msnd_DAPQ(chip, 0);96 97		chip->last_playbank = LOBYTE(wMessage);98		chip->playDMAPos += chip->play_period_bytes;99		if (chip->playDMAPos > chip->playLimit)100			chip->playDMAPos = 0;101		snd_pcm_period_elapsed(chip->playback_substream);102 103		break;104	}105	case HIMT_RECORD_DONE:106		if (chip->last_recbank == LOBYTE(wMessage))107			break;108		chip->last_recbank = LOBYTE(wMessage);109		chip->captureDMAPos += chip->capturePeriodBytes;110		if (chip->captureDMAPos > (chip->captureLimit))111			chip->captureDMAPos = 0;112 113		if (test_bit(F_READING, &chip->flags))114			snd_msnd_DARQ(chip, chip->last_recbank);115 116		snd_pcm_period_elapsed(chip->capture_substream);117		break;118 119	case HIMT_DSP:120		switch (LOBYTE(wMessage)) {121#ifndef MSND_CLASSIC122		case HIDSP_PLAY_UNDER:123#endif124		case HIDSP_INT_PLAY_UNDER:125			dev_dbg(chip->card->dev,126				LOGNAME ": Play underflow %i\n",127				chip->banksPlayed);128			if (chip->banksPlayed > 2)129				clear_bit(F_WRITING, &chip->flags);130			break;131 132		case HIDSP_INT_RECORD_OVER:133			dev_dbg(chip->card->dev, LOGNAME ": Record overflow\n");134			clear_bit(F_READING, &chip->flags);135			break;136 137		default:138			dev_dbg(chip->card->dev, LOGNAME139				": DSP message %d 0x%02x\n",140				LOBYTE(wMessage), LOBYTE(wMessage));141			break;142		}143		break;144 145	case HIMT_MIDI_IN_UCHAR:146		if (chip->msndmidi_mpu)147			snd_msndmidi_input_read(chip->msndmidi_mpu);148		break;149 150	default:151		dev_dbg(chip->card->dev, LOGNAME ": HIMT message %d 0x%02x\n",152			HIBYTE(wMessage), HIBYTE(wMessage));153		break;154	}155}156 157static irqreturn_t snd_msnd_interrupt(int irq, void *dev_id)158{159	struct snd_msnd *chip = dev_id;160	void __iomem *pwDSPQData = chip->mappedbase + DSPQ_DATA_BUFF;161	u16 head, tail, size;162 163	/* Send ack to DSP */164	/* inb(chip->io + HP_RXL); */165 166	/* Evaluate queued DSP messages */167	head = readw(chip->DSPQ + JQS_wHead);168	tail = readw(chip->DSPQ + JQS_wTail);169	size = readw(chip->DSPQ + JQS_wSize);170	if (head > size || tail > size)171		goto out;172	while (head != tail) {173		snd_msnd_eval_dsp_msg(chip, readw(pwDSPQData + 2 * head));174		if (++head > size)175			head = 0;176		writew(head, chip->DSPQ + JQS_wHead);177	}178 out:179	/* Send ack to DSP */180	inb(chip->io + HP_RXL);181	return IRQ_HANDLED;182}183 184 185static int snd_msnd_reset_dsp(struct snd_msnd *chip, unsigned char *info)186{187	long io = chip->io;188	int timeout = 100;189 190	outb(HPDSPRESET_ON, io + HP_DSPR);191	msleep(1);192#ifndef MSND_CLASSIC193	if (info)194		*info = inb(io + HP_INFO);195#endif196	outb(HPDSPRESET_OFF, io + HP_DSPR);197	msleep(1);198	while (timeout-- > 0) {199		if (inb(io + HP_CVR) == HP_CVR_DEF)200			return 0;201		msleep(1);202	}203	dev_err(chip->card->dev, LOGNAME ": Cannot reset DSP\n");204 205	return -EIO;206}207 208static int snd_msnd_probe(struct snd_card *card)209{210	struct snd_msnd *chip = card->private_data;211	unsigned char info;212#ifndef MSND_CLASSIC213	char *xv, *rev = NULL;214	char *pin = "TB Pinnacle", *fiji = "TB Fiji";215	char *pinfiji = "TB Pinnacle/Fiji";216#endif217 218	if (!request_region(chip->io, DSP_NUMIO, "probing")) {219		dev_err(card->dev, LOGNAME ": I/O port conflict\n");220		return -ENODEV;221	}222 223	if (snd_msnd_reset_dsp(chip, &info) < 0) {224		release_region(chip->io, DSP_NUMIO);225		return -ENODEV;226	}227 228#ifdef MSND_CLASSIC229	strcpy(card->shortname, "Classic/Tahiti/Monterey");230	strcpy(card->longname, "Turtle Beach Multisound");231	dev_info(card->dev, LOGNAME ": %s, "232	       "I/O 0x%lx-0x%lx, IRQ %d, memory mapped to 0x%lX-0x%lX\n",233	       card->shortname,234	       chip->io, chip->io + DSP_NUMIO - 1,235	       chip->irq,236	       chip->base, chip->base + 0x7fff);237#else238	switch (info >> 4) {239	case 0xf:240		xv = "<= 1.15";241		break;242	case 0x1:243		xv = "1.18/1.2";244		break;245	case 0x2:246		xv = "1.3";247		break;248	case 0x3:249		xv = "1.4";250		break;251	default:252		xv = "unknown";253		break;254	}255 256	switch (info & 0x7) {257	case 0x0:258		rev = "I";259		strcpy(card->shortname, pin);260		break;261	case 0x1:262		rev = "F";263		strcpy(card->shortname, pin);264		break;265	case 0x2:266		rev = "G";267		strcpy(card->shortname, pin);268		break;269	case 0x3:270		rev = "H";271		strcpy(card->shortname, pin);272		break;273	case 0x4:274		rev = "E";275		strcpy(card->shortname, fiji);276		break;277	case 0x5:278		rev = "C";279		strcpy(card->shortname, fiji);280		break;281	case 0x6:282		rev = "D";283		strcpy(card->shortname, fiji);284		break;285	case 0x7:286		rev = "A-B (Fiji) or A-E (Pinnacle)";287		strcpy(card->shortname, pinfiji);288		break;289	}290	strcpy(card->longname, "Turtle Beach Multisound Pinnacle");291	dev_info(card->dev, LOGNAME ": %s revision %s, Xilinx version %s, "292	       "I/O 0x%lx-0x%lx, IRQ %d, memory mapped to 0x%lX-0x%lX\n",293	       card->shortname,294	       rev, xv,295	       chip->io, chip->io + DSP_NUMIO - 1,296	       chip->irq,297	       chip->base, chip->base + 0x7fff);298#endif299 300	release_region(chip->io, DSP_NUMIO);301	return 0;302}303 304static int snd_msnd_init_sma(struct snd_msnd *chip)305{306	static int initted;307	u16 mastVolLeft, mastVolRight;308	unsigned long flags;309 310#ifdef MSND_CLASSIC311	outb(chip->memid, chip->io + HP_MEMM);312#endif313	outb(HPBLKSEL_0, chip->io + HP_BLKS);314	/* Motorola 56k shared memory base */315	chip->SMA = chip->mappedbase + SMA_STRUCT_START;316 317	if (initted) {318		mastVolLeft = readw(chip->SMA + SMA_wCurrMastVolLeft);319		mastVolRight = readw(chip->SMA + SMA_wCurrMastVolRight);320	} else321		mastVolLeft = mastVolRight = 0;322	memset_io(chip->mappedbase, 0, 0x8000);323 324	/* Critical section: bank 1 access */325	spin_lock_irqsave(&chip->lock, flags);326	outb(HPBLKSEL_1, chip->io + HP_BLKS);327	memset_io(chip->mappedbase, 0, 0x8000);328	outb(HPBLKSEL_0, chip->io + HP_BLKS);329	spin_unlock_irqrestore(&chip->lock, flags);330 331	/* Digital audio play queue */332	chip->DAPQ = chip->mappedbase + DAPQ_OFFSET;333	snd_msnd_init_queue(chip->DAPQ, DAPQ_DATA_BUFF, DAPQ_BUFF_SIZE);334 335	/* Digital audio record queue */336	chip->DARQ = chip->mappedbase + DARQ_OFFSET;337	snd_msnd_init_queue(chip->DARQ, DARQ_DATA_BUFF, DARQ_BUFF_SIZE);338 339	/* MIDI out queue */340	chip->MODQ = chip->mappedbase + MODQ_OFFSET;341	snd_msnd_init_queue(chip->MODQ, MODQ_DATA_BUFF, MODQ_BUFF_SIZE);342 343	/* MIDI in queue */344	chip->MIDQ = chip->mappedbase + MIDQ_OFFSET;345	snd_msnd_init_queue(chip->MIDQ, MIDQ_DATA_BUFF, MIDQ_BUFF_SIZE);346 347	/* DSP -> host message queue */348	chip->DSPQ = chip->mappedbase + DSPQ_OFFSET;349	snd_msnd_init_queue(chip->DSPQ, DSPQ_DATA_BUFF, DSPQ_BUFF_SIZE);350 351	/* Setup some DSP values */352#ifndef MSND_CLASSIC353	writew(1, chip->SMA + SMA_wCurrPlayFormat);354	writew(chip->play_sample_size, chip->SMA + SMA_wCurrPlaySampleSize);355	writew(chip->play_channels, chip->SMA + SMA_wCurrPlayChannels);356	writew(chip->play_sample_rate, chip->SMA + SMA_wCurrPlaySampleRate);357#endif358	writew(chip->play_sample_rate, chip->SMA + SMA_wCalFreqAtoD);359	writew(mastVolLeft, chip->SMA + SMA_wCurrMastVolLeft);360	writew(mastVolRight, chip->SMA + SMA_wCurrMastVolRight);361#ifndef MSND_CLASSIC362	writel(0x00010000, chip->SMA + SMA_dwCurrPlayPitch);363	writel(0x00000001, chip->SMA + SMA_dwCurrPlayRate);364#endif365	writew(0x303, chip->SMA + SMA_wCurrInputTagBits);366 367	initted = 1;368 369	return 0;370}371 372 373static int upload_dsp_code(struct snd_card *card)374{375	struct snd_msnd *chip = card->private_data;376	const struct firmware *init_fw = NULL, *perm_fw = NULL;377	int err;378 379	outb(HPBLKSEL_0, chip->io + HP_BLKS);380 381	err = request_firmware(&init_fw, INITCODEFILE, card->dev);382	if (err < 0) {383		dev_err(card->dev, LOGNAME ": Error loading " INITCODEFILE);384		goto cleanup1;385	}386	err = request_firmware(&perm_fw, PERMCODEFILE, card->dev);387	if (err < 0) {388		dev_err(card->dev, LOGNAME ": Error loading " PERMCODEFILE);389		goto cleanup;390	}391 392	memcpy_toio(chip->mappedbase, perm_fw->data, perm_fw->size);393	if (snd_msnd_upload_host(chip, init_fw->data, init_fw->size) < 0) {394		dev_warn(card->dev, LOGNAME ": Error uploading to DSP\n");395		err = -ENODEV;396		goto cleanup;397	}398	dev_info(card->dev, LOGNAME ": DSP firmware uploaded\n");399	err = 0;400 401cleanup:402	release_firmware(perm_fw);403cleanup1:404	release_firmware(init_fw);405	return err;406}407 408#ifdef MSND_CLASSIC409static void reset_proteus(struct snd_msnd *chip)410{411	outb(HPPRORESET_ON, chip->io + HP_PROR);412	msleep(TIME_PRO_RESET);413	outb(HPPRORESET_OFF, chip->io + HP_PROR);414	msleep(TIME_PRO_RESET_DONE);415}416#endif417 418static int snd_msnd_initialize(struct snd_card *card)419{420	struct snd_msnd *chip = card->private_data;421	int err, timeout;422 423#ifdef MSND_CLASSIC424	outb(HPWAITSTATE_0, chip->io + HP_WAIT);425	outb(HPBITMODE_16, chip->io + HP_BITM);426 427	reset_proteus(chip);428#endif429	err = snd_msnd_init_sma(chip);430	if (err < 0) {431		dev_warn(card->dev, LOGNAME ": Cannot initialize SMA\n");432		return err;433	}434 435	err = snd_msnd_reset_dsp(chip, NULL);436	if (err < 0)437		return err;438 439	err = upload_dsp_code(card);440	if (err < 0) {441		dev_warn(card->dev, LOGNAME ": Cannot upload DSP code\n");442		return err;443	}444 445	timeout = 200;446 447	while (readw(chip->mappedbase)) {448		msleep(1);449		if (!timeout--) {450			dev_err(card->dev, LOGNAME ": DSP reset timeout\n");451			return -EIO;452		}453	}454 455	snd_msndmix_setup(chip);456	return 0;457}458 459static int snd_msnd_dsp_full_reset(struct snd_card *card)460{461	struct snd_msnd *chip = card->private_data;462	int rv;463 464	if (test_bit(F_RESETTING, &chip->flags) || ++chip->nresets > 10)465		return 0;466 467	set_bit(F_RESETTING, &chip->flags);468	snd_msnd_dsp_halt(chip, NULL);	/* Unconditionally halt */469 470	rv = snd_msnd_initialize(card);471	if (rv)472		dev_warn(card->dev, LOGNAME ": DSP reset failed\n");473	snd_msndmix_force_recsrc(chip, 0);474	clear_bit(F_RESETTING, &chip->flags);475	return rv;476}477 478 479static int snd_msnd_send_dsp_cmd_chk(struct snd_msnd *chip, u8 cmd)480{481	if (snd_msnd_send_dsp_cmd(chip, cmd) == 0)482		return 0;483	snd_msnd_dsp_full_reset(chip->card);484	return snd_msnd_send_dsp_cmd(chip, cmd);485}486 487static int snd_msnd_calibrate_adc(struct snd_msnd *chip, u16 srate)488{489	dev_dbg(chip->card->dev, "snd_msnd_calibrate_adc(%i)\n", srate);490	writew(srate, chip->SMA + SMA_wCalFreqAtoD);491	if (chip->calibrate_signal == 0)492		writew(readw(chip->SMA + SMA_wCurrHostStatusFlags)493		       | 0x0001, chip->SMA + SMA_wCurrHostStatusFlags);494	else495		writew(readw(chip->SMA + SMA_wCurrHostStatusFlags)496		       & ~0x0001, chip->SMA + SMA_wCurrHostStatusFlags);497	if (snd_msnd_send_word(chip, 0, 0, HDEXAR_CAL_A_TO_D) == 0 &&498	    snd_msnd_send_dsp_cmd_chk(chip, HDEX_AUX_REQ) == 0) {499		schedule_timeout_interruptible(msecs_to_jiffies(333));500		return 0;501	}502	dev_warn(chip->card->dev, LOGNAME ": ADC calibration failed\n");503	return -EIO;504}505 506/*507 * ALSA callback function, called when attempting to open the MIDI device.508 */509static int snd_msnd_mpu401_open(struct snd_mpu401 *mpu)510{511	snd_msnd_enable_irq(mpu->private_data);512	snd_msnd_send_dsp_cmd(mpu->private_data, HDEX_MIDI_IN_START);513	return 0;514}515 516static void snd_msnd_mpu401_close(struct snd_mpu401 *mpu)517{518	snd_msnd_send_dsp_cmd(mpu->private_data, HDEX_MIDI_IN_STOP);519	snd_msnd_disable_irq(mpu->private_data);520}521 522static long mpu_io[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;523static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;524 525static int snd_msnd_attach(struct snd_card *card)526{527	struct snd_msnd *chip = card->private_data;528	int err;529 530	err = devm_request_irq(card->dev, chip->irq, snd_msnd_interrupt, 0,531			       card->shortname, chip);532	if (err < 0) {533		dev_err(card->dev, LOGNAME ": Couldn't grab IRQ %d\n", chip->irq);534		return err;535	}536	card->sync_irq = chip->irq;537	if (!devm_request_region(card->dev, chip->io, DSP_NUMIO,538				 card->shortname))539		return -EBUSY;540 541	if (!devm_request_mem_region(card->dev, chip->base, BUFFSIZE,542				     card->shortname)) {543		dev_err(card->dev, LOGNAME544			": unable to grab memory region 0x%lx-0x%lx\n",545			chip->base, chip->base + BUFFSIZE - 1);546		return -EBUSY;547	}548	chip->mappedbase = devm_ioremap(card->dev, chip->base, 0x8000);549	if (!chip->mappedbase) {550		dev_err(card->dev, LOGNAME551			": unable to map memory region 0x%lx-0x%lx\n",552			chip->base, chip->base + BUFFSIZE - 1);553		return -EIO;554	}555 556	err = snd_msnd_dsp_full_reset(card);557	if (err < 0)558		return err;559 560	err = snd_msnd_pcm(card, 0);561	if (err < 0) {562		dev_err(card->dev, LOGNAME ": error creating new PCM device\n");563		return err;564	}565 566	err = snd_msndmix_new(card);567	if (err < 0) {568		dev_err(card->dev, LOGNAME ": error creating new Mixer device\n");569		return err;570	}571 572 573	if (mpu_io[0] != SNDRV_AUTO_PORT) {574		struct snd_mpu401 *mpu;575 576		err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,577					  mpu_io[0],578					  MPU401_MODE_INPUT |579					  MPU401_MODE_OUTPUT,580					  mpu_irq[0],581					  &chip->rmidi);582		if (err < 0) {583			dev_err(card->dev, LOGNAME584				": error creating new Midi device\n");585			return err;586		}587		mpu = chip->rmidi->private_data;588 589		mpu->open_input = snd_msnd_mpu401_open;590		mpu->close_input = snd_msnd_mpu401_close;591		mpu->private_data = chip;592	}593 594	disable_irq(chip->irq);595	snd_msnd_calibrate_adc(chip, chip->play_sample_rate);596	snd_msndmix_force_recsrc(chip, 0);597 598	err = snd_card_register(card);599	if (err < 0)600		return err;601 602	return 0;603}604 605 606#ifndef MSND_CLASSIC607 608/* Pinnacle/Fiji Logical Device Configuration */609 610static int snd_msnd_write_cfg(struct snd_msnd *chip, int cfg, int reg, int value)611{612	outb(reg, cfg);613	outb(value, cfg + 1);614	if (value != inb(cfg + 1)) {615		dev_err(chip->card->dev, LOGNAME ": %s: I/O error\n", __func__);616		return -EIO;617	}618	return 0;619}620 621static int snd_msnd_write_cfg_io0(struct snd_msnd *chip, int cfg, int num, u16 io)622{623	if (snd_msnd_write_cfg(chip, cfg, IREG_LOGDEVICE, num))624		return -EIO;625	if (snd_msnd_write_cfg(chip, cfg, IREG_IO0_BASEHI, HIBYTE(io)))626		return -EIO;627	if (snd_msnd_write_cfg(chip, cfg, IREG_IO0_BASELO, LOBYTE(io)))628		return -EIO;629	return 0;630}631 632static int snd_msnd_write_cfg_io1(struct snd_msnd *chip, int cfg, int num, u16 io)633{634	if (snd_msnd_write_cfg(chip, cfg, IREG_LOGDEVICE, num))635		return -EIO;636	if (snd_msnd_write_cfg(chip, cfg, IREG_IO1_BASEHI, HIBYTE(io)))637		return -EIO;638	if (snd_msnd_write_cfg(chip, cfg, IREG_IO1_BASELO, LOBYTE(io)))639		return -EIO;640	return 0;641}642 643static int snd_msnd_write_cfg_irq(struct snd_msnd *chip, int cfg, int num, u16 irq)644{645	if (snd_msnd_write_cfg(chip, cfg, IREG_LOGDEVICE, num))646		return -EIO;647	if (snd_msnd_write_cfg(chip, cfg, IREG_IRQ_NUMBER, LOBYTE(irq)))648		return -EIO;649	if (snd_msnd_write_cfg(chip, cfg, IREG_IRQ_TYPE, IRQTYPE_EDGE))650		return -EIO;651	return 0;652}653 654static int snd_msnd_write_cfg_mem(struct snd_msnd *chip, int cfg, int num, int mem)655{656	u16 wmem;657 658	mem >>= 8;659	wmem = (u16)(mem & 0xfff);660	if (snd_msnd_write_cfg(chip, cfg, IREG_LOGDEVICE, num))661		return -EIO;662	if (snd_msnd_write_cfg(chip, cfg, IREG_MEMBASEHI, HIBYTE(wmem)))663		return -EIO;664	if (snd_msnd_write_cfg(chip, cfg, IREG_MEMBASELO, LOBYTE(wmem)))665		return -EIO;666	if (wmem && snd_msnd_write_cfg(chip, cfg, IREG_MEMCONTROL,667				       MEMTYPE_HIADDR | MEMTYPE_16BIT))668		return -EIO;669	return 0;670}671 672static int snd_msnd_activate_logical(struct snd_msnd *chip, int cfg, int num)673{674	if (snd_msnd_write_cfg(chip, cfg, IREG_LOGDEVICE, num))675		return -EIO;676	if (snd_msnd_write_cfg(chip, cfg, IREG_ACTIVATE, LD_ACTIVATE))677		return -EIO;678	return 0;679}680 681static int snd_msnd_write_cfg_logical(struct snd_msnd *chip,682				      int cfg, int num, u16 io0,683				      u16 io1, u16 irq, int mem)684{685	if (snd_msnd_write_cfg(chip, cfg, IREG_LOGDEVICE, num))686		return -EIO;687	if (snd_msnd_write_cfg_io0(chip, cfg, num, io0))688		return -EIO;689	if (snd_msnd_write_cfg_io1(chip, cfg, num, io1))690		return -EIO;691	if (snd_msnd_write_cfg_irq(chip, cfg, num, irq))692		return -EIO;693	if (snd_msnd_write_cfg_mem(chip, cfg, num, mem))694		return -EIO;695	if (snd_msnd_activate_logical(chip, cfg, num))696		return -EIO;697	return 0;698}699 700static int snd_msnd_pinnacle_cfg_reset(struct snd_msnd *chip, int cfg)701{702	int i;703 704	/* Reset devices if told to */705	dev_info(chip->card->dev, LOGNAME ": Resetting all devices\n");706	for (i = 0; i < 4; ++i)707		if (snd_msnd_write_cfg_logical(chip, cfg, i, 0, 0, 0, 0))708			return -EIO;709 710	return 0;711}712#endif713 714static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */715static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */716 717module_param_array(index, int, NULL, 0444);718MODULE_PARM_DESC(index, "Index value for msnd_pinnacle soundcard.");719module_param_array(id, charp, NULL, 0444);720MODULE_PARM_DESC(id, "ID string for msnd_pinnacle soundcard.");721 722static long io[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;723static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;724static long mem[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;725 726#ifndef MSND_CLASSIC727static long cfg[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;728 729/* Extra Peripheral Configuration (Default: Disable) */730static long ide_io0[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;731static long ide_io1[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;732static int ide_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;733 734static long joystick_io[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;735/* If we have the digital daugherboard... */736static int digital[SNDRV_CARDS];737 738/* Extra Peripheral Configuration */739static int reset[SNDRV_CARDS];740#endif741 742static int write_ndelay[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = 1 };743 744static int calibrate_signal;745 746#ifdef CONFIG_PNP747static bool isapnp[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;748module_param_array(isapnp, bool, NULL, 0444);749MODULE_PARM_DESC(isapnp, "ISA PnP detection for specified soundcard.");750#define has_isapnp(x) isapnp[x]751#else752#define has_isapnp(x) 0753#endif754 755MODULE_AUTHOR("Karsten Wiese <annabellesgarden@yahoo.de>");756MODULE_DESCRIPTION("Turtle Beach " LONGNAME " Linux Driver");757MODULE_LICENSE("GPL");758MODULE_FIRMWARE(INITCODEFILE);759MODULE_FIRMWARE(PERMCODEFILE);760 761module_param_hw_array(io, long, ioport, NULL, 0444);762MODULE_PARM_DESC(io, "IO port #");763module_param_hw_array(irq, int, irq, NULL, 0444);764module_param_hw_array(mem, long, iomem, NULL, 0444);765module_param_array(write_ndelay, int, NULL, 0444);766module_param(calibrate_signal, int, 0444);767#ifndef MSND_CLASSIC768module_param_array(digital, int, NULL, 0444);769module_param_hw_array(cfg, long, ioport, NULL, 0444);770module_param_array(reset, int, NULL, 0444);771module_param_hw_array(mpu_io, long, ioport, NULL, 0444);772module_param_hw_array(mpu_irq, int, irq, NULL, 0444);773module_param_hw_array(ide_io0, long, ioport, NULL, 0444);774module_param_hw_array(ide_io1, long, ioport, NULL, 0444);775module_param_hw_array(ide_irq, int, irq, NULL, 0444);776module_param_hw_array(joystick_io, long, ioport, NULL, 0444);777#endif778 779 780static int snd_msnd_isa_match(struct device *pdev, unsigned int i)781{782	if (io[i] == SNDRV_AUTO_PORT)783		return 0;784 785	if (irq[i] == SNDRV_AUTO_PORT || mem[i] == SNDRV_AUTO_PORT) {786		dev_warn(pdev, LOGNAME ": io, irq and mem must be set\n");787		return 0;788	}789 790#ifdef MSND_CLASSIC791	if (!(io[i] == 0x290 ||792	      io[i] == 0x260 ||793	      io[i] == 0x250 ||794	      io[i] == 0x240 ||795	      io[i] == 0x230 ||796	      io[i] == 0x220 ||797	      io[i] == 0x210 ||798	      io[i] == 0x3e0)) {799		dev_err(pdev, LOGNAME ": \"io\" - DSP I/O base must be set "800			" to 0x210, 0x220, 0x230, 0x240, 0x250, 0x260, 0x290, "801			"or 0x3E0\n");802		return 0;803	}804#else805	if (io[i] < 0x100 || io[i] > 0x3e0 || (io[i] % 0x10) != 0) {806		dev_err(pdev, LOGNAME807			": \"io\" - DSP I/O base must within the range 0x100 "808			"to 0x3E0 and must be evenly divisible by 0x10\n");809		return 0;810	}811#endif /* MSND_CLASSIC */812 813	if (!(irq[i] == 5 ||814	      irq[i] == 7 ||815	      irq[i] == 9 ||816	      irq[i] == 10 ||817	      irq[i] == 11 ||818	      irq[i] == 12)) {819		dev_err(pdev, LOGNAME820			": \"irq\" - must be set to 5, 7, 9, 10, 11 or 12\n");821		return 0;822	}823 824	if (!(mem[i] == 0xb0000 ||825	      mem[i] == 0xc8000 ||826	      mem[i] == 0xd0000 ||827	      mem[i] == 0xd8000 ||828	      mem[i] == 0xe0000 ||829	      mem[i] == 0xe8000)) {830		dev_err(pdev, LOGNAME ": \"mem\" - must be set to "831		       "0xb0000, 0xc8000, 0xd0000, 0xd8000, 0xe0000 or "832		       "0xe8000\n");833		return 0;834	}835 836#ifndef MSND_CLASSIC837	if (cfg[i] == SNDRV_AUTO_PORT) {838		dev_info(pdev, LOGNAME ": Assuming PnP mode\n");839	} else if (cfg[i] != 0x250 && cfg[i] != 0x260 && cfg[i] != 0x270) {840		dev_info(pdev, LOGNAME841			": Config port must be 0x250, 0x260 or 0x270 "842			"(or unspecified for PnP mode)\n");843		return 0;844	}845#endif /* MSND_CLASSIC */846 847	return 1;848}849 850static int snd_msnd_isa_probe(struct device *pdev, unsigned int idx)851{852	int err;853	struct snd_card *card;854	struct snd_msnd *chip;855 856	if (has_isapnp(idx)857#ifndef MSND_CLASSIC858	    || cfg[idx] == SNDRV_AUTO_PORT859#endif860	    ) {861		dev_info(pdev, LOGNAME ": Assuming PnP mode\n");862		return -ENODEV;863	}864 865	err = snd_devm_card_new(pdev, index[idx], id[idx], THIS_MODULE,866				sizeof(struct snd_msnd), &card);867	if (err < 0)868		return err;869 870	chip = card->private_data;871	chip->card = card;872 873#ifdef MSND_CLASSIC874	switch (irq[idx]) {875	case 5:876		chip->irqid = HPIRQ_5; break;877	case 7:878		chip->irqid = HPIRQ_7; break;879	case 9:880		chip->irqid = HPIRQ_9; break;881	case 10:882		chip->irqid = HPIRQ_10; break;883	case 11:884		chip->irqid = HPIRQ_11; break;885	case 12:886		chip->irqid = HPIRQ_12; break;887	}888 889	switch (mem[idx]) {890	case 0xb0000:891		chip->memid = HPMEM_B000; break;892	case 0xc8000:893		chip->memid = HPMEM_C800; break;894	case 0xd0000:895		chip->memid = HPMEM_D000; break;896	case 0xd8000:897		chip->memid = HPMEM_D800; break;898	case 0xe0000:899		chip->memid = HPMEM_E000; break;900	case 0xe8000:901		chip->memid = HPMEM_E800; break;902	}903#else904	dev_info(pdev, LOGNAME ": Non-PnP mode: configuring at port 0x%lx\n",905		 cfg[idx]);906 907	if (!devm_request_region(card->dev, cfg[idx], 2,908				 "Pinnacle/Fiji Config")) {909		dev_err(pdev, LOGNAME ": Config port 0x%lx conflict\n",910			cfg[idx]);911		return -EIO;912	}913	if (reset[idx])914		if (snd_msnd_pinnacle_cfg_reset(chip, cfg[idx]))915			return -EIO;916 917	/* DSP */918	err = snd_msnd_write_cfg_logical(chip, cfg[idx], 0,919					 io[idx], 0,920					 irq[idx], mem[idx]);921 922	if (err)923		return err;924 925	/* The following are Pinnacle specific */926 927	/* MPU */928	if (mpu_io[idx] != SNDRV_AUTO_PORT929	    && mpu_irq[idx] != SNDRV_AUTO_IRQ) {930		dev_info(pdev, LOGNAME931		       ": Configuring MPU to I/O 0x%lx IRQ %d\n",932		       mpu_io[idx], mpu_irq[idx]);933		err = snd_msnd_write_cfg_logical(chip, cfg[idx], 1,934						 mpu_io[idx], 0,935						 mpu_irq[idx], 0);936 937		if (err)938			return err;939	}940 941	/* IDE */942	if (ide_io0[idx] != SNDRV_AUTO_PORT943	    && ide_io1[idx] != SNDRV_AUTO_PORT944	    && ide_irq[idx] != SNDRV_AUTO_IRQ) {945		dev_info(pdev, LOGNAME946		       ": Configuring IDE to I/O 0x%lx, 0x%lx IRQ %d\n",947		       ide_io0[idx], ide_io1[idx], ide_irq[idx]);948		err = snd_msnd_write_cfg_logical(chip, cfg[idx], 2,949						 ide_io0[idx], ide_io1[idx],950						 ide_irq[idx], 0);951 952		if (err)953			return err;954	}955 956	/* Joystick */957	if (joystick_io[idx] != SNDRV_AUTO_PORT) {958		dev_info(pdev, LOGNAME959		       ": Configuring joystick to I/O 0x%lx\n",960		       joystick_io[idx]);961		err = snd_msnd_write_cfg_logical(chip, cfg[idx], 3,962						 joystick_io[idx], 0,963						 0, 0);964 965		if (err)966			return err;967	}968 969#endif /* MSND_CLASSIC */970 971	set_default_audio_parameters(chip);972#ifdef MSND_CLASSIC973	chip->type = msndClassic;974#else975	chip->type = msndPinnacle;976#endif977	chip->io = io[idx];978	chip->irq = irq[idx];979	chip->base = mem[idx];980 981	chip->calibrate_signal = calibrate_signal ? 1 : 0;982	chip->recsrc = 0;983	chip->dspq_data_buff = DSPQ_DATA_BUFF;984	chip->dspq_buff_size = DSPQ_BUFF_SIZE;985	if (write_ndelay[idx])986		clear_bit(F_DISABLE_WRITE_NDELAY, &chip->flags);987	else988		set_bit(F_DISABLE_WRITE_NDELAY, &chip->flags);989#ifndef MSND_CLASSIC990	if (digital[idx])991		set_bit(F_HAVEDIGITAL, &chip->flags);992#endif993	spin_lock_init(&chip->lock);994	err = snd_msnd_probe(card);995	if (err < 0) {996		dev_err(pdev, LOGNAME ": Probe failed\n");997		return err;998	}999 1000	err = snd_msnd_attach(card);1001	if (err < 0) {1002		dev_err(pdev, LOGNAME ": Attach failed\n");1003		return err;1004	}1005	dev_set_drvdata(pdev, card);1006 1007	return 0;1008}1009 1010static struct isa_driver snd_msnd_driver = {1011	.match		= snd_msnd_isa_match,1012	.probe		= snd_msnd_isa_probe,1013	/* FIXME: suspend, resume */1014	.driver		= {1015		.name	= DEV_NAME1016	},1017};1018 1019#ifdef CONFIG_PNP1020static int snd_msnd_pnp_detect(struct pnp_card_link *pcard,1021			       const struct pnp_card_device_id *pid)1022{1023	static int idx;1024	struct pnp_dev *pnp_dev;1025	struct pnp_dev *mpu_dev;1026	struct snd_card *card;1027	struct snd_msnd *chip;1028	int ret;1029 1030	for ( ; idx < SNDRV_CARDS; idx++) {1031		if (has_isapnp(idx))1032			break;1033	}1034	if (idx >= SNDRV_CARDS)1035		return -ENODEV;1036 1037	/*1038	 * Check that we still have room for another sound card ...1039	 */1040	pnp_dev = pnp_request_card_device(pcard, pid->devs[0].id, NULL);1041	if (!pnp_dev)1042		return -ENODEV;1043 1044	mpu_dev = pnp_request_card_device(pcard, pid->devs[1].id, NULL);1045	if (!mpu_dev)1046		return -ENODEV;1047 1048	if (!pnp_is_active(pnp_dev) && pnp_activate_dev(pnp_dev) < 0) {1049		dev_info(&pcard->card->dev, "msnd_pinnacle: device is inactive\n");1050		return -EBUSY;1051	}1052 1053	if (!pnp_is_active(mpu_dev) && pnp_activate_dev(mpu_dev) < 0) {1054		dev_info(&pcard->card->dev, "msnd_pinnacle: MPU device is inactive\n");1055		return -EBUSY;1056	}1057 1058	/*1059	 * Create a new ALSA sound card entry, in anticipation1060	 * of detecting our hardware ...1061	 */1062	ret = snd_devm_card_new(&pcard->card->dev,1063				index[idx], id[idx], THIS_MODULE,1064				sizeof(struct snd_msnd), &card);1065	if (ret < 0)1066		return ret;1067 1068	chip = card->private_data;1069	chip->card = card;1070 1071	/*1072	 * Read the correct parameters off the ISA PnP bus ...1073	 */1074	io[idx] = pnp_port_start(pnp_dev, 0);1075	irq[idx] = pnp_irq(pnp_dev, 0);1076	mem[idx] = pnp_mem_start(pnp_dev, 0);1077	mpu_io[idx] = pnp_port_start(mpu_dev, 0);1078	mpu_irq[idx] = pnp_irq(mpu_dev, 0);1079 1080	set_default_audio_parameters(chip);1081#ifdef MSND_CLASSIC1082	chip->type = msndClassic;1083#else1084	chip->type = msndPinnacle;1085#endif1086	chip->io = io[idx];1087	chip->irq = irq[idx];1088	chip->base = mem[idx];1089 1090	chip->calibrate_signal = calibrate_signal ? 1 : 0;1091	chip->recsrc = 0;1092	chip->dspq_data_buff = DSPQ_DATA_BUFF;1093	chip->dspq_buff_size = DSPQ_BUFF_SIZE;1094	if (write_ndelay[idx])1095		clear_bit(F_DISABLE_WRITE_NDELAY, &chip->flags);1096	else1097		set_bit(F_DISABLE_WRITE_NDELAY, &chip->flags);1098#ifndef MSND_CLASSIC1099	if (digital[idx])1100		set_bit(F_HAVEDIGITAL, &chip->flags);1101#endif1102	spin_lock_init(&chip->lock);1103	ret = snd_msnd_probe(card);1104	if (ret < 0) {1105		dev_err(&pcard->card->dev, LOGNAME ": Probe failed\n");1106		return ret;1107	}1108 1109	ret = snd_msnd_attach(card);1110	if (ret < 0) {1111		dev_err(&pcard->card->dev, LOGNAME ": Attach failed\n");1112		return ret;1113	}1114 1115	pnp_set_card_drvdata(pcard, card);1116	++idx;1117	return 0;1118}1119 1120static int isa_registered;1121static int pnp_registered;1122 1123static const struct pnp_card_device_id msnd_pnpids[] = {1124	/* Pinnacle PnP */1125	{ .id = "BVJ0440", .devs = { { "TBS0000" }, { "TBS0001" } } },1126	{ .id = "" }	/* end */1127};1128 1129MODULE_DEVICE_TABLE(pnp_card, msnd_pnpids);1130 1131static struct pnp_card_driver msnd_pnpc_driver = {1132	.flags = PNP_DRIVER_RES_DO_NOT_CHANGE,1133	.name = "msnd_pinnacle",1134	.id_table = msnd_pnpids,1135	.probe = snd_msnd_pnp_detect,1136};1137#endif /* CONFIG_PNP */1138 1139static int __init snd_msnd_init(void)1140{1141	int err;1142 1143	err = isa_register_driver(&snd_msnd_driver, SNDRV_CARDS);1144#ifdef CONFIG_PNP1145	if (!err)1146		isa_registered = 1;1147 1148	err = pnp_register_card_driver(&msnd_pnpc_driver);1149	if (!err)1150		pnp_registered = 1;1151 1152	if (isa_registered)1153		err = 0;1154#endif1155	return err;1156}1157 1158static void __exit snd_msnd_exit(void)1159{1160#ifdef CONFIG_PNP1161	if (pnp_registered)1162		pnp_unregister_card_driver(&msnd_pnpc_driver);1163	if (isa_registered)1164#endif1165		isa_unregister_driver(&snd_msnd_driver);1166}1167 1168module_init(snd_msnd_init);1169module_exit(snd_msnd_exit);1170 1171