162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * kinect sensor device camera, gspca driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2011 Antonio Ospite <ospite@studenti.unina.it> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Based on the OpenKinect project and libfreenect 862306a36Sopenharmony_ci * http://openkinect.org/wiki/Init_Analysis 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Special thanks to Steven Toth and kernellabs.com for sponsoring a Kinect 1162306a36Sopenharmony_ci * sensor device which I tested the driver on. 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#define MODULE_NAME "kinect" 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include "gspca.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define CTRL_TIMEOUT 500 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ciMODULE_AUTHOR("Antonio Ospite <ospite@studenti.unina.it>"); 2362306a36Sopenharmony_ciMODULE_DESCRIPTION("GSPCA/Kinect Sensor Device USB Camera Driver"); 2462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic bool depth_mode; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistruct pkt_hdr { 2962306a36Sopenharmony_ci uint8_t magic[2]; 3062306a36Sopenharmony_ci uint8_t pad; 3162306a36Sopenharmony_ci uint8_t flag; 3262306a36Sopenharmony_ci uint8_t unk1; 3362306a36Sopenharmony_ci uint8_t seq; 3462306a36Sopenharmony_ci uint8_t unk2; 3562306a36Sopenharmony_ci uint8_t unk3; 3662306a36Sopenharmony_ci uint32_t timestamp; 3762306a36Sopenharmony_ci}; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistruct cam_hdr { 4062306a36Sopenharmony_ci uint8_t magic[2]; 4162306a36Sopenharmony_ci __le16 len; 4262306a36Sopenharmony_ci __le16 cmd; 4362306a36Sopenharmony_ci __le16 tag; 4462306a36Sopenharmony_ci}; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci/* specific webcam descriptor */ 4762306a36Sopenharmony_cistruct sd { 4862306a36Sopenharmony_ci struct gspca_dev gspca_dev; /* !! must be the first item */ 4962306a36Sopenharmony_ci uint16_t cam_tag; /* a sequence number for packets */ 5062306a36Sopenharmony_ci uint8_t stream_flag; /* to identify different stream types */ 5162306a36Sopenharmony_ci uint8_t obuf[0x400]; /* output buffer for control commands */ 5262306a36Sopenharmony_ci uint8_t ibuf[0x200]; /* input buffer for control commands */ 5362306a36Sopenharmony_ci}; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci#define MODE_640x480 0x0001 5662306a36Sopenharmony_ci#define MODE_640x488 0x0002 5762306a36Sopenharmony_ci#define MODE_1280x1024 0x0004 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci#define FORMAT_BAYER 0x0010 6062306a36Sopenharmony_ci#define FORMAT_UYVY 0x0020 6162306a36Sopenharmony_ci#define FORMAT_Y10B 0x0040 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci#define FPS_HIGH 0x0100 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic const struct v4l2_pix_format depth_camera_mode[] = { 6662306a36Sopenharmony_ci {640, 480, V4L2_PIX_FMT_Y10BPACK, V4L2_FIELD_NONE, 6762306a36Sopenharmony_ci .bytesperline = 640 * 10 / 8, 6862306a36Sopenharmony_ci .sizeimage = 640 * 480 * 10 / 8, 6962306a36Sopenharmony_ci .colorspace = V4L2_COLORSPACE_SRGB, 7062306a36Sopenharmony_ci .priv = MODE_640x488 | FORMAT_Y10B}, 7162306a36Sopenharmony_ci}; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic const struct v4l2_pix_format video_camera_mode[] = { 7462306a36Sopenharmony_ci {640, 480, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE, 7562306a36Sopenharmony_ci .bytesperline = 640, 7662306a36Sopenharmony_ci .sizeimage = 640 * 480, 7762306a36Sopenharmony_ci .colorspace = V4L2_COLORSPACE_SRGB, 7862306a36Sopenharmony_ci .priv = MODE_640x480 | FORMAT_BAYER | FPS_HIGH}, 7962306a36Sopenharmony_ci {640, 480, V4L2_PIX_FMT_UYVY, V4L2_FIELD_NONE, 8062306a36Sopenharmony_ci .bytesperline = 640 * 2, 8162306a36Sopenharmony_ci .sizeimage = 640 * 480 * 2, 8262306a36Sopenharmony_ci .colorspace = V4L2_COLORSPACE_SRGB, 8362306a36Sopenharmony_ci .priv = MODE_640x480 | FORMAT_UYVY}, 8462306a36Sopenharmony_ci {1280, 1024, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE, 8562306a36Sopenharmony_ci .bytesperline = 1280, 8662306a36Sopenharmony_ci .sizeimage = 1280 * 1024, 8762306a36Sopenharmony_ci .colorspace = V4L2_COLORSPACE_SRGB, 8862306a36Sopenharmony_ci .priv = MODE_1280x1024 | FORMAT_BAYER}, 8962306a36Sopenharmony_ci {640, 488, V4L2_PIX_FMT_Y10BPACK, V4L2_FIELD_NONE, 9062306a36Sopenharmony_ci .bytesperline = 640 * 10 / 8, 9162306a36Sopenharmony_ci .sizeimage = 640 * 488 * 10 / 8, 9262306a36Sopenharmony_ci .colorspace = V4L2_COLORSPACE_SRGB, 9362306a36Sopenharmony_ci .priv = MODE_640x488 | FORMAT_Y10B | FPS_HIGH}, 9462306a36Sopenharmony_ci {1280, 1024, V4L2_PIX_FMT_Y10BPACK, V4L2_FIELD_NONE, 9562306a36Sopenharmony_ci .bytesperline = 1280 * 10 / 8, 9662306a36Sopenharmony_ci .sizeimage = 1280 * 1024 * 10 / 8, 9762306a36Sopenharmony_ci .colorspace = V4L2_COLORSPACE_SRGB, 9862306a36Sopenharmony_ci .priv = MODE_1280x1024 | FORMAT_Y10B}, 9962306a36Sopenharmony_ci}; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic int kinect_write(struct usb_device *udev, uint8_t *data, 10262306a36Sopenharmony_ci uint16_t wLength) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci return usb_control_msg(udev, 10562306a36Sopenharmony_ci usb_sndctrlpipe(udev, 0), 10662306a36Sopenharmony_ci 0x00, 10762306a36Sopenharmony_ci USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 10862306a36Sopenharmony_ci 0, 0, data, wLength, CTRL_TIMEOUT); 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic int kinect_read(struct usb_device *udev, uint8_t *data, uint16_t wLength) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci return usb_control_msg(udev, 11462306a36Sopenharmony_ci usb_rcvctrlpipe(udev, 0), 11562306a36Sopenharmony_ci 0x00, 11662306a36Sopenharmony_ci USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 11762306a36Sopenharmony_ci 0, 0, data, wLength, CTRL_TIMEOUT); 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic int send_cmd(struct gspca_dev *gspca_dev, uint16_t cmd, void *cmdbuf, 12162306a36Sopenharmony_ci unsigned int cmd_len, void *replybuf, unsigned int reply_len) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 12462306a36Sopenharmony_ci struct usb_device *udev = gspca_dev->dev; 12562306a36Sopenharmony_ci int res, actual_len; 12662306a36Sopenharmony_ci uint8_t *obuf = sd->obuf; 12762306a36Sopenharmony_ci uint8_t *ibuf = sd->ibuf; 12862306a36Sopenharmony_ci struct cam_hdr *chdr = (void *)obuf; 12962306a36Sopenharmony_ci struct cam_hdr *rhdr = (void *)ibuf; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci if (cmd_len & 1 || cmd_len > (0x400 - sizeof(*chdr))) { 13262306a36Sopenharmony_ci pr_err("send_cmd: Invalid command length (0x%x)\n", cmd_len); 13362306a36Sopenharmony_ci return -1; 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci chdr->magic[0] = 0x47; 13762306a36Sopenharmony_ci chdr->magic[1] = 0x4d; 13862306a36Sopenharmony_ci chdr->cmd = cpu_to_le16(cmd); 13962306a36Sopenharmony_ci chdr->tag = cpu_to_le16(sd->cam_tag); 14062306a36Sopenharmony_ci chdr->len = cpu_to_le16(cmd_len / 2); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci memcpy(obuf+sizeof(*chdr), cmdbuf, cmd_len); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci res = kinect_write(udev, obuf, cmd_len + sizeof(*chdr)); 14562306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_USBO, "Control cmd=%04x tag=%04x len=%04x: %d\n", 14662306a36Sopenharmony_ci cmd, 14762306a36Sopenharmony_ci sd->cam_tag, cmd_len, res); 14862306a36Sopenharmony_ci if (res < 0) { 14962306a36Sopenharmony_ci pr_err("send_cmd: Output control transfer failed (%d)\n", res); 15062306a36Sopenharmony_ci return res; 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci do { 15462306a36Sopenharmony_ci actual_len = kinect_read(udev, ibuf, 0x200); 15562306a36Sopenharmony_ci } while (actual_len == 0); 15662306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_USBO, "Control reply: %d\n", actual_len); 15762306a36Sopenharmony_ci if (actual_len < (int)sizeof(*rhdr)) { 15862306a36Sopenharmony_ci pr_err("send_cmd: Input control transfer failed (%d)\n", 15962306a36Sopenharmony_ci actual_len); 16062306a36Sopenharmony_ci return actual_len < 0 ? actual_len : -EREMOTEIO; 16162306a36Sopenharmony_ci } 16262306a36Sopenharmony_ci actual_len -= sizeof(*rhdr); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci if (rhdr->magic[0] != 0x52 || rhdr->magic[1] != 0x42) { 16562306a36Sopenharmony_ci pr_err("send_cmd: Bad magic %02x %02x\n", 16662306a36Sopenharmony_ci rhdr->magic[0], rhdr->magic[1]); 16762306a36Sopenharmony_ci return -1; 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci if (rhdr->cmd != chdr->cmd) { 17062306a36Sopenharmony_ci pr_err("send_cmd: Bad cmd %02x != %02x\n", 17162306a36Sopenharmony_ci rhdr->cmd, chdr->cmd); 17262306a36Sopenharmony_ci return -1; 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci if (rhdr->tag != chdr->tag) { 17562306a36Sopenharmony_ci pr_err("send_cmd: Bad tag %04x != %04x\n", 17662306a36Sopenharmony_ci rhdr->tag, chdr->tag); 17762306a36Sopenharmony_ci return -1; 17862306a36Sopenharmony_ci } 17962306a36Sopenharmony_ci if (le16_to_cpu(rhdr->len) != (actual_len/2)) { 18062306a36Sopenharmony_ci pr_err("send_cmd: Bad len %04x != %04x\n", 18162306a36Sopenharmony_ci le16_to_cpu(rhdr->len), (int)(actual_len/2)); 18262306a36Sopenharmony_ci return -1; 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci if (actual_len > reply_len) { 18662306a36Sopenharmony_ci pr_warn("send_cmd: Data buffer is %d bytes long, but got %d bytes\n", 18762306a36Sopenharmony_ci reply_len, actual_len); 18862306a36Sopenharmony_ci memcpy(replybuf, ibuf+sizeof(*rhdr), reply_len); 18962306a36Sopenharmony_ci } else { 19062306a36Sopenharmony_ci memcpy(replybuf, ibuf+sizeof(*rhdr), actual_len); 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci sd->cam_tag++; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci return actual_len; 19662306a36Sopenharmony_ci} 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_cistatic int write_register(struct gspca_dev *gspca_dev, uint16_t reg, 19962306a36Sopenharmony_ci uint16_t data) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci uint16_t reply[2]; 20262306a36Sopenharmony_ci __le16 cmd[2]; 20362306a36Sopenharmony_ci int res; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci cmd[0] = cpu_to_le16(reg); 20662306a36Sopenharmony_ci cmd[1] = cpu_to_le16(data); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_USBO, "Write Reg 0x%04x <= 0x%02x\n", reg, data); 20962306a36Sopenharmony_ci res = send_cmd(gspca_dev, 0x03, cmd, 4, reply, 4); 21062306a36Sopenharmony_ci if (res < 0) 21162306a36Sopenharmony_ci return res; 21262306a36Sopenharmony_ci if (res != 2) { 21362306a36Sopenharmony_ci pr_warn("send_cmd returned %d [%04x %04x], 0000 expected\n", 21462306a36Sopenharmony_ci res, reply[0], reply[1]); 21562306a36Sopenharmony_ci } 21662306a36Sopenharmony_ci return 0; 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci/* this function is called at probe time */ 22062306a36Sopenharmony_cistatic int sd_config_video(struct gspca_dev *gspca_dev, 22162306a36Sopenharmony_ci const struct usb_device_id *id) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 22462306a36Sopenharmony_ci struct cam *cam; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci sd->cam_tag = 0; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci sd->stream_flag = 0x80; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci cam = &gspca_dev->cam; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci cam->cam_mode = video_camera_mode; 23362306a36Sopenharmony_ci cam->nmodes = ARRAY_SIZE(video_camera_mode); 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci gspca_dev->xfer_ep = 0x81; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci#if 0 23862306a36Sopenharmony_ci /* Setting those values is not needed for video stream */ 23962306a36Sopenharmony_ci cam->npkt = 15; 24062306a36Sopenharmony_ci gspca_dev->pkt_size = 960 * 2; 24162306a36Sopenharmony_ci#endif 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci return 0; 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cistatic int sd_config_depth(struct gspca_dev *gspca_dev, 24762306a36Sopenharmony_ci const struct usb_device_id *id) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 25062306a36Sopenharmony_ci struct cam *cam; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci sd->cam_tag = 0; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci sd->stream_flag = 0x70; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci cam = &gspca_dev->cam; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci cam->cam_mode = depth_camera_mode; 25962306a36Sopenharmony_ci cam->nmodes = ARRAY_SIZE(depth_camera_mode); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci gspca_dev->xfer_ep = 0x82; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci return 0; 26462306a36Sopenharmony_ci} 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci/* this function is called at probe and resume time */ 26762306a36Sopenharmony_cistatic int sd_init(struct gspca_dev *gspca_dev) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_PROBE, "Kinect Camera device.\n"); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci return 0; 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_cistatic int sd_start_video(struct gspca_dev *gspca_dev) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci int mode; 27762306a36Sopenharmony_ci uint8_t fmt_reg, fmt_val; 27862306a36Sopenharmony_ci uint8_t res_reg, res_val; 27962306a36Sopenharmony_ci uint8_t fps_reg, fps_val; 28062306a36Sopenharmony_ci uint8_t mode_val; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci if (mode & FORMAT_Y10B) { 28562306a36Sopenharmony_ci fmt_reg = 0x19; 28662306a36Sopenharmony_ci res_reg = 0x1a; 28762306a36Sopenharmony_ci fps_reg = 0x1b; 28862306a36Sopenharmony_ci mode_val = 0x03; 28962306a36Sopenharmony_ci } else { 29062306a36Sopenharmony_ci fmt_reg = 0x0c; 29162306a36Sopenharmony_ci res_reg = 0x0d; 29262306a36Sopenharmony_ci fps_reg = 0x0e; 29362306a36Sopenharmony_ci mode_val = 0x01; 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci /* format */ 29762306a36Sopenharmony_ci if (mode & FORMAT_UYVY) 29862306a36Sopenharmony_ci fmt_val = 0x05; 29962306a36Sopenharmony_ci else 30062306a36Sopenharmony_ci fmt_val = 0x00; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci if (mode & MODE_1280x1024) 30362306a36Sopenharmony_ci res_val = 0x02; 30462306a36Sopenharmony_ci else 30562306a36Sopenharmony_ci res_val = 0x01; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci if (mode & FPS_HIGH) 30862306a36Sopenharmony_ci fps_val = 0x1e; 30962306a36Sopenharmony_ci else 31062306a36Sopenharmony_ci fps_val = 0x0f; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci /* turn off IR-reset function */ 31462306a36Sopenharmony_ci write_register(gspca_dev, 0x105, 0x00); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci /* Reset video stream */ 31762306a36Sopenharmony_ci write_register(gspca_dev, 0x05, 0x00); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci /* Due to some ridiculous condition in the firmware, we have to start 32062306a36Sopenharmony_ci * and stop the depth stream before the camera will hand us 1280x1024 32162306a36Sopenharmony_ci * IR. This is a stupid workaround, but we've yet to find a better 32262306a36Sopenharmony_ci * solution. 32362306a36Sopenharmony_ci * 32462306a36Sopenharmony_ci * Thanks to Drew Fisher for figuring this out. 32562306a36Sopenharmony_ci */ 32662306a36Sopenharmony_ci if (mode & (FORMAT_Y10B | MODE_1280x1024)) { 32762306a36Sopenharmony_ci write_register(gspca_dev, 0x13, 0x01); 32862306a36Sopenharmony_ci write_register(gspca_dev, 0x14, 0x1e); 32962306a36Sopenharmony_ci write_register(gspca_dev, 0x06, 0x02); 33062306a36Sopenharmony_ci write_register(gspca_dev, 0x06, 0x00); 33162306a36Sopenharmony_ci } 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci write_register(gspca_dev, fmt_reg, fmt_val); 33462306a36Sopenharmony_ci write_register(gspca_dev, res_reg, res_val); 33562306a36Sopenharmony_ci write_register(gspca_dev, fps_reg, fps_val); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci /* Start video stream */ 33862306a36Sopenharmony_ci write_register(gspca_dev, 0x05, mode_val); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci /* disable Hflip */ 34162306a36Sopenharmony_ci write_register(gspca_dev, 0x47, 0x00); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci return 0; 34462306a36Sopenharmony_ci} 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_cistatic int sd_start_depth(struct gspca_dev *gspca_dev) 34762306a36Sopenharmony_ci{ 34862306a36Sopenharmony_ci /* turn off IR-reset function */ 34962306a36Sopenharmony_ci write_register(gspca_dev, 0x105, 0x00); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci /* reset depth stream */ 35262306a36Sopenharmony_ci write_register(gspca_dev, 0x06, 0x00); 35362306a36Sopenharmony_ci /* Depth Stream Format 0x03: 11 bit stream | 0x02: 10 bit */ 35462306a36Sopenharmony_ci write_register(gspca_dev, 0x12, 0x02); 35562306a36Sopenharmony_ci /* Depth Stream Resolution 1: standard (640x480) */ 35662306a36Sopenharmony_ci write_register(gspca_dev, 0x13, 0x01); 35762306a36Sopenharmony_ci /* Depth Framerate / 0x1e (30): 30 fps */ 35862306a36Sopenharmony_ci write_register(gspca_dev, 0x14, 0x1e); 35962306a36Sopenharmony_ci /* Depth Stream Control / 2: Open Depth Stream */ 36062306a36Sopenharmony_ci write_register(gspca_dev, 0x06, 0x02); 36162306a36Sopenharmony_ci /* disable depth hflip / LSB = 0: Smoothing Disabled */ 36262306a36Sopenharmony_ci write_register(gspca_dev, 0x17, 0x00); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci return 0; 36562306a36Sopenharmony_ci} 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_cistatic void sd_stopN_video(struct gspca_dev *gspca_dev) 36862306a36Sopenharmony_ci{ 36962306a36Sopenharmony_ci /* reset video stream */ 37062306a36Sopenharmony_ci write_register(gspca_dev, 0x05, 0x00); 37162306a36Sopenharmony_ci} 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_cistatic void sd_stopN_depth(struct gspca_dev *gspca_dev) 37462306a36Sopenharmony_ci{ 37562306a36Sopenharmony_ci /* reset depth stream */ 37662306a36Sopenharmony_ci write_register(gspca_dev, 0x06, 0x00); 37762306a36Sopenharmony_ci} 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_cistatic void sd_pkt_scan(struct gspca_dev *gspca_dev, u8 *__data, int len) 38062306a36Sopenharmony_ci{ 38162306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci struct pkt_hdr *hdr = (void *)__data; 38462306a36Sopenharmony_ci uint8_t *data = __data + sizeof(*hdr); 38562306a36Sopenharmony_ci int datalen = len - sizeof(*hdr); 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci uint8_t sof = sd->stream_flag | 1; 38862306a36Sopenharmony_ci uint8_t mof = sd->stream_flag | 2; 38962306a36Sopenharmony_ci uint8_t eof = sd->stream_flag | 5; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci if (len < 12) 39262306a36Sopenharmony_ci return; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci if (hdr->magic[0] != 'R' || hdr->magic[1] != 'B') { 39562306a36Sopenharmony_ci pr_warn("[Stream %02x] Invalid magic %02x%02x\n", 39662306a36Sopenharmony_ci sd->stream_flag, hdr->magic[0], hdr->magic[1]); 39762306a36Sopenharmony_ci return; 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci if (hdr->flag == sof) 40162306a36Sopenharmony_ci gspca_frame_add(gspca_dev, FIRST_PACKET, data, datalen); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci else if (hdr->flag == mof) 40462306a36Sopenharmony_ci gspca_frame_add(gspca_dev, INTER_PACKET, data, datalen); 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci else if (hdr->flag == eof) 40762306a36Sopenharmony_ci gspca_frame_add(gspca_dev, LAST_PACKET, data, datalen); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci else 41062306a36Sopenharmony_ci pr_warn("Packet type not recognized...\n"); 41162306a36Sopenharmony_ci} 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci/* sub-driver description */ 41462306a36Sopenharmony_cistatic const struct sd_desc sd_desc_video = { 41562306a36Sopenharmony_ci .name = MODULE_NAME, 41662306a36Sopenharmony_ci .config = sd_config_video, 41762306a36Sopenharmony_ci .init = sd_init, 41862306a36Sopenharmony_ci .start = sd_start_video, 41962306a36Sopenharmony_ci .stopN = sd_stopN_video, 42062306a36Sopenharmony_ci .pkt_scan = sd_pkt_scan, 42162306a36Sopenharmony_ci /* 42262306a36Sopenharmony_ci .get_streamparm = sd_get_streamparm, 42362306a36Sopenharmony_ci .set_streamparm = sd_set_streamparm, 42462306a36Sopenharmony_ci */ 42562306a36Sopenharmony_ci}; 42662306a36Sopenharmony_cistatic const struct sd_desc sd_desc_depth = { 42762306a36Sopenharmony_ci .name = MODULE_NAME, 42862306a36Sopenharmony_ci .config = sd_config_depth, 42962306a36Sopenharmony_ci .init = sd_init, 43062306a36Sopenharmony_ci .start = sd_start_depth, 43162306a36Sopenharmony_ci .stopN = sd_stopN_depth, 43262306a36Sopenharmony_ci .pkt_scan = sd_pkt_scan, 43362306a36Sopenharmony_ci /* 43462306a36Sopenharmony_ci .get_streamparm = sd_get_streamparm, 43562306a36Sopenharmony_ci .set_streamparm = sd_set_streamparm, 43662306a36Sopenharmony_ci */ 43762306a36Sopenharmony_ci}; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci/* -- module initialisation -- */ 44062306a36Sopenharmony_cistatic const struct usb_device_id device_table[] = { 44162306a36Sopenharmony_ci {USB_DEVICE(0x045e, 0x02ae)}, 44262306a36Sopenharmony_ci {USB_DEVICE(0x045e, 0x02bf)}, 44362306a36Sopenharmony_ci {} 44462306a36Sopenharmony_ci}; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, device_table); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci/* -- device connect -- */ 44962306a36Sopenharmony_cistatic int sd_probe(struct usb_interface *intf, const struct usb_device_id *id) 45062306a36Sopenharmony_ci{ 45162306a36Sopenharmony_ci if (depth_mode) 45262306a36Sopenharmony_ci return gspca_dev_probe(intf, id, &sd_desc_depth, 45362306a36Sopenharmony_ci sizeof(struct sd), THIS_MODULE); 45462306a36Sopenharmony_ci else 45562306a36Sopenharmony_ci return gspca_dev_probe(intf, id, &sd_desc_video, 45662306a36Sopenharmony_ci sizeof(struct sd), THIS_MODULE); 45762306a36Sopenharmony_ci} 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_cistatic struct usb_driver sd_driver = { 46062306a36Sopenharmony_ci .name = MODULE_NAME, 46162306a36Sopenharmony_ci .id_table = device_table, 46262306a36Sopenharmony_ci .probe = sd_probe, 46362306a36Sopenharmony_ci .disconnect = gspca_disconnect, 46462306a36Sopenharmony_ci#ifdef CONFIG_PM 46562306a36Sopenharmony_ci .suspend = gspca_suspend, 46662306a36Sopenharmony_ci .resume = gspca_resume, 46762306a36Sopenharmony_ci .reset_resume = gspca_resume, 46862306a36Sopenharmony_ci#endif 46962306a36Sopenharmony_ci}; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_cimodule_usb_driver(sd_driver); 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_cimodule_param(depth_mode, bool, 0644); 47462306a36Sopenharmony_ciMODULE_PARM_DESC(depth_mode, "0=video 1=depth"); 475