Merge branch 'for-greg' of git://gitorious.org/usb/usb into usb-linus
[pandora-kernel.git] / drivers / media / video / omap / omap_voutlib.c
1 /*
2  * omap_voutlib.c
3  *
4  * Copyright (C) 2005-2010 Texas Instruments.
5  *
6  * This file is licensed under the terms of the GNU General Public License
7  * version 2. This program is licensed "as is" without any warranty of any
8  * kind, whether express or implied.
9  *
10  * Based on the OMAP2 camera driver
11  * Video-for-Linux (Version 2) camera capture driver for
12  * the OMAP24xx camera controller.
13  *
14  * Author: Andy Lowe (source@mvista.com)
15  *
16  * Copyright (C) 2004 MontaVista Software, Inc.
17  * Copyright (C) 2010 Texas Instruments.
18  *
19  */
20
21 #include <linux/module.h>
22 #include <linux/errno.h>
23 #include <linux/kernel.h>
24 #include <linux/types.h>
25 #include <linux/videodev2.h>
26
27 #include <plat/cpu.h>
28
29 MODULE_AUTHOR("Texas Instruments");
30 MODULE_DESCRIPTION("OMAP Video library");
31 MODULE_LICENSE("GPL");
32
33 /* Return the default overlay cropping rectangle in crop given the image
34  * size in pix and the video display size in fbuf.  The default
35  * cropping rectangle is the largest rectangle no larger than the capture size
36  * that will fit on the display.  The default cropping rectangle is centered in
37  * the image.  All dimensions and offsets are rounded down to even numbers.
38  */
39 void omap_vout_default_crop(struct v4l2_pix_format *pix,
40                   struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop)
41 {
42         crop->width = (pix->width < fbuf->fmt.width) ?
43                 pix->width : fbuf->fmt.width;
44         crop->height = (pix->height < fbuf->fmt.height) ?
45                 pix->height : fbuf->fmt.height;
46         crop->width &= ~1;
47         crop->height &= ~1;
48         crop->left = ((pix->width - crop->width) >> 1) & ~1;
49         crop->top = ((pix->height - crop->height) >> 1) & ~1;
50 }
51 EXPORT_SYMBOL_GPL(omap_vout_default_crop);
52
53 /* Given a new render window in new_win, adjust the window to the
54  * nearest supported configuration.  The adjusted window parameters are
55  * returned in new_win.
56  * Returns zero if successful, or -EINVAL if the requested window is
57  * impossible and cannot reasonably be adjusted.
58  */
59 int omap_vout_try_window(struct v4l2_framebuffer *fbuf,
60                         struct v4l2_window *new_win)
61 {
62         struct v4l2_rect try_win;
63
64         /* make a working copy of the new_win rectangle */
65         try_win = new_win->w;
66
67         /* adjust the preview window so it fits on the display by clipping any
68          * offscreen areas
69          */
70         if (try_win.left < 0) {
71                 try_win.width += try_win.left;
72                 try_win.left = 0;
73         }
74         if (try_win.top < 0) {
75                 try_win.height += try_win.top;
76                 try_win.top = 0;
77         }
78         try_win.width = (try_win.width < fbuf->fmt.width) ?
79                 try_win.width : fbuf->fmt.width;
80         try_win.height = (try_win.height < fbuf->fmt.height) ?
81                 try_win.height : fbuf->fmt.height;
82         if (try_win.left + try_win.width > fbuf->fmt.width)
83                 try_win.width = fbuf->fmt.width - try_win.left;
84         if (try_win.top + try_win.height > fbuf->fmt.height)
85                 try_win.height = fbuf->fmt.height - try_win.top;
86         try_win.width &= ~1;
87         try_win.height &= ~1;
88
89         if (try_win.width <= 0 || try_win.height <= 0)
90                 return -EINVAL;
91
92         /* We now have a valid preview window, so go with it */
93         new_win->w = try_win;
94         new_win->field = V4L2_FIELD_ANY;
95         return 0;
96 }
97 EXPORT_SYMBOL_GPL(omap_vout_try_window);
98
99 /* Given a new render window in new_win, adjust the window to the
100  * nearest supported configuration.  The image cropping window in crop
101  * will also be adjusted if necessary.  Preference is given to keeping the
102  * the window as close to the requested configuration as possible.  If
103  * successful, new_win, vout->win, and crop are updated.
104  * Returns zero if successful, or -EINVAL if the requested preview window is
105  * impossible and cannot reasonably be adjusted.
106  */
107 int omap_vout_new_window(struct v4l2_rect *crop,
108                 struct v4l2_window *win, struct v4l2_framebuffer *fbuf,
109                 struct v4l2_window *new_win)
110 {
111         int err;
112
113         err = omap_vout_try_window(fbuf, new_win);
114         if (err)
115                 return err;
116
117         /* update our preview window */
118         win->w = new_win->w;
119         win->field = new_win->field;
120         win->chromakey = new_win->chromakey;
121
122         /* Adjust the cropping window to allow for resizing limitation */
123         if (cpu_is_omap24xx()) {
124                 /* For 24xx limit is 8x to 1/2x scaling. */
125                 if ((crop->height/win->w.height) >= 2)
126                         crop->height = win->w.height * 2;
127
128                 if ((crop->width/win->w.width) >= 2)
129                         crop->width = win->w.width * 2;
130
131                 if (crop->width > 768) {
132                         /* The OMAP2420 vertical resizing line buffer is 768
133                          * pixels wide. If the cropped image is wider than
134                          * 768 pixels then it cannot be vertically resized.
135                          */
136                         if (crop->height != win->w.height)
137                                 crop->width = 768;
138                 }
139         } else if (cpu_is_omap34xx()) {
140                 /* For 34xx limit is 8x to 1/4x scaling. */
141                 if ((crop->height/win->w.height) >= 4)
142                         crop->height = win->w.height * 4;
143
144                 if ((crop->width/win->w.width) >= 4)
145                         crop->width = win->w.width * 4;
146         }
147         return 0;
148 }
149 EXPORT_SYMBOL_GPL(omap_vout_new_window);
150
151 /* Given a new cropping rectangle in new_crop, adjust the cropping rectangle to
152  * the nearest supported configuration.  The image render window in win will
153  * also be adjusted if necessary.  The preview window is adjusted such that the
154  * horizontal and vertical rescaling ratios stay constant.  If the render
155  * window would fall outside the display boundaries, the cropping rectangle
156  * will also be adjusted to maintain the rescaling ratios.  If successful, crop
157  * and win are updated.
158  * Returns zero if successful, or -EINVAL if the requested cropping rectangle is
159  * impossible and cannot reasonably be adjusted.
160  */
161 int omap_vout_new_crop(struct v4l2_pix_format *pix,
162               struct v4l2_rect *crop, struct v4l2_window *win,
163               struct v4l2_framebuffer *fbuf, const struct v4l2_rect *new_crop)
164 {
165         struct v4l2_rect try_crop;
166         unsigned long vresize, hresize;
167
168         /* make a working copy of the new_crop rectangle */
169         try_crop = *new_crop;
170
171         /* adjust the cropping rectangle so it fits in the image */
172         if (try_crop.left < 0) {
173                 try_crop.width += try_crop.left;
174                 try_crop.left = 0;
175         }
176         if (try_crop.top < 0) {
177                 try_crop.height += try_crop.top;
178                 try_crop.top = 0;
179         }
180         try_crop.width = (try_crop.width < pix->width) ?
181                 try_crop.width : pix->width;
182         try_crop.height = (try_crop.height < pix->height) ?
183                 try_crop.height : pix->height;
184         if (try_crop.left + try_crop.width > pix->width)
185                 try_crop.width = pix->width - try_crop.left;
186         if (try_crop.top + try_crop.height > pix->height)
187                 try_crop.height = pix->height - try_crop.top;
188
189         try_crop.width &= ~1;
190         try_crop.height &= ~1;
191
192         if (try_crop.width <= 0 || try_crop.height <= 0)
193                 return -EINVAL;
194
195         if (cpu_is_omap24xx()) {
196                 if (crop->height != win->w.height) {
197                         /* If we're resizing vertically, we can't support a
198                          * crop width wider than 768 pixels.
199                          */
200                         if (try_crop.width > 768)
201                                 try_crop.width = 768;
202                 }
203         }
204         /* vertical resizing */
205         vresize = (1024 * crop->height) / win->w.height;
206         if (cpu_is_omap24xx() && (vresize > 2048))
207                 vresize = 2048;
208         else if (cpu_is_omap34xx() && (vresize > 4096))
209                 vresize = 4096;
210
211         win->w.height = ((1024 * try_crop.height) / vresize) & ~1;
212         if (win->w.height == 0)
213                 win->w.height = 2;
214         if (win->w.height + win->w.top > fbuf->fmt.height) {
215                 /* We made the preview window extend below the bottom of the
216                  * display, so clip it to the display boundary and resize the
217                  * cropping height to maintain the vertical resizing ratio.
218                  */
219                 win->w.height = (fbuf->fmt.height - win->w.top) & ~1;
220                 if (try_crop.height == 0)
221                         try_crop.height = 2;
222         }
223         /* horizontal resizing */
224         hresize = (1024 * crop->width) / win->w.width;
225         if (cpu_is_omap24xx() && (hresize > 2048))
226                 hresize = 2048;
227         else if (cpu_is_omap34xx() && (hresize > 4096))
228                 hresize = 4096;
229
230         win->w.width = ((1024 * try_crop.width) / hresize) & ~1;
231         if (win->w.width == 0)
232                 win->w.width = 2;
233         if (win->w.width + win->w.left > fbuf->fmt.width) {
234                 /* We made the preview window extend past the right side of the
235                  * display, so clip it to the display boundary and resize the
236                  * cropping width to maintain the horizontal resizing ratio.
237                  */
238                 win->w.width = (fbuf->fmt.width - win->w.left) & ~1;
239                 if (try_crop.width == 0)
240                         try_crop.width = 2;
241         }
242         if (cpu_is_omap24xx()) {
243                 if ((try_crop.height/win->w.height) >= 2)
244                         try_crop.height = win->w.height * 2;
245
246                 if ((try_crop.width/win->w.width) >= 2)
247                         try_crop.width = win->w.width * 2;
248
249                 if (try_crop.width > 768) {
250                         /* The OMAP2420 vertical resizing line buffer is
251                          * 768 pixels wide.  If the cropped image is wider
252                          * than 768 pixels then it cannot be vertically resized.
253                          */
254                         if (try_crop.height != win->w.height)
255                                 try_crop.width = 768;
256                 }
257         } else if (cpu_is_omap34xx()) {
258                 if ((try_crop.height/win->w.height) >= 4)
259                         try_crop.height = win->w.height * 4;
260
261                 if ((try_crop.width/win->w.width) >= 4)
262                         try_crop.width = win->w.width * 4;
263         }
264         /* update our cropping rectangle and we're done */
265         *crop = try_crop;
266         return 0;
267 }
268 EXPORT_SYMBOL_GPL(omap_vout_new_crop);
269
270 /* Given a new format in pix and fbuf,  crop and win
271  * structures are initialized to default values. crop
272  * is initialized to the largest window size that will fit on the display.  The
273  * crop window is centered in the image. win is initialized to
274  * the same size as crop and is centered on the display.
275  * All sizes and offsets are constrained to be even numbers.
276  */
277 void omap_vout_new_format(struct v4l2_pix_format *pix,
278                 struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop,
279                 struct v4l2_window *win)
280 {
281         /* crop defines the preview source window in the image capture
282          * buffer
283          */
284         omap_vout_default_crop(pix, fbuf, crop);
285
286         /* win defines the preview target window on the display */
287         win->w.width = crop->width;
288         win->w.height = crop->height;
289         win->w.left = ((fbuf->fmt.width - win->w.width) >> 1) & ~1;
290         win->w.top = ((fbuf->fmt.height - win->w.height) >> 1) & ~1;
291 }
292 EXPORT_SYMBOL_GPL(omap_vout_new_format);
293