2c3023643edcae614955e21c47a5b1e2c51e3208
[openembedded.git] /
1 From ad3bbadb7fc39a946dfd0cdac19e2ec8647b2c2c Mon Sep 17 00:00:00 2001
2 From: Vaibhav Hiremath <vaibhav@psp-nfs-02.india.ti.com>
3 Date: Wed, 29 Apr 2009 17:20:27 +0530
4 Subject: [PATCH 24/26] OMAP3-Resizer: V4L2-buf layer issues fixed
5
6 V4L2-Buffer layer issues fixed under this commit.
7 This patch is same as available with PSP1.0.2 release
8
9 The discussion is initiated on this with V4L2 mailing list.
10
11 Please note that this patch is not being tested.
12 ---
13  drivers/media/video/isp/omap_resizer.c |  417 ++++++++++++++++++++++++--------
14  include/linux/omap_resizer.h           |    3 +-
15  2 files changed, 321 insertions(+), 99 deletions(-)
16
17 diff --git a/drivers/media/video/isp/omap_resizer.c b/drivers/media/video/isp/omap_resizer.c
18 index 54bc425..8059c70 100644
19 --- a/drivers/media/video/isp/omap_resizer.c
20 +++ b/drivers/media/video/isp/omap_resizer.c
21 @@ -28,6 +28,7 @@
22  #include <linux/platform_device.h>
23  #include <linux/io.h>
24  #include <linux/uaccess.h>
25 +#include <linux/pci.h>
26  #include <media/v4l2-dev.h>
27  #include <asm/cacheflush.h>
28  
29 @@ -76,6 +77,10 @@
30  #define MAX_COEF_COUNTER       16
31  #define COEFF_ADDRESS_OFFSET   0x04
32  
33 +#define RSZ_DEF_REQ_EXP                0xE     /* Default read operation expand
34 +                                        * for the Resizer driver; value
35 +                                        * taken from Davinci.
36 +                                        */
37  /* Global structure which contains information about number of channels
38     and protection variables */
39  struct device_params {
40 @@ -85,6 +90,7 @@ struct device_params {
41         struct mutex reszwrap_mutex;            /* Semaphore for array */
42  
43         struct videobuf_queue_ops vbq_ops;      /* videobuf queue operations */
44 +       unsigned long extra_page_addr;
45  };
46  
47  /* Register mapped structure which contains the every register
48 @@ -126,6 +132,9 @@ struct resizer_config {
49         u32 rsz_yehn;                           /* yehn(luma)register mapping
50                                                  * variable.
51                                                  */
52 +       u32 sdr_req_exp;                        /* Configuration for Non
53 +                                                * real time read expand
54 +                                                */
55  };
56  
57  struct rsz_mult {
58 @@ -179,6 +188,7 @@ struct channel_config {
59                                                  * channel is busy or not
60                                                  */
61         struct mutex chanprotection_mutex;
62 +       int buf_address[VIDEO_MAX_FRAME];
63         enum config_done config_state;
64         u8 input_buf_index;
65         u8 output_buf_index;
66 @@ -200,8 +210,6 @@ struct rsz_fh {
67         struct videobuf_queue vbq;
68         struct device_params *device;
69  
70 -       dma_addr_t isp_addr_read;               /* Input/Output address */
71 -       dma_addr_t isp_addr_write;              /* Input/Output address */
72         u32 rsz_bufsize;                        /* channel specific buffersize
73                                                  */
74  };
75 @@ -227,6 +235,10 @@ static int rsz_set_ratio(struct rsz_mult *multipass,
76  static void rsz_config_ratio(struct rsz_mult *multipass,
77                                         struct channel_config *rsz_conf_chan);
78  
79 +static void inline rsz_set_exp(unsigned int exp)
80 +{
81 +       omap_writel(((exp & 0x3FF) << 10), OMAP3ISP_SBL_REG(0xF8));
82 +}
83  /**
84   * rsz_hardware_setup - Sets hardware configuration registers
85   * @rsz_conf_chan: Structure containing channel configuration
86 @@ -271,12 +283,15 @@ static void rsz_hardware_setup(struct channel_config *rsz_conf_chan)
87                                                 + coeffoffset));
88                 coeffoffset = coeffoffset + COEFF_ADDRESS_OFFSET;
89         }
90 +       /* Configure the read expand register */
91 +       rsz_set_exp(rsz_conf_chan->register_config.sdr_req_exp);
92  }
93  
94  /**
95   * rsz_start - Enables Resizer Wrapper
96   * @arg: Currently not used.
97 - * @device: Structure containing ISP resizer wrapper global information
98 + * @fh: File structure containing ISP resizer information specific to
99 + *      channel opened.
100   *
101   * Submits a resizing task specified by the rsz_resize structure. The call can
102   * either be blocked until the task is completed or returned immediately based
103 @@ -292,12 +307,18 @@ int rsz_start(int *arg, struct rsz_fh *fh)
104         struct channel_config *rsz_conf_chan = fh->config;
105         struct rsz_mult *multipass = fh->multipass;
106         struct videobuf_queue *q = &fh->vbq;
107 +       struct videobuf_buffer *buf;
108         int ret;
109  
110         if (rsz_conf_chan->config_state) {
111                 dev_err(rsz_device, "State not configured \n");
112                 goto err_einval;
113         }
114 +       if (!rsz_conf_chan->register_config.rsz_sdr_inadd ||
115 +                       !rsz_conf_chan->register_config.rsz_sdr_outadd) {
116 +               dev_err(rsz_device, "address is null\n");
117 +               goto err_einval;
118 +       }
119  
120         rsz_conf_chan->status = CHANNEL_BUSY;
121  
122 @@ -325,33 +346,22 @@ mult:
123                 goto mult;
124         }
125  
126 -       if (fh->isp_addr_read) {
127 -               ispmmu_unmap(fh->isp_addr_read);
128 -               fh->isp_addr_read = 0;
129 -       }
130 -       if (fh->isp_addr_write) {
131 -               ispmmu_unmap(fh->isp_addr_write);
132 -               fh->isp_addr_write = 0;
133 -       }
134 -
135         rsz_conf_chan->status = CHANNEL_FREE;
136 -       q->bufs[rsz_conf_chan->input_buf_index]->state = VIDEOBUF_NEEDS_INIT;
137 -       q->bufs[rsz_conf_chan->output_buf_index]->state = VIDEOBUF_NEEDS_INIT;
138         rsz_conf_chan->register_config.rsz_sdr_outadd = 0;
139         rsz_conf_chan->register_config.rsz_sdr_inadd = 0;
140  
141 -       /* Unmap and free the DMA memory allocated for buffers */
142 -       videobuf_dma_unmap(q, videobuf_to_dma(
143 -                               q->bufs[rsz_conf_chan->input_buf_index]));
144 -       videobuf_dma_unmap(q, videobuf_to_dma(
145 -                               q->bufs[rsz_conf_chan->output_buf_index]));
146 -       videobuf_dma_free(videobuf_to_dma(
147 -                               q->bufs[rsz_conf_chan->input_buf_index]));
148 -       videobuf_dma_free(videobuf_to_dma(
149 -                               q->bufs[rsz_conf_chan->output_buf_index]));
150 -
151         isp_unset_callback(CBK_RESZ_DONE);
152  
153 +       /* Empty the Videobuf queue which was filled during the qbuf */
154 +       buf = q->bufs[rsz_conf_chan->input_buf_index];
155 +       buf->state = VIDEOBUF_IDLE;
156 +       list_del(&buf->stream);
157 +       if (rsz_conf_chan->input_buf_index != rsz_conf_chan->output_buf_index) {
158 +               buf = q->bufs[rsz_conf_chan->output_buf_index];
159 +               buf->state = VIDEOBUF_IDLE;
160 +               list_del(&buf->stream);
161 +       }
162 +
163         return 0;
164  err_einval:
165         return -EINVAL;
166 @@ -359,6 +369,8 @@ err_einval:
167  
168  /**
169   * rsz_set_multipass - Set resizer multipass
170 + * @multipass: Structure containing channel configuration
171 +                       for multipass support
172   * @rsz_conf_chan: Structure containing channel configuration
173   *
174   * Returns always 0
175 @@ -384,6 +396,8 @@ static int rsz_set_multipass(struct rsz_mult *multipass,
176  
177  /**
178   * rsz_copy_data - Copy data
179 + * @multipass: Structure containing channel configuration
180 +                       for multipass support
181   * @params: Structure containing the Resizer Wrapper parameters
182   *
183   * Copy data
184 @@ -413,6 +427,8 @@ static void rsz_copy_data(struct rsz_mult *multipass, struct rsz_params *params)
185  
186  /**
187   * rsz_set_params - Set parameters for resizer wrapper
188 + * @multipass: Structure containing channel configuration
189 +                       for multipass support
190   * @params: Structure containing the Resizer Wrapper parameters
191   * @rsz_conf_chan: Structure containing channel configuration
192   *
193 @@ -524,6 +540,8 @@ static int rsz_set_params(struct rsz_mult *multipass, struct rsz_params *params,
194         }
195  
196         rsz_config_ratio(multipass, rsz_conf_chan);
197 +       /* Default value for read expand:Taken from Davinci */
198 +       rsz_conf_chan->register_config.sdr_req_exp = RSZ_DEF_REQ_EXP;
199  
200         rsz_conf_chan->config_state = STATE_CONFIGURED;
201  
202 @@ -534,6 +552,8 @@ err_einval:
203  
204  /**
205   * rsz_set_ratio - Set ratio
206 + * @multipass: Structure containing channel configuration
207 +                       for multipass support
208   * @rsz_conf_chan: Structure containing channel configuration
209   *
210   * Returns 0 if successful, -EINVAL if invalid output size, upscaling ratio is
211 @@ -548,7 +568,8 @@ static int rsz_set_ratio(struct rsz_mult *multipass,
212  
213         if ((multipass->out_hsize > MAX_IMAGE_WIDTH) ||
214                         (multipass->out_vsize > MAX_IMAGE_WIDTH)) {
215 -               dev_err(rsz_device, "Invalid output size!");
216 +               dev_err(rsz_device, "Invalid output size! - %d", \
217 +                                       multipass->out_hsize);
218                 goto err_einval;
219         }
220         if (multipass->cbilin) {
221 @@ -758,6 +779,8 @@ err_einval:
222  
223  /**
224   * rsz_config_ratio - Configure ratio
225 + * @multipass: Structure containing channel configuration
226 +                       for multipass support
227   * @rsz_conf_chan: Structure containing channel configuration
228   *
229   * Configure ratio
230 @@ -789,6 +812,20 @@ static void rsz_config_ratio(struct rsz_mult *multipass,
231                                         ((vsize << ISPRSZ_IN_SIZE_VERT_SHIFT)
232                                         & ISPRSZ_IN_SIZE_VERT_MASK);
233  
234 +       /* This is another workaround for the ISP-MMU translation fault.
235 +          For the parameters whose image size comes exactly to PAGE_SIZE
236 +          generates ISP-MMU translation fault. The root-cause is the equation
237 +               input width = (32*sph + (ow - 1)*hrsz + 16) >> 8 + 7
238 +                       = (64*sph + (ow - 1)*hrsz + 32) >> 8 + 7
239 +               input height = (32*spv + (oh - 1)*vrsz + 16) >> 8 + 4
240 +               = (64*spv + (oh - 1)*vrsz + 32) >> 8 + 7
241 +
242 +          we are adjusting the input width to suit for Resizer module,
243 +          application should use this configuration henceforth.
244 +        */
245 +       multipass->in_hsize = hsize;
246 +       multipass->in_vsize = vsize;
247 +
248         for (coeffcounter = 0; coeffcounter < MAX_COEF_COUNTER;
249                                                         coeffcounter++) {
250                 if (multipass->num_htap) {
251 @@ -990,24 +1027,15 @@ static void rsz_calculate_crop(struct channel_config *rsz_conf_chan,
252  static void rsz_vbq_release(struct videobuf_queue *q,
253                                                 struct videobuf_buffer *vb)
254  {
255 -       int i;
256         struct rsz_fh *fh = q->priv_data;
257 +       struct videobuf_dmabuf *dma = NULL;
258  
259 -       for (i = 0; i < VIDEO_MAX_FRAME; i++) {
260 -               struct videobuf_dmabuf *dma = NULL;
261 -               if (!q->bufs[i])
262 -                       continue;
263 -               if (q->bufs[i]->memory != V4L2_MEMORY_MMAP)
264 -                       continue;
265 -               dma = videobuf_to_dma(q->bufs[i]);
266 -               videobuf_dma_unmap(q, dma);
267 -               videobuf_dma_free(dma);
268 -       }
269 +       dma = videobuf_to_dma(q->bufs[vb->i]);
270 +       videobuf_dma_unmap(q, dma);
271 +       videobuf_dma_free(dma);
272 +       ispmmu_unmap(fh->config->buf_address[vb->i]);
273 +       fh->config->buf_address[vb->i] = 0;
274  
275 -       ispmmu_unmap(fh->isp_addr_read);
276 -       ispmmu_unmap(fh->isp_addr_write);
277 -       fh->isp_addr_read = 0;
278 -       fh->isp_addr_write = 0;
279         spin_lock(&fh->vbq_lock);
280         vb->state = VIDEOBUF_NEEDS_INIT;
281         spin_unlock(&fh->vbq_lock);
282 @@ -1062,7 +1090,105 @@ err_einval:
283         spin_unlock(&fh->vbq_lock);
284         return -EINVAL;
285  }
286 +/*
287 + * This function is work around for the videobuf_iolock API,
288 + * for User memory allocated with ioremap (VM_IO flag) the API
289 + * get_user_pages fails.
290 + *
291 + * To fulfill this requirement, we have completely ignored VM layer of
292 + * Linux, and configuring the ISP MMU with physical address.
293 + */
294 +static int omap_videobuf_dma_init_user(struct videobuf_buffer *vb,
295 +               unsigned long physp, unsigned long asize)
296 +{
297 +       struct videobuf_dmabuf *dma;
298 +       struct scatterlist *sglist;
299 +       unsigned long data, first, last;
300 +       int len, i = 0;
301 +
302 +       dma = videobuf_to_dma(vb);
303 +       data = vb->baddr;
304 +
305 +        first = (data & PAGE_MASK) >> PAGE_SHIFT;
306 +        last  = ((data+asize-1) & PAGE_MASK) >> PAGE_SHIFT;
307 +        dma->offset   = data & ~PAGE_MASK;
308 +        dma->nr_pages = last-first+1;
309 +
310 +       dma->direction = PCI_DMA_FROMDEVICE;
311 +       /*
312 +        * Allocate array of sglen + 1, to add entry of extra page
313 +        * for input buffer. Driver always uses 0th buffer as input buffer.
314 +        */
315 +       len = dma->nr_pages + (vb->i ? 0 : 1);
316 +       sglist = kcalloc(len, sizeof(*sglist), GFP_KERNEL);
317 +       if (NULL == sglist)
318 +                return -ENOMEM;
319 +
320 +       sglist[0].offset = 0;
321 +       sglist[0].length = PAGE_SIZE - dma->offset;
322 +       sglist[0].dma_address = (dma_addr_t)physp;
323 +       physp += sglist[0].length;
324 +       /*
325 +        * Iterate in a loop for the number of pages
326 +        */
327 +       for (i = 1; i < (len - (vb->i ? 0 : 1)); i++) {
328 +               sglist[i].offset = 0;
329 +               sglist[i].length = PAGE_SIZE;
330 +               sglist[i].dma_address = (dma_addr_t)physp;
331 +               physp += PAGE_SIZE;
332 +       }
333 +       if (0 == vb->i) {
334 +               sglist[i].offset = 0;
335 +               sglist[i].length = PAGE_SIZE;
336 +               sglist[i].dma_address =
337 +                       (dma_addr_t)device_config->extra_page_addr;
338 +        }
339 +       dma->sglist = sglist;
340 +       dma->sglen = len;
341 +        return 0;
342 +
343 +               }
344 +/*
345 + * This function is workaround for the issue, where ISP-MMU generated
346 + * translation fault for specific params whose size is aligned to PAGE_SIZE.
347 +
348 + * As a workaround we are padding one extra page for input buffer. This page
349 + * we are allocating during init time and will not be released through-out
350 + * life time of resizer driver. Please note that Resizer module only reads
351 + * from this extra page.
352 + */
353 +int omap_create_sg(struct videobuf_queue *q, struct videobuf_dmabuf *dma)
354 +{
355 +       struct scatterlist *sglist;
356 +       int sglen;
357  
358 +       sglen = dma->sglen;
359 +       sglist = kcalloc(sglen + 1, sizeof(*sglist), GFP_KERNEL);
360 +       if (NULL == sglist)
361 +               return -ENOMEM;
362 +       /*
363 +        * Copy the sglist locally
364 +        */
365 +       memcpy(sglist, dma->sglist, sglen * sizeof(*sglist));
366 +       /*
367 +        * Release the old sglist, since we already copied it locally
368 +        */
369 +       videobuf_dma_unmap(q, dma);
370 +       /*
371 +        * Add extra entry to sglist to work with specific params, whose
372 +        * buffer address alined to PAGE_SIZE.
373 +        */
374 +       sglist[sglen].offset = 0;
375 +       sglist[sglen].length = PAGE_SIZE;
376 +       sglist[sglen].dma_address = (dma_addr_t)device_config->extra_page_addr;
377 +       sglen++;
378 +       /*
379 +        * Save the sglist for mapping to ISP-MMU space
380 +        */
381 +       dma->sglist = sglist;
382 +       dma->sglen = sglen;
383 +       return 0;
384 +}
385  /**
386   * rsz_vbq_prepare - Videobuffer is prepared and mmapped.
387   * @q: Structure containing the videobuffer queue file handle, and device
388 @@ -1079,19 +1205,24 @@ static int rsz_vbq_prepare(struct videobuf_queue *q,
389  {
390         struct rsz_fh *fh = q->priv_data;
391         struct channel_config *rsz_conf_chan = fh->config;
392 -       struct rsz_mult *multipass = fh->multipass;
393         int err = 0;
394         unsigned int isp_addr, insize, outsize;
395 -       struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
396 -
397 +       struct rsz_mult *multipass = fh->multipass;
398         spin_lock(&fh->vbq_lock);
399         if (vb->baddr) {
400 +               /* Check for 32 byte alignement */
401 +               if (vb->baddr != (vb->baddr & ~0x1F)) {
402 +                       spin_unlock(&fh->vbq_lock);
403 +                       dev_err(rsz_device, "Buffer address should be aligned \
404 +                                       to 32 byte\n");
405 +                       return -EINVAL;
406 +               }
407                 vb->size = fh->rsz_bufsize;
408                 vb->bsize = fh->rsz_bufsize;
409         } else {
410                 spin_unlock(&fh->vbq_lock);
411                 dev_err(rsz_device, "No user buffer allocated\n");
412 -               goto out;
413 +               return -EINVAL;
414         }
415         if (vb->i) {
416                 vb->width = fh->params->out_hsize;
417 @@ -1103,55 +1234,128 @@ static int rsz_vbq_prepare(struct videobuf_queue *q,
418  
419         vb->field = field;
420         spin_unlock(&fh->vbq_lock);
421 +       /*
422 +        * Calculate input and output sizes, will be used while mapping
423 +        * user pages
424 +        */
425 +       outsize = multipass->out_pitch * multipass->out_vsize;
426 +       insize = multipass->in_pitch * multipass->in_vsize;
427  
428         if (vb->state == VIDEOBUF_NEEDS_INIT) {
429 -               err = videobuf_iolock(q, vb, NULL);
430 -               if (!err) {
431 -                       isp_addr = ispmmu_map_sg(dma->sglist, dma->sglen);
432 -                       if (!isp_addr)
433 -                               err = -EIO;
434 -                       else {
435 -                               if (vb->i) {
436 -                                       rsz_conf_chan->register_config.
437 -                                                       rsz_sdr_outadd
438 -                                                       = isp_addr;
439 -                                       fh->isp_addr_write = isp_addr;
440 -                                       rsz_conf_chan->output_buf_index = vb->i;
441 -                               } else {
442 +               struct videobuf_dmabuf *dma;
443 +               struct vm_area_struct *vma;
444 +               spin_lock(&fh->vbq_lock);
445 +               dma = videobuf_to_dma(vb);
446 +               vma = find_vma(current->mm, vb->baddr);
447 +               if ((vma) && (vma->vm_flags & VM_IO) && (vma->vm_pgoff)) {
448 +                       /* This will catch ioremaped buffers to the kernel.
449 +                        *  It gives two possible scenarios -
450 +                        *  - Driver allocates buffer using either
451 +                        *    dma_alloc_coherent or get_free_pages,
452 +                        *    and maps to user space using
453 +                        *    io_remap_pfn_range/remap_pfn_range
454 +                        *  - Drivers maps memory outside from Linux using
455 +                        *    io_remap
456 +                        */
457 +                       unsigned long physp = 0, asize;
458 +                       asize = vb->i ? outsize : insize;
459 +                       if ((vb->baddr + asize) > vma->vm_end) {
460 +                               spin_unlock(&fh->vbq_lock);
461 +                               dev_err(rsz_device, "User Buffer Allocation:" \
462 +                                       "err=%lu[%lu]\n",\
463 +                                       (vma->vm_end - vb->baddr), asize);
464 +                               return -ENOMEM;
465 +                       }
466 +                       physp = (vma->vm_pgoff << PAGE_SHIFT) +
467 +                                       (vb->baddr - vma->vm_start);
468 +                       err = omap_videobuf_dma_init_user(vb, physp, asize);
469 +                       spin_unlock(&fh->vbq_lock);
470 +                       if (0 != err)
471 +                               return err;
472 +               } else {
473 +                       err = videobuf_iolock(q, vb, NULL);
474 +                       /*
475 +                        * In case of user pointer mode, the get_user_pages
476 +                        * will fail if user has allocated less memory than
477 +                        * vb->size. But it is not error from resizer driver
478 +                        * point of view. so handled seperately
479 +                        */
480 +                       if ((err < 0) && (dma->nr_pages > 0))
481 +                               err = videobuf_dma_map(q, dma);
482 +                       if (err)
483 +                               goto buf_release;
484 +                       /*
485 +                        * Add one extra page for input buffer
486 +                        */
487 +                       if (0 == vb->i)
488 +                               err = omap_create_sg(q, dma);
489 +                       if (err)
490 +                               goto buf_release;
491 +                       spin_unlock(&fh->vbq_lock);
492 +               }
493 +               isp_addr = ispmmu_map_sg(dma->sglist, dma->sglen);
494 +               if (!isp_addr)
495 +                       err = -EIO;
496 +               else {
497 +                       if (vb->i) {
498 +                               rsz_conf_chan->buf_address[vb->i] = isp_addr;
499 +                               rsz_conf_chan->register_config.
500 +                                       rsz_sdr_outadd
501 +                                       = isp_addr;
502 +                               rsz_conf_chan->output_buf_index = vb->i;
503 +                       } else {
504 +                               rsz_conf_chan->buf_address[vb->i] = isp_addr;
505 +                               rsz_conf_chan->register_config.
506 +                                       rsz_sdr_inadd
507 +                                       = isp_addr;
508 +                               rsz_conf_chan->input_buf_index = vb->i;
509 +                               if (outsize < insize && rsz_conf_chan->
510 +                                               register_config.
511 +                                               rsz_sdr_outadd == 0) {
512                                         rsz_conf_chan->register_config.
513 -                                                       rsz_sdr_inadd
514 -                                                       = isp_addr;
515 -                                       rsz_conf_chan->input_buf_index = vb->i;
516 -                                       outsize = multipass->out_pitch *
517 -                                                       multipass->out_vsize;
518 -                                       insize = multipass->in_pitch *
519 -                                                       multipass->in_vsize;
520 -                                       if (outsize < insize) {
521 -                                               rsz_conf_chan->register_config.
522 -                                                               rsz_sdr_outadd
523 -                                                               = isp_addr;
524 -                                               rsz_conf_chan->
525 -                                                       output_buf_index =
526 -                                                       vb->i;
527 -                                       }
528 -
529 -                                       fh->isp_addr_read = isp_addr;
530 +                                               rsz_sdr_outadd
531 +                                               = isp_addr;
532 +                                       rsz_conf_chan->
533 +                                               output_buf_index =
534 +                                               vb->i;
535                                 }
536                         }
537                 }
538  
539 -       }
540 +       } else {
541 +               if(vb->i) {
542 +                       rsz_conf_chan->register_config.
543 +                               rsz_sdr_outadd =
544 +                                       rsz_conf_chan->buf_address[vb->i];
545 +                       rsz_conf_chan->output_buf_index = vb->i;
546 +               } else {
547 +                       rsz_conf_chan->register_config.
548 +                               rsz_sdr_inadd =
549 +                                       rsz_conf_chan->buf_address[vb->i];
550 +                       rsz_conf_chan->input_buf_index = vb->i;
551 +                       if(outsize < insize && rsz_conf_chan->
552 +                                       register_config.
553 +                                       rsz_sdr_outadd == 0) {
554 +                               rsz_conf_chan->register_config.
555 +                                       rsz_sdr_outadd
556 +                                       = rsz_conf_chan->buf_address[vb->i];
557 +                               rsz_conf_chan->output_buf_index = vb->i;
558 +                       }
559 +
560 +               }
561  
562 +       }
563         if (!err) {
564                 spin_lock(&fh->vbq_lock);
565                 vb->state = VIDEOBUF_PREPARED;
566                 spin_unlock(&fh->vbq_lock);
567 -               flush_cache_user_range(NULL, vb->baddr, (vb->baddr
568 -                                                               + vb->bsize));
569         } else
570                 rsz_vbq_release(q, vb);
571  
572 -out:
573 +       return err;
574 +buf_release:
575 +       spin_unlock(&fh->vbq_lock);
576 +       rsz_vbq_release(q, vb);
577         return err;
578  }
579  
580 @@ -1255,7 +1459,8 @@ err_enomem0:
581   **/
582  static int rsz_release(struct inode *inode, struct file *filp)
583  {
584 -       u32 timeout = 0;
585 +       int i;
586 +       unsigned int timeout = 0;
587         struct rsz_fh *fh = filp->private_data;
588         struct channel_config *rsz_conf_chan = fh->config;
589         struct rsz_params *params = fh->params;
590 @@ -1266,17 +1471,17 @@ static int rsz_release(struct inode *inode, struct file *filp)
591                 timeout++;
592                 schedule();
593         }
594 -       if (mutex_lock_interruptible(&device_config->reszwrap_mutex))
595 -               return -EINTR;
596 -       device_config->opened--;
597 -       mutex_unlock(&device_config->reszwrap_mutex);
598 -       /* This will Free memory allocated to the buffers,
599 -        * and flushes the queue
600 -        */
601 -       videobuf_queue_cancel(q);
602 -       fh->params = NULL;
603 -       fh->config = NULL;
604 +       /* Free memory allocated to the buffers */
605 +       for (i = 0 ; i < VIDEO_MAX_FRAME ; i++) {
606 +               struct videobuf_dmabuf *dma = NULL;
607 +               if (!q->bufs[i])
608 +                       continue;
609 +               dma = videobuf_to_dma(q->bufs[i]);
610 +               videobuf_dma_unmap(q, dma);
611 +               videobuf_dma_free(dma);
612 +       }
613  
614 +       videobuf_mmap_free(q);
615         fh->rsz_bufsize = 0;
616         filp->private_data = NULL;
617  
618 @@ -1286,7 +1491,8 @@ static int rsz_release(struct inode *inode, struct file *filp)
619         kfree(fh);
620  
621         isp_put();
622 -
623 +       fh->params = NULL;
624 +       fh->config = NULL;
625         return 0;
626  }
627  
628 @@ -1353,6 +1559,12 @@ static long rsz_unlocked_ioctl(struct file *file, unsigned int cmd,
629                                                         chanprotection_mutex))
630                         return -EINTR;
631                 ret = videobuf_reqbufs(&fh->vbq, (void *)&req_buf);
632 +               if (ret >= 0) {
633 +                       if (copy_to_user((struct v4l2_requestbuffers *)arg,
634 +                                               &req_buf, sizeof(struct
635 +                                               v4l2_requestbuffers)))
636 +                               return -EFAULT;
637 +               }
638                 mutex_unlock(&rsz_conf_chan->chanprotection_mutex);
639                 break;
640         }
641 @@ -1394,11 +1606,7 @@ static long rsz_unlocked_ioctl(struct file *file, unsigned int cmd,
642                                                 sizeof(struct rsz_params))) {
643                         return -EFAULT;
644                 }
645 -               if (mutex_lock_interruptible(&rsz_conf_chan->
646 -                                                       chanprotection_mutex))
647 -                       return -EINTR;
648 -               ret = rsz_set_params(fh->multipass, params, rsz_conf_chan);
649 -               mutex_unlock(&rsz_conf_chan->chanprotection_mutex);
650 +               ret = rsz_set_params(fh->multipass, fh->params, rsz_conf_chan);
651                 break;
652         }
653         case RSZ_G_PARAM:
654 @@ -1433,6 +1641,12 @@ static long rsz_unlocked_ioctl(struct file *file, unsigned int cmd,
655                 rsz_calculate_crop(rsz_conf_chan, (struct rsz_cropsize *)arg);
656                 break;
657  
658 +       case RSZ_S_EXP:
659 +               if (mutex_lock_interruptible(&rsz_conf_chan->chanprotection_mutex))
660 +                       return -EINTR;
661 +               rsz_conf_chan->register_config.sdr_req_exp = *((unsigned int *)arg);
662 +               mutex_unlock(&rsz_conf_chan->chanprotection_mutex);
663 +               break;
664         default:
665                 dev_err(rsz_device, "resizer_ioctl: Invalid Command Value");
666                 return -EINVAL;
667 @@ -1535,14 +1749,18 @@ static int __init omap_rsz_init(void)
668                                                                 "memory\n");
669                 return -ENOMEM;
670         }
671 -
672 +       device->extra_page_addr = __get_free_pages(GFP_KERNEL | GFP_DMA, 0);
673 +       if (!device->extra_page_addr) {
674 +               dev_err(rsz_device, OMAP_REZR_NAME ":Allocation failed. ");
675 +               kfree(device);
676 +               return -ENOMEM;
677 +       }
678         ret = alloc_chrdev_region(&dev, 0, 1, OMAP_REZR_NAME);
679         if (ret < 0) {
680                 dev_err(rsz_device, OMAP_REZR_NAME ": intialization failed. "
681                         "Could not allocate region "
682                         "for character device\n");
683 -               kfree(device);
684 -               return -ENODEV;
685 +               goto fail1;
686         }
687  
688         /* Register the driver in the kernel */
689 @@ -1608,6 +1826,8 @@ fail3:
690         cdev_del(&c_dev);
691  fail2:
692         unregister_chrdev_region(dev, 1);
693 +fail1:
694 +       free_pages((unsigned long)device->extra_page_addr, 0);
695         kfree(device);
696         return ret;
697  }
698 @@ -1623,6 +1843,7 @@ void __exit omap_rsz_exit(void)
699         platform_driver_unregister(&omap_resizer_driver);
700         cdev_del(&c_dev);
701         unregister_chrdev_region(dev, 1);
702 +       free_pages((unsigned long)device_config->extra_page_addr, 0);
703         kfree(device_config);
704  }
705  
706 diff --git a/include/linux/omap_resizer.h b/include/linux/omap_resizer.h
707 index 5ac0c88..47b8dd8 100644
708 --- a/include/linux/omap_resizer.h
709 +++ b/include/linux/omap_resizer.h
710 @@ -21,7 +21,7 @@
711  
712  /* ioctls definition */
713  #define RSZ_IOC_BASE           'R'
714 -#define RSZ_IOC_MAXNR          8
715 +#define RSZ_IOC_MAXNR          9
716  
717  /*Ioctl options which are to be passed while calling the ioctl*/
718  #define RSZ_REQBUF             _IOWR(RSZ_IOC_BASE, 1,\
719 @@ -33,6 +33,7 @@
720  #define RSZ_G_STATUS           _IOWR(RSZ_IOC_BASE, 6, struct rsz_status)
721  #define RSZ_QUEUEBUF           _IOWR(RSZ_IOC_BASE, 7, struct v4l2_buffer)
722  #define RSZ_GET_CROPSIZE       _IOWR(RSZ_IOC_BASE, 8, struct rsz_cropsize)
723 +#define RSZ_S_EXP              _IOWR(RSZ_IOC_BASE, 9, __s32)
724  
725  #define RSZ_INTYPE_YCBCR422_16BIT      0
726  #define RSZ_INTYPE_PLANAR_8BIT         1
727 -- 
728 1.6.2.4
729