/* * try to allocate as the large pages as possible. * stores the resultant memory size in *res_size. * * the minimum size is snd_minimum_buffer. it should be power of 2. */ static int preallocate_pcm_pages(struct snd_pcm_substream *substream, size_t size) { struct snd_dma_buffer *dmab = &substream->dma_buffer; size_t orig_size = size; int err; /* already reserved? */ if (snd_dma_get_reserved_buf(dmab, substream->dma_buf_id) > 0) { if (dmab->bytes >= size) return 0; /* yes */ /* no, free the reserved block */ snd_dma_free_pages(dmab); dmab->bytes = 0; } do { if ((err = snd_dma_alloc_pages(dmab->dev.type, dmab->dev.dev, size, dmab)) < 0) { if (err != -ENOMEM) return err; /* fatal error */ } else return 0; size >>= 1; } while (size >= snd_minimum_buffer); dmab->bytes = 0; /* tell error */ pr_warn("ALSA pcmC%dD%d%c,%d:%s: cannot preallocate for size %zu\n", substream->pcm->card->number, substream->pcm->device, substream->stream ? 'c' : 'p', substream->number, substream->pcm->name, orig_size); return 0; }
int __devinit lola_create_pcm(struct lola *chip) { struct snd_pcm *pcm; int i, err; for (i = 0; i < 2; i++) { err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), PAGE_SIZE, &chip->pcm[i].bdl); if (err < 0) return err; } err = snd_pcm_new(chip->card, "Digigram Lola", 0, chip->pcm[SNDRV_PCM_STREAM_PLAYBACK].num_streams, chip->pcm[SNDRV_PCM_STREAM_CAPTURE].num_streams, &pcm); if (err < 0) return err; strlcpy(pcm->name, "Digigram Lola", sizeof(pcm->name)); pcm->private_data = chip; for (i = 0; i < 2; i++) { if (chip->pcm[i].num_streams) snd_pcm_set_ops(pcm, i, &lola_pcm_ops); } /* buffer pre-allocation */ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, snd_dma_pci_data(chip->pci), 1024 * 64, 32 * 1024 * 1024); return 0; }
/* * try to allocate as the large pages as possible. * stores the resultant memory size in *res_size. * * the minimum size is snd_minimum_buffer. it should be power of 2. */ static int preallocate_pcm_pages(snd_pcm_substream_t *substream, size_t size) { struct snd_dma_buffer *dmab = &substream->dma_buffer; int err; snd_assert(size > 0, return -EINVAL); /* already reserved? */ if (snd_dma_get_reserved_buf(dmab, substream->dma_buf_id) > 0) { if (dmab->bytes >= size) return 0; /* yes */ /* no, free the reserved block */ snd_dma_free_pages(dmab); dmab->bytes = 0; } do { if ((err = snd_dma_alloc_pages(dmab->dev.type, dmab->dev.dev, size, dmab)) < 0) { if (err != -ENOMEM) return err; /* fatal error */ } else return 0; size >>= 1; } while (size >= snd_minimum_buffer); dmab->bytes = 0; /* tell error */ return 0; }
static int snd_hammerfall_get_buffer(struct pci_dev *pci, struct snd_dma_buffer *dmab, size_t size) { dmab->dev.type = SNDRV_DMA_TYPE_DEV; dmab->dev.dev = snd_dma_pci_data(pci); if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), size, dmab) < 0) return -ENOMEM; return 0; }
void *snd_malloc_sgbuf_pages(struct device *device, size_t size, struct snd_dma_buffer *dmab, size_t *res_size) { struct snd_sg_buf *sgbuf; unsigned int i, pages; struct snd_dma_buffer tmpb; dmab->area = NULL; dmab->addr = 0; dmab->private_data = sgbuf = kzalloc(sizeof(*sgbuf), GFP_KERNEL); if (! sgbuf) return NULL; sgbuf->dev = device; pages = snd_sgbuf_aligned_pages(size); sgbuf->tblsize = sgbuf_align_table(pages); sgbuf->table = kcalloc(sgbuf->tblsize, sizeof(*sgbuf->table), GFP_KERNEL); if (! sgbuf->table) goto _failed; sgbuf->page_table = kcalloc(sgbuf->tblsize, sizeof(*sgbuf->page_table), GFP_KERNEL); if (! sgbuf->page_table) goto _failed; /* allocate each page */ for (i = 0; i < pages; i++) { if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, device, PAGE_SIZE, &tmpb) < 0) { if (res_size == NULL) goto _failed; *res_size = size = sgbuf->pages * PAGE_SIZE; break; } sgbuf->table[i].buf = tmpb.area; sgbuf->table[i].addr = tmpb.addr; #if (defined(CONFIG_LS2E_DEV_BOARD) || defined(CONFIG_LS2F_DEV_BOARD)) && defined(CONFIG_DMA_NONCOHERENT) sgbuf->page_table[i] = virt_to_page(CAC_ADDR(tmpb.area)); #else sgbuf->page_table[i] = virt_to_page(tmpb.area); #endif sgbuf->pages++; } sgbuf->size = size; #if (defined(CONFIG_LS2E_DEV_BOARD) || defined(CONFIG_LS2F_DEV_BOARD)) && defined(CONFIG_DMA_NONCOHERENT) dmab->area = vmap(sgbuf->page_table, sgbuf->pages, VM_MAP | VM_IO, pgprot_noncached(PAGE_KERNEL)); #else dmab->area = vmap(sgbuf->page_table, sgbuf->pages, VM_MAP, PAGE_KERNEL); #endif if (! dmab->area) goto _failed; return dmab->area; _failed: snd_free_sgbuf_pages(dmab); /* free the table */ return NULL; }
/* * build packets ring for the given buffer size. * * IXP handles the buffer descriptors, which are connected as a linked * list. although we can change the list dynamically, in this version, * a static RING of buffer descriptors is used. * * the ring is built in this function, and is set up to the hardware. */ static int atiixp_build_dma_packets(struct atiixp *chip, struct atiixp_dma *dma, struct snd_pcm_substream *substream, unsigned int periods, unsigned int period_bytes) { unsigned int i; u32 addr, desc_addr; unsigned long flags; if (periods > ATI_MAX_DESCRIPTORS) return -ENOMEM; if (dma->desc_buf.area == NULL) { if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), ATI_DESC_LIST_SIZE, &dma->desc_buf) < 0) return -ENOMEM; dma->period_bytes = dma->periods = 0; /* clear */ } if (dma->periods == periods && dma->period_bytes == period_bytes) return 0; /* reset DMA before changing the descriptor table */ spin_lock_irqsave(&chip->reg_lock, flags); writel(0, chip->remap_addr + dma->ops->llp_offset); dma->ops->enable_dma(chip, 0); dma->ops->enable_dma(chip, 1); spin_unlock_irqrestore(&chip->reg_lock, flags); /* fill the entries */ addr = (u32)substream->runtime->dma_addr; desc_addr = (u32)dma->desc_buf.addr; for (i = 0; i < periods; i++) { struct atiixp_dma_desc *desc; desc = &((struct atiixp_dma_desc *)dma->desc_buf.area)[i]; desc->addr = cpu_to_le32(addr); desc->status = 0; desc->size = period_bytes >> 2; /* in dwords */ desc_addr += sizeof(struct atiixp_dma_desc); if (i == periods - 1) desc->next = cpu_to_le32((u32)dma->desc_buf.addr); else desc->next = cpu_to_le32(desc_addr); addr += period_bytes; } writel((u32)dma->desc_buf.addr | ATI_REG_LINKPTR_EN, chip->remap_addr + dma->ops->llp_offset); dma->period_bytes = period_bytes; dma->periods = periods; return 0; }
static int cs5535audio_build_dma_packets(struct cs5535audio *cs5535au, struct cs5535audio_dma *dma, struct snd_pcm_substream *substream, unsigned int periods, unsigned int period_bytes) { unsigned int i; u32 addr, desc_addr, jmpprd_addr; struct cs5535audio_dma_desc *lastdesc; if (periods > CS5535AUDIO_MAX_DESCRIPTORS) return -ENOMEM; if (dma->desc_buf.area == NULL) { if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(cs5535au->pci), CS5535AUDIO_DESC_LIST_SIZE+1, &dma->desc_buf) < 0) return -ENOMEM; dma->period_bytes = dma->periods = 0; } if (dma->periods == periods && dma->period_bytes == period_bytes) return 0; /* the u32 cast is okay because in snd*create we successfully told pci alloc that we're only 32 bit capable so the uppper will be 0 */ addr = (u32) substream->runtime->dma_addr; desc_addr = (u32) dma->desc_buf.addr; for (i = 0; i < periods; i++) { struct cs5535audio_dma_desc *desc = &((struct cs5535audio_dma_desc *) dma->desc_buf.area)[i]; desc->addr = cpu_to_le32(addr); desc->size = cpu_to_le32(period_bytes); desc->ctlreserved = cpu_to_le16(PRD_EOP); desc_addr += sizeof(struct cs5535audio_dma_desc); addr += period_bytes; } /* we reserved one dummy descriptor at the end to do the PRD jump */ lastdesc = &((struct cs5535audio_dma_desc *) dma->desc_buf.area)[periods]; lastdesc->addr = cpu_to_le32((u32) dma->desc_buf.addr); lastdesc->size = 0; lastdesc->ctlreserved = cpu_to_le16(PRD_JMP); jmpprd_addr = cpu_to_le32(lastdesc->addr + (sizeof(struct cs5535audio_dma_desc)*periods)); dma->substream = substream; dma->period_bytes = period_bytes; dma->periods = periods; spin_lock_irq(&cs5535au->reg_lock); dma->ops->disable_dma(cs5535au); dma->ops->setup_prd(cs5535au, jmpprd_addr); spin_unlock_irq(&cs5535au->reg_lock); return 0; }
static int snd_bt87x_create_risc(struct snd_bt87x *chip, struct snd_pcm_substream *substream, unsigned int periods, unsigned int period_bytes) { unsigned int i, offset; u32 *risc; if (chip->dma_risc.area == NULL) { if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), PAGE_ALIGN(MAX_RISC_SIZE), &chip->dma_risc) < 0) return -ENOMEM; } risc = (u32 *)chip->dma_risc.area; offset = 0; *risc++ = cpu_to_le32(RISC_SYNC | RISC_SYNC_FM1); *risc++ = cpu_to_le32(0); for (i = 0; i < periods; ++i) { u32 rest; rest = period_bytes; do { u32 cmd, len; unsigned int addr; len = PAGE_SIZE - (offset % PAGE_SIZE); if (len > rest) len = rest; cmd = RISC_WRITE | len; if (rest == period_bytes) { u32 block = i * 16 / periods; cmd |= RISC_SOL; cmd |= block << RISC_SET_STATUS_SHIFT; cmd |= (~block & 0xf) << RISC_RESET_STATUS_SHIFT; } if (len == rest) cmd |= RISC_EOL | RISC_IRQ; *risc++ = cpu_to_le32(cmd); addr = snd_pcm_sgbuf_get_addr(substream, offset); *risc++ = cpu_to_le32(addr); offset += len; rest -= len; } while (rest > 0); } *risc++ = cpu_to_le32(RISC_SYNC | RISC_SYNC_VRO); *risc++ = cpu_to_le32(0); *risc++ = cpu_to_le32(RISC_JUMP); *risc++ = cpu_to_le32(chip->dma_risc.addr); chip->line_bytes = period_bytes; chip->lines = periods; return 0; }
void *snd_malloc_sgbuf_pages(struct device *device, size_t size, struct snd_dma_buffer *dmab, size_t *res_size) { struct snd_sg_buf *sgbuf; unsigned int i, pages; struct snd_dma_buffer tmpb; dmab->area = NULL; dmab->addr = 0; dmab->private_data = sgbuf = kzalloc(sizeof(*sgbuf), GFP_KERNEL); if (! sgbuf) return NULL; sgbuf->dev = device; pages = snd_sgbuf_aligned_pages(size); sgbuf->tblsize = sgbuf_align_table(pages); sgbuf->table = kcalloc(sgbuf->tblsize, sizeof(*sgbuf->table), GFP_KERNEL); if (! sgbuf->table) goto _failed; sgbuf->page_table = kcalloc(sgbuf->tblsize, sizeof(*sgbuf->page_table), GFP_KERNEL); if (! sgbuf->page_table) goto _failed; /* allocate each page */ for (i = 0; i < pages; i++) { if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, device, PAGE_SIZE, &tmpb) < 0) { if (res_size == NULL) goto _failed; *res_size = size = sgbuf->pages * PAGE_SIZE; break; } sgbuf->table[i].buf = tmpb.area; sgbuf->table[i].addr = tmpb.addr; sgbuf->page_table[i] = virt_to_page(tmpb.area); sgbuf->pages++; } sgbuf->size = size; dmab->area = vmap(sgbuf->page_table, sgbuf->pages, VM_MAP, PAGE_KERNEL); if (! dmab->area) goto _failed; return dmab->area; _failed: snd_free_sgbuf_pages(dmab); /* free the table */ return NULL; }
/** * snd_dma_alloc_pages_fallback - allocate the buffer area according to the given type with fallback * @type: the DMA buffer type * @device: the device pointer * @size: the buffer size to allocate * @dmab: buffer allocation record to store the allocated data * * Calls the memory-allocator function for the corresponding * buffer type. When no space is left, this function reduces the size and * tries to allocate again. The size actually allocated is stored in * res_size argument. * * Return: Zero if the buffer with the given size is allocated successfully, * otherwise a negative value on error. */ int snd_dma_alloc_pages_fallback(int type, struct device *device, size_t size, struct snd_dma_buffer *dmab) { int err; while ((err = snd_dma_alloc_pages(type, device, size, dmab)) < 0) { if (err != -ENOMEM) return err; if (size <= PAGE_SIZE) return -ENOMEM; size >>= 1; size = PAGE_SIZE << get_order(size); } if (! dmab->area) return -ENOMEM; return 0; }
static int stm32_spdifrx_dma_ctrl_register(struct device *dev, struct stm32_spdifrx_data *spdifrx) { int ret; spdifrx->dmab = devm_kzalloc(dev, sizeof(struct snd_dma_buffer), GFP_KERNEL); if (!spdifrx->dmab) return -ENOMEM; spdifrx->dmab->dev.type = SNDRV_DMA_TYPE_DEV_IRAM; spdifrx->dmab->dev.dev = dev; ret = snd_dma_alloc_pages(spdifrx->dmab->dev.type, dev, SPDIFRX_CSR_BUF_LENGTH, spdifrx->dmab); if (ret < 0) { dev_err(dev, "snd_dma_alloc_pages returned error %d\n", ret); return ret; } spdifrx->ctrl_chan = dma_request_chan(dev, "rx-ctrl"); if (!spdifrx->ctrl_chan) { dev_err(dev, "dma_request_slave_channel failed\n"); return -EINVAL; } spdifrx->slave_config.direction = DMA_DEV_TO_MEM; spdifrx->slave_config.src_addr = (dma_addr_t)(spdifrx->phys_addr + STM32_SPDIFRX_CSR); spdifrx->slave_config.dst_addr = spdifrx->dmab->addr; spdifrx->slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; spdifrx->slave_config.src_maxburst = 1; ret = dmaengine_slave_config(spdifrx->ctrl_chan, &spdifrx->slave_config); if (ret < 0) { dev_err(dev, "dmaengine_slave_config returned error %d\n", ret); dma_release_channel(spdifrx->ctrl_chan); spdifrx->ctrl_chan = NULL; } return ret; };
/** * snd_pcm_lib_malloc_pages - allocate the DMA buffer * @substream: the substream to allocate the DMA buffer to * @size: the requested buffer size in bytes * * Allocates the DMA buffer on the BUS type given earlier to * snd_pcm_lib_preallocate_xxx_pages(). * * Return: 1 if the buffer is changed, 0 if not changed, or a negative * code on failure. */ int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size) { struct snd_pcm_runtime *runtime; struct snd_dma_buffer *dmab = NULL; if (PCM_RUNTIME_CHECK(substream)) return -EINVAL; if (snd_BUG_ON(substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_UNKNOWN)) return -EINVAL; runtime = substream->runtime; if (runtime->dma_buffer_p) { /* perphaps, we might free the large DMA memory region to save some space here, but the actual solution costs us less time */ if (runtime->dma_buffer_p->bytes >= size) { runtime->dma_bytes = size; return 0; /* ok, do not change */ } snd_pcm_lib_free_pages(substream); } if (substream->dma_buffer.area != NULL && substream->dma_buffer.bytes >= size) { dmab = &substream->dma_buffer; /* use the pre-allocated buffer */ } else { dmab = kzalloc(sizeof(*dmab), GFP_KERNEL); if (! dmab) return -ENOMEM; dmab->dev = substream->dma_buffer.dev; if (snd_dma_alloc_pages(substream->dma_buffer.dev.type, substream->dma_buffer.dev.dev, size, dmab) < 0) { kfree(dmab); return -ENOMEM; } } snd_pcm_set_runtime_buffer(substream, dmab); runtime->dma_bytes = size; return 1; /* area was changed */ }
/* * write callback for prealloc proc file * * accepts the preallocation size in kB. */ static void snd_pcm_lib_preallocate_proc_write(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { struct snd_pcm_substream *substream = entry->private_data; char line[64], str[64]; size_t size; struct snd_dma_buffer new_dmab; if (substream->runtime) { buffer->error = -EBUSY; return; } if (!snd_info_get_line(buffer, line, sizeof(line))) { snd_info_get_str(str, line, sizeof(str)); size = simple_strtoul(str, NULL, 10) * 1024; if ((size != 0 && size < 8192) || size > substream->dma_max) { buffer->error = -EINVAL; return; } if (substream->dma_buffer.bytes == size) return; memset(&new_dmab, 0, sizeof(new_dmab)); new_dmab.dev = substream->dma_buffer.dev; if (size > 0) { if (snd_dma_alloc_pages(substream->dma_buffer.dev.type, substream->dma_buffer.dev.dev, size, &new_dmab) < 0) { buffer->error = -ENOMEM; return; } substream->buffer_bytes_max = size; } else { substream->buffer_bytes_max = UINT_MAX; } if (substream->dma_buffer.area) snd_dma_free_pages(&substream->dma_buffer); substream->dma_buffer = new_dmab; } else { buffer->error = -EINVAL; } }
static int setup_corb_rirb(struct lola *chip) { int err; unsigned char tmp; unsigned long end_time; err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), PAGE_SIZE, &chip->rb); if (err < 0) return err; chip->corb.addr = chip->rb.addr; chip->corb.buf = (u32 *)chip->rb.area; chip->rirb.addr = chip->rb.addr + 2048; chip->rirb.buf = (u32 *)(chip->rb.area + 2048); /* */ lola_writeb(chip, BAR0, RIRBCTL, 0); lola_writeb(chip, BAR0, CORBCTL, 0); end_time = jiffies + msecs_to_jiffies(200); do { if (!lola_readb(chip, BAR0, RIRBCTL) && !lola_readb(chip, BAR0, CORBCTL)) break; msleep(1); } while (time_before(jiffies, end_time)); /* */ lola_writel(chip, BAR0, CORBLBASE, (u32)chip->corb.addr); lola_writel(chip, BAR0, CORBUBASE, upper_32_bits(chip->corb.addr)); /* */ lola_writeb(chip, BAR0, CORBSIZE, 0x02); /* */ lola_writew(chip, BAR0, CORBWP, 0); /* */ lola_writew(chip, BAR0, CORBRP, LOLA_RBRWP_CLR); /* */ lola_writeb(chip, BAR0, CORBCTL, LOLA_RBCTL_DMA_EN); /* */ tmp = lola_readb(chip, BAR0, CORBSTS) & LOLA_CORB_INT_MASK; if (tmp) lola_writeb(chip, BAR0, CORBSTS, tmp); chip->corb.wp = 0; /* */ lola_writel(chip, BAR0, RIRBLBASE, (u32)chip->rirb.addr); lola_writel(chip, BAR0, RIRBUBASE, upper_32_bits(chip->rirb.addr)); /* */ lola_writeb(chip, BAR0, RIRBSIZE, 0x02); /* */ lola_writew(chip, BAR0, RIRBWP, LOLA_RBRWP_CLR); /* */ lola_writew(chip, BAR0, RINTCNT, 1); /* */ lola_writeb(chip, BAR0, RIRBCTL, LOLA_RBCTL_DMA_EN | LOLA_RBCTL_IRQ_EN); /* */ tmp = lola_readb(chip, BAR0, RIRBSTS) & LOLA_RIRB_INT_MASK; if (tmp) lola_writeb(chip, BAR0, RIRBSTS, tmp); chip->rirb.rp = chip->rirb.cmds = 0; return 0; }
/* * DMA page allocation ops. */ static int dma_alloc_pages(struct azx *chip, int type, size_t size, struct snd_dma_buffer *buf) { return snd_dma_alloc_pages(type, chip->card->dev, size, buf); }
static int 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; } err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); if (err < 0) return err; 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; emu->delay_pcm_irq = delay_pcm_irq[dev] & 0x1f; 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 strlcpy(card->driver, emu->card_capabilities->driver, sizeof(card->driver)); strlcpy(card->shortname, emu->card_capabilities->name, sizeof(card->shortname)); 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; }
/* * DMA page allocation ops. */ static int dma_alloc_pages(struct hdac_bus *bus, int type, size_t size, struct snd_dma_buffer *buf) { return snd_dma_alloc_pages(type, bus->dev, size, buf); }
/* * allocate and initialize the descriptor buffers * periods = number of periods * fragsize = period size in bytes */ static int build_via_table(struct viadev *dev, struct snd_pcm_substream *substream, struct pci_dev *pci, unsigned int periods, unsigned int fragsize) { unsigned int i, idx, ofs, rest; struct via82xx_modem *chip = snd_pcm_substream_chip(substream); if (dev->table.area == NULL) { /* the start of each lists must be aligned to 8 bytes, * but the kernel pages are much bigger, so we don't care */ if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), PAGE_ALIGN(VIA_TABLE_SIZE * 2 * 8), &dev->table) < 0) return -ENOMEM; } if (! dev->idx_table) { dev->idx_table = kmalloc(sizeof(*dev->idx_table) * VIA_TABLE_SIZE, GFP_KERNEL); if (! dev->idx_table) return -ENOMEM; } /* fill the entries */ idx = 0; ofs = 0; for (i = 0; i < periods; i++) { rest = fragsize; /* fill descriptors for a period. * a period can be split to several descriptors if it's * over page boundary. */ do { unsigned int r; unsigned int flag; unsigned int addr; if (idx >= VIA_TABLE_SIZE) { snd_printk(KERN_ERR "via82xx: too much table size!\n"); return -EINVAL; } addr = snd_pcm_sgbuf_get_addr(substream, ofs); ((u32 *)dev->table.area)[idx << 1] = cpu_to_le32(addr); r = PAGE_SIZE - (ofs % PAGE_SIZE); if (rest < r) r = rest; rest -= r; if (! rest) { if (i == periods - 1) flag = VIA_TBL_BIT_EOL; /* buffer boundary */ else flag = VIA_TBL_BIT_FLAG; /* period boundary */ } else flag = 0; /* period continues to the next */ /* printk(KERN_DEBUG "via: tbl %d: at %d size %d " "(rest %d)\n", idx, ofs, r, rest); */ ((u32 *)dev->table.area)[(idx<<1) + 1] = cpu_to_le32(r | flag); dev->idx_table[idx].offset = ofs; dev->idx_table[idx].size = r; ofs += r; idx++; } while (rest > 0); } dev->tbl_entries = idx; dev->bufsize = periods * fragsize; dev->bufsize2 = dev->bufsize / 2; return 0; }
static int build_via_table(struct viadev *dev, struct snd_pcm_substream *substream, struct pci_dev *pci, unsigned int periods, unsigned int fragsize) { unsigned int i, idx, ofs, rest; struct via82xx_modem *chip = snd_pcm_substream_chip(substream); if (dev->table.area == NULL) { /* */ if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), PAGE_ALIGN(VIA_TABLE_SIZE * 2 * 8), &dev->table) < 0) return -ENOMEM; } if (! dev->idx_table) { dev->idx_table = kmalloc(sizeof(*dev->idx_table) * VIA_TABLE_SIZE, GFP_KERNEL); if (! dev->idx_table) return -ENOMEM; } /* */ idx = 0; ofs = 0; for (i = 0; i < periods; i++) { rest = fragsize; /* */ do { unsigned int r; unsigned int flag; unsigned int addr; if (idx >= VIA_TABLE_SIZE) { snd_printk(KERN_ERR "via82xx: too much table size!\n"); return -EINVAL; } addr = snd_pcm_sgbuf_get_addr(substream, ofs); ((u32 *)dev->table.area)[idx << 1] = cpu_to_le32(addr); r = PAGE_SIZE - (ofs % PAGE_SIZE); if (rest < r) r = rest; rest -= r; if (! rest) { if (i == periods - 1) flag = VIA_TBL_BIT_EOL; /* */ else flag = VIA_TBL_BIT_FLAG; /* */ } else flag = 0; /* */ /* */ ((u32 *)dev->table.area)[(idx<<1) + 1] = cpu_to_le32(r | flag); dev->idx_table[idx].offset = ofs; dev->idx_table[idx].size = r; ofs += r; idx++; } while (rest > 0); } dev->tbl_entries = idx; dev->bufsize = periods * fragsize; dev->bufsize2 = dev->bufsize / 2; return 0; }
static int setup_corb_rirb(struct lola *chip) { int err; unsigned char tmp; unsigned long end_time; err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), PAGE_SIZE, &chip->rb); if (err < 0) return err; chip->corb.addr = chip->rb.addr; chip->corb.buf = (u32 *)chip->rb.area; chip->rirb.addr = chip->rb.addr + 2048; chip->rirb.buf = (u32 *)(chip->rb.area + 2048); /* disable ringbuffer DMAs */ lola_writeb(chip, BAR0, RIRBCTL, 0); lola_writeb(chip, BAR0, CORBCTL, 0); end_time = jiffies + msecs_to_jiffies(200); do { if (!lola_readb(chip, BAR0, RIRBCTL) && !lola_readb(chip, BAR0, CORBCTL)) break; msleep(1); } while (time_before(jiffies, end_time)); /* CORB set up */ lola_writel(chip, BAR0, CORBLBASE, (u32)chip->corb.addr); lola_writel(chip, BAR0, CORBUBASE, upper_32_bits(chip->corb.addr)); /* set the corb size to 256 entries */ lola_writeb(chip, BAR0, CORBSIZE, 0x02); /* set the corb write pointer to 0 */ lola_writew(chip, BAR0, CORBWP, 0); /* reset the corb hw read pointer */ lola_writew(chip, BAR0, CORBRP, LOLA_RBRWP_CLR); /* enable corb dma */ lola_writeb(chip, BAR0, CORBCTL, LOLA_RBCTL_DMA_EN); /* clear flags if set */ tmp = lola_readb(chip, BAR0, CORBSTS) & LOLA_CORB_INT_MASK; if (tmp) lola_writeb(chip, BAR0, CORBSTS, tmp); chip->corb.wp = 0; /* RIRB set up */ lola_writel(chip, BAR0, RIRBLBASE, (u32)chip->rirb.addr); lola_writel(chip, BAR0, RIRBUBASE, upper_32_bits(chip->rirb.addr)); /* set the rirb size to 256 entries */ lola_writeb(chip, BAR0, RIRBSIZE, 0x02); /* reset the rirb hw write pointer */ lola_writew(chip, BAR0, RIRBWP, LOLA_RBRWP_CLR); /* set N=1, get RIRB response interrupt for new entry */ lola_writew(chip, BAR0, RINTCNT, 1); /* enable rirb dma and response irq */ lola_writeb(chip, BAR0, RIRBCTL, LOLA_RBCTL_DMA_EN | LOLA_RBCTL_IRQ_EN); /* clear flags if set */ tmp = lola_readb(chip, BAR0, RIRBSTS) & LOLA_RIRB_INT_MASK; if (tmp) lola_writeb(chip, BAR0, RIRBSTS, tmp); chip->rirb.rp = chip->rirb.cmds = 0; 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_32BIT_MASK) < 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, CARD_NAME, 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); card = snd_card_new(idx, tmpid, THIS_MODULE, 0); if (! card) { snd_printk(KERN_ERR "cannot allocate the card %d\n", i); snd_mixart_free(mgr); return -ENOMEM; } 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; }