/** * prev_get_status - Get status of ISP preview module * @status: Structure containing the busy state. * * Checks if the ISP preview module is busy. * * Returns 0 if successful, or -EINVAL if the status parameter is invalid. **/ static int prev_get_status(struct prev_status *status) { if (!status) { dev_err(prev_dev, "get_status: invalid parameter\n"); return -EINVAL; } status->hw_busy = (char)isppreview_busy(); return 0; }
/** * prev2resz_ioctl - I/O control function for device */ static int prev2resz_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct prev2resz_fhdl *fh = file->private_data; long rval = 0; if ((_IOC_TYPE(cmd) != PREV2RESZ_IOC_BASE) && (_IOC_TYPE(cmd) != 'M') && (cmd < BASE_VIDIOC_PRIVATE)) { dev_err(p2r_device, "Bad command value.\n"); return -EFAULT; } if (_IOC_DIR(cmd) & _IOC_READ) rval = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd)); else if (_IOC_DIR(cmd) & _IOC_WRITE) rval = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd)); if (rval) { dev_err(p2r_device, "Access denied\n"); return -EFAULT; } switch (cmd) { case PREV2RESZ_REQBUF: { struct v4l2_requestbuffers v4l2_req; if (copy_from_user(&v4l2_req, (void *)arg, sizeof(struct v4l2_requestbuffers))) return -EIO; if (v4l2_req.type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { if (videobuf_reqbufs(&fh->src_vbq, &v4l2_req) < 0) return -EINVAL; } else if (v4l2_req.type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { if (videobuf_reqbufs(&fh->dst_vbq, &v4l2_req) < 0) return -EINVAL; } if (copy_to_user((void *)arg, &v4l2_req, sizeof(struct v4l2_requestbuffers))) return -EIO; break; } case PREV2RESZ_QUERYBUF: { struct v4l2_buffer v4l2_buf; if (copy_from_user(&v4l2_buf, (void *)arg, sizeof(struct v4l2_buffer))) return -EIO; if (v4l2_buf.type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { if (videobuf_querybuf(&fh->src_vbq, &v4l2_buf) < 0) return -EINVAL; } else if (v4l2_buf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { if (videobuf_querybuf(&fh->dst_vbq, &v4l2_buf) < 0) return -EINVAL; } if (copy_to_user((void *)arg, &v4l2_buf, sizeof(struct v4l2_buffer))) return -EIO; break; } case PREV2RESZ_QUEUEBUF: { struct v4l2_buffer v4l2_buf; if (copy_from_user(&v4l2_buf, (void *)arg, sizeof(struct v4l2_buffer))) return -EIO; if (v4l2_buf.type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { if (videobuf_qbuf(&fh->src_vbq, &v4l2_buf) < 0) return -EINVAL; } else if (v4l2_buf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { if (videobuf_qbuf(&fh->dst_vbq, &v4l2_buf) < 0) return -EINVAL; } if (copy_to_user((void *)arg, &v4l2_buf, sizeof(struct v4l2_buffer))) return -EIO; break; } case PREV2RESZ_SET_CONFIG: if (copy_from_user(&fh->pipe, (void *)arg, sizeof(fh->pipe))) return -EIO; if (prev2resz_ioc_set_config(fh) < 0) return -EINVAL; if (copy_to_user((void *)arg, &fh->pipe, sizeof(fh->pipe))) return -EIO; break; case PREV2RESZ_GET_CONFIG: if (copy_to_user((void *)arg, &fh->pipe, sizeof(fh->pipe))) return -EIO; break; case PREV2RESZ_RUN_ENGINE: if (file->f_flags & O_NONBLOCK) { if (isppreview_busy(fh->isp_prev)) return -EBUSY; if (ispresizer_busy(fh->isp_resz)) return -EBUSY; } if (prev2resz_ioc_run_engine(fh) < 0) return -EINVAL; break; case PREV2RESZ_GET_STATUS: { struct prev2resz_status *status = (struct prev2resz_status *)arg; status->prv_busy = isppreview_busy(fh->isp_prev); status->rsz_busy = ispresizer_busy(fh->isp_resz); break; } case VIDIOC_QUERYCAP: { struct v4l2_capability v4l2_cap; if (copy_from_user(&v4l2_cap, (void *)arg, sizeof(struct v4l2_capability))) return -EIO; strcpy(v4l2_cap.driver, "omap3wrapper"); strcpy(v4l2_cap.card, "omap3wrapper/prev-resz"); v4l2_cap.version = 1.0;; v4l2_cap.capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE; if (copy_to_user((void *)arg, &v4l2_cap, sizeof(struct v4l2_capability))) return -EIO; break; } case VIDIOC_PRIVATE_ISP_PRV_CFG: if (isppreview_config(fh->isp_prev, (void *)arg)) return -EIO; break; default: dev_err(p2r_device, "IOC: Invalid Command Value!\n"); return -EINVAL; } return 0; }
int isp_process_mem_data(struct isp_mem_data *data) { int i; int ret = -1; struct isp_mem_data *ppreview_user = \ (struct isp_mem_data *)data; struct isp_mem_data preview_param; u32 input_buffer_size, output_buffer_size; u32 input_nr_pages, output_nr_pages; struct page **input_pages = NULL; struct page **output_pages = NULL; unsigned long isp_addr_in = 0; unsigned long isp_addr_out = 0; unsigned long isp_addr_tmp = 0; unsigned long timeout; struct isp_mem_resize_data resizer_param; u16 cropadjust = 0; if (ppreview_user == NULL) { printk(KERN_ERR "ISP_PROC_ERR: Invalid user data!\n"); return -EINVAL; } memcpy(&preview_param, ppreview_user, \ sizeof(struct isp_mem_data)); DPRINTK_ISPPROC("input(%d-%d) - output(%d-%d)\n", preview_param.input_width, preview_param.input_height, preview_param.output_width, preview_param.output_height); DPRINTK_ISPPROC("start(%d-%d) - end(%d-%d)\n", preview_param.left, preview_param.top, preview_param.crop_width, preview_param.crop_height); if (ppreview_user->datain == 0 || ppreview_user->dataout == 0) return -EINVAL; isppreview_enable(0); ispresizer_enable(0); timeout = jiffies + msecs_to_jiffies(200); while (isppreview_busy() || ispresizer_busy()) { if (time_after(jiffies, timeout)) return -EINVAL; msleep(1); } isppreview_save_context(); ispresizer_save_context(); isppreview_free(); ispresizer_free(); isppreview_request(); ispresizer_request(); /* set data path before configuring modules. */ isppreview_update_datapath(PRV_RAW_MEM, PREVIEW_MEM); ispresizer_config_datapath(RSZ_MEM_YUV, 0); ret = isppreview_try_size(preview_param.input_width, preview_param.input_height, &preview_param.output_width, &preview_param.output_height); if (ret < 0) goto exit_cleanup; ret = isppreview_config_size(preview_param.input_width, preview_param.input_height, preview_param.output_width, preview_param.output_height); if (ret < 0) goto exit_cleanup; input_buffer_size = ALIGN_TO(ppreview_user->input_width* \ ppreview_user->input_height*2 , 0x100); input_pages = map_user_memory_to_kernel(preview_param.datain, input_buffer_size, &input_nr_pages); if (input_pages == NULL) { ret = -EINVAL; printk(KERN_ERR "ISP_PROC_ERR: memory allocation failed\n"); goto exit_cleanup; } output_buffer_size = ALIGN_TO(ppreview_user->output_width* \ ppreview_user->output_height*2, 0x1000); output_pages = map_user_memory_to_kernel(preview_param.dataout, output_buffer_size, &output_nr_pages); if (output_pages == NULL) { ret = -EINVAL; printk(KERN_ERR "ISP_PROC_ERR: memory allocation failed\n"); goto exit_cleanup; } for (i = 0; i < output_nr_pages; ++i) flush_dcache_page(output_pages[i]); isp_addr_in = ispmmu_vmap_pages(input_pages, input_nr_pages); if (IS_ERR((void *)isp_addr_in)) { isp_addr_in = 0; ret = -EINVAL; printk(KERN_ERR "ISP_PROC_ERR: isp mmu map failed\n"); goto exit_cleanup; } isp_addr_out = ispmmu_vmap_pages(output_pages, output_nr_pages); if (IS_ERR((void *)isp_addr_out)) { isp_addr_out = 0; ret = -EINVAL; printk(KERN_ERR "ISP_PROC_ERR: isp mmu map failed\n"); goto exit_cleanup; } /* This buffer must be allocated and mapped to the ISP MMU previously. */ isp_addr_tmp = isp_tmp_buf_addr(); if (isp_addr_tmp == 0) { printk(KERN_ERR "ISP_PROC_ERR: Invalid isp tmp buffer address!\n"); goto exit_cleanup; } isppreview_config_inlineoffset(ppreview_user->input_width * 2); isppreview_set_inaddr(isp_addr_in); isppreview_set_outaddr(isp_addr_tmp); resizer_param.input_width = preview_param.output_width; resizer_param.input_height = preview_param.output_height; resizer_param.output_width = ppreview_user->output_width; resizer_param.output_height = ppreview_user->output_height; if ((preview_param.left == 0) && (preview_param.top == 0)) { ret = ispresizer_try_size(&resizer_param.input_width, &resizer_param.input_height, &resizer_param.output_width, &resizer_param.output_height); if (ret < 0) goto exit_cleanup; ret = ispresizer_config_size(resizer_param.input_width, resizer_param.input_height, resizer_param.output_width, resizer_param.output_height); if (ret < 0) goto exit_cleanup; ispresizer_set_inaddr(isp_addr_tmp); } else { ispresizer_trycrop(preview_param.left, preview_param.top, preview_param.crop_width, preview_param.crop_height, resizer_param.output_width, resizer_param.output_height); ispresizer_applycrop(); /* account for pixel loss when using crop*/ if ((preview_param.input_height > preview_param.output_height) && (preview_param.top > 16)) cropadjust = 8; else cropadjust = 0; /* pixel alignment in 32bit space, vertical must be 0 per TRM */ isp_reg_writel(((preview_param.left%16) << ISPRSZ_IN_START_HORZ_ST_SHIFT) | (0 << ISPRSZ_IN_START_VERT_ST_SHIFT), OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_START); /* Align input address for cropping, per TRM */ ispresizer_set_inaddr(isp_addr_tmp - (resizer_param.input_width*2*cropadjust) + (preview_param.top*resizer_param.input_width*2) + ((preview_param.left/16)*32)); } ispresizer_set_outaddr(isp_addr_out); ispresizer_config_inlineoffset( ALIGN_TO(resizer_param.input_width*2, 32)); if (isp_set_callback(CBK_PREV_DONE, prv_isr, (void *) NULL, (void *)NULL) != 0) { printk(KERN_ERR "ISP_PROC_ERR: Error setting PRV callback.\n"); goto exit_cleanup; } if (isp_set_callback(CBK_RESZ_DONE, rsz_isr, (void *) NULL, (void *)NULL) != 0) { printk(KERN_ERR "ISP_PROC_ERR: Error setting RSZ callback.\n"); goto exit_cleanup; } isp_reg_writel(0xFFFFFFFF, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS); isp_wfc.done = 0; /* start preview engine. */ isppreview_enable(1); ret = wait_for_completion_timeout(&isp_wfc, msecs_to_jiffies(1000)); if (!ret) { isppreview_enable(0); ispresizer_enable(0); } timeout = jiffies + msecs_to_jiffies(50); while (ispresizer_busy()) { msleep(5); if (time_after(jiffies, timeout)) { printk(KERN_ERR "ISP_RESZ_ERR: Resizer still busy"); break; } } isp_reg_writel(0xFFFFFFFF, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS); isp_unset_callback(CBK_PREV_DONE); isp_unset_callback(CBK_RESZ_DONE); exit_cleanup: isppreview_restore_context(); ispresizer_restore_context(); if (isp_addr_in != 0) ispmmu_vunmap(isp_addr_in); if (isp_addr_out != 0) ispmmu_vunmap(isp_addr_out); if (input_pages != NULL) { unmap_user_memory_from_kernel(input_pages, input_nr_pages); kfree(input_pages); } if (output_pages != NULL) { unmap_user_memory_from_kernel(output_pages, output_nr_pages); kfree(output_pages); } DPRINTK_ISPPROC("exit.\n"); return ret; }