diff options
-rw-r--r-- | drivers/media/video/ivtv/ivtv-driver.h | 2 | ||||
-rw-r--r-- | drivers/media/video/ivtv/ivtv-udma.c | 45 | ||||
-rw-r--r-- | drivers/media/video/ivtv/ivtv-yuv.c | 9 |
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 | |||
38 | int ivtv_udma_fill_sg_list (struct ivtv_user_dma *dma, struct ivtv_dma_page_info *dma_page, int map_offset) | 38 | int 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 | ||
60 | void ivtv_udma_fill_sg_array (struct ivtv_user_dma *dma, u32 buffer_offset, u32 buffer_offset_2, u32 split) { | 75 | void 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 | ||
167 | void ivtv_udma_free(struct ivtv *itv) | 189 | void 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 | ||
181 | void ivtv_udma_start(struct ivtv *itv) | 210 | void 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 */ |