/*
 * parse the audio format type I descriptor
 * and returns the corresponding pcm format
 *
 * @dev: usb device
 * @fp: audioformat record
 * @format: the format tag (wFormatTag)
 * @fmt: the format type descriptor
 */
static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,
				     struct audioformat *fp,
				     unsigned int format, void *_fmt,
				     int protocol)
{
	int sample_width, sample_bytes;
	u64 pcm_formats = 0;

	switch (protocol) {
	case UAC_VERSION_1:
	default: {
		struct uac_format_type_i_discrete_descriptor *fmt = _fmt;
		sample_width = fmt->bBitResolution;
		sample_bytes = fmt->bSubframeSize;
		format = 1 << format;
		break;
	}

	case UAC_VERSION_2: {
		struct uac_format_type_i_ext_descriptor *fmt = _fmt;
		sample_width = fmt->bBitResolution;
		sample_bytes = fmt->bSubslotSize;

		if (format & UAC2_FORMAT_TYPE_I_RAW_DATA)
			pcm_formats |= SNDRV_PCM_FMTBIT_SPECIAL;

		format <<= 1;
		break;
	}
	}

	if ((pcm_formats == 0) &&
	    (format == 0 || format == (1 << UAC_FORMAT_TYPE_I_UNDEFINED))) {
		/* some devices don't define this correctly... */
		snd_printdd(KERN_INFO "%d:%u:%d : format type 0 is detected, processed as PCM\n",
			    chip->dev->devnum, fp->iface, fp->altsetting);
		format = 1 << UAC_FORMAT_TYPE_I_PCM;
	}
	if (format & (1 << UAC_FORMAT_TYPE_I_PCM)) {
		if (chip->usb_id == USB_ID(0x0582, 0x0016) /* Edirol SD-90 */ &&
		    sample_width == 24 && sample_bytes == 2)
			sample_bytes = 3;
		else if (sample_width > sample_bytes * 8) {
			snd_printk(KERN_INFO "%d:%u:%d : sample bitwidth %d in over sample bytes %d\n",
				   chip->dev->devnum, fp->iface, fp->altsetting,
				   sample_width, sample_bytes);
		}
		/* check the format byte size */
		switch (sample_bytes) {
		case 1:
			pcm_formats |= SNDRV_PCM_FMTBIT_S8;
			break;
		case 2:
			if (snd_usb_is_big_endian_format(chip, fp))
				pcm_formats |= SNDRV_PCM_FMTBIT_S16_BE; /* grrr, big endian!! */
			else
				pcm_formats |= SNDRV_PCM_FMTBIT_S16_LE;
			break;
		case 3:
			if (snd_usb_is_big_endian_format(chip, fp))
				pcm_formats |= SNDRV_PCM_FMTBIT_S24_3BE; /* grrr, big endian!! */
			else
				pcm_formats |= SNDRV_PCM_FMTBIT_S24_3LE;
			break;
		case 4:
			pcm_formats |= SNDRV_PCM_FMTBIT_S32_LE;
			break;
		default:
			snd_printk(KERN_INFO "%d:%u:%d : unsupported sample bitwidth %d in %d bytes\n",
				   chip->dev->devnum, fp->iface, fp->altsetting,
				   sample_width, sample_bytes);
			break;
		}
	}
	if (format & (1 << UAC_FORMAT_TYPE_I_PCM8)) {
		/* Dallas DS4201 workaround: it advertises U8 format, but really
		   supports S8. */
		if (chip->usb_id == USB_ID(0x04fa, 0x4201))
			pcm_formats |= SNDRV_PCM_FMTBIT_S8;
		else
			pcm_formats |= SNDRV_PCM_FMTBIT_U8;
	}
	if (format & (1 << UAC_FORMAT_TYPE_I_IEEE_FLOAT)) {
		pcm_formats |= SNDRV_PCM_FMTBIT_FLOAT_LE;
	}
	if (format & (1 << UAC_FORMAT_TYPE_I_ALAW)) {
		pcm_formats |= SNDRV_PCM_FMTBIT_A_LAW;
	}
	if (format & (1 << UAC_FORMAT_TYPE_I_MULAW)) {
		pcm_formats |= SNDRV_PCM_FMTBIT_MU_LAW;
	}
	if (format & ~0x3f) {
		snd_printk(KERN_INFO "%d:%u:%d : unsupported format bits %#x\n",
			   chip->dev->devnum, fp->iface, fp->altsetting, format);
	}

	pcm_formats |= snd_usb_interface_dsd_format_quirks(chip, fp, sample_bytes);

	return pcm_formats;
}
Example #2
0
static int __devinit snd_card_ymfpci_probe(struct pci_dev *pci,
					   const struct pci_device_id *pci_id)
{
	static int dev;
	struct snd_card *card;
	struct resource *fm_res = NULL;
	struct resource *mpu_res = NULL;
	struct snd_ymfpci *chip;
	struct snd_opl3 *opl3;
	const char *str, *model;
	int err;
	u16 legacy_ctrl, legacy_ctrl2, old_legacy_ctrl;

	if (dev >= SNDRV_CARDS)
		return -ENODEV;
	if (!enable[dev]) {
		dev++;
		return -ENOENT;
	}

	err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
	if (err < 0)
		return err;

	switch (pci_id->device) {
	case 0x0004: str = "YMF724";  model = "DS-1"; break;
	case 0x000d: str = "YMF724F"; model = "DS-1"; break;
	case 0x000a: str = "YMF740";  model = "DS-1L"; break;
	case 0x000c: str = "YMF740C"; model = "DS-1L"; break;
	case 0x0010: str = "YMF744";  model = "DS-1S"; break;
	case 0x0012: str = "YMF754";  model = "DS-1E"; break;
	default: model = str = "???"; break;
	}

	legacy_ctrl = 0;
	legacy_ctrl2 = 0x0800;	/* SBEN = 0, SMOD = 01, LAD = 0 */

	if (pci_id->device >= 0x0010) { /* YMF 744/754 */
		if (fm_port[dev] == 1) {
			/* auto-detect */
			fm_port[dev] = pci_resource_start(pci, 1);
		}
		if (fm_port[dev] > 0 &&
		    (fm_res = request_region(fm_port[dev], 4, "YMFPCI OPL3")) != NULL) {
			legacy_ctrl |= YMFPCI_LEGACY_FMEN;
			pci_write_config_word(pci, PCIR_DSXG_FMBASE, fm_port[dev]);
		}
		if (mpu_port[dev] == 1) {
			/* auto-detect */
			mpu_port[dev] = pci_resource_start(pci, 1) + 0x20;
		}
		if (mpu_port[dev] > 0 &&
		    (mpu_res = request_region(mpu_port[dev], 2, "YMFPCI MPU401")) != NULL) {
			legacy_ctrl |= YMFPCI_LEGACY_MEN;
			pci_write_config_word(pci, PCIR_DSXG_MPU401BASE, mpu_port[dev]);
		}
	} else {
		switch (fm_port[dev]) {
		case 0x388: legacy_ctrl2 |= 0; break;
		case 0x398: legacy_ctrl2 |= 1; break;
		case 0x3a0: legacy_ctrl2 |= 2; break;
		case 0x3a8: legacy_ctrl2 |= 3; break;
		default: fm_port[dev] = 0; break;
		}
		if (fm_port[dev] > 0 &&
		    (fm_res = request_region(fm_port[dev], 4, "YMFPCI OPL3")) != NULL) {
			legacy_ctrl |= YMFPCI_LEGACY_FMEN;
		} else {
			legacy_ctrl2 &= ~YMFPCI_LEGACY2_FMIO;
			fm_port[dev] = 0;
		}
		switch (mpu_port[dev]) {
		case 0x330: legacy_ctrl2 |= 0 << 4; break;
		case 0x300: legacy_ctrl2 |= 1 << 4; break;
		case 0x332: legacy_ctrl2 |= 2 << 4; break;
		case 0x334: legacy_ctrl2 |= 3 << 4; break;
		default: mpu_port[dev] = 0; break;
		}
		if (mpu_port[dev] > 0 &&
		    (mpu_res = request_region(mpu_port[dev], 2, "YMFPCI MPU401")) != NULL) {
			legacy_ctrl |= YMFPCI_LEGACY_MEN;
		} else {
			legacy_ctrl2 &= ~YMFPCI_LEGACY2_MPUIO;
			mpu_port[dev] = 0;
		}
	}
	if (mpu_res) {
		legacy_ctrl |= YMFPCI_LEGACY_MIEN;
		legacy_ctrl2 |= YMFPCI_LEGACY2_IMOD;
	}
	pci_read_config_word(pci, PCIR_DSXG_LEGACY, &old_legacy_ctrl);
	pci_write_config_word(pci, PCIR_DSXG_LEGACY, legacy_ctrl);
	pci_write_config_word(pci, PCIR_DSXG_ELEGACY, legacy_ctrl2);
	if ((err = snd_ymfpci_create(card, pci,
				     old_legacy_ctrl,
			 	     &chip)) < 0) {
		snd_card_free(card);
		release_and_free_resource(mpu_res);
		release_and_free_resource(fm_res);
		return err;
	}
	chip->fm_res = fm_res;
	chip->mpu_res = mpu_res;
	card->private_data = chip;

	strcpy(card->driver, str);
	sprintf(card->shortname, "Yamaha %s (%s)", model, str);
	sprintf(card->longname, "%s at 0x%lx, irq %i",
		card->shortname,
		chip->reg_area_phys,
		chip->irq);
	if ((err = snd_ymfpci_pcm(chip, 0, NULL)) < 0) {
		snd_card_free(card);
		return err;
	}
	if ((err = snd_ymfpci_pcm_spdif(chip, 1, NULL)) < 0) {
		snd_card_free(card);
		return err;
	}
	if ((err = snd_ymfpci_pcm_4ch(chip, 2, NULL)) < 0) {
		snd_card_free(card);
		return err;
	}
	if ((err = snd_ymfpci_pcm2(chip, 3, NULL)) < 0) {
		snd_card_free(card);
		return err;
	}
	if ((err = snd_ymfpci_mixer(chip, rear_switch[dev])) < 0) {
		snd_card_free(card);
		return err;
	}
	if ((err = snd_ymfpci_timer(chip, 0)) < 0) {
		snd_card_free(card);
		return err;
	}
	if (chip->mpu_res) {
		if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_YMFPCI,
					       mpu_port[dev],
					       MPU401_INFO_INTEGRATED,
					       pci->irq, 0, &chip->rawmidi)) < 0) {
			printk(KERN_WARNING "ymfpci: cannot initialize MPU401 at 0x%lx, skipping...\n", mpu_port[dev]);
			legacy_ctrl &= ~YMFPCI_LEGACY_MIEN; /* disable MPU401 irq */
			pci_write_config_word(pci, PCIR_DSXG_LEGACY, legacy_ctrl);
		}
	}
	if (chip->fm_res) {
		if ((err = snd_opl3_create(card,
					   fm_port[dev],
					   fm_port[dev] + 2,
					   OPL3_HW_OPL3, 1, &opl3)) < 0) {
			printk(KERN_WARNING "ymfpci: cannot initialize FM OPL3 at 0x%lx, skipping...\n", fm_port[dev]);
			legacy_ctrl &= ~YMFPCI_LEGACY_FMEN;
			pci_write_config_word(pci, PCIR_DSXG_LEGACY, legacy_ctrl);
		} else if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) {
			snd_card_free(card);
			snd_printk(KERN_ERR "cannot create opl3 hwdep\n");
			return err;
		}
	}

	snd_ymfpci_create_gameport(chip, dev, legacy_ctrl, legacy_ctrl2);

	if ((err = snd_card_register(card)) < 0) {
		snd_card_free(card);
		return err;
	}
	pci_set_drvdata(pci, card);
	dev++;
	return 0;
}
Example #3
0
static int usb6fire_chip_probe(struct usb_interface *intf,
			       const struct usb_device_id *usb_id)
{
	int ret;
	int i;
	struct sfire_chip *chip = NULL;
	struct usb_device *device = interface_to_usbdev(intf);
	int regidx = -1; /* index in module parameter array */
	struct snd_card *card = NULL;

	/* look if we already serve this card and return if so */
	mutex_lock(&register_mutex);
	for (i = 0; i < SNDRV_CARDS; i++) {
		if (devices[i] == device) {
			if (chips[i])
				chips[i]->intf_count++;
			usb_set_intfdata(intf, chips[i]);
			mutex_unlock(&register_mutex);
			return 0;
		} else if (regidx < 0)
			regidx = i;
	}
	if (regidx < 0) {
		mutex_unlock(&register_mutex);
		snd_printk(KERN_ERR PREFIX "too many cards registered.\n");
		return -ENODEV;
	}
	devices[regidx] = device;
	mutex_unlock(&register_mutex);

	/* check, if firmware is present on device, upload it if not */
	ret = usb6fire_fw_init(intf);
	if (ret < 0)
		return ret;
	else if (ret == FW_NOT_READY) /* firmware update performed */
		return 0;

	/* if we are here, card can be registered in alsa. */
	if (usb_set_interface(device, 0, 0) != 0) {
		snd_printk(KERN_ERR PREFIX "can't set first interface.\n");
		return -EIO;
	}
	ret = snd_card_create(index[regidx], id[regidx], THIS_MODULE,
			sizeof(struct sfire_chip), &card);
	if (ret < 0) {
		snd_printk(KERN_ERR PREFIX "cannot create alsa card.\n");
		return ret;
	}
	strcpy(card->driver, "6FireUSB");
	strcpy(card->shortname, "TerraTec DMX6FireUSB");
	sprintf(card->longname, "%s at %d:%d", card->shortname,
			device->bus->busnum, device->devnum);
	snd_card_set_dev(card, &intf->dev);

	chip = card->private_data;
	chips[regidx] = chip;
	chip->dev = device;
	chip->regidx = regidx;
	chip->intf_count = 1;
	chip->card = card;

	ret = usb6fire_comm_init(chip);
	if (ret < 0) {
		usb6fire_chip_destroy(chip);
		return ret;
	}

	ret = usb6fire_midi_init(chip);
	if (ret < 0) {
		usb6fire_chip_destroy(chip);
		return ret;
	}

	ret = usb6fire_pcm_init(chip);
	if (ret < 0) {
		usb6fire_chip_destroy(chip);
		return ret;
	}

	ret = usb6fire_control_init(chip);
	if (ret < 0) {
		usb6fire_chip_destroy(chip);
		return ret;
	}

	ret = snd_card_register(card);
	if (ret < 0) {
		snd_printk(KERN_ERR PREFIX "cannot register card.");
		usb6fire_chip_destroy(chip);
		return ret;
	}
	usb_set_intfdata(intf, chip);
	return 0;
}
Example #4
0
static int __init snd_sgalaxy_probe(int dev)
{
	static int possible_irqs[] = {7, 9, 10, 11, -1};
	static int possible_dmas[] = {1, 3, 0, -1};
	int err, xirq, xdma1;
	snd_card_t *card;
	ad1848_t *chip;

	if (sbport[dev] == SNDRV_AUTO_PORT) {
		snd_printk("specify SB port\n");
		return -EINVAL;
	}
	if (wssport[dev] == SNDRV_AUTO_PORT) {
		snd_printk("specify WSS port\n");
		return -EINVAL;
	}
	card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
	if (card == NULL)
		return -ENOMEM;

	xirq = irq[dev];
	if (xirq == SNDRV_AUTO_IRQ) {
		if ((xirq = snd_legacy_find_free_irq(possible_irqs)) < 0) {
			snd_card_free(card);
			snd_printk("unable to find a free IRQ\n");
			return -EBUSY;
		}
	}
	xdma1 = dma1[dev];
        if (xdma1 == SNDRV_AUTO_DMA) {
		if ((xdma1 = snd_legacy_find_free_dma(possible_dmas)) < 0) {
			snd_card_free(card);
			snd_printk("unable to find a free DMA\n");
			return -EBUSY;
		}
	}

	if ((err = snd_sgalaxy_detect(dev, xirq, xdma1)) < 0) {
		snd_card_free(card);
		return err;
	}

	if ((err = snd_ad1848_create(card, wssport[dev] + 4,
				     xirq, xdma1,
				     AD1848_HW_DETECT, &chip)) < 0) {
		snd_card_free(card);
		return err;
	}

	if ((err = snd_ad1848_pcm(chip, 0, NULL)) < 0) {
		snd_printdd("sgalaxy - error creating new ad1848 PCM device\n");
		snd_card_free(card);
		return err;
	}
	if ((err = snd_ad1848_mixer(chip)) < 0) {
		snd_printdd("sgalaxy - error creating new ad1848 mixer\n");
		snd_card_free(card);
		return err;
	}
	if (snd_sgalaxy_mixer(chip) < 0) {
		snd_printdd("sgalaxy - the mixer rewrite failed\n");
		snd_card_free(card);
		return err;
	}

	strcpy(card->driver, "Sound Galaxy");
	strcpy(card->shortname, "Sound Galaxy");
	sprintf(card->longname, "Sound Galaxy at 0x%lx, irq %d, dma %d",
		wssport[dev], xirq, xdma1);

	if ((err = snd_card_register(card)) < 0) {
		snd_card_free(card);
		return err;
	}
	snd_sgalaxy_cards[dev] = card;
	return 0;
}
Example #5
0
/**
 * snd_soc_new_compress - create a new compress.
 *
 * @rtd: The runtime for which we will create compress
 * @num: the device index number (zero based - shared with normal PCMs)
 *
 * Return: 0 for success, else error.
 */
int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
{
	struct snd_soc_codec *codec = rtd->codec;
	struct snd_soc_platform *platform = rtd->platform;
	struct snd_soc_dai *codec_dai = rtd->codec_dai;
	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
	struct snd_compr *compr;
	struct snd_pcm *be_pcm;
	char new_name[64];
	int ret = 0, direction = 0;

	if (rtd->num_codecs > 1) {
		dev_err(rtd->card->dev, "Multicodec not supported for compressed stream\n");
		return -EINVAL;
	}

	/* check client and interface hw capabilities */
	snprintf(new_name, sizeof(new_name), "%s %s-%d",
			rtd->dai_link->stream_name, codec_dai->name, num);

	if (codec_dai->driver->playback.channels_min)
		direction = SND_COMPRESS_PLAYBACK;
	else if (codec_dai->driver->capture.channels_min)
		direction = SND_COMPRESS_CAPTURE;
	else
		return -EINVAL;

	compr = kzalloc(sizeof(*compr), GFP_KERNEL);
	if (compr == NULL) {
		snd_printk(KERN_ERR "Cannot allocate compr\n");
		return -ENOMEM;
	}

	compr->ops = devm_kzalloc(rtd->card->dev, sizeof(soc_compr_ops),
				  GFP_KERNEL);
	if (compr->ops == NULL) {
		dev_err(rtd->card->dev, "Cannot allocate compressed ops\n");
		ret = -ENOMEM;
		goto compr_err;
	}

	if (rtd->dai_link->dynamic) {
		snprintf(new_name, sizeof(new_name), "(%s)",
			rtd->dai_link->stream_name);

		ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
				rtd->dai_link->dpcm_playback,
				rtd->dai_link->dpcm_capture, &be_pcm);
		if (ret < 0) {
			dev_err(rtd->card->dev, "ASoC: can't create compressed for %s\n",
				rtd->dai_link->name);
			goto compr_err;
		}

		rtd->pcm = be_pcm;
		rtd->fe_compr = 1;
		if (rtd->dai_link->dpcm_playback)
			be_pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd;
		else if (rtd->dai_link->dpcm_capture)
			be_pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd;
		memcpy(compr->ops, &soc_compr_dyn_ops, sizeof(soc_compr_dyn_ops));
	} else
		memcpy(compr->ops, &soc_compr_ops, sizeof(soc_compr_ops));

	/* Add copy callback for not memory mapped DSPs */
	if (platform->driver->compr_ops && platform->driver->compr_ops->copy)
		compr->ops->copy = soc_compr_copy;

	mutex_init(&compr->lock);
	ret = snd_compress_new(rtd->card->snd_card, num, direction, compr);
	if (ret < 0) {
		pr_err("compress asoc: can't create compress for codec %s\n",
			codec->component.name);
		goto compr_err;
	}

	/* DAPM dai link stream work */
	INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);

	rtd->compr = compr;
	compr->private_data = rtd;

	printk(KERN_INFO "compress asoc: %s <-> %s mapping ok\n", codec_dai->name,
		cpu_dai->name);
	return ret;

