15bc3cb74SMauro Carvalho Chehab /* 25bc3cb74SMauro Carvalho Chehab * helper functions for physically contiguous capture buffers 35bc3cb74SMauro Carvalho Chehab * 45bc3cb74SMauro Carvalho Chehab * The functions support hardware lacking scatter gather support 55bc3cb74SMauro Carvalho Chehab * (i.e. the buffers must be linear in physical memory) 65bc3cb74SMauro Carvalho Chehab * 75bc3cb74SMauro Carvalho Chehab * Copyright (c) 2008 Magnus Damm 85bc3cb74SMauro Carvalho Chehab * 95bc3cb74SMauro Carvalho Chehab * Based on videobuf-vmalloc.c, 105bc3cb74SMauro Carvalho Chehab * (c) 2007 Mauro Carvalho Chehab, <mchehab@infradead.org> 115bc3cb74SMauro Carvalho Chehab * 125bc3cb74SMauro Carvalho Chehab * This program is free software; you can redistribute it and/or modify 135bc3cb74SMauro Carvalho Chehab * it under the terms of the GNU General Public License as published by 145bc3cb74SMauro Carvalho Chehab * the Free Software Foundation; either version 2 155bc3cb74SMauro Carvalho Chehab */ 165bc3cb74SMauro Carvalho Chehab 175bc3cb74SMauro Carvalho Chehab #include <linux/init.h> 185bc3cb74SMauro Carvalho Chehab #include <linux/module.h> 195bc3cb74SMauro Carvalho Chehab #include <linux/mm.h> 205bc3cb74SMauro Carvalho Chehab #include <linux/pagemap.h> 215bc3cb74SMauro Carvalho Chehab #include <linux/dma-mapping.h> 225bc3cb74SMauro Carvalho Chehab #include <linux/sched.h> 235bc3cb74SMauro Carvalho Chehab #include <linux/slab.h> 245bc3cb74SMauro Carvalho Chehab #include <media/videobuf-dma-contig.h> 255bc3cb74SMauro Carvalho Chehab 265bc3cb74SMauro Carvalho Chehab struct videobuf_dma_contig_memory { 275bc3cb74SMauro Carvalho Chehab u32 magic; 285bc3cb74SMauro Carvalho Chehab void *vaddr; 295bc3cb74SMauro Carvalho Chehab dma_addr_t dma_handle; 305bc3cb74SMauro Carvalho Chehab unsigned long size; 315bc3cb74SMauro Carvalho Chehab }; 325bc3cb74SMauro Carvalho Chehab 335bc3cb74SMauro Carvalho Chehab #define MAGIC_DC_MEM 0x0733ac61 345bc3cb74SMauro Carvalho Chehab #define MAGIC_CHECK(is, should) \ 355bc3cb74SMauro Carvalho Chehab if (unlikely((is) != (should))) { \ 365bc3cb74SMauro Carvalho Chehab pr_err("magic mismatch: %x expected %x\n", (is), (should)); \ 375bc3cb74SMauro Carvalho Chehab BUG(); \ 385bc3cb74SMauro Carvalho Chehab } 395bc3cb74SMauro Carvalho Chehab 405bc3cb74SMauro Carvalho Chehab static int __videobuf_dc_alloc(struct device *dev, 415bc3cb74SMauro Carvalho Chehab struct videobuf_dma_contig_memory *mem, 425bc3cb74SMauro Carvalho Chehab unsigned long size, gfp_t flags) 435bc3cb74SMauro Carvalho Chehab { 445bc3cb74SMauro Carvalho Chehab mem->size = size; 455bc3cb74SMauro Carvalho Chehab mem->vaddr = dma_alloc_coherent(dev, mem->size, 465bc3cb74SMauro Carvalho Chehab &mem->dma_handle, flags); 475bc3cb74SMauro Carvalho Chehab 485bc3cb74SMauro Carvalho Chehab if (!mem->vaddr) { 495bc3cb74SMauro Carvalho Chehab dev_err(dev, "memory alloc size %ld failed\n", mem->size); 505bc3cb74SMauro Carvalho Chehab return -ENOMEM; 515bc3cb74SMauro Carvalho Chehab } 525bc3cb74SMauro Carvalho Chehab 535bc3cb74SMauro Carvalho Chehab dev_dbg(dev, "dma mapped data is at %p (%ld)\n", mem->vaddr, mem->size); 545bc3cb74SMauro Carvalho Chehab 555bc3cb74SMauro Carvalho Chehab return 0; 565bc3cb74SMauro Carvalho Chehab } 575bc3cb74SMauro Carvalho Chehab 585bc3cb74SMauro Carvalho Chehab static void __videobuf_dc_free(struct device *dev, 595bc3cb74SMauro Carvalho Chehab struct videobuf_dma_contig_memory *mem) 605bc3cb74SMauro Carvalho Chehab { 615bc3cb74SMauro Carvalho Chehab dma_free_coherent(dev, mem->size, mem->vaddr, mem->dma_handle); 625bc3cb74SMauro Carvalho Chehab 635bc3cb74SMauro Carvalho Chehab mem->vaddr = NULL; 645bc3cb74SMauro Carvalho Chehab } 655bc3cb74SMauro Carvalho Chehab 665bc3cb74SMauro Carvalho Chehab static void videobuf_vm_open(struct vm_area_struct *vma) 675bc3cb74SMauro Carvalho Chehab { 685bc3cb74SMauro Carvalho Chehab struct videobuf_mapping *map = vma->vm_private_data; 695bc3cb74SMauro Carvalho Chehab 70cca36e2eSHans Verkuil dev_dbg(map->q->dev, "vm_open %p [count=%u,vma=%08lx-%08lx]\n", 715bc3cb74SMauro Carvalho Chehab map, map->count, vma->vm_start, vma->vm_end); 725bc3cb74SMauro Carvalho Chehab 735bc3cb74SMauro Carvalho Chehab map->count++; 745bc3cb74SMauro Carvalho Chehab } 755bc3cb74SMauro Carvalho Chehab 765bc3cb74SMauro Carvalho Chehab static void videobuf_vm_close(struct vm_area_struct *vma) 775bc3cb74SMauro Carvalho Chehab { 785bc3cb74SMauro Carvalho Chehab struct videobuf_mapping *map = vma->vm_private_data; 795bc3cb74SMauro Carvalho Chehab struct videobuf_queue *q = map->q; 805bc3cb74SMauro Carvalho Chehab int i; 815bc3cb74SMauro Carvalho Chehab 825bc3cb74SMauro Carvalho Chehab dev_dbg(q->dev, "vm_close %p [count=%u,vma=%08lx-%08lx]\n", 835bc3cb74SMauro Carvalho Chehab map, map->count, vma->vm_start, vma->vm_end); 845bc3cb74SMauro Carvalho Chehab 85cca36e2eSHans Verkuil map->count--; 86cca36e2eSHans Verkuil if (0 == map->count) { 875bc3cb74SMauro Carvalho Chehab struct videobuf_dma_contig_memory *mem; 885bc3cb74SMauro Carvalho Chehab 895bc3cb74SMauro Carvalho Chehab dev_dbg(q->dev, "munmap %p q=%p\n", map, q); 90cca36e2eSHans Verkuil videobuf_queue_lock(q); 915bc3cb74SMauro Carvalho Chehab 925bc3cb74SMauro Carvalho Chehab /* We need first to cancel streams, before unmapping */ 935bc3cb74SMauro Carvalho Chehab if (q->streaming) 945bc3cb74SMauro Carvalho Chehab videobuf_queue_cancel(q); 955bc3cb74SMauro Carvalho Chehab 965bc3cb74SMauro Carvalho Chehab for (i = 0; i < VIDEO_MAX_FRAME; i++) { 975bc3cb74SMauro Carvalho Chehab if (NULL == q->bufs[i]) 985bc3cb74SMauro Carvalho Chehab continue; 995bc3cb74SMauro Carvalho Chehab 1005bc3cb74SMauro Carvalho Chehab if (q->bufs[i]->map != map) 1015bc3cb74SMauro Carvalho Chehab continue; 1025bc3cb74SMauro Carvalho Chehab 1035bc3cb74SMauro Carvalho Chehab mem = q->bufs[i]->priv; 1045bc3cb74SMauro Carvalho Chehab if (mem) { 1055bc3cb74SMauro Carvalho Chehab /* This callback is called only if kernel has 1065bc3cb74SMauro Carvalho Chehab allocated memory and this memory is mmapped. 1075bc3cb74SMauro Carvalho Chehab In this case, memory should be freed, 1085bc3cb74SMauro Carvalho Chehab in order to do memory unmap. 1095bc3cb74SMauro Carvalho Chehab */ 1105bc3cb74SMauro Carvalho Chehab 1115bc3cb74SMauro Carvalho Chehab MAGIC_CHECK(mem->magic, MAGIC_DC_MEM); 1125bc3cb74SMauro Carvalho Chehab 1135bc3cb74SMauro Carvalho Chehab /* vfree is not atomic - can't be 1145bc3cb74SMauro Carvalho Chehab called with IRQ's disabled 1155bc3cb74SMauro Carvalho Chehab */ 1165bc3cb74SMauro Carvalho Chehab dev_dbg(q->dev, "buf[%d] freeing %p\n", 1175bc3cb74SMauro Carvalho Chehab i, mem->vaddr); 1185bc3cb74SMauro Carvalho Chehab 1195bc3cb74SMauro Carvalho Chehab __videobuf_dc_free(q->dev, mem); 1205bc3cb74SMauro Carvalho Chehab mem->vaddr = NULL; 1215bc3cb74SMauro Carvalho Chehab } 1225bc3cb74SMauro Carvalho Chehab 1235bc3cb74SMauro Carvalho Chehab q->bufs[i]->map = NULL; 1245bc3cb74SMauro Carvalho Chehab q->bufs[i]->baddr = 0; 1255bc3cb74SMauro Carvalho Chehab } 1265bc3cb74SMauro Carvalho Chehab 1275bc3cb74SMauro Carvalho Chehab kfree(map); 1285bc3cb74SMauro Carvalho Chehab 129a242f426SAl Viro videobuf_queue_unlock(q); 1305bc3cb74SMauro Carvalho Chehab } 131cca36e2eSHans Verkuil } 1325bc3cb74SMauro Carvalho Chehab 1335bc3cb74SMauro Carvalho Chehab static const struct vm_operations_struct videobuf_vm_ops = { 1345bc3cb74SMauro Carvalho Chehab .open = videobuf_vm_open, 1355bc3cb74SMauro Carvalho Chehab .close = videobuf_vm_close, 1365bc3cb74SMauro Carvalho Chehab }; 1375bc3cb74SMauro Carvalho Chehab 1385bc3cb74SMauro Carvalho Chehab /** 1395bc3cb74SMauro Carvalho Chehab * videobuf_dma_contig_user_put() - reset pointer to user space buffer 1405bc3cb74SMauro Carvalho Chehab * @mem: per-buffer private videobuf-dma-contig data 1415bc3cb74SMauro Carvalho Chehab * 1425bc3cb74SMauro Carvalho Chehab * This function resets the user space pointer 1435bc3cb74SMauro Carvalho Chehab */ 1445bc3cb74SMauro Carvalho Chehab static void videobuf_dma_contig_user_put(struct videobuf_dma_contig_memory *mem) 1455bc3cb74SMauro Carvalho Chehab { 1465bc3cb74SMauro Carvalho Chehab mem->dma_handle = 0; 1475bc3cb74SMauro Carvalho Chehab mem->size = 0; 1485bc3cb74SMauro Carvalho Chehab } 1495bc3cb74SMauro Carvalho Chehab 1505bc3cb74SMauro Carvalho Chehab /** 1515bc3cb74SMauro Carvalho Chehab * videobuf_dma_contig_user_get() - setup user space memory pointer 1525bc3cb74SMauro Carvalho Chehab * @mem: per-buffer private videobuf-dma-contig data 1535bc3cb74SMauro Carvalho Chehab * @vb: video buffer to map 1545bc3cb74SMauro Carvalho Chehab * 1555bc3cb74SMauro Carvalho Chehab * This function validates and sets up a pointer to user space memory. 1565bc3cb74SMauro Carvalho Chehab * Only physically contiguous pfn-mapped memory is accepted. 1575bc3cb74SMauro Carvalho Chehab * 1585bc3cb74SMauro Carvalho Chehab * Returns 0 if successful. 1595bc3cb74SMauro Carvalho Chehab */ 1605bc3cb74SMauro Carvalho Chehab static int videobuf_dma_contig_user_get(struct videobuf_dma_contig_memory *mem, 1615bc3cb74SMauro Carvalho Chehab struct videobuf_buffer *vb) 1625bc3cb74SMauro Carvalho Chehab { 1635bc3cb74SMauro Carvalho Chehab struct mm_struct *mm = current->mm; 1645bc3cb74SMauro Carvalho Chehab struct vm_area_struct *vma; 1655bc3cb74SMauro Carvalho Chehab unsigned long prev_pfn, this_pfn; 1665bc3cb74SMauro Carvalho Chehab unsigned long pages_done, user_address; 1675bc3cb74SMauro Carvalho Chehab unsigned int offset; 1685bc3cb74SMauro Carvalho Chehab int ret; 1695bc3cb74SMauro Carvalho Chehab 1705bc3cb74SMauro Carvalho Chehab offset = vb->baddr & ~PAGE_MASK; 1715bc3cb74SMauro Carvalho Chehab mem->size = PAGE_ALIGN(vb->size + offset); 1725bc3cb74SMauro Carvalho Chehab ret = -EINVAL; 1735bc3cb74SMauro Carvalho Chehab 1745bc3cb74SMauro Carvalho Chehab down_read(&mm->mmap_sem); 1755bc3cb74SMauro Carvalho Chehab 1765bc3cb74SMauro Carvalho Chehab vma = find_vma(mm, vb->baddr); 1775bc3cb74SMauro Carvalho Chehab if (!vma) 1785bc3cb74SMauro Carvalho Chehab goto out_up; 1795bc3cb74SMauro Carvalho Chehab 1805bc3cb74SMauro Carvalho Chehab if ((vb->baddr + mem->size) > vma->vm_end) 1815bc3cb74SMauro Carvalho Chehab goto out_up; 1825bc3cb74SMauro Carvalho Chehab 1835bc3cb74SMauro Carvalho Chehab pages_done = 0; 1845bc3cb74SMauro Carvalho Chehab prev_pfn = 0; /* kill warning */ 1855bc3cb74SMauro Carvalho Chehab user_address = vb->baddr; 1865bc3cb74SMauro Carvalho Chehab 1875bc3cb74SMauro Carvalho Chehab while (pages_done < (mem->size >> PAGE_SHIFT)) { 1885bc3cb74SMauro Carvalho Chehab ret = follow_pfn(vma, user_address, &this_pfn); 1895bc3cb74SMauro Carvalho Chehab if (ret) 1905bc3cb74SMauro Carvalho Chehab break; 1915bc3cb74SMauro Carvalho Chehab 1925bc3cb74SMauro Carvalho Chehab if (pages_done == 0) 1935bc3cb74SMauro Carvalho Chehab mem->dma_handle = (this_pfn << PAGE_SHIFT) + offset; 1945bc3cb74SMauro Carvalho Chehab else if (this_pfn != (prev_pfn + 1)) 1955bc3cb74SMauro Carvalho Chehab ret = -EFAULT; 1965bc3cb74SMauro Carvalho Chehab 1975bc3cb74SMauro Carvalho Chehab if (ret) 1985bc3cb74SMauro Carvalho Chehab break; 1995bc3cb74SMauro Carvalho Chehab 2005bc3cb74SMauro Carvalho Chehab prev_pfn = this_pfn; 2015bc3cb74SMauro Carvalho Chehab user_address += PAGE_SIZE; 2025bc3cb74SMauro Carvalho Chehab pages_done++; 2035bc3cb74SMauro Carvalho Chehab } 2045bc3cb74SMauro Carvalho Chehab 2055bc3cb74SMauro Carvalho Chehab out_up: 2065bc3cb74SMauro Carvalho Chehab up_read(¤t->mm->mmap_sem); 2075bc3cb74SMauro Carvalho Chehab 2085bc3cb74SMauro Carvalho Chehab return ret; 2095bc3cb74SMauro Carvalho Chehab } 2105bc3cb74SMauro Carvalho Chehab 211cb132cd5SMauro Carvalho Chehab static struct videobuf_buffer *__videobuf_alloc(size_t size) 2125bc3cb74SMauro Carvalho Chehab { 2135bc3cb74SMauro Carvalho Chehab struct videobuf_dma_contig_memory *mem; 2145bc3cb74SMauro Carvalho Chehab struct videobuf_buffer *vb; 2155bc3cb74SMauro Carvalho Chehab 2165bc3cb74SMauro Carvalho Chehab vb = kzalloc(size + sizeof(*mem), GFP_KERNEL); 2175bc3cb74SMauro Carvalho Chehab if (vb) { 2185bc3cb74SMauro Carvalho Chehab vb->priv = ((char *)vb) + size; 2195bc3cb74SMauro Carvalho Chehab mem = vb->priv; 2205bc3cb74SMauro Carvalho Chehab mem->magic = MAGIC_DC_MEM; 2215bc3cb74SMauro Carvalho Chehab } 2225bc3cb74SMauro Carvalho Chehab 2235bc3cb74SMauro Carvalho Chehab return vb; 2245bc3cb74SMauro Carvalho Chehab } 2255bc3cb74SMauro Carvalho Chehab 2265bc3cb74SMauro Carvalho Chehab static void *__videobuf_to_vaddr(struct videobuf_buffer *buf) 2275bc3cb74SMauro Carvalho Chehab { 2285bc3cb74SMauro Carvalho Chehab struct videobuf_dma_contig_memory *mem = buf->priv; 2295bc3cb74SMauro Carvalho Chehab 2305bc3cb74SMauro Carvalho Chehab BUG_ON(!mem); 2315bc3cb74SMauro Carvalho Chehab MAGIC_CHECK(mem->magic, MAGIC_DC_MEM); 2325bc3cb74SMauro Carvalho Chehab 2335bc3cb74SMauro Carvalho Chehab return mem->vaddr; 2345bc3cb74SMauro Carvalho Chehab } 2355bc3cb74SMauro Carvalho Chehab 2365bc3cb74SMauro Carvalho Chehab static int __videobuf_iolock(struct videobuf_queue *q, 2375bc3cb74SMauro Carvalho Chehab struct videobuf_buffer *vb, 2385bc3cb74SMauro Carvalho Chehab struct v4l2_framebuffer *fbuf) 2395bc3cb74SMauro Carvalho Chehab { 2405bc3cb74SMauro Carvalho Chehab struct videobuf_dma_contig_memory *mem = vb->priv; 2415bc3cb74SMauro Carvalho Chehab 2425bc3cb74SMauro Carvalho Chehab BUG_ON(!mem); 2435bc3cb74SMauro Carvalho Chehab MAGIC_CHECK(mem->magic, MAGIC_DC_MEM); 2445bc3cb74SMauro Carvalho Chehab 2455bc3cb74SMauro Carvalho Chehab switch (vb->memory) { 2465bc3cb74SMauro Carvalho Chehab case V4L2_MEMORY_MMAP: 2475bc3cb74SMauro Carvalho Chehab dev_dbg(q->dev, "%s memory method MMAP\n", __func__); 2485bc3cb74SMauro Carvalho Chehab 2495bc3cb74SMauro Carvalho Chehab /* All handling should be done by __videobuf_mmap_mapper() */ 2505bc3cb74SMauro Carvalho Chehab if (!mem->vaddr) { 2515bc3cb74SMauro Carvalho Chehab dev_err(q->dev, "memory is not alloced/mmapped.\n"); 2525bc3cb74SMauro Carvalho Chehab return -EINVAL; 2535bc3cb74SMauro Carvalho Chehab } 2545bc3cb74SMauro Carvalho Chehab break; 2555bc3cb74SMauro Carvalho Chehab case V4L2_MEMORY_USERPTR: 2565bc3cb74SMauro Carvalho Chehab dev_dbg(q->dev, "%s memory method USERPTR\n", __func__); 2575bc3cb74SMauro Carvalho Chehab 2585bc3cb74SMauro Carvalho Chehab /* handle pointer from user space */ 2595bc3cb74SMauro Carvalho Chehab if (vb->baddr) 2605bc3cb74SMauro Carvalho Chehab return videobuf_dma_contig_user_get(mem, vb); 2615bc3cb74SMauro Carvalho Chehab 2625bc3cb74SMauro Carvalho Chehab /* allocate memory for the read() method */ 2635bc3cb74SMauro Carvalho Chehab if (__videobuf_dc_alloc(q->dev, mem, PAGE_ALIGN(vb->size), 2645bc3cb74SMauro Carvalho Chehab GFP_KERNEL)) 2655bc3cb74SMauro Carvalho Chehab return -ENOMEM; 2665bc3cb74SMauro Carvalho Chehab break; 2675bc3cb74SMauro Carvalho Chehab case V4L2_MEMORY_OVERLAY: 2685bc3cb74SMauro Carvalho Chehab default: 2695bc3cb74SMauro Carvalho Chehab dev_dbg(q->dev, "%s memory method OVERLAY/unknown\n", __func__); 2705bc3cb74SMauro Carvalho Chehab return -EINVAL; 2715bc3cb74SMauro Carvalho Chehab } 2725bc3cb74SMauro Carvalho Chehab 2735bc3cb74SMauro Carvalho Chehab return 0; 2745bc3cb74SMauro Carvalho Chehab } 2755bc3cb74SMauro Carvalho Chehab 2765bc3cb74SMauro Carvalho Chehab static int __videobuf_mmap_mapper(struct videobuf_queue *q, 2775bc3cb74SMauro Carvalho Chehab struct videobuf_buffer *buf, 2785bc3cb74SMauro Carvalho Chehab struct vm_area_struct *vma) 2795bc3cb74SMauro Carvalho Chehab { 2805bc3cb74SMauro Carvalho Chehab struct videobuf_dma_contig_memory *mem; 2815bc3cb74SMauro Carvalho Chehab struct videobuf_mapping *map; 2825bc3cb74SMauro Carvalho Chehab int retval; 2835bc3cb74SMauro Carvalho Chehab unsigned long size; 2845bc3cb74SMauro Carvalho Chehab 2855bc3cb74SMauro Carvalho Chehab dev_dbg(q->dev, "%s\n", __func__); 2865bc3cb74SMauro Carvalho Chehab 2875bc3cb74SMauro Carvalho Chehab /* create mapping + update buffer list */ 2885bc3cb74SMauro Carvalho Chehab map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL); 2895bc3cb74SMauro Carvalho Chehab if (!map) 2905bc3cb74SMauro Carvalho Chehab return -ENOMEM; 2915bc3cb74SMauro Carvalho Chehab 2925bc3cb74SMauro Carvalho Chehab buf->map = map; 2935bc3cb74SMauro Carvalho Chehab map->q = q; 2945bc3cb74SMauro Carvalho Chehab 2955bc3cb74SMauro Carvalho Chehab buf->baddr = vma->vm_start; 2965bc3cb74SMauro Carvalho Chehab 2975bc3cb74SMauro Carvalho Chehab mem = buf->priv; 2985bc3cb74SMauro Carvalho Chehab BUG_ON(!mem); 2995bc3cb74SMauro Carvalho Chehab MAGIC_CHECK(mem->magic, MAGIC_DC_MEM); 3005bc3cb74SMauro Carvalho Chehab 3015bc3cb74SMauro Carvalho Chehab if (__videobuf_dc_alloc(q->dev, mem, PAGE_ALIGN(buf->bsize), 3025bc3cb74SMauro Carvalho Chehab GFP_KERNEL | __GFP_COMP)) 3035bc3cb74SMauro Carvalho Chehab goto error; 3045bc3cb74SMauro Carvalho Chehab 3055bc3cb74SMauro Carvalho Chehab /* Try to remap memory */ 3065bc3cb74SMauro Carvalho Chehab size = vma->vm_end - vma->vm_start; 3075bc3cb74SMauro Carvalho Chehab vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 30829f1cdb0SMa Haijun retval = vm_iomap_memory(vma, mem->dma_handle, size); 3095bc3cb74SMauro Carvalho Chehab if (retval) { 3105bc3cb74SMauro Carvalho Chehab dev_err(q->dev, "mmap: remap failed with error %d. ", 3115bc3cb74SMauro Carvalho Chehab retval); 3125bc3cb74SMauro Carvalho Chehab dma_free_coherent(q->dev, mem->size, 3135bc3cb74SMauro Carvalho Chehab mem->vaddr, mem->dma_handle); 3145bc3cb74SMauro Carvalho Chehab goto error; 3155bc3cb74SMauro Carvalho Chehab } 3165bc3cb74SMauro Carvalho Chehab 3175bc3cb74SMauro Carvalho Chehab vma->vm_ops = &videobuf_vm_ops; 3185bc3cb74SMauro Carvalho Chehab vma->vm_flags |= VM_DONTEXPAND; 3195bc3cb74SMauro Carvalho Chehab vma->vm_private_data = map; 3205bc3cb74SMauro Carvalho Chehab 3215bc3cb74SMauro Carvalho Chehab dev_dbg(q->dev, "mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n", 3225bc3cb74SMauro Carvalho Chehab map, q, vma->vm_start, vma->vm_end, 3235bc3cb74SMauro Carvalho Chehab (long int)buf->bsize, vma->vm_pgoff, buf->i); 3245bc3cb74SMauro Carvalho Chehab 3255bc3cb74SMauro Carvalho Chehab videobuf_vm_open(vma); 3265bc3cb74SMauro Carvalho Chehab 3275bc3cb74SMauro Carvalho Chehab return 0; 3285bc3cb74SMauro Carvalho Chehab 3295bc3cb74SMauro Carvalho Chehab error: 3305bc3cb74SMauro Carvalho Chehab kfree(map); 3315bc3cb74SMauro Carvalho Chehab return -ENOMEM; 3325bc3cb74SMauro Carvalho Chehab } 3335bc3cb74SMauro Carvalho Chehab 3345bc3cb74SMauro Carvalho Chehab static struct videobuf_qtype_ops qops = { 3355bc3cb74SMauro Carvalho Chehab .magic = MAGIC_QTYPE_OPS, 336cb132cd5SMauro Carvalho Chehab .alloc_vb = __videobuf_alloc, 3375bc3cb74SMauro Carvalho Chehab .iolock = __videobuf_iolock, 3385bc3cb74SMauro Carvalho Chehab .mmap_mapper = __videobuf_mmap_mapper, 3395bc3cb74SMauro Carvalho Chehab .vaddr = __videobuf_to_vaddr, 3405bc3cb74SMauro Carvalho Chehab }; 3415bc3cb74SMauro Carvalho Chehab 3425bc3cb74SMauro Carvalho Chehab void videobuf_queue_dma_contig_init(struct videobuf_queue *q, 3435bc3cb74SMauro Carvalho Chehab const struct videobuf_queue_ops *ops, 3445bc3cb74SMauro Carvalho Chehab struct device *dev, 3455bc3cb74SMauro Carvalho Chehab spinlock_t *irqlock, 3465bc3cb74SMauro Carvalho Chehab enum v4l2_buf_type type, 3475bc3cb74SMauro Carvalho Chehab enum v4l2_field field, 3485bc3cb74SMauro Carvalho Chehab unsigned int msize, 3495bc3cb74SMauro Carvalho Chehab void *priv, 3505bc3cb74SMauro Carvalho Chehab struct mutex *ext_lock) 3515bc3cb74SMauro Carvalho Chehab { 3525bc3cb74SMauro Carvalho Chehab videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize, 3535bc3cb74SMauro Carvalho Chehab priv, &qops, ext_lock); 3545bc3cb74SMauro Carvalho Chehab } 3555bc3cb74SMauro Carvalho Chehab EXPORT_SYMBOL_GPL(videobuf_queue_dma_contig_init); 3565bc3cb74SMauro Carvalho Chehab 3575bc3cb74SMauro Carvalho Chehab dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf) 3585bc3cb74SMauro Carvalho Chehab { 3595bc3cb74SMauro Carvalho Chehab struct videobuf_dma_contig_memory *mem = buf->priv; 3605bc3cb74SMauro Carvalho Chehab 3615bc3cb74SMauro Carvalho Chehab BUG_ON(!mem); 3625bc3cb74SMauro Carvalho Chehab MAGIC_CHECK(mem->magic, MAGIC_DC_MEM); 3635bc3cb74SMauro Carvalho Chehab 3645bc3cb74SMauro Carvalho Chehab return mem->dma_handle; 3655bc3cb74SMauro Carvalho Chehab } 3665bc3cb74SMauro Carvalho Chehab EXPORT_SYMBOL_GPL(videobuf_to_dma_contig); 3675bc3cb74SMauro Carvalho Chehab 3685bc3cb74SMauro Carvalho Chehab void videobuf_dma_contig_free(struct videobuf_queue *q, 3695bc3cb74SMauro Carvalho Chehab struct videobuf_buffer *buf) 3705bc3cb74SMauro Carvalho Chehab { 3715bc3cb74SMauro Carvalho Chehab struct videobuf_dma_contig_memory *mem = buf->priv; 3725bc3cb74SMauro Carvalho Chehab 3735bc3cb74SMauro Carvalho Chehab /* mmapped memory can't be freed here, otherwise mmapped region 3745bc3cb74SMauro Carvalho Chehab would be released, while still needed. In this case, the memory 3755bc3cb74SMauro Carvalho Chehab release should happen inside videobuf_vm_close(). 3765bc3cb74SMauro Carvalho Chehab So, it should free memory only if the memory were allocated for 3775bc3cb74SMauro Carvalho Chehab read() operation. 3785bc3cb74SMauro Carvalho Chehab */ 3795bc3cb74SMauro Carvalho Chehab if (buf->memory != V4L2_MEMORY_USERPTR) 3805bc3cb74SMauro Carvalho Chehab return; 3815bc3cb74SMauro Carvalho Chehab 3825bc3cb74SMauro Carvalho Chehab if (!mem) 3835bc3cb74SMauro Carvalho Chehab return; 3845bc3cb74SMauro Carvalho Chehab 3855bc3cb74SMauro Carvalho Chehab MAGIC_CHECK(mem->magic, MAGIC_DC_MEM); 3865bc3cb74SMauro Carvalho Chehab 3875bc3cb74SMauro Carvalho Chehab /* handle user space pointer case */ 3885bc3cb74SMauro Carvalho Chehab if (buf->baddr) { 3895bc3cb74SMauro Carvalho Chehab videobuf_dma_contig_user_put(mem); 3905bc3cb74SMauro Carvalho Chehab return; 3915bc3cb74SMauro Carvalho Chehab } 3925bc3cb74SMauro Carvalho Chehab 3935bc3cb74SMauro Carvalho Chehab /* read() method */ 3945bc3cb74SMauro Carvalho Chehab if (mem->vaddr) { 3955bc3cb74SMauro Carvalho Chehab __videobuf_dc_free(q->dev, mem); 3965bc3cb74SMauro Carvalho Chehab mem->vaddr = NULL; 3975bc3cb74SMauro Carvalho Chehab } 3985bc3cb74SMauro Carvalho Chehab } 3995bc3cb74SMauro Carvalho Chehab EXPORT_SYMBOL_GPL(videobuf_dma_contig_free); 4005bc3cb74SMauro Carvalho Chehab 4015bc3cb74SMauro Carvalho Chehab MODULE_DESCRIPTION("helper module to manage video4linux dma contig buffers"); 4025bc3cb74SMauro Carvalho Chehab MODULE_AUTHOR("Magnus Damm"); 4035bc3cb74SMauro Carvalho Chehab MODULE_LICENSE("GPL"); 404