/** * flush_dcache_ibuffer - Flushes dcache corresponding to a internal buffer. * @ibuffer: Pointer to internal buffer to be flushed from cache. * * No return value. **/ void flush_dcache_ibuffer(struct hp3a_internal_buffer *ibuffer) { int i; int nr_pages = NR_PAGES(ibuffer->user_addr, (unsigned long)ibuffer->buffer_size); for (i = 0; i < nr_pages; ++i) { flush_dcache_page(ibuffer->pages[i]); } }
/** * unmap_buffers_from_kernel - Unmaps memory from isp and kernel address space. * @ibuffer: Pointer to internal buffer to be unmapped. * * No return value. **/ void unmap_buffer_from_kernel(struct hp3a_internal_buffer *ibuffer) { if (ibuffer->isp_addr) { #if defined(CONFIG_VIDEO_OLDOMAP3) if (ispmmu_unmap(ibuffer->isp_addr) != 0) { printk(KERN_ERR "Error unmapping from ispmmu (0x%x)!", (unsigned int)ibuffer->isp_addr); } #else ispmmu_vunmap(ibuffer->isp_addr); #endif ibuffer->isp_addr = 0; } if (ibuffer->pages != NULL && ibuffer->buffer_size > 0) { unmap_user_memory(ibuffer->pages, NR_PAGES(ibuffer->user_addr, ibuffer->buffer_size)); kfree(ibuffer->pages); ibuffer->pages = NULL; } }
/** * hp3a_unlocked_ioctl - I/O control function for hp3a module * @inode: Inode structure associated with the Resizer Wrapper. * @file: File structure associated with the hp3a driver. * @cmd: Type of command to execute. * @arg: Argument to send to requested command. * * Returns 0 if successful, -1 if bad command passed or access is denied, * -EFAULT if copy_from_user() or copy_to_user() fails, * -EINVAL if parameter validation fails or parameter structure is not present. **/ long hp3a_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int ret = -1; struct hp3a_fh *fh = file->private_data; struct hp3a_dev *device = fh->device; if (unlikely(_IOC_TYPE(cmd) != OMAP3_HP3A_MAGIC)) { dev_err(device->dev, "Bad command value (%d)\n", cmd); return -ENOTTY; } switch (cmd) { /* * Gets all statistics. */ case HP3A_G_STATISTICS: { struct hp3a_statistics statistics; ret = hp3a_collect_statistics(&statistics); if (SUCCEEDED(ret)) { if (copy_to_user((struct hp3a_statistics *)arg, &statistics, sizeof(struct hp3a_statistics)) != 0) ret = -EFAULT; } break; } /* * Set sensor parameters. */ case HP3A_S_SENSOR_PARAM: { struct hp3a_sensor_param sensor_param; if (copy_from_user(&sensor_param, (struct hp3a_sensor_param *)arg, sizeof(struct hp3a_sensor_param)) == 0) { ret = hp3a_set_sensor_param(&sensor_param, fh); } else { ret = -EFAULT; } break; } /* * Set ISP/Hardpipe parameters */ case HP3A_S_HARDPIPE_PARAM: { struct hp3a_hardpipe_param hpipe_param; if (copy_from_user(&hpipe_param, (struct hp3a_hardpipe_param *)arg, sizeof(struct hp3a_hardpipe_param)) == 0) { ret = hp3a_set_hardpipe_param(&hpipe_param, fh); } else { ret = -EFAULT; } break; } /* * Queue histogram stat buffer. */ case HP3A_QBUF_HISTQ: { struct hp3a_internal_buffer *ibuffer; int index = (int)arg; if (index < fh->buffer_count && index > -1) { ibuffer = &(fh->buffers[index]); ret = hp3a_enqueue_irqsave(&g_tc.hist_stat_queue, &ibuffer); } break; } /* * Queue AF stat buffer. */ case HP3A_QBUF_AFQ: { struct hp3a_internal_buffer *ibuffer; int index = (int)arg; if (index < fh->buffer_count && index > -1) { ibuffer = &(fh->buffers[index]); if (ibuffer->isp_addr == 0) { ibuffer->isp_addr = ispmmu_map_pages(ibuffer->pages, NR_PAGES((unsigned long)ibuffer->user_addr, ibuffer->buffer_size)); if (ibuffer->isp_addr == 0) { dev_err(device->dev , \ "isp mmu fail to map memory\n"); return -EFAULT; } } flush_dcache_ibuffer(ibuffer); ret = hp3a_enqueue_irqsave(&g_tc.af_stat_queue, &ibuffer); } break; } /* * Queue RAW frame buffer. */ case HP3A_QBUF_RAWQ: { struct hp3a_internal_buffer *ibuffer ; int index = (int)arg; if (index < fh->buffer_count && index > -1) { ibuffer = &(fh->buffers[index]); if (ibuffer->isp_addr == 0) { ibuffer->isp_addr = ispmmu_map_pages(ibuffer->pages, NR_PAGES((unsigned long)ibuffer->user_addr, ibuffer->buffer_size)); if (ibuffer->isp_addr == 0) { dev_err(device->dev , \ "isp mmu fail to map memory\n"); return -EFAULT; } } ret = hp3a_enqueue_irqsave(&g_tc.raw_frame_queue, &ibuffer); } break; } /* * Request for array of buffer placeholders. */ case HP3A_REQBUF: { struct hp3a_request_bufffers req_buf; int i; if (copy_from_user(&req_buf, (struct hp3a_request_bufffers *)arg, sizeof(struct hp3a_request_bufffers)) == 0) { ret = -1; if (req_buf.count > 0) { fh->buffers = kzalloc(req_buf.count * \ sizeof(struct hp3a_internal_buffer), GFP_KERNEL); if (fh->buffers) { fh->buffer_count = req_buf.count; for (i = 0; i < fh->buffer_count; ++i) fh->buffers[i].index = i; ret = 0; } } } else { ret = -EFAULT; } break; } /* * Install buffers into internal list and map to kernel space. */ case HP3A_INSTALL_BUF: { struct hp3a_buffer buffer; if (copy_from_user(&buffer, (struct hp3a_buffer *)arg, sizeof(struct hp3a_buffer)) == 0) { ret = -1; if (buffer.index >= 0 && buffer.index < fh->buffer_count) { if (fh->buffers[buffer.index].buffer_size == 0) { ret = map_user_to_kernel(&buffer, &(fh->buffers[buffer.index])); } } } else { ret = -EFAULT; } break; } /* * Remove buffers from internal list and unmap from kernel space. */ case HP3A_UNINSTALL_BUF: { struct hp3a_buffer buffer; if (copy_from_user(&buffer, (struct hp3a_buffer *)arg, sizeof(struct hp3a_buffer)) == 0) { ret = -1; if (buffer.index >= 0 && buffer.index < fh->buffer_count) { if (fh->buffers[buffer.index].buffer_size && fh->buffers[buffer.index].pages) { unmap_buffer_from_kernel( &(fh->buffers[buffer.index])); ret = 0; } } } else { ret = -EFAULT; } break; } /* * Configure Histogram hardware. */ case HP3A_CONFIG_HIST: { struct hp3a_histogram_config config; if (copy_from_user(&config, (struct hp3a_histogram_config *)arg, sizeof(struct hp3a_histogram_config)) == 0) { ret = hp3a_config_histogram(&config, fh); } else { ret = -EFAULT; } break; } /* * Configure Histogram hardware. */ case HP3A_CONFIG_AF: { struct hp3a_af_config config; if (copy_from_user(&config, (struct hp3a_af_config *)arg, sizeof(struct hp3a_af_config)) == 0) { ret = hp3a_config_af(&config, fh); } else { ret = -EFAULT; } break; } /* * Configure raw hardware. */ case HP3A_CONFIG_RAW: { struct hp3a_raw_config config; if (copy_from_user(&config, (struct hp3a_raw_config *)arg, sizeof(struct hp3a_raw_config)) == 0) { ret = hp3a_configure_raw(&config); if (SUCCEEDED(ret)) { if (copy_to_user((struct hp3a_raw_config *)arg, &config, sizeof(struct hp3a_raw_config)) != 0) ret = -EFAULT; } } else { ret = -EFAULT; } break; } /* * Flush histogram queue. */ case HP3A_FLUSH_HISTQ: { hp3a_flush_queue_irqsave(&g_tc.hist_stat_queue); ret = 0; break; } /* * Flush AF queue. */ case HP3A_FLUSH_AFQ: { hp3a_flush_queue_irqsave(&g_tc.af_stat_queue); ret = 0; break; } /* * Flush RAW queue. */ case HP3A_FLUSH_RAWQ: { hp3a_flush_queue_irqsave(&g_tc.raw_frame_queue); ret = 0; break; } /* * Set V4L2 device specific index. */ case HP3A_S_V4L2_DEV_INDEX: { fh->v4l2_dev = (int)arg; g_tc.default_v4l2_dev = fh->v4l2_dev; ret = 0; break; } /* * Read ISP registers. */ case HP3A_READ_ISP_REGS: { ret = hp3a_read_ispregs_to_user((struct hp3a_reg_page *)arg); break; } case HP3A_READ_ISP_REG: { ret = hp3a_read_ispreg_to_user((struct hp3a_reg *)arg); break; } default: break; } return (long)ret; }