compr_err:
	kfree(compr);
	return ret;
}
Example #6
0
/*
 * Upload a byte-stream into the SoundScape using DMA channel A.
 */
static int upload_dma_data(struct soundscape *s,
                           const unsigned char __user *data,
                           size_t size)
{
	unsigned long flags;
	struct snd_dma_buffer dma;
	int ret;

	if (!get_dmabuf(&dma, PAGE_ALIGN(size)))
		return -ENOMEM;

	spin_lock_irqsave(&s->lock, flags);

	/*
	 * Reset the board ...
	 */
	sscape_write_unsafe(s->io_base, GA_HMCTL_REG, sscape_read_unsafe(s->io_base, GA_HMCTL_REG) & 0x3f);

	/*
	 * Enable the DMA channels and configure them ...
	 */
	sscape_write_unsafe(s->io_base, GA_DMACFG_REG, 0x50);
	sscape_write_unsafe(s->io_base, GA_DMAA_REG, (s->chip->dma1 << 4) | DMA_8BIT);
	sscape_write_unsafe(s->io_base, GA_DMAB_REG, 0x20);

	/*
	 * Take the board out of reset ...
	 */
	sscape_write_unsafe(s->io_base, GA_HMCTL_REG, sscape_read_unsafe(s->io_base, GA_HMCTL_REG) | 0x80);

	/*
	 * Upload the user's data (firmware?) to the SoundScape
	 * board through the DMA channel ...
	 */
	while (size != 0) {
		unsigned long len;

		/*
		 * Apparently, copying to/from userspace can sleep.
		 * We are therefore forbidden from holding any
		 * spinlocks while we copy ...
		 */
		spin_unlock_irqrestore(&s->lock, flags);

		/*
		 * Remember that the data that we want to DMA
		 * comes from USERSPACE. We have already verified
		 * the userspace pointer ...
		 */
		len = min(size, dma.bytes);
		len -= __copy_from_user(dma.area, data, len);
		data += len;
		size -= len;

		/*
		 * Grab that spinlock again, now that we've
		 * finished copying!
		 */
		spin_lock_irqsave(&s->lock, flags);

		snd_dma_program(s->chip->dma1, dma.addr, len, DMA_MODE_WRITE);
		sscape_start_dma_unsafe(s->io_base, GA_DMAA_REG);
		if (!sscape_wait_dma_unsafe(s->io_base, GA_DMAA_REG, 5000)) {
			/*
			 * Don't forget to release this spinlock we're holding ...
			 */
			spin_unlock_irqrestore(&s->lock, flags);

			snd_printk(KERN_ERR "sscape: DMA upload has timed out\n");
			ret = -EAGAIN;
			goto _release_dma;
		}
	} /* while */

	set_host_mode_unsafe(s->io_base);

	/*
	 * Boot the board ... (I think)
	 */
	sscape_write_unsafe(s->io_base, GA_HMCTL_REG, sscape_read_unsafe(s->io_base, GA_HMCTL_REG) | 0x40);
	spin_unlock_irqrestore(&s->lock, flags);

	/*
	 * If all has gone well, then the board should acknowledge
	 * the new upload and tell us that it has rebooted OK. We
	 * give it 5 seconds (max) ...
	 */
	ret = 0;
	if (!obp_startup_ack(s, 5)) {
		snd_printk(KERN_ERR "sscape: No response from on-board processor after upload\n");
		ret = -EAGAIN;
	} else if (!host_startup_ack(s, 5)) {
		snd_printk(KERN_ERR "sscape: SoundScape failed to initialise\n");
		ret = -EAGAIN;
	}

_release_dma:
	/*
	 * NOTE!!! We are NOT holding any spinlocks at this point !!!
	 */
	sscape_write(s, GA_DMAA_REG, (s->ic_type == IC_ODIE ? 0x70 : 0x40));
	free_dmabuf(&dma);

	return ret;
}
Example #7
0
static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev)
{
	static int possible_irqs[] = { 5, 7, 9, 10, 11, -1 };
	static int possible_dmas[] = { 1, 3, 0, -1 };
	int err;
	int xirq = irq[dev];
	int xdma = dma[dev];
	struct snd_card *card;
	struct snd_wss *chip;
	struct snd_opl3 *opl3;
	char __iomem *vport;
	char __iomem *vmss_port;


	card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
	if (!card)
		return -ENOMEM;

	if (xirq == SNDRV_AUTO_IRQ) {
		xirq = snd_legacy_find_free_irq(possible_irqs);
		if (xirq < 0) {
			snd_printk(KERN_ERR PFX "unable to find a free IRQ\n");
			err = -EBUSY;
			goto err_exit;
		}
	}

	if (xdma == SNDRV_AUTO_DMA) {
		xdma = snd_legacy_find_free_dma(possible_dmas);
		if (xdma < 0) {
			snd_printk(KERN_ERR PFX "unable to find a free DMA\n");
			err = -EBUSY;
			goto err_exit;
		}
	}

	if (!request_region(port[dev], 0x10, DRV_NAME)) {
		snd_printk(KERN_ERR PFX
			   "I/O port region is already in use.\n");
		err = -EBUSY;
		goto err_exit;
	}
	vport = devm_ioport_map(devptr, port[dev], 0x10);
	if (!vport) {
		snd_printk(KERN_ERR PFX
			   "I/O port cannot be iomaped.\n");
		err = -EBUSY;
		goto err_unmap1;
	}

	/* to make it marked as used */
	if (!request_region(mss_port[dev], 4, DRV_NAME)) {
		snd_printk(KERN_ERR PFX
			   "SC-6000 port I/O port region is already in use.\n");
		err = -EBUSY;
		goto err_unmap1;
	}
	vmss_port = devm_ioport_map(devptr, mss_port[dev], 4);
	if (!vport) {
		snd_printk(KERN_ERR PFX
			   "MSS port I/O cannot be iomaped.\n");
		err = -EBUSY;
		goto err_unmap2;
	}

	snd_printd("Initializing BASE[0x%lx] IRQ[%d] DMA[%d] MIRQ[%d]\n",
		   port[dev], xirq, xdma,
		   mpu_irq[dev] == SNDRV_AUTO_IRQ ? 0 : mpu_irq[dev]);

	err = sc6000_init_board(vport, xirq, xdma, vmss_port, mpu_irq[dev]);
	if (err < 0)
		goto err_unmap2;

	err = snd_wss_create(card, mss_port[dev] + 4,  -1, xirq, xdma, -1,
			     WSS_HW_DETECT, 0, &chip);
	if (err < 0)
		goto err_unmap2;
	card->private_data = chip;

	err = snd_wss_pcm(chip, 0, NULL);
	if (err < 0) {
		snd_printk(KERN_ERR PFX
			   "error creating new WSS PCM device\n");
		goto err_unmap2;
	}
	err = snd_wss_mixer(chip);
	if (err < 0) {
		snd_printk(KERN_ERR PFX "error creating new WSS mixer\n");
		goto err_unmap2;
	}
	err = snd_sc6000_mixer(chip);
	if (err < 0) {
		snd_printk(KERN_ERR PFX "the mixer rewrite failed\n");
		goto err_unmap2;
	}
	if (snd_opl3_create(card,
			    0x388, 0x388 + 2,
			    OPL3_HW_AUTO, 0, &opl3) < 0) {
		snd_printk(KERN_ERR PFX "no OPL device at 0x%x-0x%x ?\n",
			   0x388, 0x388 + 2);
	} else {
		err = snd_opl3_timer_new(opl3, 0, 1);
		if (err < 0)
			goto err_unmap2;

		err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
		if (err < 0)
			goto err_unmap2;
	}

	if (mpu_port[dev] != SNDRV_AUTO_PORT) {
		if (mpu_irq[dev] == SNDRV_AUTO_IRQ)
			mpu_irq[dev] = -1;
		if (snd_mpu401_uart_new(card, 0,
					MPU401_HW_MPU401,
					mpu_port[dev], 0,
					mpu_irq[dev], IRQF_DISABLED,
					NULL) < 0)
			snd_printk(KERN_ERR "no MPU-401 device at 0x%lx ?\n",
					mpu_port[dev]);
	}

	strcpy(card->driver, DRV_NAME);
	strcpy(card->shortname, "SC-6000");
	sprintf(card->longname, "Gallant SC-6000 at 0x%lx, irq %d, dma %d",
		mss_port[dev], xirq, xdma);

	snd_card_set_dev(card, devptr);

	err = snd_card_register(card);
	if (err < 0)
		goto err_unmap2;

	dev_set_drvdata(devptr, card);
	return 0;

err_unmap2:
	release_region(mss_port[dev], 4);
err_unmap1:
	release_region(port[dev], 0x10);
err_exit:
	snd_card_free(card);
	return err;
}
Example #8
0
static int __init snd_audiodrive_probe(int dev)
{
    static int possible_irqs[] = {5, 9, 10, 7, -1};
    static int possible_dmas[] = {1, 3, 0, -1};
    int xirq, xdma, xmpu_irq;
    snd_card_t *card;
    es1688_t *chip;
    opl3_t *opl3;
    snd_pcm_t *pcm;
    int err;

    card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
    if (card == NULL)
        return -ENOMEM;

    xirq = irq[dev];
    if (xirq == SNDRV_AUTO_IRQ) {
        if ((xirq = snd_legacy_find_free_irq(possible_irqs)) < 0) {
            snd_card_free(card);
            snd_printk("unable to find a free IRQ\n");
            return -EBUSY;
        }
    }
    xmpu_irq = mpu_irq[dev];
    xdma = dma8[dev];
    if (xdma == SNDRV_AUTO_DMA) {
        if ((xdma = snd_legacy_find_free_dma(possible_dmas)) < 0) {
            snd_card_free(card);
            snd_printk("unable to find a free DMA\n");
            return -EBUSY;
        }
    }

    if ((err = snd_es1688_create(card, port[dev], mpu_port[dev],
                                 xirq, xmpu_irq, xdma,
                                 ES1688_HW_AUTO, &chip)) < 0) {
        snd_card_free(card);
        return err;
    }
    if ((err = snd_es1688_pcm(chip, 0, &pcm)) < 0) {
        snd_card_free(card);
        return err;
    }
    if ((err = snd_es1688_mixer(chip)) < 0) {
        snd_card_free(card);
        return err;
    }

    strcpy(card->driver, "ES1688");
    strcpy(card->shortname, pcm->name);
    sprintf(card->longname, "%s at 0x%lx, irq %i, dma %i", pcm->name, chip->port, xirq, xdma);

    if ((snd_opl3_create(card, chip->port, chip->port + 2, OPL3_HW_OPL3, 0, &opl3)) < 0) {
        printk(KERN_ERR "es1688: opl3 not detected at 0x%lx\n", chip->port);
    } else {
        if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) {
            snd_card_free(card);
            return err;
        }
    }

    if (xmpu_irq >= 0 && xmpu_irq != SNDRV_AUTO_IRQ && chip->mpu_port > 0) {
        if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_ES1688,
                                       chip->mpu_port, 0,
                                       xmpu_irq,
                                       SA_INTERRUPT,
                                       NULL)) < 0) {
            snd_card_free(card);
            return err;
        }
    }
    if ((err = snd_card_register(card)) < 0) {
        snd_card_free(card);
        return err;
    }
    snd_audiodrive_cards[dev] = card;
    return 0;

}
static int __init snd_sgalaxy_probe(struct platform_device *devptr)
{
	int dev = devptr->id;
	static int possible_irqs[] = {7, 9, 10, 11, -1};
	static int possible_dmas[] = {1, 3, 0, -1};
	int err, xirq, xdma1;
	struct snd_card *card;
	struct snd_ad1848 *chip;

	if (sbport[dev] == SNDRV_AUTO_PORT) {
		snd_printk(KERN_ERR PFX "specify SB port\n");
		return -EINVAL;
	}
	if (wssport[dev] == SNDRV_AUTO_PORT) {
		snd_printk(KERN_ERR PFX "specify WSS port\n");
		return -EINVAL;
	}
	card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
	if (card == NULL)
		return -ENOMEM;

	xirq = irq[dev];
	if (xirq == SNDRV_AUTO_IRQ) {
		if ((xirq = snd_legacy_find_free_irq(possible_irqs)) < 0) {
			snd_printk(KERN_ERR PFX "unable to find a free IRQ\n");
			err = -EBUSY;
			goto _err;
		}
	}
	xdma1 = dma1[dev];
        if (xdma1 == SNDRV_AUTO_DMA) {
		if ((xdma1 = snd_legacy_find_free_dma(possible_dmas)) < 0) {
			snd_printk(KERN_ERR PFX "unable to find a free DMA\n");
			err = -EBUSY;
			goto _err;
		}
	}

	if ((err = snd_sgalaxy_detect(dev, xirq, xdma1)) < 0)
		goto _err;

	if ((err = snd_ad1848_create(card, wssport[dev] + 4,
				     xirq, xdma1,
				     AD1848_HW_DETECT, &chip)) < 0)
		goto _err;
	card->private_data = chip;

	if ((err = snd_ad1848_pcm(chip, 0, NULL)) < 0) {
		snd_printdd(PFX "error creating new ad1848 PCM device\n");
		goto _err;
	}
	if ((err = snd_ad1848_mixer(chip)) < 0) {
		snd_printdd(PFX "error creating new ad1848 mixer\n");
		goto _err;
	}
	if ((err = snd_sgalaxy_mixer(chip)) < 0) {
		snd_printdd(PFX "the mixer rewrite failed\n");
		goto _err;
	}

	strcpy(card->driver, "Sound Galaxy");
	strcpy(card->shortname, "Sound Galaxy");
	sprintf(card->longname, "Sound Galaxy at 0x%lx, irq %d, dma %d",
		wssport[dev], xirq, xdma1);

	snd_card_set_dev(card, &devptr->dev);

	if ((err = snd_card_register(card)) < 0)
		goto _err;

	platform_set_drvdata(devptr, card);
	return 0;

 _err:
	snd_card_free(card);
	return err;
}
Example #10
0
static int tegra_pcm_open(struct snd_pcm_substream *substream)
{
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct snd_pcm *pcm = substream->pcm;
	struct pcm_runtime_data *prtd;
	int ret = 0;
	NvError e = NvSuccess;
	NvAudioFxMessage message;
	NvAudioFxObjectHandle hSource = 0;
	struct tegra_audio_data *ptscx = tegra_snd_cx[pcm->device];

	prtd = kzalloc(sizeof(struct pcm_runtime_data), GFP_KERNEL);
	if (prtd == NULL)
		return -ENOMEM;

	runtime->private_data = prtd;
	snd_soc_set_runtime_hwparams(substream, &tegra_pcm_hardware);
	spin_lock_init(&prtd->lock);
	prtd->timeout = INIT_TIMEOUT;
	prtd->stdoutpath = 0;
	prtd->stdinpath = 0;
	prtd->state = NVALSA_INVALID_STATE;
	prtd->stream = substream->stream;

	if (!ptscx->mixer_handle) {
		ret = tegra_audiofx_init(ptscx);
		if (ret)
			goto fail;
	}

	init_completion(&prtd->thread_comp);
	init_waitqueue_head(&prtd->buf_wait);
	sema_init(&prtd->buf_done_sem, 0);
	sema_init(&prtd->stop_done_sem, 0);

	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK){
		hSource = ptscx->i2s1_play_mix;
		if (pcm->device == I2S2)
			hSource = ptscx->i2s2_play_mix;

		prtd->mixer_buffer = ptscx->mixer_buffer[0];
		prtd->stdoutpath = (StandardPath*)kzalloc(sizeof(StandardPath),
							  GFP_KERNEL);
		if (prtd->stdoutpath == NULL) {
			snd_printk(KERN_ERR "pcm_open kzalloc failed \n");
			ret = -ENOMEM;
			goto fail;
		}

		e = tegra_audiofx_create_output(ptscx->m_hRm,
						ptscx->mixer_handle,
						prtd->stdoutpath,
						hSource);
		if (e != NvSuccess) {
			snd_printk(KERN_ERR "audiofx_create_output failed \n");
			ret = -EFAULT;
			goto fail;
		}

		memset(&message, 0, sizeof(NvAudioFxMessage));
		message.Event = (NvAudioFxEventBufferDone |
				 NvAudioFxEventStateChange);
		message.hFx = (NvAudioFxHandle)prtd->stdoutpath->Stream;
		message.pContext = prtd;

		e = ptscx->xrt_fxn.SetProperty(
		    (NvAudioFxObjectHandle)ptscx->m_FxNotifier.hNotifier,
		    NvAudioFxIoProperty_AddEvent,
		    sizeof(NvAudioFxMessage),
		    &message);

		if (e != NvSuccess) {
			snd_printk(KERN_ERR "TransportSetProperty failed\n");
			ret = -EFAULT;
			goto fail;
		}

		ptscx->m_FxNotifier.Event |= (NvAudioFxEventBufferDone |
						     NvAudioFxEventStateChange);

		prtd->play_thread = kthread_run(play_thread,
						substream,
						"%sthread",
						"play");
		if (IS_ERR(prtd->play_thread)) {
			snd_printk(KERN_ERR "KTHREAD RUN FAIL\n");
			ret = PTR_ERR(prtd->play_thread);
			goto fail;
		}
	} else {
		hSource = ptscx->i2s1_rec_split;
		if (pcm->device == I2S2)
			hSource = ptscx->i2s2_rec_split;

		prtd->mixer_buffer = ptscx->mixer_buffer[1];
		prtd->stdinpath = (StandardPath*)kzalloc(sizeof(StandardPath),
							  GFP_KERNEL);
		if (prtd->stdinpath == NULL) {
			snd_printk(KERN_ERR "pcm_open kzalloc failed \n");
			ret = -ENOMEM;
			goto fail;
		}
		e = tegra_audiofx_create_input(ptscx->m_hRm,
						ptscx->mixer_handle,
						prtd->stdinpath,
						NvAudioInputSelect_Record,
						hSource);
		if (e != NvSuccess) {
			snd_printk(KERN_ERR "audiofx_create_input failed \n");
			ret = -EFAULT;
			goto fail;
		}

		memset(&message, 0, sizeof(NvAudioFxMessage));
		message.Event = (NvAudioFxEventBufferDone |
				 NvAudioFxEventStateChange);
		message.hFx = (NvAudioFxHandle)prtd->stdinpath->Stream;
		message.pContext = prtd;

		e = ptscx->xrt_fxn.SetProperty(
		    (NvAudioFxObjectHandle)ptscx->m_FxNotifier.hNotifier,
		    NvAudioFxIoProperty_AddEvent,
		    sizeof(NvAudioFxMessage),
		    &message);
		if (e != NvSuccess) {
			snd_printk(KERN_ERR "TransportSetProperty failed\n");
			ret = -EFAULT;
			goto fail;
		}
		ptscx->m_FxNotifier.Event |= (NvAudioFxEventBufferDone |
						     NvAudioFxEventStateChange);

		prtd->rec_thread = kthread_run(rec_thread,
						substream,
						"%sthread",
						"rec" );
		if (IS_ERR(prtd->rec_thread)) {
			snd_printk(KERN_ERR "Kthread Run Fail\n");
			ret = PTR_ERR(prtd->rec_thread);
			goto fail;
		}
	}

	if (pcm->device == I2S2) {
		NvAudioFxIoDevice io_device;

		mutex_lock(&tegra_audio_state.mutex_lock);
		tegra_audio_state.audio_mode |= NvAudioFxMode_Bluetooth_Sco;
		tegra_audio_state.devices_available |=
					NvAudioFxIoDevice_Bluetooth_Sco;
		mutex_unlock(&tegra_audio_state.mutex_lock);

		ptscx->xrt_fxn.SetProperty(
				(NvAudioFxObjectHandle)ptscx->mixer_handle,
				NvAudioFxMixerProperty_ModeSelect,
				sizeof(NvAudioFxMode),
				&tegra_audio_state.audio_mode);

		ptscx->xrt_fxn.SetProperty(ptscx->mi2s1,
				NvAudioFxIoProperty_OutputAvailable,
				sizeof(NvAudioFxIoDevice),
				&tegra_audio_state.devices_available);

		ptscx->xrt_fxn.SetProperty(ptscx->mi2s1,
				NvAudioFxIoProperty_InputAvailable,
				sizeof(NvAudioFxIoDevice),
				&tegra_audio_state.devices_available);

		io_device = NvAudioFxIoDevice_Bluetooth_Sco;

		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
			ptscx->xrt_fxn.SetProperty(ptscx->mi2s1,
				NvAudioFxIoProperty_OutputEnable,
				sizeof(NvAudioFxIoDevice),
				&io_device);
		}
		else {
			ptscx->xrt_fxn.SetProperty(ptscx->mi2s1,
				NvAudioFxIoProperty_InputEnable,
				sizeof(NvAudioFxIoDevice),
				&io_device);
		}
	}

	return ret;
