18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * kinect sensor device camera, gspca driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2011 Antonio Ospite <ospite@studenti.unina.it> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Based on the OpenKinect project and libfreenect 88c2ecf20Sopenharmony_ci * http://openkinect.org/wiki/Init_Analysis 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Special thanks to Steven Toth and kernellabs.com for sponsoring a Kinect 118c2ecf20Sopenharmony_ci * sensor device which I tested the driver on. 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#define MODULE_NAME "kinect" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include "gspca.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define CTRL_TIMEOUT 500 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ciMODULE_AUTHOR("Antonio Ospite <ospite@studenti.unina.it>"); 238c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("GSPCA/Kinect Sensor Device USB Camera Driver"); 248c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic bool depth_mode; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistruct pkt_hdr { 298c2ecf20Sopenharmony_ci uint8_t magic[2]; 308c2ecf20Sopenharmony_ci uint8_t pad; 318c2ecf20Sopenharmony_ci uint8_t flag; 328c2ecf20Sopenharmony_ci uint8_t unk1; 338c2ecf20Sopenharmony_ci uint8_t seq; 348c2ecf20Sopenharmony_ci uint8_t unk2; 358c2ecf20Sopenharmony_ci uint8_t unk3; 368c2ecf20Sopenharmony_ci uint32_t timestamp; 378c2ecf20Sopenharmony_ci}; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistruct cam_hdr { 408c2ecf20Sopenharmony_ci uint8_t magic[2]; 418c2ecf20Sopenharmony_ci __le16 len; 428c2ecf20Sopenharmony_ci __le16 cmd; 438c2ecf20Sopenharmony_ci __le16 tag; 448c2ecf20Sopenharmony_ci}; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci/* specific webcam descriptor */ 478c2ecf20Sopenharmony_cistruct sd { 488c2ecf20Sopenharmony_ci struct gspca_dev gspca_dev; /* !! must be the first item */ 498c2ecf20Sopenharmony_ci uint16_t cam_tag; /* a sequence number for packets */ 508c2ecf20Sopenharmony_ci uint8_t stream_flag; /* to identify different stream types */ 518c2ecf20Sopenharmony_ci uint8_t obuf[0x400]; /* output buffer for control commands */ 528c2ecf20Sopenharmony_ci uint8_t ibuf[0x200]; /* input buffer for control commands */ 538c2ecf20Sopenharmony_ci}; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci#define MODE_640x480 0x0001 568c2ecf20Sopenharmony_ci#define MODE_640x488 0x0002 578c2ecf20Sopenharmony_ci#define MODE_1280x1024 0x0004 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci#define FORMAT_BAYER 0x0010 608c2ecf20Sopenharmony_ci#define FORMAT_UYVY 0x0020 618c2ecf20Sopenharmony_ci#define FORMAT_Y10B 0x0040 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci#define FPS_HIGH 0x0100 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic const struct v4l2_pix_format depth_camera_mode[] = { 668c2ecf20Sopenharmony_ci {640, 480, V4L2_PIX_FMT_Y10BPACK, V4L2_FIELD_NONE, 678c2ecf20Sopenharmony_ci .bytesperline = 640 * 10 / 8, 688c2ecf20Sopenharmony_ci .sizeimage = 640 * 480 * 10 / 8, 698c2ecf20Sopenharmony_ci .colorspace = V4L2_COLORSPACE_SRGB, 708c2ecf20Sopenharmony_ci .priv = MODE_640x488 | FORMAT_Y10B}, 718c2ecf20Sopenharmony_ci}; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic const struct v4l2_pix_format video_camera_mode[] = { 748c2ecf20Sopenharmony_ci {640, 480, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE, 758c2ecf20Sopenharmony_ci .bytesperline = 640, 768c2ecf20Sopenharmony_ci .sizeimage = 640 * 480, 778c2ecf20Sopenharmony_ci .colorspace = V4L2_COLORSPACE_SRGB, 788c2ecf20Sopenharmony_ci .priv = MODE_640x480 | FORMAT_BAYER | FPS_HIGH}, 798c2ecf20Sopenharmony_ci {640, 480, V4L2_PIX_FMT_UYVY, V4L2_FIELD_NONE, 808c2ecf20Sopenharmony_ci .bytesperline = 640 * 2, 818c2ecf20Sopenharmony_ci .sizeimage = 640 * 480 * 2, 828c2ecf20Sopenharmony_ci .colorspace = V4L2_COLORSPACE_SRGB, 838c2ecf20Sopenharmony_ci .priv = MODE_640x480 | FORMAT_UYVY}, 848c2ecf20Sopenharmony_ci {1280, 1024, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE, 858c2ecf20Sopenharmony_ci .bytesperline = 1280, 868c2ecf20Sopenharmony_ci .sizeimage = 1280 * 1024, 878c2ecf20Sopenharmony_ci .colorspace = V4L2_COLORSPACE_SRGB, 888c2ecf20Sopenharmony_ci .priv = MODE_1280x1024 | FORMAT_BAYER}, 898c2ecf20Sopenharmony_ci {640, 488, V4L2_PIX_FMT_Y10BPACK, V4L2_FIELD_NONE, 908c2ecf20Sopenharmony_ci .bytesperline = 640 * 10 / 8, 918c2ecf20Sopenharmony_ci .sizeimage = 640 * 488 * 10 / 8, 928c2ecf20Sopenharmony_ci .colorspace = V4L2_COLORSPACE_SRGB, 938c2ecf20Sopenharmony_ci .priv = MODE_640x488 | FORMAT_Y10B | FPS_HIGH}, 948c2ecf20Sopenharmony_ci {1280, 1024, V4L2_PIX_FMT_Y10BPACK, V4L2_FIELD_NONE, 958c2ecf20Sopenharmony_ci .bytesperline = 1280 * 10 / 8, 968c2ecf20Sopenharmony_ci .sizeimage = 1280 * 1024 * 10 / 8, 978c2ecf20Sopenharmony_ci .colorspace = V4L2_COLORSPACE_SRGB, 988c2ecf20Sopenharmony_ci .priv = MODE_1280x1024 | FORMAT_Y10B}, 998c2ecf20Sopenharmony_ci}; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic int kinect_write(struct usb_device *udev, uint8_t *data, 1028c2ecf20Sopenharmony_ci uint16_t wLength) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci return usb_control_msg(udev, 1058c2ecf20Sopenharmony_ci usb_sndctrlpipe(udev, 0), 1068c2ecf20Sopenharmony_ci 0x00, 1078c2ecf20Sopenharmony_ci USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 1088c2ecf20Sopenharmony_ci 0, 0, data, wLength, CTRL_TIMEOUT); 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic int kinect_read(struct usb_device *udev, uint8_t *data, uint16_t wLength) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci return usb_control_msg(udev, 1148c2ecf20Sopenharmony_ci usb_rcvctrlpipe(udev, 0), 1158c2ecf20Sopenharmony_ci 0x00, 1168c2ecf20Sopenharmony_ci USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 1178c2ecf20Sopenharmony_ci 0, 0, data, wLength, CTRL_TIMEOUT); 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic int send_cmd(struct gspca_dev *gspca_dev, uint16_t cmd, void *cmdbuf, 1218c2ecf20Sopenharmony_ci unsigned int cmd_len, void *replybuf, unsigned int reply_len) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 1248c2ecf20Sopenharmony_ci struct usb_device *udev = gspca_dev->dev; 1258c2ecf20Sopenharmony_ci int res, actual_len; 1268c2ecf20Sopenharmony_ci uint8_t *obuf = sd->obuf; 1278c2ecf20Sopenharmony_ci uint8_t *ibuf = sd->ibuf; 1288c2ecf20Sopenharmony_ci struct cam_hdr *chdr = (void *)obuf; 1298c2ecf20Sopenharmony_ci struct cam_hdr *rhdr = (void *)ibuf; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci if (cmd_len & 1 || cmd_len > (0x400 - sizeof(*chdr))) { 1328c2ecf20Sopenharmony_ci pr_err("send_cmd: Invalid command length (0x%x)\n", cmd_len); 1338c2ecf20Sopenharmony_ci return -1; 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci chdr->magic[0] = 0x47; 1378c2ecf20Sopenharmony_ci chdr->magic[1] = 0x4d; 1388c2ecf20Sopenharmony_ci chdr->cmd = cpu_to_le16(cmd); 1398c2ecf20Sopenharmony_ci chdr->tag = cpu_to_le16(sd->cam_tag); 1408c2ecf20Sopenharmony_ci chdr->len = cpu_to_le16(cmd_len / 2); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci memcpy(obuf+sizeof(*chdr), cmdbuf, cmd_len); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci res = kinect_write(udev, obuf, cmd_len + sizeof(*chdr)); 1458c2ecf20Sopenharmony_ci gspca_dbg(gspca_dev, D_USBO, "Control cmd=%04x tag=%04x len=%04x: %d\n", 1468c2ecf20Sopenharmony_ci cmd, 1478c2ecf20Sopenharmony_ci sd->cam_tag, cmd_len, res); 1488c2ecf20Sopenharmony_ci if (res < 0) { 1498c2ecf20Sopenharmony_ci pr_err("send_cmd: Output control transfer failed (%d)\n", res); 1508c2ecf20Sopenharmony_ci return res; 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci do { 1548c2ecf20Sopenharmony_ci actual_len = kinect_read(udev, ibuf, 0x200); 1558c2ecf20Sopenharmony_ci } while (actual_len == 0); 1568c2ecf20Sopenharmony_ci gspca_dbg(gspca_dev, D_USBO, "Control reply: %d\n", actual_len); 1578c2ecf20Sopenharmony_ci if (actual_len < (int)sizeof(*rhdr)) { 1588c2ecf20Sopenharmony_ci pr_err("send_cmd: Input control transfer failed (%d)\n", 1598c2ecf20Sopenharmony_ci actual_len); 1608c2ecf20Sopenharmony_ci return actual_len < 0 ? actual_len : -EREMOTEIO; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci actual_len -= sizeof(*rhdr); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci if (rhdr->magic[0] != 0x52 || rhdr->magic[1] != 0x42) { 1658c2ecf20Sopenharmony_ci pr_err("send_cmd: Bad magic %02x %02x\n", 1668c2ecf20Sopenharmony_ci rhdr->magic[0], rhdr->magic[1]); 1678c2ecf20Sopenharmony_ci return -1; 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci if (rhdr->cmd != chdr->cmd) { 1708c2ecf20Sopenharmony_ci pr_err("send_cmd: Bad cmd %02x != %02x\n", 1718c2ecf20Sopenharmony_ci rhdr->cmd, chdr->cmd); 1728c2ecf20Sopenharmony_ci return -1; 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci if (rhdr->tag != chdr->tag) { 1758c2ecf20Sopenharmony_ci pr_err("send_cmd: Bad tag %04x != %04x\n", 1768c2ecf20Sopenharmony_ci rhdr->tag, chdr->tag); 1778c2ecf20Sopenharmony_ci return -1; 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci if (le16_to_cpu(rhdr->len) != (actual_len/2)) { 1808c2ecf20Sopenharmony_ci pr_err("send_cmd: Bad len %04x != %04x\n", 1818c2ecf20Sopenharmony_ci le16_to_cpu(rhdr->len), (int)(actual_len/2)); 1828c2ecf20Sopenharmony_ci return -1; 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci if (actual_len > reply_len) { 1868c2ecf20Sopenharmony_ci pr_warn("send_cmd: Data buffer is %d bytes long, but got %d bytes\n", 1878c2ecf20Sopenharmony_ci reply_len, actual_len); 1888c2ecf20Sopenharmony_ci memcpy(replybuf, ibuf+sizeof(*rhdr), reply_len); 1898c2ecf20Sopenharmony_ci } else { 1908c2ecf20Sopenharmony_ci memcpy(replybuf, ibuf+sizeof(*rhdr), actual_len); 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci sd->cam_tag++; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci return actual_len; 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_cistatic int write_register(struct gspca_dev *gspca_dev, uint16_t reg, 1998c2ecf20Sopenharmony_ci uint16_t data) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci uint16_t reply[2]; 2028c2ecf20Sopenharmony_ci __le16 cmd[2]; 2038c2ecf20Sopenharmony_ci int res; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci cmd[0] = cpu_to_le16(reg); 2068c2ecf20Sopenharmony_ci cmd[1] = cpu_to_le16(data); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci gspca_dbg(gspca_dev, D_USBO, "Write Reg 0x%04x <= 0x%02x\n", reg, data); 2098c2ecf20Sopenharmony_ci res = send_cmd(gspca_dev, 0x03, cmd, 4, reply, 4); 2108c2ecf20Sopenharmony_ci if (res < 0) 2118c2ecf20Sopenharmony_ci return res; 2128c2ecf20Sopenharmony_ci if (res != 2) { 2138c2ecf20Sopenharmony_ci pr_warn("send_cmd returned %d [%04x %04x], 0000 expected\n", 2148c2ecf20Sopenharmony_ci res, reply[0], reply[1]); 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci return 0; 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci/* this function is called at probe time */ 2208c2ecf20Sopenharmony_cistatic int sd_config_video(struct gspca_dev *gspca_dev, 2218c2ecf20Sopenharmony_ci const struct usb_device_id *id) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 2248c2ecf20Sopenharmony_ci struct cam *cam; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci sd->cam_tag = 0; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci sd->stream_flag = 0x80; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci cam = &gspca_dev->cam; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci cam->cam_mode = video_camera_mode; 2338c2ecf20Sopenharmony_ci cam->nmodes = ARRAY_SIZE(video_camera_mode); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci gspca_dev->xfer_ep = 0x81; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci#if 0 2388c2ecf20Sopenharmony_ci /* Setting those values is not needed for video stream */ 2398c2ecf20Sopenharmony_ci cam->npkt = 15; 2408c2ecf20Sopenharmony_ci gspca_dev->pkt_size = 960 * 2; 2418c2ecf20Sopenharmony_ci#endif 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci return 0; 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cistatic int sd_config_depth(struct gspca_dev *gspca_dev, 2478c2ecf20Sopenharmony_ci const struct usb_device_id *id) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 2508c2ecf20Sopenharmony_ci struct cam *cam; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci sd->cam_tag = 0; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci sd->stream_flag = 0x70; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci cam = &gspca_dev->cam; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci cam->cam_mode = depth_camera_mode; 2598c2ecf20Sopenharmony_ci cam->nmodes = ARRAY_SIZE(depth_camera_mode); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci gspca_dev->xfer_ep = 0x82; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci return 0; 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci/* this function is called at probe and resume time */ 2678c2ecf20Sopenharmony_cistatic int sd_init(struct gspca_dev *gspca_dev) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci gspca_dbg(gspca_dev, D_PROBE, "Kinect Camera device.\n"); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci return 0; 2728c2ecf20Sopenharmony_ci} 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_cistatic int sd_start_video(struct gspca_dev *gspca_dev) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci int mode; 2778c2ecf20Sopenharmony_ci uint8_t fmt_reg, fmt_val; 2788c2ecf20Sopenharmony_ci uint8_t res_reg, res_val; 2798c2ecf20Sopenharmony_ci uint8_t fps_reg, fps_val; 2808c2ecf20Sopenharmony_ci uint8_t mode_val; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci if (mode & FORMAT_Y10B) { 2858c2ecf20Sopenharmony_ci fmt_reg = 0x19; 2868c2ecf20Sopenharmony_ci res_reg = 0x1a; 2878c2ecf20Sopenharmony_ci fps_reg = 0x1b; 2888c2ecf20Sopenharmony_ci mode_val = 0x03; 2898c2ecf20Sopenharmony_ci } else { 2908c2ecf20Sopenharmony_ci fmt_reg = 0x0c; 2918c2ecf20Sopenharmony_ci res_reg = 0x0d; 2928c2ecf20Sopenharmony_ci fps_reg = 0x0e; 2938c2ecf20Sopenharmony_ci mode_val = 0x01; 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci /* format */ 2978c2ecf20Sopenharmony_ci if (mode & FORMAT_UYVY) 2988c2ecf20Sopenharmony_ci fmt_val = 0x05; 2998c2ecf20Sopenharmony_ci else 3008c2ecf20Sopenharmony_ci fmt_val = 0x00; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci if (mode & MODE_1280x1024) 3038c2ecf20Sopenharmony_ci res_val = 0x02; 3048c2ecf20Sopenharmony_ci else 3058c2ecf20Sopenharmony_ci res_val = 0x01; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci if (mode & FPS_HIGH) 3088c2ecf20Sopenharmony_ci fps_val = 0x1e; 3098c2ecf20Sopenharmony_ci else 3108c2ecf20Sopenharmony_ci fps_val = 0x0f; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci /* turn off IR-reset function */ 3148c2ecf20Sopenharmony_ci write_register(gspca_dev, 0x105, 0x00); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci /* Reset video stream */ 3178c2ecf20Sopenharmony_ci write_register(gspca_dev, 0x05, 0x00); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci /* Due to some ridiculous condition in the firmware, we have to start 3208c2ecf20Sopenharmony_ci * and stop the depth stream before the camera will hand us 1280x1024 3218c2ecf20Sopenharmony_ci * IR. This is a stupid workaround, but we've yet to find a better 3228c2ecf20Sopenharmony_ci * solution. 3238c2ecf20Sopenharmony_ci * 3248c2ecf20Sopenharmony_ci * Thanks to Drew Fisher for figuring this out. 3258c2ecf20Sopenharmony_ci */ 3268c2ecf20Sopenharmony_ci if (mode & (FORMAT_Y10B | MODE_1280x1024)) { 3278c2ecf20Sopenharmony_ci write_register(gspca_dev, 0x13, 0x01); 3288c2ecf20Sopenharmony_ci write_register(gspca_dev, 0x14, 0x1e); 3298c2ecf20Sopenharmony_ci write_register(gspca_dev, 0x06, 0x02); 3308c2ecf20Sopenharmony_ci write_register(gspca_dev, 0x06, 0x00); 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci write_register(gspca_dev, fmt_reg, fmt_val); 3348c2ecf20Sopenharmony_ci write_register(gspca_dev, res_reg, res_val); 3358c2ecf20Sopenharmony_ci write_register(gspca_dev, fps_reg, fps_val); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci /* Start video stream */ 3388c2ecf20Sopenharmony_ci write_register(gspca_dev, 0x05, mode_val); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci /* disable Hflip */ 3418c2ecf20Sopenharmony_ci write_register(gspca_dev, 0x47, 0x00); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci return 0; 3448c2ecf20Sopenharmony_ci} 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_cistatic int sd_start_depth(struct gspca_dev *gspca_dev) 3478c2ecf20Sopenharmony_ci{ 3488c2ecf20Sopenharmony_ci /* turn off IR-reset function */ 3498c2ecf20Sopenharmony_ci write_register(gspca_dev, 0x105, 0x00); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci /* reset depth stream */ 3528c2ecf20Sopenharmony_ci write_register(gspca_dev, 0x06, 0x00); 3538c2ecf20Sopenharmony_ci /* Depth Stream Format 0x03: 11 bit stream | 0x02: 10 bit */ 3548c2ecf20Sopenharmony_ci write_register(gspca_dev, 0x12, 0x02); 3558c2ecf20Sopenharmony_ci /* Depth Stream Resolution 1: standard (640x480) */ 3568c2ecf20Sopenharmony_ci write_register(gspca_dev, 0x13, 0x01); 3578c2ecf20Sopenharmony_ci /* Depth Framerate / 0x1e (30): 30 fps */ 3588c2ecf20Sopenharmony_ci write_register(gspca_dev, 0x14, 0x1e); 3598c2ecf20Sopenharmony_ci /* Depth Stream Control / 2: Open Depth Stream */ 3608c2ecf20Sopenharmony_ci write_register(gspca_dev, 0x06, 0x02); 3618c2ecf20Sopenharmony_ci /* disable depth hflip / LSB = 0: Smoothing Disabled */ 3628c2ecf20Sopenharmony_ci write_register(gspca_dev, 0x17, 0x00); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci return 0; 3658c2ecf20Sopenharmony_ci} 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_cistatic void sd_stopN_video(struct gspca_dev *gspca_dev) 3688c2ecf20Sopenharmony_ci{ 3698c2ecf20Sopenharmony_ci /* reset video stream */ 3708c2ecf20Sopenharmony_ci write_register(gspca_dev, 0x05, 0x00); 3718c2ecf20Sopenharmony_ci} 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_cistatic void sd_stopN_depth(struct gspca_dev *gspca_dev) 3748c2ecf20Sopenharmony_ci{ 3758c2ecf20Sopenharmony_ci /* reset depth stream */ 3768c2ecf20Sopenharmony_ci write_register(gspca_dev, 0x06, 0x00); 3778c2ecf20Sopenharmony_ci} 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_cistatic void sd_pkt_scan(struct gspca_dev *gspca_dev, u8 *__data, int len) 3808c2ecf20Sopenharmony_ci{ 3818c2ecf20Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci struct pkt_hdr *hdr = (void *)__data; 3848c2ecf20Sopenharmony_ci uint8_t *data = __data + sizeof(*hdr); 3858c2ecf20Sopenharmony_ci int datalen = len - sizeof(*hdr); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci uint8_t sof = sd->stream_flag | 1; 3888c2ecf20Sopenharmony_ci uint8_t mof = sd->stream_flag | 2; 3898c2ecf20Sopenharmony_ci uint8_t eof = sd->stream_flag | 5; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci if (len < 12) 3928c2ecf20Sopenharmony_ci return; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci if (hdr->magic[0] != 'R' || hdr->magic[1] != 'B') { 3958c2ecf20Sopenharmony_ci pr_warn("[Stream %02x] Invalid magic %02x%02x\n", 3968c2ecf20Sopenharmony_ci sd->stream_flag, hdr->magic[0], hdr->magic[1]); 3978c2ecf20Sopenharmony_ci return; 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci if (hdr->flag == sof) 4018c2ecf20Sopenharmony_ci gspca_frame_add(gspca_dev, FIRST_PACKET, data, datalen); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci else if (hdr->flag == mof) 4048c2ecf20Sopenharmony_ci gspca_frame_add(gspca_dev, INTER_PACKET, data, datalen); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci else if (hdr->flag == eof) 4078c2ecf20Sopenharmony_ci gspca_frame_add(gspca_dev, LAST_PACKET, data, datalen); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci else 4108c2ecf20Sopenharmony_ci pr_warn("Packet type not recognized...\n"); 4118c2ecf20Sopenharmony_ci} 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci/* sub-driver description */ 4148c2ecf20Sopenharmony_cistatic const struct sd_desc sd_desc_video = { 4158c2ecf20Sopenharmony_ci .name = MODULE_NAME, 4168c2ecf20Sopenharmony_ci .config = sd_config_video, 4178c2ecf20Sopenharmony_ci .init = sd_init, 4188c2ecf20Sopenharmony_ci .start = sd_start_video, 4198c2ecf20Sopenharmony_ci .stopN = sd_stopN_video, 4208c2ecf20Sopenharmony_ci .pkt_scan = sd_pkt_scan, 4218c2ecf20Sopenharmony_ci /* 4228c2ecf20Sopenharmony_ci .get_streamparm = sd_get_streamparm, 4238c2ecf20Sopenharmony_ci .set_streamparm = sd_set_streamparm, 4248c2ecf20Sopenharmony_ci */ 4258c2ecf20Sopenharmony_ci}; 4268c2ecf20Sopenharmony_cistatic const struct sd_desc sd_desc_depth = { 4278c2ecf20Sopenharmony_ci .name = MODULE_NAME, 4288c2ecf20Sopenharmony_ci .config = sd_config_depth, 4298c2ecf20Sopenharmony_ci .init = sd_init, 4308c2ecf20Sopenharmony_ci .start = sd_start_depth, 4318c2ecf20Sopenharmony_ci .stopN = sd_stopN_depth, 4328c2ecf20Sopenharmony_ci .pkt_scan = sd_pkt_scan, 4338c2ecf20Sopenharmony_ci /* 4348c2ecf20Sopenharmony_ci .get_streamparm = sd_get_streamparm, 4358c2ecf20Sopenharmony_ci .set_streamparm = sd_set_streamparm, 4368c2ecf20Sopenharmony_ci */ 4378c2ecf20Sopenharmony_ci}; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci/* -- module initialisation -- */ 4408c2ecf20Sopenharmony_cistatic const struct usb_device_id device_table[] = { 4418c2ecf20Sopenharmony_ci {USB_DEVICE(0x045e, 0x02ae)}, 4428c2ecf20Sopenharmony_ci {USB_DEVICE(0x045e, 0x02bf)}, 4438c2ecf20Sopenharmony_ci {} 4448c2ecf20Sopenharmony_ci}; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(usb, device_table); 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci/* -- device connect -- */ 4498c2ecf20Sopenharmony_cistatic int sd_probe(struct usb_interface *intf, const struct usb_device_id *id) 4508c2ecf20Sopenharmony_ci{ 4518c2ecf20Sopenharmony_ci if (depth_mode) 4528c2ecf20Sopenharmony_ci return gspca_dev_probe(intf, id, &sd_desc_depth, 4538c2ecf20Sopenharmony_ci sizeof(struct sd), THIS_MODULE); 4548c2ecf20Sopenharmony_ci else 4558c2ecf20Sopenharmony_ci return gspca_dev_probe(intf, id, &sd_desc_video, 4568c2ecf20Sopenharmony_ci sizeof(struct sd), THIS_MODULE); 4578c2ecf20Sopenharmony_ci} 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_cistatic struct usb_driver sd_driver = { 4608c2ecf20Sopenharmony_ci .name = MODULE_NAME, 4618c2ecf20Sopenharmony_ci .id_table = device_table, 4628c2ecf20Sopenharmony_ci .probe = sd_probe, 4638c2ecf20Sopenharmony_ci .disconnect = gspca_disconnect, 4648c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 4658c2ecf20Sopenharmony_ci .suspend = gspca_suspend, 4668c2ecf20Sopenharmony_ci .resume = gspca_resume, 4678c2ecf20Sopenharmony_ci .reset_resume = gspca_resume, 4688c2ecf20Sopenharmony_ci#endif 4698c2ecf20Sopenharmony_ci}; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_cimodule_usb_driver(sd_driver); 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_cimodule_param(depth_mode, bool, 0644); 4748c2ecf20Sopenharmony_ciMODULE_PARM_DESC(depth_mode, "0=video 1=depth"); 475