本文均属自己阅读源码的点滴总结,转账请注明出处谢谢。
欢迎和大家交流。qq:1037701636 email:[email protected],[email protected]
在这里分析驱动的ioctl的内容时,需要结合相关的应用层的操作,之前我已经说过,这块V4L2的控制都是Ioclt实现的,在完成前期的驱动后,后续的系统调用都由他来完成,主要通过应用层发送一定的命令来完成调用。之前看过很多V4L2的内容,都会涉及到ioctl的内容,在这里我不再介绍。只解析几个核心的控制命令,来实现一个简单的视频采集。
先简单的说下视频ioctl系统调用的流程如下:
case VIDIOC_REQBUFS: //Initiates memory mapping or user pointer I/O,申请内存 dev_dbg(vpfe_dev, "\nEnd of VIDIOC_REQBUFS ioctl"); if (vpfe->io_usrs != 0) { ret = -EBUSY; break; } down_interruptible(&vpfe->lock); videobuf_queue_init(&vpfe->bufqueue, &video_qops, NULL, &vpfe->irqlock, V4L2_BUF_TYPE_VIDEO_CAPTURE, vpfe->field, //filed=V4L2_FIELD_INTERLACED sizeof(struct videobuf_buffer), fh);//主要完成vpfe_obj中的成员变量videobuf_queue的初始化 videobuf_set_buftype(&vpfe->bufqueue, VIDEOBUF_BUF_LINEAR);//buf_type=VIDEOBUF_BUF_LINEAR fh->io_allowed = TRUE; vpfe->io_usrs = 1; INIT_LIST_HEAD(&vpfe->dma_queue);//初始化DMA链表头 ret = videobuf_reqbufs(&vpfe->bufqueue, arg);//获取内存分配,完成相关初始化 up(&vpfe->lock); dev_dbg(vpfe_dev, "\nEnd of VIDIOC_REQBUFS ioctl"); break;
buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) { vpfe_obj *vpfe = &vpfe_device; int i; unsigned int buf_size; dev_dbg(vpfe_dev, "\nstarting buffer_setup"); if (device_type == TVP5146) { *size = buf_size = VPFE_TVP5146_MAX_FBUF_SIZE; //最大缓冲区768*576*2 } else { *size = buf_size = VPFE_MT9T001_MAX_FBUF_SIZE; } for (i = VPFE_DEFNUM_FBUFS; i < *count; i++) { //VPFE_DEFNUM_FBUFS=3,如果多余3个再申请,否则跳过 u32 size = PAGE_SIZE << (get_order(buf_size)); void *mem = (void *)__get_free_pages(GFP_KERNEL | GFP_DMA, //DMA内存申请 get_order(buf_size)); if (mem) { unsigned long adr = (unsigned long)mem; while (size > 0) { /* make sure the frame buffers are never swapped out of memory *///交换内存 SetPageReserved(virt_to_page(adr)); adr += PAGE_SIZE; size -= PAGE_SIZE; } vpfe->fbuffers[i] = mem; } else { break; } } *count = vpfe->numbuffers = i; //3 dev_dbg(vpfe_dev, "\nEnd of buffer_setup"); return 0; }
int videobuf_mmap_mapper(struct videobuf_queue *q, struct vm_area_struct *vma) { struct videobuf_mapping *map; unsigned int first,last,size,i; int retval; down(&q->lock); retval = -EINVAL; if (!(vma->vm_flags & VM_WRITE)) { dprintk(1,"mmap app bug: PROT_WRITE please\n"); goto done; } if (!(vma->vm_flags & VM_SHARED)) { dprintk(1,"mmap app bug: MAP_SHARED please\n"); goto done; } /* look for first buffer to map */ for (first = 0; first < VIDEO_MAX_FRAME; first++) { if (NULL == q->bufs[first]) continue; if (V4L2_MEMORY_MMAP != q->bufs[first]->memory) continue; if (q->bufs[first]->boff == (vma->vm_pgoff << PAGE_SHIFT))//在这里boff对应的为缓存区的物理首地址 ,这部分的内容由前期的VIDIOC_QUERYBUF来获取boff,在mmap传入offset时,意味着vm_pgoff等于offset. break; } if (VIDEO_MAX_FRAME == first) { dprintk(1,"mmap app bug: offset invalid [offset=0x%lx]\n", (vma->vm_pgoff << PAGE_SHIFT)); goto done; } /* look for last buffer to map */ for (size = 0, last = first; last < VIDEO_MAX_FRAME; last++) { if (NULL == q->bufs[last]) continue; if (V4L2_MEMORY_MMAP != q->bufs[last]->memory) continue; if (q->bufs[last]->map) { retval = -EBUSY; goto done; } size += q->bufs[last]->bsize; if (size == (vma->vm_end - vma->vm_start)) break; } if (VIDEO_MAX_FRAME == last) { dprintk(1,"mmap app bug: size invalid [size=0x%lx]\n", (vma->vm_end - vma->vm_start)); goto done; } /* create mapping + update buffer list */ retval = -ENOMEM; map = kmalloc(sizeof(struct videobuf_mapping),GFP_KERNEL); if (NULL == map) goto done; for (size = 0, i = first; i <= last; size += q->bufs[i++]->bsize) { q->bufs[i]->map = map; q->bufs[i]->baddr = vma->vm_start + size; } map->count = 1; map->start = vma->vm_start; map->end = vma->vm_end; map->q = q; if(q->buf_type == VIDEOBUF_BUF_LINEAR){ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); if (io_remap_page_range(vma, vma->vm_start, //建立页表,完成用户空间和物理内存的直接映射 (vma->vm_pgoff << PAGE_SHIFT),//实际所在的需要映射的物理页地址 (vma->vm_end - vma->vm_start), vma->vm_page_prot)){ return -EAGAIN; } vma->vm_flags |= VM_RESERVED | VM_IO; }else { vma->vm_ops = &videobuf_vm_ops; vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED; vma->vm_flags &= ~VM_IO; /* using shared anonymous pages */ } vma->vm_private_data = map; dprintk(1,"mmap %p: q=%p %08lx-%08lx pgoff %08lx bufs %d-%d\n", map,q,vma->vm_start,vma->vm_end,vma->vm_pgoff,first,last); retval = 0; done: up(&q->lock); return retval; } int videobuf_set_buftype(struct videobuf_queue *q, enum videobuf_buf_type type) { q->buf_type = type; return 0; }