fail:
	snd_printk(KERN_ERR "tegra_pcm_open - failed \n");
	pcm_common_close(substream);
	return ret;
}
Example #11
0
/*
 * register a new port if it doesn't exist yet
 */
int
snd_seq_oss_midi_check_new_port(struct snd_seq_port_info *pinfo)
{
	int i;
	struct seq_oss_midi *mdev;
	unsigned long flags;

	debug_printk(("check for MIDI client %d port %d\n", pinfo->addr.client, pinfo->addr.port));
	/* the port must include generic midi */
	if (! (pinfo->type & SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC))
		return 0;
	/* either read or write subscribable */
	if ((pinfo->capability & PERM_WRITE) != PERM_WRITE &&
	    (pinfo->capability & PERM_READ) != PERM_READ)
		return 0;

	/*
	 * look for the identical slot
	 */
	if ((mdev = find_slot(pinfo->addr.client, pinfo->addr.port)) != NULL) {
		/* already exists */
		snd_use_lock_free(&mdev->use_lock);
		return 0;
	}

	/*
	 * allocate midi info record
	 */
	if ((mdev = kzalloc(sizeof(*mdev), GFP_KERNEL)) == NULL) {
		snd_printk(KERN_ERR "can't malloc midi info\n");
		return -ENOMEM;
	}

	/* copy the port information */
	mdev->client = pinfo->addr.client;
	mdev->port = pinfo->addr.port;
	mdev->flags = pinfo->capability;
	mdev->opened = 0;
	snd_use_lock_init(&mdev->use_lock);

	/* copy and truncate the name of synth device */
	strlcpy(mdev->name, pinfo->name, sizeof(mdev->name));

	/* create MIDI coder */
	if (snd_midi_event_new(MAX_MIDI_EVENT_BUF, &mdev->coder) < 0) {
		snd_printk(KERN_ERR "can't malloc midi coder\n");
		kfree(mdev);
		return -ENOMEM;
	}
	/* OSS sequencer adds running status to all sequences */
	snd_midi_event_no_status(mdev->coder, 1);

	/*
	 * look for en empty slot
	 */
	spin_lock_irqsave(&register_lock, flags);
	for (i = 0; i < max_midi_devs; i++) {
		if (midi_devs[i] == NULL)
			break;
	}
	if (i >= max_midi_devs) {
		if (max_midi_devs >= SNDRV_SEQ_OSS_MAX_MIDI_DEVS) {
			spin_unlock_irqrestore(&register_lock, flags);
			snd_midi_event_free(mdev->coder);
			kfree(mdev);
			return -ENOMEM;
		}
		max_midi_devs++;
	}
	mdev->seq_device = i;
	midi_devs[mdev->seq_device] = mdev;
	spin_unlock_irqrestore(&register_lock, flags);

	return 0;
}
Example #12
0
static int pcm_common_close(struct snd_pcm_substream *substream)
{
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct pcm_runtime_data *prtd = runtime->private_data;
	struct snd_pcm *pcm = substream->pcm;
	struct tegra_audio_data *ptscx = tegra_snd_cx[pcm->device];
	NvAudioFxMessage message;
	NvError e;
	NvAudioFxIoDevice io_device;

	if (!prtd)
		snd_printk(KERN_ERR "pcm_close called with prtd = NULL\n");

	prtd->state = SNDRV_PCM_TRIGGER_STOP;

	if (completion_done(&prtd->thread_comp) == 0)
		complete(&prtd->thread_comp);

	wake_up_all(&prtd->buf_wait);

	if (prtd->play_thread)
		kthread_stop(prtd->play_thread);

	if (prtd->rec_thread)
		kthread_stop(prtd->rec_thread);

	if (ptscx->m_FxNotifier.Event) {

		memset(&message, 0, sizeof(NvAudioFxMessage));
		message.Event = NvAudioFxEventAll;
		message.pContext = NULL;
		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
			message.hFx = (NvAudioFxHandle)prtd->stdoutpath->Stream;
		else
			message.hFx = (NvAudioFxHandle)prtd->stdinpath->Stream;

		e = ptscx->xrt_fxn.SetProperty(
		    (NvAudioFxObjectHandle)ptscx->m_FxNotifier.hNotifier,
		    NvAudioFxIoProperty_RemoveEvent,
		    sizeof(NvAudioFxMessage),
		    &message);

		ptscx->m_FxNotifier.Event &= ~NvAudioFxEventAll;
	}

	if (prtd->stdoutpath) {
		if (pcm->device == I2S2) {
			io_device = NvAudioFxIoDevice_Bluetooth_Sco;
			ptscx->xrt_fxn.SetProperty(ptscx->mi2s1,
				NvAudioFxIoProperty_OutputDisable,
				sizeof(NvAudioFxIoDevice),
				&io_device);
		}
		tegra_audiofx_destroy_output(prtd->stdoutpath);
		kfree(prtd->stdoutpath);
	}

	if (prtd->stdinpath) {
		if (pcm->device == I2S2) {
			io_device = NvAudioFxIoDevice_Bluetooth_Sco;
			ptscx->xrt_fxn.SetProperty(ptscx->mi2s1,
				NvAudioFxIoProperty_InputDisable,
				sizeof(NvAudioFxIoDevice),
				&io_device);
		}
		tegra_audiofx_destroy_input(prtd->stdinpath);
		kfree(prtd->stdinpath);
	}

	if (pcm->device == I2S2) {
		ptscx->xrt_fxn.GetProperty(ptscx->mi2s1,
				NvAudioFxIoProperty_OutputSelect,
				sizeof(NvAudioFxIoDevice),
				&io_device);
		if (io_device & NvAudioFxIoDevice_Bluetooth_Sco) {
			ptscx->xrt_fxn.GetProperty(ptscx->mi2s1,
				NvAudioFxIoProperty_InputSelect,
				sizeof(NvAudioFxIoDevice),
				&io_device);
			if (io_device & NvAudioFxIoDevice_Bluetooth_Sco) {
				mutex_lock(&tegra_audio_state.mutex_lock);
				tegra_audio_state.devices_available &=
				~(NvAudioFxIoDevice_Bluetooth_Sco);

				ptscx->xrt_fxn.SetProperty(ptscx->mi2s1,
					NvAudioFxIoProperty_OutputAvailable,
					sizeof(NvAudioFxIoDevice),
					&tegra_audio_state.devices_available);

				ptscx->xrt_fxn.SetProperty(ptscx->mi2s1,
					NvAudioFxIoProperty_InputAvailable,
					sizeof(NvAudioFxIoDevice),
					&tegra_audio_state.devices_available);

				tegra_audio_state.audio_mode &=
					~(NvAudioFxMode_Bluetooth_Sco);
				ptscx->xrt_fxn.SetProperty(
				(NvAudioFxObjectHandle)ptscx->mixer_handle,
				NvAudioFxMixerProperty_ModeSelect,
				sizeof(NvAudioFxMode),
				&tegra_audio_state.audio_mode);
				mutex_unlock(&tegra_audio_state.mutex_lock);
			}
		}
	}

	if (prtd)
		kfree(prtd);

	return 0;
}
Example #13
0
static int rec_thread( void *arg )
{
	struct snd_pcm_substream *substream = arg;
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct pcm_runtime_data *prtd = substream->runtime->private_data;
	NvError e;
	int size = 0;
	int offset = 0;
	int period_offset = 0;
	int rtbuffersize = 0;
	int buffer_to_prime = 0, buffer_in_queue = 0;
	NvAudioFxBufferDescriptor abd;
	NvAudioFxState state = NVALSA_INVALID_STATE;
	NvAudioFxPinFormatDescriptor pin_format;
	struct snd_pcm *pcm = substream->pcm;
	struct tegra_audio_data *ptscx = tegra_snd_cx[pcm->device];

	wait_for_completion(&prtd->thread_comp);
	rtbuffersize = frames_to_bytes(runtime, runtime->buffer_size);
	buffer_to_prime  = (rtbuffersize / TEGRA_DEFAULT_BUFFER_SIZE);

	for (;;) {
		switch (prtd->state) {
		case SNDRV_PCM_TRIGGER_START:
			if (state != NvAudioFxState_Run) {
				pin_format.Format.FormatTag = 1;
				pin_format.Format.SampleRate = runtime->rate;
				pin_format.Format.BitsPerSample = runtime->sample_bits;
				pin_format.Format.Channels = runtime->channels;
				pin_format.Format.ChannelMask = 0;
				pin_format.Format.ValidBitsPerSample = 0;
				pin_format.Pin = NvAudioFxSourcePin;

				e = ptscx->xrt_fxn.SetProperty(
						 prtd->stdinpath->Convert,
						 NvAudioFxPinProperty_Format,
						 sizeof(NvAudioFxPinFormatDescriptor),
						 &pin_format);
				if (e != NvSuccess) {
					snd_printk(KERN_ERR"set_property failed!\n");
				}

				e = ptscx->xrt_fxn.SetProperty(
						 prtd->stdinpath->Src,
						 NvAudioFxProperty_SampleRate,
						 sizeof(NvS32),
						 &pin_format.Format.SampleRate);
				if (e != NvSuccess) {
					snd_printk(KERN_ERR "set_property failed!\n");
				}

				state = NvAudioFxState_Run;
				ptscx->xrt_fxn.SetProperty(
						 prtd->stdinpath->Stream,
						 NvAudioFxProperty_State,
						 sizeof(NvAudioFxState),
						 &state);
			}
			break;
		case SNDRV_PCM_TRIGGER_STOP:
			if (state != NvAudioFxState_Stop) {
				state = NvAudioFxState_Stop;
				ptscx->xrt_fxn.SetProperty(
						 prtd->stdinpath->Stream,
						 NvAudioFxProperty_State,
						 sizeof(NvAudioFxState),
						 &state);
				down(&prtd->stop_done_sem);
				buffer_in_queue = 0;
			}
			goto EXIT;
		default:
			;
		}

		if ((state == NvAudioFxState_Run) &&
			(buffer_in_queue < buffer_to_prime)) {
			memset(&abd, 0, sizeof(NvAudioFxBufferDescriptor));

			size = TEGRA_DEFAULT_BUFFER_SIZE;
			if ((offset + size) > rtbuffersize) {
				size = rtbuffersize - offset;
			}

			abd.hMixBuffer = prtd->mixer_buffer;
			abd.Offset = offset;
			abd.Size = size;
			abd.Format.FormatTag = 1;
			abd.Format.SampleRate = runtime->rate;
			abd.Format.BitsPerSample = runtime->sample_bits;
			abd.Format.Channels = runtime->channels;
			abd.Format.ChannelMask = 0;

			e = ptscx->xrt_fxn.StreamAddBuffer(
				(NvAudioFxStreamHandle)prtd->stdinpath->Stream, &abd);
			buffer_in_queue++;
			offset += size;

			if (offset >= rtbuffersize)
				offset =0;
		}

		if ((buffer_to_prime == buffer_in_queue) &&
		    ((runtime->status->hw_ptr - runtime->control->appl_ptr) <
		    (runtime->buffer_size -runtime->period_size))) {
			down(&prtd->buf_done_sem);

			buffer_in_queue--;

			if ((frames_to_bytes(runtime, prtd->cur_pos) +
				TEGRA_DEFAULT_BUFFER_SIZE) > rtbuffersize) {
				size = rtbuffersize -
				       frames_to_bytes(runtime, prtd->cur_pos);
			} else {
				size = TEGRA_DEFAULT_BUFFER_SIZE;
			}

			prtd->cur_pos += bytes_to_frames(runtime, size);

			if (prtd->cur_pos < prtd->last_pos) {
				period_offset = (runtime->buffer_size +
						prtd->cur_pos) - prtd->last_pos;
			} else {
				period_offset = prtd->cur_pos - prtd->last_pos;
			}

			if (period_offset >= runtime->period_size) {
				prtd->last_pos = prtd->cur_pos;
				snd_pcm_period_elapsed(substream);
			}

			if (prtd->cur_pos >= runtime->buffer_size) {
				prtd->cur_pos -= runtime->buffer_size;
			}
		}
	}
EXIT:

	while (!kthread_should_stop()) {
	}

	return 0;
}
Example #14
0
/*
 * Create an AD1845 PCM subdevice on the SoundScape. The AD1845
 * is very much like a CS4231, with a few extra bits. We will
 * try to support at least some of the extra bits by overriding
 * some of the CS4231 callback.
 */
static int __devinit create_ad1845(struct snd_card *card, unsigned port,
				   int irq, int dma1, int dma2)
{
	register struct soundscape *sscape = get_card_soundscape(card);
	struct snd_wss *chip;
	int err;

	if (sscape->type == SSCAPE_VIVO)
		port += 4;

	if (dma1 == dma2)
		dma2 = -1;

	err = snd_wss_create(card, port, -1, irq, dma1, dma2,
			     WSS_HW_DETECT, WSS_HWSHARE_DMA1, &chip);
	if (!err) {
		unsigned long flags;
		struct snd_pcm *pcm;

/*
 * It turns out that the PLAYBACK_ENABLE bit is set
 * by the lowlevel driver ...
 *
#define AD1845_IFACE_CONFIG  \
           (CS4231_AUTOCALIB | CS4231_RECORD_ENABLE | CS4231_PLAYBACK_ENABLE)
    snd_wss_mce_up(chip);
    spin_lock_irqsave(&chip->reg_lock, flags);
    snd_wss_out(chip, CS4231_IFACE_CTRL, AD1845_IFACE_CONFIG);
    spin_unlock_irqrestore(&chip->reg_lock, flags);
    snd_wss_mce_down(chip);
 */

		if (sscape->type != SSCAPE_VIVO) {
			/*
			 * The input clock frequency on the SoundScape must
			 * be 14.31818 MHz, because we must set this register
			 * to get the playback to sound correct ...
			 */
			snd_wss_mce_up(chip);
			spin_lock_irqsave(&chip->reg_lock, flags);
			snd_wss_out(chip, AD1845_CLOCK, 0x20);
			spin_unlock_irqrestore(&chip->reg_lock, flags);
			snd_wss_mce_down(chip);

		}

		err = snd_wss_pcm(chip, 0, &pcm);
		if (err < 0) {
			snd_printk(KERN_ERR "sscape: No PCM device "
					    "for AD1845 chip\n");
			goto _error;
		}

		err = snd_wss_mixer(chip);
		if (err < 0) {
			snd_printk(KERN_ERR "sscape: No mixer device "
					    "for AD1845 chip\n");
			goto _error;
		}
		if (chip->hardware != WSS_HW_AD1848) {
			err = snd_wss_timer(chip, 0, NULL);
			if (err < 0) {
				snd_printk(KERN_ERR "sscape: No timer device "
						    "for AD1845 chip\n");
				goto _error;
			}
		}

		if (sscape->type != SSCAPE_VIVO) {
			err = snd_ctl_add(card,
					  snd_ctl_new1(&midi_mixer_ctl, chip));
			if (err < 0) {
				snd_printk(KERN_ERR "sscape: Could not create "
						    "MIDI mixer control\n");
				goto _error;
			}
		}

		strcpy(card->driver, "SoundScape");
		strcpy(card->shortname, pcm->name);
		snprintf(card->longname, sizeof(card->longname),
			 "%s at 0x%lx, IRQ %d, DMA1 %d, DMA2 %d\n",
			 pcm->name, chip->port, chip->irq,
			 chip->dma1, chip->dma2);

		sscape->chip = chip;
	}

	_error:
	return err;
}
Example #15
0
/*
 * Create an AD1845 PCM subdevice on the SoundScape. The AD1845
 * is very much like a CS4231, with a few extra bits. We will
 * try to support at least some of the extra bits by overriding
 * some of the CS4231 callback.
 */
static int __devinit create_ad1845(struct snd_card *card, unsigned port,
				   int irq, int dma1, int dma2)
{
	register struct soundscape *sscape = get_card_soundscape(card);
	struct snd_wss *chip;
	int err;

	if (sscape->type == SSCAPE_VIVO)
		port += 4;

	if (dma1 == dma2)
		dma2 = -1;

	err = snd_wss_create(card, port, -1, irq, dma1, dma2,
			     WSS_HW_DETECT, WSS_HWSHARE_DMA1, &chip);
	if (!err) {
		unsigned long flags;
		struct snd_pcm *pcm;

#define AD1845_FREQ_SEL_ENABLE  0x08

#define AD1845_PWR_DOWN_CTRL   0x1b
#define AD1845_CRYS_CLOCK_SEL  0x1d

/*
 * It turns out that the PLAYBACK_ENABLE bit is set
 * by the lowlevel driver ...
 *
#define AD1845_IFACE_CONFIG  \
           (CS4231_AUTOCALIB | CS4231_RECORD_ENABLE | CS4231_PLAYBACK_ENABLE)
    snd_wss_mce_up(chip);
    spin_lock_irqsave(&chip->reg_lock, flags);
    snd_wss_out(chip, CS4231_IFACE_CTRL, AD1845_IFACE_CONFIG);
    spin_unlock_irqrestore(&chip->reg_lock, flags);
    snd_wss_mce_down(chip);
 */

		if (sscape->type != SSCAPE_VIVO) {
			int val;
			/*
			 * The input clock frequency on the SoundScape must
			 * be 14.31818 MHz, because we must set this register
			 * to get the playback to sound correct ...
			 */
			snd_wss_mce_up(chip);
			spin_lock_irqsave(&chip->reg_lock, flags);
			snd_wss_out(chip, AD1845_CRYS_CLOCK_SEL, 0x20);
			spin_unlock_irqrestore(&chip->reg_lock, flags);
			snd_wss_mce_down(chip);

			/*
			 * More custom configuration:
			 * a) select "mode 2" and provide a current drive of 8mA
			 * b) enable frequency selection (for capture/playback)
			 */
			spin_lock_irqsave(&chip->reg_lock, flags);
			snd_wss_out(chip, CS4231_MISC_INFO,
				    CS4231_MODE2 | 0x10);
			val = snd_wss_in(chip, AD1845_PWR_DOWN_CTRL);
			snd_wss_out(chip, AD1845_PWR_DOWN_CTRL,
				    val | AD1845_FREQ_SEL_ENABLE);
			spin_unlock_irqrestore(&chip->reg_lock, flags);
		}

		err = snd_wss_pcm(chip, 0, &pcm);
		if (err < 0) {
			snd_printk(KERN_ERR "sscape: No PCM device "
					    "for AD1845 chip\n");
			goto _error;
		}

		err = snd_wss_mixer(chip);
		if (err < 0) {
			snd_printk(KERN_ERR "sscape: No mixer device "
					    "for AD1845 chip\n");
			goto _error;
		}
		err = snd_wss_timer(chip, 0, NULL);
		if (err < 0) {
			snd_printk(KERN_ERR "sscape: No timer device "
					    "for AD1845 chip\n");
			goto _error;
		}

		if (sscape->type != SSCAPE_VIVO) {
			err = snd_ctl_add(card,
					  snd_ctl_new1(&midi_mixer_ctl, chip));
			if (err < 0) {
				snd_printk(KERN_ERR "sscape: Could not create "
						    "MIDI mixer control\n");
				goto _error;
			}
			chip->set_playback_format = ad1845_playback_format;
			chip->set_capture_format = ad1845_capture_format;
		}

		strcpy(card->driver, "SoundScape");
		strcpy(card->shortname, pcm->name);
		snprintf(card->longname, sizeof(card->longname),
			 "%s at 0x%lx, IRQ %d, DMA1 %d, DMA2 %d\n",
			 pcm->name, chip->port, chip->irq,
			 chip->dma1, chip->dma2);

		sscape->chip = chip;
	}

	_error:
	return err;
}
Example #16
0
static int __devinit
snd_nm256_create(struct snd_card *card, struct pci_dev *pci,
		 struct nm256 **chip_ret)
{
	struct nm256 *chip;
	int err, pval;
	static struct snd_device_ops ops = {
		.dev_free =	snd_nm256_dev_free,
	};
	u32 addr;

