/* * set up a BDL entry */ static int setup_bdle(struct snd_pcm_substream *substream, struct lola_stream *str, u32 **bdlp, int ofs, int size) { u32 *bdl = *bdlp; while (size > 0) { dma_addr_t addr; int chunk; if (str->frags >= LOLA_MAX_BDL_ENTRIES) return -EINVAL; addr = snd_pcm_sgbuf_get_addr(substream, ofs); /* program the address field of the BDL entry */ bdl[0] = cpu_to_le32((u32)addr); bdl[1] = cpu_to_le32(upper_32_bits(addr)); /* program the size field of the BDL entry */ chunk = snd_pcm_sgbuf_get_chunk_size(substream, ofs, size); bdl[2] = cpu_to_le32(chunk); /* program the IOC to enable interrupt * only when the whole fragment is processed */ size -= chunk; bdl[3] = size ? 0 : cpu_to_le32(0x01); bdl += 4; str->frags++; ofs += chunk; } *bdlp = bdl; return ofs; }
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; }
/* * 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; }