memalloc.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 665 行 · 第 1/2 页
C
665 行
{ snd_assert(size > 0, return -ENXIO); snd_assert(dmab != NULL, return -ENXIO); dmab->dev.type = type; dmab->dev.dev = device; dmab->bytes = 0; switch (type) { case SNDRV_DMA_TYPE_CONTINUOUS: dmab->area = snd_malloc_pages(size, (unsigned long)device); dmab->addr = 0; break;#ifdef CONFIG_SBUS case SNDRV_DMA_TYPE_SBUS: dmab->area = snd_malloc_sbus_pages(device, size, &dmab->addr); break;#endif case SNDRV_DMA_TYPE_DEV: dmab->area = snd_malloc_dev_pages(device, size, &dmab->addr); break; case SNDRV_DMA_TYPE_DEV_SG: snd_malloc_sgbuf_pages(device, size, dmab, NULL); break; default: printk(KERN_ERR "snd-malloc: invalid device type %d\n", type); dmab->area = NULL; dmab->addr = 0; return -ENXIO; } if (! dmab->area) return -ENOMEM; dmab->bytes = size; return 0;}/** * 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. * * Returns zero if the buffer with the given size is allocated successfuly, * other a negative value at error. */int snd_dma_alloc_pages_fallback(int type, struct device *device, size_t size, struct snd_dma_buffer *dmab){ int err; snd_assert(size > 0, return -ENXIO); snd_assert(dmab != NULL, return -ENXIO); while ((err = snd_dma_alloc_pages(type, device, size, dmab)) < 0) { if (err != -ENOMEM) return err; size >>= 1; if (size <= PAGE_SIZE) return -ENOMEM; } if (! dmab->area) return -ENOMEM; return 0;}/** * snd_dma_free_pages - release the allocated buffer * @dmab: the buffer allocation record to release * * Releases the allocated buffer via snd_dma_alloc_pages(). */void snd_dma_free_pages(struct snd_dma_buffer *dmab){ switch (dmab->dev.type) { case SNDRV_DMA_TYPE_CONTINUOUS: snd_free_pages(dmab->area, dmab->bytes); break;#ifdef CONFIG_SBUS case SNDRV_DMA_TYPE_SBUS: snd_free_sbus_pages(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr); break;#endif case SNDRV_DMA_TYPE_DEV: snd_free_dev_pages(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr); break; case SNDRV_DMA_TYPE_DEV_SG: snd_free_sgbuf_pages(dmab); break; default: printk(KERN_ERR "snd-malloc: invalid device type %d\n", dmab->dev.type); }}/** * snd_dma_get_reserved - get the reserved buffer for the given device * @dmab: the buffer allocation record to store * @id: the buffer id * * Looks for the reserved-buffer list and re-uses if the same buffer * is found in the list. When the buffer is found, it's removed from the free list. * * Returns the size of buffer if the buffer is found, or zero if not found. */size_t snd_dma_get_reserved_buf(struct snd_dma_buffer *dmab, unsigned int id){ struct list_head *p; struct snd_mem_list *mem; snd_assert(dmab, return 0); down(&list_mutex); list_for_each(p, &mem_list_head) { mem = list_entry(p, struct snd_mem_list, list); if (mem->id == id && ! memcmp(&mem->buffer.dev, &dmab->dev, sizeof(dmab->dev))) { list_del(p); *dmab = mem->buffer; kfree(mem); up(&list_mutex); return dmab->bytes; } } up(&list_mutex); return 0;}/** * snd_dma_reserve_buf - reserve the buffer * @dmab: the buffer to reserve * @id: the buffer id * * Reserves the given buffer as a reserved buffer. * * Returns zero if successful, or a negative code at error. */int snd_dma_reserve_buf(struct snd_dma_buffer *dmab, unsigned int id){ struct snd_mem_list *mem; snd_assert(dmab, return -EINVAL); mem = kmalloc(sizeof(*mem), GFP_KERNEL); if (! mem) return -ENOMEM; down(&list_mutex); mem->buffer = *dmab; mem->id = id; list_add_tail(&mem->list, &mem_list_head); up(&list_mutex); return 0;}/* * purge all reserved buffers */static void free_all_reserved_pages(void){ struct list_head *p; struct snd_mem_list *mem; down(&list_mutex); while (! list_empty(&mem_list_head)) { p = mem_list_head.next; mem = list_entry(p, struct snd_mem_list, list); list_del(p); snd_dma_free_pages(&mem->buffer); kfree(mem); } up(&list_mutex);}/* * allocation of buffers for pre-defined devices */#ifdef CONFIG_PCI/* FIXME: for pci only - other bus? */struct prealloc_dev { unsigned short vendor; unsigned short device; unsigned long dma_mask; unsigned int size; unsigned int buffers;};#define HAMMERFALL_BUFFER_SIZE (16*1024*4*(26+1)+0x10000)static struct prealloc_dev prealloc_devices[] __initdata = { { /* hammerfall */ .vendor = 0x10ee, .device = 0x3fc4, .dma_mask = 0xffffffff, .size = HAMMERFALL_BUFFER_SIZE, .buffers = 2 }, { /* HDSP */ .vendor = 0x10ee, .device = 0x3fc5, .dma_mask = 0xffffffff, .size = HAMMERFALL_BUFFER_SIZE, .buffers = 2 }, { }, /* terminator */};static void __init preallocate_cards(void){ struct pci_dev *pci = NULL; int card; card = 0; while ((pci = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci)) != NULL) { struct prealloc_dev *dev; unsigned int i; if (card >= SNDRV_CARDS) break; for (dev = prealloc_devices; dev->vendor; dev++) { if (dev->vendor == pci->vendor && dev->device == pci->device) break; } if (! dev->vendor) continue; if (! enable[card++]) { printk(KERN_DEBUG "snd-page-alloc: skipping card %d, device %04x:%04x\n", card, pci->vendor, pci->device); continue; } if (pci_set_dma_mask(pci, dev->dma_mask) < 0 || pci_set_consistent_dma_mask(pci, dev->dma_mask) < 0) { printk(KERN_ERR "snd-page-alloc: cannot set DMA mask %lx for pci %04x:%04x\n", dev->dma_mask, dev->vendor, dev->device); continue; } for (i = 0; i < dev->buffers; i++) { struct snd_dma_buffer dmab; memset(&dmab, 0, sizeof(dmab)); if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), dev->size, &dmab) < 0) printk(KERN_WARNING "snd-page-alloc: cannot allocate buffer pages (size = %d)\n", dev->size); else snd_dma_reserve_buf(&dmab, snd_dma_pci_buf_id(pci)); } }}#else#define preallocate_cards() /* NOP */#endif#ifdef CONFIG_PROC_FS/* * proc file interface */static int snd_mem_proc_read(char *page, char **start, off_t off, int count, int *eof, void *data){ int len = 0; long pages = snd_allocated_pages >> (PAGE_SHIFT-12); struct list_head *p; struct snd_mem_list *mem; int devno; static char *types[] = { "UNKNOWN", "CONT", "DEV", "DEV-SG", "SBUS" }; down(&list_mutex); len += snprintf(page + len, count - len, "pages : %li bytes (%li pages per %likB)\n", pages * PAGE_SIZE, pages, PAGE_SIZE / 1024); devno = 0; list_for_each(p, &mem_list_head) { mem = list_entry(p, struct snd_mem_list, list); devno++; len += snprintf(page + len, count - len, "buffer %d : ID %08x : type %s\n", devno, mem->id, types[mem->buffer.dev.type]); len += snprintf(page + len, count - len, " addr = 0x%lx, size = %d bytes\n", (unsigned long)mem->buffer.addr, (int)mem->buffer.bytes); } up(&list_mutex); return len;}#endif /* CONFIG_PROC_FS *//* * module entry */static int __init snd_mem_init(void){#ifdef CONFIG_PROC_FS create_proc_read_entry("driver/snd-page-alloc", 0, NULL, snd_mem_proc_read, NULL);#endif preallocate_cards(); return 0;}static void __exit snd_mem_exit(void){ remove_proc_entry("driver/snd-page-alloc", NULL); free_all_reserved_pages(); if (snd_allocated_pages > 0) printk(KERN_ERR "snd-malloc: Memory leak? pages not freed = %li\n", snd_allocated_pages);}module_init(snd_mem_init)module_exit(snd_mem_exit)/* * exports */EXPORT_SYMBOL(snd_dma_alloc_pages);EXPORT_SYMBOL(snd_dma_alloc_pages_fallback);EXPORT_SYMBOL(snd_dma_free_pages);EXPORT_SYMBOL(snd_dma_get_reserved_buf);EXPORT_SYMBOL(snd_dma_reserve_buf);EXPORT_SYMBOL(snd_malloc_pages);EXPORT_SYMBOL(snd_free_pages);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?