	*chip_ret = NULL;

	if ((err = pci_enable_device(pci)) < 0)
		return err;

	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
	if (chip == NULL) {
		pci_disable_device(pci);
		return -ENOMEM;
	}

	chip->card = card;
	chip->pci = pci;
	chip->use_cache = use_cache;
	spin_lock_init(&chip->reg_lock);
	chip->irq = -1;
	mutex_init(&chip->irq_mutex);

	/* store buffer sizes in bytes */
	chip->streams[SNDRV_PCM_STREAM_PLAYBACK].bufsize = playback_bufsize * 1024;
	chip->streams[SNDRV_PCM_STREAM_CAPTURE].bufsize = capture_bufsize * 1024;

	/* 
	 * The NM256 has two memory ports.  The first port is nothing
	 * more than a chunk of video RAM, which is used as the I/O ring
	 * buffer.  The second port has the actual juicy stuff (like the
	 * mixer and the playback engine control registers).
	 */

	chip->buffer_addr = pci_resource_start(pci, 0);
	chip->cport_addr = pci_resource_start(pci, 1);

	/* Init the memory port info.  */
	/* remap control port (#2) */
	chip->res_cport = request_mem_region(chip->cport_addr, NM_PORT2_SIZE,
					     card->driver);
	if (chip->res_cport == NULL) {
		snd_printk(KERN_ERR "memory region 0x%lx (size 0x%x) busy\n",
			   chip->cport_addr, NM_PORT2_SIZE);
		err = -EBUSY;
		goto __error;
	}
	chip->cport = ioremap_nocache(chip->cport_addr, NM_PORT2_SIZE);
	if (chip->cport == NULL) {
		snd_printk(KERN_ERR "unable to map control port %lx\n", chip->cport_addr);
		err = -ENOMEM;
		goto __error;
	}

	if (!strcmp(card->driver, "NM256AV")) {
		/* Ok, try to see if this is a non-AC97 version of the hardware. */
		pval = snd_nm256_readw(chip, NM_MIXER_PRESENCE);
		if ((pval & NM_PRESENCE_MASK) != NM_PRESENCE_VALUE) {
			if (! force_ac97) {
				printk(KERN_ERR "nm256: no ac97 is found!\n");
				printk(KERN_ERR "  force the driver to load by "
				       "passing in the module parameter\n");
				printk(KERN_ERR "    force_ac97=1\n");
				printk(KERN_ERR "  or try sb16, opl3sa2, or "
				       "cs423x drivers instead.\n");
				err = -ENXIO;
				goto __error;
			}
		}
		chip->buffer_end = 2560 * 1024;
		chip->interrupt = snd_nm256_interrupt;
		chip->mixer_status_offset = NM_MIXER_STATUS_OFFSET;
		chip->mixer_status_mask = NM_MIXER_READY_MASK;
	} else {
		/* Not sure if there is any relevant detect for the ZX or not.  */
		if (snd_nm256_readb(chip, 0xa0b) != 0)
			chip->buffer_end = 6144 * 1024;
		else
			chip->buffer_end = 4096 * 1024;

		chip->interrupt = snd_nm256_interrupt_zx;
		chip->mixer_status_offset = NM2_MIXER_STATUS_OFFSET;
		chip->mixer_status_mask = NM2_MIXER_READY_MASK;
	}
	
	chip->buffer_size = chip->streams[SNDRV_PCM_STREAM_PLAYBACK].bufsize +
		chip->streams[SNDRV_PCM_STREAM_CAPTURE].bufsize;
	if (chip->use_cache)
		chip->buffer_size += NM_TOTAL_COEFF_COUNT * 4;
	else
		chip->buffer_size += NM_MAX_PLAYBACK_COEF_SIZE + NM_MAX_RECORD_COEF_SIZE;

	if (buffer_top >= chip->buffer_size && buffer_top < chip->buffer_end)
		chip->buffer_end = buffer_top;
	else {
		/* get buffer end pointer from signature */
		if ((err = snd_nm256_peek_for_sig(chip)) < 0)
			goto __error;
	}

	chip->buffer_start = chip->buffer_end - chip->buffer_size;
	chip->buffer_addr += chip->buffer_start;

	printk(KERN_INFO "nm256: Mapping port 1 from 0x%x - 0x%x\n",
	       chip->buffer_start, chip->buffer_end);

	chip->res_buffer = request_mem_region(chip->buffer_addr,
					      chip->buffer_size,
					      card->driver);
	if (chip->res_buffer == NULL) {
		snd_printk(KERN_ERR "nm256: buffer 0x%lx (size 0x%x) busy\n",
			   chip->buffer_addr, chip->buffer_size);
		err = -EBUSY;
		goto __error;
	}
	chip->buffer = ioremap_nocache(chip->buffer_addr, chip->buffer_size);
	if (chip->buffer == NULL) {
		err = -ENOMEM;
		snd_printk(KERN_ERR "unable to map ring buffer at %lx\n", chip->buffer_addr);
		goto __error;
	}

	/* set offsets */
	addr = chip->buffer_start;
	chip->streams[SNDRV_PCM_STREAM_PLAYBACK].buf = addr;
	addr += chip->streams[SNDRV_PCM_STREAM_PLAYBACK].bufsize;
	chip->streams[SNDRV_PCM_STREAM_CAPTURE].buf = addr;
	addr += chip->streams[SNDRV_PCM_STREAM_CAPTURE].bufsize;
	if (chip->use_cache) {
		chip->all_coeff_buf = addr;
	} else {
		chip->coeff_buf[SNDRV_PCM_STREAM_PLAYBACK] = addr;
		addr += NM_MAX_PLAYBACK_COEF_SIZE;
		chip->coeff_buf[SNDRV_PCM_STREAM_CAPTURE] = addr;
	}

	/* Fixed setting. */
	chip->mixer_base = NM_MIXER_OFFSET;

	chip->coeffs_current = 0;

	snd_nm256_init_chip(chip);

	// pci_set_master(pci); /* needed? */
	
	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0)
		goto __error;

	snd_card_set_dev(card, &pci->dev);

	*chip_ret = chip;
	return 0;

__error:
	snd_nm256_free(chip);
	return err;
}
Example #17
0
/*
 * Create an ALSA soundcard entry for the SoundScape, using
 * the given list of port, IRQ and DMA resources.
 */
static int __devinit create_sscape(int dev, struct snd_card *card)
{
	struct soundscape *sscape = get_card_soundscape(card);
	unsigned dma_cfg;
	unsigned irq_cfg;
	unsigned mpu_irq_cfg;
	unsigned xport;
	struct resource *io_res;
	struct resource *wss_res;
	unsigned long flags;
	int err;

	/*
	 * Check that the user didn't pass us garbage data ...
	 */
	irq_cfg = get_irq_config(irq[dev]);
	if (irq_cfg == INVALID_IRQ) {
		snd_printk(KERN_ERR "sscape: Invalid IRQ %d\n", irq[dev]);
		return -ENXIO;
	}

	mpu_irq_cfg = get_irq_config(mpu_irq[dev]);
	if (mpu_irq_cfg == INVALID_IRQ) {
		printk(KERN_ERR "sscape: Invalid IRQ %d\n", mpu_irq[dev]);
		return -ENXIO;
	}
	xport = port[dev];

	/*
	 * Grab IO ports that we will need to probe so that we
	 * can detect and control this hardware ...
	 */
	io_res = request_region(xport, 8, "SoundScape");
	if (!io_res) {
		snd_printk(KERN_ERR "sscape: can't grab port 0x%x\n", xport);
		return -EBUSY;
	}
	wss_res = NULL;
	if (sscape->type == SSCAPE_VIVO) {
		wss_res = request_region(wss_port[dev], 4, "SoundScape");
		if (!wss_res) {
			snd_printk(KERN_ERR "sscape: can't grab port 0x%lx\n",
					    wss_port[dev]);
			err = -EBUSY;
			goto _release_region;
		}
	}

	/*
	 * Grab one DMA channel ...
	 */
	err = request_dma(dma[dev], "SoundScape");
	if (err < 0) {
		snd_printk(KERN_ERR "sscape: can't grab DMA %d\n", dma[dev]);
		goto _release_region;
	}

	spin_lock_init(&sscape->lock);
	spin_lock_init(&sscape->fwlock);
	sscape->io_res = io_res;
	sscape->wss_res = wss_res;
	sscape->io_base = xport;
	sscape->wss_base = wss_port[dev];

	if (!detect_sscape(sscape)) {
		printk(KERN_ERR "sscape: hardware not detected at 0x%x\n", sscape->io_base);
		err = -ENODEV;
		goto _release_dma;
	}

	printk(KERN_INFO "sscape: hardware detected at 0x%x, using IRQ %d, DMA %d\n",
			 sscape->io_base, irq[dev], dma[dev]);

	if (sscape->type != SSCAPE_VIVO) {
		/*
		 * Now create the hardware-specific device so that we can
		 * load the microcode into the on-board processor.
		 * We cannot use the MPU-401 MIDI system until this firmware
		 * has been loaded into the card.
		 */
		err = snd_hwdep_new(card, "MC68EC000", 0, &(sscape->hw));
		if (err < 0) {
			printk(KERN_ERR "sscape: Failed to create "
					"firmware device\n");
			goto _release_dma;
		}
		strlcpy(sscape->hw->name, "SoundScape M68K",
			sizeof(sscape->hw->name));
		sscape->hw->name[sizeof(sscape->hw->name) - 1] = '\0';
		sscape->hw->iface = SNDRV_HWDEP_IFACE_SSCAPE;
		sscape->hw->ops.open = sscape_hw_open;
		sscape->hw->ops.release = sscape_hw_release;
		sscape->hw->ops.ioctl = sscape_hw_ioctl;
		sscape->hw->private_data = sscape;
	}

	/*
	 * Tell the on-board devices where their resources are (I think -
	 * I can't be sure without a datasheet ... So many magic values!)
	 */
	spin_lock_irqsave(&sscape->lock, flags);

	activate_ad1845_unsafe(sscape->io_base);

	sscape_write_unsafe(sscape->io_base, GA_INTENA_REG, 0x00); /* disable */
	sscape_write_unsafe(sscape->io_base, GA_SMCFGA_REG, 0x2e);
	sscape_write_unsafe(sscape->io_base, GA_SMCFGB_REG, 0x00);

	/*
	 * Enable and configure the DMA channels ...
	 */
	sscape_write_unsafe(sscape->io_base, GA_DMACFG_REG, 0x50);
	dma_cfg = (sscape->ic_type == IC_ODIE ? 0x70 : 0x40);
	sscape_write_unsafe(sscape->io_base, GA_DMAA_REG, dma_cfg);
	sscape_write_unsafe(sscape->io_base, GA_DMAB_REG, 0x20);

	sscape_write_unsafe(sscape->io_base,
	                    GA_INTCFG_REG, 0xf0 | (mpu_irq_cfg << 2) | mpu_irq_cfg);
	sscape_write_unsafe(sscape->io_base,
			    GA_CDCFG_REG, 0x09 | DMA_8BIT
			    | (dma[dev] << 4) | (irq_cfg << 1));

	spin_unlock_irqrestore(&sscape->lock, flags);

	/*
	 * We have now enabled the codec chip, and so we should
	 * detect the AD1845 device ...
	 */
	err = create_ad1845(card, wss_port[dev], irq[dev],
			    dma[dev], dma2[dev]);
	if (err < 0) {
		printk(KERN_ERR "sscape: No AD1845 device at 0x%lx, IRQ %d\n",
		       wss_port[dev], irq[dev]);
		goto _release_dma;
	}
#define MIDI_DEVNUM  0
	if (sscape->type != SSCAPE_VIVO) {
		err = create_mpu401(card, MIDI_DEVNUM,
				    MPU401_IO(xport), mpu_irq[dev]);
		if (err < 0) {
			printk(KERN_ERR "sscape: Failed to create "
					"MPU-401 device at 0x%x\n",
					MPU401_IO(xport));
			goto _release_dma;
		}

		/*
		 * Enable the master IRQ ...
		 */
		sscape_write(sscape, GA_INTENA_REG, 0x80);

		/*
		 * Initialize mixer
		 */
		sscape->midi_vol = 0;
		host_write_ctrl_unsafe(sscape->io_base, CMD_SET_MIDI_VOL, 100);
		host_write_ctrl_unsafe(sscape->io_base, 0, 100);
		host_write_ctrl_unsafe(sscape->io_base, CMD_XXX_MIDI_VOL, 100);
	}

	/*
	 * Now that we have successfully created this sound card,
	 * it is safe to store the pointer.
	 * NOTE: we only register the sound card's "destructor"
	 *       function now that our "constructor" has completed.
	 */
	card->private_free = soundscape_free;

	return 0;

_release_dma:
	free_dma(dma[dev]);

_release_region:
	release_and_free_resource(wss_res);
	release_and_free_resource(io_res);

	return err;
}
Example #18
0
static int __devinit snd_nm256_probe(struct pci_dev *pci,
				     const struct pci_device_id *pci_id)
{
	struct snd_card *card;
	struct nm256 *chip;
	int err;
	const struct snd_pci_quirk *q;

	q = snd_pci_quirk_lookup(pci, nm256_quirks);
	if (q) {
		snd_printdd(KERN_INFO "nm256: Enabled quirk for %s.\n", q->name);
		switch (q->value) {
		case NM_BLACKLISTED:
			printk(KERN_INFO "nm256: The device is blacklisted. "
			       "Loading stopped\n");
			return -ENODEV;
		case NM_RESET_WORKAROUND_2:
			reset_workaround_2 = 1;
			/* Fall-through */
		case NM_RESET_WORKAROUND:
			reset_workaround = 1;
			break;
		}
	}

	err = snd_card_create(index, id, THIS_MODULE, 0, &card);
	if (err < 0)
		return err;

	switch (pci->device) {
	case PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO:
		strcpy(card->driver, "NM256AV");
		break;
	case PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO:
		strcpy(card->driver, "NM256ZX");
		break;
	case PCI_DEVICE_ID_NEOMAGIC_NM256XL_PLUS_AUDIO:
		strcpy(card->driver, "NM256XL+");
		break;
	default:
		snd_printk(KERN_ERR "invalid device id 0x%x\n", pci->device);
		snd_card_free(card);
		return -EINVAL;
	}

	if (vaio_hack)
		buffer_top = 0x25a800;	/* this avoids conflicts with XFree86 server */

	if (playback_bufsize < 4)
		playback_bufsize = 4;
	if (playback_bufsize > 128)
		playback_bufsize = 128;
	if (capture_bufsize < 4)
		capture_bufsize = 4;
	if (capture_bufsize > 128)
		capture_bufsize = 128;
	if ((err = snd_nm256_create(card, pci, &chip)) < 0) {
		snd_card_free(card);
		return err;
	}
	card->private_data = chip;

	if (reset_workaround) {
		snd_printdd(KERN_INFO "nm256: reset_workaround activated\n");
		chip->reset_workaround = 1;
	}

	if (reset_workaround_2) {
		snd_printdd(KERN_INFO "nm256: reset_workaround_2 activated\n");
		chip->reset_workaround_2 = 1;
	}

	if ((err = snd_nm256_pcm(chip, 0)) < 0 ||
	    (err = snd_nm256_mixer(chip)) < 0) {
		snd_card_free(card);
		return err;
	}

	sprintf(card->shortname, "NeoMagic %s", card->driver);
	sprintf(card->longname, "%s at 0x%lx & 0x%lx, irq %d",
		card->shortname,
		chip->buffer_addr, chip->cport_addr, chip->irq);

	if ((err = snd_card_register(card)) < 0) {
		snd_card_free(card);
		return err;
	}

	pci_set_drvdata(pci, card);
	return 0;
}
Example #19
0
static int __devinit sc6000_init_board(char __iomem *vport, int irq, int dma,
					char __iomem *vmss_port, int mpu_irq)
{
	char answer[15];
	char version[2];
	int mss_config = sc6000_irq_to_softcfg(irq) |
			 sc6000_dma_to_softcfg(dma);
	int config = mss_config |
		     sc6000_mpu_irq_to_softcfg(mpu_irq);
	int err;

	err = sc6000_dsp_reset(vport);
	if (err < 0) {
		snd_printk(KERN_ERR "sc6000_dsp_reset: failed!\n");
		return err;
	}

	memset(answer, 0, sizeof(answer));
	err = sc6000_dsp_get_answer(vport, GET_DSP_COPYRIGHT, answer, 15);
	if (err <= 0) {
		snd_printk(KERN_ERR "sc6000_dsp_copyright: failed!\n");
		return -ENODEV;
	}
	/*
	 * My SC-6000 card return "SC-6000" in DSPCopyright, so
	 * if we have something different, we have to be warned.
	 * Mine returns "SC-6000A " - KH
	 */
	if (strncmp("SC-6000", answer, 7))
		snd_printk(KERN_WARNING "Warning: non SC-6000 audio card!\n");

	if (sc6000_dsp_get_answer(vport, GET_DSP_VERSION, version, 2) < 2) {
		snd_printk(KERN_ERR "sc6000_dsp_version: failed!\n");
		return -ENODEV;
	}
	printk(KERN_INFO PFX "Detected model: %s, DSP version %d.%d\n",
		answer, version[0], version[1]);

	/*
	 * 0x0A == (IRQ 7, DMA 1, MIRQ 0)
	 */
	err = sc6000_cfg_write(vport, 0x0a);
	if (err < 0) {
		snd_printk(KERN_ERR "sc6000_cfg_write: failed!\n");
		return -EFAULT;
	}

	err = sc6000_setup_board(vport, config);
	if (err < 0) {
		snd_printk(KERN_ERR "sc6000_setup_board: failed!\n");
		return -ENODEV;
	}

	err = sc6000_init_mss(vport, config, vmss_port, mss_config);
	if (err < 0) {
		snd_printk(KERN_ERR "Can not initialize "
			   "Microsoft Sound System mode.\n");
		return -ENODEV;
	}

	return 0;
}
/*
 *    probe function - creates the card manager
 */
