18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Zoran 364xx based USB webcam module version 0.73 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Allows you to use your USB webcam with V4L2 applications 68c2ecf20Sopenharmony_ci * This is still in heavy development ! 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Copyright (C) 2004 Antoine Jacquet <royale@zerezo.com> 98c2ecf20Sopenharmony_ci * http://royale.zerezo.com/zr364xx/ 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Heavily inspired by usb-skeleton.c, vicam.c, cpia.c and spca50x.c drivers 128c2ecf20Sopenharmony_ci * V4L2 version inspired by meye.c driver 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * Some video buffer code by Lamarque based on s2255drv.c and vivi.c drivers. 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <linux/module.h> 198c2ecf20Sopenharmony_ci#include <linux/init.h> 208c2ecf20Sopenharmony_ci#include <linux/usb.h> 218c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 228c2ecf20Sopenharmony_ci#include <linux/slab.h> 238c2ecf20Sopenharmony_ci#include <linux/highmem.h> 248c2ecf20Sopenharmony_ci#include <media/v4l2-common.h> 258c2ecf20Sopenharmony_ci#include <media/v4l2-ioctl.h> 268c2ecf20Sopenharmony_ci#include <media/v4l2-device.h> 278c2ecf20Sopenharmony_ci#include <media/v4l2-ctrls.h> 288c2ecf20Sopenharmony_ci#include <media/v4l2-fh.h> 298c2ecf20Sopenharmony_ci#include <media/v4l2-event.h> 308c2ecf20Sopenharmony_ci#include <media/videobuf-vmalloc.h> 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/* Version Information */ 348c2ecf20Sopenharmony_ci#define DRIVER_VERSION "0.7.4" 358c2ecf20Sopenharmony_ci#define DRIVER_AUTHOR "Antoine Jacquet, http://royale.zerezo.com/" 368c2ecf20Sopenharmony_ci#define DRIVER_DESC "Zoran 364xx" 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci/* Camera */ 408c2ecf20Sopenharmony_ci#define FRAMES 1 418c2ecf20Sopenharmony_ci#define MAX_FRAME_SIZE 200000 428c2ecf20Sopenharmony_ci#define BUFFER_SIZE 0x1000 438c2ecf20Sopenharmony_ci#define CTRL_TIMEOUT 500 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#define ZR364XX_DEF_BUFS 4 468c2ecf20Sopenharmony_ci#define ZR364XX_READ_IDLE 0 478c2ecf20Sopenharmony_ci#define ZR364XX_READ_FRAME 1 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci/* Debug macro */ 508c2ecf20Sopenharmony_ci#define DBG(fmt, args...) \ 518c2ecf20Sopenharmony_ci do { \ 528c2ecf20Sopenharmony_ci if (debug) { \ 538c2ecf20Sopenharmony_ci printk(KERN_INFO KBUILD_MODNAME " " fmt, ##args); \ 548c2ecf20Sopenharmony_ci } \ 558c2ecf20Sopenharmony_ci } while (0) 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci/*#define FULL_DEBUG 1*/ 588c2ecf20Sopenharmony_ci#ifdef FULL_DEBUG 598c2ecf20Sopenharmony_ci#define _DBG DBG 608c2ecf20Sopenharmony_ci#else 618c2ecf20Sopenharmony_ci#define _DBG(fmt, args...) 628c2ecf20Sopenharmony_ci#endif 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci/* Init methods, need to find nicer names for these 658c2ecf20Sopenharmony_ci * the exact names of the chipsets would be the best if someone finds it */ 668c2ecf20Sopenharmony_ci#define METHOD0 0 678c2ecf20Sopenharmony_ci#define METHOD1 1 688c2ecf20Sopenharmony_ci#define METHOD2 2 698c2ecf20Sopenharmony_ci#define METHOD3 3 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci/* Module parameters */ 738c2ecf20Sopenharmony_cistatic int debug; 748c2ecf20Sopenharmony_cistatic int mode; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci/* Module parameters interface */ 788c2ecf20Sopenharmony_cimodule_param(debug, int, 0644); 798c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "Debug level"); 808c2ecf20Sopenharmony_cimodule_param(mode, int, 0644); 818c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mode, "0 = 320x240, 1 = 160x120, 2 = 640x480"); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci/* Devices supported by this driver 858c2ecf20Sopenharmony_ci * .driver_info contains the init method used by the camera */ 868c2ecf20Sopenharmony_cistatic const struct usb_device_id device_table[] = { 878c2ecf20Sopenharmony_ci {USB_DEVICE(0x08ca, 0x0109), .driver_info = METHOD0 }, 888c2ecf20Sopenharmony_ci {USB_DEVICE(0x041e, 0x4024), .driver_info = METHOD0 }, 898c2ecf20Sopenharmony_ci {USB_DEVICE(0x0d64, 0x0108), .driver_info = METHOD0 }, 908c2ecf20Sopenharmony_ci {USB_DEVICE(0x0546, 0x3187), .driver_info = METHOD0 }, 918c2ecf20Sopenharmony_ci {USB_DEVICE(0x0d64, 0x3108), .driver_info = METHOD0 }, 928c2ecf20Sopenharmony_ci {USB_DEVICE(0x0595, 0x4343), .driver_info = METHOD0 }, 938c2ecf20Sopenharmony_ci {USB_DEVICE(0x0bb0, 0x500d), .driver_info = METHOD0 }, 948c2ecf20Sopenharmony_ci {USB_DEVICE(0x0feb, 0x2004), .driver_info = METHOD0 }, 958c2ecf20Sopenharmony_ci {USB_DEVICE(0x055f, 0xb500), .driver_info = METHOD0 }, 968c2ecf20Sopenharmony_ci {USB_DEVICE(0x08ca, 0x2062), .driver_info = METHOD2 }, 978c2ecf20Sopenharmony_ci {USB_DEVICE(0x052b, 0x1a18), .driver_info = METHOD1 }, 988c2ecf20Sopenharmony_ci {USB_DEVICE(0x04c8, 0x0729), .driver_info = METHOD0 }, 998c2ecf20Sopenharmony_ci {USB_DEVICE(0x04f2, 0xa208), .driver_info = METHOD0 }, 1008c2ecf20Sopenharmony_ci {USB_DEVICE(0x0784, 0x0040), .driver_info = METHOD1 }, 1018c2ecf20Sopenharmony_ci {USB_DEVICE(0x06d6, 0x0034), .driver_info = METHOD0 }, 1028c2ecf20Sopenharmony_ci {USB_DEVICE(0x0a17, 0x0062), .driver_info = METHOD2 }, 1038c2ecf20Sopenharmony_ci {USB_DEVICE(0x06d6, 0x003b), .driver_info = METHOD0 }, 1048c2ecf20Sopenharmony_ci {USB_DEVICE(0x0a17, 0x004e), .driver_info = METHOD2 }, 1058c2ecf20Sopenharmony_ci {USB_DEVICE(0x041e, 0x405d), .driver_info = METHOD2 }, 1068c2ecf20Sopenharmony_ci {USB_DEVICE(0x08ca, 0x2102), .driver_info = METHOD3 }, 1078c2ecf20Sopenharmony_ci {USB_DEVICE(0x06d6, 0x003d), .driver_info = METHOD0 }, 1088c2ecf20Sopenharmony_ci {} /* Terminating entry */ 1098c2ecf20Sopenharmony_ci}; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(usb, device_table); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci/* frame structure */ 1148c2ecf20Sopenharmony_cistruct zr364xx_framei { 1158c2ecf20Sopenharmony_ci unsigned long ulState; /* ulState:ZR364XX_READ_IDLE, 1168c2ecf20Sopenharmony_ci ZR364XX_READ_FRAME */ 1178c2ecf20Sopenharmony_ci void *lpvbits; /* image data */ 1188c2ecf20Sopenharmony_ci unsigned long cur_size; /* current data copied to it */ 1198c2ecf20Sopenharmony_ci}; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci/* image buffer structure */ 1228c2ecf20Sopenharmony_cistruct zr364xx_bufferi { 1238c2ecf20Sopenharmony_ci unsigned long dwFrames; /* number of frames in buffer */ 1248c2ecf20Sopenharmony_ci struct zr364xx_framei frame[FRAMES]; /* array of FRAME structures */ 1258c2ecf20Sopenharmony_ci}; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistruct zr364xx_dmaqueue { 1288c2ecf20Sopenharmony_ci struct list_head active; 1298c2ecf20Sopenharmony_ci struct zr364xx_camera *cam; 1308c2ecf20Sopenharmony_ci}; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistruct zr364xx_pipeinfo { 1338c2ecf20Sopenharmony_ci u32 transfer_size; 1348c2ecf20Sopenharmony_ci u8 *transfer_buffer; 1358c2ecf20Sopenharmony_ci u32 state; 1368c2ecf20Sopenharmony_ci void *stream_urb; 1378c2ecf20Sopenharmony_ci void *cam; /* back pointer to zr364xx_camera struct */ 1388c2ecf20Sopenharmony_ci u32 err_count; 1398c2ecf20Sopenharmony_ci u32 idx; 1408c2ecf20Sopenharmony_ci}; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistruct zr364xx_fmt { 1438c2ecf20Sopenharmony_ci u32 fourcc; 1448c2ecf20Sopenharmony_ci int depth; 1458c2ecf20Sopenharmony_ci}; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci/* image formats. */ 1488c2ecf20Sopenharmony_cistatic const struct zr364xx_fmt formats[] = { 1498c2ecf20Sopenharmony_ci { 1508c2ecf20Sopenharmony_ci .fourcc = V4L2_PIX_FMT_JPEG, 1518c2ecf20Sopenharmony_ci .depth = 24 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci}; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci/* Camera stuff */ 1568c2ecf20Sopenharmony_cistruct zr364xx_camera { 1578c2ecf20Sopenharmony_ci struct usb_device *udev; /* save off the usb device pointer */ 1588c2ecf20Sopenharmony_ci struct usb_interface *interface;/* the interface for this device */ 1598c2ecf20Sopenharmony_ci struct v4l2_device v4l2_dev; 1608c2ecf20Sopenharmony_ci struct v4l2_ctrl_handler ctrl_handler; 1618c2ecf20Sopenharmony_ci struct video_device vdev; /* v4l video device */ 1628c2ecf20Sopenharmony_ci struct v4l2_fh *owner; /* owns the streaming */ 1638c2ecf20Sopenharmony_ci int nb; 1648c2ecf20Sopenharmony_ci struct zr364xx_bufferi buffer; 1658c2ecf20Sopenharmony_ci int skip; 1668c2ecf20Sopenharmony_ci int width; 1678c2ecf20Sopenharmony_ci int height; 1688c2ecf20Sopenharmony_ci int method; 1698c2ecf20Sopenharmony_ci struct mutex lock; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci spinlock_t slock; 1728c2ecf20Sopenharmony_ci struct zr364xx_dmaqueue vidq; 1738c2ecf20Sopenharmony_ci int last_frame; 1748c2ecf20Sopenharmony_ci int cur_frame; 1758c2ecf20Sopenharmony_ci unsigned long frame_count; 1768c2ecf20Sopenharmony_ci int b_acquire; 1778c2ecf20Sopenharmony_ci struct zr364xx_pipeinfo pipe[1]; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci u8 read_endpoint; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci const struct zr364xx_fmt *fmt; 1828c2ecf20Sopenharmony_ci struct videobuf_queue vb_vidq; 1838c2ecf20Sopenharmony_ci bool was_streaming; 1848c2ecf20Sopenharmony_ci}; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci/* buffer for one video frame */ 1878c2ecf20Sopenharmony_cistruct zr364xx_buffer { 1888c2ecf20Sopenharmony_ci /* common v4l buffer stuff -- must be first */ 1898c2ecf20Sopenharmony_ci struct videobuf_buffer vb; 1908c2ecf20Sopenharmony_ci const struct zr364xx_fmt *fmt; 1918c2ecf20Sopenharmony_ci}; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci/* function used to send initialisation commands to the camera */ 1948c2ecf20Sopenharmony_cistatic int send_control_msg(struct usb_device *udev, u8 request, u16 value, 1958c2ecf20Sopenharmony_ci u16 index, unsigned char *cp, u16 size) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci int status; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci unsigned char *transfer_buffer = kmemdup(cp, size, GFP_KERNEL); 2008c2ecf20Sopenharmony_ci if (!transfer_buffer) 2018c2ecf20Sopenharmony_ci return -ENOMEM; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci status = usb_control_msg(udev, 2048c2ecf20Sopenharmony_ci usb_sndctrlpipe(udev, 0), 2058c2ecf20Sopenharmony_ci request, 2068c2ecf20Sopenharmony_ci USB_DIR_OUT | USB_TYPE_VENDOR | 2078c2ecf20Sopenharmony_ci USB_RECIP_DEVICE, value, index, 2088c2ecf20Sopenharmony_ci transfer_buffer, size, CTRL_TIMEOUT); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci kfree(transfer_buffer); 2118c2ecf20Sopenharmony_ci return status; 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci/* Control messages sent to the camera to initialize it 2168c2ecf20Sopenharmony_ci * and launch the capture */ 2178c2ecf20Sopenharmony_citypedef struct { 2188c2ecf20Sopenharmony_ci unsigned int value; 2198c2ecf20Sopenharmony_ci unsigned int size; 2208c2ecf20Sopenharmony_ci unsigned char *bytes; 2218c2ecf20Sopenharmony_ci} message; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci/* method 0 */ 2248c2ecf20Sopenharmony_cistatic unsigned char m0d1[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 2258c2ecf20Sopenharmony_cistatic unsigned char m0d2[] = { 0, 0, 0, 0, 0, 0 }; 2268c2ecf20Sopenharmony_cistatic unsigned char m0d3[] = { 0, 0 }; 2278c2ecf20Sopenharmony_cistatic message m0[] = { 2288c2ecf20Sopenharmony_ci {0x1f30, 0, NULL}, 2298c2ecf20Sopenharmony_ci {0xd000, 0, NULL}, 2308c2ecf20Sopenharmony_ci {0x3370, sizeof(m0d1), m0d1}, 2318c2ecf20Sopenharmony_ci {0x2000, 0, NULL}, 2328c2ecf20Sopenharmony_ci {0x2f0f, 0, NULL}, 2338c2ecf20Sopenharmony_ci {0x2610, sizeof(m0d2), m0d2}, 2348c2ecf20Sopenharmony_ci {0xe107, 0, NULL}, 2358c2ecf20Sopenharmony_ci {0x2502, 0, NULL}, 2368c2ecf20Sopenharmony_ci {0x1f70, 0, NULL}, 2378c2ecf20Sopenharmony_ci {0xd000, 0, NULL}, 2388c2ecf20Sopenharmony_ci {0x9a01, sizeof(m0d3), m0d3}, 2398c2ecf20Sopenharmony_ci {-1, -1, NULL} 2408c2ecf20Sopenharmony_ci}; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci/* method 1 */ 2438c2ecf20Sopenharmony_cistatic unsigned char m1d1[] = { 0xff, 0xff }; 2448c2ecf20Sopenharmony_cistatic unsigned char m1d2[] = { 0x00, 0x00 }; 2458c2ecf20Sopenharmony_cistatic message m1[] = { 2468c2ecf20Sopenharmony_ci {0x1f30, 0, NULL}, 2478c2ecf20Sopenharmony_ci {0xd000, 0, NULL}, 2488c2ecf20Sopenharmony_ci {0xf000, 0, NULL}, 2498c2ecf20Sopenharmony_ci {0x2000, 0, NULL}, 2508c2ecf20Sopenharmony_ci {0x2f0f, 0, NULL}, 2518c2ecf20Sopenharmony_ci {0x2650, 0, NULL}, 2528c2ecf20Sopenharmony_ci {0xe107, 0, NULL}, 2538c2ecf20Sopenharmony_ci {0x2502, sizeof(m1d1), m1d1}, 2548c2ecf20Sopenharmony_ci {0x1f70, 0, NULL}, 2558c2ecf20Sopenharmony_ci {0xd000, 0, NULL}, 2568c2ecf20Sopenharmony_ci {0xd000, 0, NULL}, 2578c2ecf20Sopenharmony_ci {0xd000, 0, NULL}, 2588c2ecf20Sopenharmony_ci {0x9a01, sizeof(m1d2), m1d2}, 2598c2ecf20Sopenharmony_ci {-1, -1, NULL} 2608c2ecf20Sopenharmony_ci}; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci/* method 2 */ 2638c2ecf20Sopenharmony_cistatic unsigned char m2d1[] = { 0xff, 0xff }; 2648c2ecf20Sopenharmony_cistatic message m2[] = { 2658c2ecf20Sopenharmony_ci {0x1f30, 0, NULL}, 2668c2ecf20Sopenharmony_ci {0xf000, 0, NULL}, 2678c2ecf20Sopenharmony_ci {0x2000, 0, NULL}, 2688c2ecf20Sopenharmony_ci {0x2f0f, 0, NULL}, 2698c2ecf20Sopenharmony_ci {0x2650, 0, NULL}, 2708c2ecf20Sopenharmony_ci {0xe107, 0, NULL}, 2718c2ecf20Sopenharmony_ci {0x2502, sizeof(m2d1), m2d1}, 2728c2ecf20Sopenharmony_ci {0x1f70, 0, NULL}, 2738c2ecf20Sopenharmony_ci {-1, -1, NULL} 2748c2ecf20Sopenharmony_ci}; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci/* init table */ 2778c2ecf20Sopenharmony_cistatic message *init[4] = { m0, m1, m2, m2 }; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci/* JPEG static data in header (Huffman table, etc) */ 2818c2ecf20Sopenharmony_cistatic unsigned char header1[] = { 2828c2ecf20Sopenharmony_ci 0xFF, 0xD8, 2838c2ecf20Sopenharmony_ci /* 2848c2ecf20Sopenharmony_ci 0xFF, 0xE0, 0x00, 0x10, 'J', 'F', 'I', 'F', 2858c2ecf20Sopenharmony_ci 0x00, 0x01, 0x01, 0x00, 0x33, 0x8A, 0x00, 0x00, 0x33, 0x88, 2868c2ecf20Sopenharmony_ci */ 2878c2ecf20Sopenharmony_ci 0xFF, 0xDB, 0x00, 0x84 2888c2ecf20Sopenharmony_ci}; 2898c2ecf20Sopenharmony_cistatic unsigned char header2[] = { 2908c2ecf20Sopenharmony_ci 0xFF, 0xC4, 0x00, 0x1F, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 2918c2ecf20Sopenharmony_ci 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 2928c2ecf20Sopenharmony_ci 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 2938c2ecf20Sopenharmony_ci 0xFF, 0xC4, 0x00, 0xB5, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 2948c2ecf20Sopenharmony_ci 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7D, 0x01, 2958c2ecf20Sopenharmony_ci 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 2968c2ecf20Sopenharmony_ci 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, 2978c2ecf20Sopenharmony_ci 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24, 0x33, 2988c2ecf20Sopenharmony_ci 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x25, 2998c2ecf20Sopenharmony_ci 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 3008c2ecf20Sopenharmony_ci 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 3018c2ecf20Sopenharmony_ci 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 3028c2ecf20Sopenharmony_ci 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 3038c2ecf20Sopenharmony_ci 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 3048c2ecf20Sopenharmony_ci 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 3058c2ecf20Sopenharmony_ci 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 3068c2ecf20Sopenharmony_ci 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 3078c2ecf20Sopenharmony_ci 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1, 0xE2, 3088c2ecf20Sopenharmony_ci 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, 3098c2ecf20Sopenharmony_ci 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFF, 0xC4, 0x00, 0x1F, 3108c2ecf20Sopenharmony_ci 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 3118c2ecf20Sopenharmony_ci 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 3128c2ecf20Sopenharmony_ci 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0xFF, 0xC4, 0x00, 0xB5, 3138c2ecf20Sopenharmony_ci 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 3148c2ecf20Sopenharmony_ci 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 3158c2ecf20Sopenharmony_ci 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 3168c2ecf20Sopenharmony_ci 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xA1, 0xB1, 0xC1, 3178c2ecf20Sopenharmony_ci 0x09, 0x23, 0x33, 0x52, 0xF0, 0x15, 0x62, 0x72, 0xD1, 0x0A, 0x16, 3188c2ecf20Sopenharmony_ci 0x24, 0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26, 0x27, 3198c2ecf20Sopenharmony_ci 0x28, 0x29, 0x2A, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 3208c2ecf20Sopenharmony_ci 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 3218c2ecf20Sopenharmony_ci 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 3228c2ecf20Sopenharmony_ci 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x82, 0x83, 0x84, 3238c2ecf20Sopenharmony_ci 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 3248c2ecf20Sopenharmony_ci 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 3258c2ecf20Sopenharmony_ci 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 3268c2ecf20Sopenharmony_ci 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 3278c2ecf20Sopenharmony_ci 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, 3288c2ecf20Sopenharmony_ci 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 3298c2ecf20Sopenharmony_ci 0xF8, 0xF9, 0xFA, 0xFF, 0xC0, 0x00, 0x11, 0x08, 0x00, 0xF0, 0x01, 3308c2ecf20Sopenharmony_ci 0x40, 0x03, 0x01, 0x21, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 3318c2ecf20Sopenharmony_ci 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 3328c2ecf20Sopenharmony_ci 0x00, 0x3F, 0x00 3338c2ecf20Sopenharmony_ci}; 3348c2ecf20Sopenharmony_cistatic unsigned char header3; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------ 3378c2ecf20Sopenharmony_ci Videobuf operations 3388c2ecf20Sopenharmony_ci ------------------------------------------------------------------*/ 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_cistatic int buffer_setup(struct videobuf_queue *vq, unsigned int *count, 3418c2ecf20Sopenharmony_ci unsigned int *size) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci struct zr364xx_camera *cam = vq->priv_data; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci *size = cam->width * cam->height * (cam->fmt->depth >> 3); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci if (*count == 0) 3488c2ecf20Sopenharmony_ci *count = ZR364XX_DEF_BUFS; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci if (*size * *count > ZR364XX_DEF_BUFS * 1024 * 1024) 3518c2ecf20Sopenharmony_ci *count = (ZR364XX_DEF_BUFS * 1024 * 1024) / *size; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci return 0; 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_cistatic void free_buffer(struct videobuf_queue *vq, struct zr364xx_buffer *buf) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci _DBG("%s\n", __func__); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci BUG_ON(in_interrupt()); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci videobuf_vmalloc_free(&buf->vb); 3638c2ecf20Sopenharmony_ci buf->vb.state = VIDEOBUF_NEEDS_INIT; 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_cistatic int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, 3678c2ecf20Sopenharmony_ci enum v4l2_field field) 3688c2ecf20Sopenharmony_ci{ 3698c2ecf20Sopenharmony_ci struct zr364xx_camera *cam = vq->priv_data; 3708c2ecf20Sopenharmony_ci struct zr364xx_buffer *buf = container_of(vb, struct zr364xx_buffer, 3718c2ecf20Sopenharmony_ci vb); 3728c2ecf20Sopenharmony_ci int rc; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci DBG("%s, field=%d\n", __func__, field); 3758c2ecf20Sopenharmony_ci if (!cam->fmt) 3768c2ecf20Sopenharmony_ci return -EINVAL; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci buf->vb.size = cam->width * cam->height * (cam->fmt->depth >> 3); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci if (buf->vb.baddr != 0 && buf->vb.bsize < buf->vb.size) { 3818c2ecf20Sopenharmony_ci DBG("invalid buffer prepare\n"); 3828c2ecf20Sopenharmony_ci return -EINVAL; 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci buf->fmt = cam->fmt; 3868c2ecf20Sopenharmony_ci buf->vb.width = cam->width; 3878c2ecf20Sopenharmony_ci buf->vb.height = cam->height; 3888c2ecf20Sopenharmony_ci buf->vb.field = field; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci if (buf->vb.state == VIDEOBUF_NEEDS_INIT) { 3918c2ecf20Sopenharmony_ci rc = videobuf_iolock(vq, &buf->vb, NULL); 3928c2ecf20Sopenharmony_ci if (rc < 0) 3938c2ecf20Sopenharmony_ci goto fail; 3948c2ecf20Sopenharmony_ci } 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci buf->vb.state = VIDEOBUF_PREPARED; 3978c2ecf20Sopenharmony_ci return 0; 3988c2ecf20Sopenharmony_cifail: 3998c2ecf20Sopenharmony_ci free_buffer(vq, buf); 4008c2ecf20Sopenharmony_ci return rc; 4018c2ecf20Sopenharmony_ci} 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_cistatic void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) 4048c2ecf20Sopenharmony_ci{ 4058c2ecf20Sopenharmony_ci struct zr364xx_buffer *buf = container_of(vb, struct zr364xx_buffer, 4068c2ecf20Sopenharmony_ci vb); 4078c2ecf20Sopenharmony_ci struct zr364xx_camera *cam = vq->priv_data; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci _DBG("%s\n", __func__); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci buf->vb.state = VIDEOBUF_QUEUED; 4128c2ecf20Sopenharmony_ci list_add_tail(&buf->vb.queue, &cam->vidq.active); 4138c2ecf20Sopenharmony_ci} 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_cistatic void buffer_release(struct videobuf_queue *vq, 4168c2ecf20Sopenharmony_ci struct videobuf_buffer *vb) 4178c2ecf20Sopenharmony_ci{ 4188c2ecf20Sopenharmony_ci struct zr364xx_buffer *buf = container_of(vb, struct zr364xx_buffer, 4198c2ecf20Sopenharmony_ci vb); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci _DBG("%s\n", __func__); 4228c2ecf20Sopenharmony_ci free_buffer(vq, buf); 4238c2ecf20Sopenharmony_ci} 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_cistatic const struct videobuf_queue_ops zr364xx_video_qops = { 4268c2ecf20Sopenharmony_ci .buf_setup = buffer_setup, 4278c2ecf20Sopenharmony_ci .buf_prepare = buffer_prepare, 4288c2ecf20Sopenharmony_ci .buf_queue = buffer_queue, 4298c2ecf20Sopenharmony_ci .buf_release = buffer_release, 4308c2ecf20Sopenharmony_ci}; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci/********************/ 4338c2ecf20Sopenharmony_ci/* V4L2 integration */ 4348c2ecf20Sopenharmony_ci/********************/ 4358c2ecf20Sopenharmony_cistatic int zr364xx_vidioc_streamon(struct file *file, void *priv, 4368c2ecf20Sopenharmony_ci enum v4l2_buf_type type); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_cistatic ssize_t zr364xx_read(struct file *file, char __user *buf, size_t count, 4398c2ecf20Sopenharmony_ci loff_t * ppos) 4408c2ecf20Sopenharmony_ci{ 4418c2ecf20Sopenharmony_ci struct zr364xx_camera *cam = video_drvdata(file); 4428c2ecf20Sopenharmony_ci int err = 0; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci _DBG("%s\n", __func__); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci if (!buf) 4478c2ecf20Sopenharmony_ci return -EINVAL; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci if (!count) 4508c2ecf20Sopenharmony_ci return -EINVAL; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&cam->lock)) 4538c2ecf20Sopenharmony_ci return -ERESTARTSYS; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci err = zr364xx_vidioc_streamon(file, file->private_data, 4568c2ecf20Sopenharmony_ci V4L2_BUF_TYPE_VIDEO_CAPTURE); 4578c2ecf20Sopenharmony_ci if (err == 0) { 4588c2ecf20Sopenharmony_ci DBG("%s: reading %d bytes at pos %d.\n", __func__, 4598c2ecf20Sopenharmony_ci (int) count, (int) *ppos); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci /* NoMan Sux ! */ 4628c2ecf20Sopenharmony_ci err = videobuf_read_one(&cam->vb_vidq, buf, count, ppos, 4638c2ecf20Sopenharmony_ci file->f_flags & O_NONBLOCK); 4648c2ecf20Sopenharmony_ci } 4658c2ecf20Sopenharmony_ci mutex_unlock(&cam->lock); 4668c2ecf20Sopenharmony_ci return err; 4678c2ecf20Sopenharmony_ci} 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci/* video buffer vmalloc implementation based partly on VIVI driver which is 4708c2ecf20Sopenharmony_ci * Copyright (c) 2006 by 4718c2ecf20Sopenharmony_ci * Mauro Carvalho Chehab <mchehab--a.t--infradead.org> 4728c2ecf20Sopenharmony_ci * Ted Walther <ted--a.t--enumera.com> 4738c2ecf20Sopenharmony_ci * John Sokol <sokol--a.t--videotechnology.com> 4748c2ecf20Sopenharmony_ci * http://v4l.videotechnology.com/ 4758c2ecf20Sopenharmony_ci * 4768c2ecf20Sopenharmony_ci */ 4778c2ecf20Sopenharmony_cistatic void zr364xx_fillbuff(struct zr364xx_camera *cam, 4788c2ecf20Sopenharmony_ci struct zr364xx_buffer *buf, 4798c2ecf20Sopenharmony_ci int jpgsize) 4808c2ecf20Sopenharmony_ci{ 4818c2ecf20Sopenharmony_ci int pos = 0; 4828c2ecf20Sopenharmony_ci const char *tmpbuf; 4838c2ecf20Sopenharmony_ci char *vbuf = videobuf_to_vmalloc(&buf->vb); 4848c2ecf20Sopenharmony_ci unsigned long last_frame; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci if (!vbuf) 4878c2ecf20Sopenharmony_ci return; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci last_frame = cam->last_frame; 4908c2ecf20Sopenharmony_ci if (last_frame != -1) { 4918c2ecf20Sopenharmony_ci tmpbuf = (const char *)cam->buffer.frame[last_frame].lpvbits; 4928c2ecf20Sopenharmony_ci switch (buf->fmt->fourcc) { 4938c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_JPEG: 4948c2ecf20Sopenharmony_ci buf->vb.size = jpgsize; 4958c2ecf20Sopenharmony_ci memcpy(vbuf, tmpbuf, buf->vb.size); 4968c2ecf20Sopenharmony_ci break; 4978c2ecf20Sopenharmony_ci default: 4988c2ecf20Sopenharmony_ci printk(KERN_DEBUG KBUILD_MODNAME ": unknown format?\n"); 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci cam->last_frame = -1; 5018c2ecf20Sopenharmony_ci } else { 5028c2ecf20Sopenharmony_ci printk(KERN_ERR KBUILD_MODNAME ": =======no frame\n"); 5038c2ecf20Sopenharmony_ci return; 5048c2ecf20Sopenharmony_ci } 5058c2ecf20Sopenharmony_ci DBG("%s: Buffer %p size= %d\n", __func__, vbuf, pos); 5068c2ecf20Sopenharmony_ci /* tell v4l buffer was filled */ 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci buf->vb.field_count = cam->frame_count * 2; 5098c2ecf20Sopenharmony_ci buf->vb.ts = ktime_get_ns(); 5108c2ecf20Sopenharmony_ci buf->vb.state = VIDEOBUF_DONE; 5118c2ecf20Sopenharmony_ci} 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_cistatic int zr364xx_got_frame(struct zr364xx_camera *cam, int jpgsize) 5148c2ecf20Sopenharmony_ci{ 5158c2ecf20Sopenharmony_ci struct zr364xx_dmaqueue *dma_q = &cam->vidq; 5168c2ecf20Sopenharmony_ci struct zr364xx_buffer *buf; 5178c2ecf20Sopenharmony_ci unsigned long flags = 0; 5188c2ecf20Sopenharmony_ci int rc = 0; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci DBG("wakeup: %p\n", &dma_q); 5218c2ecf20Sopenharmony_ci spin_lock_irqsave(&cam->slock, flags); 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci if (list_empty(&dma_q->active)) { 5248c2ecf20Sopenharmony_ci DBG("No active queue to serve\n"); 5258c2ecf20Sopenharmony_ci rc = -1; 5268c2ecf20Sopenharmony_ci goto unlock; 5278c2ecf20Sopenharmony_ci } 5288c2ecf20Sopenharmony_ci buf = list_entry(dma_q->active.next, 5298c2ecf20Sopenharmony_ci struct zr364xx_buffer, vb.queue); 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci if (!waitqueue_active(&buf->vb.done)) { 5328c2ecf20Sopenharmony_ci /* no one active */ 5338c2ecf20Sopenharmony_ci rc = -1; 5348c2ecf20Sopenharmony_ci goto unlock; 5358c2ecf20Sopenharmony_ci } 5368c2ecf20Sopenharmony_ci list_del(&buf->vb.queue); 5378c2ecf20Sopenharmony_ci buf->vb.ts = ktime_get_ns(); 5388c2ecf20Sopenharmony_ci DBG("[%p/%d] wakeup\n", buf, buf->vb.i); 5398c2ecf20Sopenharmony_ci zr364xx_fillbuff(cam, buf, jpgsize); 5408c2ecf20Sopenharmony_ci wake_up(&buf->vb.done); 5418c2ecf20Sopenharmony_ci DBG("wakeup [buf/i] [%p/%d]\n", buf, buf->vb.i); 5428c2ecf20Sopenharmony_ciunlock: 5438c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cam->slock, flags); 5448c2ecf20Sopenharmony_ci return rc; 5458c2ecf20Sopenharmony_ci} 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci/* this function moves the usb stream read pipe data 5488c2ecf20Sopenharmony_ci * into the system buffers. 5498c2ecf20Sopenharmony_ci * returns 0 on success, EAGAIN if more data to process (call this 5508c2ecf20Sopenharmony_ci * function again). 5518c2ecf20Sopenharmony_ci */ 5528c2ecf20Sopenharmony_cistatic int zr364xx_read_video_callback(struct zr364xx_camera *cam, 5538c2ecf20Sopenharmony_ci struct zr364xx_pipeinfo *pipe_info, 5548c2ecf20Sopenharmony_ci struct urb *purb) 5558c2ecf20Sopenharmony_ci{ 5568c2ecf20Sopenharmony_ci unsigned char *pdest; 5578c2ecf20Sopenharmony_ci unsigned char *psrc; 5588c2ecf20Sopenharmony_ci s32 idx = cam->cur_frame; 5598c2ecf20Sopenharmony_ci struct zr364xx_framei *frm = &cam->buffer.frame[idx]; 5608c2ecf20Sopenharmony_ci int i = 0; 5618c2ecf20Sopenharmony_ci unsigned char *ptr = NULL; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci _DBG("buffer to user\n"); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci /* swap bytes if camera needs it */ 5668c2ecf20Sopenharmony_ci if (cam->method == METHOD0) { 5678c2ecf20Sopenharmony_ci u16 *buf = (u16 *)pipe_info->transfer_buffer; 5688c2ecf20Sopenharmony_ci for (i = 0; i < purb->actual_length/2; i++) 5698c2ecf20Sopenharmony_ci swab16s(buf + i); 5708c2ecf20Sopenharmony_ci } 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci /* search done. now find out if should be acquiring */ 5738c2ecf20Sopenharmony_ci if (!cam->b_acquire) { 5748c2ecf20Sopenharmony_ci /* we found a frame, but this channel is turned off */ 5758c2ecf20Sopenharmony_ci frm->ulState = ZR364XX_READ_IDLE; 5768c2ecf20Sopenharmony_ci return -EINVAL; 5778c2ecf20Sopenharmony_ci } 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci psrc = (u8 *)pipe_info->transfer_buffer; 5808c2ecf20Sopenharmony_ci ptr = pdest = frm->lpvbits; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci if (frm->ulState == ZR364XX_READ_IDLE) { 5838c2ecf20Sopenharmony_ci if (purb->actual_length < 128) { 5848c2ecf20Sopenharmony_ci /* header incomplete */ 5858c2ecf20Sopenharmony_ci dev_info(&cam->udev->dev, 5868c2ecf20Sopenharmony_ci "%s: buffer (%d bytes) too small to hold jpeg header. Discarding.\n", 5878c2ecf20Sopenharmony_ci __func__, purb->actual_length); 5888c2ecf20Sopenharmony_ci return -EINVAL; 5898c2ecf20Sopenharmony_ci } 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci frm->ulState = ZR364XX_READ_FRAME; 5928c2ecf20Sopenharmony_ci frm->cur_size = 0; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci _DBG("jpeg header, "); 5958c2ecf20Sopenharmony_ci memcpy(ptr, header1, sizeof(header1)); 5968c2ecf20Sopenharmony_ci ptr += sizeof(header1); 5978c2ecf20Sopenharmony_ci header3 = 0; 5988c2ecf20Sopenharmony_ci memcpy(ptr, &header3, 1); 5998c2ecf20Sopenharmony_ci ptr++; 6008c2ecf20Sopenharmony_ci memcpy(ptr, psrc, 64); 6018c2ecf20Sopenharmony_ci ptr += 64; 6028c2ecf20Sopenharmony_ci header3 = 1; 6038c2ecf20Sopenharmony_ci memcpy(ptr, &header3, 1); 6048c2ecf20Sopenharmony_ci ptr++; 6058c2ecf20Sopenharmony_ci memcpy(ptr, psrc + 64, 64); 6068c2ecf20Sopenharmony_ci ptr += 64; 6078c2ecf20Sopenharmony_ci memcpy(ptr, header2, sizeof(header2)); 6088c2ecf20Sopenharmony_ci ptr += sizeof(header2); 6098c2ecf20Sopenharmony_ci memcpy(ptr, psrc + 128, 6108c2ecf20Sopenharmony_ci purb->actual_length - 128); 6118c2ecf20Sopenharmony_ci ptr += purb->actual_length - 128; 6128c2ecf20Sopenharmony_ci _DBG("header : %d %d %d %d %d %d %d %d %d\n", 6138c2ecf20Sopenharmony_ci psrc[0], psrc[1], psrc[2], 6148c2ecf20Sopenharmony_ci psrc[3], psrc[4], psrc[5], 6158c2ecf20Sopenharmony_ci psrc[6], psrc[7], psrc[8]); 6168c2ecf20Sopenharmony_ci frm->cur_size = ptr - pdest; 6178c2ecf20Sopenharmony_ci } else { 6188c2ecf20Sopenharmony_ci if (frm->cur_size + purb->actual_length > MAX_FRAME_SIZE) { 6198c2ecf20Sopenharmony_ci dev_info(&cam->udev->dev, 6208c2ecf20Sopenharmony_ci "%s: buffer (%d bytes) too small to hold frame data. Discarding frame data.\n", 6218c2ecf20Sopenharmony_ci __func__, MAX_FRAME_SIZE); 6228c2ecf20Sopenharmony_ci } else { 6238c2ecf20Sopenharmony_ci pdest += frm->cur_size; 6248c2ecf20Sopenharmony_ci memcpy(pdest, psrc, purb->actual_length); 6258c2ecf20Sopenharmony_ci frm->cur_size += purb->actual_length; 6268c2ecf20Sopenharmony_ci } 6278c2ecf20Sopenharmony_ci } 6288c2ecf20Sopenharmony_ci /*_DBG("cur_size %lu urb size %d\n", frm->cur_size, 6298c2ecf20Sopenharmony_ci purb->actual_length);*/ 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci if (purb->actual_length < pipe_info->transfer_size) { 6328c2ecf20Sopenharmony_ci _DBG("****************Buffer[%d]full*************\n", idx); 6338c2ecf20Sopenharmony_ci cam->last_frame = cam->cur_frame; 6348c2ecf20Sopenharmony_ci cam->cur_frame++; 6358c2ecf20Sopenharmony_ci /* end of system frame ring buffer, start at zero */ 6368c2ecf20Sopenharmony_ci if (cam->cur_frame == cam->buffer.dwFrames) 6378c2ecf20Sopenharmony_ci cam->cur_frame = 0; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci /* frame ready */ 6408c2ecf20Sopenharmony_ci /* go back to find the JPEG EOI marker */ 6418c2ecf20Sopenharmony_ci ptr = pdest = frm->lpvbits; 6428c2ecf20Sopenharmony_ci ptr += frm->cur_size - 2; 6438c2ecf20Sopenharmony_ci while (ptr > pdest) { 6448c2ecf20Sopenharmony_ci if (*ptr == 0xFF && *(ptr + 1) == 0xD9 6458c2ecf20Sopenharmony_ci && *(ptr + 2) == 0xFF) 6468c2ecf20Sopenharmony_ci break; 6478c2ecf20Sopenharmony_ci ptr--; 6488c2ecf20Sopenharmony_ci } 6498c2ecf20Sopenharmony_ci if (ptr == pdest) 6508c2ecf20Sopenharmony_ci DBG("No EOI marker\n"); 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci /* Sometimes there is junk data in the middle of the picture, 6538c2ecf20Sopenharmony_ci * we want to skip this bogus frames */ 6548c2ecf20Sopenharmony_ci while (ptr > pdest) { 6558c2ecf20Sopenharmony_ci if (*ptr == 0xFF && *(ptr + 1) == 0xFF 6568c2ecf20Sopenharmony_ci && *(ptr + 2) == 0xFF) 6578c2ecf20Sopenharmony_ci break; 6588c2ecf20Sopenharmony_ci ptr--; 6598c2ecf20Sopenharmony_ci } 6608c2ecf20Sopenharmony_ci if (ptr != pdest) { 6618c2ecf20Sopenharmony_ci DBG("Bogus frame ? %d\n", ++(cam->nb)); 6628c2ecf20Sopenharmony_ci } else if (cam->b_acquire) { 6638c2ecf20Sopenharmony_ci /* we skip the 2 first frames which are usually buggy */ 6648c2ecf20Sopenharmony_ci if (cam->skip) 6658c2ecf20Sopenharmony_ci cam->skip--; 6668c2ecf20Sopenharmony_ci else { 6678c2ecf20Sopenharmony_ci _DBG("jpeg(%lu): %d %d %d %d %d %d %d %d\n", 6688c2ecf20Sopenharmony_ci frm->cur_size, 6698c2ecf20Sopenharmony_ci pdest[0], pdest[1], pdest[2], pdest[3], 6708c2ecf20Sopenharmony_ci pdest[4], pdest[5], pdest[6], pdest[7]); 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci zr364xx_got_frame(cam, frm->cur_size); 6738c2ecf20Sopenharmony_ci } 6748c2ecf20Sopenharmony_ci } 6758c2ecf20Sopenharmony_ci cam->frame_count++; 6768c2ecf20Sopenharmony_ci frm->ulState = ZR364XX_READ_IDLE; 6778c2ecf20Sopenharmony_ci frm->cur_size = 0; 6788c2ecf20Sopenharmony_ci } 6798c2ecf20Sopenharmony_ci /* done successfully */ 6808c2ecf20Sopenharmony_ci return 0; 6818c2ecf20Sopenharmony_ci} 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_cistatic int zr364xx_vidioc_querycap(struct file *file, void *priv, 6848c2ecf20Sopenharmony_ci struct v4l2_capability *cap) 6858c2ecf20Sopenharmony_ci{ 6868c2ecf20Sopenharmony_ci struct zr364xx_camera *cam = video_drvdata(file); 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci strscpy(cap->driver, DRIVER_DESC, sizeof(cap->driver)); 6898c2ecf20Sopenharmony_ci if (cam->udev->product) 6908c2ecf20Sopenharmony_ci strscpy(cap->card, cam->udev->product, sizeof(cap->card)); 6918c2ecf20Sopenharmony_ci strscpy(cap->bus_info, dev_name(&cam->udev->dev), 6928c2ecf20Sopenharmony_ci sizeof(cap->bus_info)); 6938c2ecf20Sopenharmony_ci return 0; 6948c2ecf20Sopenharmony_ci} 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_cistatic int zr364xx_vidioc_enum_input(struct file *file, void *priv, 6978c2ecf20Sopenharmony_ci struct v4l2_input *i) 6988c2ecf20Sopenharmony_ci{ 6998c2ecf20Sopenharmony_ci if (i->index != 0) 7008c2ecf20Sopenharmony_ci return -EINVAL; 7018c2ecf20Sopenharmony_ci strscpy(i->name, DRIVER_DESC " Camera", sizeof(i->name)); 7028c2ecf20Sopenharmony_ci i->type = V4L2_INPUT_TYPE_CAMERA; 7038c2ecf20Sopenharmony_ci return 0; 7048c2ecf20Sopenharmony_ci} 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_cistatic int zr364xx_vidioc_g_input(struct file *file, void *priv, 7078c2ecf20Sopenharmony_ci unsigned int *i) 7088c2ecf20Sopenharmony_ci{ 7098c2ecf20Sopenharmony_ci *i = 0; 7108c2ecf20Sopenharmony_ci return 0; 7118c2ecf20Sopenharmony_ci} 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_cistatic int zr364xx_vidioc_s_input(struct file *file, void *priv, 7148c2ecf20Sopenharmony_ci unsigned int i) 7158c2ecf20Sopenharmony_ci{ 7168c2ecf20Sopenharmony_ci if (i != 0) 7178c2ecf20Sopenharmony_ci return -EINVAL; 7188c2ecf20Sopenharmony_ci return 0; 7198c2ecf20Sopenharmony_ci} 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_cistatic int zr364xx_s_ctrl(struct v4l2_ctrl *ctrl) 7228c2ecf20Sopenharmony_ci{ 7238c2ecf20Sopenharmony_ci struct zr364xx_camera *cam = 7248c2ecf20Sopenharmony_ci container_of(ctrl->handler, struct zr364xx_camera, ctrl_handler); 7258c2ecf20Sopenharmony_ci int temp; 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci switch (ctrl->id) { 7288c2ecf20Sopenharmony_ci case V4L2_CID_BRIGHTNESS: 7298c2ecf20Sopenharmony_ci /* hardware brightness */ 7308c2ecf20Sopenharmony_ci send_control_msg(cam->udev, 1, 0x2001, 0, NULL, 0); 7318c2ecf20Sopenharmony_ci temp = (0x60 << 8) + 127 - ctrl->val; 7328c2ecf20Sopenharmony_ci send_control_msg(cam->udev, 1, temp, 0, NULL, 0); 7338c2ecf20Sopenharmony_ci break; 7348c2ecf20Sopenharmony_ci default: 7358c2ecf20Sopenharmony_ci return -EINVAL; 7368c2ecf20Sopenharmony_ci } 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci return 0; 7398c2ecf20Sopenharmony_ci} 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_cistatic int zr364xx_vidioc_enum_fmt_vid_cap(struct file *file, 7428c2ecf20Sopenharmony_ci void *priv, struct v4l2_fmtdesc *f) 7438c2ecf20Sopenharmony_ci{ 7448c2ecf20Sopenharmony_ci if (f->index > 0) 7458c2ecf20Sopenharmony_ci return -EINVAL; 7468c2ecf20Sopenharmony_ci f->pixelformat = formats[0].fourcc; 7478c2ecf20Sopenharmony_ci return 0; 7488c2ecf20Sopenharmony_ci} 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_cistatic char *decode_fourcc(__u32 pixelformat, char *buf) 7518c2ecf20Sopenharmony_ci{ 7528c2ecf20Sopenharmony_ci buf[0] = pixelformat & 0xff; 7538c2ecf20Sopenharmony_ci buf[1] = (pixelformat >> 8) & 0xff; 7548c2ecf20Sopenharmony_ci buf[2] = (pixelformat >> 16) & 0xff; 7558c2ecf20Sopenharmony_ci buf[3] = (pixelformat >> 24) & 0xff; 7568c2ecf20Sopenharmony_ci buf[4] = '\0'; 7578c2ecf20Sopenharmony_ci return buf; 7588c2ecf20Sopenharmony_ci} 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_cistatic int zr364xx_vidioc_try_fmt_vid_cap(struct file *file, void *priv, 7618c2ecf20Sopenharmony_ci struct v4l2_format *f) 7628c2ecf20Sopenharmony_ci{ 7638c2ecf20Sopenharmony_ci struct zr364xx_camera *cam = video_drvdata(file); 7648c2ecf20Sopenharmony_ci char pixelformat_name[5]; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci if (!cam) 7678c2ecf20Sopenharmony_ci return -ENODEV; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG) { 7708c2ecf20Sopenharmony_ci DBG("%s: unsupported pixelformat V4L2_PIX_FMT_%s\n", __func__, 7718c2ecf20Sopenharmony_ci decode_fourcc(f->fmt.pix.pixelformat, pixelformat_name)); 7728c2ecf20Sopenharmony_ci return -EINVAL; 7738c2ecf20Sopenharmony_ci } 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci if (!(f->fmt.pix.width == 160 && f->fmt.pix.height == 120) && 7768c2ecf20Sopenharmony_ci !(f->fmt.pix.width == 640 && f->fmt.pix.height == 480)) { 7778c2ecf20Sopenharmony_ci f->fmt.pix.width = 320; 7788c2ecf20Sopenharmony_ci f->fmt.pix.height = 240; 7798c2ecf20Sopenharmony_ci } 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci f->fmt.pix.field = V4L2_FIELD_NONE; 7828c2ecf20Sopenharmony_ci f->fmt.pix.bytesperline = f->fmt.pix.width * 2; 7838c2ecf20Sopenharmony_ci f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; 7848c2ecf20Sopenharmony_ci f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; 7858c2ecf20Sopenharmony_ci DBG("%s: V4L2_PIX_FMT_%s (%d) ok!\n", __func__, 7868c2ecf20Sopenharmony_ci decode_fourcc(f->fmt.pix.pixelformat, pixelformat_name), 7878c2ecf20Sopenharmony_ci f->fmt.pix.field); 7888c2ecf20Sopenharmony_ci return 0; 7898c2ecf20Sopenharmony_ci} 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_cistatic int zr364xx_vidioc_g_fmt_vid_cap(struct file *file, void *priv, 7928c2ecf20Sopenharmony_ci struct v4l2_format *f) 7938c2ecf20Sopenharmony_ci{ 7948c2ecf20Sopenharmony_ci struct zr364xx_camera *cam; 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci if (!file) 7978c2ecf20Sopenharmony_ci return -ENODEV; 7988c2ecf20Sopenharmony_ci cam = video_drvdata(file); 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci f->fmt.pix.pixelformat = formats[0].fourcc; 8018c2ecf20Sopenharmony_ci f->fmt.pix.field = V4L2_FIELD_NONE; 8028c2ecf20Sopenharmony_ci f->fmt.pix.width = cam->width; 8038c2ecf20Sopenharmony_ci f->fmt.pix.height = cam->height; 8048c2ecf20Sopenharmony_ci f->fmt.pix.bytesperline = f->fmt.pix.width * 2; 8058c2ecf20Sopenharmony_ci f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; 8068c2ecf20Sopenharmony_ci f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; 8078c2ecf20Sopenharmony_ci return 0; 8088c2ecf20Sopenharmony_ci} 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_cistatic int zr364xx_vidioc_s_fmt_vid_cap(struct file *file, void *priv, 8118c2ecf20Sopenharmony_ci struct v4l2_format *f) 8128c2ecf20Sopenharmony_ci{ 8138c2ecf20Sopenharmony_ci struct zr364xx_camera *cam = video_drvdata(file); 8148c2ecf20Sopenharmony_ci struct videobuf_queue *q = &cam->vb_vidq; 8158c2ecf20Sopenharmony_ci char pixelformat_name[5]; 8168c2ecf20Sopenharmony_ci int ret = zr364xx_vidioc_try_fmt_vid_cap(file, cam, f); 8178c2ecf20Sopenharmony_ci int i; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci if (ret < 0) 8208c2ecf20Sopenharmony_ci return ret; 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci mutex_lock(&q->vb_lock); 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci if (videobuf_queue_is_busy(&cam->vb_vidq)) { 8258c2ecf20Sopenharmony_ci DBG("%s queue busy\n", __func__); 8268c2ecf20Sopenharmony_ci ret = -EBUSY; 8278c2ecf20Sopenharmony_ci goto out; 8288c2ecf20Sopenharmony_ci } 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci if (cam->owner) { 8318c2ecf20Sopenharmony_ci DBG("%s can't change format after started\n", __func__); 8328c2ecf20Sopenharmony_ci ret = -EBUSY; 8338c2ecf20Sopenharmony_ci goto out; 8348c2ecf20Sopenharmony_ci } 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci cam->width = f->fmt.pix.width; 8378c2ecf20Sopenharmony_ci cam->height = f->fmt.pix.height; 8388c2ecf20Sopenharmony_ci DBG("%s: %dx%d mode selected\n", __func__, 8398c2ecf20Sopenharmony_ci cam->width, cam->height); 8408c2ecf20Sopenharmony_ci f->fmt.pix.bytesperline = f->fmt.pix.width * 2; 8418c2ecf20Sopenharmony_ci f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; 8428c2ecf20Sopenharmony_ci f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; 8438c2ecf20Sopenharmony_ci cam->vb_vidq.field = f->fmt.pix.field; 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci if (f->fmt.pix.width == 160 && f->fmt.pix.height == 120) 8468c2ecf20Sopenharmony_ci mode = 1; 8478c2ecf20Sopenharmony_ci else if (f->fmt.pix.width == 640 && f->fmt.pix.height == 480) 8488c2ecf20Sopenharmony_ci mode = 2; 8498c2ecf20Sopenharmony_ci else 8508c2ecf20Sopenharmony_ci mode = 0; 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci m0d1[0] = mode; 8538c2ecf20Sopenharmony_ci m1[2].value = 0xf000 + mode; 8548c2ecf20Sopenharmony_ci m2[1].value = 0xf000 + mode; 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci /* special case for METHOD3, the modes are different */ 8578c2ecf20Sopenharmony_ci if (cam->method == METHOD3) { 8588c2ecf20Sopenharmony_ci switch (mode) { 8598c2ecf20Sopenharmony_ci case 1: 8608c2ecf20Sopenharmony_ci m2[1].value = 0xf000 + 4; 8618c2ecf20Sopenharmony_ci break; 8628c2ecf20Sopenharmony_ci case 2: 8638c2ecf20Sopenharmony_ci m2[1].value = 0xf000 + 0; 8648c2ecf20Sopenharmony_ci break; 8658c2ecf20Sopenharmony_ci default: 8668c2ecf20Sopenharmony_ci m2[1].value = 0xf000 + 1; 8678c2ecf20Sopenharmony_ci break; 8688c2ecf20Sopenharmony_ci } 8698c2ecf20Sopenharmony_ci } 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci header2[437] = cam->height / 256; 8728c2ecf20Sopenharmony_ci header2[438] = cam->height % 256; 8738c2ecf20Sopenharmony_ci header2[439] = cam->width / 256; 8748c2ecf20Sopenharmony_ci header2[440] = cam->width % 256; 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci for (i = 0; init[cam->method][i].size != -1; i++) { 8778c2ecf20Sopenharmony_ci ret = 8788c2ecf20Sopenharmony_ci send_control_msg(cam->udev, 1, init[cam->method][i].value, 8798c2ecf20Sopenharmony_ci 0, init[cam->method][i].bytes, 8808c2ecf20Sopenharmony_ci init[cam->method][i].size); 8818c2ecf20Sopenharmony_ci if (ret < 0) { 8828c2ecf20Sopenharmony_ci dev_err(&cam->udev->dev, 8838c2ecf20Sopenharmony_ci "error during resolution change sequence: %d\n", i); 8848c2ecf20Sopenharmony_ci goto out; 8858c2ecf20Sopenharmony_ci } 8868c2ecf20Sopenharmony_ci } 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci /* Added some delay here, since opening/closing the camera quickly, 8898c2ecf20Sopenharmony_ci * like Ekiga does during its startup, can crash the webcam 8908c2ecf20Sopenharmony_ci */ 8918c2ecf20Sopenharmony_ci mdelay(100); 8928c2ecf20Sopenharmony_ci cam->skip = 2; 8938c2ecf20Sopenharmony_ci ret = 0; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ciout: 8968c2ecf20Sopenharmony_ci mutex_unlock(&q->vb_lock); 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci DBG("%s: V4L2_PIX_FMT_%s (%d) ok!\n", __func__, 8998c2ecf20Sopenharmony_ci decode_fourcc(f->fmt.pix.pixelformat, pixelformat_name), 9008c2ecf20Sopenharmony_ci f->fmt.pix.field); 9018c2ecf20Sopenharmony_ci return ret; 9028c2ecf20Sopenharmony_ci} 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_cistatic int zr364xx_vidioc_reqbufs(struct file *file, void *priv, 9058c2ecf20Sopenharmony_ci struct v4l2_requestbuffers *p) 9068c2ecf20Sopenharmony_ci{ 9078c2ecf20Sopenharmony_ci struct zr364xx_camera *cam = video_drvdata(file); 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci if (cam->owner && cam->owner != priv) 9108c2ecf20Sopenharmony_ci return -EBUSY; 9118c2ecf20Sopenharmony_ci return videobuf_reqbufs(&cam->vb_vidq, p); 9128c2ecf20Sopenharmony_ci} 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_cistatic int zr364xx_vidioc_querybuf(struct file *file, 9158c2ecf20Sopenharmony_ci void *priv, 9168c2ecf20Sopenharmony_ci struct v4l2_buffer *p) 9178c2ecf20Sopenharmony_ci{ 9188c2ecf20Sopenharmony_ci int rc; 9198c2ecf20Sopenharmony_ci struct zr364xx_camera *cam = video_drvdata(file); 9208c2ecf20Sopenharmony_ci rc = videobuf_querybuf(&cam->vb_vidq, p); 9218c2ecf20Sopenharmony_ci return rc; 9228c2ecf20Sopenharmony_ci} 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_cistatic int zr364xx_vidioc_qbuf(struct file *file, 9258c2ecf20Sopenharmony_ci void *priv, 9268c2ecf20Sopenharmony_ci struct v4l2_buffer *p) 9278c2ecf20Sopenharmony_ci{ 9288c2ecf20Sopenharmony_ci int rc; 9298c2ecf20Sopenharmony_ci struct zr364xx_camera *cam = video_drvdata(file); 9308c2ecf20Sopenharmony_ci _DBG("%s\n", __func__); 9318c2ecf20Sopenharmony_ci if (cam->owner && cam->owner != priv) 9328c2ecf20Sopenharmony_ci return -EBUSY; 9338c2ecf20Sopenharmony_ci rc = videobuf_qbuf(&cam->vb_vidq, p); 9348c2ecf20Sopenharmony_ci return rc; 9358c2ecf20Sopenharmony_ci} 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_cistatic int zr364xx_vidioc_dqbuf(struct file *file, 9388c2ecf20Sopenharmony_ci void *priv, 9398c2ecf20Sopenharmony_ci struct v4l2_buffer *p) 9408c2ecf20Sopenharmony_ci{ 9418c2ecf20Sopenharmony_ci int rc; 9428c2ecf20Sopenharmony_ci struct zr364xx_camera *cam = video_drvdata(file); 9438c2ecf20Sopenharmony_ci _DBG("%s\n", __func__); 9448c2ecf20Sopenharmony_ci if (cam->owner && cam->owner != priv) 9458c2ecf20Sopenharmony_ci return -EBUSY; 9468c2ecf20Sopenharmony_ci rc = videobuf_dqbuf(&cam->vb_vidq, p, file->f_flags & O_NONBLOCK); 9478c2ecf20Sopenharmony_ci return rc; 9488c2ecf20Sopenharmony_ci} 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_cistatic void read_pipe_completion(struct urb *purb) 9518c2ecf20Sopenharmony_ci{ 9528c2ecf20Sopenharmony_ci struct zr364xx_pipeinfo *pipe_info; 9538c2ecf20Sopenharmony_ci struct zr364xx_camera *cam; 9548c2ecf20Sopenharmony_ci int pipe; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci pipe_info = purb->context; 9578c2ecf20Sopenharmony_ci _DBG("%s %p, status %d\n", __func__, purb, purb->status); 9588c2ecf20Sopenharmony_ci if (!pipe_info) { 9598c2ecf20Sopenharmony_ci printk(KERN_ERR KBUILD_MODNAME ": no context!\n"); 9608c2ecf20Sopenharmony_ci return; 9618c2ecf20Sopenharmony_ci } 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci cam = pipe_info->cam; 9648c2ecf20Sopenharmony_ci if (!cam) { 9658c2ecf20Sopenharmony_ci printk(KERN_ERR KBUILD_MODNAME ": no context!\n"); 9668c2ecf20Sopenharmony_ci return; 9678c2ecf20Sopenharmony_ci } 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci /* if shutting down, do not resubmit, exit immediately */ 9708c2ecf20Sopenharmony_ci if (purb->status == -ESHUTDOWN) { 9718c2ecf20Sopenharmony_ci DBG("%s, err shutdown\n", __func__); 9728c2ecf20Sopenharmony_ci pipe_info->err_count++; 9738c2ecf20Sopenharmony_ci return; 9748c2ecf20Sopenharmony_ci } 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci if (pipe_info->state == 0) { 9778c2ecf20Sopenharmony_ci DBG("exiting USB pipe\n"); 9788c2ecf20Sopenharmony_ci return; 9798c2ecf20Sopenharmony_ci } 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci if (purb->actual_length > pipe_info->transfer_size) { 9828c2ecf20Sopenharmony_ci dev_err(&cam->udev->dev, "wrong number of bytes\n"); 9838c2ecf20Sopenharmony_ci return; 9848c2ecf20Sopenharmony_ci } 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci if (purb->status == 0) 9878c2ecf20Sopenharmony_ci zr364xx_read_video_callback(cam, pipe_info, purb); 9888c2ecf20Sopenharmony_ci else { 9898c2ecf20Sopenharmony_ci pipe_info->err_count++; 9908c2ecf20Sopenharmony_ci DBG("%s: failed URB %d\n", __func__, purb->status); 9918c2ecf20Sopenharmony_ci } 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci pipe = usb_rcvbulkpipe(cam->udev, cam->read_endpoint); 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci /* reuse urb */ 9968c2ecf20Sopenharmony_ci usb_fill_bulk_urb(pipe_info->stream_urb, cam->udev, 9978c2ecf20Sopenharmony_ci pipe, 9988c2ecf20Sopenharmony_ci pipe_info->transfer_buffer, 9998c2ecf20Sopenharmony_ci pipe_info->transfer_size, 10008c2ecf20Sopenharmony_ci read_pipe_completion, pipe_info); 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci if (pipe_info->state != 0) { 10038c2ecf20Sopenharmony_ci purb->status = usb_submit_urb(pipe_info->stream_urb, 10048c2ecf20Sopenharmony_ci GFP_ATOMIC); 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci if (purb->status) 10078c2ecf20Sopenharmony_ci dev_err(&cam->udev->dev, 10088c2ecf20Sopenharmony_ci "error submitting urb (error=%i)\n", 10098c2ecf20Sopenharmony_ci purb->status); 10108c2ecf20Sopenharmony_ci } else 10118c2ecf20Sopenharmony_ci DBG("read pipe complete state 0\n"); 10128c2ecf20Sopenharmony_ci} 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_cistatic int zr364xx_start_readpipe(struct zr364xx_camera *cam) 10158c2ecf20Sopenharmony_ci{ 10168c2ecf20Sopenharmony_ci int pipe; 10178c2ecf20Sopenharmony_ci int retval; 10188c2ecf20Sopenharmony_ci struct zr364xx_pipeinfo *pipe_info = cam->pipe; 10198c2ecf20Sopenharmony_ci pipe = usb_rcvbulkpipe(cam->udev, cam->read_endpoint); 10208c2ecf20Sopenharmony_ci DBG("%s: start pipe IN x%x\n", __func__, cam->read_endpoint); 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci pipe_info->state = 1; 10238c2ecf20Sopenharmony_ci pipe_info->err_count = 0; 10248c2ecf20Sopenharmony_ci pipe_info->stream_urb = usb_alloc_urb(0, GFP_KERNEL); 10258c2ecf20Sopenharmony_ci if (!pipe_info->stream_urb) 10268c2ecf20Sopenharmony_ci return -ENOMEM; 10278c2ecf20Sopenharmony_ci /* transfer buffer allocated in board_init */ 10288c2ecf20Sopenharmony_ci usb_fill_bulk_urb(pipe_info->stream_urb, cam->udev, 10298c2ecf20Sopenharmony_ci pipe, 10308c2ecf20Sopenharmony_ci pipe_info->transfer_buffer, 10318c2ecf20Sopenharmony_ci pipe_info->transfer_size, 10328c2ecf20Sopenharmony_ci read_pipe_completion, pipe_info); 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci DBG("submitting URB %p\n", pipe_info->stream_urb); 10358c2ecf20Sopenharmony_ci retval = usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL); 10368c2ecf20Sopenharmony_ci if (retval) { 10378c2ecf20Sopenharmony_ci usb_free_urb(pipe_info->stream_urb); 10388c2ecf20Sopenharmony_ci printk(KERN_ERR KBUILD_MODNAME ": start read pipe failed\n"); 10398c2ecf20Sopenharmony_ci return retval; 10408c2ecf20Sopenharmony_ci } 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci return 0; 10438c2ecf20Sopenharmony_ci} 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_cistatic void zr364xx_stop_readpipe(struct zr364xx_camera *cam) 10468c2ecf20Sopenharmony_ci{ 10478c2ecf20Sopenharmony_ci struct zr364xx_pipeinfo *pipe_info; 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci if (!cam) { 10508c2ecf20Sopenharmony_ci printk(KERN_ERR KBUILD_MODNAME ": invalid device\n"); 10518c2ecf20Sopenharmony_ci return; 10528c2ecf20Sopenharmony_ci } 10538c2ecf20Sopenharmony_ci DBG("stop read pipe\n"); 10548c2ecf20Sopenharmony_ci pipe_info = cam->pipe; 10558c2ecf20Sopenharmony_ci if (pipe_info) { 10568c2ecf20Sopenharmony_ci if (pipe_info->state != 0) 10578c2ecf20Sopenharmony_ci pipe_info->state = 0; 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci if (pipe_info->stream_urb) { 10608c2ecf20Sopenharmony_ci /* cancel urb */ 10618c2ecf20Sopenharmony_ci usb_kill_urb(pipe_info->stream_urb); 10628c2ecf20Sopenharmony_ci usb_free_urb(pipe_info->stream_urb); 10638c2ecf20Sopenharmony_ci pipe_info->stream_urb = NULL; 10648c2ecf20Sopenharmony_ci } 10658c2ecf20Sopenharmony_ci } 10668c2ecf20Sopenharmony_ci return; 10678c2ecf20Sopenharmony_ci} 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci/* starts acquisition process */ 10708c2ecf20Sopenharmony_cistatic int zr364xx_start_acquire(struct zr364xx_camera *cam) 10718c2ecf20Sopenharmony_ci{ 10728c2ecf20Sopenharmony_ci int j; 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci DBG("start acquire\n"); 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci cam->last_frame = -1; 10778c2ecf20Sopenharmony_ci cam->cur_frame = 0; 10788c2ecf20Sopenharmony_ci for (j = 0; j < FRAMES; j++) { 10798c2ecf20Sopenharmony_ci cam->buffer.frame[j].ulState = ZR364XX_READ_IDLE; 10808c2ecf20Sopenharmony_ci cam->buffer.frame[j].cur_size = 0; 10818c2ecf20Sopenharmony_ci } 10828c2ecf20Sopenharmony_ci cam->b_acquire = 1; 10838c2ecf20Sopenharmony_ci return 0; 10848c2ecf20Sopenharmony_ci} 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_cistatic inline int zr364xx_stop_acquire(struct zr364xx_camera *cam) 10878c2ecf20Sopenharmony_ci{ 10888c2ecf20Sopenharmony_ci cam->b_acquire = 0; 10898c2ecf20Sopenharmony_ci return 0; 10908c2ecf20Sopenharmony_ci} 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_cistatic int zr364xx_prepare(struct zr364xx_camera *cam) 10938c2ecf20Sopenharmony_ci{ 10948c2ecf20Sopenharmony_ci int res; 10958c2ecf20Sopenharmony_ci int i, j; 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci for (i = 0; init[cam->method][i].size != -1; i++) { 10988c2ecf20Sopenharmony_ci res = send_control_msg(cam->udev, 1, init[cam->method][i].value, 10998c2ecf20Sopenharmony_ci 0, init[cam->method][i].bytes, 11008c2ecf20Sopenharmony_ci init[cam->method][i].size); 11018c2ecf20Sopenharmony_ci if (res < 0) { 11028c2ecf20Sopenharmony_ci dev_err(&cam->udev->dev, 11038c2ecf20Sopenharmony_ci "error during open sequence: %d\n", i); 11048c2ecf20Sopenharmony_ci return res; 11058c2ecf20Sopenharmony_ci } 11068c2ecf20Sopenharmony_ci } 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci cam->skip = 2; 11098c2ecf20Sopenharmony_ci cam->last_frame = -1; 11108c2ecf20Sopenharmony_ci cam->cur_frame = 0; 11118c2ecf20Sopenharmony_ci cam->frame_count = 0; 11128c2ecf20Sopenharmony_ci for (j = 0; j < FRAMES; j++) { 11138c2ecf20Sopenharmony_ci cam->buffer.frame[j].ulState = ZR364XX_READ_IDLE; 11148c2ecf20Sopenharmony_ci cam->buffer.frame[j].cur_size = 0; 11158c2ecf20Sopenharmony_ci } 11168c2ecf20Sopenharmony_ci v4l2_ctrl_handler_setup(&cam->ctrl_handler); 11178c2ecf20Sopenharmony_ci return 0; 11188c2ecf20Sopenharmony_ci} 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_cistatic int zr364xx_vidioc_streamon(struct file *file, void *priv, 11218c2ecf20Sopenharmony_ci enum v4l2_buf_type type) 11228c2ecf20Sopenharmony_ci{ 11238c2ecf20Sopenharmony_ci struct zr364xx_camera *cam = video_drvdata(file); 11248c2ecf20Sopenharmony_ci int res; 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci DBG("%s\n", __func__); 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 11298c2ecf20Sopenharmony_ci return -EINVAL; 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci if (cam->owner && cam->owner != priv) 11328c2ecf20Sopenharmony_ci return -EBUSY; 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci res = zr364xx_prepare(cam); 11358c2ecf20Sopenharmony_ci if (res) 11368c2ecf20Sopenharmony_ci return res; 11378c2ecf20Sopenharmony_ci res = videobuf_streamon(&cam->vb_vidq); 11388c2ecf20Sopenharmony_ci if (res == 0) { 11398c2ecf20Sopenharmony_ci zr364xx_start_acquire(cam); 11408c2ecf20Sopenharmony_ci cam->owner = file->private_data; 11418c2ecf20Sopenharmony_ci } 11428c2ecf20Sopenharmony_ci return res; 11438c2ecf20Sopenharmony_ci} 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_cistatic int zr364xx_vidioc_streamoff(struct file *file, void *priv, 11468c2ecf20Sopenharmony_ci enum v4l2_buf_type type) 11478c2ecf20Sopenharmony_ci{ 11488c2ecf20Sopenharmony_ci struct zr364xx_camera *cam = video_drvdata(file); 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci DBG("%s\n", __func__); 11518c2ecf20Sopenharmony_ci if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 11528c2ecf20Sopenharmony_ci return -EINVAL; 11538c2ecf20Sopenharmony_ci if (cam->owner && cam->owner != priv) 11548c2ecf20Sopenharmony_ci return -EBUSY; 11558c2ecf20Sopenharmony_ci zr364xx_stop_acquire(cam); 11568c2ecf20Sopenharmony_ci return videobuf_streamoff(&cam->vb_vidq); 11578c2ecf20Sopenharmony_ci} 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci/* open the camera */ 11618c2ecf20Sopenharmony_cistatic int zr364xx_open(struct file *file) 11628c2ecf20Sopenharmony_ci{ 11638c2ecf20Sopenharmony_ci struct zr364xx_camera *cam = video_drvdata(file); 11648c2ecf20Sopenharmony_ci int err; 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci DBG("%s\n", __func__); 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&cam->lock)) 11698c2ecf20Sopenharmony_ci return -ERESTARTSYS; 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci err = v4l2_fh_open(file); 11728c2ecf20Sopenharmony_ci if (err) 11738c2ecf20Sopenharmony_ci goto out; 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci /* Added some delay here, since opening/closing the camera quickly, 11768c2ecf20Sopenharmony_ci * like Ekiga does during its startup, can crash the webcam 11778c2ecf20Sopenharmony_ci */ 11788c2ecf20Sopenharmony_ci mdelay(100); 11798c2ecf20Sopenharmony_ci err = 0; 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ciout: 11828c2ecf20Sopenharmony_ci mutex_unlock(&cam->lock); 11838c2ecf20Sopenharmony_ci DBG("%s: %d\n", __func__, err); 11848c2ecf20Sopenharmony_ci return err; 11858c2ecf20Sopenharmony_ci} 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_cistatic void zr364xx_board_uninit(struct zr364xx_camera *cam) 11888c2ecf20Sopenharmony_ci{ 11898c2ecf20Sopenharmony_ci unsigned long i; 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci zr364xx_stop_readpipe(cam); 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci /* release sys buffers */ 11948c2ecf20Sopenharmony_ci for (i = 0; i < FRAMES; i++) { 11958c2ecf20Sopenharmony_ci if (cam->buffer.frame[i].lpvbits) { 11968c2ecf20Sopenharmony_ci DBG("vfree %p\n", cam->buffer.frame[i].lpvbits); 11978c2ecf20Sopenharmony_ci vfree(cam->buffer.frame[i].lpvbits); 11988c2ecf20Sopenharmony_ci } 11998c2ecf20Sopenharmony_ci cam->buffer.frame[i].lpvbits = NULL; 12008c2ecf20Sopenharmony_ci } 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci /* release transfer buffer */ 12038c2ecf20Sopenharmony_ci kfree(cam->pipe->transfer_buffer); 12048c2ecf20Sopenharmony_ci} 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_cistatic void zr364xx_release(struct v4l2_device *v4l2_dev) 12078c2ecf20Sopenharmony_ci{ 12088c2ecf20Sopenharmony_ci struct zr364xx_camera *cam = 12098c2ecf20Sopenharmony_ci container_of(v4l2_dev, struct zr364xx_camera, v4l2_dev); 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci videobuf_mmap_free(&cam->vb_vidq); 12128c2ecf20Sopenharmony_ci v4l2_ctrl_handler_free(&cam->ctrl_handler); 12138c2ecf20Sopenharmony_ci zr364xx_board_uninit(cam); 12148c2ecf20Sopenharmony_ci v4l2_device_unregister(&cam->v4l2_dev); 12158c2ecf20Sopenharmony_ci kfree(cam); 12168c2ecf20Sopenharmony_ci} 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci/* release the camera */ 12198c2ecf20Sopenharmony_cistatic int zr364xx_close(struct file *file) 12208c2ecf20Sopenharmony_ci{ 12218c2ecf20Sopenharmony_ci struct zr364xx_camera *cam; 12228c2ecf20Sopenharmony_ci struct usb_device *udev; 12238c2ecf20Sopenharmony_ci int i; 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci DBG("%s\n", __func__); 12268c2ecf20Sopenharmony_ci cam = video_drvdata(file); 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci mutex_lock(&cam->lock); 12298c2ecf20Sopenharmony_ci udev = cam->udev; 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci if (file->private_data == cam->owner) { 12328c2ecf20Sopenharmony_ci /* turn off stream */ 12338c2ecf20Sopenharmony_ci if (cam->b_acquire) 12348c2ecf20Sopenharmony_ci zr364xx_stop_acquire(cam); 12358c2ecf20Sopenharmony_ci videobuf_streamoff(&cam->vb_vidq); 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 12388c2ecf20Sopenharmony_ci send_control_msg(udev, 1, init[cam->method][i].value, 12398c2ecf20Sopenharmony_ci 0, init[cam->method][i].bytes, 12408c2ecf20Sopenharmony_ci init[cam->method][i].size); 12418c2ecf20Sopenharmony_ci } 12428c2ecf20Sopenharmony_ci cam->owner = NULL; 12438c2ecf20Sopenharmony_ci } 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci /* Added some delay here, since opening/closing the camera quickly, 12468c2ecf20Sopenharmony_ci * like Ekiga does during its startup, can crash the webcam 12478c2ecf20Sopenharmony_ci */ 12488c2ecf20Sopenharmony_ci mdelay(100); 12498c2ecf20Sopenharmony_ci mutex_unlock(&cam->lock); 12508c2ecf20Sopenharmony_ci return v4l2_fh_release(file); 12518c2ecf20Sopenharmony_ci} 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_cistatic int zr364xx_mmap(struct file *file, struct vm_area_struct *vma) 12558c2ecf20Sopenharmony_ci{ 12568c2ecf20Sopenharmony_ci struct zr364xx_camera *cam = video_drvdata(file); 12578c2ecf20Sopenharmony_ci int ret; 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci if (!cam) { 12608c2ecf20Sopenharmony_ci DBG("%s: cam == NULL\n", __func__); 12618c2ecf20Sopenharmony_ci return -ENODEV; 12628c2ecf20Sopenharmony_ci } 12638c2ecf20Sopenharmony_ci DBG("mmap called, vma=%p\n", vma); 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci ret = videobuf_mmap_mapper(&cam->vb_vidq, vma); 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci DBG("vma start=0x%08lx, size=%ld, ret=%d\n", 12688c2ecf20Sopenharmony_ci (unsigned long)vma->vm_start, 12698c2ecf20Sopenharmony_ci (unsigned long)vma->vm_end - (unsigned long)vma->vm_start, ret); 12708c2ecf20Sopenharmony_ci return ret; 12718c2ecf20Sopenharmony_ci} 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_cistatic __poll_t zr364xx_poll(struct file *file, 12748c2ecf20Sopenharmony_ci struct poll_table_struct *wait) 12758c2ecf20Sopenharmony_ci{ 12768c2ecf20Sopenharmony_ci struct zr364xx_camera *cam = video_drvdata(file); 12778c2ecf20Sopenharmony_ci struct videobuf_queue *q = &cam->vb_vidq; 12788c2ecf20Sopenharmony_ci __poll_t res = v4l2_ctrl_poll(file, wait); 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci _DBG("%s\n", __func__); 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci return res | videobuf_poll_stream(file, q, wait); 12838c2ecf20Sopenharmony_ci} 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_ops zr364xx_ctrl_ops = { 12868c2ecf20Sopenharmony_ci .s_ctrl = zr364xx_s_ctrl, 12878c2ecf20Sopenharmony_ci}; 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_cistatic const struct v4l2_file_operations zr364xx_fops = { 12908c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 12918c2ecf20Sopenharmony_ci .open = zr364xx_open, 12928c2ecf20Sopenharmony_ci .release = zr364xx_close, 12938c2ecf20Sopenharmony_ci .read = zr364xx_read, 12948c2ecf20Sopenharmony_ci .mmap = zr364xx_mmap, 12958c2ecf20Sopenharmony_ci .unlocked_ioctl = video_ioctl2, 12968c2ecf20Sopenharmony_ci .poll = zr364xx_poll, 12978c2ecf20Sopenharmony_ci}; 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_cistatic const struct v4l2_ioctl_ops zr364xx_ioctl_ops = { 13008c2ecf20Sopenharmony_ci .vidioc_querycap = zr364xx_vidioc_querycap, 13018c2ecf20Sopenharmony_ci .vidioc_enum_fmt_vid_cap = zr364xx_vidioc_enum_fmt_vid_cap, 13028c2ecf20Sopenharmony_ci .vidioc_try_fmt_vid_cap = zr364xx_vidioc_try_fmt_vid_cap, 13038c2ecf20Sopenharmony_ci .vidioc_s_fmt_vid_cap = zr364xx_vidioc_s_fmt_vid_cap, 13048c2ecf20Sopenharmony_ci .vidioc_g_fmt_vid_cap = zr364xx_vidioc_g_fmt_vid_cap, 13058c2ecf20Sopenharmony_ci .vidioc_enum_input = zr364xx_vidioc_enum_input, 13068c2ecf20Sopenharmony_ci .vidioc_g_input = zr364xx_vidioc_g_input, 13078c2ecf20Sopenharmony_ci .vidioc_s_input = zr364xx_vidioc_s_input, 13088c2ecf20Sopenharmony_ci .vidioc_streamon = zr364xx_vidioc_streamon, 13098c2ecf20Sopenharmony_ci .vidioc_streamoff = zr364xx_vidioc_streamoff, 13108c2ecf20Sopenharmony_ci .vidioc_reqbufs = zr364xx_vidioc_reqbufs, 13118c2ecf20Sopenharmony_ci .vidioc_querybuf = zr364xx_vidioc_querybuf, 13128c2ecf20Sopenharmony_ci .vidioc_qbuf = zr364xx_vidioc_qbuf, 13138c2ecf20Sopenharmony_ci .vidioc_dqbuf = zr364xx_vidioc_dqbuf, 13148c2ecf20Sopenharmony_ci .vidioc_log_status = v4l2_ctrl_log_status, 13158c2ecf20Sopenharmony_ci .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, 13168c2ecf20Sopenharmony_ci .vidioc_unsubscribe_event = v4l2_event_unsubscribe, 13178c2ecf20Sopenharmony_ci}; 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_cistatic const struct video_device zr364xx_template = { 13208c2ecf20Sopenharmony_ci .name = DRIVER_DESC, 13218c2ecf20Sopenharmony_ci .fops = &zr364xx_fops, 13228c2ecf20Sopenharmony_ci .ioctl_ops = &zr364xx_ioctl_ops, 13238c2ecf20Sopenharmony_ci .release = video_device_release_empty, 13248c2ecf20Sopenharmony_ci .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | 13258c2ecf20Sopenharmony_ci V4L2_CAP_STREAMING, 13268c2ecf20Sopenharmony_ci}; 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci/*******************/ 13318c2ecf20Sopenharmony_ci/* USB integration */ 13328c2ecf20Sopenharmony_ci/*******************/ 13338c2ecf20Sopenharmony_cistatic int zr364xx_board_init(struct zr364xx_camera *cam) 13348c2ecf20Sopenharmony_ci{ 13358c2ecf20Sopenharmony_ci struct zr364xx_pipeinfo *pipe = cam->pipe; 13368c2ecf20Sopenharmony_ci unsigned long i; 13378c2ecf20Sopenharmony_ci int err; 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_ci DBG("board init: %p\n", cam); 13408c2ecf20Sopenharmony_ci memset(pipe, 0, sizeof(*pipe)); 13418c2ecf20Sopenharmony_ci pipe->cam = cam; 13428c2ecf20Sopenharmony_ci pipe->transfer_size = BUFFER_SIZE; 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci pipe->transfer_buffer = kzalloc(pipe->transfer_size, 13458c2ecf20Sopenharmony_ci GFP_KERNEL); 13468c2ecf20Sopenharmony_ci if (!pipe->transfer_buffer) { 13478c2ecf20Sopenharmony_ci DBG("out of memory!\n"); 13488c2ecf20Sopenharmony_ci return -ENOMEM; 13498c2ecf20Sopenharmony_ci } 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci cam->b_acquire = 0; 13528c2ecf20Sopenharmony_ci cam->frame_count = 0; 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci /*** start create system buffers ***/ 13558c2ecf20Sopenharmony_ci for (i = 0; i < FRAMES; i++) { 13568c2ecf20Sopenharmony_ci /* always allocate maximum size for system buffers */ 13578c2ecf20Sopenharmony_ci cam->buffer.frame[i].lpvbits = vmalloc(MAX_FRAME_SIZE); 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci DBG("valloc %p, idx %lu, pdata %p\n", 13608c2ecf20Sopenharmony_ci &cam->buffer.frame[i], i, 13618c2ecf20Sopenharmony_ci cam->buffer.frame[i].lpvbits); 13628c2ecf20Sopenharmony_ci if (!cam->buffer.frame[i].lpvbits) { 13638c2ecf20Sopenharmony_ci printk(KERN_INFO KBUILD_MODNAME ": out of memory. Using less frames\n"); 13648c2ecf20Sopenharmony_ci break; 13658c2ecf20Sopenharmony_ci } 13668c2ecf20Sopenharmony_ci } 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci if (i == 0) { 13698c2ecf20Sopenharmony_ci printk(KERN_INFO KBUILD_MODNAME ": out of memory. Aborting\n"); 13708c2ecf20Sopenharmony_ci err = -ENOMEM; 13718c2ecf20Sopenharmony_ci goto err_free; 13728c2ecf20Sopenharmony_ci } else 13738c2ecf20Sopenharmony_ci cam->buffer.dwFrames = i; 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_ci /* make sure internal states are set */ 13768c2ecf20Sopenharmony_ci for (i = 0; i < FRAMES; i++) { 13778c2ecf20Sopenharmony_ci cam->buffer.frame[i].ulState = ZR364XX_READ_IDLE; 13788c2ecf20Sopenharmony_ci cam->buffer.frame[i].cur_size = 0; 13798c2ecf20Sopenharmony_ci } 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci cam->cur_frame = 0; 13828c2ecf20Sopenharmony_ci cam->last_frame = -1; 13838c2ecf20Sopenharmony_ci /*** end create system buffers ***/ 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci /* start read pipe */ 13868c2ecf20Sopenharmony_ci err = zr364xx_start_readpipe(cam); 13878c2ecf20Sopenharmony_ci if (err) 13888c2ecf20Sopenharmony_ci goto err_free_frames; 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_ci DBG(": board initialized\n"); 13918c2ecf20Sopenharmony_ci return 0; 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_cierr_free_frames: 13948c2ecf20Sopenharmony_ci for (i = 0; i < FRAMES; i++) 13958c2ecf20Sopenharmony_ci vfree(cam->buffer.frame[i].lpvbits); 13968c2ecf20Sopenharmony_cierr_free: 13978c2ecf20Sopenharmony_ci kfree(cam->pipe->transfer_buffer); 13988c2ecf20Sopenharmony_ci cam->pipe->transfer_buffer = NULL; 13998c2ecf20Sopenharmony_ci return err; 14008c2ecf20Sopenharmony_ci} 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_cistatic int zr364xx_probe(struct usb_interface *intf, 14038c2ecf20Sopenharmony_ci const struct usb_device_id *id) 14048c2ecf20Sopenharmony_ci{ 14058c2ecf20Sopenharmony_ci struct usb_device *udev = interface_to_usbdev(intf); 14068c2ecf20Sopenharmony_ci struct zr364xx_camera *cam = NULL; 14078c2ecf20Sopenharmony_ci struct usb_host_interface *iface_desc; 14088c2ecf20Sopenharmony_ci struct usb_endpoint_descriptor *endpoint; 14098c2ecf20Sopenharmony_ci struct v4l2_ctrl_handler *hdl; 14108c2ecf20Sopenharmony_ci int err; 14118c2ecf20Sopenharmony_ci int i; 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci DBG("probing...\n"); 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci dev_info(&intf->dev, DRIVER_DESC " compatible webcam plugged\n"); 14168c2ecf20Sopenharmony_ci dev_info(&intf->dev, "model %04x:%04x detected\n", 14178c2ecf20Sopenharmony_ci le16_to_cpu(udev->descriptor.idVendor), 14188c2ecf20Sopenharmony_ci le16_to_cpu(udev->descriptor.idProduct)); 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci cam = kzalloc(sizeof(*cam), GFP_KERNEL); 14218c2ecf20Sopenharmony_ci if (!cam) 14228c2ecf20Sopenharmony_ci return -ENOMEM; 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci err = v4l2_device_register(&intf->dev, &cam->v4l2_dev); 14258c2ecf20Sopenharmony_ci if (err < 0) { 14268c2ecf20Sopenharmony_ci dev_err(&udev->dev, "couldn't register v4l2_device\n"); 14278c2ecf20Sopenharmony_ci goto free_cam; 14288c2ecf20Sopenharmony_ci } 14298c2ecf20Sopenharmony_ci hdl = &cam->ctrl_handler; 14308c2ecf20Sopenharmony_ci v4l2_ctrl_handler_init(hdl, 1); 14318c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(hdl, &zr364xx_ctrl_ops, 14328c2ecf20Sopenharmony_ci V4L2_CID_BRIGHTNESS, 0, 127, 1, 64); 14338c2ecf20Sopenharmony_ci if (hdl->error) { 14348c2ecf20Sopenharmony_ci err = hdl->error; 14358c2ecf20Sopenharmony_ci dev_err(&udev->dev, "couldn't register control\n"); 14368c2ecf20Sopenharmony_ci goto free_hdlr_and_unreg_dev; 14378c2ecf20Sopenharmony_ci } 14388c2ecf20Sopenharmony_ci /* save the init method used by this camera */ 14398c2ecf20Sopenharmony_ci cam->method = id->driver_info; 14408c2ecf20Sopenharmony_ci mutex_init(&cam->lock); 14418c2ecf20Sopenharmony_ci cam->vdev = zr364xx_template; 14428c2ecf20Sopenharmony_ci cam->vdev.lock = &cam->lock; 14438c2ecf20Sopenharmony_ci cam->vdev.v4l2_dev = &cam->v4l2_dev; 14448c2ecf20Sopenharmony_ci cam->vdev.ctrl_handler = &cam->ctrl_handler; 14458c2ecf20Sopenharmony_ci video_set_drvdata(&cam->vdev, cam); 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci cam->udev = udev; 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci switch (mode) { 14508c2ecf20Sopenharmony_ci case 1: 14518c2ecf20Sopenharmony_ci dev_info(&udev->dev, "160x120 mode selected\n"); 14528c2ecf20Sopenharmony_ci cam->width = 160; 14538c2ecf20Sopenharmony_ci cam->height = 120; 14548c2ecf20Sopenharmony_ci break; 14558c2ecf20Sopenharmony_ci case 2: 14568c2ecf20Sopenharmony_ci dev_info(&udev->dev, "640x480 mode selected\n"); 14578c2ecf20Sopenharmony_ci cam->width = 640; 14588c2ecf20Sopenharmony_ci cam->height = 480; 14598c2ecf20Sopenharmony_ci break; 14608c2ecf20Sopenharmony_ci default: 14618c2ecf20Sopenharmony_ci dev_info(&udev->dev, "320x240 mode selected\n"); 14628c2ecf20Sopenharmony_ci cam->width = 320; 14638c2ecf20Sopenharmony_ci cam->height = 240; 14648c2ecf20Sopenharmony_ci break; 14658c2ecf20Sopenharmony_ci } 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci m0d1[0] = mode; 14688c2ecf20Sopenharmony_ci m1[2].value = 0xf000 + mode; 14698c2ecf20Sopenharmony_ci m2[1].value = 0xf000 + mode; 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci /* special case for METHOD3, the modes are different */ 14728c2ecf20Sopenharmony_ci if (cam->method == METHOD3) { 14738c2ecf20Sopenharmony_ci switch (mode) { 14748c2ecf20Sopenharmony_ci case 1: 14758c2ecf20Sopenharmony_ci m2[1].value = 0xf000 + 4; 14768c2ecf20Sopenharmony_ci break; 14778c2ecf20Sopenharmony_ci case 2: 14788c2ecf20Sopenharmony_ci m2[1].value = 0xf000 + 0; 14798c2ecf20Sopenharmony_ci break; 14808c2ecf20Sopenharmony_ci default: 14818c2ecf20Sopenharmony_ci m2[1].value = 0xf000 + 1; 14828c2ecf20Sopenharmony_ci break; 14838c2ecf20Sopenharmony_ci } 14848c2ecf20Sopenharmony_ci } 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci header2[437] = cam->height / 256; 14878c2ecf20Sopenharmony_ci header2[438] = cam->height % 256; 14888c2ecf20Sopenharmony_ci header2[439] = cam->width / 256; 14898c2ecf20Sopenharmony_ci header2[440] = cam->width % 256; 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci cam->nb = 0; 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci DBG("dev: %p, udev %p interface %p\n", cam, cam->udev, intf); 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci /* set up the endpoint information */ 14968c2ecf20Sopenharmony_ci iface_desc = intf->cur_altsetting; 14978c2ecf20Sopenharmony_ci DBG("num endpoints %d\n", iface_desc->desc.bNumEndpoints); 14988c2ecf20Sopenharmony_ci for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { 14998c2ecf20Sopenharmony_ci endpoint = &iface_desc->endpoint[i].desc; 15008c2ecf20Sopenharmony_ci if (!cam->read_endpoint && usb_endpoint_is_bulk_in(endpoint)) { 15018c2ecf20Sopenharmony_ci /* we found the bulk in endpoint */ 15028c2ecf20Sopenharmony_ci cam->read_endpoint = endpoint->bEndpointAddress; 15038c2ecf20Sopenharmony_ci } 15048c2ecf20Sopenharmony_ci } 15058c2ecf20Sopenharmony_ci 15068c2ecf20Sopenharmony_ci if (!cam->read_endpoint) { 15078c2ecf20Sopenharmony_ci err = -ENOMEM; 15088c2ecf20Sopenharmony_ci dev_err(&intf->dev, "Could not find bulk-in endpoint\n"); 15098c2ecf20Sopenharmony_ci goto free_hdlr_and_unreg_dev; 15108c2ecf20Sopenharmony_ci } 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_ci /* v4l */ 15138c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&cam->vidq.active); 15148c2ecf20Sopenharmony_ci cam->vidq.cam = cam; 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci usb_set_intfdata(intf, cam); 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci /* load zr364xx board specific */ 15198c2ecf20Sopenharmony_ci err = zr364xx_board_init(cam); 15208c2ecf20Sopenharmony_ci if (err) 15218c2ecf20Sopenharmony_ci goto free_hdlr_and_unreg_dev; 15228c2ecf20Sopenharmony_ci err = v4l2_ctrl_handler_setup(hdl); 15238c2ecf20Sopenharmony_ci if (err) 15248c2ecf20Sopenharmony_ci goto board_uninit; 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci spin_lock_init(&cam->slock); 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_ci cam->fmt = formats; 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_ci videobuf_queue_vmalloc_init(&cam->vb_vidq, &zr364xx_video_qops, 15318c2ecf20Sopenharmony_ci NULL, &cam->slock, 15328c2ecf20Sopenharmony_ci V4L2_BUF_TYPE_VIDEO_CAPTURE, 15338c2ecf20Sopenharmony_ci V4L2_FIELD_NONE, 15348c2ecf20Sopenharmony_ci sizeof(struct zr364xx_buffer), cam, &cam->lock); 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci err = video_register_device(&cam->vdev, VFL_TYPE_VIDEO, -1); 15378c2ecf20Sopenharmony_ci if (err) { 15388c2ecf20Sopenharmony_ci dev_err(&udev->dev, "video_register_device failed\n"); 15398c2ecf20Sopenharmony_ci goto board_uninit; 15408c2ecf20Sopenharmony_ci } 15418c2ecf20Sopenharmony_ci cam->v4l2_dev.release = zr364xx_release; 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ci dev_info(&udev->dev, DRIVER_DESC " controlling device %s\n", 15448c2ecf20Sopenharmony_ci video_device_node_name(&cam->vdev)); 15458c2ecf20Sopenharmony_ci return 0; 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ciboard_uninit: 15488c2ecf20Sopenharmony_ci zr364xx_board_uninit(cam); 15498c2ecf20Sopenharmony_cifree_hdlr_and_unreg_dev: 15508c2ecf20Sopenharmony_ci v4l2_ctrl_handler_free(hdl); 15518c2ecf20Sopenharmony_ci v4l2_device_unregister(&cam->v4l2_dev); 15528c2ecf20Sopenharmony_cifree_cam: 15538c2ecf20Sopenharmony_ci kfree(cam); 15548c2ecf20Sopenharmony_ci return err; 15558c2ecf20Sopenharmony_ci} 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_cistatic void zr364xx_disconnect(struct usb_interface *intf) 15598c2ecf20Sopenharmony_ci{ 15608c2ecf20Sopenharmony_ci struct zr364xx_camera *cam = usb_get_intfdata(intf); 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_ci mutex_lock(&cam->lock); 15638c2ecf20Sopenharmony_ci usb_set_intfdata(intf, NULL); 15648c2ecf20Sopenharmony_ci dev_info(&intf->dev, DRIVER_DESC " webcam unplugged\n"); 15658c2ecf20Sopenharmony_ci video_unregister_device(&cam->vdev); 15668c2ecf20Sopenharmony_ci v4l2_device_disconnect(&cam->v4l2_dev); 15678c2ecf20Sopenharmony_ci 15688c2ecf20Sopenharmony_ci /* stops the read pipe if it is running */ 15698c2ecf20Sopenharmony_ci if (cam->b_acquire) 15708c2ecf20Sopenharmony_ci zr364xx_stop_acquire(cam); 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_ci zr364xx_stop_readpipe(cam); 15738c2ecf20Sopenharmony_ci mutex_unlock(&cam->lock); 15748c2ecf20Sopenharmony_ci v4l2_device_put(&cam->v4l2_dev); 15758c2ecf20Sopenharmony_ci} 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 15798c2ecf20Sopenharmony_cistatic int zr364xx_suspend(struct usb_interface *intf, pm_message_t message) 15808c2ecf20Sopenharmony_ci{ 15818c2ecf20Sopenharmony_ci struct zr364xx_camera *cam = usb_get_intfdata(intf); 15828c2ecf20Sopenharmony_ci 15838c2ecf20Sopenharmony_ci cam->was_streaming = cam->b_acquire; 15848c2ecf20Sopenharmony_ci if (!cam->was_streaming) 15858c2ecf20Sopenharmony_ci return 0; 15868c2ecf20Sopenharmony_ci zr364xx_stop_acquire(cam); 15878c2ecf20Sopenharmony_ci zr364xx_stop_readpipe(cam); 15888c2ecf20Sopenharmony_ci return 0; 15898c2ecf20Sopenharmony_ci} 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_cistatic int zr364xx_resume(struct usb_interface *intf) 15928c2ecf20Sopenharmony_ci{ 15938c2ecf20Sopenharmony_ci struct zr364xx_camera *cam = usb_get_intfdata(intf); 15948c2ecf20Sopenharmony_ci int res; 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci if (!cam->was_streaming) 15978c2ecf20Sopenharmony_ci return 0; 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci res = zr364xx_start_readpipe(cam); 16008c2ecf20Sopenharmony_ci if (res) 16018c2ecf20Sopenharmony_ci return res; 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci res = zr364xx_prepare(cam); 16048c2ecf20Sopenharmony_ci if (res) 16058c2ecf20Sopenharmony_ci goto err_prepare; 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci zr364xx_start_acquire(cam); 16088c2ecf20Sopenharmony_ci return 0; 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_cierr_prepare: 16118c2ecf20Sopenharmony_ci zr364xx_stop_readpipe(cam); 16128c2ecf20Sopenharmony_ci return res; 16138c2ecf20Sopenharmony_ci} 16148c2ecf20Sopenharmony_ci#endif 16158c2ecf20Sopenharmony_ci 16168c2ecf20Sopenharmony_ci/**********************/ 16178c2ecf20Sopenharmony_ci/* Module integration */ 16188c2ecf20Sopenharmony_ci/**********************/ 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_cistatic struct usb_driver zr364xx_driver = { 16218c2ecf20Sopenharmony_ci .name = "zr364xx", 16228c2ecf20Sopenharmony_ci .probe = zr364xx_probe, 16238c2ecf20Sopenharmony_ci .disconnect = zr364xx_disconnect, 16248c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 16258c2ecf20Sopenharmony_ci .suspend = zr364xx_suspend, 16268c2ecf20Sopenharmony_ci .resume = zr364xx_resume, 16278c2ecf20Sopenharmony_ci .reset_resume = zr364xx_resume, 16288c2ecf20Sopenharmony_ci#endif 16298c2ecf20Sopenharmony_ci .id_table = device_table 16308c2ecf20Sopenharmony_ci}; 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_cimodule_usb_driver(zr364xx_driver); 16338c2ecf20Sopenharmony_ci 16348c2ecf20Sopenharmony_ciMODULE_AUTHOR(DRIVER_AUTHOR); 16358c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC); 16368c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 16378c2ecf20Sopenharmony_ciMODULE_VERSION(DRIVER_VERSION); 1638