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