static int __devinit snd_mixart_probe(struct pci_dev *pci,
				      const struct pci_device_id *pci_id)
{
	static int dev;
	struct mixart_mgr *mgr;
	unsigned int i;
	int err;
	size_t size;

	/*
	 */
	if (dev >= SNDRV_CARDS)
		return -ENODEV;
	if (! enable[dev]) {
		dev++;
		return -ENOENT;
	}

	/* enable PCI device */
	if ((err = pci_enable_device(pci)) < 0)
		return err;
	pci_set_master(pci);

	/* check if we can restrict PCI DMA transfers to 32 bits */
	if (pci_set_dma_mask(pci, DMA_BIT_MASK(32)) < 0) {
		snd_printk(KERN_ERR "architecture does not support 32bit PCI busmaster DMA\n");
		pci_disable_device(pci);
		return -ENXIO;
	}

	/*
	 */
	mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
	if (! mgr) {
		pci_disable_device(pci);
		return -ENOMEM;
	}

	mgr->pci = pci;
	mgr->irq = -1;

	/* resource assignment */
	if ((err = pci_request_regions(pci, CARD_NAME)) < 0) {
		kfree(mgr);
		pci_disable_device(pci);
		return err;
	}
	for (i = 0; i < 2; i++) {
		mgr->mem[i].phys = pci_resource_start(pci, i);
		mgr->mem[i].virt = pci_ioremap_bar(pci, i);
		if (!mgr->mem[i].virt) {
		        printk(KERN_ERR "unable to remap resource 0x%lx\n",
			       mgr->mem[i].phys);
			snd_mixart_free(mgr);
			return -EBUSY;
		}
	}

	if (request_irq(pci->irq, snd_mixart_interrupt, IRQF_SHARED,
			KBUILD_MODNAME, mgr)) {
		snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
		snd_mixart_free(mgr);
		return -EBUSY;
	}
	mgr->irq = pci->irq;

	sprintf(mgr->shortname, "Digigram miXart");
	sprintf(mgr->longname, "%s at 0x%lx & 0x%lx, irq %i", mgr->shortname, mgr->mem[0].phys, mgr->mem[1].phys, mgr->irq);

	/* ISR spinlock  */
	spin_lock_init(&mgr->lock);

	/* init mailbox  */
	mgr->msg_fifo_readptr = 0;
	mgr->msg_fifo_writeptr = 0;

	spin_lock_init(&mgr->msg_lock);
	mutex_init(&mgr->msg_mutex);
	init_waitqueue_head(&mgr->msg_sleep);
	atomic_set(&mgr->msg_processed, 0);

	/* init setup mutex*/
	mutex_init(&mgr->setup_mutex);

	/* init message taslket */
	tasklet_init(&mgr->msg_taskq, snd_mixart_msg_tasklet, (unsigned long) mgr);

	/* card assignment */
	mgr->num_cards = MIXART_MAX_CARDS; /* 4  FIXME: configurable? */
	for (i = 0; i < mgr->num_cards; i++) {
		struct snd_card *card;
		char tmpid[16];
		int idx;

		if (index[dev] < 0)
			idx = index[dev];
		else
			idx = index[dev] + i;
		snprintf(tmpid, sizeof(tmpid), "%s-%d", id[dev] ? id[dev] : "MIXART", i);
		err = snd_card_create(idx, tmpid, THIS_MODULE, 0, &card);

		if (err < 0) {
			snd_printk(KERN_ERR "cannot allocate the card %d\n", i);
			snd_mixart_free(mgr);
			return err;
		}

		strcpy(card->driver, CARD_NAME);
		sprintf(card->shortname, "%s [PCM #%d]", mgr->shortname, i);
		sprintf(card->longname, "%s [PCM #%d]", mgr->longname, i);

		if ((err = snd_mixart_create(mgr, card, i)) < 0) {
			snd_card_free(card);
			snd_mixart_free(mgr);
			return err;
		}

		if(i==0) {
			/* init proc interface only for chip0 */
			snd_mixart_proc_init(mgr->chip[i]);
		}

		if ((err = snd_card_register(card)) < 0) {
			snd_mixart_free(mgr);
			return err;
		}
	}

	/* init firmware status (mgr->dsp_loaded reset in hwdep_new) */
	mgr->board_type = MIXART_DAUGHTER_TYPE_NONE;

	/* create array of streaminfo */
	size = PAGE_ALIGN( (MIXART_MAX_STREAM_PER_CARD * MIXART_MAX_CARDS *
			    sizeof(struct mixart_flowinfo)) );
	if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
				size, &mgr->flowinfo) < 0) {
		snd_mixart_free(mgr);
		return -ENOMEM;
	}
	/* init streaminfo_array */
	memset(mgr->flowinfo.area, 0, size);

	/* create array of bufferinfo */
	size = PAGE_ALIGN( (MIXART_MAX_STREAM_PER_CARD * MIXART_MAX_CARDS *
			    sizeof(struct mixart_bufferinfo)) );
	if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
				size, &mgr->bufferinfo) < 0) {
		snd_mixart_free(mgr);
		return -ENOMEM;
	}
	/* init bufferinfo_array */
	memset(mgr->bufferinfo.area, 0, size);

	/* set up firmware */
	err = snd_mixart_setup_firmware(mgr);
	if (err < 0) {
		snd_mixart_free(mgr);
		return err;
	}

	pci_set_drvdata(pci, mgr);
	dev++;
	return 0;
}
Example #21
0
static int __init snd_gusmax_probe(int dev)
{
    static int possible_irqs[] = {5, 11, 12, 9, 7, 15, 3, -1};
    static int possible_dmas[] = {5, 6, 7, 1, 3, -1};
    int xirq, xdma1, xdma2, err;
    snd_card_t *card;
    snd_gus_card_t *gus = NULL;
    cs4231_t *cs4231;
    struct snd_gusmax *maxcard;

    card = snd_card_new(index[dev], id[dev], THIS_MODULE,
                        sizeof(struct snd_gusmax));
    if (card == NULL)
        return -ENOMEM;
    card->private_free = snd_gusmax_free;
    maxcard = (struct snd_gusmax *)card->private_data;
    maxcard->card = card;
    maxcard->irq = -1;

    xirq = irq[dev];
    if (xirq == SNDRV_AUTO_IRQ) {
        if ((xirq = snd_legacy_find_free_irq(possible_irqs)) < 0) {
            snd_card_free(card);
            snd_printk("unable to find a free IRQ\n");
            return -EBUSY;
        }
    }
    xdma1 = dma1[dev];
    if (xdma1 == SNDRV_AUTO_DMA) {
        if ((xdma1 = snd_legacy_find_free_dma(possible_dmas)) < 0) {
            snd_card_free(card);
            snd_printk("unable to find a free DMA1\n");
            return -EBUSY;
        }
    }
    xdma2 = dma2[dev];
    if (xdma2 == SNDRV_AUTO_DMA) {
        if ((xdma2 = snd_legacy_find_free_dma(possible_dmas)) < 0) {
            snd_card_free(card);
            snd_printk("unable to find a free DMA2\n");
            return -EBUSY;
        }
    }

    if ((err = snd_gus_create(card,
                              port[dev],
                              -xirq, xdma1, xdma2,
                              0, channels[dev],
                              pcm_channels[dev],
                              0, &gus)) < 0) {
        snd_card_free(card);
        return err;
    }
    if ((err = snd_gusmax_detect(gus)) < 0) {
        snd_card_free(card);
        return err;
    }
    maxcard->gus_status_reg = gus->gf1.reg_irqstat;
    maxcard->pcm_status_reg = gus->gf1.port + 0x10c + 2;
    snd_gusmax_init(dev, card, gus);
    if ((err = snd_gus_initialize(gus)) < 0) {
        snd_card_free(card);
        return err;
    }
    if (!gus->max_flag) {
        printk(KERN_ERR "GUS MAX soundcard was not detected at 0x%lx\n", gus->gf1.port);
        snd_card_free(card);
        return -ENODEV;
    }

    if (request_irq(xirq, snd_gusmax_interrupt, SA_INTERRUPT, "GUS MAX", (void *)maxcard)) {
        snd_card_free(card);
        printk(KERN_ERR "gusmax: unable to grab IRQ %d\n", xirq);
        return -EBUSY;
    }
    maxcard->irq = xirq;

    if ((err = snd_cs4231_create(card,
                                 gus->gf1.port + 0x10c, -1, xirq,
                                 xdma2 < 0 ? xdma1 : xdma2, xdma1,
                                 CS4231_HW_DETECT,
                                 CS4231_HWSHARE_IRQ |
                                 CS4231_HWSHARE_DMA1 |
                                 CS4231_HWSHARE_DMA2,
                                 &cs4231)) < 0) {
        snd_card_free(card);
        return err;
    }
    if ((err = snd_cs4231_pcm(cs4231, 0, NULL)) < 0) {
        snd_card_free(card);
        return err;
    }
    if ((err = snd_cs4231_mixer(cs4231)) < 0) {
        snd_card_free(card);
        return err;
    }
    if ((err = snd_cs4231_timer(cs4231, 2, NULL)) < 0) {
        snd_card_free(card);
        return err;
    }
    if (pcm_channels[dev] > 0) {
        if ((err = snd_gf1_pcm_new(gus, 1, 1, NULL)) < 0) {
            snd_card_free(card);
            return err;
        }
    }
    if ((err = snd_gusmax_mixer(cs4231)) < 0) {
        snd_card_free(card);
        return err;
    }

    if ((err = snd_gf1_rawmidi_new(gus, 0, NULL)) < 0) {
        snd_card_free(card);
        return err;
    }

    sprintf(card->longname + strlen(card->longname), " at 0x%lx, irq %i, dma %i", gus->gf1.port, xirq, xdma1);
    if (xdma2 >= 0)
        sprintf(card->longname + strlen(card->longname), "&%i", xdma2);
    if ((err = snd_card_register(card)) < 0) {
        snd_card_free(card);
        return err;
    }

    maxcard->gus = gus;
    maxcard->cs4231 = cs4231;
    snd_gusmax_cards[dev] = card;
    return 0;
}
int snd_mixart_kill_ref_pipe(struct mixart_mgr *mgr,
			     struct mixart_pipe *pipe, int monitoring)
{
	int err = 0;

	if(pipe->status == PIPE_UNDEFINED)
		return 0;

	if(monitoring)
		pipe->monitoring = 0;
	else
		pipe->references--;

	if((pipe->references <= 0) && (pipe->monitoring == 0)) {

		struct mixart_msg request;
		struct mixart_delete_group_resp delete_resp;

		/* release the clock */
		err = mixart_set_clock( mgr, pipe, 0);
		if( err < 0 ) {
			snd_printk(KERN_ERR "mixart_set_clock(0) return error!\n");
		}

		/* stop the pipe */
		err = mixart_set_pipe_state(mgr, pipe, 0);
		if( err < 0 ) {
			snd_printk(KERN_ERR "error stopping pipe!\n");
		}

		request.message_id = MSG_STREAM_DELETE_GROUP;
		request.uid = (struct mixart_uid){0,0};
		request.data = &pipe->group_uid;            /* the streaming group ! */
		request.size = sizeof(pipe->group_uid);

		/* delete the pipe */
		err = snd_mixart_send_msg(mgr, &request, sizeof(delete_resp), &delete_resp);
		if ((err < 0) || (delete_resp.status != 0)) {
			snd_printk(KERN_ERR "error MSG_STREAM_DELETE_GROUP err(%x), status(%x)\n", err, delete_resp.status);
		}

		pipe->group_uid = (struct mixart_uid){0,0};
		pipe->stream_count = 0;
		pipe->status = PIPE_UNDEFINED;
	}

	return err;
}

static int mixart_set_stream_state(struct mixart_stream *stream, int start)
{
	struct snd_mixart *chip;
	struct mixart_stream_state_req stream_state_req;
	struct mixart_msg request;

	if(!stream->substream)
		return -EINVAL;

	memset(&stream_state_req, 0, sizeof(stream_state_req));
	stream_state_req.stream_count = 1;
	stream_state_req.stream_info.stream_desc.uid_pipe = stream->pipe->group_uid;
	stream_state_req.stream_info.stream_desc.stream_idx = stream->substream->number;

	if (stream->substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
		request.message_id = start ? MSG_STREAM_START_INPUT_STAGE_PACKET : MSG_STREAM_STOP_INPUT_STAGE_PACKET;
	else
		request.message_id = start ? MSG_STREAM_START_OUTPUT_STAGE_PACKET : MSG_STREAM_STOP_OUTPUT_STAGE_PACKET;

	request.uid = (struct mixart_uid){0,0};
	request.data = &stream_state_req;
	request.size = sizeof(stream_state_req);

	stream->abs_period_elapsed = 0;            /* reset stream pos      */
	stream->buf_periods = 0;
	stream->buf_period_frag = 0;

	chip = snd_pcm_substream_chip(stream->substream);

	return snd_mixart_send_msg_nonblock(chip->mgr, &request);
}

/*
 *  Trigger callback
 */

static int snd_mixart_trigger(struct snd_pcm_substream *subs, int cmd)
{
	struct mixart_stream *stream = subs->runtime->private_data;

	switch (cmd) {
	case SNDRV_PCM_TRIGGER_START:

		snd_printdd("SNDRV_PCM_TRIGGER_START\n");

		/* START_STREAM */
		if( mixart_set_stream_state(stream, 1) )
			return -EINVAL;

		stream->status = MIXART_STREAM_STATUS_RUNNING;

		break;
	case SNDRV_PCM_TRIGGER_STOP:

		/* STOP_STREAM */
		if( mixart_set_stream_state(stream, 0) )
			return -EINVAL;

		stream->status = MIXART_STREAM_STATUS_OPEN;

		snd_printdd("SNDRV_PCM_TRIGGER_STOP\n");

		break;

	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
		/* TODO */
		stream->status = MIXART_STREAM_STATUS_PAUSE;
		snd_printdd("SNDRV_PCM_PAUSE_PUSH\n");
		break;
	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
		/* TODO */
		stream->status = MIXART_STREAM_STATUS_RUNNING;
		snd_printdd("SNDRV_PCM_PAUSE_RELEASE\n");
		break;
	default:
		return -EINVAL;
	}
	return 0;
}

static int mixart_sync_nonblock_events(struct mixart_mgr *mgr)
{
	unsigned long timeout = jiffies + HZ;
	while (atomic_read(&mgr->msg_processed) > 0) {
		if (time_after(jiffies, timeout)) {
			snd_printk(KERN_ERR "mixart: cannot process nonblock events!\n");
			return -EBUSY;
		}
		schedule_timeout_uninterruptible(1);
	}
	return 0;
}

/*
 *  prepare callback for all pcms
 */
static int snd_mixart_prepare(struct snd_pcm_substream *subs)
{
	struct snd_mixart *chip = snd_pcm_substream_chip(subs);
	struct mixart_stream *stream = subs->runtime->private_data;

	/* TODO de façon non bloquante, réappliquer les hw_params (rate, bits, codec) */

	snd_printdd("snd_mixart_prepare\n");

	mixart_sync_nonblock_events(chip->mgr);

	/* only the first stream can choose the sample rate */
	/* the further opened streams will be limited to its frequency (see open) */
	if(chip->mgr->ref_count_rate == 1)
		chip->mgr->sample_rate = subs->runtime->rate;

	/* set the clock only once (first stream) on the same pipe */
	if(stream->pipe->references == 1) {
		if( mixart_set_clock(chip->mgr, stream->pipe, subs->runtime->rate) )
			return -EINVAL;
	}

	return 0;
}


static int mixart_set_format(struct mixart_stream *stream, snd_pcm_format_t format)
{
	int err;
	struct snd_mixart *chip;
	struct mixart_msg request;
	struct mixart_stream_param_desc stream_param;
	struct mixart_return_uid resp;

	chip = snd_pcm_substream_chip(stream->substream);

	memset(&stream_param, 0, sizeof(stream_param));

	stream_param.coding_type = CT_LINEAR;
	stream_param.number_of_channel = stream->channels;

	stream_param.sampling_freq = chip->mgr->sample_rate;
	if(stream_param.sampling_freq == 0)
		stream_param.sampling_freq = 44100; /* if frequency not yet defined, use some default */

	switch(format){
	case SNDRV_PCM_FORMAT_U8:
		stream_param.sample_type = ST_INTEGER_8;
		stream_param.sample_size = 8;
		break;
	case SNDRV_PCM_FORMAT_S16_LE:
		stream_param.sample_type = ST_INTEGER_16LE;
		stream_param.sample_size = 16;
		break;
	case SNDRV_PCM_FORMAT_S16_BE:
		stream_param.sample_type = ST_INTEGER_16BE;
		stream_param.sample_size = 16;
		break;
	case SNDRV_PCM_FORMAT_S24_3LE:
		stream_param.sample_type = ST_INTEGER_24LE;
		stream_param.sample_size = 24;
		break;
	case SNDRV_PCM_FORMAT_S24_3BE:
		stream_param.sample_type = ST_INTEGER_24BE;
		stream_param.sample_size = 24;
		break;
	case SNDRV_PCM_FORMAT_FLOAT_LE:
		stream_param.sample_type = ST_FLOATING_POINT_32LE;
		stream_param.sample_size = 32;
		break;
	case  SNDRV_PCM_FORMAT_FLOAT_BE:
		stream_param.sample_type = ST_FLOATING_POINT_32BE;
		stream_param.sample_size = 32;
		break;
	default:
		snd_printk(KERN_ERR "error mixart_set_format() : unknown format\n");
		return -EINVAL;
	}

	snd_printdd("set SNDRV_PCM_FORMAT sample_type(%d) sample_size(%d) freq(%d) channels(%d)\n",
		   stream_param.sample_type, stream_param.sample_size, stream_param.sampling_freq, stream->channels);

	/* TODO: what else to configure ? */
	/* stream_param.samples_per_frame = 2; */
	/* stream_param.bytes_per_frame = 4; */
	/* stream_param.bytes_per_sample = 2; */

	stream_param.pipe_count = 1;      /* set to 1 */
	stream_param.stream_count = 1;    /* set to 1 */
	stream_param.stream_desc[0].uid_pipe = stream->pipe->group_uid;
	stream_param.stream_desc[0].stream_idx = stream->substream->number;

	request.message_id = MSG_STREAM_SET_INPUT_STAGE_PARAM;
	request.uid = (struct mixart_uid){0,0};
	request.data = &stream_param;
	request.size = sizeof(stream_param);

	err = snd_mixart_send_msg(chip->mgr, &request, sizeof(resp), &resp);
	if((err < 0) || resp.error_code) {
		snd_printk(KERN_ERR "MSG_STREAM_SET_INPUT_STAGE_PARAM err=%x; resp=%x\n", err, resp.error_code);
		return -EINVAL;
	}
	return 0;
}


/*
 *  HW_PARAMS callback for all pcms
 */
static int snd_mixart_hw_params(struct snd_pcm_substream *subs,
                                struct snd_pcm_hw_params *hw)
{
	struct snd_mixart *chip = snd_pcm_substream_chip(subs);
	struct mixart_mgr *mgr = chip->mgr;
	struct mixart_stream *stream = subs->runtime->private_data;
	snd_pcm_format_t format;
	int err;
	int channels;

	/* set up channels */
	channels = params_channels(hw);

	/*  set up format for the stream */
	format = params_format(hw);

	mutex_lock(&mgr->setup_mutex);

	/* update the stream levels */
	if( stream->pcm_number <= MIXART_PCM_DIGITAL ) {
		int is_aes = stream->pcm_number > MIXART_PCM_ANALOG;
		if( subs->stream == SNDRV_PCM_STREAM_PLAYBACK )
			mixart_update_playback_stream_level(chip, is_aes, subs->number);
		else
			mixart_update_capture_stream_level( chip, is_aes);
	}

	stream->channels = channels;

	/* set the format to the board */
	err = mixart_set_format(stream, format);
	if(err < 0) {
		mutex_unlock(&mgr->setup_mutex);
		return err;
	}

	/* allocate buffer */
	err = snd_pcm_lib_malloc_pages(subs, params_buffer_bytes(hw));

	if (err > 0) {
		struct mixart_bufferinfo *bufferinfo;
		int i = (chip->chip_idx * MIXART_MAX_STREAM_PER_CARD) + (stream->pcm_number * (MIXART_PLAYBACK_STREAMS+MIXART_CAPTURE_STREAMS)) + subs->number;
		if( subs->stream == SNDRV_PCM_STREAM_CAPTURE ) {
			i += MIXART_PLAYBACK_STREAMS; /* in array capture is behind playback */
		}
		
		bufferinfo = (struct mixart_bufferinfo *)chip->mgr->bufferinfo.area;
		bufferinfo[i].buffer_address = subs->runtime->dma_addr;
		bufferinfo[i].available_length = subs->runtime->dma_bytes;
		/* bufferinfo[i].buffer_id  is already defined */

		snd_printdd("snd_mixart_hw_params(pcm %d) : dma_addr(%x) dma_bytes(%x) subs-number(%d)\n", i,
				bufferinfo[i].buffer_address,
				bufferinfo[i].available_length,
				subs->number);
	}
	mutex_unlock(&mgr->setup_mutex);

	return err;
}

static int snd_mixart_hw_free(struct snd_pcm_substream *subs)
{
	struct snd_mixart *chip = snd_pcm_substream_chip(subs);
	snd_pcm_lib_free_pages(subs);
	mixart_sync_nonblock_events(chip->mgr);
	return 0;
}



/*
 *  TODO CONFIGURATION SPACE for all pcms, mono pcm must update channels_max
 */
static struct snd_pcm_hardware snd_mixart_analog_caps =
{
	.info             = ( SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
			      SNDRV_PCM_INFO_MMAP_VALID |
			      SNDRV_PCM_INFO_PAUSE),
	.formats	  = ( SNDRV_PCM_FMTBIT_U8 |
			      SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
			      SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE |
			      SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE ),
	.rates            = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
	.rate_min         = 8000,
	.rate_max         = 48000,
	.channels_min     = 1,
	.channels_max     = 2,
	.buffer_bytes_max = (32*1024),
	.period_bytes_min = 256,                  /* 256 frames U8 mono*/
	.period_bytes_max = (16*1024),
	.periods_min      = 2,
	.periods_max      = (32*1024/256),
};

static struct snd_pcm_hardware snd_mixart_digital_caps =
{
	.info             = ( SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
			      SNDRV_PCM_INFO_MMAP_VALID |
			      SNDRV_PCM_INFO_PAUSE),
	.formats	  = ( SNDRV_PCM_FMTBIT_U8 |
			      SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
			      SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE |
			      SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE ),
	.rates            = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
	.rate_min         = 32000,
	.rate_max         = 48000,
	.channels_min     = 1,
	.channels_max     = 2,
	.buffer_bytes_max = (32*1024),
	.period_bytes_min = 256,                  /* 256 frames U8 mono*/
	.period_bytes_max = (16*1024),
	.periods_min      = 2,
	.periods_max      = (32*1024/256),
};


static int snd_mixart_playback_open(struct snd_pcm_substream *subs)
{
	struct snd_mixart            *chip = snd_pcm_substream_chip(subs);
	struct mixart_mgr        *mgr = chip->mgr;
	struct snd_pcm_runtime *runtime = subs->runtime;
	struct snd_pcm *pcm = subs->pcm;
	struct mixart_stream     *stream;
	struct mixart_pipe       *pipe;
	int err = 0;
	int pcm_number;

	mutex_lock(&mgr->setup_mutex);

	if ( pcm == chip->pcm ) {
		pcm_number = MIXART_PCM_ANALOG;
		runtime->hw = snd_mixart_analog_caps;
	} else {
		snd_BUG_ON(pcm != chip->pcm_dig);
		pcm_number = MIXART_PCM_DIGITAL;
		runtime->hw = snd_mixart_digital_caps;
	}
	snd_printdd("snd_mixart_playback_open C%d/P%d/Sub%d\n", chip->chip_idx, pcm_number, subs->number);

	/* get stream info */
	stream = &(chip->playback_stream[pcm_number][subs->number]);

	if (stream->status != MIXART_STREAM_STATUS_FREE){
		/* streams in use */
		snd_printk(KERN_ERR "snd_mixart_playback_open C%d/P%d/Sub%d in use\n", chip->chip_idx, pcm_number, subs->number);
		err = -EBUSY;
		goto _exit_open;
	}

	/* get pipe pointer (out pipe) */
	pipe = snd_mixart_add_ref_pipe(chip, pcm_number, 0, 0);

	if (pipe == NULL) {
		err = -EINVAL;
		goto _exit_open;
	}

	/* start the pipe if necessary */
	err = mixart_set_pipe_state(chip->mgr, pipe, 1);
	if( err < 0 ) {
		snd_printk(KERN_ERR "error starting pipe!\n");
		snd_mixart_kill_ref_pipe(chip->mgr, pipe, 0);
		err = -EINVAL;
		goto _exit_open;
	}

	stream->pipe        = pipe;
	stream->pcm_number  = pcm_number;
	stream->status      = MIXART_STREAM_STATUS_OPEN;
	stream->substream   = subs;
	stream->channels    = 0; /* not configured yet */

	runtime->private_data = stream;

	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 64);

	/* if a sample rate is already used, another stream cannot change */
	if(mgr->ref_count_rate++) {
		if(mgr->sample_rate) {
			runtime->hw.rate_min = runtime->hw.rate_max = mgr->sample_rate;
		}
	}

 _exit_open:
	mutex_unlock(&mgr->setup_mutex);

	return err;
}


