18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * SPCA500 chip based cameras initialization data
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#define MODULE_NAME "spca500"
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include "gspca.h"
138c2ecf20Sopenharmony_ci#include "jpeg.h"
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ciMODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
168c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("GSPCA/SPCA500 USB Camera Driver");
178c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#define QUALITY 85
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci/* specific webcam descriptor */
228c2ecf20Sopenharmony_cistruct sd {
238c2ecf20Sopenharmony_ci	struct gspca_dev gspca_dev;		/* !! must be the first item */
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci	char subtype;
268c2ecf20Sopenharmony_ci#define AgfaCl20 0
278c2ecf20Sopenharmony_ci#define AiptekPocketDV 1
288c2ecf20Sopenharmony_ci#define BenqDC1016 2
298c2ecf20Sopenharmony_ci#define CreativePCCam300 3
308c2ecf20Sopenharmony_ci#define DLinkDSC350 4
318c2ecf20Sopenharmony_ci#define Gsmartmini 5
328c2ecf20Sopenharmony_ci#define IntelPocketPCCamera 6
338c2ecf20Sopenharmony_ci#define KodakEZ200 7
348c2ecf20Sopenharmony_ci#define LogitechClickSmart310 8
358c2ecf20Sopenharmony_ci#define LogitechClickSmart510 9
368c2ecf20Sopenharmony_ci#define LogitechTraveler 10
378c2ecf20Sopenharmony_ci#define MustekGsmart300 11
388c2ecf20Sopenharmony_ci#define Optimedia 12
398c2ecf20Sopenharmony_ci#define PalmPixDC85 13
408c2ecf20Sopenharmony_ci#define ToptroIndus 14
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	u8 jpeg_hdr[JPEG_HDR_SZ];
438c2ecf20Sopenharmony_ci};
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistatic const struct v4l2_pix_format vga_mode[] = {
468c2ecf20Sopenharmony_ci	{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
478c2ecf20Sopenharmony_ci		.bytesperline = 320,
488c2ecf20Sopenharmony_ci		.sizeimage = 320 * 240 * 3 / 8 + 590,
498c2ecf20Sopenharmony_ci		.colorspace = V4L2_COLORSPACE_JPEG,
508c2ecf20Sopenharmony_ci		.priv = 1},
518c2ecf20Sopenharmony_ci	{640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
528c2ecf20Sopenharmony_ci		.bytesperline = 640,
538c2ecf20Sopenharmony_ci		.sizeimage = 640 * 480 * 3 / 8 + 590,
548c2ecf20Sopenharmony_ci		.colorspace = V4L2_COLORSPACE_JPEG,
558c2ecf20Sopenharmony_ci		.priv = 0},
568c2ecf20Sopenharmony_ci};
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_cistatic const struct v4l2_pix_format sif_mode[] = {
598c2ecf20Sopenharmony_ci	{176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
608c2ecf20Sopenharmony_ci		.bytesperline = 176,
618c2ecf20Sopenharmony_ci		.sizeimage = 176 * 144 * 3 / 8 + 590,
628c2ecf20Sopenharmony_ci		.colorspace = V4L2_COLORSPACE_JPEG,
638c2ecf20Sopenharmony_ci		.priv = 1},
648c2ecf20Sopenharmony_ci	{352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
658c2ecf20Sopenharmony_ci		.bytesperline = 352,
668c2ecf20Sopenharmony_ci		.sizeimage = 352 * 288 * 3 / 8 + 590,
678c2ecf20Sopenharmony_ci		.colorspace = V4L2_COLORSPACE_JPEG,
688c2ecf20Sopenharmony_ci		.priv = 0},
698c2ecf20Sopenharmony_ci};
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci/* Frame packet header offsets for the spca500 */
728c2ecf20Sopenharmony_ci#define SPCA500_OFFSET_PADDINGLB 2
738c2ecf20Sopenharmony_ci#define SPCA500_OFFSET_PADDINGHB 3
748c2ecf20Sopenharmony_ci#define SPCA500_OFFSET_MODE      4
758c2ecf20Sopenharmony_ci#define SPCA500_OFFSET_IMGWIDTH  5
768c2ecf20Sopenharmony_ci#define SPCA500_OFFSET_IMGHEIGHT 6
778c2ecf20Sopenharmony_ci#define SPCA500_OFFSET_IMGMODE   7
788c2ecf20Sopenharmony_ci#define SPCA500_OFFSET_QTBLINDEX 8
798c2ecf20Sopenharmony_ci#define SPCA500_OFFSET_FRAMSEQ   9
808c2ecf20Sopenharmony_ci#define SPCA500_OFFSET_CDSPINFO  10
818c2ecf20Sopenharmony_ci#define SPCA500_OFFSET_GPIO      11
828c2ecf20Sopenharmony_ci#define SPCA500_OFFSET_AUGPIO    12
838c2ecf20Sopenharmony_ci#define SPCA500_OFFSET_DATA      16
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_cistatic const __u16 spca500_visual_defaults[][3] = {
878c2ecf20Sopenharmony_ci	{0x00, 0x0003, 0x816b},	/* SSI not active sync with vsync,
888c2ecf20Sopenharmony_ci				 * hue (H byte) = 0,
898c2ecf20Sopenharmony_ci				 * saturation/hue enable,
908c2ecf20Sopenharmony_ci				 * brightness/contrast enable.
918c2ecf20Sopenharmony_ci				 */
928c2ecf20Sopenharmony_ci	{0x00, 0x0000, 0x8167},	/* brightness = 0 */
938c2ecf20Sopenharmony_ci	{0x00, 0x0020, 0x8168},	/* contrast = 0 */
948c2ecf20Sopenharmony_ci	{0x00, 0x0003, 0x816b},	/* SSI not active sync with vsync,
958c2ecf20Sopenharmony_ci				 * hue (H byte) = 0, saturation/hue enable,
968c2ecf20Sopenharmony_ci				 * brightness/contrast enable.
978c2ecf20Sopenharmony_ci				 * was 0x0003, now 0x0000.
988c2ecf20Sopenharmony_ci				 */
998c2ecf20Sopenharmony_ci	{0x00, 0x0000, 0x816a},	/* hue (L byte) = 0 */
1008c2ecf20Sopenharmony_ci	{0x00, 0x0020, 0x8169},	/* saturation = 0x20 */
1018c2ecf20Sopenharmony_ci	{0x00, 0x0050, 0x8157},	/* edge gain high threshold */
1028c2ecf20Sopenharmony_ci	{0x00, 0x0030, 0x8158},	/* edge gain low threshold */
1038c2ecf20Sopenharmony_ci	{0x00, 0x0028, 0x8159},	/* edge bandwidth high threshold */
1048c2ecf20Sopenharmony_ci	{0x00, 0x000a, 0x815a},	/* edge bandwidth low threshold */
1058c2ecf20Sopenharmony_ci	{0x00, 0x0001, 0x8202},	/* clock rate compensation = 1/25 sec/frame */
1068c2ecf20Sopenharmony_ci	{0x0c, 0x0004, 0x0000},
1078c2ecf20Sopenharmony_ci	/* set interface */
1088c2ecf20Sopenharmony_ci	{}
1098c2ecf20Sopenharmony_ci};
1108c2ecf20Sopenharmony_cistatic const __u16 Clicksmart510_defaults[][3] = {
1118c2ecf20Sopenharmony_ci	{0x00, 0x00, 0x8211},
1128c2ecf20Sopenharmony_ci	{0x00, 0x01, 0x82c0},
1138c2ecf20Sopenharmony_ci	{0x00, 0x10, 0x82cb},
1148c2ecf20Sopenharmony_ci	{0x00, 0x0f, 0x800d},
1158c2ecf20Sopenharmony_ci	{0x00, 0x82, 0x8225},
1168c2ecf20Sopenharmony_ci	{0x00, 0x21, 0x8228},
1178c2ecf20Sopenharmony_ci	{0x00, 0x00, 0x8203},
1188c2ecf20Sopenharmony_ci	{0x00, 0x00, 0x8204},
1198c2ecf20Sopenharmony_ci	{0x00, 0x08, 0x8205},
1208c2ecf20Sopenharmony_ci	{0x00, 0xf8, 0x8206},
1218c2ecf20Sopenharmony_ci	{0x00, 0x28, 0x8207},
1228c2ecf20Sopenharmony_ci	{0x00, 0xa0, 0x8208},
1238c2ecf20Sopenharmony_ci	{0x00, 0x08, 0x824a},
1248c2ecf20Sopenharmony_ci	{0x00, 0x08, 0x8214},
1258c2ecf20Sopenharmony_ci	{0x00, 0x80, 0x82c1},
1268c2ecf20Sopenharmony_ci	{0x00, 0x00, 0x82c2},
1278c2ecf20Sopenharmony_ci	{0x00, 0x00, 0x82ca},
1288c2ecf20Sopenharmony_ci	{0x00, 0x80, 0x82c1},
1298c2ecf20Sopenharmony_ci	{0x00, 0x04, 0x82c2},
1308c2ecf20Sopenharmony_ci	{0x00, 0x00, 0x82ca},
1318c2ecf20Sopenharmony_ci	{0x00, 0xfc, 0x8100},
1328c2ecf20Sopenharmony_ci	{0x00, 0xfc, 0x8105},
1338c2ecf20Sopenharmony_ci	{0x00, 0x30, 0x8101},
1348c2ecf20Sopenharmony_ci	{0x00, 0x00, 0x8102},
1358c2ecf20Sopenharmony_ci	{0x00, 0x00, 0x8103},
1368c2ecf20Sopenharmony_ci	{0x00, 0x66, 0x8107},
1378c2ecf20Sopenharmony_ci	{0x00, 0x00, 0x816b},
1388c2ecf20Sopenharmony_ci	{0x00, 0x00, 0x8155},
1398c2ecf20Sopenharmony_ci	{0x00, 0x01, 0x8156},
1408c2ecf20Sopenharmony_ci	{0x00, 0x60, 0x8157},
1418c2ecf20Sopenharmony_ci	{0x00, 0x40, 0x8158},
1428c2ecf20Sopenharmony_ci	{0x00, 0x0a, 0x8159},
1438c2ecf20Sopenharmony_ci	{0x00, 0x06, 0x815a},
1448c2ecf20Sopenharmony_ci	{0x00, 0x00, 0x813f},
1458c2ecf20Sopenharmony_ci	{0x00, 0x00, 0x8200},
1468c2ecf20Sopenharmony_ci	{0x00, 0x19, 0x8201},
1478c2ecf20Sopenharmony_ci	{0x00, 0x00, 0x82c1},
1488c2ecf20Sopenharmony_ci	{0x00, 0xa0, 0x82c2},
1498c2ecf20Sopenharmony_ci	{0x00, 0x00, 0x82ca},
1508c2ecf20Sopenharmony_ci	{0x00, 0x00, 0x8117},
1518c2ecf20Sopenharmony_ci	{0x00, 0x00, 0x8118},
1528c2ecf20Sopenharmony_ci	{0x00, 0x65, 0x8119},
1538c2ecf20Sopenharmony_ci	{0x00, 0x00, 0x811a},
1548c2ecf20Sopenharmony_ci	{0x00, 0x00, 0x811b},
1558c2ecf20Sopenharmony_ci	{0x00, 0x55, 0x811c},
1568c2ecf20Sopenharmony_ci	{0x00, 0x65, 0x811d},
1578c2ecf20Sopenharmony_ci	{0x00, 0x55, 0x811e},
1588c2ecf20Sopenharmony_ci	{0x00, 0x16, 0x811f},
1598c2ecf20Sopenharmony_ci	{0x00, 0x19, 0x8120},
1608c2ecf20Sopenharmony_ci	{0x00, 0x80, 0x8103},
1618c2ecf20Sopenharmony_ci	{0x00, 0x83, 0x816b},
1628c2ecf20Sopenharmony_ci	{0x00, 0x25, 0x8168},
1638c2ecf20Sopenharmony_ci	{0x00, 0x01, 0x820f},
1648c2ecf20Sopenharmony_ci	{0x00, 0xff, 0x8115},
1658c2ecf20Sopenharmony_ci	{0x00, 0x48, 0x8116},
1668c2ecf20Sopenharmony_ci	{0x00, 0x50, 0x8151},
1678c2ecf20Sopenharmony_ci	{0x00, 0x40, 0x8152},
1688c2ecf20Sopenharmony_ci	{0x00, 0x78, 0x8153},
1698c2ecf20Sopenharmony_ci	{0x00, 0x40, 0x8154},
1708c2ecf20Sopenharmony_ci	{0x00, 0x00, 0x8167},
1718c2ecf20Sopenharmony_ci	{0x00, 0x20, 0x8168},
1728c2ecf20Sopenharmony_ci	{0x00, 0x00, 0x816a},
1738c2ecf20Sopenharmony_ci	{0x00, 0x03, 0x816b},
1748c2ecf20Sopenharmony_ci	{0x00, 0x20, 0x8169},
1758c2ecf20Sopenharmony_ci	{0x00, 0x60, 0x8157},
1768c2ecf20Sopenharmony_ci	{0x00, 0x00, 0x8190},
1778c2ecf20Sopenharmony_ci	{0x00, 0x00, 0x81a1},
1788c2ecf20Sopenharmony_ci	{0x00, 0x00, 0x81b2},
1798c2ecf20Sopenharmony_ci	{0x00, 0x27, 0x8191},
1808c2ecf20Sopenharmony_ci	{0x00, 0x27, 0x81a2},
1818c2ecf20Sopenharmony_ci	{0x00, 0x27, 0x81b3},
1828c2ecf20Sopenharmony_ci	{0x00, 0x4b, 0x8192},
1838c2ecf20Sopenharmony_ci	{0x00, 0x4b, 0x81a3},
1848c2ecf20Sopenharmony_ci	{0x00, 0x4b, 0x81b4},
1858c2ecf20Sopenharmony_ci	{0x00, 0x66, 0x8193},
1868c2ecf20Sopenharmony_ci	{0x00, 0x66, 0x81a4},
1878c2ecf20Sopenharmony_ci	{0x00, 0x66, 0x81b5},
1888c2ecf20Sopenharmony_ci	{0x00, 0x79, 0x8194},
1898c2ecf20Sopenharmony_ci	{0x00, 0x79, 0x81a5},
1908c2ecf20Sopenharmony_ci	{0x00, 0x79, 0x81b6},
1918c2ecf20Sopenharmony_ci	{0x00, 0x8a, 0x8195},
1928c2ecf20Sopenharmony_ci	{0x00, 0x8a, 0x81a6},
1938c2ecf20Sopenharmony_ci	{0x00, 0x8a, 0x81b7},
1948c2ecf20Sopenharmony_ci	{0x00, 0x9b, 0x8196},
1958c2ecf20Sopenharmony_ci	{0x00, 0x9b, 0x81a7},
1968c2ecf20Sopenharmony_ci	{0x00, 0x9b, 0x81b8},
1978c2ecf20Sopenharmony_ci	{0x00, 0xa6, 0x8197},
1988c2ecf20Sopenharmony_ci	{0x00, 0xa6, 0x81a8},
1998c2ecf20Sopenharmony_ci	{0x00, 0xa6, 0x81b9},
2008c2ecf20Sopenharmony_ci	{0x00, 0xb2, 0x8198},
2018c2ecf20Sopenharmony_ci	{0x00, 0xb2, 0x81a9},
2028c2ecf20Sopenharmony_ci	{0x00, 0xb2, 0x81ba},
2038c2ecf20Sopenharmony_ci	{0x00, 0xbe, 0x8199},
2048c2ecf20Sopenharmony_ci	{0x00, 0xbe, 0x81aa},
2058c2ecf20Sopenharmony_ci	{0x00, 0xbe, 0x81bb},
2068c2ecf20Sopenharmony_ci	{0x00, 0xc8, 0x819a},
2078c2ecf20Sopenharmony_ci	{0x00, 0xc8, 0x81ab},
2088c2ecf20Sopenharmony_ci	{0x00, 0xc8, 0x81bc},
2098c2ecf20Sopenharmony_ci	{0x00, 0xd2, 0x819b},
2108c2ecf20Sopenharmony_ci	{0x00, 0xd2, 0x81ac},
2118c2ecf20Sopenharmony_ci	{0x00, 0xd2, 0x81bd},
2128c2ecf20Sopenharmony_ci	{0x00, 0xdb, 0x819c},
2138c2ecf20Sopenharmony_ci	{0x00, 0xdb, 0x81ad},
2148c2ecf20Sopenharmony_ci	{0x00, 0xdb, 0x81be},
2158c2ecf20Sopenharmony_ci	{0x00, 0xe4, 0x819d},
2168c2ecf20Sopenharmony_ci	{0x00, 0xe4, 0x81ae},
2178c2ecf20Sopenharmony_ci	{0x00, 0xe4, 0x81bf},
2188c2ecf20Sopenharmony_ci	{0x00, 0xed, 0x819e},
2198c2ecf20Sopenharmony_ci	{0x00, 0xed, 0x81af},
2208c2ecf20Sopenharmony_ci	{0x00, 0xed, 0x81c0},
2218c2ecf20Sopenharmony_ci	{0x00, 0xf7, 0x819f},
2228c2ecf20Sopenharmony_ci	{0x00, 0xf7, 0x81b0},
2238c2ecf20Sopenharmony_ci	{0x00, 0xf7, 0x81c1},
2248c2ecf20Sopenharmony_ci	{0x00, 0xff, 0x81a0},
2258c2ecf20Sopenharmony_ci	{0x00, 0xff, 0x81b1},
2268c2ecf20Sopenharmony_ci	{0x00, 0xff, 0x81c2},
2278c2ecf20Sopenharmony_ci	{0x00, 0x03, 0x8156},
2288c2ecf20Sopenharmony_ci	{0x00, 0x00, 0x8211},
2298c2ecf20Sopenharmony_ci	{0x00, 0x20, 0x8168},
2308c2ecf20Sopenharmony_ci	{0x00, 0x01, 0x8202},
2318c2ecf20Sopenharmony_ci	{0x00, 0x30, 0x8101},
2328c2ecf20Sopenharmony_ci	{0x00, 0x00, 0x8111},
2338c2ecf20Sopenharmony_ci	{0x00, 0x00, 0x8112},
2348c2ecf20Sopenharmony_ci	{0x00, 0x00, 0x8113},
2358c2ecf20Sopenharmony_ci	{0x00, 0x00, 0x8114},
2368c2ecf20Sopenharmony_ci	{}
2378c2ecf20Sopenharmony_ci};
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_cistatic const __u8 qtable_creative_pccam[2][64] = {
2408c2ecf20Sopenharmony_ci	{				/* Q-table Y-components */
2418c2ecf20Sopenharmony_ci	 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
2428c2ecf20Sopenharmony_ci	 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
2438c2ecf20Sopenharmony_ci	 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
2448c2ecf20Sopenharmony_ci	 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
2458c2ecf20Sopenharmony_ci	 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
2468c2ecf20Sopenharmony_ci	 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
2478c2ecf20Sopenharmony_ci	 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
2488c2ecf20Sopenharmony_ci	 0x16, 0x1c, 0x1d, 0x1d, 0x22, 0x1e, 0x1f, 0x1e},
2498c2ecf20Sopenharmony_ci	{				/* Q-table C-components */
2508c2ecf20Sopenharmony_ci	 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
2518c2ecf20Sopenharmony_ci	 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
2528c2ecf20Sopenharmony_ci	 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
2538c2ecf20Sopenharmony_ci	 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
2548c2ecf20Sopenharmony_ci	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
2558c2ecf20Sopenharmony_ci	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
2568c2ecf20Sopenharmony_ci	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
2578c2ecf20Sopenharmony_ci	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
2588c2ecf20Sopenharmony_ci};
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_cistatic const __u8 qtable_kodak_ez200[2][64] = {
2618c2ecf20Sopenharmony_ci	{				/* Q-table Y-components */
2628c2ecf20Sopenharmony_ci	 0x02, 0x01, 0x01, 0x02, 0x02, 0x04, 0x05, 0x06,
2638c2ecf20Sopenharmony_ci	 0x01, 0x01, 0x01, 0x02, 0x03, 0x06, 0x06, 0x06,
2648c2ecf20Sopenharmony_ci	 0x01, 0x01, 0x02, 0x02, 0x04, 0x06, 0x07, 0x06,
2658c2ecf20Sopenharmony_ci	 0x01, 0x02, 0x02, 0x03, 0x05, 0x09, 0x08, 0x06,
2668c2ecf20Sopenharmony_ci	 0x02, 0x02, 0x04, 0x06, 0x07, 0x0b, 0x0a, 0x08,
2678c2ecf20Sopenharmony_ci	 0x02, 0x04, 0x06, 0x06, 0x08, 0x0a, 0x0b, 0x09,
2688c2ecf20Sopenharmony_ci	 0x05, 0x06, 0x08, 0x09, 0x0a, 0x0c, 0x0c, 0x0a,
2698c2ecf20Sopenharmony_ci	 0x07, 0x09, 0x0a, 0x0a, 0x0b, 0x0a, 0x0a, 0x0a},
2708c2ecf20Sopenharmony_ci	{				/* Q-table C-components */
2718c2ecf20Sopenharmony_ci	 0x02, 0x02, 0x02, 0x05, 0x0a, 0x0a, 0x0a, 0x0a,
2728c2ecf20Sopenharmony_ci	 0x02, 0x02, 0x03, 0x07, 0x0a, 0x0a, 0x0a, 0x0a,
2738c2ecf20Sopenharmony_ci	 0x02, 0x03, 0x06, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
2748c2ecf20Sopenharmony_ci	 0x05, 0x07, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
2758c2ecf20Sopenharmony_ci	 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
2768c2ecf20Sopenharmony_ci	 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
2778c2ecf20Sopenharmony_ci	 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
2788c2ecf20Sopenharmony_ci	 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a}
2798c2ecf20Sopenharmony_ci};
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_cistatic const __u8 qtable_pocketdv[2][64] = {
2828c2ecf20Sopenharmony_ci	{		/* Q-table Y-components start registers 0x8800 */
2838c2ecf20Sopenharmony_ci	 0x06, 0x04, 0x04, 0x06, 0x0a, 0x10, 0x14, 0x18,
2848c2ecf20Sopenharmony_ci	 0x05, 0x05, 0x06, 0x08, 0x0a, 0x17, 0x18, 0x16,
2858c2ecf20Sopenharmony_ci	 0x06, 0x05, 0x06, 0x0a, 0x10, 0x17, 0x1c, 0x16,
2868c2ecf20Sopenharmony_ci	 0x06, 0x07, 0x09, 0x0c, 0x14, 0x23, 0x20, 0x19,
2878c2ecf20Sopenharmony_ci	 0x07, 0x09, 0x0f, 0x16, 0x1b, 0x2c, 0x29, 0x1f,
2888c2ecf20Sopenharmony_ci	 0x0a, 0x0e, 0x16, 0x1a, 0x20, 0x2a, 0x2d, 0x25,
2898c2ecf20Sopenharmony_ci	 0x14, 0x1a, 0x1f, 0x23, 0x29, 0x30, 0x30, 0x28,
2908c2ecf20Sopenharmony_ci	 0x1d, 0x25, 0x26, 0x27, 0x2d, 0x28, 0x29, 0x28,
2918c2ecf20Sopenharmony_ci	 },
2928c2ecf20Sopenharmony_ci	{		/* Q-table C-components start registers 0x8840 */
2938c2ecf20Sopenharmony_ci	 0x07, 0x07, 0x0a, 0x13, 0x28, 0x28, 0x28, 0x28,
2948c2ecf20Sopenharmony_ci	 0x07, 0x08, 0x0a, 0x1a, 0x28, 0x28, 0x28, 0x28,
2958c2ecf20Sopenharmony_ci	 0x0a, 0x0a, 0x16, 0x28, 0x28, 0x28, 0x28, 0x28,
2968c2ecf20Sopenharmony_ci	 0x13, 0x1a, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
2978c2ecf20Sopenharmony_ci	 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
2988c2ecf20Sopenharmony_ci	 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
2998c2ecf20Sopenharmony_ci	 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
3008c2ecf20Sopenharmony_ci	 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28}
3018c2ecf20Sopenharmony_ci};
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci/* read 'len' bytes to gspca_dev->usb_buf */
3048c2ecf20Sopenharmony_cistatic void reg_r(struct gspca_dev *gspca_dev,
3058c2ecf20Sopenharmony_ci		  __u16 index,
3068c2ecf20Sopenharmony_ci		  __u16 length)
3078c2ecf20Sopenharmony_ci{
3088c2ecf20Sopenharmony_ci	usb_control_msg(gspca_dev->dev,
3098c2ecf20Sopenharmony_ci			usb_rcvctrlpipe(gspca_dev->dev, 0),
3108c2ecf20Sopenharmony_ci			0,
3118c2ecf20Sopenharmony_ci			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
3128c2ecf20Sopenharmony_ci			0,		/* value */
3138c2ecf20Sopenharmony_ci			index, gspca_dev->usb_buf, length, 500);
3148c2ecf20Sopenharmony_ci}
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_cistatic int reg_w(struct gspca_dev *gspca_dev,
3178c2ecf20Sopenharmony_ci		     __u16 req, __u16 index, __u16 value)
3188c2ecf20Sopenharmony_ci{
3198c2ecf20Sopenharmony_ci	int ret;
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	gspca_dbg(gspca_dev, D_USBO, "reg write: [0x%02x] = 0x%02x\n",
3228c2ecf20Sopenharmony_ci		  index, value);
3238c2ecf20Sopenharmony_ci	ret = usb_control_msg(gspca_dev->dev,
3248c2ecf20Sopenharmony_ci			usb_sndctrlpipe(gspca_dev->dev, 0),
3258c2ecf20Sopenharmony_ci			req,
3268c2ecf20Sopenharmony_ci			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
3278c2ecf20Sopenharmony_ci			value, index, NULL, 0, 500);
3288c2ecf20Sopenharmony_ci	if (ret < 0)
3298c2ecf20Sopenharmony_ci		pr_err("reg write: error %d\n", ret);
3308c2ecf20Sopenharmony_ci	return ret;
3318c2ecf20Sopenharmony_ci}
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci/* returns: negative is error, pos or zero is data */
3348c2ecf20Sopenharmony_cistatic int reg_r_12(struct gspca_dev *gspca_dev,
3358c2ecf20Sopenharmony_ci			__u16 req,	/* bRequest */
3368c2ecf20Sopenharmony_ci			__u16 index,	/* wIndex */
3378c2ecf20Sopenharmony_ci			__u16 length)	/* wLength (1 or 2 only) */
3388c2ecf20Sopenharmony_ci{
3398c2ecf20Sopenharmony_ci	int ret;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	gspca_dev->usb_buf[1] = 0;
3428c2ecf20Sopenharmony_ci	ret = usb_control_msg(gspca_dev->dev,
3438c2ecf20Sopenharmony_ci			usb_rcvctrlpipe(gspca_dev->dev, 0),
3448c2ecf20Sopenharmony_ci			req,
3458c2ecf20Sopenharmony_ci			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
3468c2ecf20Sopenharmony_ci			0,		/* value */
3478c2ecf20Sopenharmony_ci			index,
3488c2ecf20Sopenharmony_ci			gspca_dev->usb_buf, length,
3498c2ecf20Sopenharmony_ci			500);		/* timeout */
3508c2ecf20Sopenharmony_ci	if (ret < 0) {
3518c2ecf20Sopenharmony_ci		pr_err("reg_r_12 err %d\n", ret);
3528c2ecf20Sopenharmony_ci		return ret;
3538c2ecf20Sopenharmony_ci	}
3548c2ecf20Sopenharmony_ci	return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0];
3558c2ecf20Sopenharmony_ci}
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci/*
3588c2ecf20Sopenharmony_ci * Simple function to wait for a given 8-bit value to be returned from
3598c2ecf20Sopenharmony_ci * a reg_read call.
3608c2ecf20Sopenharmony_ci * Returns: negative is error or timeout, zero is success.
3618c2ecf20Sopenharmony_ci */
3628c2ecf20Sopenharmony_cistatic int reg_r_wait(struct gspca_dev *gspca_dev,
3638c2ecf20Sopenharmony_ci			__u16 reg, __u16 index, __u16 value)
3648c2ecf20Sopenharmony_ci{
3658c2ecf20Sopenharmony_ci	int ret, cnt = 20;
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	while (--cnt > 0) {
3688c2ecf20Sopenharmony_ci		ret = reg_r_12(gspca_dev, reg, index, 1);
3698c2ecf20Sopenharmony_ci		if (ret == value)
3708c2ecf20Sopenharmony_ci			return 0;
3718c2ecf20Sopenharmony_ci		msleep(50);
3728c2ecf20Sopenharmony_ci	}
3738c2ecf20Sopenharmony_ci	return -EIO;
3748c2ecf20Sopenharmony_ci}
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_cistatic int write_vector(struct gspca_dev *gspca_dev,
3778c2ecf20Sopenharmony_ci			const __u16 data[][3])
3788c2ecf20Sopenharmony_ci{
3798c2ecf20Sopenharmony_ci	int ret, i = 0;
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) {
3828c2ecf20Sopenharmony_ci		ret = reg_w(gspca_dev, data[i][0], data[i][2], data[i][1]);
3838c2ecf20Sopenharmony_ci		if (ret < 0)
3848c2ecf20Sopenharmony_ci			return ret;
3858c2ecf20Sopenharmony_ci		i++;
3868c2ecf20Sopenharmony_ci	}
3878c2ecf20Sopenharmony_ci	return 0;
3888c2ecf20Sopenharmony_ci}
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_cistatic int spca50x_setup_qtable(struct gspca_dev *gspca_dev,
3918c2ecf20Sopenharmony_ci				unsigned int request,
3928c2ecf20Sopenharmony_ci				unsigned int ybase,
3938c2ecf20Sopenharmony_ci				unsigned int cbase,
3948c2ecf20Sopenharmony_ci				const __u8 qtable[2][64])
3958c2ecf20Sopenharmony_ci{
3968c2ecf20Sopenharmony_ci	int i, err;
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	/* loop over y components */
3998c2ecf20Sopenharmony_ci	for (i = 0; i < 64; i++) {
4008c2ecf20Sopenharmony_ci		err = reg_w(gspca_dev, request, ybase + i, qtable[0][i]);
4018c2ecf20Sopenharmony_ci		if (err < 0)
4028c2ecf20Sopenharmony_ci			return err;
4038c2ecf20Sopenharmony_ci	}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	/* loop over c components */
4068c2ecf20Sopenharmony_ci	for (i = 0; i < 64; i++) {
4078c2ecf20Sopenharmony_ci		err = reg_w(gspca_dev, request, cbase + i, qtable[1][i]);
4088c2ecf20Sopenharmony_ci		if (err < 0)
4098c2ecf20Sopenharmony_ci			return err;
4108c2ecf20Sopenharmony_ci	}
4118c2ecf20Sopenharmony_ci	return 0;
4128c2ecf20Sopenharmony_ci}
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_cistatic void spca500_ping310(struct gspca_dev *gspca_dev)
4158c2ecf20Sopenharmony_ci{
4168c2ecf20Sopenharmony_ci	reg_r(gspca_dev, 0x0d04, 2);
4178c2ecf20Sopenharmony_ci	gspca_dbg(gspca_dev, D_STREAM, "ClickSmart310 ping 0x0d04 0x%02x 0x%02x\n",
4188c2ecf20Sopenharmony_ci		  gspca_dev->usb_buf[0], gspca_dev->usb_buf[1]);
4198c2ecf20Sopenharmony_ci}
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_cistatic void spca500_clksmart310_init(struct gspca_dev *gspca_dev)
4228c2ecf20Sopenharmony_ci{
4238c2ecf20Sopenharmony_ci	reg_r(gspca_dev, 0x0d05, 2);
4248c2ecf20Sopenharmony_ci	gspca_dbg(gspca_dev, D_STREAM, "ClickSmart310 init 0x0d05 0x%02x 0x%02x\n",
4258c2ecf20Sopenharmony_ci		  gspca_dev->usb_buf[0], gspca_dev->usb_buf[1]);
4268c2ecf20Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x8167, 0x5a);
4278c2ecf20Sopenharmony_ci	spca500_ping310(gspca_dev);
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x8168, 0x22);
4308c2ecf20Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x816a, 0xc0);
4318c2ecf20Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x816b, 0x0b);
4328c2ecf20Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x8169, 0x25);
4338c2ecf20Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x8157, 0x5b);
4348c2ecf20Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x8158, 0x5b);
4358c2ecf20Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x813f, 0x03);
4368c2ecf20Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x8151, 0x4a);
4378c2ecf20Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x8153, 0x78);
4388c2ecf20Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x0d01, 0x04);
4398c2ecf20Sopenharmony_ci						/* 00 for adjust shutter */
4408c2ecf20Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x0d02, 0x01);
4418c2ecf20Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x8169, 0x25);
4428c2ecf20Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x0d01, 0x02);
4438c2ecf20Sopenharmony_ci}
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_cistatic void spca500_setmode(struct gspca_dev *gspca_dev,
4468c2ecf20Sopenharmony_ci			__u8 xmult, __u8 ymult)
4478c2ecf20Sopenharmony_ci{
4488c2ecf20Sopenharmony_ci	int mode;
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	/* set x multiplier */
4518c2ecf20Sopenharmony_ci	reg_w(gspca_dev, 0, 0x8001, xmult);
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	/* set y multiplier */
4548c2ecf20Sopenharmony_ci	reg_w(gspca_dev, 0, 0x8002, ymult);
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	/* use compressed mode, VGA, with mode specific subsample */
4578c2ecf20Sopenharmony_ci	mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
4588c2ecf20Sopenharmony_ci	reg_w(gspca_dev, 0, 0x8003, mode << 4);
4598c2ecf20Sopenharmony_ci}
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_cistatic int spca500_full_reset(struct gspca_dev *gspca_dev)
4628c2ecf20Sopenharmony_ci{
4638c2ecf20Sopenharmony_ci	int err;
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	/* send the reset command */
4668c2ecf20Sopenharmony_ci	err = reg_w(gspca_dev, 0xe0, 0x0001, 0x0000);
4678c2ecf20Sopenharmony_ci	if (err < 0)
4688c2ecf20Sopenharmony_ci		return err;
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	/* wait for the reset to complete */
4718c2ecf20Sopenharmony_ci	err = reg_r_wait(gspca_dev, 0x06, 0x0000, 0x0000);
4728c2ecf20Sopenharmony_ci	if (err < 0)
4738c2ecf20Sopenharmony_ci		return err;
4748c2ecf20Sopenharmony_ci	err = reg_w(gspca_dev, 0xe0, 0x0000, 0x0000);
4758c2ecf20Sopenharmony_ci	if (err < 0)
4768c2ecf20Sopenharmony_ci		return err;
4778c2ecf20Sopenharmony_ci	err = reg_r_wait(gspca_dev, 0x06, 0, 0);
4788c2ecf20Sopenharmony_ci	if (err < 0) {
4798c2ecf20Sopenharmony_ci		gspca_err(gspca_dev, "reg_r_wait() failed\n");
4808c2ecf20Sopenharmony_ci		return err;
4818c2ecf20Sopenharmony_ci	}
4828c2ecf20Sopenharmony_ci	/* all ok */
4838c2ecf20Sopenharmony_ci	return 0;
4848c2ecf20Sopenharmony_ci}
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci/* Synchro the Bridge with sensor */
4878c2ecf20Sopenharmony_ci/* Maybe that will work on all spca500 chip */
4888c2ecf20Sopenharmony_ci/* because i only own a clicksmart310 try for that chip */
4898c2ecf20Sopenharmony_ci/* using spca50x_set_packet_size() cause an Ooops here */
4908c2ecf20Sopenharmony_ci/* usb_set_interface from kernel 2.6.x clear all the urb stuff */
4918c2ecf20Sopenharmony_ci/* up-port the same feature as in 2.4.x kernel */
4928c2ecf20Sopenharmony_cistatic int spca500_synch310(struct gspca_dev *gspca_dev)
4938c2ecf20Sopenharmony_ci{
4948c2ecf20Sopenharmony_ci	if (usb_set_interface(gspca_dev->dev, gspca_dev->iface, 0) < 0) {
4958c2ecf20Sopenharmony_ci		gspca_err(gspca_dev, "Set packet size: set interface error\n");
4968c2ecf20Sopenharmony_ci		goto error;
4978c2ecf20Sopenharmony_ci	}
4988c2ecf20Sopenharmony_ci	spca500_ping310(gspca_dev);
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	reg_r(gspca_dev, 0x0d00, 1);
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	/* need alt setting here */
5038c2ecf20Sopenharmony_ci	gspca_dbg(gspca_dev, D_PACK, "ClickSmart310 sync alt: %d\n",
5048c2ecf20Sopenharmony_ci		  gspca_dev->alt);
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	/* Windoze use pipe with altsetting 6 why 7 here */
5078c2ecf20Sopenharmony_ci	if (usb_set_interface(gspca_dev->dev,
5088c2ecf20Sopenharmony_ci				gspca_dev->iface,
5098c2ecf20Sopenharmony_ci				gspca_dev->alt) < 0) {
5108c2ecf20Sopenharmony_ci		gspca_err(gspca_dev, "Set packet size: set interface error\n");
5118c2ecf20Sopenharmony_ci		goto error;
5128c2ecf20Sopenharmony_ci	}
5138c2ecf20Sopenharmony_ci	return 0;
5148c2ecf20Sopenharmony_cierror:
5158c2ecf20Sopenharmony_ci	return -EBUSY;
5168c2ecf20Sopenharmony_ci}
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_cistatic void spca500_reinit(struct gspca_dev *gspca_dev)
5198c2ecf20Sopenharmony_ci{
5208c2ecf20Sopenharmony_ci	int err;
5218c2ecf20Sopenharmony_ci	__u8 Data;
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	/* some unknown command from Aiptek pocket dv and family300 */
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x0d01, 0x01);
5268c2ecf20Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x0d03, 0x00);
5278c2ecf20Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x0d02, 0x01);
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	/* enable drop packet */
5308c2ecf20Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x850a, 0x0001);
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	err = spca50x_setup_qtable(gspca_dev, 0x00, 0x8800, 0x8840,
5338c2ecf20Sopenharmony_ci				 qtable_pocketdv);
5348c2ecf20Sopenharmony_ci	if (err < 0)
5358c2ecf20Sopenharmony_ci		gspca_err(gspca_dev, "spca50x_setup_qtable failed on init\n");
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	/* set qtable index */
5388c2ecf20Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x8880, 2);
5398c2ecf20Sopenharmony_ci	/* family cam Quicksmart stuff */
5408c2ecf20Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x800a, 0x00);
5418c2ecf20Sopenharmony_ci	/* Set agc transfer: synced between frames */
5428c2ecf20Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x820f, 0x01);
5438c2ecf20Sopenharmony_ci	/* Init SDRAM - needed for SDRAM access */
5448c2ecf20Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x870a, 0x04);
5458c2ecf20Sopenharmony_ci	/*Start init sequence or stream */
5468c2ecf20Sopenharmony_ci	reg_w(gspca_dev, 0, 0x8003, 0x00);
5478c2ecf20Sopenharmony_ci	/* switch to video camera mode */
5488c2ecf20Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x8000, 0x0004);
5498c2ecf20Sopenharmony_ci	msleep(2000);
5508c2ecf20Sopenharmony_ci	if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0) {
5518c2ecf20Sopenharmony_ci		reg_r(gspca_dev, 0x816b, 1);
5528c2ecf20Sopenharmony_ci		Data = gspca_dev->usb_buf[0];
5538c2ecf20Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x816b, Data);
5548c2ecf20Sopenharmony_ci	}
5558c2ecf20Sopenharmony_ci}
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci/* this function is called at probe time */
5588c2ecf20Sopenharmony_cistatic int sd_config(struct gspca_dev *gspca_dev,
5598c2ecf20Sopenharmony_ci			const struct usb_device_id *id)
5608c2ecf20Sopenharmony_ci{
5618c2ecf20Sopenharmony_ci	struct sd *sd = (struct sd *) gspca_dev;
5628c2ecf20Sopenharmony_ci	struct cam *cam;
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci	cam = &gspca_dev->cam;
5658c2ecf20Sopenharmony_ci	sd->subtype = id->driver_info;
5668c2ecf20Sopenharmony_ci	if (sd->subtype != LogitechClickSmart310) {
5678c2ecf20Sopenharmony_ci		cam->cam_mode = vga_mode;
5688c2ecf20Sopenharmony_ci		cam->nmodes = ARRAY_SIZE(vga_mode);
5698c2ecf20Sopenharmony_ci	} else {
5708c2ecf20Sopenharmony_ci		cam->cam_mode = sif_mode;
5718c2ecf20Sopenharmony_ci		cam->nmodes = ARRAY_SIZE(sif_mode);
5728c2ecf20Sopenharmony_ci	}
5738c2ecf20Sopenharmony_ci	return 0;
5748c2ecf20Sopenharmony_ci}
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci/* this function is called at probe and resume time */
5778c2ecf20Sopenharmony_cistatic int sd_init(struct gspca_dev *gspca_dev)
5788c2ecf20Sopenharmony_ci{
5798c2ecf20Sopenharmony_ci	struct sd *sd = (struct sd *) gspca_dev;
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	/* initialisation of spca500 based cameras is deferred */
5828c2ecf20Sopenharmony_ci	gspca_dbg(gspca_dev, D_STREAM, "SPCA500 init\n");
5838c2ecf20Sopenharmony_ci	if (sd->subtype == LogitechClickSmart310)
5848c2ecf20Sopenharmony_ci		spca500_clksmart310_init(gspca_dev);
5858c2ecf20Sopenharmony_ci/*	else
5868c2ecf20Sopenharmony_ci		spca500_initialise(gspca_dev); */
5878c2ecf20Sopenharmony_ci	gspca_dbg(gspca_dev, D_STREAM, "SPCA500 init done\n");
5888c2ecf20Sopenharmony_ci	return 0;
5898c2ecf20Sopenharmony_ci}
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_cistatic int sd_start(struct gspca_dev *gspca_dev)
5928c2ecf20Sopenharmony_ci{
5938c2ecf20Sopenharmony_ci	struct sd *sd = (struct sd *) gspca_dev;
5948c2ecf20Sopenharmony_ci	int err;
5958c2ecf20Sopenharmony_ci	__u8 Data;
5968c2ecf20Sopenharmony_ci	__u8 xmult, ymult;
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci	/* create the JPEG header */
5998c2ecf20Sopenharmony_ci	jpeg_define(sd->jpeg_hdr, gspca_dev->pixfmt.height,
6008c2ecf20Sopenharmony_ci			gspca_dev->pixfmt.width,
6018c2ecf20Sopenharmony_ci			0x22);		/* JPEG 411 */
6028c2ecf20Sopenharmony_ci	jpeg_set_qual(sd->jpeg_hdr, QUALITY);
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci	if (sd->subtype == LogitechClickSmart310) {
6058c2ecf20Sopenharmony_ci		xmult = 0x16;
6068c2ecf20Sopenharmony_ci		ymult = 0x12;
6078c2ecf20Sopenharmony_ci	} else {
6088c2ecf20Sopenharmony_ci		xmult = 0x28;
6098c2ecf20Sopenharmony_ci		ymult = 0x1e;
6108c2ecf20Sopenharmony_ci	}
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	/* is there a sensor here ? */
6138c2ecf20Sopenharmony_ci	reg_r(gspca_dev, 0x8a04, 1);
6148c2ecf20Sopenharmony_ci	gspca_dbg(gspca_dev, D_STREAM, "Spca500 Sensor Address 0x%02x\n",
6158c2ecf20Sopenharmony_ci		  gspca_dev->usb_buf[0]);
6168c2ecf20Sopenharmony_ci	gspca_dbg(gspca_dev, D_STREAM, "Spca500 curr_mode: %d Xmult: 0x%02x, Ymult: 0x%02x",
6178c2ecf20Sopenharmony_ci		  gspca_dev->curr_mode, xmult, ymult);
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	/* setup qtable */
6208c2ecf20Sopenharmony_ci	switch (sd->subtype) {
6218c2ecf20Sopenharmony_ci	case LogitechClickSmart310:
6228c2ecf20Sopenharmony_ci		 spca500_setmode(gspca_dev, xmult, ymult);
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci		/* enable drop packet */
6258c2ecf20Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x850a, 0x0001);
6268c2ecf20Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x8880, 3);
6278c2ecf20Sopenharmony_ci		err = spca50x_setup_qtable(gspca_dev,
6288c2ecf20Sopenharmony_ci					   0x00, 0x8800, 0x8840,
6298c2ecf20Sopenharmony_ci					   qtable_creative_pccam);
6308c2ecf20Sopenharmony_ci		if (err < 0)
6318c2ecf20Sopenharmony_ci			gspca_err(gspca_dev, "spca50x_setup_qtable failed\n");
6328c2ecf20Sopenharmony_ci		/* Init SDRAM - needed for SDRAM access */
6338c2ecf20Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x870a, 0x04);
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci		/* switch to video camera mode */
6368c2ecf20Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x8000, 0x0004);
6378c2ecf20Sopenharmony_ci		msleep(500);
6388c2ecf20Sopenharmony_ci		if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0)
6398c2ecf20Sopenharmony_ci			gspca_err(gspca_dev, "reg_r_wait() failed\n");
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci		reg_r(gspca_dev, 0x816b, 1);
6428c2ecf20Sopenharmony_ci		Data = gspca_dev->usb_buf[0];
6438c2ecf20Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x816b, Data);
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci		spca500_synch310(gspca_dev);
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci		write_vector(gspca_dev, spca500_visual_defaults);
6488c2ecf20Sopenharmony_ci		spca500_setmode(gspca_dev, xmult, ymult);
6498c2ecf20Sopenharmony_ci		/* enable drop packet */
6508c2ecf20Sopenharmony_ci		err = reg_w(gspca_dev, 0x00, 0x850a, 0x0001);
6518c2ecf20Sopenharmony_ci		if (err < 0)
6528c2ecf20Sopenharmony_ci			gspca_err(gspca_dev, "failed to enable drop packet\n");
6538c2ecf20Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x8880, 3);
6548c2ecf20Sopenharmony_ci		err = spca50x_setup_qtable(gspca_dev,
6558c2ecf20Sopenharmony_ci					   0x00, 0x8800, 0x8840,
6568c2ecf20Sopenharmony_ci					   qtable_creative_pccam);
6578c2ecf20Sopenharmony_ci		if (err < 0)
6588c2ecf20Sopenharmony_ci			gspca_err(gspca_dev, "spca50x_setup_qtable failed\n");
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci		/* Init SDRAM - needed for SDRAM access */
6618c2ecf20Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x870a, 0x04);
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci		/* switch to video camera mode */
6648c2ecf20Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x8000, 0x0004);
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci		if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0)
6678c2ecf20Sopenharmony_ci			gspca_err(gspca_dev, "reg_r_wait() failed\n");
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci		reg_r(gspca_dev, 0x816b, 1);
6708c2ecf20Sopenharmony_ci		Data = gspca_dev->usb_buf[0];
6718c2ecf20Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x816b, Data);
6728c2ecf20Sopenharmony_ci		break;
6738c2ecf20Sopenharmony_ci	case CreativePCCam300:		/* Creative PC-CAM 300 640x480 CCD */
6748c2ecf20Sopenharmony_ci	case IntelPocketPCCamera:	/* FIXME: Temporary fix for
6758c2ecf20Sopenharmony_ci					 *	Intel Pocket PC Camera
6768c2ecf20Sopenharmony_ci					 *	- NWG (Sat 29th March 2003) */
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci		/* do a full reset */
6798c2ecf20Sopenharmony_ci		err = spca500_full_reset(gspca_dev);
6808c2ecf20Sopenharmony_ci		if (err < 0)
6818c2ecf20Sopenharmony_ci			gspca_err(gspca_dev, "spca500_full_reset failed\n");
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_ci		/* enable drop packet */
6848c2ecf20Sopenharmony_ci		err = reg_w(gspca_dev, 0x00, 0x850a, 0x0001);
6858c2ecf20Sopenharmony_ci		if (err < 0)
6868c2ecf20Sopenharmony_ci			gspca_err(gspca_dev, "failed to enable drop packet\n");
6878c2ecf20Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x8880, 3);
6888c2ecf20Sopenharmony_ci		err = spca50x_setup_qtable(gspca_dev,
6898c2ecf20Sopenharmony_ci					   0x00, 0x8800, 0x8840,
6908c2ecf20Sopenharmony_ci					   qtable_creative_pccam);
6918c2ecf20Sopenharmony_ci		if (err < 0)
6928c2ecf20Sopenharmony_ci			gspca_err(gspca_dev, "spca50x_setup_qtable failed\n");
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci		spca500_setmode(gspca_dev, xmult, ymult);
6958c2ecf20Sopenharmony_ci		reg_w(gspca_dev, 0x20, 0x0001, 0x0004);
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci		/* switch to video camera mode */
6988c2ecf20Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x8000, 0x0004);
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci		if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0)
7018c2ecf20Sopenharmony_ci			gspca_err(gspca_dev, "reg_r_wait() failed\n");
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci		reg_r(gspca_dev, 0x816b, 1);
7048c2ecf20Sopenharmony_ci		Data = gspca_dev->usb_buf[0];
7058c2ecf20Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x816b, Data);
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci/*		write_vector(gspca_dev, spca500_visual_defaults); */
7088c2ecf20Sopenharmony_ci		break;
7098c2ecf20Sopenharmony_ci	case KodakEZ200:		/* Kodak EZ200 */
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci		/* do a full reset */
7128c2ecf20Sopenharmony_ci		err = spca500_full_reset(gspca_dev);
7138c2ecf20Sopenharmony_ci		if (err < 0)
7148c2ecf20Sopenharmony_ci			gspca_err(gspca_dev, "spca500_full_reset failed\n");
7158c2ecf20Sopenharmony_ci		/* enable drop packet */
7168c2ecf20Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x850a, 0x0001);
7178c2ecf20Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x8880, 0);
7188c2ecf20Sopenharmony_ci		err = spca50x_setup_qtable(gspca_dev,
7198c2ecf20Sopenharmony_ci					   0x00, 0x8800, 0x8840,
7208c2ecf20Sopenharmony_ci					   qtable_kodak_ez200);
7218c2ecf20Sopenharmony_ci		if (err < 0)
7228c2ecf20Sopenharmony_ci			gspca_err(gspca_dev, "spca50x_setup_qtable failed\n");
7238c2ecf20Sopenharmony_ci		spca500_setmode(gspca_dev, xmult, ymult);
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci		reg_w(gspca_dev, 0x20, 0x0001, 0x0004);
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci		/* switch to video camera mode */
7288c2ecf20Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x8000, 0x0004);
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci		if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0)
7318c2ecf20Sopenharmony_ci			gspca_err(gspca_dev, "reg_r_wait() failed\n");
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci		reg_r(gspca_dev, 0x816b, 1);
7348c2ecf20Sopenharmony_ci		Data = gspca_dev->usb_buf[0];
7358c2ecf20Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x816b, Data);
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_ci/*		write_vector(gspca_dev, spca500_visual_defaults); */
7388c2ecf20Sopenharmony_ci		break;
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	case BenqDC1016:
7418c2ecf20Sopenharmony_ci	case DLinkDSC350:		/* FamilyCam 300 */
7428c2ecf20Sopenharmony_ci	case AiptekPocketDV:		/* Aiptek PocketDV */
7438c2ecf20Sopenharmony_ci	case Gsmartmini:		/*Mustek Gsmart Mini */
7448c2ecf20Sopenharmony_ci	case MustekGsmart300:		/* Mustek Gsmart 300 */
7458c2ecf20Sopenharmony_ci	case PalmPixDC85:
7468c2ecf20Sopenharmony_ci	case Optimedia:
7478c2ecf20Sopenharmony_ci	case ToptroIndus:
7488c2ecf20Sopenharmony_ci	case AgfaCl20:
7498c2ecf20Sopenharmony_ci		spca500_reinit(gspca_dev);
7508c2ecf20Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x0d01, 0x01);
7518c2ecf20Sopenharmony_ci		/* enable drop packet */
7528c2ecf20Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x850a, 0x0001);
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci		err = spca50x_setup_qtable(gspca_dev,
7558c2ecf20Sopenharmony_ci				   0x00, 0x8800, 0x8840, qtable_pocketdv);
7568c2ecf20Sopenharmony_ci		if (err < 0)
7578c2ecf20Sopenharmony_ci			gspca_err(gspca_dev, "spca50x_setup_qtable failed\n");
7588c2ecf20Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x8880, 2);
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci		/* familycam Quicksmart pocketDV stuff */
7618c2ecf20Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x800a, 0x00);
7628c2ecf20Sopenharmony_ci		/* Set agc transfer: synced between frames */
7638c2ecf20Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x820f, 0x01);
7648c2ecf20Sopenharmony_ci		/* Init SDRAM - needed for SDRAM access */
7658c2ecf20Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x870a, 0x04);
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci		spca500_setmode(gspca_dev, xmult, ymult);
7688c2ecf20Sopenharmony_ci		/* switch to video camera mode */
7698c2ecf20Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x8000, 0x0004);
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci		reg_r_wait(gspca_dev, 0, 0x8000, 0x44);
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_ci		reg_r(gspca_dev, 0x816b, 1);
7748c2ecf20Sopenharmony_ci		Data = gspca_dev->usb_buf[0];
7758c2ecf20Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x816b, Data);
7768c2ecf20Sopenharmony_ci		break;
7778c2ecf20Sopenharmony_ci	case LogitechTraveler:
7788c2ecf20Sopenharmony_ci	case LogitechClickSmart510:
7798c2ecf20Sopenharmony_ci		reg_w(gspca_dev, 0x02, 0x00, 0x00);
7808c2ecf20Sopenharmony_ci		/* enable drop packet */
7818c2ecf20Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x850a, 0x0001);
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_ci		err = spca50x_setup_qtable(gspca_dev,
7848c2ecf20Sopenharmony_ci					0x00, 0x8800,
7858c2ecf20Sopenharmony_ci					0x8840, qtable_creative_pccam);
7868c2ecf20Sopenharmony_ci		if (err < 0)
7878c2ecf20Sopenharmony_ci			gspca_err(gspca_dev, "spca50x_setup_qtable failed\n");
7888c2ecf20Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x8880, 3);
7898c2ecf20Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x800a, 0x00);
7908c2ecf20Sopenharmony_ci		/* Init SDRAM - needed for SDRAM access */
7918c2ecf20Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x870a, 0x04);
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci		spca500_setmode(gspca_dev, xmult, ymult);
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci		/* switch to video camera mode */
7968c2ecf20Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x8000, 0x0004);
7978c2ecf20Sopenharmony_ci		reg_r_wait(gspca_dev, 0, 0x8000, 0x44);
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci		reg_r(gspca_dev, 0x816b, 1);
8008c2ecf20Sopenharmony_ci		Data = gspca_dev->usb_buf[0];
8018c2ecf20Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x816b, Data);
8028c2ecf20Sopenharmony_ci		write_vector(gspca_dev, Clicksmart510_defaults);
8038c2ecf20Sopenharmony_ci		break;
8048c2ecf20Sopenharmony_ci	}
8058c2ecf20Sopenharmony_ci	return 0;
8068c2ecf20Sopenharmony_ci}
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_cistatic void sd_stopN(struct gspca_dev *gspca_dev)
8098c2ecf20Sopenharmony_ci{
8108c2ecf20Sopenharmony_ci	reg_w(gspca_dev, 0, 0x8003, 0x00);
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci	/* switch to video camera mode */
8138c2ecf20Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x8000, 0x0004);
8148c2ecf20Sopenharmony_ci	reg_r(gspca_dev, 0x8000, 1);
8158c2ecf20Sopenharmony_ci	gspca_dbg(gspca_dev, D_STREAM, "stop SPCA500 done reg8000: 0x%2x\n",
8168c2ecf20Sopenharmony_ci		  gspca_dev->usb_buf[0]);
8178c2ecf20Sopenharmony_ci}
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_cistatic void sd_pkt_scan(struct gspca_dev *gspca_dev,
8208c2ecf20Sopenharmony_ci			u8 *data,			/* isoc packet */
8218c2ecf20Sopenharmony_ci			int len)			/* iso packet length */
8228c2ecf20Sopenharmony_ci{
8238c2ecf20Sopenharmony_ci	struct sd *sd = (struct sd *) gspca_dev;
8248c2ecf20Sopenharmony_ci	int i;
8258c2ecf20Sopenharmony_ci	static __u8 ffd9[] = {0xff, 0xd9};
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci/* frames are jpeg 4.1.1 without 0xff escape */
8288c2ecf20Sopenharmony_ci	if (data[0] == 0xff) {
8298c2ecf20Sopenharmony_ci		if (data[1] != 0x01) {	/* drop packet */
8308c2ecf20Sopenharmony_ci/*			gspca_dev->last_packet_type = DISCARD_PACKET; */
8318c2ecf20Sopenharmony_ci			return;
8328c2ecf20Sopenharmony_ci		}
8338c2ecf20Sopenharmony_ci		gspca_frame_add(gspca_dev, LAST_PACKET,
8348c2ecf20Sopenharmony_ci					ffd9, 2);
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_ci		/* put the JPEG header in the new frame */
8378c2ecf20Sopenharmony_ci		gspca_frame_add(gspca_dev, FIRST_PACKET,
8388c2ecf20Sopenharmony_ci			sd->jpeg_hdr, JPEG_HDR_SZ);
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci		data += SPCA500_OFFSET_DATA;
8418c2ecf20Sopenharmony_ci		len -= SPCA500_OFFSET_DATA;
8428c2ecf20Sopenharmony_ci	} else {
8438c2ecf20Sopenharmony_ci		data += 1;
8448c2ecf20Sopenharmony_ci		len -= 1;
8458c2ecf20Sopenharmony_ci	}
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci	/* add 0x00 after 0xff */
8488c2ecf20Sopenharmony_ci	i = 0;
8498c2ecf20Sopenharmony_ci	do {
8508c2ecf20Sopenharmony_ci		if (data[i] == 0xff) {
8518c2ecf20Sopenharmony_ci			gspca_frame_add(gspca_dev, INTER_PACKET,
8528c2ecf20Sopenharmony_ci					data, i + 1);
8538c2ecf20Sopenharmony_ci			len -= i;
8548c2ecf20Sopenharmony_ci			data += i;
8558c2ecf20Sopenharmony_ci			*data = 0x00;
8568c2ecf20Sopenharmony_ci			i = 0;
8578c2ecf20Sopenharmony_ci		}
8588c2ecf20Sopenharmony_ci		i++;
8598c2ecf20Sopenharmony_ci	} while (i < len);
8608c2ecf20Sopenharmony_ci	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
8618c2ecf20Sopenharmony_ci}
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_cistatic void setbrightness(struct gspca_dev *gspca_dev, s32 val)
8648c2ecf20Sopenharmony_ci{
8658c2ecf20Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x8167,
8668c2ecf20Sopenharmony_ci			(__u8) (val - 128));
8678c2ecf20Sopenharmony_ci}
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_cistatic void setcontrast(struct gspca_dev *gspca_dev, s32 val)
8708c2ecf20Sopenharmony_ci{
8718c2ecf20Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x8168, val);
8728c2ecf20Sopenharmony_ci}
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_cistatic void setcolors(struct gspca_dev *gspca_dev, s32 val)
8758c2ecf20Sopenharmony_ci{
8768c2ecf20Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x8169, val);
8778c2ecf20Sopenharmony_ci}
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_cistatic int sd_s_ctrl(struct v4l2_ctrl *ctrl)
8808c2ecf20Sopenharmony_ci{
8818c2ecf20Sopenharmony_ci	struct gspca_dev *gspca_dev =
8828c2ecf20Sopenharmony_ci		container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci	gspca_dev->usb_err = 0;
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_ci	if (!gspca_dev->streaming)
8878c2ecf20Sopenharmony_ci		return 0;
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci	switch (ctrl->id) {
8908c2ecf20Sopenharmony_ci	case V4L2_CID_BRIGHTNESS:
8918c2ecf20Sopenharmony_ci		setbrightness(gspca_dev, ctrl->val);
8928c2ecf20Sopenharmony_ci		break;
8938c2ecf20Sopenharmony_ci	case V4L2_CID_CONTRAST:
8948c2ecf20Sopenharmony_ci		setcontrast(gspca_dev, ctrl->val);
8958c2ecf20Sopenharmony_ci		break;
8968c2ecf20Sopenharmony_ci	case V4L2_CID_SATURATION:
8978c2ecf20Sopenharmony_ci		setcolors(gspca_dev, ctrl->val);
8988c2ecf20Sopenharmony_ci		break;
8998c2ecf20Sopenharmony_ci	}
9008c2ecf20Sopenharmony_ci	return gspca_dev->usb_err;
9018c2ecf20Sopenharmony_ci}
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_ops sd_ctrl_ops = {
9048c2ecf20Sopenharmony_ci	.s_ctrl = sd_s_ctrl,
9058c2ecf20Sopenharmony_ci};
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_cistatic int sd_init_controls(struct gspca_dev *gspca_dev)
9088c2ecf20Sopenharmony_ci{
9098c2ecf20Sopenharmony_ci	struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ci	gspca_dev->vdev.ctrl_handler = hdl;
9128c2ecf20Sopenharmony_ci	v4l2_ctrl_handler_init(hdl, 3);
9138c2ecf20Sopenharmony_ci	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
9148c2ecf20Sopenharmony_ci			V4L2_CID_BRIGHTNESS, 0, 255, 1, 127);
9158c2ecf20Sopenharmony_ci	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
9168c2ecf20Sopenharmony_ci			V4L2_CID_CONTRAST, 0, 63, 1, 31);
9178c2ecf20Sopenharmony_ci	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
9188c2ecf20Sopenharmony_ci			V4L2_CID_SATURATION, 0, 63, 1, 31);
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ci	if (hdl->error) {
9218c2ecf20Sopenharmony_ci		pr_err("Could not initialize controls\n");
9228c2ecf20Sopenharmony_ci		return hdl->error;
9238c2ecf20Sopenharmony_ci	}
9248c2ecf20Sopenharmony_ci	return 0;
9258c2ecf20Sopenharmony_ci}
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_ci/* sub-driver description */
9288c2ecf20Sopenharmony_cistatic const struct sd_desc sd_desc = {
9298c2ecf20Sopenharmony_ci	.name = MODULE_NAME,
9308c2ecf20Sopenharmony_ci	.config = sd_config,
9318c2ecf20Sopenharmony_ci	.init = sd_init,
9328c2ecf20Sopenharmony_ci	.init_controls = sd_init_controls,
9338c2ecf20Sopenharmony_ci	.start = sd_start,
9348c2ecf20Sopenharmony_ci	.stopN = sd_stopN,
9358c2ecf20Sopenharmony_ci	.pkt_scan = sd_pkt_scan,
9368c2ecf20Sopenharmony_ci};
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci/* -- module initialisation -- */
9398c2ecf20Sopenharmony_cistatic const struct usb_device_id device_table[] = {
9408c2ecf20Sopenharmony_ci	{USB_DEVICE(0x040a, 0x0300), .driver_info = KodakEZ200},
9418c2ecf20Sopenharmony_ci	{USB_DEVICE(0x041e, 0x400a), .driver_info = CreativePCCam300},
9428c2ecf20Sopenharmony_ci	{USB_DEVICE(0x046d, 0x0890), .driver_info = LogitechTraveler},
9438c2ecf20Sopenharmony_ci	{USB_DEVICE(0x046d, 0x0900), .driver_info = LogitechClickSmart310},
9448c2ecf20Sopenharmony_ci	{USB_DEVICE(0x046d, 0x0901), .driver_info = LogitechClickSmart510},
9458c2ecf20Sopenharmony_ci	{USB_DEVICE(0x04a5, 0x300c), .driver_info = BenqDC1016},
9468c2ecf20Sopenharmony_ci	{USB_DEVICE(0x04fc, 0x7333), .driver_info = PalmPixDC85},
9478c2ecf20Sopenharmony_ci	{USB_DEVICE(0x055f, 0xc200), .driver_info = MustekGsmart300},
9488c2ecf20Sopenharmony_ci	{USB_DEVICE(0x055f, 0xc220), .driver_info = Gsmartmini},
9498c2ecf20Sopenharmony_ci	{USB_DEVICE(0x06bd, 0x0404), .driver_info = AgfaCl20},
9508c2ecf20Sopenharmony_ci	{USB_DEVICE(0x06be, 0x0800), .driver_info = Optimedia},
9518c2ecf20Sopenharmony_ci	{USB_DEVICE(0x084d, 0x0003), .driver_info = DLinkDSC350},
9528c2ecf20Sopenharmony_ci	{USB_DEVICE(0x08ca, 0x0103), .driver_info = AiptekPocketDV},
9538c2ecf20Sopenharmony_ci	{USB_DEVICE(0x2899, 0x012c), .driver_info = ToptroIndus},
9548c2ecf20Sopenharmony_ci	{USB_DEVICE(0x8086, 0x0630), .driver_info = IntelPocketPCCamera},
9558c2ecf20Sopenharmony_ci	{}
9568c2ecf20Sopenharmony_ci};
9578c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(usb, device_table);
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_ci/* -- device connect -- */
9608c2ecf20Sopenharmony_cistatic int sd_probe(struct usb_interface *intf,
9618c2ecf20Sopenharmony_ci			const struct usb_device_id *id)
9628c2ecf20Sopenharmony_ci{
9638c2ecf20Sopenharmony_ci	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
9648c2ecf20Sopenharmony_ci				THIS_MODULE);
9658c2ecf20Sopenharmony_ci}
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_cistatic struct usb_driver sd_driver = {
9688c2ecf20Sopenharmony_ci	.name = MODULE_NAME,
9698c2ecf20Sopenharmony_ci	.id_table = device_table,
9708c2ecf20Sopenharmony_ci	.probe = sd_probe,
9718c2ecf20Sopenharmony_ci	.disconnect = gspca_disconnect,
9728c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
9738c2ecf20Sopenharmony_ci	.suspend = gspca_suspend,
9748c2ecf20Sopenharmony_ci	.resume = gspca_resume,
9758c2ecf20Sopenharmony_ci	.reset_resume = gspca_resume,
9768c2ecf20Sopenharmony_ci#endif
9778c2ecf20Sopenharmony_ci};
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_cimodule_usb_driver(sd_driver);
980