1 /*
2 
3     btcx-risc.c
4 
5     bt848/bt878/cx2388x risc code generator.
6 
7     (c) 2000-03 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
8 
9     This program is free software; you can redistribute it and/or modify
10     it under the terms of the GNU General Public License as published by
11     the Free Software Foundation; either version 2 of the License, or
12     (at your option) any later version.
13 
14     This program is distributed in the hope that it will be useful,
15     but WITHOUT ANY WARRANTY; without even the implied warranty of
16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17     GNU General Public License for more details.
18 
19     You should have received a copy of the GNU General Public License
20     along with this program; if not, write to the Free Software
21     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 
23 */
24 
25 #include <linux/module.h>
26 #include <linux/init.h>
27 #include <linux/pci.h>
28 #include <linux/interrupt.h>
29 #include <linux/videodev2.h>
30 #include <asm/page.h>
31 #include <asm/pgtable.h>
32 
33 #include "btcx-risc.h"
34 
35 MODULE_DESCRIPTION("some code shared by bttv and cx88xx drivers");
36 MODULE_AUTHOR("Gerd Knorr");
37 MODULE_LICENSE("GPL");
38 
39 static unsigned int debug;
40 module_param(debug, int, 0644);
41 MODULE_PARM_DESC(debug,"debug messages, default is 0 (no)");
42 
43 /* ---------------------------------------------------------- */
44 /* allocate/free risc memory                                  */
45 
46 static int memcnt;
47 
btcx_riscmem_free(struct pci_dev * pci,struct btcx_riscmem * risc)48 void btcx_riscmem_free(struct pci_dev *pci,
49 		       struct btcx_riscmem *risc)
50 {
51 	if (NULL == risc->cpu)
52 		return;
53 	if (debug) {
54 		memcnt--;
55 		printk("btcx: riscmem free [%d] dma=%lx\n",
56 		       memcnt, (unsigned long)risc->dma);
57 	}
58 	pci_free_consistent(pci, risc->size, risc->cpu, risc->dma);
59 	memset(risc,0,sizeof(*risc));
60 }
61 
btcx_riscmem_alloc(struct pci_dev * pci,struct btcx_riscmem * risc,unsigned int size)62 int btcx_riscmem_alloc(struct pci_dev *pci,
63 		       struct btcx_riscmem *risc,
64 		       unsigned int size)
65 {
66 	__le32 *cpu;
67 	dma_addr_t dma = 0;
68 
69 	if (NULL != risc->cpu && risc->size < size)
70 		btcx_riscmem_free(pci,risc);
71 	if (NULL == risc->cpu) {
72 		cpu = pci_alloc_consistent(pci, size, &dma);
73 		if (NULL == cpu)
74 			return -ENOMEM;
75 		risc->cpu  = cpu;
76 		risc->dma  = dma;
77 		risc->size = size;
78 		if (debug) {
79 			memcnt++;
80 			printk("btcx: riscmem alloc [%d] dma=%lx cpu=%p size=%d\n",
81 			       memcnt, (unsigned long)dma, cpu, size);
82 		}
83 	}
84 	memset(risc->cpu,0,risc->size);
85 	return 0;
86 }
87 
88 /* ---------------------------------------------------------- */
89 /* screen overlay helpers                                     */
90 
91 int
btcx_screen_clips(int swidth,int sheight,struct v4l2_rect * win,struct v4l2_clip * clips,unsigned int n)92 btcx_screen_clips(int swidth, int sheight, struct v4l2_rect *win,
93 		  struct v4l2_clip *clips, unsigned int n)
94 {
95 	if (win->left < 0) {
96 		/* left */
97 		clips[n].c.left = 0;
98 		clips[n].c.top = 0;
99 		clips[n].c.width  = -win->left;
100 		clips[n].c.height = win->height;
101 		n++;
102 	}
103 	if (win->left + win->width > swidth) {
104 		/* right */
105 		clips[n].c.left   = swidth - win->left;
106 		clips[n].c.top    = 0;
107 		clips[n].c.width  = win->width - clips[n].c.left;
108 		clips[n].c.height = win->height;
109 		n++;
110 	}
111 	if (win->top < 0) {
112 		/* top */
113 		clips[n].c.left = 0;
114 		clips[n].c.top = 0;
115 		clips[n].c.width  = win->width;
116 		clips[n].c.height = -win->top;
117 		n++;
118 	}
119 	if (win->top + win->height > sheight) {
120 		/* bottom */
121 		clips[n].c.left = 0;
122 		clips[n].c.top = sheight - win->top;
123 		clips[n].c.width  = win->width;
124 		clips[n].c.height = win->height - clips[n].c.top;
125 		n++;
126 	}
127 	return n;
128 }
129 
130 int
btcx_align(struct v4l2_rect * win,struct v4l2_clip * clips,unsigned int n,int mask)131 btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips, unsigned int n, int mask)
132 {
133 	s32 nx,nw,dx;
134 	unsigned int i;
135 
136 	/* fixup window */
137 	nx = (win->left + mask) & ~mask;
138 	nw = (win->width) & ~mask;
139 	if (nx + nw > win->left + win->width)
140 		nw -= mask+1;
141 	dx = nx - win->left;
142 	win->left  = nx;
143 	win->width = nw;
144 	if (debug)
145 		printk(KERN_DEBUG "btcx: window align %dx%d+%d+%d [dx=%d]\n",
146 		       win->width, win->height, win->left, win->top, dx);
147 
148 	/* fixup clips */
149 	for (i = 0; i < n; i++) {
150 		nx = (clips[i].c.left-dx) & ~mask;
151 		nw = (clips[i].c.width) & ~mask;
152 		if (nx + nw < clips[i].c.left-dx + clips[i].c.width)
153 			nw += mask+1;
154 		clips[i].c.left  = nx;
155 		clips[i].c.width = nw;
156 		if (debug)
157 			printk(KERN_DEBUG "btcx:   clip align %dx%d+%d+%d\n",
158 			       clips[i].c.width, clips[i].c.height,
159 			       clips[i].c.left, clips[i].c.top);
160 	}
161 	return 0;
162 }
163 
164 void
btcx_sort_clips(struct v4l2_clip * clips,unsigned int nclips)165 btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips)
166 {
167 	struct v4l2_clip swap;
168 	int i,j,n;
169 
170 	if (nclips < 2)
171 		return;
172 	for (i = nclips-2; i >= 0; i--) {
173 		for (n = 0, j = 0; j <= i; j++) {
174 			if (clips[j].c.left > clips[j+1].c.left) {
175 				swap = clips[j];
176 				clips[j] = clips[j+1];
177 				clips[j+1] = swap;
178 				n++;
179 			}
180 		}
181 		if (0 == n)
182 			break;
183 	}
184 }
185 
186 void
btcx_calc_skips(int line,int width,int * maxy,struct btcx_skiplist * skips,unsigned int * nskips,const struct v4l2_clip * clips,unsigned int nclips)187 btcx_calc_skips(int line, int width, int *maxy,
188 		struct btcx_skiplist *skips, unsigned int *nskips,
189 		const struct v4l2_clip *clips, unsigned int nclips)
190 {
191 	unsigned int clip,skip;
192 	int end, maxline;
193 
194 	skip=0;
195 	maxline = 9999;
196 	for (clip = 0; clip < nclips; clip++) {
197 
198 		/* sanity checks */
199 		if (clips[clip].c.left + clips[clip].c.width <= 0)
200 			continue;
201 		if (clips[clip].c.left > (signed)width)
202 			break;
203 
204 		/* vertical range */
205 		if (line > clips[clip].c.top+clips[clip].c.height-1)
206 			continue;
207 		if (line < clips[clip].c.top) {
208 			if (maxline > clips[clip].c.top-1)
209 				maxline = clips[clip].c.top-1;
210 			continue;
211 		}
212 		if (maxline > clips[clip].c.top+clips[clip].c.height-1)
213 			maxline = clips[clip].c.top+clips[clip].c.height-1;
214 
215 		/* horizontal range */
216 		if (0 == skip || clips[clip].c.left > skips[skip-1].end) {
217 			/* new one */
218 			skips[skip].start = clips[clip].c.left;
219 			if (skips[skip].start < 0)
220 				skips[skip].start = 0;
221 			skips[skip].end = clips[clip].c.left + clips[clip].c.width;
222 			if (skips[skip].end > width)
223 				skips[skip].end = width;
224 			skip++;
225 		} else {
226 			/* overlaps -- expand last one */
227 			end = clips[clip].c.left + clips[clip].c.width;
228 			if (skips[skip-1].end < end)
229 				skips[skip-1].end = end;
230 			if (skips[skip-1].end > width)
231 				skips[skip-1].end = width;
232 		}
233 	}
234 	*nskips = skip;
235 	*maxy = maxline;
236 
237 	if (debug) {
238 		printk(KERN_DEBUG "btcx: skips line %d-%d:",line,maxline);
239 		for (skip = 0; skip < *nskips; skip++) {
240 			printk(" %d-%d",skips[skip].start,skips[skip].end);
241 		}
242 		printk("\n");
243 	}
244 }
245 
246 /* ---------------------------------------------------------- */
247 
248 EXPORT_SYMBOL(btcx_riscmem_alloc);
249 EXPORT_SYMBOL(btcx_riscmem_free);
250 
251 EXPORT_SYMBOL(btcx_screen_clips);
252 EXPORT_SYMBOL(btcx_align);
253 EXPORT_SYMBOL(btcx_sort_clips);
254 EXPORT_SYMBOL(btcx_calc_skips);
255 
256 /*
257  * Local variables:
258  * c-basic-offset: 8
259  * End:
260  */
261