18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/**************************************************************************** 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Filename: cpia2_v4l.c 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright 2001, STMicrolectronics, Inc. 78c2ecf20Sopenharmony_ci * Contact: steve.miller@st.com 88c2ecf20Sopenharmony_ci * Copyright 2001,2005, Scott J. Bertin <scottbertin@yahoo.com> 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Description: 118c2ecf20Sopenharmony_ci * This is a USB driver for CPia2 based video cameras. 128c2ecf20Sopenharmony_ci * The infrastructure of this driver is based on the cpia usb driver by 138c2ecf20Sopenharmony_ci * Jochen Scharrlach and Johannes Erdfeldt. 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * Stripped of 2.4 stuff ready for main kernel submit by 168c2ecf20Sopenharmony_ci * Alan Cox <alan@lxorguk.ukuu.org.uk> 178c2ecf20Sopenharmony_ci ****************************************************************************/ 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#define CPIA_VERSION "3.0.1" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <linux/module.h> 228c2ecf20Sopenharmony_ci#include <linux/time.h> 238c2ecf20Sopenharmony_ci#include <linux/sched.h> 248c2ecf20Sopenharmony_ci#include <linux/slab.h> 258c2ecf20Sopenharmony_ci#include <linux/init.h> 268c2ecf20Sopenharmony_ci#include <linux/videodev2.h> 278c2ecf20Sopenharmony_ci#include <linux/stringify.h> 288c2ecf20Sopenharmony_ci#include <media/v4l2-ioctl.h> 298c2ecf20Sopenharmony_ci#include <media/v4l2-event.h> 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#include "cpia2.h" 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic int video_nr = -1; 348c2ecf20Sopenharmony_cimodule_param(video_nr, int, 0); 358c2ecf20Sopenharmony_ciMODULE_PARM_DESC(video_nr, "video device to register (0=/dev/video0, etc)"); 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic int buffer_size = 68 * 1024; 388c2ecf20Sopenharmony_cimodule_param(buffer_size, int, 0); 398c2ecf20Sopenharmony_ciMODULE_PARM_DESC(buffer_size, "Size for each frame buffer in bytes (default 68k)"); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic int num_buffers = 3; 428c2ecf20Sopenharmony_cimodule_param(num_buffers, int, 0); 438c2ecf20Sopenharmony_ciMODULE_PARM_DESC(num_buffers, "Number of frame buffers (1-" 448c2ecf20Sopenharmony_ci __stringify(VIDEO_MAX_FRAME) ", default 3)"); 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic int alternate = DEFAULT_ALT; 478c2ecf20Sopenharmony_cimodule_param(alternate, int, 0); 488c2ecf20Sopenharmony_ciMODULE_PARM_DESC(alternate, "USB Alternate (" __stringify(USBIF_ISO_1) "-" 498c2ecf20Sopenharmony_ci __stringify(USBIF_ISO_6) ", default " 508c2ecf20Sopenharmony_ci __stringify(DEFAULT_ALT) ")"); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic int flicker_mode; 538c2ecf20Sopenharmony_cimodule_param(flicker_mode, int, 0); 548c2ecf20Sopenharmony_ciMODULE_PARM_DESC(flicker_mode, "Flicker frequency (0 (disabled), " __stringify(50) " or " 558c2ecf20Sopenharmony_ci __stringify(60) ", default 0)"); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ciMODULE_AUTHOR("Steve Miller (STMicroelectronics) <steve.miller@st.com>"); 588c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("V4L-driver for STMicroelectronics CPiA2 based cameras"); 598c2ecf20Sopenharmony_ciMODULE_SUPPORTED_DEVICE("video"); 608c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 618c2ecf20Sopenharmony_ciMODULE_VERSION(CPIA_VERSION); 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci#define ABOUT "V4L-Driver for Vision CPiA2 based cameras" 648c2ecf20Sopenharmony_ci#define CPIA2_CID_USB_ALT (V4L2_CID_USER_BASE | 0xf000) 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci/****************************************************************************** 678c2ecf20Sopenharmony_ci * 688c2ecf20Sopenharmony_ci * cpia2_open 698c2ecf20Sopenharmony_ci * 708c2ecf20Sopenharmony_ci *****************************************************************************/ 718c2ecf20Sopenharmony_cistatic int cpia2_open(struct file *file) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci struct camera_data *cam = video_drvdata(file); 748c2ecf20Sopenharmony_ci int retval; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&cam->v4l2_lock)) 778c2ecf20Sopenharmony_ci return -ERESTARTSYS; 788c2ecf20Sopenharmony_ci retval = v4l2_fh_open(file); 798c2ecf20Sopenharmony_ci if (retval) 808c2ecf20Sopenharmony_ci goto open_unlock; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci if (v4l2_fh_is_singular_file(file)) { 838c2ecf20Sopenharmony_ci if (cpia2_allocate_buffers(cam)) { 848c2ecf20Sopenharmony_ci v4l2_fh_release(file); 858c2ecf20Sopenharmony_ci retval = -ENOMEM; 868c2ecf20Sopenharmony_ci goto open_unlock; 878c2ecf20Sopenharmony_ci } 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci /* reset the camera */ 908c2ecf20Sopenharmony_ci if (cpia2_reset_camera(cam) < 0) { 918c2ecf20Sopenharmony_ci v4l2_fh_release(file); 928c2ecf20Sopenharmony_ci retval = -EIO; 938c2ecf20Sopenharmony_ci goto open_unlock; 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci cam->APP_len = 0; 978c2ecf20Sopenharmony_ci cam->COM_len = 0; 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci cpia2_dbg_dump_registers(cam); 1018c2ecf20Sopenharmony_ciopen_unlock: 1028c2ecf20Sopenharmony_ci mutex_unlock(&cam->v4l2_lock); 1038c2ecf20Sopenharmony_ci return retval; 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci/****************************************************************************** 1078c2ecf20Sopenharmony_ci * 1088c2ecf20Sopenharmony_ci * cpia2_close 1098c2ecf20Sopenharmony_ci * 1108c2ecf20Sopenharmony_ci *****************************************************************************/ 1118c2ecf20Sopenharmony_cistatic int cpia2_close(struct file *file) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci struct video_device *dev = video_devdata(file); 1148c2ecf20Sopenharmony_ci struct camera_data *cam = video_get_drvdata(dev); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci mutex_lock(&cam->v4l2_lock); 1178c2ecf20Sopenharmony_ci if (video_is_registered(&cam->vdev) && v4l2_fh_is_singular_file(file)) { 1188c2ecf20Sopenharmony_ci cpia2_usb_stream_stop(cam); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci /* save camera state for later open */ 1218c2ecf20Sopenharmony_ci cpia2_save_camera_state(cam); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci cpia2_set_low_power(cam); 1248c2ecf20Sopenharmony_ci cpia2_free_buffers(cam); 1258c2ecf20Sopenharmony_ci } 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci if (cam->stream_fh == file->private_data) { 1288c2ecf20Sopenharmony_ci cam->stream_fh = NULL; 1298c2ecf20Sopenharmony_ci cam->mmapped = 0; 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci mutex_unlock(&cam->v4l2_lock); 1328c2ecf20Sopenharmony_ci return v4l2_fh_release(file); 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci/****************************************************************************** 1368c2ecf20Sopenharmony_ci * 1378c2ecf20Sopenharmony_ci * cpia2_v4l_read 1388c2ecf20Sopenharmony_ci * 1398c2ecf20Sopenharmony_ci *****************************************************************************/ 1408c2ecf20Sopenharmony_cistatic ssize_t cpia2_v4l_read(struct file *file, char __user *buf, size_t count, 1418c2ecf20Sopenharmony_ci loff_t *off) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci struct camera_data *cam = video_drvdata(file); 1448c2ecf20Sopenharmony_ci int noblock = file->f_flags&O_NONBLOCK; 1458c2ecf20Sopenharmony_ci ssize_t ret; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci if(!cam) 1488c2ecf20Sopenharmony_ci return -EINVAL; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&cam->v4l2_lock)) 1518c2ecf20Sopenharmony_ci return -ERESTARTSYS; 1528c2ecf20Sopenharmony_ci ret = cpia2_read(cam, buf, count, noblock); 1538c2ecf20Sopenharmony_ci mutex_unlock(&cam->v4l2_lock); 1548c2ecf20Sopenharmony_ci return ret; 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci/****************************************************************************** 1598c2ecf20Sopenharmony_ci * 1608c2ecf20Sopenharmony_ci * cpia2_v4l_poll 1618c2ecf20Sopenharmony_ci * 1628c2ecf20Sopenharmony_ci *****************************************************************************/ 1638c2ecf20Sopenharmony_cistatic __poll_t cpia2_v4l_poll(struct file *filp, struct poll_table_struct *wait) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci struct camera_data *cam = video_drvdata(filp); 1668c2ecf20Sopenharmony_ci __poll_t res; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci mutex_lock(&cam->v4l2_lock); 1698c2ecf20Sopenharmony_ci res = cpia2_poll(cam, filp, wait); 1708c2ecf20Sopenharmony_ci mutex_unlock(&cam->v4l2_lock); 1718c2ecf20Sopenharmony_ci return res; 1728c2ecf20Sopenharmony_ci} 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic int sync(struct camera_data *cam, int frame_nr) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci struct framebuf *frame = &cam->buffers[frame_nr]; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci while (1) { 1808c2ecf20Sopenharmony_ci if (frame->status == FRAME_READY) 1818c2ecf20Sopenharmony_ci return 0; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci if (!cam->streaming) { 1848c2ecf20Sopenharmony_ci frame->status = FRAME_READY; 1858c2ecf20Sopenharmony_ci frame->length = 0; 1868c2ecf20Sopenharmony_ci return 0; 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci mutex_unlock(&cam->v4l2_lock); 1908c2ecf20Sopenharmony_ci wait_event_interruptible(cam->wq_stream, 1918c2ecf20Sopenharmony_ci !cam->streaming || 1928c2ecf20Sopenharmony_ci frame->status == FRAME_READY); 1938c2ecf20Sopenharmony_ci mutex_lock(&cam->v4l2_lock); 1948c2ecf20Sopenharmony_ci if (signal_pending(current)) 1958c2ecf20Sopenharmony_ci return -ERESTARTSYS; 1968c2ecf20Sopenharmony_ci if (!video_is_registered(&cam->vdev)) 1978c2ecf20Sopenharmony_ci return -ENOTTY; 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci/****************************************************************************** 2028c2ecf20Sopenharmony_ci * 2038c2ecf20Sopenharmony_ci * ioctl_querycap 2048c2ecf20Sopenharmony_ci * 2058c2ecf20Sopenharmony_ci * V4L2 device capabilities 2068c2ecf20Sopenharmony_ci * 2078c2ecf20Sopenharmony_ci *****************************************************************************/ 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistatic int cpia2_querycap(struct file *file, void *fh, struct v4l2_capability *vc) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci struct camera_data *cam = video_drvdata(file); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci strscpy(vc->driver, "cpia2", sizeof(vc->driver)); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci if (cam->params.pnp_id.product == 0x151) 2168c2ecf20Sopenharmony_ci strscpy(vc->card, "QX5 Microscope", sizeof(vc->card)); 2178c2ecf20Sopenharmony_ci else 2188c2ecf20Sopenharmony_ci strscpy(vc->card, "CPiA2 Camera", sizeof(vc->card)); 2198c2ecf20Sopenharmony_ci switch (cam->params.pnp_id.device_type) { 2208c2ecf20Sopenharmony_ci case DEVICE_STV_672: 2218c2ecf20Sopenharmony_ci strcat(vc->card, " (672/"); 2228c2ecf20Sopenharmony_ci break; 2238c2ecf20Sopenharmony_ci case DEVICE_STV_676: 2248c2ecf20Sopenharmony_ci strcat(vc->card, " (676/"); 2258c2ecf20Sopenharmony_ci break; 2268c2ecf20Sopenharmony_ci default: 2278c2ecf20Sopenharmony_ci strcat(vc->card, " (XXX/"); 2288c2ecf20Sopenharmony_ci break; 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci switch (cam->params.version.sensor_flags) { 2318c2ecf20Sopenharmony_ci case CPIA2_VP_SENSOR_FLAGS_404: 2328c2ecf20Sopenharmony_ci strcat(vc->card, "404)"); 2338c2ecf20Sopenharmony_ci break; 2348c2ecf20Sopenharmony_ci case CPIA2_VP_SENSOR_FLAGS_407: 2358c2ecf20Sopenharmony_ci strcat(vc->card, "407)"); 2368c2ecf20Sopenharmony_ci break; 2378c2ecf20Sopenharmony_ci case CPIA2_VP_SENSOR_FLAGS_409: 2388c2ecf20Sopenharmony_ci strcat(vc->card, "409)"); 2398c2ecf20Sopenharmony_ci break; 2408c2ecf20Sopenharmony_ci case CPIA2_VP_SENSOR_FLAGS_410: 2418c2ecf20Sopenharmony_ci strcat(vc->card, "410)"); 2428c2ecf20Sopenharmony_ci break; 2438c2ecf20Sopenharmony_ci case CPIA2_VP_SENSOR_FLAGS_500: 2448c2ecf20Sopenharmony_ci strcat(vc->card, "500)"); 2458c2ecf20Sopenharmony_ci break; 2468c2ecf20Sopenharmony_ci default: 2478c2ecf20Sopenharmony_ci strcat(vc->card, "XXX)"); 2488c2ecf20Sopenharmony_ci break; 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci if (usb_make_path(cam->dev, vc->bus_info, sizeof(vc->bus_info)) <0) 2528c2ecf20Sopenharmony_ci memset(vc->bus_info,0, sizeof(vc->bus_info)); 2538c2ecf20Sopenharmony_ci return 0; 2548c2ecf20Sopenharmony_ci} 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci/****************************************************************************** 2578c2ecf20Sopenharmony_ci * 2588c2ecf20Sopenharmony_ci * ioctl_input 2598c2ecf20Sopenharmony_ci * 2608c2ecf20Sopenharmony_ci * V4L2 input get/set/enumerate 2618c2ecf20Sopenharmony_ci * 2628c2ecf20Sopenharmony_ci *****************************************************************************/ 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_cistatic int cpia2_enum_input(struct file *file, void *fh, struct v4l2_input *i) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci if (i->index) 2678c2ecf20Sopenharmony_ci return -EINVAL; 2688c2ecf20Sopenharmony_ci strscpy(i->name, "Camera", sizeof(i->name)); 2698c2ecf20Sopenharmony_ci i->type = V4L2_INPUT_TYPE_CAMERA; 2708c2ecf20Sopenharmony_ci return 0; 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_cistatic int cpia2_g_input(struct file *file, void *fh, unsigned int *i) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci *i = 0; 2768c2ecf20Sopenharmony_ci return 0; 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_cistatic int cpia2_s_input(struct file *file, void *fh, unsigned int i) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci return i ? -EINVAL : 0; 2828c2ecf20Sopenharmony_ci} 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci/****************************************************************************** 2858c2ecf20Sopenharmony_ci * 2868c2ecf20Sopenharmony_ci * ioctl_enum_fmt 2878c2ecf20Sopenharmony_ci * 2888c2ecf20Sopenharmony_ci * V4L2 format enumerate 2898c2ecf20Sopenharmony_ci * 2908c2ecf20Sopenharmony_ci *****************************************************************************/ 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_cistatic int cpia2_enum_fmt_vid_cap(struct file *file, void *fh, 2938c2ecf20Sopenharmony_ci struct v4l2_fmtdesc *f) 2948c2ecf20Sopenharmony_ci{ 2958c2ecf20Sopenharmony_ci if (f->index > 1) 2968c2ecf20Sopenharmony_ci return -EINVAL; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci if (f->index == 0) 2998c2ecf20Sopenharmony_ci f->pixelformat = V4L2_PIX_FMT_MJPEG; 3008c2ecf20Sopenharmony_ci else 3018c2ecf20Sopenharmony_ci f->pixelformat = V4L2_PIX_FMT_JPEG; 3028c2ecf20Sopenharmony_ci return 0; 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci/****************************************************************************** 3068c2ecf20Sopenharmony_ci * 3078c2ecf20Sopenharmony_ci * ioctl_try_fmt 3088c2ecf20Sopenharmony_ci * 3098c2ecf20Sopenharmony_ci * V4L2 format try 3108c2ecf20Sopenharmony_ci * 3118c2ecf20Sopenharmony_ci *****************************************************************************/ 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_cistatic int cpia2_try_fmt_vid_cap(struct file *file, void *fh, 3148c2ecf20Sopenharmony_ci struct v4l2_format *f) 3158c2ecf20Sopenharmony_ci{ 3168c2ecf20Sopenharmony_ci struct camera_data *cam = video_drvdata(file); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG && 3198c2ecf20Sopenharmony_ci f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG) 3208c2ecf20Sopenharmony_ci return -EINVAL; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci f->fmt.pix.field = V4L2_FIELD_NONE; 3238c2ecf20Sopenharmony_ci f->fmt.pix.bytesperline = 0; 3248c2ecf20Sopenharmony_ci f->fmt.pix.sizeimage = cam->frame_size; 3258c2ecf20Sopenharmony_ci f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci switch (cpia2_match_video_size(f->fmt.pix.width, f->fmt.pix.height)) { 3288c2ecf20Sopenharmony_ci case VIDEOSIZE_VGA: 3298c2ecf20Sopenharmony_ci f->fmt.pix.width = 640; 3308c2ecf20Sopenharmony_ci f->fmt.pix.height = 480; 3318c2ecf20Sopenharmony_ci break; 3328c2ecf20Sopenharmony_ci case VIDEOSIZE_CIF: 3338c2ecf20Sopenharmony_ci f->fmt.pix.width = 352; 3348c2ecf20Sopenharmony_ci f->fmt.pix.height = 288; 3358c2ecf20Sopenharmony_ci break; 3368c2ecf20Sopenharmony_ci case VIDEOSIZE_QVGA: 3378c2ecf20Sopenharmony_ci f->fmt.pix.width = 320; 3388c2ecf20Sopenharmony_ci f->fmt.pix.height = 240; 3398c2ecf20Sopenharmony_ci break; 3408c2ecf20Sopenharmony_ci case VIDEOSIZE_288_216: 3418c2ecf20Sopenharmony_ci f->fmt.pix.width = 288; 3428c2ecf20Sopenharmony_ci f->fmt.pix.height = 216; 3438c2ecf20Sopenharmony_ci break; 3448c2ecf20Sopenharmony_ci case VIDEOSIZE_256_192: 3458c2ecf20Sopenharmony_ci f->fmt.pix.width = 256; 3468c2ecf20Sopenharmony_ci f->fmt.pix.height = 192; 3478c2ecf20Sopenharmony_ci break; 3488c2ecf20Sopenharmony_ci case VIDEOSIZE_224_168: 3498c2ecf20Sopenharmony_ci f->fmt.pix.width = 224; 3508c2ecf20Sopenharmony_ci f->fmt.pix.height = 168; 3518c2ecf20Sopenharmony_ci break; 3528c2ecf20Sopenharmony_ci case VIDEOSIZE_192_144: 3538c2ecf20Sopenharmony_ci f->fmt.pix.width = 192; 3548c2ecf20Sopenharmony_ci f->fmt.pix.height = 144; 3558c2ecf20Sopenharmony_ci break; 3568c2ecf20Sopenharmony_ci case VIDEOSIZE_QCIF: 3578c2ecf20Sopenharmony_ci default: 3588c2ecf20Sopenharmony_ci f->fmt.pix.width = 176; 3598c2ecf20Sopenharmony_ci f->fmt.pix.height = 144; 3608c2ecf20Sopenharmony_ci break; 3618c2ecf20Sopenharmony_ci } 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci return 0; 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci/****************************************************************************** 3678c2ecf20Sopenharmony_ci * 3688c2ecf20Sopenharmony_ci * ioctl_set_fmt 3698c2ecf20Sopenharmony_ci * 3708c2ecf20Sopenharmony_ci * V4L2 format set 3718c2ecf20Sopenharmony_ci * 3728c2ecf20Sopenharmony_ci *****************************************************************************/ 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_cistatic int cpia2_s_fmt_vid_cap(struct file *file, void *_fh, 3758c2ecf20Sopenharmony_ci struct v4l2_format *f) 3768c2ecf20Sopenharmony_ci{ 3778c2ecf20Sopenharmony_ci struct camera_data *cam = video_drvdata(file); 3788c2ecf20Sopenharmony_ci int err, frame; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci err = cpia2_try_fmt_vid_cap(file, _fh, f); 3818c2ecf20Sopenharmony_ci if(err != 0) 3828c2ecf20Sopenharmony_ci return err; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci cam->pixelformat = f->fmt.pix.pixelformat; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci /* NOTE: This should be set to 1 for MJPEG, but some apps don't handle 3878c2ecf20Sopenharmony_ci * the missing Huffman table properly. */ 3888c2ecf20Sopenharmony_ci cam->params.compression.inhibit_htables = 0; 3898c2ecf20Sopenharmony_ci /*f->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG;*/ 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci /* we set the video window to something smaller or equal to what 3928c2ecf20Sopenharmony_ci * is requested by the user??? 3938c2ecf20Sopenharmony_ci */ 3948c2ecf20Sopenharmony_ci DBG("Requested width = %d, height = %d\n", 3958c2ecf20Sopenharmony_ci f->fmt.pix.width, f->fmt.pix.height); 3968c2ecf20Sopenharmony_ci if (f->fmt.pix.width != cam->width || 3978c2ecf20Sopenharmony_ci f->fmt.pix.height != cam->height) { 3988c2ecf20Sopenharmony_ci cam->width = f->fmt.pix.width; 3998c2ecf20Sopenharmony_ci cam->height = f->fmt.pix.height; 4008c2ecf20Sopenharmony_ci cam->params.roi.width = f->fmt.pix.width; 4018c2ecf20Sopenharmony_ci cam->params.roi.height = f->fmt.pix.height; 4028c2ecf20Sopenharmony_ci cpia2_set_format(cam); 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci for (frame = 0; frame < cam->num_frames; ++frame) { 4068c2ecf20Sopenharmony_ci if (cam->buffers[frame].status == FRAME_READING) 4078c2ecf20Sopenharmony_ci if ((err = sync(cam, frame)) < 0) 4088c2ecf20Sopenharmony_ci return err; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci cam->buffers[frame].status = FRAME_EMPTY; 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci return 0; 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci/****************************************************************************** 4178c2ecf20Sopenharmony_ci * 4188c2ecf20Sopenharmony_ci * ioctl_get_fmt 4198c2ecf20Sopenharmony_ci * 4208c2ecf20Sopenharmony_ci * V4L2 format get 4218c2ecf20Sopenharmony_ci * 4228c2ecf20Sopenharmony_ci *****************************************************************************/ 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_cistatic int cpia2_g_fmt_vid_cap(struct file *file, void *fh, 4258c2ecf20Sopenharmony_ci struct v4l2_format *f) 4268c2ecf20Sopenharmony_ci{ 4278c2ecf20Sopenharmony_ci struct camera_data *cam = video_drvdata(file); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci f->fmt.pix.width = cam->width; 4308c2ecf20Sopenharmony_ci f->fmt.pix.height = cam->height; 4318c2ecf20Sopenharmony_ci f->fmt.pix.pixelformat = cam->pixelformat; 4328c2ecf20Sopenharmony_ci f->fmt.pix.field = V4L2_FIELD_NONE; 4338c2ecf20Sopenharmony_ci f->fmt.pix.bytesperline = 0; 4348c2ecf20Sopenharmony_ci f->fmt.pix.sizeimage = cam->frame_size; 4358c2ecf20Sopenharmony_ci f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci return 0; 4388c2ecf20Sopenharmony_ci} 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci/****************************************************************************** 4418c2ecf20Sopenharmony_ci * 4428c2ecf20Sopenharmony_ci * ioctl_cropcap 4438c2ecf20Sopenharmony_ci * 4448c2ecf20Sopenharmony_ci * V4L2 query cropping capabilities 4458c2ecf20Sopenharmony_ci * NOTE: cropping is currently disabled 4468c2ecf20Sopenharmony_ci * 4478c2ecf20Sopenharmony_ci *****************************************************************************/ 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_cistatic int cpia2_g_selection(struct file *file, void *fh, 4508c2ecf20Sopenharmony_ci struct v4l2_selection *s) 4518c2ecf20Sopenharmony_ci{ 4528c2ecf20Sopenharmony_ci struct camera_data *cam = video_drvdata(file); 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 4558c2ecf20Sopenharmony_ci return -EINVAL; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci switch (s->target) { 4588c2ecf20Sopenharmony_ci case V4L2_SEL_TGT_CROP_BOUNDS: 4598c2ecf20Sopenharmony_ci case V4L2_SEL_TGT_CROP_DEFAULT: 4608c2ecf20Sopenharmony_ci s->r.left = 0; 4618c2ecf20Sopenharmony_ci s->r.top = 0; 4628c2ecf20Sopenharmony_ci s->r.width = cam->width; 4638c2ecf20Sopenharmony_ci s->r.height = cam->height; 4648c2ecf20Sopenharmony_ci break; 4658c2ecf20Sopenharmony_ci default: 4668c2ecf20Sopenharmony_ci return -EINVAL; 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci return 0; 4698c2ecf20Sopenharmony_ci} 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_cistruct framerate_info { 4728c2ecf20Sopenharmony_ci int value; 4738c2ecf20Sopenharmony_ci struct v4l2_fract period; 4748c2ecf20Sopenharmony_ci}; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_cistatic const struct framerate_info framerate_controls[] = { 4778c2ecf20Sopenharmony_ci { CPIA2_VP_FRAMERATE_6_25, { 4, 25 } }, 4788c2ecf20Sopenharmony_ci { CPIA2_VP_FRAMERATE_7_5, { 2, 15 } }, 4798c2ecf20Sopenharmony_ci { CPIA2_VP_FRAMERATE_12_5, { 2, 25 } }, 4808c2ecf20Sopenharmony_ci { CPIA2_VP_FRAMERATE_15, { 1, 15 } }, 4818c2ecf20Sopenharmony_ci { CPIA2_VP_FRAMERATE_25, { 1, 25 } }, 4828c2ecf20Sopenharmony_ci { CPIA2_VP_FRAMERATE_30, { 1, 30 } }, 4838c2ecf20Sopenharmony_ci}; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_cistatic int cpia2_g_parm(struct file *file, void *fh, struct v4l2_streamparm *p) 4868c2ecf20Sopenharmony_ci{ 4878c2ecf20Sopenharmony_ci struct camera_data *cam = video_drvdata(file); 4888c2ecf20Sopenharmony_ci struct v4l2_captureparm *cap = &p->parm.capture; 4898c2ecf20Sopenharmony_ci int i; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 4928c2ecf20Sopenharmony_ci return -EINVAL; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci cap->capability = V4L2_CAP_TIMEPERFRAME; 4958c2ecf20Sopenharmony_ci cap->readbuffers = cam->num_frames; 4968c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(framerate_controls); i++) 4978c2ecf20Sopenharmony_ci if (cam->params.vp_params.frame_rate == framerate_controls[i].value) { 4988c2ecf20Sopenharmony_ci cap->timeperframe = framerate_controls[i].period; 4998c2ecf20Sopenharmony_ci break; 5008c2ecf20Sopenharmony_ci } 5018c2ecf20Sopenharmony_ci return 0; 5028c2ecf20Sopenharmony_ci} 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_cistatic int cpia2_s_parm(struct file *file, void *fh, struct v4l2_streamparm *p) 5058c2ecf20Sopenharmony_ci{ 5068c2ecf20Sopenharmony_ci struct camera_data *cam = video_drvdata(file); 5078c2ecf20Sopenharmony_ci struct v4l2_captureparm *cap = &p->parm.capture; 5088c2ecf20Sopenharmony_ci struct v4l2_fract tpf = cap->timeperframe; 5098c2ecf20Sopenharmony_ci int max = ARRAY_SIZE(framerate_controls) - 1; 5108c2ecf20Sopenharmony_ci int ret; 5118c2ecf20Sopenharmony_ci int i; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci ret = cpia2_g_parm(file, fh, p); 5148c2ecf20Sopenharmony_ci if (ret || !tpf.denominator || !tpf.numerator) 5158c2ecf20Sopenharmony_ci return ret; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci /* Maximum 15 fps for this model */ 5188c2ecf20Sopenharmony_ci if (cam->params.pnp_id.device_type == DEVICE_STV_672 && 5198c2ecf20Sopenharmony_ci cam->params.version.sensor_flags == CPIA2_VP_SENSOR_FLAGS_500) 5208c2ecf20Sopenharmony_ci max -= 2; 5218c2ecf20Sopenharmony_ci for (i = 0; i <= max; i++) { 5228c2ecf20Sopenharmony_ci struct v4l2_fract f1 = tpf; 5238c2ecf20Sopenharmony_ci struct v4l2_fract f2 = framerate_controls[i].period; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci f1.numerator *= f2.denominator; 5268c2ecf20Sopenharmony_ci f2.numerator *= f1.denominator; 5278c2ecf20Sopenharmony_ci if (f1.numerator >= f2.numerator) 5288c2ecf20Sopenharmony_ci break; 5298c2ecf20Sopenharmony_ci } 5308c2ecf20Sopenharmony_ci if (i > max) 5318c2ecf20Sopenharmony_ci i = max; 5328c2ecf20Sopenharmony_ci cap->timeperframe = framerate_controls[i].period; 5338c2ecf20Sopenharmony_ci return cpia2_set_fps(cam, framerate_controls[i].value); 5348c2ecf20Sopenharmony_ci} 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_cistatic const struct { 5378c2ecf20Sopenharmony_ci u32 width; 5388c2ecf20Sopenharmony_ci u32 height; 5398c2ecf20Sopenharmony_ci} cpia2_framesizes[] = { 5408c2ecf20Sopenharmony_ci { 640, 480 }, 5418c2ecf20Sopenharmony_ci { 352, 288 }, 5428c2ecf20Sopenharmony_ci { 320, 240 }, 5438c2ecf20Sopenharmony_ci { 288, 216 }, 5448c2ecf20Sopenharmony_ci { 256, 192 }, 5458c2ecf20Sopenharmony_ci { 224, 168 }, 5468c2ecf20Sopenharmony_ci { 192, 144 }, 5478c2ecf20Sopenharmony_ci { 176, 144 }, 5488c2ecf20Sopenharmony_ci}; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_cistatic int cpia2_enum_framesizes(struct file *file, void *fh, 5518c2ecf20Sopenharmony_ci struct v4l2_frmsizeenum *fsize) 5528c2ecf20Sopenharmony_ci{ 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci if (fsize->pixel_format != V4L2_PIX_FMT_MJPEG && 5558c2ecf20Sopenharmony_ci fsize->pixel_format != V4L2_PIX_FMT_JPEG) 5568c2ecf20Sopenharmony_ci return -EINVAL; 5578c2ecf20Sopenharmony_ci if (fsize->index >= ARRAY_SIZE(cpia2_framesizes)) 5588c2ecf20Sopenharmony_ci return -EINVAL; 5598c2ecf20Sopenharmony_ci fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; 5608c2ecf20Sopenharmony_ci fsize->discrete.width = cpia2_framesizes[fsize->index].width; 5618c2ecf20Sopenharmony_ci fsize->discrete.height = cpia2_framesizes[fsize->index].height; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci return 0; 5648c2ecf20Sopenharmony_ci} 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_cistatic int cpia2_enum_frameintervals(struct file *file, void *fh, 5678c2ecf20Sopenharmony_ci struct v4l2_frmivalenum *fival) 5688c2ecf20Sopenharmony_ci{ 5698c2ecf20Sopenharmony_ci struct camera_data *cam = video_drvdata(file); 5708c2ecf20Sopenharmony_ci int max = ARRAY_SIZE(framerate_controls) - 1; 5718c2ecf20Sopenharmony_ci int i; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci if (fival->pixel_format != V4L2_PIX_FMT_MJPEG && 5748c2ecf20Sopenharmony_ci fival->pixel_format != V4L2_PIX_FMT_JPEG) 5758c2ecf20Sopenharmony_ci return -EINVAL; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci /* Maximum 15 fps for this model */ 5788c2ecf20Sopenharmony_ci if (cam->params.pnp_id.device_type == DEVICE_STV_672 && 5798c2ecf20Sopenharmony_ci cam->params.version.sensor_flags == CPIA2_VP_SENSOR_FLAGS_500) 5808c2ecf20Sopenharmony_ci max -= 2; 5818c2ecf20Sopenharmony_ci if (fival->index > max) 5828c2ecf20Sopenharmony_ci return -EINVAL; 5838c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(cpia2_framesizes); i++) 5848c2ecf20Sopenharmony_ci if (fival->width == cpia2_framesizes[i].width && 5858c2ecf20Sopenharmony_ci fival->height == cpia2_framesizes[i].height) 5868c2ecf20Sopenharmony_ci break; 5878c2ecf20Sopenharmony_ci if (i == ARRAY_SIZE(cpia2_framesizes)) 5888c2ecf20Sopenharmony_ci return -EINVAL; 5898c2ecf20Sopenharmony_ci fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; 5908c2ecf20Sopenharmony_ci fival->discrete = framerate_controls[fival->index].period; 5918c2ecf20Sopenharmony_ci return 0; 5928c2ecf20Sopenharmony_ci} 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci/****************************************************************************** 5958c2ecf20Sopenharmony_ci * 5968c2ecf20Sopenharmony_ci * ioctl_s_ctrl 5978c2ecf20Sopenharmony_ci * 5988c2ecf20Sopenharmony_ci * V4L2 set the value of a control variable 5998c2ecf20Sopenharmony_ci * 6008c2ecf20Sopenharmony_ci *****************************************************************************/ 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_cistatic int cpia2_s_ctrl(struct v4l2_ctrl *ctrl) 6038c2ecf20Sopenharmony_ci{ 6048c2ecf20Sopenharmony_ci struct camera_data *cam = 6058c2ecf20Sopenharmony_ci container_of(ctrl->handler, struct camera_data, hdl); 6068c2ecf20Sopenharmony_ci static const int flicker_table[] = { 6078c2ecf20Sopenharmony_ci NEVER_FLICKER, 6088c2ecf20Sopenharmony_ci FLICKER_50, 6098c2ecf20Sopenharmony_ci FLICKER_60, 6108c2ecf20Sopenharmony_ci }; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci DBG("Set control id:%d, value:%d\n", ctrl->id, ctrl->val); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci switch (ctrl->id) { 6158c2ecf20Sopenharmony_ci case V4L2_CID_BRIGHTNESS: 6168c2ecf20Sopenharmony_ci cpia2_set_brightness(cam, ctrl->val); 6178c2ecf20Sopenharmony_ci break; 6188c2ecf20Sopenharmony_ci case V4L2_CID_CONTRAST: 6198c2ecf20Sopenharmony_ci cpia2_set_contrast(cam, ctrl->val); 6208c2ecf20Sopenharmony_ci break; 6218c2ecf20Sopenharmony_ci case V4L2_CID_SATURATION: 6228c2ecf20Sopenharmony_ci cpia2_set_saturation(cam, ctrl->val); 6238c2ecf20Sopenharmony_ci break; 6248c2ecf20Sopenharmony_ci case V4L2_CID_HFLIP: 6258c2ecf20Sopenharmony_ci cpia2_set_property_mirror(cam, ctrl->val); 6268c2ecf20Sopenharmony_ci break; 6278c2ecf20Sopenharmony_ci case V4L2_CID_VFLIP: 6288c2ecf20Sopenharmony_ci cpia2_set_property_flip(cam, ctrl->val); 6298c2ecf20Sopenharmony_ci break; 6308c2ecf20Sopenharmony_ci case V4L2_CID_POWER_LINE_FREQUENCY: 6318c2ecf20Sopenharmony_ci return cpia2_set_flicker_mode(cam, flicker_table[ctrl->val]); 6328c2ecf20Sopenharmony_ci case V4L2_CID_ILLUMINATORS_1: 6338c2ecf20Sopenharmony_ci return cpia2_set_gpio(cam, (cam->top_light->val << 6) | 6348c2ecf20Sopenharmony_ci (cam->bottom_light->val << 7)); 6358c2ecf20Sopenharmony_ci case V4L2_CID_JPEG_ACTIVE_MARKER: 6368c2ecf20Sopenharmony_ci cam->params.compression.inhibit_htables = 6378c2ecf20Sopenharmony_ci !(ctrl->val & V4L2_JPEG_ACTIVE_MARKER_DHT); 6388c2ecf20Sopenharmony_ci break; 6398c2ecf20Sopenharmony_ci case V4L2_CID_JPEG_COMPRESSION_QUALITY: 6408c2ecf20Sopenharmony_ci cam->params.vc_params.quality = ctrl->val; 6418c2ecf20Sopenharmony_ci break; 6428c2ecf20Sopenharmony_ci case CPIA2_CID_USB_ALT: 6438c2ecf20Sopenharmony_ci cam->params.camera_state.stream_mode = ctrl->val; 6448c2ecf20Sopenharmony_ci break; 6458c2ecf20Sopenharmony_ci default: 6468c2ecf20Sopenharmony_ci return -EINVAL; 6478c2ecf20Sopenharmony_ci } 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci return 0; 6508c2ecf20Sopenharmony_ci} 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci/****************************************************************************** 6538c2ecf20Sopenharmony_ci * 6548c2ecf20Sopenharmony_ci * ioctl_g_jpegcomp 6558c2ecf20Sopenharmony_ci * 6568c2ecf20Sopenharmony_ci * V4L2 get the JPEG compression parameters 6578c2ecf20Sopenharmony_ci * 6588c2ecf20Sopenharmony_ci *****************************************************************************/ 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_cistatic int cpia2_g_jpegcomp(struct file *file, void *fh, struct v4l2_jpegcompression *parms) 6618c2ecf20Sopenharmony_ci{ 6628c2ecf20Sopenharmony_ci struct camera_data *cam = video_drvdata(file); 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci memset(parms, 0, sizeof(*parms)); 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci parms->quality = 80; // TODO: Can this be made meaningful? 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci parms->jpeg_markers = V4L2_JPEG_MARKER_DQT | V4L2_JPEG_MARKER_DRI; 6698c2ecf20Sopenharmony_ci if(!cam->params.compression.inhibit_htables) { 6708c2ecf20Sopenharmony_ci parms->jpeg_markers |= V4L2_JPEG_MARKER_DHT; 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci parms->APPn = cam->APPn; 6748c2ecf20Sopenharmony_ci parms->APP_len = cam->APP_len; 6758c2ecf20Sopenharmony_ci if(cam->APP_len > 0) { 6768c2ecf20Sopenharmony_ci memcpy(parms->APP_data, cam->APP_data, cam->APP_len); 6778c2ecf20Sopenharmony_ci parms->jpeg_markers |= V4L2_JPEG_MARKER_APP; 6788c2ecf20Sopenharmony_ci } 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci parms->COM_len = cam->COM_len; 6818c2ecf20Sopenharmony_ci if(cam->COM_len > 0) { 6828c2ecf20Sopenharmony_ci memcpy(parms->COM_data, cam->COM_data, cam->COM_len); 6838c2ecf20Sopenharmony_ci parms->jpeg_markers |= JPEG_MARKER_COM; 6848c2ecf20Sopenharmony_ci } 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci DBG("G_JPEGCOMP APP_len:%d COM_len:%d\n", 6878c2ecf20Sopenharmony_ci parms->APP_len, parms->COM_len); 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci return 0; 6908c2ecf20Sopenharmony_ci} 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci/****************************************************************************** 6938c2ecf20Sopenharmony_ci * 6948c2ecf20Sopenharmony_ci * ioctl_s_jpegcomp 6958c2ecf20Sopenharmony_ci * 6968c2ecf20Sopenharmony_ci * V4L2 set the JPEG compression parameters 6978c2ecf20Sopenharmony_ci * NOTE: quality and some jpeg_markers are ignored. 6988c2ecf20Sopenharmony_ci * 6998c2ecf20Sopenharmony_ci *****************************************************************************/ 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_cistatic int cpia2_s_jpegcomp(struct file *file, void *fh, 7028c2ecf20Sopenharmony_ci const struct v4l2_jpegcompression *parms) 7038c2ecf20Sopenharmony_ci{ 7048c2ecf20Sopenharmony_ci struct camera_data *cam = video_drvdata(file); 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci DBG("S_JPEGCOMP APP_len:%d COM_len:%d\n", 7078c2ecf20Sopenharmony_ci parms->APP_len, parms->COM_len); 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci cam->params.compression.inhibit_htables = 7108c2ecf20Sopenharmony_ci !(parms->jpeg_markers & V4L2_JPEG_MARKER_DHT); 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci if(parms->APP_len != 0) { 7138c2ecf20Sopenharmony_ci if(parms->APP_len > 0 && 7148c2ecf20Sopenharmony_ci parms->APP_len <= sizeof(cam->APP_data) && 7158c2ecf20Sopenharmony_ci parms->APPn >= 0 && parms->APPn <= 15) { 7168c2ecf20Sopenharmony_ci cam->APPn = parms->APPn; 7178c2ecf20Sopenharmony_ci cam->APP_len = parms->APP_len; 7188c2ecf20Sopenharmony_ci memcpy(cam->APP_data, parms->APP_data, parms->APP_len); 7198c2ecf20Sopenharmony_ci } else { 7208c2ecf20Sopenharmony_ci LOG("Bad APPn Params n=%d len=%d\n", 7218c2ecf20Sopenharmony_ci parms->APPn, parms->APP_len); 7228c2ecf20Sopenharmony_ci return -EINVAL; 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci } else { 7258c2ecf20Sopenharmony_ci cam->APP_len = 0; 7268c2ecf20Sopenharmony_ci } 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci if(parms->COM_len != 0) { 7298c2ecf20Sopenharmony_ci if(parms->COM_len > 0 && 7308c2ecf20Sopenharmony_ci parms->COM_len <= sizeof(cam->COM_data)) { 7318c2ecf20Sopenharmony_ci cam->COM_len = parms->COM_len; 7328c2ecf20Sopenharmony_ci memcpy(cam->COM_data, parms->COM_data, parms->COM_len); 7338c2ecf20Sopenharmony_ci } else { 7348c2ecf20Sopenharmony_ci LOG("Bad COM_len=%d\n", parms->COM_len); 7358c2ecf20Sopenharmony_ci return -EINVAL; 7368c2ecf20Sopenharmony_ci } 7378c2ecf20Sopenharmony_ci } 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci return 0; 7408c2ecf20Sopenharmony_ci} 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci/****************************************************************************** 7438c2ecf20Sopenharmony_ci * 7448c2ecf20Sopenharmony_ci * ioctl_reqbufs 7458c2ecf20Sopenharmony_ci * 7468c2ecf20Sopenharmony_ci * V4L2 Initiate memory mapping. 7478c2ecf20Sopenharmony_ci * NOTE: The user's request is ignored. For now the buffers are fixed. 7488c2ecf20Sopenharmony_ci * 7498c2ecf20Sopenharmony_ci *****************************************************************************/ 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_cistatic int cpia2_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *req) 7528c2ecf20Sopenharmony_ci{ 7538c2ecf20Sopenharmony_ci struct camera_data *cam = video_drvdata(file); 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci if(req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || 7568c2ecf20Sopenharmony_ci req->memory != V4L2_MEMORY_MMAP) 7578c2ecf20Sopenharmony_ci return -EINVAL; 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci DBG("REQBUFS requested:%d returning:%d\n", req->count, cam->num_frames); 7608c2ecf20Sopenharmony_ci req->count = cam->num_frames; 7618c2ecf20Sopenharmony_ci memset(&req->reserved, 0, sizeof(req->reserved)); 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci return 0; 7648c2ecf20Sopenharmony_ci} 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci/****************************************************************************** 7678c2ecf20Sopenharmony_ci * 7688c2ecf20Sopenharmony_ci * ioctl_querybuf 7698c2ecf20Sopenharmony_ci * 7708c2ecf20Sopenharmony_ci * V4L2 Query memory buffer status. 7718c2ecf20Sopenharmony_ci * 7728c2ecf20Sopenharmony_ci *****************************************************************************/ 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_cistatic int cpia2_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf) 7758c2ecf20Sopenharmony_ci{ 7768c2ecf20Sopenharmony_ci struct camera_data *cam = video_drvdata(file); 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || 7798c2ecf20Sopenharmony_ci buf->index >= cam->num_frames) 7808c2ecf20Sopenharmony_ci return -EINVAL; 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer; 7838c2ecf20Sopenharmony_ci buf->length = cam->frame_size; 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci buf->memory = V4L2_MEMORY_MMAP; 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci if(cam->mmapped) 7888c2ecf20Sopenharmony_ci buf->flags = V4L2_BUF_FLAG_MAPPED; 7898c2ecf20Sopenharmony_ci else 7908c2ecf20Sopenharmony_ci buf->flags = 0; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci buf->flags |= V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci switch (cam->buffers[buf->index].status) { 7958c2ecf20Sopenharmony_ci case FRAME_EMPTY: 7968c2ecf20Sopenharmony_ci case FRAME_ERROR: 7978c2ecf20Sopenharmony_ci case FRAME_READING: 7988c2ecf20Sopenharmony_ci buf->bytesused = 0; 7998c2ecf20Sopenharmony_ci buf->flags = V4L2_BUF_FLAG_QUEUED; 8008c2ecf20Sopenharmony_ci break; 8018c2ecf20Sopenharmony_ci case FRAME_READY: 8028c2ecf20Sopenharmony_ci buf->bytesused = cam->buffers[buf->index].length; 8038c2ecf20Sopenharmony_ci v4l2_buffer_set_timestamp(buf, cam->buffers[buf->index].ts); 8048c2ecf20Sopenharmony_ci buf->sequence = cam->buffers[buf->index].seq; 8058c2ecf20Sopenharmony_ci buf->flags = V4L2_BUF_FLAG_DONE; 8068c2ecf20Sopenharmony_ci break; 8078c2ecf20Sopenharmony_ci } 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci DBG("QUERYBUF index:%d offset:%d flags:%d seq:%d bytesused:%d\n", 8108c2ecf20Sopenharmony_ci buf->index, buf->m.offset, buf->flags, buf->sequence, 8118c2ecf20Sopenharmony_ci buf->bytesused); 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci return 0; 8148c2ecf20Sopenharmony_ci} 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci/****************************************************************************** 8178c2ecf20Sopenharmony_ci * 8188c2ecf20Sopenharmony_ci * ioctl_qbuf 8198c2ecf20Sopenharmony_ci * 8208c2ecf20Sopenharmony_ci * V4L2 User is freeing buffer 8218c2ecf20Sopenharmony_ci * 8228c2ecf20Sopenharmony_ci *****************************************************************************/ 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_cistatic int cpia2_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf) 8258c2ecf20Sopenharmony_ci{ 8268c2ecf20Sopenharmony_ci struct camera_data *cam = video_drvdata(file); 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || 8298c2ecf20Sopenharmony_ci buf->memory != V4L2_MEMORY_MMAP || 8308c2ecf20Sopenharmony_ci buf->index >= cam->num_frames) 8318c2ecf20Sopenharmony_ci return -EINVAL; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci DBG("QBUF #%d\n", buf->index); 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci if(cam->buffers[buf->index].status == FRAME_READY) 8368c2ecf20Sopenharmony_ci cam->buffers[buf->index].status = FRAME_EMPTY; 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci return 0; 8398c2ecf20Sopenharmony_ci} 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci/****************************************************************************** 8428c2ecf20Sopenharmony_ci * 8438c2ecf20Sopenharmony_ci * find_earliest_filled_buffer 8448c2ecf20Sopenharmony_ci * 8458c2ecf20Sopenharmony_ci * Helper for ioctl_dqbuf. Find the next ready buffer. 8468c2ecf20Sopenharmony_ci * 8478c2ecf20Sopenharmony_ci *****************************************************************************/ 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_cistatic int find_earliest_filled_buffer(struct camera_data *cam) 8508c2ecf20Sopenharmony_ci{ 8518c2ecf20Sopenharmony_ci int i; 8528c2ecf20Sopenharmony_ci int found = -1; 8538c2ecf20Sopenharmony_ci for (i=0; i<cam->num_frames; i++) { 8548c2ecf20Sopenharmony_ci if(cam->buffers[i].status == FRAME_READY) { 8558c2ecf20Sopenharmony_ci if(found < 0) { 8568c2ecf20Sopenharmony_ci found = i; 8578c2ecf20Sopenharmony_ci } else { 8588c2ecf20Sopenharmony_ci /* find which buffer is earlier */ 8598c2ecf20Sopenharmony_ci if (cam->buffers[i].ts < cam->buffers[found].ts) 8608c2ecf20Sopenharmony_ci found = i; 8618c2ecf20Sopenharmony_ci } 8628c2ecf20Sopenharmony_ci } 8638c2ecf20Sopenharmony_ci } 8648c2ecf20Sopenharmony_ci return found; 8658c2ecf20Sopenharmony_ci} 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci/****************************************************************************** 8688c2ecf20Sopenharmony_ci * 8698c2ecf20Sopenharmony_ci * ioctl_dqbuf 8708c2ecf20Sopenharmony_ci * 8718c2ecf20Sopenharmony_ci * V4L2 User is asking for a filled buffer. 8728c2ecf20Sopenharmony_ci * 8738c2ecf20Sopenharmony_ci *****************************************************************************/ 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_cistatic int cpia2_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf) 8768c2ecf20Sopenharmony_ci{ 8778c2ecf20Sopenharmony_ci struct camera_data *cam = video_drvdata(file); 8788c2ecf20Sopenharmony_ci int frame; 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || 8818c2ecf20Sopenharmony_ci buf->memory != V4L2_MEMORY_MMAP) 8828c2ecf20Sopenharmony_ci return -EINVAL; 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci frame = find_earliest_filled_buffer(cam); 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci if(frame < 0 && file->f_flags&O_NONBLOCK) 8878c2ecf20Sopenharmony_ci return -EAGAIN; 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci if(frame < 0) { 8908c2ecf20Sopenharmony_ci /* Wait for a frame to become available */ 8918c2ecf20Sopenharmony_ci struct framebuf *cb=cam->curbuff; 8928c2ecf20Sopenharmony_ci mutex_unlock(&cam->v4l2_lock); 8938c2ecf20Sopenharmony_ci wait_event_interruptible(cam->wq_stream, 8948c2ecf20Sopenharmony_ci !video_is_registered(&cam->vdev) || 8958c2ecf20Sopenharmony_ci (cb=cam->curbuff)->status == FRAME_READY); 8968c2ecf20Sopenharmony_ci mutex_lock(&cam->v4l2_lock); 8978c2ecf20Sopenharmony_ci if (signal_pending(current)) 8988c2ecf20Sopenharmony_ci return -ERESTARTSYS; 8998c2ecf20Sopenharmony_ci if (!video_is_registered(&cam->vdev)) 9008c2ecf20Sopenharmony_ci return -ENOTTY; 9018c2ecf20Sopenharmony_ci frame = cb->num; 9028c2ecf20Sopenharmony_ci } 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci buf->index = frame; 9068c2ecf20Sopenharmony_ci buf->bytesused = cam->buffers[buf->index].length; 9078c2ecf20Sopenharmony_ci buf->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE 9088c2ecf20Sopenharmony_ci | V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; 9098c2ecf20Sopenharmony_ci buf->field = V4L2_FIELD_NONE; 9108c2ecf20Sopenharmony_ci v4l2_buffer_set_timestamp(buf, cam->buffers[buf->index].ts); 9118c2ecf20Sopenharmony_ci buf->sequence = cam->buffers[buf->index].seq; 9128c2ecf20Sopenharmony_ci buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer; 9138c2ecf20Sopenharmony_ci buf->length = cam->frame_size; 9148c2ecf20Sopenharmony_ci buf->reserved2 = 0; 9158c2ecf20Sopenharmony_ci buf->request_fd = 0; 9168c2ecf20Sopenharmony_ci memset(&buf->timecode, 0, sizeof(buf->timecode)); 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci DBG("DQBUF #%d status:%d seq:%d length:%d\n", buf->index, 9198c2ecf20Sopenharmony_ci cam->buffers[buf->index].status, buf->sequence, buf->bytesused); 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci return 0; 9228c2ecf20Sopenharmony_ci} 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_cistatic int cpia2_streamon(struct file *file, void *fh, enum v4l2_buf_type type) 9258c2ecf20Sopenharmony_ci{ 9268c2ecf20Sopenharmony_ci struct camera_data *cam = video_drvdata(file); 9278c2ecf20Sopenharmony_ci int ret = -EINVAL; 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci DBG("VIDIOC_STREAMON, streaming=%d\n", cam->streaming); 9308c2ecf20Sopenharmony_ci if (!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 9318c2ecf20Sopenharmony_ci return -EINVAL; 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci if (!cam->streaming) { 9348c2ecf20Sopenharmony_ci ret = cpia2_usb_stream_start(cam, 9358c2ecf20Sopenharmony_ci cam->params.camera_state.stream_mode); 9368c2ecf20Sopenharmony_ci if (!ret) 9378c2ecf20Sopenharmony_ci v4l2_ctrl_grab(cam->usb_alt, true); 9388c2ecf20Sopenharmony_ci } 9398c2ecf20Sopenharmony_ci return ret; 9408c2ecf20Sopenharmony_ci} 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_cistatic int cpia2_streamoff(struct file *file, void *fh, enum v4l2_buf_type type) 9438c2ecf20Sopenharmony_ci{ 9448c2ecf20Sopenharmony_ci struct camera_data *cam = video_drvdata(file); 9458c2ecf20Sopenharmony_ci int ret = -EINVAL; 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci DBG("VIDIOC_STREAMOFF, streaming=%d\n", cam->streaming); 9488c2ecf20Sopenharmony_ci if (!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 9498c2ecf20Sopenharmony_ci return -EINVAL; 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci if (cam->streaming) { 9528c2ecf20Sopenharmony_ci ret = cpia2_usb_stream_stop(cam); 9538c2ecf20Sopenharmony_ci if (!ret) 9548c2ecf20Sopenharmony_ci v4l2_ctrl_grab(cam->usb_alt, false); 9558c2ecf20Sopenharmony_ci } 9568c2ecf20Sopenharmony_ci return ret; 9578c2ecf20Sopenharmony_ci} 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci/****************************************************************************** 9608c2ecf20Sopenharmony_ci * 9618c2ecf20Sopenharmony_ci * cpia2_mmap 9628c2ecf20Sopenharmony_ci * 9638c2ecf20Sopenharmony_ci *****************************************************************************/ 9648c2ecf20Sopenharmony_cistatic int cpia2_mmap(struct file *file, struct vm_area_struct *area) 9658c2ecf20Sopenharmony_ci{ 9668c2ecf20Sopenharmony_ci struct camera_data *cam = video_drvdata(file); 9678c2ecf20Sopenharmony_ci int retval; 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&cam->v4l2_lock)) 9708c2ecf20Sopenharmony_ci return -ERESTARTSYS; 9718c2ecf20Sopenharmony_ci retval = cpia2_remap_buffer(cam, area); 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci if(!retval) 9748c2ecf20Sopenharmony_ci cam->stream_fh = file->private_data; 9758c2ecf20Sopenharmony_ci mutex_unlock(&cam->v4l2_lock); 9768c2ecf20Sopenharmony_ci return retval; 9778c2ecf20Sopenharmony_ci} 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci/****************************************************************************** 9808c2ecf20Sopenharmony_ci * 9818c2ecf20Sopenharmony_ci * reset_camera_struct_v4l 9828c2ecf20Sopenharmony_ci * 9838c2ecf20Sopenharmony_ci * Sets all values to the defaults 9848c2ecf20Sopenharmony_ci *****************************************************************************/ 9858c2ecf20Sopenharmony_cistatic void reset_camera_struct_v4l(struct camera_data *cam) 9868c2ecf20Sopenharmony_ci{ 9878c2ecf20Sopenharmony_ci cam->width = cam->params.roi.width; 9888c2ecf20Sopenharmony_ci cam->height = cam->params.roi.height; 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci cam->frame_size = buffer_size; 9918c2ecf20Sopenharmony_ci cam->num_frames = num_buffers; 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci /* Flicker modes */ 9948c2ecf20Sopenharmony_ci cam->params.flicker_control.flicker_mode_req = flicker_mode; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci /* stream modes */ 9978c2ecf20Sopenharmony_ci cam->params.camera_state.stream_mode = alternate; 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci cam->pixelformat = V4L2_PIX_FMT_JPEG; 10008c2ecf20Sopenharmony_ci} 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_cistatic const struct v4l2_ioctl_ops cpia2_ioctl_ops = { 10038c2ecf20Sopenharmony_ci .vidioc_querycap = cpia2_querycap, 10048c2ecf20Sopenharmony_ci .vidioc_enum_input = cpia2_enum_input, 10058c2ecf20Sopenharmony_ci .vidioc_g_input = cpia2_g_input, 10068c2ecf20Sopenharmony_ci .vidioc_s_input = cpia2_s_input, 10078c2ecf20Sopenharmony_ci .vidioc_enum_fmt_vid_cap = cpia2_enum_fmt_vid_cap, 10088c2ecf20Sopenharmony_ci .vidioc_g_fmt_vid_cap = cpia2_g_fmt_vid_cap, 10098c2ecf20Sopenharmony_ci .vidioc_s_fmt_vid_cap = cpia2_s_fmt_vid_cap, 10108c2ecf20Sopenharmony_ci .vidioc_try_fmt_vid_cap = cpia2_try_fmt_vid_cap, 10118c2ecf20Sopenharmony_ci .vidioc_g_jpegcomp = cpia2_g_jpegcomp, 10128c2ecf20Sopenharmony_ci .vidioc_s_jpegcomp = cpia2_s_jpegcomp, 10138c2ecf20Sopenharmony_ci .vidioc_g_selection = cpia2_g_selection, 10148c2ecf20Sopenharmony_ci .vidioc_reqbufs = cpia2_reqbufs, 10158c2ecf20Sopenharmony_ci .vidioc_querybuf = cpia2_querybuf, 10168c2ecf20Sopenharmony_ci .vidioc_qbuf = cpia2_qbuf, 10178c2ecf20Sopenharmony_ci .vidioc_dqbuf = cpia2_dqbuf, 10188c2ecf20Sopenharmony_ci .vidioc_streamon = cpia2_streamon, 10198c2ecf20Sopenharmony_ci .vidioc_streamoff = cpia2_streamoff, 10208c2ecf20Sopenharmony_ci .vidioc_s_parm = cpia2_s_parm, 10218c2ecf20Sopenharmony_ci .vidioc_g_parm = cpia2_g_parm, 10228c2ecf20Sopenharmony_ci .vidioc_enum_framesizes = cpia2_enum_framesizes, 10238c2ecf20Sopenharmony_ci .vidioc_enum_frameintervals = cpia2_enum_frameintervals, 10248c2ecf20Sopenharmony_ci .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, 10258c2ecf20Sopenharmony_ci .vidioc_unsubscribe_event = v4l2_event_unsubscribe, 10268c2ecf20Sopenharmony_ci}; 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci/*** 10298c2ecf20Sopenharmony_ci * The v4l video device structure initialized for this device 10308c2ecf20Sopenharmony_ci ***/ 10318c2ecf20Sopenharmony_cistatic const struct v4l2_file_operations cpia2_fops = { 10328c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 10338c2ecf20Sopenharmony_ci .open = cpia2_open, 10348c2ecf20Sopenharmony_ci .release = cpia2_close, 10358c2ecf20Sopenharmony_ci .read = cpia2_v4l_read, 10368c2ecf20Sopenharmony_ci .poll = cpia2_v4l_poll, 10378c2ecf20Sopenharmony_ci .unlocked_ioctl = video_ioctl2, 10388c2ecf20Sopenharmony_ci .mmap = cpia2_mmap, 10398c2ecf20Sopenharmony_ci}; 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_cistatic const struct video_device cpia2_template = { 10428c2ecf20Sopenharmony_ci /* I could not find any place for the old .initialize initializer?? */ 10438c2ecf20Sopenharmony_ci .name = "CPiA2 Camera", 10448c2ecf20Sopenharmony_ci .fops = &cpia2_fops, 10458c2ecf20Sopenharmony_ci .ioctl_ops = &cpia2_ioctl_ops, 10468c2ecf20Sopenharmony_ci .release = video_device_release_empty, 10478c2ecf20Sopenharmony_ci}; 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_civoid cpia2_camera_release(struct v4l2_device *v4l2_dev) 10508c2ecf20Sopenharmony_ci{ 10518c2ecf20Sopenharmony_ci struct camera_data *cam = 10528c2ecf20Sopenharmony_ci container_of(v4l2_dev, struct camera_data, v4l2_dev); 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci v4l2_ctrl_handler_free(&cam->hdl); 10558c2ecf20Sopenharmony_ci v4l2_device_unregister(&cam->v4l2_dev); 10568c2ecf20Sopenharmony_ci kfree(cam); 10578c2ecf20Sopenharmony_ci} 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_ops cpia2_ctrl_ops = { 10608c2ecf20Sopenharmony_ci .s_ctrl = cpia2_s_ctrl, 10618c2ecf20Sopenharmony_ci}; 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci/****************************************************************************** 10648c2ecf20Sopenharmony_ci * 10658c2ecf20Sopenharmony_ci * cpia2_register_camera 10668c2ecf20Sopenharmony_ci * 10678c2ecf20Sopenharmony_ci *****************************************************************************/ 10688c2ecf20Sopenharmony_ciint cpia2_register_camera(struct camera_data *cam) 10698c2ecf20Sopenharmony_ci{ 10708c2ecf20Sopenharmony_ci struct v4l2_ctrl_handler *hdl = &cam->hdl; 10718c2ecf20Sopenharmony_ci struct v4l2_ctrl_config cpia2_usb_alt = { 10728c2ecf20Sopenharmony_ci .ops = &cpia2_ctrl_ops, 10738c2ecf20Sopenharmony_ci .id = CPIA2_CID_USB_ALT, 10748c2ecf20Sopenharmony_ci .name = "USB Alternate", 10758c2ecf20Sopenharmony_ci .type = V4L2_CTRL_TYPE_INTEGER, 10768c2ecf20Sopenharmony_ci .min = USBIF_ISO_1, 10778c2ecf20Sopenharmony_ci .max = USBIF_ISO_6, 10788c2ecf20Sopenharmony_ci .step = 1, 10798c2ecf20Sopenharmony_ci }; 10808c2ecf20Sopenharmony_ci int ret; 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci v4l2_ctrl_handler_init(hdl, 12); 10838c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops, 10848c2ecf20Sopenharmony_ci V4L2_CID_BRIGHTNESS, 10858c2ecf20Sopenharmony_ci cam->params.pnp_id.device_type == DEVICE_STV_672 ? 1 : 0, 10868c2ecf20Sopenharmony_ci 255, 1, DEFAULT_BRIGHTNESS); 10878c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops, 10888c2ecf20Sopenharmony_ci V4L2_CID_CONTRAST, 0, 255, 1, DEFAULT_CONTRAST); 10898c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops, 10908c2ecf20Sopenharmony_ci V4L2_CID_SATURATION, 0, 255, 1, DEFAULT_SATURATION); 10918c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops, 10928c2ecf20Sopenharmony_ci V4L2_CID_HFLIP, 0, 1, 1, 0); 10938c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops, 10948c2ecf20Sopenharmony_ci V4L2_CID_JPEG_ACTIVE_MARKER, 0, 10958c2ecf20Sopenharmony_ci V4L2_JPEG_ACTIVE_MARKER_DHT, 0, 10968c2ecf20Sopenharmony_ci V4L2_JPEG_ACTIVE_MARKER_DHT); 10978c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops, 10988c2ecf20Sopenharmony_ci V4L2_CID_JPEG_COMPRESSION_QUALITY, 1, 10998c2ecf20Sopenharmony_ci 100, 1, 100); 11008c2ecf20Sopenharmony_ci cpia2_usb_alt.def = alternate; 11018c2ecf20Sopenharmony_ci cam->usb_alt = v4l2_ctrl_new_custom(hdl, &cpia2_usb_alt, NULL); 11028c2ecf20Sopenharmony_ci /* VP5 Only */ 11038c2ecf20Sopenharmony_ci if (cam->params.pnp_id.device_type != DEVICE_STV_672) 11048c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops, 11058c2ecf20Sopenharmony_ci V4L2_CID_VFLIP, 0, 1, 1, 0); 11068c2ecf20Sopenharmony_ci /* Flicker control only valid for 672 */ 11078c2ecf20Sopenharmony_ci if (cam->params.pnp_id.device_type == DEVICE_STV_672) 11088c2ecf20Sopenharmony_ci v4l2_ctrl_new_std_menu(hdl, &cpia2_ctrl_ops, 11098c2ecf20Sopenharmony_ci V4L2_CID_POWER_LINE_FREQUENCY, 11108c2ecf20Sopenharmony_ci V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 0, 0); 11118c2ecf20Sopenharmony_ci /* Light control only valid for the QX5 Microscope */ 11128c2ecf20Sopenharmony_ci if (cam->params.pnp_id.product == 0x151) { 11138c2ecf20Sopenharmony_ci cam->top_light = v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops, 11148c2ecf20Sopenharmony_ci V4L2_CID_ILLUMINATORS_1, 0, 1, 1, 0); 11158c2ecf20Sopenharmony_ci cam->bottom_light = v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops, 11168c2ecf20Sopenharmony_ci V4L2_CID_ILLUMINATORS_2, 0, 1, 1, 0); 11178c2ecf20Sopenharmony_ci v4l2_ctrl_cluster(2, &cam->top_light); 11188c2ecf20Sopenharmony_ci } 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci if (hdl->error) { 11218c2ecf20Sopenharmony_ci ret = hdl->error; 11228c2ecf20Sopenharmony_ci v4l2_ctrl_handler_free(hdl); 11238c2ecf20Sopenharmony_ci return ret; 11248c2ecf20Sopenharmony_ci } 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci cam->vdev = cpia2_template; 11278c2ecf20Sopenharmony_ci video_set_drvdata(&cam->vdev, cam); 11288c2ecf20Sopenharmony_ci cam->vdev.lock = &cam->v4l2_lock; 11298c2ecf20Sopenharmony_ci cam->vdev.ctrl_handler = hdl; 11308c2ecf20Sopenharmony_ci cam->vdev.v4l2_dev = &cam->v4l2_dev; 11318c2ecf20Sopenharmony_ci cam->vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | 11328c2ecf20Sopenharmony_ci V4L2_CAP_STREAMING; 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci reset_camera_struct_v4l(cam); 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci /* register v4l device */ 11378c2ecf20Sopenharmony_ci if (video_register_device(&cam->vdev, VFL_TYPE_VIDEO, video_nr) < 0) { 11388c2ecf20Sopenharmony_ci ERR("video_register_device failed\n"); 11398c2ecf20Sopenharmony_ci return -ENODEV; 11408c2ecf20Sopenharmony_ci } 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci return 0; 11438c2ecf20Sopenharmony_ci} 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci/****************************************************************************** 11468c2ecf20Sopenharmony_ci * 11478c2ecf20Sopenharmony_ci * cpia2_unregister_camera 11488c2ecf20Sopenharmony_ci * 11498c2ecf20Sopenharmony_ci *****************************************************************************/ 11508c2ecf20Sopenharmony_civoid cpia2_unregister_camera(struct camera_data *cam) 11518c2ecf20Sopenharmony_ci{ 11528c2ecf20Sopenharmony_ci video_unregister_device(&cam->vdev); 11538c2ecf20Sopenharmony_ci} 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci/****************************************************************************** 11568c2ecf20Sopenharmony_ci * 11578c2ecf20Sopenharmony_ci * check_parameters 11588c2ecf20Sopenharmony_ci * 11598c2ecf20Sopenharmony_ci * Make sure that all user-supplied parameters are sensible 11608c2ecf20Sopenharmony_ci *****************************************************************************/ 11618c2ecf20Sopenharmony_cistatic void __init check_parameters(void) 11628c2ecf20Sopenharmony_ci{ 11638c2ecf20Sopenharmony_ci if(buffer_size < PAGE_SIZE) { 11648c2ecf20Sopenharmony_ci buffer_size = PAGE_SIZE; 11658c2ecf20Sopenharmony_ci LOG("buffer_size too small, setting to %d\n", buffer_size); 11668c2ecf20Sopenharmony_ci } else if(buffer_size > 1024*1024) { 11678c2ecf20Sopenharmony_ci /* arbitrary upper limiit */ 11688c2ecf20Sopenharmony_ci buffer_size = 1024*1024; 11698c2ecf20Sopenharmony_ci LOG("buffer_size ridiculously large, setting to %d\n", 11708c2ecf20Sopenharmony_ci buffer_size); 11718c2ecf20Sopenharmony_ci } else { 11728c2ecf20Sopenharmony_ci buffer_size += PAGE_SIZE-1; 11738c2ecf20Sopenharmony_ci buffer_size &= ~(PAGE_SIZE-1); 11748c2ecf20Sopenharmony_ci } 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci if(num_buffers < 1) { 11778c2ecf20Sopenharmony_ci num_buffers = 1; 11788c2ecf20Sopenharmony_ci LOG("num_buffers too small, setting to %d\n", num_buffers); 11798c2ecf20Sopenharmony_ci } else if(num_buffers > VIDEO_MAX_FRAME) { 11808c2ecf20Sopenharmony_ci num_buffers = VIDEO_MAX_FRAME; 11818c2ecf20Sopenharmony_ci LOG("num_buffers too large, setting to %d\n", num_buffers); 11828c2ecf20Sopenharmony_ci } 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci if(alternate < USBIF_ISO_1 || alternate > USBIF_ISO_6) { 11858c2ecf20Sopenharmony_ci alternate = DEFAULT_ALT; 11868c2ecf20Sopenharmony_ci LOG("alternate specified is invalid, using %d\n", alternate); 11878c2ecf20Sopenharmony_ci } 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci if (flicker_mode != 0 && flicker_mode != FLICKER_50 && flicker_mode != FLICKER_60) { 11908c2ecf20Sopenharmony_ci flicker_mode = 0; 11918c2ecf20Sopenharmony_ci LOG("Flicker mode specified is invalid, using %d\n", 11928c2ecf20Sopenharmony_ci flicker_mode); 11938c2ecf20Sopenharmony_ci } 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci DBG("Using %d buffers, each %d bytes, alternate=%d\n", 11968c2ecf20Sopenharmony_ci num_buffers, buffer_size, alternate); 11978c2ecf20Sopenharmony_ci} 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci/************ Module Stuff ***************/ 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci/****************************************************************************** 12038c2ecf20Sopenharmony_ci * 12048c2ecf20Sopenharmony_ci * cpia2_init/module_init 12058c2ecf20Sopenharmony_ci * 12068c2ecf20Sopenharmony_ci *****************************************************************************/ 12078c2ecf20Sopenharmony_cistatic int __init cpia2_init(void) 12088c2ecf20Sopenharmony_ci{ 12098c2ecf20Sopenharmony_ci LOG("%s v%s\n", 12108c2ecf20Sopenharmony_ci ABOUT, CPIA_VERSION); 12118c2ecf20Sopenharmony_ci check_parameters(); 12128c2ecf20Sopenharmony_ci return cpia2_usb_init(); 12138c2ecf20Sopenharmony_ci} 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci/****************************************************************************** 12178c2ecf20Sopenharmony_ci * 12188c2ecf20Sopenharmony_ci * cpia2_exit/module_exit 12198c2ecf20Sopenharmony_ci * 12208c2ecf20Sopenharmony_ci *****************************************************************************/ 12218c2ecf20Sopenharmony_cistatic void __exit cpia2_exit(void) 12228c2ecf20Sopenharmony_ci{ 12238c2ecf20Sopenharmony_ci cpia2_usb_cleanup(); 12248c2ecf20Sopenharmony_ci schedule_timeout(2 * HZ); 12258c2ecf20Sopenharmony_ci} 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_cimodule_init(cpia2_init); 12288c2ecf20Sopenharmony_cimodule_exit(cpia2_exit); 1229