static int snd_mixart_capture_open(struct snd_pcm_substream *subs)
{
	struct snd_mixart            *chip = snd_pcm_substream_chip(subs);
	struct mixart_mgr        *mgr = chip->mgr;
	struct snd_pcm_runtime *runtime = subs->runtime;
	struct snd_pcm *pcm = subs->pcm;
	struct mixart_stream     *stream;
	struct mixart_pipe       *pipe;
	int err = 0;
	int pcm_number;

	mutex_lock(&mgr->setup_mutex);

	if ( pcm == chip->pcm ) {
		pcm_number = MIXART_PCM_ANALOG;
		runtime->hw = snd_mixart_analog_caps;
	} else {
		snd_BUG_ON(pcm != chip->pcm_dig);
		pcm_number = MIXART_PCM_DIGITAL;
		runtime->hw = snd_mixart_digital_caps;
	}

	runtime->hw.channels_min = 2; /* for instance, no mono */

	snd_printdd("snd_mixart_capture_open C%d/P%d/Sub%d\n", chip->chip_idx, pcm_number, subs->number);

	/* get stream info */
	stream = &(chip->capture_stream[pcm_number]);

	if (stream->status != MIXART_STREAM_STATUS_FREE){
		/* streams in use */
		snd_printk(KERN_ERR "snd_mixart_capture_open C%d/P%d/Sub%d in use\n", chip->chip_idx, pcm_number, subs->number);
		err = -EBUSY;
		goto _exit_open;
	}

	/* get pipe pointer (in pipe) */
	pipe = snd_mixart_add_ref_pipe(chip, pcm_number, 1, 0);

	if (pipe == NULL) {
		err = -EINVAL;
		goto _exit_open;
	}

	/* start the pipe if necessary */
	err = mixart_set_pipe_state(chip->mgr, pipe, 1);
	if( err < 0 ) {
		snd_printk(KERN_ERR "error starting pipe!\n");
		snd_mixart_kill_ref_pipe(chip->mgr, pipe, 0);
		err = -EINVAL;
		goto _exit_open;
	}

	stream->pipe        = pipe;
	stream->pcm_number  = pcm_number;
	stream->status      = MIXART_STREAM_STATUS_OPEN;
	stream->substream   = subs;
	stream->channels    = 0; /* not configured yet */

	runtime->private_data = stream;

	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 64);

	/* if a sample rate is already used, another stream cannot change */
	if(mgr->ref_count_rate++) {
		if(mgr->sample_rate) {
			runtime->hw.rate_min = runtime->hw.rate_max = mgr->sample_rate;
		}
	}

 _exit_open:
	mutex_unlock(&mgr->setup_mutex);

	return err;
}



static int snd_mixart_close(struct snd_pcm_substream *subs)
{
	struct snd_mixart *chip = snd_pcm_substream_chip(subs);
	struct mixart_mgr *mgr = chip->mgr;
	struct mixart_stream *stream = subs->runtime->private_data;

	mutex_lock(&mgr->setup_mutex);

	snd_printdd("snd_mixart_close C%d/P%d/Sub%d\n", chip->chip_idx, stream->pcm_number, subs->number);

	/* sample rate released */
	if(--mgr->ref_count_rate == 0) {
		mgr->sample_rate = 0;
	}

	/* delete pipe */
	if (snd_mixart_kill_ref_pipe(mgr, stream->pipe, 0 ) < 0) {

		snd_printk(KERN_ERR "error snd_mixart_kill_ref_pipe C%dP%d\n", chip->chip_idx, stream->pcm_number);
	}

	stream->pipe      = NULL;
	stream->status    = MIXART_STREAM_STATUS_FREE;
	stream->substream = NULL;

	mutex_unlock(&mgr->setup_mutex);
	return 0;
}


static snd_pcm_uframes_t snd_mixart_stream_pointer(struct snd_pcm_substream *subs)
{
	struct snd_pcm_runtime *runtime = subs->runtime;
	struct mixart_stream   *stream  = runtime->private_data;

	return (snd_pcm_uframes_t)((stream->buf_periods * runtime->period_size) + stream->buf_period_frag);
}



static struct snd_pcm_ops snd_mixart_playback_ops = {
	.open      = snd_mixart_playback_open,
	.close     = snd_mixart_close,
	.ioctl     = snd_pcm_lib_ioctl,
	.prepare   = snd_mixart_prepare,
	.hw_params = snd_mixart_hw_params,
	.hw_free   = snd_mixart_hw_free,
	.trigger   = snd_mixart_trigger,
	.pointer   = snd_mixart_stream_pointer,
};

static struct snd_pcm_ops snd_mixart_capture_ops = {
	.open      = snd_mixart_capture_open,
	.close     = snd_mixart_close,
	.ioctl     = snd_pcm_lib_ioctl,
	.prepare   = snd_mixart_prepare,
	.hw_params = snd_mixart_hw_params,
	.hw_free   = snd_mixart_hw_free,
	.trigger   = snd_mixart_trigger,
	.pointer   = snd_mixart_stream_pointer,
};

static void preallocate_buffers(struct snd_mixart *chip, struct snd_pcm *pcm)
{
#if 0
	struct snd_pcm_substream *subs;
	int stream;

	for (stream = 0; stream < 2; stream++) {
		int idx = 0;
		for (subs = pcm->streams[stream].substream; subs; subs = subs->next, idx++)
			/* set up the unique device id with the chip index */
			subs->dma_device.id = subs->pcm->device << 16 |
				subs->stream << 8 | (subs->number + 1) |
				(chip->chip_idx + 1) << 24;
	}
#endif
	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
					      snd_dma_pci_data(chip->mgr->pci), 32*1024, 32*1024);
}

/*
 */
static int snd_mixart_pcm_analog(struct snd_mixart *chip)
{
	int err;
	struct snd_pcm *pcm;
	char name[32];

	sprintf(name, "miXart analog %d", chip->chip_idx);
	if ((err = snd_pcm_new(chip->card, name, MIXART_PCM_ANALOG,
			       MIXART_PLAYBACK_STREAMS,
			       MIXART_CAPTURE_STREAMS, &pcm)) < 0) {
		snd_printk(KERN_ERR "cannot create the analog pcm %d\n", chip->chip_idx);
		return err;
	}

	pcm->private_data = chip;

	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_mixart_playback_ops);
	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_mixart_capture_ops);

	pcm->info_flags = 0;
	strcpy(pcm->name, name);

	preallocate_buffers(chip, pcm);

	chip->pcm = pcm;
	return 0;
}


/*
 */
static int snd_mixart_pcm_digital(struct snd_mixart *chip)
{
	int err;
	struct snd_pcm *pcm;
	char name[32];

	sprintf(name, "miXart AES/EBU %d", chip->chip_idx);
	if ((err = snd_pcm_new(chip->card, name, MIXART_PCM_DIGITAL,
			       MIXART_PLAYBACK_STREAMS,
			       MIXART_CAPTURE_STREAMS, &pcm)) < 0) {
		snd_printk(KERN_ERR "cannot create the digital pcm %d\n", chip->chip_idx);
		return err;
	}

	pcm->private_data = chip;

	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_mixart_playback_ops);
	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_mixart_capture_ops);

	pcm->info_flags = 0;
	strcpy(pcm->name, name);

	preallocate_buffers(chip, pcm);

	chip->pcm_dig = pcm;
	return 0;
}

static int snd_mixart_chip_free(struct snd_mixart *chip)
{
	kfree(chip);
	return 0;
}

static int snd_mixart_chip_dev_free(struct snd_device *device)
{
	struct snd_mixart *chip = device->device_data;
	return snd_mixart_chip_free(chip);
}


/*
 */
static int __devinit snd_mixart_create(struct mixart_mgr *mgr, struct snd_card *card, int idx)
{
	int err;
	struct snd_mixart *chip;
	static struct snd_device_ops ops = {
		.dev_free = snd_mixart_chip_dev_free,
	};

	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
	if (! chip) {
		snd_printk(KERN_ERR "cannot allocate chip\n");
		return -ENOMEM;
	}

	chip->card = card;
	chip->chip_idx = idx;
	chip->mgr = mgr;

	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
		snd_mixart_chip_free(chip);
		return err;
	}

	mgr->chip[idx] = chip;
	snd_card_set_dev(card, &mgr->pci->dev);

	return 0;
}
Example #23
0
/*
 * Alsa Constructor - Component probe
 */
int tm6000_audio_init(struct tm6000_core *dev)
{
    struct snd_card		*card;
    struct snd_tm6000_card	*chip;
    int			rc;
    static int		devnr;
    char			component[14];
    struct snd_pcm		*pcm;

    if (!dev)
        return 0;

    if (devnr >= SNDRV_CARDS)
        return -ENODEV;

    if (!enable[devnr])
        return -ENOENT;

    rc = snd_card_create(index[devnr], "tm6000", THIS_MODULE, 0, &card);
    if (rc < 0) {
        snd_printk(KERN_ERR "cannot create card instance %d\n", devnr);
        return rc;
    }
    strcpy(card->driver, "tm6000-alsa");
    strcpy(card->shortname, "TM5600/60x0");
    sprintf(card->longname, "TM5600/60x0 Audio at bus %d device %d",
            dev->udev->bus->busnum, dev->udev->devnum);

    sprintf(component, "USB%04x:%04x",
            le16_to_cpu(dev->udev->descriptor.idVendor),
            le16_to_cpu(dev->udev->descriptor.idProduct));
    snd_component_add(card, component);
    snd_card_set_dev(card, &dev->udev->dev);

    chip = kzalloc(sizeof(struct snd_tm6000_card), GFP_KERNEL);
    if (!chip) {
        rc = -ENOMEM;
        goto error;
    }

    chip->core = dev;
    chip->card = card;
    dev->adev = chip;
    spin_lock_init(&chip->reg_lock);

    rc = snd_pcm_new(card, "TM6000 Audio", 0, 0, 1, &pcm);
    if (rc < 0)
        goto error_chip;

    pcm->info_flags = 0;
    pcm->private_data = chip;
    strcpy(pcm->name, "Trident TM5600/60x0");

    snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_tm6000_pcm_ops);

    INIT_WORK(&dev->wq_trigger, audio_trigger);
    rc = snd_card_register(card);
    if (rc < 0)
        goto error_chip;

    dprintk(1,"Registered audio driver for %s\n", card->longname);

    return 0;

error_chip:
    kfree(chip);
    dev->adev = NULL;
error:
    snd_card_free(card);
    return rc;
}
static int mixart_set_pipe_state(struct mixart_mgr *mgr,
				 struct mixart_pipe *pipe, int start)
{
	struct mixart_group_state_req group_state;
	struct mixart_group_state_resp group_state_resp;
	struct mixart_msg request;
	int err;
	u32 system_msg_uid;

	switch(pipe->status) {
	case PIPE_RUNNING:
	case PIPE_CLOCK_SET:
		if(start) return 0; /* already started */
		break;
	case PIPE_STOPPED:
		if(!start) return 0; /* already stopped */
		break;
	default:
		snd_printk(KERN_ERR "error mixart_set_pipe_state called with wrong pipe->status!\n");
		return -EINVAL;      /* function called with wrong pipe status */
	}

	system_msg_uid = 0x12345678; /* the event ! (take care: the MSB and two LSB's have to be 0) */

	/* wait on the last MSG_SYSTEM_SEND_SYNCHRO_CMD command to be really finished */

	request.message_id = MSG_SYSTEM_WAIT_SYNCHRO_CMD;
	request.uid = (struct mixart_uid){0,0};
	request.data = &system_msg_uid;
	request.size = sizeof(system_msg_uid);

	err = snd_mixart_send_msg_wait_notif(mgr, &request, system_msg_uid);
	if(err) {
		snd_printk(KERN_ERR "error : MSG_SYSTEM_WAIT_SYNCHRO_CMD was not notified !\n");
		return err;
	}

	/* start or stop the pipe (1 pipe) */

	memset(&group_state, 0, sizeof(group_state));
	group_state.pipe_count = 1;
	group_state.pipe_uid[0] = pipe->group_uid;

	if(start)
		request.message_id = MSG_STREAM_START_STREAM_GRP_PACKET;
	else
		request.message_id = MSG_STREAM_STOP_STREAM_GRP_PACKET;

	request.uid = pipe->group_uid; /*(struct mixart_uid){0,0};*/
	request.data = &group_state;
	request.size = sizeof(group_state);

	err = snd_mixart_send_msg(mgr, &request, sizeof(group_state_resp), &group_state_resp);
	if (err < 0 || group_state_resp.txx_status != 0) {
		snd_printk(KERN_ERR "error MSG_STREAM_ST***_STREAM_GRP_PACKET err=%x stat=%x !\n", err, group_state_resp.txx_status);
		return -EINVAL;
	}

	if(start) {
		u32 stat;

		group_state.pipe_count = 0; /* in case of start same command once again with pipe_count=0 */

		err = snd_mixart_send_msg(mgr, &request, sizeof(group_state_resp), &group_state_resp);
		if (err < 0 || group_state_resp.txx_status != 0) {
			snd_printk(KERN_ERR "error MSG_STREAM_START_STREAM_GRP_PACKET err=%x stat=%x !\n", err, group_state_resp.txx_status);
 			return -EINVAL;
		}

		/* in case of start send a synchro top */

		request.message_id = MSG_SYSTEM_SEND_SYNCHRO_CMD;
		request.uid = (struct mixart_uid){0,0};
		request.data = NULL;
		request.size = 0;

		err = snd_mixart_send_msg(mgr, &request, sizeof(stat), &stat);
		if (err < 0 || stat != 0) {
			snd_printk(KERN_ERR "error MSG_SYSTEM_SEND_SYNCHRO_CMD err=%x stat=%x !\n", err, stat);
			return -EINVAL;
		}

		pipe->status = PIPE_RUNNING;
	}
	else /* !start */
		pipe->status = PIPE_STOPPED;

