diff options
Diffstat (limited to 'drivers/media/video/videobuf-dma-sg.c')
-rw-r--r-- | drivers/media/video/videobuf-dma-sg.c | 32 |
1 files changed, 27 insertions, 5 deletions
diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c index 0939ede831ab..05dd38343fa3 100644 --- a/drivers/media/video/videobuf-dma-sg.c +++ b/drivers/media/video/videobuf-dma-sg.c | |||
@@ -134,8 +134,8 @@ void videobuf_dma_init(struct videobuf_dmabuf *dma) | |||
134 | dma->magic = MAGIC_DMABUF; | 134 | dma->magic = MAGIC_DMABUF; |
135 | } | 135 | } |
136 | 136 | ||
137 | int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, | 137 | static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma, |
138 | unsigned long data, unsigned long size) | 138 | int direction, unsigned long data, unsigned long size) |
139 | { | 139 | { |
140 | unsigned long first,last; | 140 | unsigned long first,last; |
141 | int err, rw = 0; | 141 | int err, rw = 0; |
@@ -160,12 +160,12 @@ int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, | |||
160 | 160 | ||
161 | dma->varea = (void *) data; | 161 | dma->varea = (void *) data; |
162 | 162 | ||
163 | down_read(¤t->mm->mmap_sem); | 163 | |
164 | err = get_user_pages(current,current->mm, | 164 | err = get_user_pages(current,current->mm, |
165 | data & PAGE_MASK, dma->nr_pages, | 165 | data & PAGE_MASK, dma->nr_pages, |
166 | rw == READ, 1, /* force */ | 166 | rw == READ, 1, /* force */ |
167 | dma->pages, NULL); | 167 | dma->pages, NULL); |
168 | up_read(¤t->mm->mmap_sem); | 168 | |
169 | if (err != dma->nr_pages) { | 169 | if (err != dma->nr_pages) { |
170 | dma->nr_pages = (err >= 0) ? err : 0; | 170 | dma->nr_pages = (err >= 0) ? err : 0; |
171 | dprintk(1,"get_user_pages: err=%d [%d]\n",err,dma->nr_pages); | 171 | dprintk(1,"get_user_pages: err=%d [%d]\n",err,dma->nr_pages); |
@@ -174,6 +174,17 @@ int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, | |||
174 | return 0; | 174 | return 0; |
175 | } | 175 | } |
176 | 176 | ||
177 | int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, | ||
178 | unsigned long data, unsigned long size) | ||
179 | { | ||
180 | int ret; | ||
181 | down_read(¤t->mm->mmap_sem); | ||
182 | ret = videobuf_dma_init_user_locked(dma, direction, data, size); | ||
183 | up_read(¤t->mm->mmap_sem); | ||
184 | |||
185 | return ret; | ||
186 | } | ||
187 | |||
177 | int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction, | 188 | int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction, |
178 | int nr_pages) | 189 | int nr_pages) |
179 | { | 190 | { |
@@ -469,13 +480,24 @@ static int __videobuf_iolock (struct videobuf_queue* q, | |||
469 | pages ); | 480 | pages ); |
470 | if (0 != err) | 481 | if (0 != err) |
471 | return err; | 482 | return err; |
472 | } else { | 483 | } else if (vb->memory == V4L2_MEMORY_USERPTR) { |
473 | /* dma directly to userspace */ | 484 | /* dma directly to userspace */ |
474 | err = videobuf_dma_init_user( &mem->dma, | 485 | err = videobuf_dma_init_user( &mem->dma, |
475 | PCI_DMA_FROMDEVICE, | 486 | PCI_DMA_FROMDEVICE, |
476 | vb->baddr,vb->bsize ); | 487 | vb->baddr,vb->bsize ); |
477 | if (0 != err) | 488 | if (0 != err) |
478 | return err; | 489 | return err; |
490 | } else { | ||
491 | /* NOTE: HACK: videobuf_iolock on V4L2_MEMORY_MMAP | ||
492 | buffers can only be called from videobuf_qbuf | ||
493 | we take current->mm->mmap_sem there, to prevent | ||
494 | locking inversion, so don't take it here */ | ||
495 | |||
496 | err = videobuf_dma_init_user_locked(&mem->dma, | ||
497 | PCI_DMA_FROMDEVICE, | ||
498 | vb->baddr, vb->bsize); | ||
499 | if (0 != err) | ||
500 | return err; | ||
479 | } | 501 | } |
480 | break; | 502 | break; |
481 | case V4L2_MEMORY_OVERLAY: | 503 | case V4L2_MEMORY_OVERLAY: |