/* * 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; }
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; }
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(®ister_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(®ister_mutex); return 0; } else if (regidx < 0) regidx = i; } if (regidx < 0) { mutex_unlock(®ister_mutex); snd_printk(KERN_ERR PREFIX "too many cards registered.\n"); return -ENODEV; } devices[regidx] = device; mutex_unlock(®ister_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; }
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; }
/** * 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; }
/* * 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; }
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; }
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; }
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; }
/* * 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(®ister_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(®ister_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(®ister_lock, flags); return 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; }
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; }
/* * 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; }
/* * 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; }
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; }
/* * 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; }
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; }
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; }
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; }
/* * 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; }
// 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; }
/* * 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; }
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; }
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); }
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; }