⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 memory.c

📁 linux2.6.16版本
💻 C
📖 第 1 页 / 共 2 页
字号:
}/* * page allocation for DMA */struct snd_util_memblk *snd_emu10k1_alloc_pages(struct snd_emu10k1 *emu, struct snd_pcm_substream *substream){	struct snd_pcm_runtime *runtime = substream->runtime;	struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream);	struct snd_util_memhdr *hdr;	struct snd_emu10k1_memblk *blk;	int page, err, idx;	snd_assert(emu, return NULL);	snd_assert(runtime->dma_bytes > 0 && runtime->dma_bytes < MAXPAGES * EMUPAGESIZE, return NULL);	hdr = emu->memhdr;	snd_assert(hdr, return NULL);	down(&hdr->block_mutex);	blk = search_empty(emu, runtime->dma_bytes);	if (blk == NULL) {		up(&hdr->block_mutex);		return NULL;	}	/* fill buffer addresses but pointers are not stored so that	 * snd_free_pci_page() is not called in in synth_free()	 */	idx = 0;	for (page = blk->first_page; page <= blk->last_page; page++, idx++) {		dma_addr_t addr;#ifdef CONFIG_SND_DEBUG		if (idx >= sgbuf->pages) {			printk(KERN_ERR "emu: pages overflow! (%d-%d) for %d\n",			       blk->first_page, blk->last_page, sgbuf->pages);			up(&hdr->block_mutex);			return NULL;		}#endif		addr = sgbuf->table[idx].addr;		if (! is_valid_page(emu, addr)) {			printk(KERN_ERR "emu: failure page = %d\n", idx);			up(&hdr->block_mutex);			return NULL;		}		emu->page_addr_table[page] = addr;		emu->page_ptr_table[page] = NULL;	}	/* set PTB entries */	blk->map_locked = 1; /* do not unmap this block! */	err = snd_emu10k1_memblk_map(emu, blk);	if (err < 0) {		__snd_util_mem_free(hdr, (struct snd_util_memblk *)blk);		up(&hdr->block_mutex);		return NULL;	}	up(&hdr->block_mutex);	return (struct snd_util_memblk *)blk;}/* * release DMA buffer from page table */int snd_emu10k1_free_pages(struct snd_emu10k1 *emu, struct snd_util_memblk *blk){	snd_assert(emu && blk, return -EINVAL);	return snd_emu10k1_synth_free(emu, blk);}/* * memory allocation using multiple pages (for synth) * Unlike the DMA allocation above, non-contiguous pages are assined. *//* * allocate a synth sample area */struct snd_util_memblk *snd_emu10k1_synth_alloc(struct snd_emu10k1 *hw, unsigned int size){	struct snd_emu10k1_memblk *blk;	struct snd_util_memhdr *hdr = hw->memhdr; 	down(&hdr->block_mutex);	blk = (struct snd_emu10k1_memblk *)__snd_util_mem_alloc(hdr, size);	if (blk == NULL) {		up(&hdr->block_mutex);		return NULL;	}	if (synth_alloc_pages(hw, blk)) {		__snd_util_mem_free(hdr, (struct snd_util_memblk *)blk);		up(&hdr->block_mutex);		return NULL;	}	snd_emu10k1_memblk_map(hw, blk);	up(&hdr->block_mutex);	return (struct snd_util_memblk *)blk;}/* * free a synth sample area */intsnd_emu10k1_synth_free(struct snd_emu10k1 *emu, struct snd_util_memblk *memblk){	struct snd_util_memhdr *hdr = emu->memhdr; 	struct snd_emu10k1_memblk *blk = (struct snd_emu10k1_memblk *)memblk;	unsigned long flags;	down(&hdr->block_mutex);	spin_lock_irqsave(&emu->memblk_lock, flags);	if (blk->mapped_page >= 0)		unmap_memblk(emu, blk);	spin_unlock_irqrestore(&emu->memblk_lock, flags);	synth_free_pages(emu, blk);	 __snd_util_mem_free(hdr, memblk);	up(&hdr->block_mutex);	return 0;}/* check new allocation range */static void get_single_page_range(struct snd_util_memhdr *hdr,				  struct snd_emu10k1_memblk *blk,				  int *first_page_ret, int *last_page_ret){	struct list_head *p;	struct snd_emu10k1_memblk *q;	int first_page, last_page;	first_page = blk->first_page;	if ((p = blk->mem.list.prev) != &hdr->block) {		q = get_emu10k1_memblk(p, mem.list);		if (q->last_page == first_page)			first_page++;  /* first page was already allocated */	}	last_page = blk->last_page;	if ((p = blk->mem.list.next) != &hdr->block) {		q = get_emu10k1_memblk(p, mem.list);		if (q->first_page == last_page)			last_page--; /* last page was already allocated */	}	*first_page_ret = first_page;	*last_page_ret = last_page;}/* * allocate kernel pages */static int synth_alloc_pages(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *blk){	int page, first_page, last_page;	struct snd_dma_buffer dmab;	emu10k1_memblk_init(blk);	get_single_page_range(emu->memhdr, blk, &first_page, &last_page);	/* allocate kernel pages */	for (page = first_page; page <= last_page; page++) {		if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci),					PAGE_SIZE, &dmab) < 0)			goto __fail;		if (! is_valid_page(emu, dmab.addr)) {			snd_dma_free_pages(&dmab);			goto __fail;		}		emu->page_addr_table[page] = dmab.addr;		emu->page_ptr_table[page] = dmab.area;	}	return 0;__fail:	/* release allocated pages */	last_page = page - 1;	for (page = first_page; page <= last_page; page++) {		dmab.area = emu->page_ptr_table[page];		dmab.addr = emu->page_addr_table[page];		dmab.bytes = PAGE_SIZE;		snd_dma_free_pages(&dmab);		emu->page_addr_table[page] = 0;		emu->page_ptr_table[page] = NULL;	}	return -ENOMEM;}/* * free pages */static int synth_free_pages(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *blk){	int page, first_page, last_page;	struct snd_dma_buffer dmab;	get_single_page_range(emu->memhdr, blk, &first_page, &last_page);	dmab.dev.type = SNDRV_DMA_TYPE_DEV;	dmab.dev.dev = snd_dma_pci_data(emu->pci);	for (page = first_page; page <= last_page; page++) {		if (emu->page_ptr_table[page] == NULL)			continue;		dmab.area = emu->page_ptr_table[page];		dmab.addr = emu->page_addr_table[page];		dmab.bytes = PAGE_SIZE;		snd_dma_free_pages(&dmab);		emu->page_addr_table[page] = 0;		emu->page_ptr_table[page] = NULL;	}	return 0;}/* calculate buffer pointer from offset address */static inline void *offset_ptr(struct snd_emu10k1 *emu, int page, int offset){	char *ptr;	snd_assert(page >= 0 && page < emu->max_cache_pages, return NULL);	ptr = emu->page_ptr_table[page];	if (! ptr) {		printk(KERN_ERR "emu10k1: access to NULL ptr: page = %d\n", page);		return NULL;	}	ptr += offset & (PAGE_SIZE - 1);	return (void*)ptr;}/* * bzero(blk + offset, size) */int snd_emu10k1_synth_bzero(struct snd_emu10k1 *emu, struct snd_util_memblk *blk,			    int offset, int size){	int page, nextofs, end_offset, temp, temp1;	void *ptr;	struct snd_emu10k1_memblk *p = (struct snd_emu10k1_memblk *)blk;	offset += blk->offset & (PAGE_SIZE - 1);	end_offset = offset + size;	page = get_aligned_page(offset);	do {		nextofs = aligned_page_offset(page + 1);		temp = nextofs - offset;		temp1 = end_offset - offset;		if (temp1 < temp)			temp = temp1;		ptr = offset_ptr(emu, page + p->first_page, offset);		if (ptr)			memset(ptr, 0, temp);		offset = nextofs;		page++;	} while (offset < end_offset);	return 0;}/* * copy_from_user(blk + offset, data, size) */int snd_emu10k1_synth_copy_from_user(struct snd_emu10k1 *emu, struct snd_util_memblk *blk,				     int offset, const char __user *data, int size){	int page, nextofs, end_offset, temp, temp1;	void *ptr;	struct snd_emu10k1_memblk *p = (struct snd_emu10k1_memblk *)blk;	offset += blk->offset & (PAGE_SIZE - 1);	end_offset = offset + size;	page = get_aligned_page(offset);	do {		nextofs = aligned_page_offset(page + 1);		temp = nextofs - offset;		temp1 = end_offset - offset;		if (temp1 < temp)			temp = temp1;		ptr = offset_ptr(emu, page + p->first_page, offset);		if (ptr && copy_from_user(ptr, data, temp))			return -EFAULT;		offset = nextofs;		data += temp;		page++;	} while (offset < end_offset);	return 0;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -