static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,enum v4l2_field field) { struct file *file = q->priv_data; struct saa7146_fh *fh = file->private_data; struct saa7146_dev *dev = fh->dev; struct saa7146_buf *buf = (struct saa7146_buf *)vb; int err = 0; int lines, llength, size; lines = 16 * 2 ; /* 2 fields */ llength = vbi_pixel_to_capture; size = lines * llength; DEB_VBI("vb:%p\n", vb); if (0 != buf->vb.baddr && buf->vb.bsize < size) { DEB_VBI("size mismatch\n"); return -EINVAL; } if (buf->vb.size != size) saa7146_dma_free(dev,q,buf); if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); buf->vb.width = llength; buf->vb.height = lines; buf->vb.size = size; buf->vb.field = field; // FIXME: check this saa7146_pgtable_free(dev->pci, &buf->pt[2]); saa7146_pgtable_alloc(dev->pci, &buf->pt[2]); err = videobuf_iolock(q,&buf->vb, NULL); if (err) goto oops; err = saa7146_pgtable_build_single(dev->pci, &buf->pt[2], dma->sglist, dma->sglen); if (0 != err) return err; } buf->vb.state = VIDEOBUF_PREPARED; buf->activate = buffer_activate; return 0; oops: DEB_VBI("error out\n"); saa7146_dma_free(dev,q,buf); return err; }
void *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt) { int pages = (length+PAGE_SIZE-1)/PAGE_SIZE; void *mem = vmalloc_32(length); int slen = 0; if (NULL == mem) goto err_null; if (!(pt->slist = vmalloc_to_sg(mem, pages))) goto err_free_mem; if (saa7146_pgtable_alloc(pci, pt)) goto err_free_slist; pt->nents = pages; slen = pci_map_sg(pci,pt->slist,pt->nents,PCI_DMA_FROMDEVICE); if (0 == slen) goto err_free_pgtable; if (0 != saa7146_pgtable_build_single(pci, pt, pt->slist, slen)) goto err_unmap_sg; return mem; err_unmap_sg: pci_unmap_sg(pci, pt->slist, pt->nents, PCI_DMA_FROMDEVICE); err_free_pgtable: saa7146_pgtable_free(pci, pt); err_free_slist: kfree(pt->slist); pt->slist = NULL; err_free_mem: vfree(mem); err_null: return NULL; }
static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *buf) { struct pci_dev *pci = dev->pci; struct scatterlist *list = buf->vb.dma.sglist; int length = buf->vb.dma.sglen; struct saa7146_format *sfmt = format_by_fourcc(dev,buf->fmt->pixelformat); DEB_EE(("dev:%p, buf:%p, sg_len:%d\n",dev,buf,length)); if( 0 != IS_PLANAR(sfmt->trans)) { struct saa7146_pgtable *pt1 = &buf->pt[0]; struct saa7146_pgtable *pt2 = &buf->pt[1]; struct saa7146_pgtable *pt3 = &buf->pt[2]; u32 *ptr1, *ptr2, *ptr3; u32 fill; int size = buf->fmt->width*buf->fmt->height; int i,p,m1,m2,m3,o1,o2; switch( sfmt->depth ) { case 12: { /* create some offsets inside the page table */ m1 = ((size+PAGE_SIZE)/PAGE_SIZE)-1; m2 = ((size+(size/4)+PAGE_SIZE)/PAGE_SIZE)-1; m3 = ((size+(size/2)+PAGE_SIZE)/PAGE_SIZE)-1; o1 = size%PAGE_SIZE; o2 = (size+(size/4))%PAGE_SIZE; DEB_CAP(("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",size,m1,m2,m3,o1,o2)); break; } case 16: { /* create some offsets inside the page table */ m1 = ((size+PAGE_SIZE)/PAGE_SIZE)-1; m2 = ((size+(size/2)+PAGE_SIZE)/PAGE_SIZE)-1; m3 = ((2*size+PAGE_SIZE)/PAGE_SIZE)-1; o1 = size%PAGE_SIZE; o2 = (size+(size/2))%PAGE_SIZE; DEB_CAP(("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",size,m1,m2,m3,o1,o2)); break; } default: { return -1; } } ptr1 = pt1->cpu; ptr2 = pt2->cpu; ptr3 = pt3->cpu; /* walk all pages, copy all page addresses to ptr1 */ for (i = 0; i < length; i++, list++) { for (p = 0; p * 4096 < list->length; p++, ptr1++) { *ptr1 = cpu_to_le32(sg_dma_address(list) - list->offset); } } /* ptr1 = pt1->cpu; for(j=0;j<40;j++) { printk("ptr1 %d: 0x%08x\n",j,ptr1[j]); } */ /* if we have a user buffer, the first page may not be aligned to a page boundary. */ pt1->offset = buf->vb.dma.sglist->offset; pt2->offset = pt1->offset+o1; pt3->offset = pt1->offset+o2; /* create video-dma2 page table */ ptr1 = pt1->cpu; for(i = m1; i <= m2 ; i++, ptr2++) { *ptr2 = ptr1[i]; } fill = *(ptr2-1); for(;i<1024;i++,ptr2++) { *ptr2 = fill; } /* create video-dma3 page table */ ptr1 = pt1->cpu; for(i = m2; i <= m3; i++,ptr3++) { *ptr3 = ptr1[i]; } fill = *(ptr3-1); for(;i<1024;i++,ptr3++) { *ptr3 = fill; } /* finally: finish up video-dma1 page table */ ptr1 = pt1->cpu+m1; fill = pt1->cpu[m1]; for(i=m1;i<1024;i++,ptr1++) { *ptr1 = fill; } /* ptr1 = pt1->cpu; ptr2 = pt2->cpu; ptr3 = pt3->cpu; for(j=0;j<40;j++) { printk("ptr1 %d: 0x%08x\n",j,ptr1[j]); } for(j=0;j<40;j++) { printk("ptr2 %d: 0x%08x\n",j,ptr2[j]); } for(j=0;j<40;j++) { printk("ptr3 %d: 0x%08x\n",j,ptr3[j]); } */ } else { struct saa7146_pgtable *pt = &buf->pt[0]; return saa7146_pgtable_build_single(pci, pt, list, length); } return 0; }