4 Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com>
5 Copyright (C) 2004 Chris Kennedy <c@groovy.org>
6 Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "ivtv-driver.h"
24 #include "ivtv-streams.h"
25 #include "ivtv-udma.h"
27 void ivtv_udma_get_page_info(struct ivtv_dma_page_info
*dma_page
, unsigned long first
, unsigned long size
)
29 dma_page
->uaddr
= first
& PAGE_MASK
;
30 dma_page
->offset
= first
& ~PAGE_MASK
;
31 dma_page
->tail
= 1 + ((first
+size
-1) & ~PAGE_MASK
);
32 dma_page
->first
= (first
& PAGE_MASK
) >> PAGE_SHIFT
;
33 dma_page
->last
= ((first
+size
-1) & PAGE_MASK
) >> PAGE_SHIFT
;
34 dma_page
->page_count
= dma_page
->last
- dma_page
->first
+ 1;
35 if (dma_page
->page_count
== 1) dma_page
->tail
-= dma_page
->offset
;
38 int ivtv_udma_fill_sg_list (struct ivtv_user_dma
*dma
, struct ivtv_dma_page_info
*dma_page
, int map_offset
)
42 offset
= dma_page
->offset
;
44 /* Fill SG Array with new values */
45 for (i
= 0; i
< dma_page
->page_count
; i
++) {
46 if (i
== dma_page
->page_count
- 1) {
47 dma
->SGlist
[map_offset
].length
= dma_page
->tail
;
50 dma
->SGlist
[map_offset
].length
= PAGE_SIZE
- offset
;
52 dma
->SGlist
[map_offset
].offset
= offset
;
53 dma
->SGlist
[map_offset
].page
= dma
->map
[map_offset
];
60 void ivtv_udma_fill_sg_array (struct ivtv_user_dma
*dma
, u32 buffer_offset
, u32 buffer_offset_2
, u32 split
) {
62 struct scatterlist
*sg
;
64 for (i
= 0, sg
= dma
->SGlist
; i
< dma
->SG_length
; i
++, sg
++) {
65 dma
->SGarray
[i
].size
= cpu_to_le32(sg_dma_len(sg
));
66 dma
->SGarray
[i
].src
= cpu_to_le32(sg_dma_address(sg
));
67 dma
->SGarray
[i
].dst
= cpu_to_le32(buffer_offset
);
68 buffer_offset
+= sg_dma_len(sg
);
70 split
-= sg_dma_len(sg
);
72 buffer_offset
= buffer_offset_2
;
76 /* User DMA Buffers */
77 void ivtv_udma_alloc(struct ivtv
*itv
)
79 if (itv
->udma
.SG_handle
== 0) {
80 /* Map DMA Page Array Buffer */
81 itv
->udma
.SG_handle
= pci_map_single(itv
->dev
, itv
->udma
.SGarray
,
82 sizeof(itv
->udma
.SGarray
), PCI_DMA_TODEVICE
);
83 ivtv_udma_sync_for_cpu(itv
);
87 int ivtv_udma_setup(struct ivtv
*itv
, unsigned long ivtv_dest_addr
,
88 void __user
*userbuf
, int size_in_bytes
)
90 struct ivtv_dma_page_info user_dma
;
91 struct ivtv_user_dma
*dma
= &itv
->udma
;
94 IVTV_DEBUG_DMA("ivtv_udma_setup, dst: 0x%08x\n", (unsigned int)ivtv_dest_addr
);
97 if (dma
->SG_length
|| dma
->page_count
) {
98 IVTV_DEBUG_WARN("ivtv_udma_setup: SG_length %d page_count %d still full?\n",
99 dma
->SG_length
, dma
->page_count
);
103 ivtv_udma_get_page_info(&user_dma
, (unsigned long)userbuf
, size_in_bytes
);
105 if (user_dma
.page_count
<= 0) {
106 IVTV_DEBUG_WARN("ivtv_udma_setup: Error %d page_count from %d bytes %d offset\n",
107 user_dma
.page_count
, size_in_bytes
, user_dma
.offset
);
111 /* Get user pages for DMA Xfer */
112 down_read(¤t
->mm
->mmap_sem
);
113 err
= get_user_pages(current
, current
->mm
,
114 user_dma
.uaddr
, user_dma
.page_count
, 0, 1, dma
->map
, NULL
);
115 up_read(¤t
->mm
->mmap_sem
);
117 if (user_dma
.page_count
!= err
) {
118 IVTV_DEBUG_WARN("failed to map user pages, returned %d instead of %d\n",
119 err
, user_dma
.page_count
);
123 dma
->page_count
= user_dma
.page_count
;
125 /* Fill SG List with new values */
126 ivtv_udma_fill_sg_list(dma
, &user_dma
, 0);
129 dma
->SG_length
= pci_map_sg(itv
->dev
, dma
->SGlist
, dma
->page_count
, PCI_DMA_TODEVICE
);
131 /* Fill SG Array with new values */
132 ivtv_udma_fill_sg_array (dma
, ivtv_dest_addr
, 0, -1);
134 /* Tag SG Array with Interrupt Bit */
135 dma
->SGarray
[dma
->SG_length
- 1].size
|= cpu_to_le32(0x80000000);
137 ivtv_udma_sync_for_device(itv
);
138 return dma
->page_count
;
141 void ivtv_udma_unmap(struct ivtv
*itv
)
143 struct ivtv_user_dma
*dma
= &itv
->udma
;
146 IVTV_DEBUG_INFO("ivtv_unmap_user_dma\n");
148 /* Nothing to free */
149 if (dma
->page_count
== 0)
152 /* Unmap Scatterlist */
153 if (dma
->SG_length
) {
154 pci_unmap_sg(itv
->dev
, dma
->SGlist
, dma
->page_count
, PCI_DMA_TODEVICE
);
158 ivtv_udma_sync_for_cpu(itv
);
160 /* Release User Pages */
161 for (i
= 0; i
< dma
->page_count
; i
++) {
162 put_page(dma
->map
[i
]);
167 void ivtv_udma_free(struct ivtv
*itv
)
170 if (itv
->udma
.SG_handle
) {
171 pci_unmap_single(itv
->dev
, itv
->udma
.SG_handle
,
172 sizeof(itv
->udma
.SGarray
), PCI_DMA_TODEVICE
);
175 /* Unmap Scatterlist */
176 if (itv
->udma
.SG_length
) {
177 pci_unmap_sg(itv
->dev
, itv
->udma
.SGlist
, itv
->udma
.page_count
, PCI_DMA_TODEVICE
);
181 void ivtv_udma_start(struct ivtv
*itv
)
183 IVTV_DEBUG_DMA("start UDMA\n");
184 write_reg(itv
->udma
.SG_handle
, IVTV_REG_DECDMAADDR
);
185 write_reg_sync(read_reg(IVTV_REG_DMAXFER
) | 0x01, IVTV_REG_DMAXFER
);
186 set_bit(IVTV_F_I_DMA
, &itv
->i_flags
);
187 set_bit(IVTV_F_I_UDMA
, &itv
->i_flags
);
190 void ivtv_udma_prepare(struct ivtv
*itv
)
194 spin_lock_irqsave(&itv
->dma_reg_lock
, flags
);
195 if (!test_bit(IVTV_F_I_DMA
, &itv
->i_flags
))
196 ivtv_udma_start(itv
);
198 set_bit(IVTV_F_I_UDMA_PENDING
, &itv
->i_flags
);
199 spin_unlock_irqrestore(&itv
->dma_reg_lock
, flags
);