	return 0;
}


static int mixart_set_clock(struct mixart_mgr *mgr,
			    struct mixart_pipe *pipe, unsigned int rate)
{
	struct mixart_msg request;
	struct mixart_clock_properties clock_properties;
	struct mixart_clock_properties_resp clock_prop_resp;
	int err;

	switch(pipe->status) {
	case PIPE_CLOCK_SET:
		break;
	case PIPE_RUNNING:
		if(rate != 0)
			break;
	default:
		if(rate == 0)
			return 0; /* nothing to do */
		else {
			snd_printk(KERN_ERR "error mixart_set_clock(%d) called with wrong pipe->status !\n", rate);
			return -EINVAL;
		}
	}

	memset(&clock_properties, 0, sizeof(clock_properties));
	clock_properties.clock_generic_type = (rate != 0) ? CGT_INTERNAL_CLOCK : CGT_NO_CLOCK;
	clock_properties.clock_mode = CM_STANDALONE;
	clock_properties.frequency = rate;
	clock_properties.nb_callers = 1; /* only one entry in uid_caller ! */
	clock_properties.uid_caller[0] = pipe->group_uid;

	snd_printdd("mixart_set_clock to %d kHz\n", rate);

	request.message_id = MSG_CLOCK_SET_PROPERTIES;
	request.uid = mgr->uid_console_manager;
	request.data = &clock_properties;
	request.size = sizeof(clock_properties);

	err = snd_mixart_send_msg(mgr, &request, sizeof(clock_prop_resp), &clock_prop_resp);
	if (err < 0 || clock_prop_resp.status != 0 || clock_prop_resp.clock_mode != CM_STANDALONE) {
		snd_printk(KERN_ERR "error MSG_CLOCK_SET_PROPERTIES err=%x stat=%x mod=%x !\n", err, clock_prop_resp.status, clock_prop_resp.clock_mode);
		return -EINVAL;
	}

	if(rate)  pipe->status = PIPE_CLOCK_SET;
	else      pipe->status = PIPE_RUNNING;

	return 0;
}


/*
 *  Allocate or reference output pipe for analog IOs (pcmp0/1)
 */
struct mixart_pipe *
snd_mixart_add_ref_pipe(struct snd_mixart *chip, int pcm_number, int capture,
			int monitoring)
{
	int stream_count;
	struct mixart_pipe *pipe;
	struct mixart_msg request;

	if(capture) {
		if (pcm_number == MIXART_PCM_ANALOG) {
			pipe = &(chip->pipe_in_ana);  /* analog inputs */
		} else {
			pipe = &(chip->pipe_in_dig); /* digital inputs */
		}
		request.message_id = MSG_STREAM_ADD_OUTPUT_GROUP;
		stream_count = MIXART_CAPTURE_STREAMS;
	} else {
		if (pcm_number == MIXART_PCM_ANALOG) {
			pipe = &(chip->pipe_out_ana);  /* analog outputs */
		} else {
			pipe = &(chip->pipe_out_dig);  /* digital outputs */
		}
		request.message_id = MSG_STREAM_ADD_INPUT_GROUP;
		stream_count = MIXART_PLAYBACK_STREAMS;
	}

	/* a new stream is opened and there are already all streams in use */
	if( (monitoring == 0) && (pipe->references >= stream_count) ) {
		return NULL;
	}

	/* pipe is not yet defined */
	if( pipe->status == PIPE_UNDEFINED ) {
		int err, i;
		struct {
			struct mixart_streaming_group_req sgroup_req;
			struct mixart_streaming_group sgroup_resp;
		} *buf;

		snd_printdd("add_ref_pipe audio chip(%d) pcm(%d)\n", chip->chip_idx, pcm_number);

		buf = kmalloc(sizeof(*buf), GFP_KERNEL);
		if (!buf)
			return NULL;

		request.uid = (struct mixart_uid){0,0};      /* should be StreamManagerUID, but zero is OK if there is only one ! */
		request.data = &buf->sgroup_req;
		request.size = sizeof(buf->sgroup_req);

		memset(&buf->sgroup_req, 0, sizeof(buf->sgroup_req));

		buf->sgroup_req.stream_count = stream_count;
		buf->sgroup_req.channel_count = 2;
		buf->sgroup_req.latency = 256;
		buf->sgroup_req.connector = pipe->uid_left_connector;  /* the left connector */

		for (i=0; i<stream_count; i++) {
			int j;
			struct mixart_flowinfo *flowinfo;
			struct mixart_bufferinfo *bufferinfo;
			
			/* we don't yet know the format, so config 16 bit pcm audio for instance */
			buf->sgroup_req.stream_info[i].size_max_byte_frame = 1024;
			buf->sgroup_req.stream_info[i].size_max_sample_frame = 256;
			buf->sgroup_req.stream_info[i].nb_bytes_max_per_sample = MIXART_FLOAT_P__4_0_TO_HEX; /* is 4.0f */

			/* find the right bufferinfo_array */
			j = (chip->chip_idx * MIXART_MAX_STREAM_PER_CARD) + (pcm_number * (MIXART_PLAYBACK_STREAMS + MIXART_CAPTURE_STREAMS)) + i;
			if(capture) j += MIXART_PLAYBACK_STREAMS; /* in the array capture is behind playback */

			buf->sgroup_req.flow_entry[i] = j;

			flowinfo = (struct mixart_flowinfo *)chip->mgr->flowinfo.area;
			flowinfo[j].bufferinfo_array_phy_address = (u32)chip->mgr->bufferinfo.addr + (j * sizeof(struct mixart_bufferinfo));
			flowinfo[j].bufferinfo_count = 1;               /* 1 will set the miXart to ring-buffer mode ! */

			bufferinfo = (struct mixart_bufferinfo *)chip->mgr->bufferinfo.area;
			bufferinfo[j].buffer_address = 0;               /* buffer is not yet allocated */
			bufferinfo[j].available_length = 0;             /* buffer is not yet allocated */

			/* construct the identifier of the stream buffer received in the interrupts ! */
			bufferinfo[j].buffer_id = (chip->chip_idx << MIXART_NOTIFY_CARD_OFFSET) + (pcm_number << MIXART_NOTIFY_PCM_OFFSET ) + i;
			if(capture) {
				bufferinfo[j].buffer_id |= MIXART_NOTIFY_CAPT_MASK;
			}
		}

		err = snd_mixart_send_msg(chip->mgr, &request, sizeof(buf->sgroup_resp), &buf->sgroup_resp);
		if((err < 0) || (buf->sgroup_resp.status != 0)) {
			snd_printk(KERN_ERR "error MSG_STREAM_ADD_**PUT_GROUP err=%x stat=%x !\n", err, buf->sgroup_resp.status);
			kfree(buf);
			return NULL;
		}

		pipe->group_uid = buf->sgroup_resp.group;     /* id of the pipe, as returned by embedded */
		pipe->stream_count = buf->sgroup_resp.stream_count;
		/* pipe->stream_uid[i] = buf->sgroup_resp.stream[i].stream_uid; */

		pipe->status = PIPE_STOPPED;
		kfree(buf);
	}

	if(monitoring)	pipe->monitoring = 1;
	else		pipe->references++;

	return pipe;
}
Example #25
0
// constructor -- see "Constructor" sub-section
static int __devinit
snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
{
	static int dev;
	struct snd_card *card;
	vortex_t *chip;
	int err;

	// (1)
	if (dev >= SNDRV_CARDS)
		return -ENODEV;
	if (!enable[dev]) {
		dev++;
		return -ENOENT;
	}
	// (2)
	err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
	if (err < 0)
		return err;

	// (3)
	if ((err = snd_vortex_create(card, pci, &chip)) < 0) {
		snd_card_free(card);
		return err;
	}
	snd_vortex_workaround(pci, pcifix[dev]);

	// Card details needed in snd_vortex_midi
	strcpy(card->driver, CARD_NAME_SHORT);
	sprintf(card->shortname, "Aureal Vortex %s", CARD_NAME_SHORT);
	sprintf(card->longname, "%s at 0x%lx irq %i",
		card->shortname, chip->io, chip->irq);

	// (4) Alloc components.
	// ADB pcm.
	if ((err = snd_vortex_new_pcm(chip, VORTEX_PCM_ADB, NR_ADB)) < 0) {
		snd_card_free(card);
		return err;
	}
#ifndef CHIP_AU8820
	// ADB SPDIF
	if ((err = snd_vortex_new_pcm(chip, VORTEX_PCM_SPDIF, 1)) < 0) {
		snd_card_free(card);
		return err;
	}
	// A3D
	if ((err = snd_vortex_new_pcm(chip, VORTEX_PCM_A3D, NR_A3D)) < 0) {
		snd_card_free(card);
		return err;
	}
#endif
	/*
	   // ADB I2S
	   if ((err = snd_vortex_new_pcm(chip, VORTEX_PCM_I2S, 1)) < 0) {
	   snd_card_free(card);
	   return err;
	   }
	 */
#ifndef CHIP_AU8810
	// WT pcm.
	if ((err = snd_vortex_new_pcm(chip, VORTEX_PCM_WT, NR_WT)) < 0) {
		snd_card_free(card);
		return err;
	}
#endif
	// snd_ac97_mixer and Vortex mixer.
	if ((err = snd_vortex_mixer(chip)) < 0) {
		snd_card_free(card);
		return err;
	}
	if ((err = snd_vortex_midi(chip)) < 0) {
		snd_card_free(card);
		return err;
	}

	vortex_gameport_register(chip);

#if 0
	if (snd_seq_device_new(card, 1, SNDRV_SEQ_DEV_ID_VORTEX_SYNTH,
			       sizeof(snd_vortex_synth_arg_t), &wave) < 0
	    || wave == NULL) {
		snd_printk(KERN_ERR "Can't initialize Aureal wavetable synth\n");
	} else {
		snd_vortex_synth_arg_t *arg;

		arg = SNDRV_SEQ_DEVICE_ARGPTR(wave);
		strcpy(wave->name, "Aureal Synth");
		arg->hwptr = vortex;
		arg->index = 1;
		arg->seq_ports = seq_ports[dev];
		arg->max_voices = max_synth_voices[dev];
	}
#endif

	// (5)
	if ((err = pci_read_config_word(pci, PCI_DEVICE_ID,
				  &(chip->device))) < 0) {
		snd_card_free(card);
		return err;
	}	
	if ((err = pci_read_config_word(pci, PCI_VENDOR_ID,
				  &(chip->vendor))) < 0) {
		snd_card_free(card);
		return err;
	}
	chip->rev = pci->revision;
#ifdef CHIP_AU8830
	if ((chip->rev) != 0xfe && (chip->rev) != 0xfa) {
		printk(KERN_ALERT
		       "vortex: The revision (%x) of your card has not been seen before.\n",
		       chip->rev);
		printk(KERN_ALERT
		       "vortex: Please email the results of 'lspci -vv' to [email protected]\n");
		snd_card_free(card);
		err = -ENODEV;
		return err;
	}
#endif

	// (6)
	if ((err = snd_card_register(card)) < 0) {
		snd_card_free(card);
		return err;
	}
	// (7)
	pci_set_drvdata(pci, card);
	dev++;
	vortex_connect_default(chip, 1);
	vortex_enable_int(chip);
	return 0;
}
Example #26
0
/*
 * vx_load_xilinx_binary - load the xilinx binary image
 * the binary image is the binary array converted from the bitstream file.
 */
static int vxp_load_xilinx_binary(struct vx_core *_chip, const struct firmware *fw)
{
	struct snd_vxpocket *chip = to_vxpocket(_chip);
	unsigned int i;
	int c;
	int regCSUER, regRUER;
	const unsigned char *image;
	unsigned char data;

	/* Switch to programmation mode */
	chip->regDIALOG |= VXP_DLG_XILINX_REPROG_MASK;
	vx_outb(chip, DIALOG, chip->regDIALOG);

	/* Save register CSUER and RUER */
	regCSUER = vx_inb(chip, CSUER);
	regRUER = vx_inb(chip, RUER);

	/* reset HF0 and HF1 */
	vx_outb(chip, ICR, 0);

	/* Wait for answer HF2 equal to 1 */
	snd_printdd(KERN_DEBUG "check ISR_HF2\n");
	if (vx_check_isr(_chip, ISR_HF2, ISR_HF2, 20) < 0)
		goto _error;

	/* set HF1 for loading xilinx binary */
	vx_outb(chip, ICR, ICR_HF1);
	image = fw->data;
	for (i = 0; i < fw->size; i++, image++) {
		data = *image;
		if (vx_wait_isr_bit(_chip, ISR_TX_EMPTY) < 0)
			goto _error;
		vx_outb(chip, TXL, data);
		/* wait for reading */
		if (vx_wait_for_rx_full(_chip) < 0)
			goto _error;
		c = vx_inb(chip, RXL);
		if (c != (int)data)
			snd_printk(KERN_ERR "vxpocket: load xilinx mismatch at %d: 0x%x != 0x%x\n", i, c, (int)data);
        }

	/* reset HF1 */
	vx_outb(chip, ICR, 0);

	/* wait for HF3 */
	if (vx_check_isr(_chip, ISR_HF3, ISR_HF3, 20) < 0)
		goto _error;

	/* read the number of bytes received */
	if (vx_wait_for_rx_full(_chip) < 0)
		goto _error;

	c = (int)vx_inb(chip, RXH) << 16;
	c |= (int)vx_inb(chip, RXM) << 8;
	c |= vx_inb(chip, RXL);

	snd_printdd(KERN_DEBUG "xilinx: dsp size received 0x%x, orig 0x%zx\n", c, fw->size);

	vx_outb(chip, ICR, ICR_HF0);

	/* TEMPO 250ms : wait until Xilinx is downloaded */
	msleep(300);

	/* test magical word */
	if (vx_check_magic(_chip) < 0)
		goto _error;

	/* Restore register 0x0E and 0x0F (thus replacing COR and FCSR) */
	vx_outb(chip, CSUER, regCSUER);
	vx_outb(chip, RUER, regRUER);

	/* Reset the Xilinx's signal enabling IO access */
	chip->regDIALOG |= VXP_DLG_XILINX_REPROG_MASK;
	vx_outb(chip, DIALOG, chip->regDIALOG);
	vx_inb(chip, DIALOG);
	msleep(10);
	chip->regDIALOG &= ~VXP_DLG_XILINX_REPROG_MASK;
	vx_outb(chip, DIALOG, chip->regDIALOG);
	vx_inb(chip, DIALOG);

	/* Reset of the Codec */
	vxp_reset_codec(_chip);
	vx_reset_dsp(_chip);

	return 0;

 _error:
	vx_outb(chip, CSUER, regCSUER);
	vx_outb(chip, RUER, regRUER);
	chip->regDIALOG &= ~VXP_DLG_XILINX_REPROG_MASK;
	vx_outb(chip, DIALOG, chip->regDIALOG);
	return -EIO;
}
Example #27
0
static int __devinit snd_card_emu10k1_probe(struct pci_dev *pci,
					    const struct pci_device_id *pci_id)
{
	static int dev;
	struct snd_card *card;
	struct snd_emu10k1 *emu;
#ifdef ENABLE_SYNTH
	struct snd_seq_device *wave = NULL;
#endif
	int err;

	if (dev >= SNDRV_CARDS)
        	return -ENODEV;
	if (!enable[dev]) {
		dev++;
		return -ENOENT;
	}

	card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
	if (card == NULL)
		return -ENOMEM;
	if (max_buffer_size[dev] < 32)
		max_buffer_size[dev] = 32;
	else if (max_buffer_size[dev] > 1024)
		max_buffer_size[dev] = 1024;
	if ((err = snd_emu10k1_create(card, pci, extin[dev], extout[dev],
				      (long)max_buffer_size[dev] * 1024 * 1024,
				      enable_ir[dev], subsystem[dev],
				      &emu)) < 0)
		goto error;
	card->private_data = emu;
	if ((err = snd_emu10k1_pcm(emu, 0, NULL)) < 0)
		goto error;
	if ((err = snd_emu10k1_pcm_mic(emu, 1, NULL)) < 0)
		goto error;
	if ((err = snd_emu10k1_pcm_efx(emu, 2, NULL)) < 0)
		goto error;
	/* This stores the periods table. */
	if (emu->card_capabilities->ca0151_chip) { /* P16V */	
		if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
					       1024, &emu->p16v_buffer)) < 0)
			goto error;
	}

	if ((err = snd_emu10k1_mixer(emu, 0, 3)) < 0)
		goto error;
	
	if ((err = snd_emu10k1_timer(emu, 0)) < 0)
		goto error;

	if ((err = snd_emu10k1_pcm_multi(emu, 3, NULL)) < 0)
		goto error;
	if (emu->card_capabilities->ca0151_chip) { /* P16V */
		if ((err = snd_p16v_pcm(emu, 4, NULL)) < 0)
			goto error;
	}
	if (emu->audigy) {
		if ((err = snd_emu10k1_audigy_midi(emu)) < 0)
			goto error;
	} else {
		if ((err = snd_emu10k1_midi(emu)) < 0)
			goto error;
	}
	if ((err = snd_emu10k1_fx8010_new(emu, 0, NULL)) < 0)
		goto error;
#ifdef ENABLE_SYNTH
	if (snd_seq_device_new(card, 1, SNDRV_SEQ_DEV_ID_EMU10K1_SYNTH,
			       sizeof(struct snd_emu10k1_synth_arg), &wave) < 0 ||
	    wave == NULL) {
		snd_printk(KERN_WARNING "can't initialize Emu10k1 wavetable synth\n");
	} else {
		struct snd_emu10k1_synth_arg *arg;
		arg = SNDRV_SEQ_DEVICE_ARGPTR(wave);
		strcpy(wave->name, "Emu-10k1 Synth");
		arg->hwptr = emu;
		arg->index = 1;
		arg->seq_ports = seq_ports[dev];
		arg->max_voices = max_synth_voices[dev];
	}
#endif
 
	strcpy(card->driver, emu->card_capabilities->driver);
	strcpy(card->shortname, emu->card_capabilities->name);
	snprintf(card->longname, sizeof(card->longname),
		 "%s (rev.%d, serial:0x%x) at 0x%lx, irq %i",
		 card->shortname, emu->revision, emu->serial, emu->port, emu->irq);

	if ((err = snd_card_register(card)) < 0)
		goto error;

	pci_set_drvdata(pci, card);
	dev++;
	return 0;

 error:
	snd_card_free(card);
	return err;
}
Example #28
0
static int snd_atiixp_pcm_open(struct snd_pcm_substream *substream,
			       struct atiixp_dma *dma, int pcm_type)
{
	struct atiixp_modem *chip = snd_pcm_substream_chip(substream);
	struct snd_pcm_runtime *runtime = substream->runtime;
	int err;
	static unsigned int rates[] = { 8000,  9600, 12000, 16000 };
	static struct snd_pcm_hw_constraint_list hw_constraints_rates = {
		.count = ARRAY_SIZE(rates),
		.list = rates,
		.mask = 0,
	};

	if (snd_BUG_ON(!dma->ops || !dma->ops->enable_dma))
		return -EINVAL;

