aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.h2
-rw-r--r--drivers/media/video/ivtv/ivtv-udma.c45
-rw-r--r--drivers/media/video/ivtv/ivtv-yuv.c9
3 files changed, 47 insertions, 9 deletions
diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h
index 93a008409f49..784098d4bf04 100644
--- a/drivers/media/video/ivtv/ivtv-driver.h
+++ b/drivers/media/video/ivtv/ivtv-driver.h
@@ -419,6 +419,8 @@ struct ivtv_user_dma {
419 struct mutex lock; 419 struct mutex lock;
420 int page_count; 420 int page_count;
421 struct page *map[IVTV_DMA_SG_OSD_ENT]; 421 struct page *map[IVTV_DMA_SG_OSD_ENT];
422 /* Needed when dealing with highmem userspace buffers */
423 struct page *bouncemap[IVTV_DMA_SG_OSD_ENT];
422 424
423 /* Base Dev SG Array for cx23415/6 */ 425 /* Base Dev SG Array for cx23415/6 */
424 struct ivtv_sg_element SGarray[IVTV_DMA_SG_OSD_ENT]; 426 struct ivtv_sg_element SGarray[IVTV_DMA_SG_OSD_ENT];
diff --git a/drivers/media/video/ivtv/ivtv-udma.c b/drivers/media/video/ivtv/ivtv-udma.c
index bd642e1aafc3..5592abbe14e6 100644
--- a/drivers/media/video/ivtv/ivtv-udma.c
+++ b/drivers/media/video/ivtv/ivtv-udma.c
@@ -38,23 +38,38 @@ void ivtv_udma_get_page_info(struct ivtv_dma_page_info *dma_page, unsigned long
38int ivtv_udma_fill_sg_list (struct ivtv_user_dma *dma, struct ivtv_dma_page_info *dma_page, int map_offset) 38int ivtv_udma_fill_sg_list (struct ivtv_user_dma *dma, struct ivtv_dma_page_info *dma_page, int map_offset)
39{ 39{
40 int i, offset; 40 int i, offset;
41 unsigned long flags;
41 42
42 offset = dma_page->offset; 43 offset = dma_page->offset;
43 44
44 /* Fill SG Array with new values */ 45 /* Fill SG Array with new values */
45 for (i = 0; i < dma_page->page_count; i++) { 46 for (i = 0; i < dma_page->page_count; i++) {
46 if (i == dma_page->page_count - 1) { 47 unsigned int len = (i == dma_page->page_count - 1) ?
47 dma->SGlist[map_offset].length = dma_page->tail; 48 dma_page->tail : PAGE_SIZE - offset;
49
50 dma->SGlist[map_offset].length = len;
51 dma->SGlist[map_offset].offset = offset;
52 if (PageHighMem(dma->map[map_offset])) {
53 void *src;
54
55 if (dma->bouncemap[map_offset] == NULL)
56 dma->bouncemap[map_offset] = alloc_page(GFP_KERNEL);
57 if (dma->bouncemap[map_offset] == NULL)
58 return -ENOMEM;
59 local_irq_save(flags);
60 src = kmap_atomic(dma->map[map_offset], KM_BOUNCE_READ) + offset;
61 memcpy(page_address(dma->bouncemap[map_offset]) + offset, src, len);
62 kunmap_atomic(src, KM_BOUNCE_READ);
63 local_irq_restore(flags);
64 dma->SGlist[map_offset].page = dma->bouncemap[map_offset];
48 } 65 }
49 else { 66 else {
50 dma->SGlist[map_offset].length = PAGE_SIZE - offset; 67 dma->SGlist[map_offset].page = dma->map[map_offset];
51 } 68 }
52 dma->SGlist[map_offset].offset = offset;
53 dma->SGlist[map_offset].page = dma->map[map_offset];
54 offset = 0; 69 offset = 0;
55 map_offset++; 70 map_offset++;
56 } 71 }
57 return map_offset; 72 return 0;
58} 73}
59 74
60void ivtv_udma_fill_sg_array (struct ivtv_user_dma *dma, u32 buffer_offset, u32 buffer_offset_2, u32 split) { 75void ivtv_udma_fill_sg_array (struct ivtv_user_dma *dma, u32 buffer_offset, u32 buffer_offset_2, u32 split) {
@@ -89,7 +104,7 @@ int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr,
89{ 104{
90 struct ivtv_dma_page_info user_dma; 105 struct ivtv_dma_page_info user_dma;
91 struct ivtv_user_dma *dma = &itv->udma; 106 struct ivtv_user_dma *dma = &itv->udma;
92 int err; 107 int i, err;
93 108
94 IVTV_DEBUG_DMA("ivtv_udma_setup, dst: 0x%08x\n", (unsigned int)ivtv_dest_addr); 109 IVTV_DEBUG_DMA("ivtv_udma_setup, dst: 0x%08x\n", (unsigned int)ivtv_dest_addr);
95 110
@@ -123,7 +138,14 @@ int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr,
123 dma->page_count = user_dma.page_count; 138 dma->page_count = user_dma.page_count;
124 139
125 /* Fill SG List with new values */ 140 /* Fill SG List with new values */
126 ivtv_udma_fill_sg_list(dma, &user_dma, 0); 141 err = ivtv_udma_fill_sg_list(dma, &user_dma, 0);
142 if (err) {
143 for (i = 0; i < dma->page_count; i++) {
144 put_page(dma->map[i]);
145 }
146 dma->page_count = 0;
147 return err;
148 }
127 149
128 /* Map SG List */ 150 /* Map SG List */
129 dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE); 151 dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
@@ -166,6 +188,8 @@ void ivtv_udma_unmap(struct ivtv *itv)
166 188
167void ivtv_udma_free(struct ivtv *itv) 189void ivtv_udma_free(struct ivtv *itv)
168{ 190{
191 int i;
192
169 /* Unmap SG Array */ 193 /* Unmap SG Array */
170 if (itv->udma.SG_handle) { 194 if (itv->udma.SG_handle) {
171 pci_unmap_single(itv->dev, itv->udma.SG_handle, 195 pci_unmap_single(itv->dev, itv->udma.SG_handle,
@@ -176,6 +200,11 @@ void ivtv_udma_free(struct ivtv *itv)
176 if (itv->udma.SG_length) { 200 if (itv->udma.SG_length) {
177 pci_unmap_sg(itv->dev, itv->udma.SGlist, itv->udma.page_count, PCI_DMA_TODEVICE); 201 pci_unmap_sg(itv->dev, itv->udma.SGlist, itv->udma.page_count, PCI_DMA_TODEVICE);
178 } 202 }
203
204 for (i = 0; i < IVTV_DMA_SG_OSD_ENT; i++) {
205 if (itv->udma.bouncemap[i])
206 __free_page(itv->udma.bouncemap[i]);
207 }
179} 208}
180 209
181void ivtv_udma_start(struct ivtv *itv) 210void ivtv_udma_start(struct ivtv *itv)
diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c
index fa8c76f3d359..2ae7556f5e68 100644
--- a/drivers/media/video/ivtv/ivtv-yuv.c
+++ b/drivers/media/video/ivtv/ivtv-yuv.c
@@ -83,7 +83,14 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
83 } 83 }
84 84
85 /* Fill & map SG List */ 85 /* Fill & map SG List */
86 ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0)); 86 if (ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0))) {
87 IVTV_DEBUG_WARN("could not allocate bounce buffers for highmem userspace buffers\n");
88 for (i = 0; i < dma->page_count; i++) {
89 put_page(dma->map[i]);
90 }
91 dma->page_count = 0;
92 return -ENOMEM;
93 }
87 dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE); 94 dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
88 95
89 /* Fill SG Array with new values */ 96 /* Fill SG Array with new values */