1*fd9871f7SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 20c0d06caSMauro Carvalho Chehab /* 30c0d06caSMauro Carvalho Chehab * Mars-Semi MR97311A library 40c0d06caSMauro Carvalho Chehab * Copyright (C) 2005 <bradlch@hotmail.com> 50c0d06caSMauro Carvalho Chehab * 60c0d06caSMauro Carvalho Chehab * V4L2 by Jean-Francois Moine <http://moinejf.free.fr> 70c0d06caSMauro Carvalho Chehab */ 80c0d06caSMauro Carvalho Chehab 90c0d06caSMauro Carvalho Chehab #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 100c0d06caSMauro Carvalho Chehab 110c0d06caSMauro Carvalho Chehab #define MODULE_NAME "mars" 120c0d06caSMauro Carvalho Chehab 130c0d06caSMauro Carvalho Chehab #include "gspca.h" 140c0d06caSMauro Carvalho Chehab #include "jpeg.h" 150c0d06caSMauro Carvalho Chehab 160c0d06caSMauro Carvalho Chehab MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>"); 170c0d06caSMauro Carvalho Chehab MODULE_DESCRIPTION("GSPCA/Mars USB Camera Driver"); 180c0d06caSMauro Carvalho Chehab MODULE_LICENSE("GPL"); 190c0d06caSMauro Carvalho Chehab 200c0d06caSMauro Carvalho Chehab #define QUALITY 50 210c0d06caSMauro Carvalho Chehab 220c0d06caSMauro Carvalho Chehab /* specific webcam descriptor */ 230c0d06caSMauro Carvalho Chehab struct sd { 240c0d06caSMauro Carvalho Chehab struct gspca_dev gspca_dev; /* !! must be the first item */ 250c0d06caSMauro Carvalho Chehab 260c0d06caSMauro Carvalho Chehab struct v4l2_ctrl *brightness; 270c0d06caSMauro Carvalho Chehab struct v4l2_ctrl *saturation; 280c0d06caSMauro Carvalho Chehab struct v4l2_ctrl *sharpness; 290c0d06caSMauro Carvalho Chehab struct v4l2_ctrl *gamma; 300c0d06caSMauro Carvalho Chehab struct { /* illuminator control cluster */ 310c0d06caSMauro Carvalho Chehab struct v4l2_ctrl *illum_top; 320c0d06caSMauro Carvalho Chehab struct v4l2_ctrl *illum_bottom; 330c0d06caSMauro Carvalho Chehab }; 340c0d06caSMauro Carvalho Chehab u8 jpeg_hdr[JPEG_HDR_SZ]; 350c0d06caSMauro Carvalho Chehab }; 360c0d06caSMauro Carvalho Chehab 370c0d06caSMauro Carvalho Chehab /* V4L2 controls supported by the driver */ 380c0d06caSMauro Carvalho Chehab static void setbrightness(struct gspca_dev *gspca_dev, s32 val); 390c0d06caSMauro Carvalho Chehab static void setcolors(struct gspca_dev *gspca_dev, s32 val); 400c0d06caSMauro Carvalho Chehab static void setgamma(struct gspca_dev *gspca_dev, s32 val); 410c0d06caSMauro Carvalho Chehab static void setsharpness(struct gspca_dev *gspca_dev, s32 val); 420c0d06caSMauro Carvalho Chehab 430c0d06caSMauro Carvalho Chehab static const struct v4l2_pix_format vga_mode[] = { 440c0d06caSMauro Carvalho Chehab {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, 450c0d06caSMauro Carvalho Chehab .bytesperline = 320, 460c0d06caSMauro Carvalho Chehab .sizeimage = 320 * 240 * 3 / 8 + 590, 470c0d06caSMauro Carvalho Chehab .colorspace = V4L2_COLORSPACE_JPEG, 480c0d06caSMauro Carvalho Chehab .priv = 2}, 490c0d06caSMauro Carvalho Chehab {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, 500c0d06caSMauro Carvalho Chehab .bytesperline = 640, 510c0d06caSMauro Carvalho Chehab .sizeimage = 640 * 480 * 3 / 8 + 590, 520c0d06caSMauro Carvalho Chehab .colorspace = V4L2_COLORSPACE_JPEG, 530c0d06caSMauro Carvalho Chehab .priv = 1}, 540c0d06caSMauro Carvalho Chehab }; 550c0d06caSMauro Carvalho Chehab 560c0d06caSMauro Carvalho Chehab static const __u8 mi_data[0x20] = { 570c0d06caSMauro Carvalho Chehab /* 01 02 03 04 05 06 07 08 */ 580c0d06caSMauro Carvalho Chehab 0x48, 0x22, 0x01, 0x47, 0x10, 0x00, 0x00, 0x00, 590c0d06caSMauro Carvalho Chehab /* 09 0a 0b 0c 0d 0e 0f 10 */ 600c0d06caSMauro Carvalho Chehab 0x00, 0x01, 0x30, 0x01, 0x30, 0x01, 0x30, 0x01, 610c0d06caSMauro Carvalho Chehab /* 11 12 13 14 15 16 17 18 */ 620c0d06caSMauro Carvalho Chehab 0x30, 0x00, 0x04, 0x00, 0x06, 0x01, 0xe2, 0x02, 630c0d06caSMauro Carvalho Chehab /* 19 1a 1b 1c 1d 1e 1f 20 */ 640c0d06caSMauro Carvalho Chehab 0x82, 0x00, 0x20, 0x17, 0x80, 0x08, 0x0c, 0x00 650c0d06caSMauro Carvalho Chehab }; 660c0d06caSMauro Carvalho Chehab 670c0d06caSMauro Carvalho Chehab /* write <len> bytes from gspca_dev->usb_buf */ 680c0d06caSMauro Carvalho Chehab static void reg_w(struct gspca_dev *gspca_dev, 690c0d06caSMauro Carvalho Chehab int len) 700c0d06caSMauro Carvalho Chehab { 710c0d06caSMauro Carvalho Chehab int alen, ret; 720c0d06caSMauro Carvalho Chehab 730c0d06caSMauro Carvalho Chehab if (gspca_dev->usb_err < 0) 740c0d06caSMauro Carvalho Chehab return; 750c0d06caSMauro Carvalho Chehab 760c0d06caSMauro Carvalho Chehab ret = usb_bulk_msg(gspca_dev->dev, 770c0d06caSMauro Carvalho Chehab usb_sndbulkpipe(gspca_dev->dev, 4), 780c0d06caSMauro Carvalho Chehab gspca_dev->usb_buf, 790c0d06caSMauro Carvalho Chehab len, 800c0d06caSMauro Carvalho Chehab &alen, 810c0d06caSMauro Carvalho Chehab 500); /* timeout in milliseconds */ 820c0d06caSMauro Carvalho Chehab if (ret < 0) { 830c0d06caSMauro Carvalho Chehab pr_err("reg write [%02x] error %d\n", 840c0d06caSMauro Carvalho Chehab gspca_dev->usb_buf[0], ret); 850c0d06caSMauro Carvalho Chehab gspca_dev->usb_err = ret; 860c0d06caSMauro Carvalho Chehab } 870c0d06caSMauro Carvalho Chehab } 880c0d06caSMauro Carvalho Chehab 890c0d06caSMauro Carvalho Chehab static void mi_w(struct gspca_dev *gspca_dev, 900c0d06caSMauro Carvalho Chehab u8 addr, 910c0d06caSMauro Carvalho Chehab u8 value) 920c0d06caSMauro Carvalho Chehab { 930c0d06caSMauro Carvalho Chehab gspca_dev->usb_buf[0] = 0x1f; 940c0d06caSMauro Carvalho Chehab gspca_dev->usb_buf[1] = 0; /* control byte */ 950c0d06caSMauro Carvalho Chehab gspca_dev->usb_buf[2] = addr; 960c0d06caSMauro Carvalho Chehab gspca_dev->usb_buf[3] = value; 970c0d06caSMauro Carvalho Chehab 980c0d06caSMauro Carvalho Chehab reg_w(gspca_dev, 4); 990c0d06caSMauro Carvalho Chehab } 1000c0d06caSMauro Carvalho Chehab 1010c0d06caSMauro Carvalho Chehab static void setbrightness(struct gspca_dev *gspca_dev, s32 val) 1020c0d06caSMauro Carvalho Chehab { 1030c0d06caSMauro Carvalho Chehab gspca_dev->usb_buf[0] = 0x61; 1040c0d06caSMauro Carvalho Chehab gspca_dev->usb_buf[1] = val; 1050c0d06caSMauro Carvalho Chehab reg_w(gspca_dev, 2); 1060c0d06caSMauro Carvalho Chehab } 1070c0d06caSMauro Carvalho Chehab 1080c0d06caSMauro Carvalho Chehab static void setcolors(struct gspca_dev *gspca_dev, s32 val) 1090c0d06caSMauro Carvalho Chehab { 1100c0d06caSMauro Carvalho Chehab gspca_dev->usb_buf[0] = 0x5f; 1110c0d06caSMauro Carvalho Chehab gspca_dev->usb_buf[1] = val << 3; 1120c0d06caSMauro Carvalho Chehab gspca_dev->usb_buf[2] = ((val >> 2) & 0xf8) | 0x04; 1130c0d06caSMauro Carvalho Chehab reg_w(gspca_dev, 3); 1140c0d06caSMauro Carvalho Chehab } 1150c0d06caSMauro Carvalho Chehab 1160c0d06caSMauro Carvalho Chehab static void setgamma(struct gspca_dev *gspca_dev, s32 val) 1170c0d06caSMauro Carvalho Chehab { 1180c0d06caSMauro Carvalho Chehab gspca_dev->usb_buf[0] = 0x06; 1190c0d06caSMauro Carvalho Chehab gspca_dev->usb_buf[1] = val * 0x40; 1200c0d06caSMauro Carvalho Chehab reg_w(gspca_dev, 2); 1210c0d06caSMauro Carvalho Chehab } 1220c0d06caSMauro Carvalho Chehab 1230c0d06caSMauro Carvalho Chehab static void setsharpness(struct gspca_dev *gspca_dev, s32 val) 1240c0d06caSMauro Carvalho Chehab { 1250c0d06caSMauro Carvalho Chehab gspca_dev->usb_buf[0] = 0x67; 1260c0d06caSMauro Carvalho Chehab gspca_dev->usb_buf[1] = val * 4 + 3; 1270c0d06caSMauro Carvalho Chehab reg_w(gspca_dev, 2); 1280c0d06caSMauro Carvalho Chehab } 1290c0d06caSMauro Carvalho Chehab 1300c0d06caSMauro Carvalho Chehab static void setilluminators(struct gspca_dev *gspca_dev, bool top, bool bottom) 1310c0d06caSMauro Carvalho Chehab { 1320c0d06caSMauro Carvalho Chehab /* both are off if not streaming */ 1330c0d06caSMauro Carvalho Chehab gspca_dev->usb_buf[0] = 0x22; 1340c0d06caSMauro Carvalho Chehab if (top) 1350c0d06caSMauro Carvalho Chehab gspca_dev->usb_buf[1] = 0x76; 1360c0d06caSMauro Carvalho Chehab else if (bottom) 1370c0d06caSMauro Carvalho Chehab gspca_dev->usb_buf[1] = 0x7a; 1380c0d06caSMauro Carvalho Chehab else 1390c0d06caSMauro Carvalho Chehab gspca_dev->usb_buf[1] = 0x7e; 1400c0d06caSMauro Carvalho Chehab reg_w(gspca_dev, 2); 1410c0d06caSMauro Carvalho Chehab } 1420c0d06caSMauro Carvalho Chehab 1430c0d06caSMauro Carvalho Chehab static int mars_s_ctrl(struct v4l2_ctrl *ctrl) 1440c0d06caSMauro Carvalho Chehab { 1450c0d06caSMauro Carvalho Chehab struct gspca_dev *gspca_dev = 1460c0d06caSMauro Carvalho Chehab container_of(ctrl->handler, struct gspca_dev, ctrl_handler); 1470c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *)gspca_dev; 1480c0d06caSMauro Carvalho Chehab 1490c0d06caSMauro Carvalho Chehab gspca_dev->usb_err = 0; 1500c0d06caSMauro Carvalho Chehab 1510c0d06caSMauro Carvalho Chehab if (ctrl->id == V4L2_CID_ILLUMINATORS_1) { 1520c0d06caSMauro Carvalho Chehab /* only one can be on at a time */ 1530c0d06caSMauro Carvalho Chehab if (ctrl->is_new && ctrl->val) 1540c0d06caSMauro Carvalho Chehab sd->illum_bottom->val = 0; 1550c0d06caSMauro Carvalho Chehab if (sd->illum_bottom->is_new && sd->illum_bottom->val) 1560c0d06caSMauro Carvalho Chehab sd->illum_top->val = 0; 1570c0d06caSMauro Carvalho Chehab } 1580c0d06caSMauro Carvalho Chehab 1590c0d06caSMauro Carvalho Chehab if (!gspca_dev->streaming) 1600c0d06caSMauro Carvalho Chehab return 0; 1610c0d06caSMauro Carvalho Chehab 1620c0d06caSMauro Carvalho Chehab switch (ctrl->id) { 1630c0d06caSMauro Carvalho Chehab case V4L2_CID_BRIGHTNESS: 1640c0d06caSMauro Carvalho Chehab setbrightness(gspca_dev, ctrl->val); 1650c0d06caSMauro Carvalho Chehab break; 1660c0d06caSMauro Carvalho Chehab case V4L2_CID_SATURATION: 1670c0d06caSMauro Carvalho Chehab setcolors(gspca_dev, ctrl->val); 1680c0d06caSMauro Carvalho Chehab break; 1690c0d06caSMauro Carvalho Chehab case V4L2_CID_GAMMA: 1700c0d06caSMauro Carvalho Chehab setgamma(gspca_dev, ctrl->val); 1710c0d06caSMauro Carvalho Chehab break; 1720c0d06caSMauro Carvalho Chehab case V4L2_CID_ILLUMINATORS_1: 1730c0d06caSMauro Carvalho Chehab setilluminators(gspca_dev, sd->illum_top->val, 1740c0d06caSMauro Carvalho Chehab sd->illum_bottom->val); 1750c0d06caSMauro Carvalho Chehab break; 1760c0d06caSMauro Carvalho Chehab case V4L2_CID_SHARPNESS: 1770c0d06caSMauro Carvalho Chehab setsharpness(gspca_dev, ctrl->val); 1780c0d06caSMauro Carvalho Chehab break; 1790c0d06caSMauro Carvalho Chehab default: 1800c0d06caSMauro Carvalho Chehab return -EINVAL; 1810c0d06caSMauro Carvalho Chehab } 1820c0d06caSMauro Carvalho Chehab return gspca_dev->usb_err; 1830c0d06caSMauro Carvalho Chehab } 1840c0d06caSMauro Carvalho Chehab 1850c0d06caSMauro Carvalho Chehab static const struct v4l2_ctrl_ops mars_ctrl_ops = { 1860c0d06caSMauro Carvalho Chehab .s_ctrl = mars_s_ctrl, 1870c0d06caSMauro Carvalho Chehab }; 1880c0d06caSMauro Carvalho Chehab 1890c0d06caSMauro Carvalho Chehab /* this function is called at probe time */ 1900c0d06caSMauro Carvalho Chehab static int sd_init_controls(struct gspca_dev *gspca_dev) 1910c0d06caSMauro Carvalho Chehab { 1920c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev; 1930c0d06caSMauro Carvalho Chehab struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; 1940c0d06caSMauro Carvalho Chehab 1950c0d06caSMauro Carvalho Chehab gspca_dev->vdev.ctrl_handler = hdl; 1960c0d06caSMauro Carvalho Chehab v4l2_ctrl_handler_init(hdl, 6); 1970c0d06caSMauro Carvalho Chehab sd->brightness = v4l2_ctrl_new_std(hdl, &mars_ctrl_ops, 1980c0d06caSMauro Carvalho Chehab V4L2_CID_BRIGHTNESS, 0, 30, 1, 15); 1990c0d06caSMauro Carvalho Chehab sd->saturation = v4l2_ctrl_new_std(hdl, &mars_ctrl_ops, 2000c0d06caSMauro Carvalho Chehab V4L2_CID_SATURATION, 0, 255, 1, 200); 2010c0d06caSMauro Carvalho Chehab sd->gamma = v4l2_ctrl_new_std(hdl, &mars_ctrl_ops, 2020c0d06caSMauro Carvalho Chehab V4L2_CID_GAMMA, 0, 3, 1, 1); 2030c0d06caSMauro Carvalho Chehab sd->sharpness = v4l2_ctrl_new_std(hdl, &mars_ctrl_ops, 2040c0d06caSMauro Carvalho Chehab V4L2_CID_SHARPNESS, 0, 2, 1, 1); 2050c0d06caSMauro Carvalho Chehab sd->illum_top = v4l2_ctrl_new_std(hdl, &mars_ctrl_ops, 2060c0d06caSMauro Carvalho Chehab V4L2_CID_ILLUMINATORS_1, 0, 1, 1, 0); 2070c0d06caSMauro Carvalho Chehab sd->illum_top->flags |= V4L2_CTRL_FLAG_UPDATE; 2080c0d06caSMauro Carvalho Chehab sd->illum_bottom = v4l2_ctrl_new_std(hdl, &mars_ctrl_ops, 2090c0d06caSMauro Carvalho Chehab V4L2_CID_ILLUMINATORS_2, 0, 1, 1, 0); 2100c0d06caSMauro Carvalho Chehab sd->illum_bottom->flags |= V4L2_CTRL_FLAG_UPDATE; 2110c0d06caSMauro Carvalho Chehab if (hdl->error) { 2120c0d06caSMauro Carvalho Chehab pr_err("Could not initialize controls\n"); 2130c0d06caSMauro Carvalho Chehab return hdl->error; 2140c0d06caSMauro Carvalho Chehab } 2150c0d06caSMauro Carvalho Chehab v4l2_ctrl_cluster(2, &sd->illum_top); 2160c0d06caSMauro Carvalho Chehab return 0; 2170c0d06caSMauro Carvalho Chehab } 2180c0d06caSMauro Carvalho Chehab 2190c0d06caSMauro Carvalho Chehab /* this function is called at probe time */ 2200c0d06caSMauro Carvalho Chehab static int sd_config(struct gspca_dev *gspca_dev, 2210c0d06caSMauro Carvalho Chehab const struct usb_device_id *id) 2220c0d06caSMauro Carvalho Chehab { 2230c0d06caSMauro Carvalho Chehab struct cam *cam; 2240c0d06caSMauro Carvalho Chehab 2250c0d06caSMauro Carvalho Chehab cam = &gspca_dev->cam; 2260c0d06caSMauro Carvalho Chehab cam->cam_mode = vga_mode; 2270c0d06caSMauro Carvalho Chehab cam->nmodes = ARRAY_SIZE(vga_mode); 2280c0d06caSMauro Carvalho Chehab return 0; 2290c0d06caSMauro Carvalho Chehab } 2300c0d06caSMauro Carvalho Chehab 2310c0d06caSMauro Carvalho Chehab /* this function is called at probe and resume time */ 2320c0d06caSMauro Carvalho Chehab static int sd_init(struct gspca_dev *gspca_dev) 2330c0d06caSMauro Carvalho Chehab { 2340c0d06caSMauro Carvalho Chehab return 0; 2350c0d06caSMauro Carvalho Chehab } 2360c0d06caSMauro Carvalho Chehab 2370c0d06caSMauro Carvalho Chehab static int sd_start(struct gspca_dev *gspca_dev) 2380c0d06caSMauro Carvalho Chehab { 2390c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev; 2400c0d06caSMauro Carvalho Chehab u8 *data; 2410c0d06caSMauro Carvalho Chehab int i; 2420c0d06caSMauro Carvalho Chehab 2430c0d06caSMauro Carvalho Chehab /* create the JPEG header */ 2441966bc2aSOndrej Zary jpeg_define(sd->jpeg_hdr, gspca_dev->pixfmt.height, 2451966bc2aSOndrej Zary gspca_dev->pixfmt.width, 2460c0d06caSMauro Carvalho Chehab 0x21); /* JPEG 422 */ 2470c0d06caSMauro Carvalho Chehab jpeg_set_qual(sd->jpeg_hdr, QUALITY); 2480c0d06caSMauro Carvalho Chehab 2490c0d06caSMauro Carvalho Chehab data = gspca_dev->usb_buf; 2500c0d06caSMauro Carvalho Chehab 2510c0d06caSMauro Carvalho Chehab data[0] = 0x01; /* address */ 2520c0d06caSMauro Carvalho Chehab data[1] = 0x01; 2530c0d06caSMauro Carvalho Chehab reg_w(gspca_dev, 2); 2540c0d06caSMauro Carvalho Chehab 2550c0d06caSMauro Carvalho Chehab /* 2560c0d06caSMauro Carvalho Chehab Initialize the MR97113 chip register 2570c0d06caSMauro Carvalho Chehab */ 2580c0d06caSMauro Carvalho Chehab data[0] = 0x00; /* address */ 2590c0d06caSMauro Carvalho Chehab data[1] = 0x0c | 0x01; /* reg 0 */ 2600c0d06caSMauro Carvalho Chehab data[2] = 0x01; /* reg 1 */ 2611966bc2aSOndrej Zary data[3] = gspca_dev->pixfmt.width / 8; /* h_size , reg 2 */ 2621966bc2aSOndrej Zary data[4] = gspca_dev->pixfmt.height / 8; /* v_size , reg 3 */ 2630c0d06caSMauro Carvalho Chehab data[5] = 0x30; /* reg 4, MI, PAS5101 : 2640c0d06caSMauro Carvalho Chehab * 0x30 for 24mhz , 0x28 for 12mhz */ 2650c0d06caSMauro Carvalho Chehab data[6] = 0x02; /* reg 5, H start - was 0x04 */ 2660c0d06caSMauro Carvalho Chehab data[7] = v4l2_ctrl_g_ctrl(sd->gamma) * 0x40; /* reg 0x06: gamma */ 2670c0d06caSMauro Carvalho Chehab data[8] = 0x01; /* reg 7, V start - was 0x03 */ 2680c0d06caSMauro Carvalho Chehab /* if (h_size == 320 ) */ 2690c0d06caSMauro Carvalho Chehab /* data[9]= 0x56; * reg 8, 24MHz, 2:1 scale down */ 2700c0d06caSMauro Carvalho Chehab /* else */ 2710c0d06caSMauro Carvalho Chehab data[9] = 0x52; /* reg 8, 24MHz, no scale down */ 2720c0d06caSMauro Carvalho Chehab /*jfm: from win trace*/ 2730c0d06caSMauro Carvalho Chehab data[10] = 0x18; 2740c0d06caSMauro Carvalho Chehab 2750c0d06caSMauro Carvalho Chehab reg_w(gspca_dev, 11); 2760c0d06caSMauro Carvalho Chehab 2770c0d06caSMauro Carvalho Chehab data[0] = 0x23; /* address */ 2780c0d06caSMauro Carvalho Chehab data[1] = 0x09; /* reg 35, append frame header */ 2790c0d06caSMauro Carvalho Chehab 2800c0d06caSMauro Carvalho Chehab reg_w(gspca_dev, 2); 2810c0d06caSMauro Carvalho Chehab 2820c0d06caSMauro Carvalho Chehab data[0] = 0x3c; /* address */ 2830c0d06caSMauro Carvalho Chehab /* if (gspca_dev->width == 1280) */ 2840c0d06caSMauro Carvalho Chehab /* data[1] = 200; * reg 60, pc-cam frame size 2850c0d06caSMauro Carvalho Chehab * (unit: 4KB) 800KB */ 2860c0d06caSMauro Carvalho Chehab /* else */ 2870c0d06caSMauro Carvalho Chehab data[1] = 50; /* 50 reg 60, pc-cam frame size 2880c0d06caSMauro Carvalho Chehab * (unit: 4KB) 200KB */ 2890c0d06caSMauro Carvalho Chehab reg_w(gspca_dev, 2); 2900c0d06caSMauro Carvalho Chehab 2910c0d06caSMauro Carvalho Chehab /* auto dark-gain */ 2920c0d06caSMauro Carvalho Chehab data[0] = 0x5e; /* address */ 2930c0d06caSMauro Carvalho Chehab data[1] = 0; /* reg 94, Y Gain (auto) */ 2940c0d06caSMauro Carvalho Chehab /*jfm: from win trace*/ 2950c0d06caSMauro Carvalho Chehab /* reg 0x5f/0x60 (LE) = saturation */ 2960c0d06caSMauro Carvalho Chehab /* h (60): xxxx x100 2970c0d06caSMauro Carvalho Chehab * l (5f): xxxx x000 */ 2980c0d06caSMauro Carvalho Chehab data[2] = v4l2_ctrl_g_ctrl(sd->saturation) << 3; 2990c0d06caSMauro Carvalho Chehab data[3] = ((v4l2_ctrl_g_ctrl(sd->saturation) >> 2) & 0xf8) | 0x04; 3000c0d06caSMauro Carvalho Chehab data[4] = v4l2_ctrl_g_ctrl(sd->brightness); /* reg 0x61 = brightness */ 3010c0d06caSMauro Carvalho Chehab data[5] = 0x00; 3020c0d06caSMauro Carvalho Chehab 3030c0d06caSMauro Carvalho Chehab reg_w(gspca_dev, 6); 3040c0d06caSMauro Carvalho Chehab 3050c0d06caSMauro Carvalho Chehab data[0] = 0x67; 3060c0d06caSMauro Carvalho Chehab /*jfm: from win trace*/ 3070c0d06caSMauro Carvalho Chehab data[1] = v4l2_ctrl_g_ctrl(sd->sharpness) * 4 + 3; 3080c0d06caSMauro Carvalho Chehab data[2] = 0x14; 3090c0d06caSMauro Carvalho Chehab reg_w(gspca_dev, 3); 3100c0d06caSMauro Carvalho Chehab 3110c0d06caSMauro Carvalho Chehab data[0] = 0x69; 3120c0d06caSMauro Carvalho Chehab data[1] = 0x2f; 3130c0d06caSMauro Carvalho Chehab data[2] = 0x28; 3140c0d06caSMauro Carvalho Chehab data[3] = 0x42; 3150c0d06caSMauro Carvalho Chehab reg_w(gspca_dev, 4); 3160c0d06caSMauro Carvalho Chehab 3170c0d06caSMauro Carvalho Chehab data[0] = 0x63; 3180c0d06caSMauro Carvalho Chehab data[1] = 0x07; 3190c0d06caSMauro Carvalho Chehab reg_w(gspca_dev, 2); 3200c0d06caSMauro Carvalho Chehab /*jfm: win trace - many writes here to reg 0x64*/ 3210c0d06caSMauro Carvalho Chehab 3220c0d06caSMauro Carvalho Chehab /* initialize the MI sensor */ 3230c0d06caSMauro Carvalho Chehab for (i = 0; i < sizeof mi_data; i++) 3240c0d06caSMauro Carvalho Chehab mi_w(gspca_dev, i + 1, mi_data[i]); 3250c0d06caSMauro Carvalho Chehab 3260c0d06caSMauro Carvalho Chehab data[0] = 0x00; 3270c0d06caSMauro Carvalho Chehab data[1] = 0x4d; /* ISOC transferring enable... */ 3280c0d06caSMauro Carvalho Chehab reg_w(gspca_dev, 2); 3290c0d06caSMauro Carvalho Chehab 3300c0d06caSMauro Carvalho Chehab setilluminators(gspca_dev, v4l2_ctrl_g_ctrl(sd->illum_top), 3310c0d06caSMauro Carvalho Chehab v4l2_ctrl_g_ctrl(sd->illum_bottom)); 3320c0d06caSMauro Carvalho Chehab 3330c0d06caSMauro Carvalho Chehab return gspca_dev->usb_err; 3340c0d06caSMauro Carvalho Chehab } 3350c0d06caSMauro Carvalho Chehab 3360c0d06caSMauro Carvalho Chehab static void sd_stopN(struct gspca_dev *gspca_dev) 3370c0d06caSMauro Carvalho Chehab { 3380c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev; 3390c0d06caSMauro Carvalho Chehab 3400c0d06caSMauro Carvalho Chehab if (v4l2_ctrl_g_ctrl(sd->illum_top) || 3410c0d06caSMauro Carvalho Chehab v4l2_ctrl_g_ctrl(sd->illum_bottom)) { 3420c0d06caSMauro Carvalho Chehab setilluminators(gspca_dev, false, false); 3430c0d06caSMauro Carvalho Chehab msleep(20); 3440c0d06caSMauro Carvalho Chehab } 3450c0d06caSMauro Carvalho Chehab 3460c0d06caSMauro Carvalho Chehab gspca_dev->usb_buf[0] = 1; 3470c0d06caSMauro Carvalho Chehab gspca_dev->usb_buf[1] = 0; 3480c0d06caSMauro Carvalho Chehab reg_w(gspca_dev, 2); 3490c0d06caSMauro Carvalho Chehab } 3500c0d06caSMauro Carvalho Chehab 3510c0d06caSMauro Carvalho Chehab static void sd_pkt_scan(struct gspca_dev *gspca_dev, 3520c0d06caSMauro Carvalho Chehab u8 *data, /* isoc packet */ 3530c0d06caSMauro Carvalho Chehab int len) /* iso packet length */ 3540c0d06caSMauro Carvalho Chehab { 3550c0d06caSMauro Carvalho Chehab struct sd *sd = (struct sd *) gspca_dev; 3560c0d06caSMauro Carvalho Chehab int p; 3570c0d06caSMauro Carvalho Chehab 3580c0d06caSMauro Carvalho Chehab if (len < 6) { 3590c0d06caSMauro Carvalho Chehab /* gspca_dev->last_packet_type = DISCARD_PACKET; */ 3600c0d06caSMauro Carvalho Chehab return; 3610c0d06caSMauro Carvalho Chehab } 3620c0d06caSMauro Carvalho Chehab for (p = 0; p < len - 6; p++) { 3630c0d06caSMauro Carvalho Chehab if (data[0 + p] == 0xff 3640c0d06caSMauro Carvalho Chehab && data[1 + p] == 0xff 3650c0d06caSMauro Carvalho Chehab && data[2 + p] == 0x00 3660c0d06caSMauro Carvalho Chehab && data[3 + p] == 0xff 3670c0d06caSMauro Carvalho Chehab && data[4 + p] == 0x96) { 3680c0d06caSMauro Carvalho Chehab if (data[5 + p] == 0x64 3690c0d06caSMauro Carvalho Chehab || data[5 + p] == 0x65 3700c0d06caSMauro Carvalho Chehab || data[5 + p] == 0x66 3710c0d06caSMauro Carvalho Chehab || data[5 + p] == 0x67) { 37237d5efb0SJoe Perches gspca_dbg(gspca_dev, D_PACK, "sof offset: %d len: %d\n", 3730c0d06caSMauro Carvalho Chehab p, len); 3740c0d06caSMauro Carvalho Chehab gspca_frame_add(gspca_dev, LAST_PACKET, 3750c0d06caSMauro Carvalho Chehab data, p); 3760c0d06caSMauro Carvalho Chehab 3770c0d06caSMauro Carvalho Chehab /* put the JPEG header */ 3780c0d06caSMauro Carvalho Chehab gspca_frame_add(gspca_dev, FIRST_PACKET, 3790c0d06caSMauro Carvalho Chehab sd->jpeg_hdr, JPEG_HDR_SZ); 3800c0d06caSMauro Carvalho Chehab data += p + 16; 3810c0d06caSMauro Carvalho Chehab len -= p + 16; 3820c0d06caSMauro Carvalho Chehab break; 3830c0d06caSMauro Carvalho Chehab } 3840c0d06caSMauro Carvalho Chehab } 3850c0d06caSMauro Carvalho Chehab } 3860c0d06caSMauro Carvalho Chehab gspca_frame_add(gspca_dev, INTER_PACKET, data, len); 3870c0d06caSMauro Carvalho Chehab } 3880c0d06caSMauro Carvalho Chehab 3890c0d06caSMauro Carvalho Chehab /* sub-driver description */ 3900c0d06caSMauro Carvalho Chehab static const struct sd_desc sd_desc = { 3910c0d06caSMauro Carvalho Chehab .name = MODULE_NAME, 3920c0d06caSMauro Carvalho Chehab .config = sd_config, 3930c0d06caSMauro Carvalho Chehab .init = sd_init, 3940c0d06caSMauro Carvalho Chehab .init_controls = sd_init_controls, 3950c0d06caSMauro Carvalho Chehab .start = sd_start, 3960c0d06caSMauro Carvalho Chehab .stopN = sd_stopN, 3970c0d06caSMauro Carvalho Chehab .pkt_scan = sd_pkt_scan, 3980c0d06caSMauro Carvalho Chehab }; 3990c0d06caSMauro Carvalho Chehab 4000c0d06caSMauro Carvalho Chehab /* -- module initialisation -- */ 4010c0d06caSMauro Carvalho Chehab static const struct usb_device_id device_table[] = { 4020c0d06caSMauro Carvalho Chehab {USB_DEVICE(0x093a, 0x050f)}, 4030c0d06caSMauro Carvalho Chehab {} 4040c0d06caSMauro Carvalho Chehab }; 4050c0d06caSMauro Carvalho Chehab MODULE_DEVICE_TABLE(usb, device_table); 4060c0d06caSMauro Carvalho Chehab 4070c0d06caSMauro Carvalho Chehab /* -- device connect -- */ 4080c0d06caSMauro Carvalho Chehab static int sd_probe(struct usb_interface *intf, 4090c0d06caSMauro Carvalho Chehab const struct usb_device_id *id) 4100c0d06caSMauro Carvalho Chehab { 4110c0d06caSMauro Carvalho Chehab return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), 4120c0d06caSMauro Carvalho Chehab THIS_MODULE); 4130c0d06caSMauro Carvalho Chehab } 4140c0d06caSMauro Carvalho Chehab 4150c0d06caSMauro Carvalho Chehab static struct usb_driver sd_driver = { 4160c0d06caSMauro Carvalho Chehab .name = MODULE_NAME, 4170c0d06caSMauro Carvalho Chehab .id_table = device_table, 4180c0d06caSMauro Carvalho Chehab .probe = sd_probe, 4190c0d06caSMauro Carvalho Chehab .disconnect = gspca_disconnect, 4200c0d06caSMauro Carvalho Chehab #ifdef CONFIG_PM 4210c0d06caSMauro Carvalho Chehab .suspend = gspca_suspend, 4220c0d06caSMauro Carvalho Chehab .resume = gspca_resume, 4230c0d06caSMauro Carvalho Chehab .reset_resume = gspca_resume, 4240c0d06caSMauro Carvalho Chehab #endif 4250c0d06caSMauro Carvalho Chehab }; 4260c0d06caSMauro Carvalho Chehab 4270c0d06caSMauro Carvalho Chehab module_usb_driver(sd_driver); 428