summaryrefslogtreecommitdiff
path: root/recipes/linux/linux-omap-2.6.29/isp/standalone/0002-Resizer-bug-fixes-on-top-of-1.0.2-release.patch
diff options
context:
space:
mode:
Diffstat (limited to 'recipes/linux/linux-omap-2.6.29/isp/standalone/0002-Resizer-bug-fixes-on-top-of-1.0.2-release.patch')
-rw-r--r--recipes/linux/linux-omap-2.6.29/isp/standalone/0002-Resizer-bug-fixes-on-top-of-1.0.2-release.patch730
1 files changed, 730 insertions, 0 deletions
diff --git a/recipes/linux/linux-omap-2.6.29/isp/standalone/0002-Resizer-bug-fixes-on-top-of-1.0.2-release.patch b/recipes/linux/linux-omap-2.6.29/isp/standalone/0002-Resizer-bug-fixes-on-top-of-1.0.2-release.patch
new file mode 100644
index 0000000000..e14da9986a
--- /dev/null
+++ b/recipes/linux/linux-omap-2.6.29/isp/standalone/0002-Resizer-bug-fixes-on-top-of-1.0.2-release.patch
@@ -0,0 +1,730 @@
+From 20d79137ecaa6c7dad007d9ea1d7be5550db4839 Mon Sep 17 00:00:00 2001
+From: Vaibhav Hiremath <hvaibhav@ti.com>
+Date: Fri, 13 Feb 2009 15:40:25 +0530
+Subject: [PATCH 2/2] Resizer bug fixes on top of 1.0.2 release
+
+This commit contains resizer bug fixes on top of
+ PSP1.0.2 release -
+ - 4096 aligned address constraint
+ - workaround for extra page allocation for page aligned
+ size buffers
+
+Signed-off-by: Vaibhav Hiremath <hvaibhav@ti.com>
+---
+ drivers/media/video/isp/omap_resizer.c | 417 ++++++++++++++++++++++++--------
+ include/linux/omap_resizer.h | 3 +-
+ 2 files changed, 321 insertions(+), 99 deletions(-)
+
+diff --git a/drivers/media/video/isp/omap_resizer.c b/drivers/media/video/isp/omap_resizer.c
+index 54bc425..8059c70 100644
+--- a/drivers/media/video/isp/omap_resizer.c
++++ b/drivers/media/video/isp/omap_resizer.c
+@@ -28,6 +28,7 @@
+ #include <linux/platform_device.h>
+ #include <linux/io.h>
+ #include <linux/uaccess.h>
++#include <linux/pci.h>
+ #include <media/v4l2-dev.h>
+ #include <asm/cacheflush.h>
+
+@@ -76,6 +77,10 @@
+ #define MAX_COEF_COUNTER 16
+ #define COEFF_ADDRESS_OFFSET 0x04
+
++#define RSZ_DEF_REQ_EXP 0xE /* Default read operation expand
++ * for the Resizer driver; value
++ * taken from Davinci.
++ */
+ /* Global structure which contains information about number of channels
+ and protection variables */
+ struct device_params {
+@@ -85,6 +90,7 @@ struct device_params {
+ struct mutex reszwrap_mutex; /* Semaphore for array */
+
+ struct videobuf_queue_ops vbq_ops; /* videobuf queue operations */
++ unsigned long extra_page_addr;
+ };
+
+ /* Register mapped structure which contains the every register
+@@ -126,6 +132,9 @@ struct resizer_config {
+ u32 rsz_yehn; /* yehn(luma)register mapping
+ * variable.
+ */
++ u32 sdr_req_exp; /* Configuration for Non
++ * real time read expand
++ */
+ };
+
+ struct rsz_mult {
+@@ -179,6 +188,7 @@ struct channel_config {
+ * channel is busy or not
+ */
+ struct mutex chanprotection_mutex;
++ int buf_address[VIDEO_MAX_FRAME];
+ enum config_done config_state;
+ u8 input_buf_index;
+ u8 output_buf_index;
+@@ -200,8 +210,6 @@ struct rsz_fh {
+ struct videobuf_queue vbq;
+ struct device_params *device;
+
+- dma_addr_t isp_addr_read; /* Input/Output address */
+- dma_addr_t isp_addr_write; /* Input/Output address */
+ u32 rsz_bufsize; /* channel specific buffersize
+ */
+ };
+@@ -227,6 +235,10 @@ static int rsz_set_ratio(struct rsz_mult *multipass,
+ static void rsz_config_ratio(struct rsz_mult *multipass,
+ struct channel_config *rsz_conf_chan);
+
++static void inline rsz_set_exp(unsigned int exp)
++{
++ omap_writel(((exp & 0x3FF) << 10), OMAP3ISP_SBL_REG(0xF8));
++}
+ /**
+ * rsz_hardware_setup - Sets hardware configuration registers
+ * @rsz_conf_chan: Structure containing channel configuration
+@@ -271,12 +283,15 @@ static void rsz_hardware_setup(struct channel_config *rsz_conf_chan)
+ + coeffoffset));
+ coeffoffset = coeffoffset + COEFF_ADDRESS_OFFSET;
+ }
++ /* Configure the read expand register */
++ rsz_set_exp(rsz_conf_chan->register_config.sdr_req_exp);
+ }
+
+ /**
+ * rsz_start - Enables Resizer Wrapper
+ * @arg: Currently not used.
+- * @device: Structure containing ISP resizer wrapper global information
++ * @fh: File structure containing ISP resizer information specific to
++ * channel opened.
+ *
+ * Submits a resizing task specified by the rsz_resize structure. The call can
+ * either be blocked until the task is completed or returned immediately based
+@@ -292,12 +307,18 @@ int rsz_start(int *arg, struct rsz_fh *fh)
+ struct channel_config *rsz_conf_chan = fh->config;
+ struct rsz_mult *multipass = fh->multipass;
+ struct videobuf_queue *q = &fh->vbq;
++ struct videobuf_buffer *buf;
+ int ret;
+
+ if (rsz_conf_chan->config_state) {
+ dev_err(rsz_device, "State not configured \n");
+ goto err_einval;
+ }
++ if (!rsz_conf_chan->register_config.rsz_sdr_inadd ||
++ !rsz_conf_chan->register_config.rsz_sdr_outadd) {
++ dev_err(rsz_device, "address is null\n");
++ goto err_einval;
++ }
+
+ rsz_conf_chan->status = CHANNEL_BUSY;
+
+@@ -325,33 +346,22 @@ mult:
+ goto mult;
+ }
+
+- if (fh->isp_addr_read) {
+- ispmmu_unmap(fh->isp_addr_read);
+- fh->isp_addr_read = 0;
+- }
+- if (fh->isp_addr_write) {
+- ispmmu_unmap(fh->isp_addr_write);
+- fh->isp_addr_write = 0;
+- }
+-
+ rsz_conf_chan->status = CHANNEL_FREE;
+- q->bufs[rsz_conf_chan->input_buf_index]->state = VIDEOBUF_NEEDS_INIT;
+- q->bufs[rsz_conf_chan->output_buf_index]->state = VIDEOBUF_NEEDS_INIT;
+ rsz_conf_chan->register_config.rsz_sdr_outadd = 0;
+ rsz_conf_chan->register_config.rsz_sdr_inadd = 0;
+
+- /* Unmap and free the DMA memory allocated for buffers */
+- videobuf_dma_unmap(q, videobuf_to_dma(
+- q->bufs[rsz_conf_chan->input_buf_index]));
+- videobuf_dma_unmap(q, videobuf_to_dma(
+- q->bufs[rsz_conf_chan->output_buf_index]));
+- videobuf_dma_free(videobuf_to_dma(
+- q->bufs[rsz_conf_chan->input_buf_index]));
+- videobuf_dma_free(videobuf_to_dma(
+- q->bufs[rsz_conf_chan->output_buf_index]));
+-
+ isp_unset_callback(CBK_RESZ_DONE);
+
++ /* Empty the Videobuf queue which was filled during the qbuf */
++ buf = q->bufs[rsz_conf_chan->input_buf_index];
++ buf->state = VIDEOBUF_IDLE;
++ list_del(&buf->stream);
++ if (rsz_conf_chan->input_buf_index != rsz_conf_chan->output_buf_index) {
++ buf = q->bufs[rsz_conf_chan->output_buf_index];
++ buf->state = VIDEOBUF_IDLE;
++ list_del(&buf->stream);
++ }
++
+ return 0;
+ err_einval:
+ return -EINVAL;
+@@ -359,6 +369,8 @@ err_einval:
+
+ /**
+ * rsz_set_multipass - Set resizer multipass
++ * @multipass: Structure containing channel configuration
++ for multipass support
+ * @rsz_conf_chan: Structure containing channel configuration
+ *
+ * Returns always 0
+@@ -384,6 +396,8 @@ static int rsz_set_multipass(struct rsz_mult *multipass,
+
+ /**
+ * rsz_copy_data - Copy data
++ * @multipass: Structure containing channel configuration
++ for multipass support
+ * @params: Structure containing the Resizer Wrapper parameters
+ *
+ * Copy data
+@@ -413,6 +427,8 @@ static void rsz_copy_data(struct rsz_mult *multipass, struct rsz_params *params)
+
+ /**
+ * rsz_set_params - Set parameters for resizer wrapper
++ * @multipass: Structure containing channel configuration
++ for multipass support
+ * @params: Structure containing the Resizer Wrapper parameters
+ * @rsz_conf_chan: Structure containing channel configuration
+ *
+@@ -524,6 +540,8 @@ static int rsz_set_params(struct rsz_mult *multipass, struct rsz_params *params,
+ }
+
+ rsz_config_ratio(multipass, rsz_conf_chan);
++ /* Default value for read expand:Taken from Davinci */
++ rsz_conf_chan->register_config.sdr_req_exp = RSZ_DEF_REQ_EXP;
+
+ rsz_conf_chan->config_state = STATE_CONFIGURED;
+
+@@ -534,6 +552,8 @@ err_einval:
+
+ /**
+ * rsz_set_ratio - Set ratio
++ * @multipass: Structure containing channel configuration
++ for multipass support
+ * @rsz_conf_chan: Structure containing channel configuration
+ *
+ * Returns 0 if successful, -EINVAL if invalid output size, upscaling ratio is
+@@ -548,7 +568,8 @@ static int rsz_set_ratio(struct rsz_mult *multipass,
+
+ if ((multipass->out_hsize > MAX_IMAGE_WIDTH) ||
+ (multipass->out_vsize > MAX_IMAGE_WIDTH)) {
+- dev_err(rsz_device, "Invalid output size!");
++ dev_err(rsz_device, "Invalid output size! - %d", \
++ multipass->out_hsize);
+ goto err_einval;
+ }
+ if (multipass->cbilin) {
+@@ -758,6 +779,8 @@ err_einval:
+
+ /**
+ * rsz_config_ratio - Configure ratio
++ * @multipass: Structure containing channel configuration
++ for multipass support
+ * @rsz_conf_chan: Structure containing channel configuration
+ *
+ * Configure ratio
+@@ -789,6 +812,20 @@ static void rsz_config_ratio(struct rsz_mult *multipass,
+ ((vsize << ISPRSZ_IN_SIZE_VERT_SHIFT)
+ & ISPRSZ_IN_SIZE_VERT_MASK);
+
++ /* This is another workaround for the ISP-MMU translation fault.
++ For the parameters whose image size comes exactly to PAGE_SIZE
++ generates ISP-MMU translation fault. The root-cause is the equation
++ input width = (32*sph + (ow - 1)*hrsz + 16) >> 8 + 7
++ = (64*sph + (ow - 1)*hrsz + 32) >> 8 + 7
++ input height = (32*spv + (oh - 1)*vrsz + 16) >> 8 + 4
++ = (64*spv + (oh - 1)*vrsz + 32) >> 8 + 7
++
++ we are adjusting the input width to suit for Resizer module,
++ application should use this configuration henceforth.
++ */
++ multipass->in_hsize = hsize;
++ multipass->in_vsize = vsize;
++
+ for (coeffcounter = 0; coeffcounter < MAX_COEF_COUNTER;
+ coeffcounter++) {
+ if (multipass->num_htap) {
+@@ -990,24 +1027,15 @@ static void rsz_calculate_crop(struct channel_config *rsz_conf_chan,
+ static void rsz_vbq_release(struct videobuf_queue *q,
+ struct videobuf_buffer *vb)
+ {
+- int i;
+ struct rsz_fh *fh = q->priv_data;
++ struct videobuf_dmabuf *dma = NULL;
+
+- for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+- struct videobuf_dmabuf *dma = NULL;
+- if (!q->bufs[i])
+- continue;
+- if (q->bufs[i]->memory != V4L2_MEMORY_MMAP)
+- continue;
+- dma = videobuf_to_dma(q->bufs[i]);
+- videobuf_dma_unmap(q, dma);
+- videobuf_dma_free(dma);
+- }
++ dma = videobuf_to_dma(q->bufs[vb->i]);
++ videobuf_dma_unmap(q, dma);
++ videobuf_dma_free(dma);
++ ispmmu_unmap(fh->config->buf_address[vb->i]);
++ fh->config->buf_address[vb->i] = 0;
+
+- ispmmu_unmap(fh->isp_addr_read);
+- ispmmu_unmap(fh->isp_addr_write);
+- fh->isp_addr_read = 0;
+- fh->isp_addr_write = 0;
+ spin_lock(&fh->vbq_lock);
+ vb->state = VIDEOBUF_NEEDS_INIT;
+ spin_unlock(&fh->vbq_lock);
+@@ -1062,7 +1090,105 @@ err_einval:
+ spin_unlock(&fh->vbq_lock);
+ return -EINVAL;
+ }
++/*
++ * This function is work around for the videobuf_iolock API,
++ * for User memory allocated with ioremap (VM_IO flag) the API
++ * get_user_pages fails.
++ *
++ * To fulfill this requirement, we have completely ignored VM layer of
++ * Linux, and configuring the ISP MMU with physical address.
++ */
++static int omap_videobuf_dma_init_user(struct videobuf_buffer *vb,
++ unsigned long physp, unsigned long asize)
++{
++ struct videobuf_dmabuf *dma;
++ struct scatterlist *sglist;
++ unsigned long data, first, last;
++ int len, i = 0;
++
++ dma = videobuf_to_dma(vb);
++ data = vb->baddr;
++
++ first = (data & PAGE_MASK) >> PAGE_SHIFT;
++ last = ((data+asize-1) & PAGE_MASK) >> PAGE_SHIFT;
++ dma->offset = data & ~PAGE_MASK;
++ dma->nr_pages = last-first+1;
++
++ dma->direction = PCI_DMA_FROMDEVICE;
++ /*
++ * Allocate array of sglen + 1, to add entry of extra page
++ * for input buffer. Driver always uses 0th buffer as input buffer.
++ */
++ len = dma->nr_pages + (vb->i ? 0 : 1);
++ sglist = kcalloc(len, sizeof(*sglist), GFP_KERNEL);
++ if (NULL == sglist)
++ return -ENOMEM;
++
++ sglist[0].offset = 0;
++ sglist[0].length = PAGE_SIZE - dma->offset;
++ sglist[0].dma_address = (dma_addr_t)physp;
++ physp += sglist[0].length;
++ /*
++ * Iterate in a loop for the number of pages
++ */
++ for (i = 1; i < (len - (vb->i ? 0 : 1)); i++) {
++ sglist[i].offset = 0;
++ sglist[i].length = PAGE_SIZE;
++ sglist[i].dma_address = (dma_addr_t)physp;
++ physp += PAGE_SIZE;
++ }
++ if (0 == vb->i) {
++ sglist[i].offset = 0;
++ sglist[i].length = PAGE_SIZE;
++ sglist[i].dma_address =
++ (dma_addr_t)device_config->extra_page_addr;
++ }
++ dma->sglist = sglist;
++ dma->sglen = len;
++ return 0;
++
++ }
++/*
++ * This function is workaround for the issue, where ISP-MMU generated
++ * translation fault for specific params whose size is aligned to PAGE_SIZE.
++
++ * As a workaround we are padding one extra page for input buffer. This page
++ * we are allocating during init time and will not be released through-out
++ * life time of resizer driver. Please note that Resizer module only reads
++ * from this extra page.
++ */
++int omap_create_sg(struct videobuf_queue *q, struct videobuf_dmabuf *dma)
++{
++ struct scatterlist *sglist;
++ int sglen;
+
++ sglen = dma->sglen;
++ sglist = kcalloc(sglen + 1, sizeof(*sglist), GFP_KERNEL);
++ if (NULL == sglist)
++ return -ENOMEM;
++ /*
++ * Copy the sglist locally
++ */
++ memcpy(sglist, dma->sglist, sglen * sizeof(*sglist));
++ /*
++ * Release the old sglist, since we already copied it locally
++ */
++ videobuf_dma_unmap(q, dma);
++ /*
++ * Add extra entry to sglist to work with specific params, whose
++ * buffer address alined to PAGE_SIZE.
++ */
++ sglist[sglen].offset = 0;
++ sglist[sglen].length = PAGE_SIZE;
++ sglist[sglen].dma_address = (dma_addr_t)device_config->extra_page_addr;
++ sglen++;
++ /*
++ * Save the sglist for mapping to ISP-MMU space
++ */
++ dma->sglist = sglist;
++ dma->sglen = sglen;
++ return 0;
++}
+ /**
+ * rsz_vbq_prepare - Videobuffer is prepared and mmapped.
+ * @q: Structure containing the videobuffer queue file handle, and device
+@@ -1079,19 +1205,24 @@ static int rsz_vbq_prepare(struct videobuf_queue *q,
+ {
+ struct rsz_fh *fh = q->priv_data;
+ struct channel_config *rsz_conf_chan = fh->config;
+- struct rsz_mult *multipass = fh->multipass;
+ int err = 0;
+ unsigned int isp_addr, insize, outsize;
+- struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
+-
++ struct rsz_mult *multipass = fh->multipass;
+ spin_lock(&fh->vbq_lock);
+ if (vb->baddr) {
++ /* Check for 32 byte alignement */
++ if (vb->baddr != (vb->baddr & ~0x1F)) {
++ spin_unlock(&fh->vbq_lock);
++ dev_err(rsz_device, "Buffer address should be aligned \
++ to 32 byte\n");
++ return -EINVAL;
++ }
+ vb->size = fh->rsz_bufsize;
+ vb->bsize = fh->rsz_bufsize;
+ } else {
+ spin_unlock(&fh->vbq_lock);
+ dev_err(rsz_device, "No user buffer allocated\n");
+- goto out;
++ return -EINVAL;
+ }
+ if (vb->i) {
+ vb->width = fh->params->out_hsize;
+@@ -1103,55 +1234,128 @@ static int rsz_vbq_prepare(struct videobuf_queue *q,
+
+ vb->field = field;
+ spin_unlock(&fh->vbq_lock);
++ /*
++ * Calculate input and output sizes, will be used while mapping
++ * user pages
++ */
++ outsize = multipass->out_pitch * multipass->out_vsize;
++ insize = multipass->in_pitch * multipass->in_vsize;
+
+ if (vb->state == VIDEOBUF_NEEDS_INIT) {
+- err = videobuf_iolock(q, vb, NULL);
+- if (!err) {
+- isp_addr = ispmmu_map_sg(dma->sglist, dma->sglen);
+- if (!isp_addr)
+- err = -EIO;
+- else {
+- if (vb->i) {
+- rsz_conf_chan->register_config.
+- rsz_sdr_outadd
+- = isp_addr;
+- fh->isp_addr_write = isp_addr;
+- rsz_conf_chan->output_buf_index = vb->i;
+- } else {
++ struct videobuf_dmabuf *dma;
++ struct vm_area_struct *vma;
++ spin_lock(&fh->vbq_lock);
++ dma = videobuf_to_dma(vb);
++ vma = find_vma(current->mm, vb->baddr);
++ if ((vma) && (vma->vm_flags & VM_IO) && (vma->vm_pgoff)) {
++ /* This will catch ioremaped buffers to the kernel.
++ * It gives two possible scenarios -
++ * - Driver allocates buffer using either
++ * dma_alloc_coherent or get_free_pages,
++ * and maps to user space using
++ * io_remap_pfn_range/remap_pfn_range
++ * - Drivers maps memory outside from Linux using
++ * io_remap
++ */
++ unsigned long physp = 0, asize;
++ asize = vb->i ? outsize : insize;
++ if ((vb->baddr + asize) > vma->vm_end) {
++ spin_unlock(&fh->vbq_lock);
++ dev_err(rsz_device, "User Buffer Allocation:" \
++ "err=%lu[%lu]\n",\
++ (vma->vm_end - vb->baddr), asize);
++ return -ENOMEM;
++ }
++ physp = (vma->vm_pgoff << PAGE_SHIFT) +
++ (vb->baddr - vma->vm_start);
++ err = omap_videobuf_dma_init_user(vb, physp, asize);
++ spin_unlock(&fh->vbq_lock);
++ if (0 != err)
++ return err;
++ } else {
++ err = videobuf_iolock(q, vb, NULL);
++ /*
++ * In case of user pointer mode, the get_user_pages
++ * will fail if user has allocated less memory than
++ * vb->size. But it is not error from resizer driver
++ * point of view. so handled seperately
++ */
++ if ((err < 0) && (dma->nr_pages > 0))
++ err = videobuf_dma_map(q, dma);
++ if (err)
++ goto buf_release;
++ /*
++ * Add one extra page for input buffer
++ */
++ if (0 == vb->i)
++ err = omap_create_sg(q, dma);
++ if (err)
++ goto buf_release;
++ spin_unlock(&fh->vbq_lock);
++ }
++ isp_addr = ispmmu_map_sg(dma->sglist, dma->sglen);
++ if (!isp_addr)
++ err = -EIO;
++ else {
++ if (vb->i) {
++ rsz_conf_chan->buf_address[vb->i] = isp_addr;
++ rsz_conf_chan->register_config.
++ rsz_sdr_outadd
++ = isp_addr;
++ rsz_conf_chan->output_buf_index = vb->i;
++ } else {
++ rsz_conf_chan->buf_address[vb->i] = isp_addr;
++ rsz_conf_chan->register_config.
++ rsz_sdr_inadd
++ = isp_addr;
++ rsz_conf_chan->input_buf_index = vb->i;
++ if (outsize < insize && rsz_conf_chan->
++ register_config.
++ rsz_sdr_outadd == 0) {
+ rsz_conf_chan->register_config.
+- rsz_sdr_inadd
+- = isp_addr;
+- rsz_conf_chan->input_buf_index = vb->i;
+- outsize = multipass->out_pitch *
+- multipass->out_vsize;
+- insize = multipass->in_pitch *
+- multipass->in_vsize;
+- if (outsize < insize) {
+- rsz_conf_chan->register_config.
+- rsz_sdr_outadd
+- = isp_addr;
+- rsz_conf_chan->
+- output_buf_index =
+- vb->i;
+- }
+-
+- fh->isp_addr_read = isp_addr;
++ rsz_sdr_outadd
++ = isp_addr;
++ rsz_conf_chan->
++ output_buf_index =
++ vb->i;
+ }
+ }
+ }
+
+- }
++ } else {
++ if(vb->i) {
++ rsz_conf_chan->register_config.
++ rsz_sdr_outadd =
++ rsz_conf_chan->buf_address[vb->i];
++ rsz_conf_chan->output_buf_index = vb->i;
++ } else {
++ rsz_conf_chan->register_config.
++ rsz_sdr_inadd =
++ rsz_conf_chan->buf_address[vb->i];
++ rsz_conf_chan->input_buf_index = vb->i;
++ if(outsize < insize && rsz_conf_chan->
++ register_config.
++ rsz_sdr_outadd == 0) {
++ rsz_conf_chan->register_config.
++ rsz_sdr_outadd
++ = rsz_conf_chan->buf_address[vb->i];
++ rsz_conf_chan->output_buf_index = vb->i;
++ }
++
++ }
+
++ }
+ if (!err) {
+ spin_lock(&fh->vbq_lock);
+ vb->state = VIDEOBUF_PREPARED;
+ spin_unlock(&fh->vbq_lock);
+- flush_cache_user_range(NULL, vb->baddr, (vb->baddr
+- + vb->bsize));
+ } else
+ rsz_vbq_release(q, vb);
+
+-out:
++ return err;
++buf_release:
++ spin_unlock(&fh->vbq_lock);
++ rsz_vbq_release(q, vb);
+ return err;
+ }
+
+@@ -1255,7 +1459,8 @@ err_enomem0:
+ **/
+ static int rsz_release(struct inode *inode, struct file *filp)
+ {
+- u32 timeout = 0;
++ int i;
++ unsigned int timeout = 0;
+ struct rsz_fh *fh = filp->private_data;
+ struct channel_config *rsz_conf_chan = fh->config;
+ struct rsz_params *params = fh->params;
+@@ -1266,17 +1471,17 @@ static int rsz_release(struct inode *inode, struct file *filp)
+ timeout++;
+ schedule();
+ }
+- if (mutex_lock_interruptible(&device_config->reszwrap_mutex))
+- return -EINTR;
+- device_config->opened--;
+- mutex_unlock(&device_config->reszwrap_mutex);
+- /* This will Free memory allocated to the buffers,
+- * and flushes the queue
+- */
+- videobuf_queue_cancel(q);
+- fh->params = NULL;
+- fh->config = NULL;
++ /* Free memory allocated to the buffers */
++ for (i = 0 ; i < VIDEO_MAX_FRAME ; i++) {
++ struct videobuf_dmabuf *dma = NULL;
++ if (!q->bufs[i])
++ continue;
++ dma = videobuf_to_dma(q->bufs[i]);
++ videobuf_dma_unmap(q, dma);
++ videobuf_dma_free(dma);
++ }
+
++ videobuf_mmap_free(q);
+ fh->rsz_bufsize = 0;
+ filp->private_data = NULL;
+
+@@ -1286,7 +1491,8 @@ static int rsz_release(struct inode *inode, struct file *filp)
+ kfree(fh);
+
+ isp_put();
+-
++ fh->params = NULL;
++ fh->config = NULL;
+ return 0;
+ }
+
+@@ -1353,6 +1559,12 @@ static long rsz_unlocked_ioctl(struct file *file, unsigned int cmd,
+ chanprotection_mutex))
+ return -EINTR;
+ ret = videobuf_reqbufs(&fh->vbq, (void *)&req_buf);
++ if (ret >= 0) {
++ if (copy_to_user((struct v4l2_requestbuffers *)arg,
++ &req_buf, sizeof(struct
++ v4l2_requestbuffers)))
++ return -EFAULT;
++ }
+ mutex_unlock(&rsz_conf_chan->chanprotection_mutex);
+ break;
+ }
+@@ -1394,11 +1606,7 @@ static long rsz_unlocked_ioctl(struct file *file, unsigned int cmd,
+ sizeof(struct rsz_params))) {
+ return -EFAULT;
+ }
+- if (mutex_lock_interruptible(&rsz_conf_chan->
+- chanprotection_mutex))
+- return -EINTR;
+- ret = rsz_set_params(fh->multipass, params, rsz_conf_chan);
+- mutex_unlock(&rsz_conf_chan->chanprotection_mutex);
++ ret = rsz_set_params(fh->multipass, fh->params, rsz_conf_chan);
+ break;
+ }
+ case RSZ_G_PARAM:
+@@ -1433,6 +1641,12 @@ static long rsz_unlocked_ioctl(struct file *file, unsigned int cmd,
+ rsz_calculate_crop(rsz_conf_chan, (struct rsz_cropsize *)arg);
+ break;
+
++ case RSZ_S_EXP:
++ if (mutex_lock_interruptible(&rsz_conf_chan->chanprotection_mutex))
++ return -EINTR;
++ rsz_conf_chan->register_config.sdr_req_exp = *((unsigned int *)arg);
++ mutex_unlock(&rsz_conf_chan->chanprotection_mutex);
++ break;
+ default:
+ dev_err(rsz_device, "resizer_ioctl: Invalid Command Value");
+ return -EINVAL;
+@@ -1535,14 +1749,18 @@ static int __init omap_rsz_init(void)
+ "memory\n");
+ return -ENOMEM;
+ }
+-
++ device->extra_page_addr = __get_free_pages(GFP_KERNEL | GFP_DMA, 0);
++ if (!device->extra_page_addr) {
++ dev_err(rsz_device, OMAP_REZR_NAME ":Allocation failed. ");
++ kfree(device);
++ return -ENOMEM;
++ }
+ ret = alloc_chrdev_region(&dev, 0, 1, OMAP_REZR_NAME);
+ if (ret < 0) {
+ dev_err(rsz_device, OMAP_REZR_NAME ": intialization failed. "
+ "Could not allocate region "
+ "for character device\n");
+- kfree(device);
+- return -ENODEV;
++ goto fail1;
+ }
+
+ /* Register the driver in the kernel */
+@@ -1608,6 +1826,8 @@ fail3:
+ cdev_del(&c_dev);
+ fail2:
+ unregister_chrdev_region(dev, 1);
++fail1:
++ free_pages((unsigned long)device->extra_page_addr, 0);
+ kfree(device);
+ return ret;
+ }
+@@ -1623,6 +1843,7 @@ void __exit omap_rsz_exit(void)
+ platform_driver_unregister(&omap_resizer_driver);
+ cdev_del(&c_dev);
+ unregister_chrdev_region(dev, 1);
++ free_pages((unsigned long)device_config->extra_page_addr, 0);
+ kfree(device_config);
+ }
+
+diff --git a/include/linux/omap_resizer.h b/include/linux/omap_resizer.h
+index 5ac0c88..47b8dd8 100644
+--- a/include/linux/omap_resizer.h
++++ b/include/linux/omap_resizer.h
+@@ -21,7 +21,7 @@
+
+ /* ioctls definition */
+ #define RSZ_IOC_BASE 'R'
+-#define RSZ_IOC_MAXNR 8
++#define RSZ_IOC_MAXNR 9
+
+ /*Ioctl options which are to be passed while calling the ioctl*/
+ #define RSZ_REQBUF _IOWR(RSZ_IOC_BASE, 1,\
+@@ -33,6 +33,7 @@
+ #define RSZ_G_STATUS _IOWR(RSZ_IOC_BASE, 6, struct rsz_status)
+ #define RSZ_QUEUEBUF _IOWR(RSZ_IOC_BASE, 7, struct v4l2_buffer)
+ #define RSZ_GET_CROPSIZE _IOWR(RSZ_IOC_BASE, 8, struct rsz_cropsize)
++#define RSZ_S_EXP _IOWR(RSZ_IOC_BASE, 9, __s32)
+
+ #define RSZ_INTYPE_YCBCR422_16BIT 0
+ #define RSZ_INTYPE_PLANAR_8BIT 1
+--
+1.6.0.3
+