	if (dma->opened)
		return -EBUSY;
	dma->substream = substream;
	runtime->hw = snd_atiixp_pcm_hw;
	dma->ac97_pcm_type = pcm_type;
	if ((err = snd_pcm_hw_constraint_list(runtime, 0,
					      SNDRV_PCM_HW_PARAM_RATE,
					      &hw_constraints_rates)) < 0)
		return err;
	if ((err = snd_pcm_hw_constraint_integer(runtime,
						 SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
		return err;
	runtime->private_data = dma;

	/* enable DMA bits */
	spin_lock_irq(&chip->reg_lock);
	dma->ops->enable_dma(chip, 1);
	spin_unlock_irq(&chip->reg_lock);
	dma->opened = 1;

	return 0;
}

static int snd_atiixp_pcm_close(struct snd_pcm_substream *substream,
				struct atiixp_dma *dma)
{
	struct atiixp_modem *chip = snd_pcm_substream_chip(substream);
	/* disable DMA bits */
	if (snd_BUG_ON(!dma->ops || !dma->ops->enable_dma))
		return -EINVAL;
	spin_lock_irq(&chip->reg_lock);
	dma->ops->enable_dma(chip, 0);
	spin_unlock_irq(&chip->reg_lock);
	dma->substream = NULL;
	dma->opened = 0;
	return 0;
}

/*
 */
static int snd_atiixp_playback_open(struct snd_pcm_substream *substream)
{
	struct atiixp_modem *chip = snd_pcm_substream_chip(substream);
	int err;

	mutex_lock(&chip->open_mutex);
	err = snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_PLAYBACK], 0);
	mutex_unlock(&chip->open_mutex);
	if (err < 0)
		return err;
	return 0;
}

static int snd_atiixp_playback_close(struct snd_pcm_substream *substream)
{
	struct atiixp_modem *chip = snd_pcm_substream_chip(substream);
	int err;
	mutex_lock(&chip->open_mutex);
	err = snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_PLAYBACK]);
	mutex_unlock(&chip->open_mutex);
	return err;
}

static int snd_atiixp_capture_open(struct snd_pcm_substream *substream)
{
	struct atiixp_modem *chip = snd_pcm_substream_chip(substream);
	return snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_CAPTURE], 1);
}

static int snd_atiixp_capture_close(struct snd_pcm_substream *substream)
{
	struct atiixp_modem *chip = snd_pcm_substream_chip(substream);
	return snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_CAPTURE]);
}


/* AC97 playback */
static struct snd_pcm_ops snd_atiixp_playback_ops = {
	.open =		snd_atiixp_playback_open,
	.close =	snd_atiixp_playback_close,
	.ioctl =	snd_pcm_lib_ioctl,
	.hw_params =	snd_atiixp_pcm_hw_params,
	.hw_free =	snd_atiixp_pcm_hw_free,
	.prepare =	snd_atiixp_playback_prepare,
	.trigger =	snd_atiixp_pcm_trigger,
	.pointer =	snd_atiixp_pcm_pointer,
};

/* AC97 capture */
static struct snd_pcm_ops snd_atiixp_capture_ops = {
	.open =		snd_atiixp_capture_open,
	.close =	snd_atiixp_capture_close,
	.ioctl =	snd_pcm_lib_ioctl,
	.hw_params =	snd_atiixp_pcm_hw_params,
	.hw_free =	snd_atiixp_pcm_hw_free,
	.prepare =	snd_atiixp_capture_prepare,
	.trigger =	snd_atiixp_pcm_trigger,
	.pointer =	snd_atiixp_pcm_pointer,
};

static struct atiixp_dma_ops snd_atiixp_playback_dma_ops = {
	.type = ATI_DMA_PLAYBACK,
	.llp_offset = ATI_REG_MODEM_OUT_DMA1_LINKPTR,
	.dt_cur = ATI_REG_MODEM_OUT_DMA1_DT_CUR,
	.enable_dma = atiixp_out_enable_dma,
	.enable_transfer = atiixp_out_enable_transfer,
	.flush_dma = atiixp_out_flush_dma,
};
	
static struct atiixp_dma_ops snd_atiixp_capture_dma_ops = {
	.type = ATI_DMA_CAPTURE,
	.llp_offset = ATI_REG_MODEM_IN_DMA_LINKPTR,
	.dt_cur = ATI_REG_MODEM_IN_DMA_DT_CUR,
	.enable_dma = atiixp_in_enable_dma,
	.enable_transfer = atiixp_in_enable_transfer,
	.flush_dma = atiixp_in_flush_dma,
};

static int __devinit snd_atiixp_pcm_new(struct atiixp_modem *chip)
{
	struct snd_pcm *pcm;
	int err;

	/* initialize constants */
	chip->dmas[ATI_DMA_PLAYBACK].ops = &snd_atiixp_playback_dma_ops;
	chip->dmas[ATI_DMA_CAPTURE].ops = &snd_atiixp_capture_dma_ops;

	/* PCM #0: analog I/O */
	err = snd_pcm_new(chip->card, "ATI IXP MC97", ATI_PCMDEV_ANALOG, 1, 1, &pcm);
	if (err < 0)
		return err;
	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_atiixp_playback_ops);
	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_atiixp_capture_ops);
	pcm->dev_class = SNDRV_PCM_CLASS_MODEM;
	pcm->private_data = chip;
	strcpy(pcm->name, "ATI IXP MC97");
	chip->pcmdevs[ATI_PCMDEV_ANALOG] = pcm;

	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
					      snd_dma_pci_data(chip->pci),
					      64*1024, 128*1024);

	return 0;
}



/*
 * interrupt handler
 */
static irqreturn_t snd_atiixp_interrupt(int irq, void *dev_id)
{
	struct atiixp_modem *chip = dev_id;
	unsigned int status;

	status = atiixp_read(chip, ISR);

	if (! status)
		return IRQ_NONE;

	/* process audio DMA */
	if (status & ATI_REG_ISR_MODEM_OUT1_XRUN)
		snd_atiixp_xrun_dma(chip,  &chip->dmas[ATI_DMA_PLAYBACK]);
	else if (status & ATI_REG_ISR_MODEM_OUT1_STATUS)
		snd_atiixp_update_dma(chip, &chip->dmas[ATI_DMA_PLAYBACK]);
	if (status & ATI_REG_ISR_MODEM_IN_XRUN)
		snd_atiixp_xrun_dma(chip,  &chip->dmas[ATI_DMA_CAPTURE]);
	else if (status & ATI_REG_ISR_MODEM_IN_STATUS)
		snd_atiixp_update_dma(chip, &chip->dmas[ATI_DMA_CAPTURE]);

	/* for codec detection */
	if (status & CODEC_CHECK_BITS) {
		unsigned int detected;
		detected = status & CODEC_CHECK_BITS;
		spin_lock(&chip->reg_lock);
		chip->codec_not_ready_bits |= detected;
		atiixp_update(chip, IER, detected, 0); /* disable the detected irqs */
		spin_unlock(&chip->reg_lock);
	}

	/* ack */
	atiixp_write(chip, ISR, status);

	return IRQ_HANDLED;
}


/*
 * ac97 mixer section
 */

static int __devinit snd_atiixp_mixer_new(struct atiixp_modem *chip, int clock)
{
	struct snd_ac97_bus *pbus;
	struct snd_ac97_template ac97;
	int i, err;
	int codec_count;
	static struct snd_ac97_bus_ops ops = {
		.write = snd_atiixp_ac97_write,
		.read = snd_atiixp_ac97_read,
	};
	static unsigned int codec_skip[NUM_ATI_CODECS] = {
		ATI_REG_ISR_CODEC0_NOT_READY,
		ATI_REG_ISR_CODEC1_NOT_READY,
		ATI_REG_ISR_CODEC2_NOT_READY,
	};

	if (snd_atiixp_codec_detect(chip) < 0)
		return -ENXIO;

	if ((err = snd_ac97_bus(chip->card, 0, &ops, chip, &pbus)) < 0)
		return err;
	pbus->clock = clock;
	chip->ac97_bus = pbus;

	codec_count = 0;
	for (i = 0; i < NUM_ATI_CODECS; i++) {
		if (chip->codec_not_ready_bits & codec_skip[i])
			continue;
		memset(&ac97, 0, sizeof(ac97));
		ac97.private_data = chip;
		ac97.pci = chip->pci;
		ac97.num = i;
		ac97.scaps = AC97_SCAP_SKIP_AUDIO | AC97_SCAP_POWER_SAVE;
		if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0) {
			chip->ac97[i] = NULL; /* to be sure */
			snd_printdd("atiixp-modem: codec %d not available for modem\n", i);
			continue;
		}
		codec_count++;
	}

	if (! codec_count) {
		snd_printk(KERN_ERR "atiixp-modem: no codec available\n");
		return -ENODEV;
	}

	/* snd_ac97_tune_hardware(chip->ac97, ac97_quirks); */

	return 0;
}


#ifdef CONFIG_PM
/*
 * power management
 */
static int snd_atiixp_suspend(struct pci_dev *pci, pm_message_t state)
{
	struct snd_card *card = pci_get_drvdata(pci);
	struct atiixp_modem *chip = card->private_data;
	int i;

	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
	for (i = 0; i < NUM_ATI_PCMDEVS; i++)
		snd_pcm_suspend_all(chip->pcmdevs[i]);
	for (i = 0; i < NUM_ATI_CODECS; i++)
		snd_ac97_suspend(chip->ac97[i]);
	snd_atiixp_aclink_down(chip);
	snd_atiixp_chip_stop(chip);

	pci_disable_device(pci);
	pci_save_state(pci);
	pci_set_power_state(pci, pci_choose_state(pci, state));
	return 0;
}

static int snd_atiixp_resume(struct pci_dev *pci)
{
	struct snd_card *card = pci_get_drvdata(pci);
	struct atiixp_modem *chip = card->private_data;
	int i;

	pci_set_power_state(pci, PCI_D0);
	pci_restore_state(pci);
	if (pci_enable_device(pci) < 0) {
		printk(KERN_ERR "atiixp-modem: pci_enable_device failed, "
		       "disabling device\n");
		snd_card_disconnect(card);
		return -EIO;
	}
	pci_set_master(pci);

	snd_atiixp_aclink_reset(chip);
	snd_atiixp_chip_start(chip);

	for (i = 0; i < NUM_ATI_CODECS; i++)
		snd_ac97_resume(chip->ac97[i]);

	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
	return 0;
}
#endif /* CONFIG_PM */


#ifdef CONFIG_PROC_FS
/*
 * proc interface for register dump
 */

static void snd_atiixp_proc_read(struct snd_info_entry *entry,
				 struct snd_info_buffer *buffer)
{
	struct atiixp_modem *chip = entry->private_data;
	int i;

	for (i = 0; i < 256; i += 4)
		snd_iprintf(buffer, "%02x: %08x\n", i, readl(chip->remap_addr + i));
}

static void __devinit snd_atiixp_proc_init(struct atiixp_modem *chip)
{
	struct snd_info_entry *entry;

	if (! snd_card_proc_new(chip->card, "atiixp-modem", &entry))
		snd_info_set_text_ops(entry, chip, snd_atiixp_proc_read);
}
#else
#define snd_atiixp_proc_init(chip)
#endif


/*
 * destructor
 */

static int snd_atiixp_free(struct atiixp_modem *chip)
{
	if (chip->irq < 0)
		goto __hw_end;
	snd_atiixp_chip_stop(chip);

      __hw_end:
	if (chip->irq >= 0)
		free_irq(chip->irq, chip);
	if (chip->remap_addr)
		iounmap(chip->remap_addr);
	pci_release_regions(chip->pci);
	pci_disable_device(chip->pci);
	kfree(chip);
	return 0;
}

static int snd_atiixp_dev_free(struct snd_device *device)
{
	struct atiixp_modem *chip = device->device_data;
	return snd_atiixp_free(chip);
}

/*
 * constructor for chip instance
 */
static int __devinit snd_atiixp_create(struct snd_card *card,
				       struct pci_dev *pci,
				       struct atiixp_modem **r_chip)
{
	static struct snd_device_ops ops = {
		.dev_free =	snd_atiixp_dev_free,
	};
	struct atiixp_modem *chip;
	int err;

	if ((err = pci_enable_device(pci)) < 0)
		return err;

	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
	if (chip == NULL) {
		pci_disable_device(pci);
		return -ENOMEM;
	}

	spin_lock_init(&chip->reg_lock);
	mutex_init(&chip->open_mutex);
	chip->card = card;
	chip->pci = pci;
	chip->irq = -1;
	if ((err = pci_request_regions(pci, "ATI IXP MC97")) < 0) {
		kfree(chip);
		pci_disable_device(pci);
		return err;
	}
	chip->addr = pci_resource_start(pci, 0);
	chip->remap_addr = pci_ioremap_bar(pci, 0);
	if (chip->remap_addr == NULL) {
		snd_printk(KERN_ERR "AC'97 space ioremap problem\n");
		snd_atiixp_free(chip);
		return -EIO;
	}

	if (request_irq(pci->irq, snd_atiixp_interrupt, IRQF_SHARED,
			KBUILD_MODNAME, chip)) {
		snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);
		snd_atiixp_free(chip);
		return -EBUSY;
	}
	chip->irq = pci->irq;
	pci_set_master(pci);
	synchronize_irq(chip->irq);

	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
		snd_atiixp_free(chip);
		return err;
	}

	snd_card_set_dev(card, &pci->dev);

	*r_chip = chip;
	return 0;
}


static int __devinit snd_atiixp_probe(struct pci_dev *pci,
				      const struct pci_device_id *pci_id)
{
	struct snd_card *card;
	struct atiixp_modem *chip;
	int err;

	err = snd_card_create(index, id, THIS_MODULE, 0, &card);
	if (err < 0)
		return err;

	strcpy(card->driver, "ATIIXP-MODEM");
	strcpy(card->shortname, "ATI IXP Modem");
	if ((err = snd_atiixp_create(card, pci, &chip)) < 0)
		goto __error;
	card->private_data = chip;

	if ((err = snd_atiixp_aclink_reset(chip)) < 0)
		goto __error;

	if ((err = snd_atiixp_mixer_new(chip, ac97_clock)) < 0)
		goto __error;

	if ((err = snd_atiixp_pcm_new(chip)) < 0)
		goto __error;
	
	snd_atiixp_proc_init(chip);

	snd_atiixp_chip_start(chip);

	sprintf(card->longname, "%s rev %x at 0x%lx, irq %i",
		card->shortname, pci->revision, chip->addr, chip->irq);

	if ((err = snd_card_register(card)) < 0)
		goto __error;

	pci_set_drvdata(pci, card);
	return 0;

 __error:
	snd_card_free(card);
	return err;
}

static void __devexit snd_atiixp_remove(struct pci_dev *pci)
{
	snd_card_free(pci_get_drvdata(pci));
	pci_set_drvdata(pci, NULL);
}
Example #29
0
int snd_ac97_pcm_open(struct ac97_pcm *pcm, unsigned int rate,
		      enum ac97_pcm_cfg cfg, unsigned short slots)
{
	struct snd_ac97_bus *bus;
	int i, cidx, r, ok_flag;
	unsigned int reg_ok[4] = {0,0,0,0};
	unsigned char reg;
	int err = 0;

	r = rate > 48000;
	bus = pcm->bus;
	if (cfg == AC97_PCM_CFG_SPDIF) {
		for (cidx = 0; cidx < 4; cidx++)
			if (bus->codec[cidx] && (bus->codec[cidx]->ext_id & AC97_EI_SPDIF)) {
				err = set_spdif_rate(bus->codec[cidx], rate);
				if (err < 0)
					return err;
			}
	}
	spin_lock_irq(&pcm->bus->bus_lock);
	for (i = 3; i < 12; i++) {
		if (!(slots & (1 << i)))
			continue;
		ok_flag = 0;
		for (cidx = 0; cidx < 4; cidx++) {
			if (bus->used_slots[pcm->stream][cidx] & (1 << i)) {
				spin_unlock_irq(&pcm->bus->bus_lock);
				err = -EBUSY;
				goto error;
			}
			if (pcm->r[r].rslots[cidx] & (1 << i)) {
				bus->used_slots[pcm->stream][cidx] |= (1 << i);
				ok_flag++;
			}
		}
		if (!ok_flag) {
			spin_unlock_irq(&pcm->bus->bus_lock);
			snd_printk(KERN_ERR "cannot find configuration for AC97 slot %i\n", i);
			err = -EAGAIN;
			goto error;
		}
	}
	pcm->cur_dbl = r;
	spin_unlock_irq(&pcm->bus->bus_lock);
	for (i = 3; i < 12; i++) {
		if (!(slots & (1 << i)))
			continue;
		for (cidx = 0; cidx < 4; cidx++) {
			if (pcm->r[r].rslots[cidx] & (1 << i)) {
				reg = get_slot_reg(pcm, cidx, i, r);
				if (reg == 0xff) {
					snd_printk(KERN_ERR "invalid AC97 slot %i?\n", i);
					continue;
				}
				if (reg_ok[cidx] & (1 << (reg - AC97_PCM_FRONT_DAC_RATE)))
					continue;
				//printk(KERN_DEBUG "setting ac97 reg 0x%x to rate %d\n", reg, rate);
				err = snd_ac97_set_rate(pcm->r[r].codec[cidx], reg, rate);
				if (err < 0)
					snd_printk(KERN_ERR "error in snd_ac97_set_rate: cidx=%d, reg=0x%x, rate=%d, err=%d\n", cidx, reg, rate, err);
				else
					reg_ok[cidx] |= (1 << (reg - AC97_PCM_FRONT_DAC_RATE));
			}
		}
	}
	pcm->aslots = slots;
	return 0;

 error:
	pcm->aslots = slots;
	snd_ac97_pcm_close(pcm);
	return err;
}
/*
 * parse the format type I and III descriptors
 */
static int parse_audio_format_i(struct snd_usb_audio *chip,
				struct audioformat *fp, unsigned int format,
				struct uac_format_type_i_continuous_descriptor *fmt,
				struct usb_host_interface *iface)
{
	struct usb_interface_descriptor *altsd = get_iface_desc(iface);
	int protocol = altsd->bInterfaceProtocol;
	snd_pcm_format_t pcm_format;
	int ret;

	if (fmt->bFormatType == UAC_FORMAT_TYPE_III) {
		/* FIXME: the format type is really IECxxx
		 *        but we give normal PCM format to get the existing
		 *        apps working...
		 */
		switch (chip->usb_id) {

		case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */
			if (chip->setup == 0x00 && 
			    fp->altsetting == 6)
				pcm_format = SNDRV_PCM_FORMAT_S16_BE;
			else
				pcm_format = SNDRV_PCM_FORMAT_S16_LE;
			break;
		default:
			pcm_format = SNDRV_PCM_FORMAT_S16_LE;
		}
		fp->formats = pcm_format_to_bits(pcm_format);
	} else {
		fp->formats = parse_audio_format_i_type(chip, fp, format,
							fmt, protocol);
		if (!fp->formats)
			return -EINVAL;
	}

	/* gather possible sample rates */
	/* audio class v1 reports possible sample rates as part of the
	 * proprietary class specific descriptor.
	 * audio class v2 uses class specific EP0 range requests for that.
	 */
	switch (protocol) {
	default:
		snd_printdd(KERN_WARNING "%d:%u:%d : invalid protocol version %d, assuming v1\n",
			   chip->dev->devnum, fp->iface, fp->altsetting, protocol);
		/* fall through */
	case UAC_VERSION_1:
		fp->channels = fmt->bNrChannels;
		ret = parse_audio_format_rates_v1(chip, fp, (unsigned char *) fmt, 7);
		break;
	case UAC_VERSION_2:
		/* fp->channels is already set in this case */
		ret = parse_audio_format_rates_v2(chip, fp);
		break;
	}

	if (fp->channels < 1) {
		snd_printk(KERN_ERR "%d:%u:%d : invalid channels %d\n",
			   chip->dev->devnum, fp->iface, fp->altsetting, fp->channels);
		return -EINVAL;
	}

	return ret;
}