^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Pixart PAC7302 driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2008-2012 Jean-Francois Moine <http://moinejf.free.fr>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Separated from Pixart PAC7311 library by Márton Németh
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Camera button input handling by Márton Németh <nm127@freemail.hu>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Copyright (C) 2009-2010 Márton Németh <nm127@freemail.hu>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * Some documentation about various registers as determined by trial and error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * Register page 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * Address Description
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * 0x01 Red balance control
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * 0x02 Green balance control
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * 0x03 Blue balance control
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * The Windows driver uses a quadratic approach to map
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * the settable values (0-200) on register values:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * min=0x20, default=0x40, max=0x80
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * 0x0f-0x20 Color and saturation control
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * 0xa2-0xab Brightness, contrast and gamma control
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) * 0xb6 Sharpness control (bits 0-4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) * Register page 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) * Address Description
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) * 0x78 Global control, bit 6 controls the LED (inverted)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) * 0x80 Compression balance, 2 interesting settings:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) * 0x0f Default
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * 0x50 Values >= this switch the camera to a lower compression,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) * using the same table for both luminance and chrominance.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) * This gives a sharper picture. Only usable when running
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) * at < 15 fps! Note currently the driver does not use this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) * as the quality gain is small and the generated JPG-s are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) * only understood by v4l-utils >= 0.8.9
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) * Register page 3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) * Address Description
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) * 0x02 Clock divider 3-63, fps = 90 / val. Must be a multiple of 3 on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * the 7302, so one of 3, 6, 9, ..., except when between 6 and 12?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * 0x03 Variable framerate ctrl reg2==3: 0 -> ~30 fps, 255 -> ~22fps
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * 0x04 Another var framerate ctrl reg2==3, reg3==0: 0 -> ~30 fps,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) * 63 -> ~27 fps, the 2 msb's must always be 1 !!
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) * 0x05 Another var framerate ctrl reg2==3, reg3==0, reg4==0xc0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) * 1 -> ~30 fps, 2 -> ~20 fps
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) * 0x0e Exposure bits 0-7, 0-448, 0 = use full frame time
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) * 0x0f Exposure bit 8, 0-448, 448 = no exposure at all
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) * 0x10 Gain 0-31
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * 0x12 Another gain 0-31, unlike 0x10 this one seems to start with an
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) * amplification value of 1 rather then 0 at its lowest setting
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) * 0x21 Bitfield: 0-1 unused, 2-3 vflip/hflip, 4-5 unknown, 6-7 unused
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) * 0x80 Another framerate control, best left at 1, moving it from 1 to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) * 2 causes the framerate to become 3/4th of what it was, and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * also seems to cause pixel averaging, resulting in an effective
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) * resolution of 320x240 and thus a much blockier image
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) * The registers are accessed in the following functions:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) * Page | Register | Function
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) * -----+------------+---------------------------------------------------
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) * 0 | 0x01 | setredbalance()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) * 0 | 0x03 | setbluebalance()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) * 0 | 0x0f..0x20 | setcolors()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) * 0 | 0xa2..0xab | setbrightcont()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) * 0 | 0xb6 | setsharpness()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) * 0 | 0xc6 | setwhitebalance()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) * 0 | 0xdc | setbrightcont(), setcolors()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) * 3 | 0x02 | setexposure()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) * 3 | 0x10, 0x12 | setgain()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) * 3 | 0x11 | setcolors(), setgain(), setexposure(), sethvflip()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) * 3 | 0x21 | sethvflip()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) #include <linux/input.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) #include "gspca.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) /* Include pac common sof detection functions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) #include "pac_common.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) #define PAC7302_RGB_BALANCE_MIN 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) #define PAC7302_RGB_BALANCE_MAX 200
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) #define PAC7302_RGB_BALANCE_DEFAULT 100
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) #define PAC7302_GAIN_DEFAULT 15
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) #define PAC7302_GAIN_KNEE 42
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) #define PAC7302_EXPOSURE_DEFAULT 66 /* 33 ms / 30 fps */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) #define PAC7302_EXPOSURE_KNEE 133 /* 66 ms / 15 fps */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>, Thomas Kaiser thomas@kaiser-linux.li");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) MODULE_DESCRIPTION("Pixart PAC7302");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) struct sd {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) struct gspca_dev gspca_dev; /* !! must be the first item */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) struct { /* brightness / contrast cluster */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) struct v4l2_ctrl *brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) struct v4l2_ctrl *contrast;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) struct v4l2_ctrl *saturation;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) struct v4l2_ctrl *white_balance;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) struct v4l2_ctrl *red_balance;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) struct v4l2_ctrl *blue_balance;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) struct { /* flip cluster */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) struct v4l2_ctrl *hflip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) struct v4l2_ctrl *vflip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) struct v4l2_ctrl *sharpness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) u8 flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) #define FL_HFLIP 0x01 /* mirrored by default */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) #define FL_VFLIP 0x02 /* vertical flipped by default */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) u8 sof_read;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) s8 autogain_ignore_frames;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) atomic_t avg_lum;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) static const struct v4l2_pix_format vga_mode[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) {640, 480, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) .bytesperline = 640,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) .sizeimage = 640 * 480 * 3 / 8 + 590,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) .colorspace = V4L2_COLORSPACE_JPEG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) #define LOAD_PAGE3 255
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) #define END_OF_SEQUENCE 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) static const u8 init_7302[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) /* index,value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 0xff, 0x01, /* page 1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 0x78, 0x00, /* deactivate */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 0xff, 0x01,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 0x78, 0x40, /* led off */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) static const u8 start_7302[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) /* index, len, [value]* */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 0xff, 1, 0x00, /* page 0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 0x00, 12, 0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 0x00, 0x00, 0x00, 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 0x0d, 24, 0x03, 0x01, 0x00, 0xb5, 0x07, 0xcb, 0x00, 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 0x07, 0xc8, 0x00, 0xea, 0x07, 0xcf, 0x07, 0xf7,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 0x07, 0x7e, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x11,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) 0x26, 2, 0xaa, 0xaa,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) 0x2e, 1, 0x31,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) 0x38, 1, 0x01,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 0x3a, 3, 0x14, 0xff, 0x5a,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) 0x43, 11, 0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) 0x00, 0x54, 0x11,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) 0x55, 1, 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) 0x62, 4, 0x10, 0x1e, 0x1e, 0x18,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) 0x6b, 1, 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 0x6e, 3, 0x08, 0x06, 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 0x72, 3, 0x00, 0xff, 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 0x7d, 23, 0x01, 0x01, 0x58, 0x46, 0x50, 0x3c, 0x50, 0x3c,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 0x54, 0x46, 0x54, 0x56, 0x52, 0x50, 0x52, 0x50,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 0x56, 0x64, 0xa4, 0x00, 0xda, 0x00, 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 0xa2, 10, 0x22, 0x2c, 0x3c, 0x54, 0x69, 0x7c, 0x9c, 0xb9,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 0xd2, 0xeb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 0xaf, 1, 0x02,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 0xb5, 2, 0x08, 0x08,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 0xb8, 2, 0x08, 0x88,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 0xc4, 4, 0xae, 0x01, 0x04, 0x01,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 0xcc, 1, 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 0xd1, 11, 0x01, 0x30, 0x49, 0x5e, 0x6f, 0x7f, 0x8e, 0xa9,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 0xc1, 0xd7, 0xec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) 0xdc, 1, 0x01,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 0xff, 1, 0x01, /* page 1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 0x12, 3, 0x02, 0x00, 0x01,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 0x3e, 2, 0x00, 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 0x76, 5, 0x01, 0x20, 0x40, 0x00, 0xf2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 0x7c, 1, 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 0x7f, 10, 0x4b, 0x0f, 0x01, 0x2c, 0x02, 0x58, 0x03, 0x20,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 0x02, 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 0x96, 5, 0x01, 0x10, 0x04, 0x01, 0x04,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) 0xc8, 14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 0x07, 0x00, 0x01, 0x07, 0x04, 0x01,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) 0xd8, 1, 0x01,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 0xdb, 2, 0x00, 0x01,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 0xde, 7, 0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) 0xe6, 4, 0x00, 0x00, 0x00, 0x01,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) 0xeb, 1, 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) 0xff, 1, 0x02, /* page 2 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 0x22, 1, 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) 0xff, 1, 0x03, /* page 3 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) 0, LOAD_PAGE3, /* load the page 3 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) 0x11, 1, 0x01,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) 0xff, 1, 0x02, /* page 2 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) 0x13, 1, 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) 0x22, 4, 0x1f, 0xa4, 0xf0, 0x96,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) 0x27, 2, 0x14, 0x0c,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) 0x2a, 5, 0xc8, 0x00, 0x18, 0x12, 0x22,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) 0x64, 8, 0x00, 0x00, 0xf0, 0x01, 0x14, 0x44, 0x44, 0x44,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) 0x6e, 1, 0x08,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) 0xff, 1, 0x01, /* page 1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) 0x78, 1, 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) 0, END_OF_SEQUENCE /* end of sequence */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) #define SKIP 0xaa
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) /* page 3 - the value SKIP says skip the index - see reg_w_page() */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) static const u8 page3_7302[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) 0x90, 0x40, 0x03, 0x00, 0xc0, 0x01, 0x14, 0x16,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) 0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) 0x00, 0x00, 0x00, 0x47, 0x01, 0xb3, 0x01, 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) 0x00, 0x08, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x21,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) 0x00, 0x00, 0x00, 0x54, 0xf4, 0x02, 0x52, 0x54,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) 0xa4, 0xb8, 0xe0, 0x2a, 0xf6, 0x00, 0x00, 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) 0x00, 0xfc, 0x00, 0xf2, 0x1f, 0x04, 0x00, 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) SKIP, 0x00, 0x00, 0xc0, 0xc0, 0x10, 0x00, 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) 0x00, 0x40, 0xff, 0x03, 0x19, 0x00, 0x00, 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0xc8, 0xc8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) 0x08, 0x10, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) 0x01, 0x00, 0x02, 0x47, 0x00, 0x00, 0x00, 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) 0x00, 0x02, 0xfa, 0x00, 0x64, 0x5a, 0x28, 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) static void reg_w_buf(struct gspca_dev *gspca_dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) u8 index,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) const u8 *buffer, int len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) if (gspca_dev->usb_err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) memcpy(gspca_dev->usb_buf, buffer, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) ret = usb_control_msg(gspca_dev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) usb_sndctrlpipe(gspca_dev->dev, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) 0, /* request */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) 0, /* value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) index, gspca_dev->usb_buf, len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) 500);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) pr_err("reg_w_buf failed i: %02x error %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) index, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) gspca_dev->usb_err = ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) static void reg_w(struct gspca_dev *gspca_dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) u8 index,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) u8 value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) if (gspca_dev->usb_err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) gspca_dev->usb_buf[0] = value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) ret = usb_control_msg(gspca_dev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) usb_sndctrlpipe(gspca_dev->dev, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) 0, /* request */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) 0, index, gspca_dev->usb_buf, 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) 500);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) pr_err("reg_w() failed i: %02x v: %02x error %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) index, value, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) gspca_dev->usb_err = ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) static void reg_w_seq(struct gspca_dev *gspca_dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) const u8 *seq, int len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) while (--len >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) reg_w(gspca_dev, seq[0], seq[1]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) seq += 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) /* load the beginning of a page */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) static void reg_w_page(struct gspca_dev *gspca_dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) const u8 *page, int len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) int index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) if (gspca_dev->usb_err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) for (index = 0; index < len; index++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) if (page[index] == SKIP) /* skip this index */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) gspca_dev->usb_buf[0] = page[index];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) ret = usb_control_msg(gspca_dev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) usb_sndctrlpipe(gspca_dev->dev, 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) 0, /* request */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) 0, index, gspca_dev->usb_buf, 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) 500);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) pr_err("reg_w_page() failed i: %02x v: %02x error %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) index, page[index], ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) gspca_dev->usb_err = ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) /* output a variable sequence */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) static void reg_w_var(struct gspca_dev *gspca_dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) const u8 *seq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) const u8 *page3, unsigned int page3_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) int index, len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) for (;;) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) index = *seq++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) len = *seq++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) switch (len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) case END_OF_SEQUENCE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) case LOAD_PAGE3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) reg_w_page(gspca_dev, page3, page3_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) if (len > USB_BUF_SZ) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) gspca_err(gspca_dev, "Incorrect variable sequence\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) while (len > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) if (len < 8) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) reg_w_buf(gspca_dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) index, seq, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) seq += len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) reg_w_buf(gspca_dev, index, seq, 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) seq += 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) index += 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) len -= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) /* not reached */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) /* this function is called at probe time for pac7302 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) static int sd_config(struct gspca_dev *gspca_dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) const struct usb_device_id *id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) struct sd *sd = (struct sd *) gspca_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) struct cam *cam;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) cam = &gspca_dev->cam;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) cam->cam_mode = vga_mode; /* only 640x480 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) cam->nmodes = ARRAY_SIZE(vga_mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) sd->flags = id->driver_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) static void setbrightcont(struct gspca_dev *gspca_dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) struct sd *sd = (struct sd *) gspca_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) int i, v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) static const u8 max[10] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) {0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) 0xd4, 0xec};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) static const u8 delta[10] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) {0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) 0x11, 0x0b};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) for (i = 0; i < 10; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) v = max[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) v += (sd->brightness->val - (s32)sd->brightness->maximum)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) * 150 / (s32)sd->brightness->maximum; /* 200 ? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) v -= delta[i] * sd->contrast->val / (s32)sd->contrast->maximum;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) if (v < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) v = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) else if (v > 0xff)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) v = 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) reg_w(gspca_dev, 0xa2 + i, v);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) reg_w(gspca_dev, 0xdc, 0x01);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) static void setcolors(struct gspca_dev *gspca_dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) struct sd *sd = (struct sd *) gspca_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) int i, v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) static const int a[9] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) {217, -212, 0, -101, 170, -67, -38, -315, 355};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) static const int b[9] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) {19, 106, 0, 19, 106, 1, 19, 106, 1};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) reg_w(gspca_dev, 0x11, 0x01);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) for (i = 0; i < 9; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) v = a[i] * sd->saturation->val / (s32)sd->saturation->maximum;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) v += b[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) reg_w(gspca_dev, 0x0f + 2 * i + 1, v);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) reg_w(gspca_dev, 0xdc, 0x01);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) static void setwhitebalance(struct gspca_dev *gspca_dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) struct sd *sd = (struct sd *) gspca_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) reg_w(gspca_dev, 0xc6, sd->white_balance->val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) reg_w(gspca_dev, 0xdc, 0x01);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) static u8 rgbbalance_ctrl_to_reg_value(s32 rgb_ctrl_val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) const unsigned int k = 1000; /* precision factor */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) unsigned int norm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) /* Normed value [0...k] */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) norm = k * (rgb_ctrl_val - PAC7302_RGB_BALANCE_MIN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) / (PAC7302_RGB_BALANCE_MAX - PAC7302_RGB_BALANCE_MIN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) /* Qudratic apporach improves control at small (register) values: */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) return 64 * norm * norm / (k*k) + 32 * norm / k + 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) /* Y = 64*X*X + 32*X + 32
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) * => register values 0x20-0x80; Windows driver uses these limits */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) /* NOTE: for full value range (0x00-0xff) use
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) * Y = 254*X*X + X
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) * => 254 * norm * norm / (k*k) + 1 * norm / k */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) static void setredbalance(struct gspca_dev *gspca_dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) struct sd *sd = (struct sd *) gspca_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) reg_w(gspca_dev, 0x01,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) rgbbalance_ctrl_to_reg_value(sd->red_balance->val));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) reg_w(gspca_dev, 0xdc, 0x01);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) static void setbluebalance(struct gspca_dev *gspca_dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) struct sd *sd = (struct sd *) gspca_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) reg_w(gspca_dev, 0x03,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) rgbbalance_ctrl_to_reg_value(sd->blue_balance->val));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) reg_w(gspca_dev, 0xdc, 0x01);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) static void setgain(struct gspca_dev *gspca_dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) u8 reg10, reg12;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) if (gspca_dev->gain->val < 32) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) reg10 = gspca_dev->gain->val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) reg12 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) reg10 = 31;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) reg12 = gspca_dev->gain->val - 31;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) reg_w(gspca_dev, 0x10, reg10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) reg_w(gspca_dev, 0x12, reg12);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) /* load registers to sensor (Bit 0, auto clear) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) reg_w(gspca_dev, 0x11, 0x01);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) static void setexposure(struct gspca_dev *gspca_dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) u8 clockdiv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) u16 exposure;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) * Register 2 of frame 3 contains the clock divider configuring the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) * no fps according to the formula: 90 / reg. sd->exposure is the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) * desired exposure time in 0.5 ms.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) clockdiv = (90 * gspca_dev->exposure->val + 1999) / 2000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) * Note clockdiv = 3 also works, but when running at 30 fps, depending
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) * on the scene being recorded, the camera switches to another
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) * quantization table for certain JPEG blocks, and we don't know how
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) * to decompress these blocks. So we cap the framerate at 15 fps.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) if (clockdiv < 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) clockdiv = 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) else if (clockdiv > 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) clockdiv = 63;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) * Register 2 MUST be a multiple of 3, except when between 6 and 12?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) * Always round up, otherwise we cannot get the desired frametime
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) * using the partial frame time exposure control.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) if (clockdiv < 6 || clockdiv > 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) clockdiv = ((clockdiv + 2) / 3) * 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) * frame exposure time in ms = 1000 * clockdiv / 90 ->
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) * exposure = (sd->exposure / 2) * 448 / (1000 * clockdiv / 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) exposure = (gspca_dev->exposure->val * 45 * 448) / (1000 * clockdiv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) /* 0 = use full frametime, 448 = no exposure, reverse it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) exposure = 448 - exposure;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) reg_w(gspca_dev, 0x02, clockdiv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) reg_w(gspca_dev, 0x0e, exposure & 0xff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) reg_w(gspca_dev, 0x0f, exposure >> 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) /* load registers to sensor (Bit 0, auto clear) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) reg_w(gspca_dev, 0x11, 0x01);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) static void sethvflip(struct gspca_dev *gspca_dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) struct sd *sd = (struct sd *) gspca_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) u8 data, hflip, vflip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) hflip = sd->hflip->val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) if (sd->flags & FL_HFLIP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) hflip = !hflip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) vflip = sd->vflip->val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) if (sd->flags & FL_VFLIP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) vflip = !vflip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) data = (hflip ? 0x08 : 0x00) | (vflip ? 0x04 : 0x00);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) reg_w(gspca_dev, 0x21, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) /* load registers to sensor (Bit 0, auto clear) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) reg_w(gspca_dev, 0x11, 0x01);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) static void setsharpness(struct gspca_dev *gspca_dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) struct sd *sd = (struct sd *) gspca_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) reg_w(gspca_dev, 0xb6, sd->sharpness->val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) reg_w(gspca_dev, 0xdc, 0x01);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) /* this function is called at probe and resume time for pac7302 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) static int sd_init(struct gspca_dev *gspca_dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) reg_w_seq(gspca_dev, init_7302, sizeof(init_7302)/2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) return gspca_dev->usb_err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) struct gspca_dev *gspca_dev =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) struct sd *sd = (struct sd *)gspca_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) gspca_dev->usb_err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) if (ctrl->id == V4L2_CID_AUTOGAIN && ctrl->is_new && ctrl->val) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) /* when switching to autogain set defaults to make sure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) we are on a valid point of the autogain gain /
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) exposure knee graph, and give this change time to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) take effect before doing autogain. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) gspca_dev->exposure->val = PAC7302_EXPOSURE_DEFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) gspca_dev->gain->val = PAC7302_GAIN_DEFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) if (!gspca_dev->streaming)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) switch (ctrl->id) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) case V4L2_CID_BRIGHTNESS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) setbrightcont(gspca_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) case V4L2_CID_SATURATION:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) setcolors(gspca_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) case V4L2_CID_WHITE_BALANCE_TEMPERATURE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) setwhitebalance(gspca_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) case V4L2_CID_RED_BALANCE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) setredbalance(gspca_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) case V4L2_CID_BLUE_BALANCE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) setbluebalance(gspca_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) case V4L2_CID_AUTOGAIN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) if (gspca_dev->exposure->is_new || (ctrl->is_new && ctrl->val))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) setexposure(gspca_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) if (gspca_dev->gain->is_new || (ctrl->is_new && ctrl->val))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) setgain(gspca_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) case V4L2_CID_HFLIP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) sethvflip(gspca_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) case V4L2_CID_SHARPNESS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) setsharpness(gspca_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) return gspca_dev->usb_err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) static const struct v4l2_ctrl_ops sd_ctrl_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) .s_ctrl = sd_s_ctrl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) /* this function is called at probe time */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) static int sd_init_controls(struct gspca_dev *gspca_dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) struct sd *sd = (struct sd *) gspca_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) gspca_dev->vdev.ctrl_handler = hdl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) v4l2_ctrl_handler_init(hdl, 12);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) sd->brightness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) V4L2_CID_BRIGHTNESS, 0, 32, 1, 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) sd->contrast = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) V4L2_CID_CONTRAST, 0, 255, 1, 127);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) sd->saturation = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) V4L2_CID_SATURATION, 0, 255, 1, 127);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) sd->white_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) V4L2_CID_WHITE_BALANCE_TEMPERATURE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) 0, 255, 1, 55);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) sd->red_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) V4L2_CID_RED_BALANCE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) PAC7302_RGB_BALANCE_MIN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) PAC7302_RGB_BALANCE_MAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) 1, PAC7302_RGB_BALANCE_DEFAULT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) sd->blue_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) V4L2_CID_BLUE_BALANCE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) PAC7302_RGB_BALANCE_MIN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) PAC7302_RGB_BALANCE_MAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) 1, PAC7302_RGB_BALANCE_DEFAULT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) gspca_dev->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) gspca_dev->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) V4L2_CID_EXPOSURE, 0, 1023, 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) PAC7302_EXPOSURE_DEFAULT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) V4L2_CID_GAIN, 0, 62, 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) PAC7302_GAIN_DEFAULT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) sd->hflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) V4L2_CID_HFLIP, 0, 1, 1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) sd->vflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) V4L2_CID_VFLIP, 0, 1, 1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) sd->sharpness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) V4L2_CID_SHARPNESS, 0, 15, 1, 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) if (hdl->error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) pr_err("Could not initialize controls\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) return hdl->error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) v4l2_ctrl_cluster(2, &sd->brightness);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) v4l2_ctrl_auto_cluster(3, &gspca_dev->autogain, 0, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) v4l2_ctrl_cluster(2, &sd->hflip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) /* -- start the camera -- */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) static int sd_start(struct gspca_dev *gspca_dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) struct sd *sd = (struct sd *) gspca_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) reg_w_var(gspca_dev, start_7302,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) page3_7302, sizeof(page3_7302));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) sd->sof_read = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) sd->autogain_ignore_frames = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) atomic_set(&sd->avg_lum, 270 + sd->brightness->val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) /* start stream */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) reg_w(gspca_dev, 0xff, 0x01);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) reg_w(gspca_dev, 0x78, 0x01);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) return gspca_dev->usb_err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) static void sd_stopN(struct gspca_dev *gspca_dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) /* stop stream */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) reg_w(gspca_dev, 0xff, 0x01);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) reg_w(gspca_dev, 0x78, 0x00);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) /* called on streamoff with alt 0 and on disconnect for pac7302 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) static void sd_stop0(struct gspca_dev *gspca_dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) if (!gspca_dev->present)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) reg_w(gspca_dev, 0xff, 0x01);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) reg_w(gspca_dev, 0x78, 0x40);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) static void do_autogain(struct gspca_dev *gspca_dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) struct sd *sd = (struct sd *) gspca_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) int avg_lum = atomic_read(&sd->avg_lum);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) int desired_lum;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) const int deadzone = 30;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) if (sd->autogain_ignore_frames < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) if (sd->autogain_ignore_frames > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) sd->autogain_ignore_frames--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) desired_lum = 270 + sd->brightness->val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) if (gspca_expo_autogain(gspca_dev, avg_lum, desired_lum,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) deadzone, PAC7302_GAIN_KNEE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) PAC7302_EXPOSURE_KNEE))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) sd->autogain_ignore_frames =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) PAC_AUTOGAIN_IGNORE_FRAMES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) /* JPEG header */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) static const u8 jpeg_header[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) 0xff, 0xd8, /* SOI: Start of Image */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) 0xff, 0xc0, /* SOF0: Start of Frame (Baseline DCT) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) 0x00, 0x11, /* length = 17 bytes (including this length field) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) 0x08, /* Precision: 8 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) 0x02, 0x80, /* height = 640 (image rotated) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) 0x01, 0xe0, /* width = 480 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) 0x03, /* Number of image components: 3 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) 0x01, 0x21, 0x00, /* ID=1, Subsampling 1x1, Quantization table: 0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) 0x02, 0x11, 0x01, /* ID=2, Subsampling 2x1, Quantization table: 1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) 0x03, 0x11, 0x01, /* ID=3, Subsampling 2x1, Quantization table: 1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) 0xff, 0xda, /* SOS: Start Of Scan */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) 0x00, 0x0c, /* length = 12 bytes (including this length field) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) 0x03, /* number of components: 3 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) 0x01, 0x00, /* selector 1, table 0x00 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) 0x02, 0x11, /* selector 2, table 0x11 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) 0x03, 0x11, /* selector 3, table 0x11 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) 0x00, 0x3f, /* Spectral selection: 0 .. 63 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) 0x00 /* Successive approximation: 0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) /* this function is run at interrupt level */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) static void sd_pkt_scan(struct gspca_dev *gspca_dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) u8 *data, /* isoc packet */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) int len) /* iso packet length */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) struct sd *sd = (struct sd *) gspca_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) u8 *image;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) u8 *sof;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) sof = pac_find_sof(gspca_dev, &sd->sof_read, data, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) if (sof) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) int n, lum_offset, footer_length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) * 6 bytes after the FF D9 EOF marker a number of lumination
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) * bytes are send corresponding to different parts of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) * image, the 14th and 15th byte after the EOF seem to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) * correspond to the center of the image.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) lum_offset = 61 + sizeof pac_sof_marker;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) footer_length = 74;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) /* Finish decoding current frame */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) n = (sof - data) - (footer_length + sizeof pac_sof_marker);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) if (n < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) gspca_dev->image_len += n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) n = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) gspca_frame_add(gspca_dev, INTER_PACKET, data, n);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) image = gspca_dev->image;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) if (image != NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) && image[gspca_dev->image_len - 2] == 0xff
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) && image[gspca_dev->image_len - 1] == 0xd9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) n = sof - data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) len -= n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) data = sof;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) /* Get average lumination */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) if (gspca_dev->last_packet_type == LAST_PACKET &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) n >= lum_offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) atomic_set(&sd->avg_lum, data[-lum_offset] +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) data[-lum_offset + 1]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) /* Start the new frame with the jpeg header */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) /* The PAC7302 has the image rotated 90 degrees */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) gspca_frame_add(gspca_dev, FIRST_PACKET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) jpeg_header, sizeof jpeg_header);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) #ifdef CONFIG_VIDEO_ADV_DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) const struct v4l2_dbg_register *reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) u8 index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) u8 value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) * reg->reg: bit0..15: reserved for register index (wIndex is 16bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) * long on the USB bus)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) if (reg->match.addr == 0 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) (reg->reg < 0x000000ff) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) (reg->val <= 0x000000ff)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) ) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) /* Currently writing to page 0 is only supported. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) /* reg_w() only supports 8bit index */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) index = reg->reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) value = reg->val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) * Note that there shall be no access to other page
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) * by any other function between the page switch and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) * the actual register write.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) reg_w(gspca_dev, index, value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) reg_w(gspca_dev, 0xdc, 0x01);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) return gspca_dev->usb_err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) #if IS_ENABLED(CONFIG_INPUT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) u8 *data, /* interrupt packet data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) int len) /* interrupt packet length */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) int ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) u8 data0, data1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) if (len == 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) data0 = data[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) data1 = data[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) if ((data0 == 0x00 && data1 == 0x11) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) (data0 == 0x22 && data1 == 0x33) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) (data0 == 0x44 && data1 == 0x55) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) (data0 == 0x66 && data1 == 0x77) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) (data0 == 0x88 && data1 == 0x99) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) (data0 == 0xaa && data1 == 0xbb) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) (data0 == 0xcc && data1 == 0xdd) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) (data0 == 0xee && data1 == 0xff)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) input_sync(gspca_dev->input_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) input_sync(gspca_dev->input_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) /* sub-driver description for pac7302 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) static const struct sd_desc sd_desc = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) .name = KBUILD_MODNAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) .config = sd_config,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) .init = sd_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) .init_controls = sd_init_controls,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) .start = sd_start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) .stopN = sd_stopN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) .stop0 = sd_stop0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) .pkt_scan = sd_pkt_scan,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) .dq_callback = do_autogain,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) #ifdef CONFIG_VIDEO_ADV_DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) .set_register = sd_dbg_s_register,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) #if IS_ENABLED(CONFIG_INPUT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) .int_pkt_scan = sd_int_pkt_scan,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) /* -- module initialisation -- */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) static const struct usb_device_id device_table[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) {USB_DEVICE(0x06f8, 0x3009)},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) {USB_DEVICE(0x06f8, 0x301b)},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) {USB_DEVICE(0x093a, 0x2620)},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) {USB_DEVICE(0x093a, 0x2621)},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) {USB_DEVICE(0x093a, 0x2622), .driver_info = FL_VFLIP},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) {USB_DEVICE(0x093a, 0x2623), .driver_info = FL_VFLIP},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) {USB_DEVICE(0x093a, 0x2624), .driver_info = FL_VFLIP},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) {USB_DEVICE(0x093a, 0x2625)},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) {USB_DEVICE(0x093a, 0x2626)},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) {USB_DEVICE(0x093a, 0x2627), .driver_info = FL_VFLIP},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) {USB_DEVICE(0x093a, 0x2628)},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) {USB_DEVICE(0x093a, 0x2629), .driver_info = FL_VFLIP},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) {USB_DEVICE(0x093a, 0x262a)},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) {USB_DEVICE(0x093a, 0x262c)},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) {USB_DEVICE(0x145f, 0x013c)},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) {USB_DEVICE(0x1ae7, 0x2001)}, /* SpeedLink Snappy Mic SL-6825-SBK */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) MODULE_DEVICE_TABLE(usb, device_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) /* -- device connect -- */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) static int sd_probe(struct usb_interface *intf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) const struct usb_device_id *id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) THIS_MODULE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) static struct usb_driver sd_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) .name = KBUILD_MODNAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) .id_table = device_table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) .probe = sd_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) .disconnect = gspca_disconnect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) #ifdef CONFIG_PM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) .suspend = gspca_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) .resume = gspca_resume,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) .reset_resume = gspca_resume,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) module_usb_driver(sd_driver);