162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * SPCA500 chip based cameras initialization data
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#define MODULE_NAME "spca500"
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include "gspca.h"
1362306a36Sopenharmony_ci#include "jpeg.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ciMODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
1662306a36Sopenharmony_ciMODULE_DESCRIPTION("GSPCA/SPCA500 USB Camera Driver");
1762306a36Sopenharmony_ciMODULE_LICENSE("GPL");
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#define QUALITY 85
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci/* specific webcam descriptor */
2262306a36Sopenharmony_cistruct sd {
2362306a36Sopenharmony_ci	struct gspca_dev gspca_dev;		/* !! must be the first item */
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci	char subtype;
2662306a36Sopenharmony_ci#define AgfaCl20 0
2762306a36Sopenharmony_ci#define AiptekPocketDV 1
2862306a36Sopenharmony_ci#define BenqDC1016 2
2962306a36Sopenharmony_ci#define CreativePCCam300 3
3062306a36Sopenharmony_ci#define DLinkDSC350 4
3162306a36Sopenharmony_ci#define Gsmartmini 5
3262306a36Sopenharmony_ci#define IntelPocketPCCamera 6
3362306a36Sopenharmony_ci#define KodakEZ200 7
3462306a36Sopenharmony_ci#define LogitechClickSmart310 8
3562306a36Sopenharmony_ci#define LogitechClickSmart510 9
3662306a36Sopenharmony_ci#define LogitechTraveler 10
3762306a36Sopenharmony_ci#define MustekGsmart300 11
3862306a36Sopenharmony_ci#define Optimedia 12
3962306a36Sopenharmony_ci#define PalmPixDC85 13
4062306a36Sopenharmony_ci#define ToptroIndus 14
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	u8 jpeg_hdr[JPEG_HDR_SZ];
4362306a36Sopenharmony_ci};
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic const struct v4l2_pix_format vga_mode[] = {
4662306a36Sopenharmony_ci	{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
4762306a36Sopenharmony_ci		.bytesperline = 320,
4862306a36Sopenharmony_ci		.sizeimage = 320 * 240 * 3 / 8 + 590,
4962306a36Sopenharmony_ci		.colorspace = V4L2_COLORSPACE_JPEG,
5062306a36Sopenharmony_ci		.priv = 1},
5162306a36Sopenharmony_ci	{640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
5262306a36Sopenharmony_ci		.bytesperline = 640,
5362306a36Sopenharmony_ci		.sizeimage = 640 * 480 * 3 / 8 + 590,
5462306a36Sopenharmony_ci		.colorspace = V4L2_COLORSPACE_JPEG,
5562306a36Sopenharmony_ci		.priv = 0},
5662306a36Sopenharmony_ci};
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistatic const struct v4l2_pix_format sif_mode[] = {
5962306a36Sopenharmony_ci	{176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
6062306a36Sopenharmony_ci		.bytesperline = 176,
6162306a36Sopenharmony_ci		.sizeimage = 176 * 144 * 3 / 8 + 590,
6262306a36Sopenharmony_ci		.colorspace = V4L2_COLORSPACE_JPEG,
6362306a36Sopenharmony_ci		.priv = 1},
6462306a36Sopenharmony_ci	{352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
6562306a36Sopenharmony_ci		.bytesperline = 352,
6662306a36Sopenharmony_ci		.sizeimage = 352 * 288 * 3 / 8 + 590,
6762306a36Sopenharmony_ci		.colorspace = V4L2_COLORSPACE_JPEG,
6862306a36Sopenharmony_ci		.priv = 0},
6962306a36Sopenharmony_ci};
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci/* Frame packet header offsets for the spca500 */
7262306a36Sopenharmony_ci#define SPCA500_OFFSET_PADDINGLB 2
7362306a36Sopenharmony_ci#define SPCA500_OFFSET_PADDINGHB 3
7462306a36Sopenharmony_ci#define SPCA500_OFFSET_MODE      4
7562306a36Sopenharmony_ci#define SPCA500_OFFSET_IMGWIDTH  5
7662306a36Sopenharmony_ci#define SPCA500_OFFSET_IMGHEIGHT 6
7762306a36Sopenharmony_ci#define SPCA500_OFFSET_IMGMODE   7
7862306a36Sopenharmony_ci#define SPCA500_OFFSET_QTBLINDEX 8
7962306a36Sopenharmony_ci#define SPCA500_OFFSET_FRAMSEQ   9
8062306a36Sopenharmony_ci#define SPCA500_OFFSET_CDSPINFO  10
8162306a36Sopenharmony_ci#define SPCA500_OFFSET_GPIO      11
8262306a36Sopenharmony_ci#define SPCA500_OFFSET_AUGPIO    12
8362306a36Sopenharmony_ci#define SPCA500_OFFSET_DATA      16
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_cistatic const __u16 spca500_visual_defaults[][3] = {
8762306a36Sopenharmony_ci	{0x00, 0x0003, 0x816b},	/* SSI not active sync with vsync,
8862306a36Sopenharmony_ci				 * hue (H byte) = 0,
8962306a36Sopenharmony_ci				 * saturation/hue enable,
9062306a36Sopenharmony_ci				 * brightness/contrast enable.
9162306a36Sopenharmony_ci				 */
9262306a36Sopenharmony_ci	{0x00, 0x0000, 0x8167},	/* brightness = 0 */
9362306a36Sopenharmony_ci	{0x00, 0x0020, 0x8168},	/* contrast = 0 */
9462306a36Sopenharmony_ci	{0x00, 0x0003, 0x816b},	/* SSI not active sync with vsync,
9562306a36Sopenharmony_ci				 * hue (H byte) = 0, saturation/hue enable,
9662306a36Sopenharmony_ci				 * brightness/contrast enable.
9762306a36Sopenharmony_ci				 * was 0x0003, now 0x0000.
9862306a36Sopenharmony_ci				 */
9962306a36Sopenharmony_ci	{0x00, 0x0000, 0x816a},	/* hue (L byte) = 0 */
10062306a36Sopenharmony_ci	{0x00, 0x0020, 0x8169},	/* saturation = 0x20 */
10162306a36Sopenharmony_ci	{0x00, 0x0050, 0x8157},	/* edge gain high threshold */
10262306a36Sopenharmony_ci	{0x00, 0x0030, 0x8158},	/* edge gain low threshold */
10362306a36Sopenharmony_ci	{0x00, 0x0028, 0x8159},	/* edge bandwidth high threshold */
10462306a36Sopenharmony_ci	{0x00, 0x000a, 0x815a},	/* edge bandwidth low threshold */
10562306a36Sopenharmony_ci	{0x00, 0x0001, 0x8202},	/* clock rate compensation = 1/25 sec/frame */
10662306a36Sopenharmony_ci	{0x0c, 0x0004, 0x0000},
10762306a36Sopenharmony_ci	/* set interface */
10862306a36Sopenharmony_ci	{}
10962306a36Sopenharmony_ci};
11062306a36Sopenharmony_cistatic const __u16 Clicksmart510_defaults[][3] = {
11162306a36Sopenharmony_ci	{0x00, 0x00, 0x8211},
11262306a36Sopenharmony_ci	{0x00, 0x01, 0x82c0},
11362306a36Sopenharmony_ci	{0x00, 0x10, 0x82cb},
11462306a36Sopenharmony_ci	{0x00, 0x0f, 0x800d},
11562306a36Sopenharmony_ci	{0x00, 0x82, 0x8225},
11662306a36Sopenharmony_ci	{0x00, 0x21, 0x8228},
11762306a36Sopenharmony_ci	{0x00, 0x00, 0x8203},
11862306a36Sopenharmony_ci	{0x00, 0x00, 0x8204},
11962306a36Sopenharmony_ci	{0x00, 0x08, 0x8205},
12062306a36Sopenharmony_ci	{0x00, 0xf8, 0x8206},
12162306a36Sopenharmony_ci	{0x00, 0x28, 0x8207},
12262306a36Sopenharmony_ci	{0x00, 0xa0, 0x8208},
12362306a36Sopenharmony_ci	{0x00, 0x08, 0x824a},
12462306a36Sopenharmony_ci	{0x00, 0x08, 0x8214},
12562306a36Sopenharmony_ci	{0x00, 0x80, 0x82c1},
12662306a36Sopenharmony_ci	{0x00, 0x00, 0x82c2},
12762306a36Sopenharmony_ci	{0x00, 0x00, 0x82ca},
12862306a36Sopenharmony_ci	{0x00, 0x80, 0x82c1},
12962306a36Sopenharmony_ci	{0x00, 0x04, 0x82c2},
13062306a36Sopenharmony_ci	{0x00, 0x00, 0x82ca},
13162306a36Sopenharmony_ci	{0x00, 0xfc, 0x8100},
13262306a36Sopenharmony_ci	{0x00, 0xfc, 0x8105},
13362306a36Sopenharmony_ci	{0x00, 0x30, 0x8101},
13462306a36Sopenharmony_ci	{0x00, 0x00, 0x8102},
13562306a36Sopenharmony_ci	{0x00, 0x00, 0x8103},
13662306a36Sopenharmony_ci	{0x00, 0x66, 0x8107},
13762306a36Sopenharmony_ci	{0x00, 0x00, 0x816b},
13862306a36Sopenharmony_ci	{0x00, 0x00, 0x8155},
13962306a36Sopenharmony_ci	{0x00, 0x01, 0x8156},
14062306a36Sopenharmony_ci	{0x00, 0x60, 0x8157},
14162306a36Sopenharmony_ci	{0x00, 0x40, 0x8158},
14262306a36Sopenharmony_ci	{0x00, 0x0a, 0x8159},
14362306a36Sopenharmony_ci	{0x00, 0x06, 0x815a},
14462306a36Sopenharmony_ci	{0x00, 0x00, 0x813f},
14562306a36Sopenharmony_ci	{0x00, 0x00, 0x8200},
14662306a36Sopenharmony_ci	{0x00, 0x19, 0x8201},
14762306a36Sopenharmony_ci	{0x00, 0x00, 0x82c1},
14862306a36Sopenharmony_ci	{0x00, 0xa0, 0x82c2},
14962306a36Sopenharmony_ci	{0x00, 0x00, 0x82ca},
15062306a36Sopenharmony_ci	{0x00, 0x00, 0x8117},
15162306a36Sopenharmony_ci	{0x00, 0x00, 0x8118},
15262306a36Sopenharmony_ci	{0x00, 0x65, 0x8119},
15362306a36Sopenharmony_ci	{0x00, 0x00, 0x811a},
15462306a36Sopenharmony_ci	{0x00, 0x00, 0x811b},
15562306a36Sopenharmony_ci	{0x00, 0x55, 0x811c},
15662306a36Sopenharmony_ci	{0x00, 0x65, 0x811d},
15762306a36Sopenharmony_ci	{0x00, 0x55, 0x811e},
15862306a36Sopenharmony_ci	{0x00, 0x16, 0x811f},
15962306a36Sopenharmony_ci	{0x00, 0x19, 0x8120},
16062306a36Sopenharmony_ci	{0x00, 0x80, 0x8103},
16162306a36Sopenharmony_ci	{0x00, 0x83, 0x816b},
16262306a36Sopenharmony_ci	{0x00, 0x25, 0x8168},
16362306a36Sopenharmony_ci	{0x00, 0x01, 0x820f},
16462306a36Sopenharmony_ci	{0x00, 0xff, 0x8115},
16562306a36Sopenharmony_ci	{0x00, 0x48, 0x8116},
16662306a36Sopenharmony_ci	{0x00, 0x50, 0x8151},
16762306a36Sopenharmony_ci	{0x00, 0x40, 0x8152},
16862306a36Sopenharmony_ci	{0x00, 0x78, 0x8153},
16962306a36Sopenharmony_ci	{0x00, 0x40, 0x8154},
17062306a36Sopenharmony_ci	{0x00, 0x00, 0x8167},
17162306a36Sopenharmony_ci	{0x00, 0x20, 0x8168},
17262306a36Sopenharmony_ci	{0x00, 0x00, 0x816a},
17362306a36Sopenharmony_ci	{0x00, 0x03, 0x816b},
17462306a36Sopenharmony_ci	{0x00, 0x20, 0x8169},
17562306a36Sopenharmony_ci	{0x00, 0x60, 0x8157},
17662306a36Sopenharmony_ci	{0x00, 0x00, 0x8190},
17762306a36Sopenharmony_ci	{0x00, 0x00, 0x81a1},
17862306a36Sopenharmony_ci	{0x00, 0x00, 0x81b2},
17962306a36Sopenharmony_ci	{0x00, 0x27, 0x8191},
18062306a36Sopenharmony_ci	{0x00, 0x27, 0x81a2},
18162306a36Sopenharmony_ci	{0x00, 0x27, 0x81b3},
18262306a36Sopenharmony_ci	{0x00, 0x4b, 0x8192},
18362306a36Sopenharmony_ci	{0x00, 0x4b, 0x81a3},
18462306a36Sopenharmony_ci	{0x00, 0x4b, 0x81b4},
18562306a36Sopenharmony_ci	{0x00, 0x66, 0x8193},
18662306a36Sopenharmony_ci	{0x00, 0x66, 0x81a4},
18762306a36Sopenharmony_ci	{0x00, 0x66, 0x81b5},
18862306a36Sopenharmony_ci	{0x00, 0x79, 0x8194},
18962306a36Sopenharmony_ci	{0x00, 0x79, 0x81a5},
19062306a36Sopenharmony_ci	{0x00, 0x79, 0x81b6},
19162306a36Sopenharmony_ci	{0x00, 0x8a, 0x8195},
19262306a36Sopenharmony_ci	{0x00, 0x8a, 0x81a6},
19362306a36Sopenharmony_ci	{0x00, 0x8a, 0x81b7},
19462306a36Sopenharmony_ci	{0x00, 0x9b, 0x8196},
19562306a36Sopenharmony_ci	{0x00, 0x9b, 0x81a7},
19662306a36Sopenharmony_ci	{0x00, 0x9b, 0x81b8},
19762306a36Sopenharmony_ci	{0x00, 0xa6, 0x8197},
19862306a36Sopenharmony_ci	{0x00, 0xa6, 0x81a8},
19962306a36Sopenharmony_ci	{0x00, 0xa6, 0x81b9},
20062306a36Sopenharmony_ci	{0x00, 0xb2, 0x8198},
20162306a36Sopenharmony_ci	{0x00, 0xb2, 0x81a9},
20262306a36Sopenharmony_ci	{0x00, 0xb2, 0x81ba},
20362306a36Sopenharmony_ci	{0x00, 0xbe, 0x8199},
20462306a36Sopenharmony_ci	{0x00, 0xbe, 0x81aa},
20562306a36Sopenharmony_ci	{0x00, 0xbe, 0x81bb},
20662306a36Sopenharmony_ci	{0x00, 0xc8, 0x819a},
20762306a36Sopenharmony_ci	{0x00, 0xc8, 0x81ab},
20862306a36Sopenharmony_ci	{0x00, 0xc8, 0x81bc},
20962306a36Sopenharmony_ci	{0x00, 0xd2, 0x819b},
21062306a36Sopenharmony_ci	{0x00, 0xd2, 0x81ac},
21162306a36Sopenharmony_ci	{0x00, 0xd2, 0x81bd},
21262306a36Sopenharmony_ci	{0x00, 0xdb, 0x819c},
21362306a36Sopenharmony_ci	{0x00, 0xdb, 0x81ad},
21462306a36Sopenharmony_ci	{0x00, 0xdb, 0x81be},
21562306a36Sopenharmony_ci	{0x00, 0xe4, 0x819d},
21662306a36Sopenharmony_ci	{0x00, 0xe4, 0x81ae},
21762306a36Sopenharmony_ci	{0x00, 0xe4, 0x81bf},
21862306a36Sopenharmony_ci	{0x00, 0xed, 0x819e},
21962306a36Sopenharmony_ci	{0x00, 0xed, 0x81af},
22062306a36Sopenharmony_ci	{0x00, 0xed, 0x81c0},
22162306a36Sopenharmony_ci	{0x00, 0xf7, 0x819f},
22262306a36Sopenharmony_ci	{0x00, 0xf7, 0x81b0},
22362306a36Sopenharmony_ci	{0x00, 0xf7, 0x81c1},
22462306a36Sopenharmony_ci	{0x00, 0xff, 0x81a0},
22562306a36Sopenharmony_ci	{0x00, 0xff, 0x81b1},
22662306a36Sopenharmony_ci	{0x00, 0xff, 0x81c2},
22762306a36Sopenharmony_ci	{0x00, 0x03, 0x8156},
22862306a36Sopenharmony_ci	{0x00, 0x00, 0x8211},
22962306a36Sopenharmony_ci	{0x00, 0x20, 0x8168},
23062306a36Sopenharmony_ci	{0x00, 0x01, 0x8202},
23162306a36Sopenharmony_ci	{0x00, 0x30, 0x8101},
23262306a36Sopenharmony_ci	{0x00, 0x00, 0x8111},
23362306a36Sopenharmony_ci	{0x00, 0x00, 0x8112},
23462306a36Sopenharmony_ci	{0x00, 0x00, 0x8113},
23562306a36Sopenharmony_ci	{0x00, 0x00, 0x8114},
23662306a36Sopenharmony_ci	{}
23762306a36Sopenharmony_ci};
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_cistatic const __u8 qtable_creative_pccam[2][64] = {
24062306a36Sopenharmony_ci	{				/* Q-table Y-components */
24162306a36Sopenharmony_ci	 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
24262306a36Sopenharmony_ci	 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
24362306a36Sopenharmony_ci	 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
24462306a36Sopenharmony_ci	 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
24562306a36Sopenharmony_ci	 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
24662306a36Sopenharmony_ci	 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
24762306a36Sopenharmony_ci	 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
24862306a36Sopenharmony_ci	 0x16, 0x1c, 0x1d, 0x1d, 0x22, 0x1e, 0x1f, 0x1e},
24962306a36Sopenharmony_ci	{				/* Q-table C-components */
25062306a36Sopenharmony_ci	 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
25162306a36Sopenharmony_ci	 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
25262306a36Sopenharmony_ci	 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
25362306a36Sopenharmony_ci	 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
25462306a36Sopenharmony_ci	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
25562306a36Sopenharmony_ci	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
25662306a36Sopenharmony_ci	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
25762306a36Sopenharmony_ci	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
25862306a36Sopenharmony_ci};
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_cistatic const __u8 qtable_kodak_ez200[2][64] = {
26162306a36Sopenharmony_ci	{				/* Q-table Y-components */
26262306a36Sopenharmony_ci	 0x02, 0x01, 0x01, 0x02, 0x02, 0x04, 0x05, 0x06,
26362306a36Sopenharmony_ci	 0x01, 0x01, 0x01, 0x02, 0x03, 0x06, 0x06, 0x06,
26462306a36Sopenharmony_ci	 0x01, 0x01, 0x02, 0x02, 0x04, 0x06, 0x07, 0x06,
26562306a36Sopenharmony_ci	 0x01, 0x02, 0x02, 0x03, 0x05, 0x09, 0x08, 0x06,
26662306a36Sopenharmony_ci	 0x02, 0x02, 0x04, 0x06, 0x07, 0x0b, 0x0a, 0x08,
26762306a36Sopenharmony_ci	 0x02, 0x04, 0x06, 0x06, 0x08, 0x0a, 0x0b, 0x09,
26862306a36Sopenharmony_ci	 0x05, 0x06, 0x08, 0x09, 0x0a, 0x0c, 0x0c, 0x0a,
26962306a36Sopenharmony_ci	 0x07, 0x09, 0x0a, 0x0a, 0x0b, 0x0a, 0x0a, 0x0a},
27062306a36Sopenharmony_ci	{				/* Q-table C-components */
27162306a36Sopenharmony_ci	 0x02, 0x02, 0x02, 0x05, 0x0a, 0x0a, 0x0a, 0x0a,
27262306a36Sopenharmony_ci	 0x02, 0x02, 0x03, 0x07, 0x0a, 0x0a, 0x0a, 0x0a,
27362306a36Sopenharmony_ci	 0x02, 0x03, 0x06, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
27462306a36Sopenharmony_ci	 0x05, 0x07, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
27562306a36Sopenharmony_ci	 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
27662306a36Sopenharmony_ci	 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
27762306a36Sopenharmony_ci	 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
27862306a36Sopenharmony_ci	 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a}
27962306a36Sopenharmony_ci};
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_cistatic const __u8 qtable_pocketdv[2][64] = {
28262306a36Sopenharmony_ci	{		/* Q-table Y-components start registers 0x8800 */
28362306a36Sopenharmony_ci	 0x06, 0x04, 0x04, 0x06, 0x0a, 0x10, 0x14, 0x18,
28462306a36Sopenharmony_ci	 0x05, 0x05, 0x06, 0x08, 0x0a, 0x17, 0x18, 0x16,
28562306a36Sopenharmony_ci	 0x06, 0x05, 0x06, 0x0a, 0x10, 0x17, 0x1c, 0x16,
28662306a36Sopenharmony_ci	 0x06, 0x07, 0x09, 0x0c, 0x14, 0x23, 0x20, 0x19,
28762306a36Sopenharmony_ci	 0x07, 0x09, 0x0f, 0x16, 0x1b, 0x2c, 0x29, 0x1f,
28862306a36Sopenharmony_ci	 0x0a, 0x0e, 0x16, 0x1a, 0x20, 0x2a, 0x2d, 0x25,
28962306a36Sopenharmony_ci	 0x14, 0x1a, 0x1f, 0x23, 0x29, 0x30, 0x30, 0x28,
29062306a36Sopenharmony_ci	 0x1d, 0x25, 0x26, 0x27, 0x2d, 0x28, 0x29, 0x28,
29162306a36Sopenharmony_ci	 },
29262306a36Sopenharmony_ci	{		/* Q-table C-components start registers 0x8840 */
29362306a36Sopenharmony_ci	 0x07, 0x07, 0x0a, 0x13, 0x28, 0x28, 0x28, 0x28,
29462306a36Sopenharmony_ci	 0x07, 0x08, 0x0a, 0x1a, 0x28, 0x28, 0x28, 0x28,
29562306a36Sopenharmony_ci	 0x0a, 0x0a, 0x16, 0x28, 0x28, 0x28, 0x28, 0x28,
29662306a36Sopenharmony_ci	 0x13, 0x1a, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
29762306a36Sopenharmony_ci	 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
29862306a36Sopenharmony_ci	 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
29962306a36Sopenharmony_ci	 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
30062306a36Sopenharmony_ci	 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28}
30162306a36Sopenharmony_ci};
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci/* read 'len' bytes to gspca_dev->usb_buf */
30462306a36Sopenharmony_cistatic void reg_r(struct gspca_dev *gspca_dev,
30562306a36Sopenharmony_ci		  __u16 index,
30662306a36Sopenharmony_ci		  __u16 length)
30762306a36Sopenharmony_ci{
30862306a36Sopenharmony_ci	usb_control_msg(gspca_dev->dev,
30962306a36Sopenharmony_ci			usb_rcvctrlpipe(gspca_dev->dev, 0),
31062306a36Sopenharmony_ci			0,
31162306a36Sopenharmony_ci			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
31262306a36Sopenharmony_ci			0,		/* value */
31362306a36Sopenharmony_ci			index, gspca_dev->usb_buf, length, 500);
31462306a36Sopenharmony_ci}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_cistatic int reg_w(struct gspca_dev *gspca_dev,
31762306a36Sopenharmony_ci		     __u16 req, __u16 index, __u16 value)
31862306a36Sopenharmony_ci{
31962306a36Sopenharmony_ci	int ret;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	gspca_dbg(gspca_dev, D_USBO, "reg write: [0x%02x] = 0x%02x\n",
32262306a36Sopenharmony_ci		  index, value);
32362306a36Sopenharmony_ci	ret = usb_control_msg(gspca_dev->dev,
32462306a36Sopenharmony_ci			usb_sndctrlpipe(gspca_dev->dev, 0),
32562306a36Sopenharmony_ci			req,
32662306a36Sopenharmony_ci			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
32762306a36Sopenharmony_ci			value, index, NULL, 0, 500);
32862306a36Sopenharmony_ci	if (ret < 0)
32962306a36Sopenharmony_ci		pr_err("reg write: error %d\n", ret);
33062306a36Sopenharmony_ci	return ret;
33162306a36Sopenharmony_ci}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci/* returns: negative is error, pos or zero is data */
33462306a36Sopenharmony_cistatic int reg_r_12(struct gspca_dev *gspca_dev,
33562306a36Sopenharmony_ci			__u16 req,	/* bRequest */
33662306a36Sopenharmony_ci			__u16 index,	/* wIndex */
33762306a36Sopenharmony_ci			__u16 length)	/* wLength (1 or 2 only) */
33862306a36Sopenharmony_ci{
33962306a36Sopenharmony_ci	int ret;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	gspca_dev->usb_buf[1] = 0;
34262306a36Sopenharmony_ci	ret = usb_control_msg(gspca_dev->dev,
34362306a36Sopenharmony_ci			usb_rcvctrlpipe(gspca_dev->dev, 0),
34462306a36Sopenharmony_ci			req,
34562306a36Sopenharmony_ci			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
34662306a36Sopenharmony_ci			0,		/* value */
34762306a36Sopenharmony_ci			index,
34862306a36Sopenharmony_ci			gspca_dev->usb_buf, length,
34962306a36Sopenharmony_ci			500);		/* timeout */
35062306a36Sopenharmony_ci	if (ret < 0) {
35162306a36Sopenharmony_ci		pr_err("reg_r_12 err %d\n", ret);
35262306a36Sopenharmony_ci		return ret;
35362306a36Sopenharmony_ci	}
35462306a36Sopenharmony_ci	return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0];
35562306a36Sopenharmony_ci}
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci/*
35862306a36Sopenharmony_ci * Simple function to wait for a given 8-bit value to be returned from
35962306a36Sopenharmony_ci * a reg_read call.
36062306a36Sopenharmony_ci * Returns: negative is error or timeout, zero is success.
36162306a36Sopenharmony_ci */
36262306a36Sopenharmony_cistatic int reg_r_wait(struct gspca_dev *gspca_dev,
36362306a36Sopenharmony_ci			__u16 reg, __u16 index, __u16 value)
36462306a36Sopenharmony_ci{
36562306a36Sopenharmony_ci	int ret, cnt = 20;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	while (--cnt > 0) {
36862306a36Sopenharmony_ci		ret = reg_r_12(gspca_dev, reg, index, 1);
36962306a36Sopenharmony_ci		if (ret == value)
37062306a36Sopenharmony_ci			return 0;
37162306a36Sopenharmony_ci		msleep(50);
37262306a36Sopenharmony_ci	}
37362306a36Sopenharmony_ci	return -EIO;
37462306a36Sopenharmony_ci}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_cistatic int write_vector(struct gspca_dev *gspca_dev,
37762306a36Sopenharmony_ci			const __u16 data[][3])
37862306a36Sopenharmony_ci{
37962306a36Sopenharmony_ci	int ret, i = 0;
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) {
38262306a36Sopenharmony_ci		ret = reg_w(gspca_dev, data[i][0], data[i][2], data[i][1]);
38362306a36Sopenharmony_ci		if (ret < 0)
38462306a36Sopenharmony_ci			return ret;
38562306a36Sopenharmony_ci		i++;
38662306a36Sopenharmony_ci	}
38762306a36Sopenharmony_ci	return 0;
38862306a36Sopenharmony_ci}
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_cistatic int spca50x_setup_qtable(struct gspca_dev *gspca_dev,
39162306a36Sopenharmony_ci				unsigned int request,
39262306a36Sopenharmony_ci				unsigned int ybase,
39362306a36Sopenharmony_ci				unsigned int cbase,
39462306a36Sopenharmony_ci				const __u8 qtable[2][64])
39562306a36Sopenharmony_ci{
39662306a36Sopenharmony_ci	int i, err;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	/* loop over y components */
39962306a36Sopenharmony_ci	for (i = 0; i < 64; i++) {
40062306a36Sopenharmony_ci		err = reg_w(gspca_dev, request, ybase + i, qtable[0][i]);
40162306a36Sopenharmony_ci		if (err < 0)
40262306a36Sopenharmony_ci			return err;
40362306a36Sopenharmony_ci	}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	/* loop over c components */
40662306a36Sopenharmony_ci	for (i = 0; i < 64; i++) {
40762306a36Sopenharmony_ci		err = reg_w(gspca_dev, request, cbase + i, qtable[1][i]);
40862306a36Sopenharmony_ci		if (err < 0)
40962306a36Sopenharmony_ci			return err;
41062306a36Sopenharmony_ci	}
41162306a36Sopenharmony_ci	return 0;
41262306a36Sopenharmony_ci}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_cistatic void spca500_ping310(struct gspca_dev *gspca_dev)
41562306a36Sopenharmony_ci{
41662306a36Sopenharmony_ci	reg_r(gspca_dev, 0x0d04, 2);
41762306a36Sopenharmony_ci	gspca_dbg(gspca_dev, D_STREAM, "ClickSmart310 ping 0x0d04 0x%02x 0x%02x\n",
41862306a36Sopenharmony_ci		  gspca_dev->usb_buf[0], gspca_dev->usb_buf[1]);
41962306a36Sopenharmony_ci}
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_cistatic void spca500_clksmart310_init(struct gspca_dev *gspca_dev)
42262306a36Sopenharmony_ci{
42362306a36Sopenharmony_ci	reg_r(gspca_dev, 0x0d05, 2);
42462306a36Sopenharmony_ci	gspca_dbg(gspca_dev, D_STREAM, "ClickSmart310 init 0x0d05 0x%02x 0x%02x\n",
42562306a36Sopenharmony_ci		  gspca_dev->usb_buf[0], gspca_dev->usb_buf[1]);
42662306a36Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x8167, 0x5a);
42762306a36Sopenharmony_ci	spca500_ping310(gspca_dev);
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x8168, 0x22);
43062306a36Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x816a, 0xc0);
43162306a36Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x816b, 0x0b);
43262306a36Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x8169, 0x25);
43362306a36Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x8157, 0x5b);
43462306a36Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x8158, 0x5b);
43562306a36Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x813f, 0x03);
43662306a36Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x8151, 0x4a);
43762306a36Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x8153, 0x78);
43862306a36Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x0d01, 0x04);
43962306a36Sopenharmony_ci						/* 00 for adjust shutter */
44062306a36Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x0d02, 0x01);
44162306a36Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x8169, 0x25);
44262306a36Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x0d01, 0x02);
44362306a36Sopenharmony_ci}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_cistatic void spca500_setmode(struct gspca_dev *gspca_dev,
44662306a36Sopenharmony_ci			__u8 xmult, __u8 ymult)
44762306a36Sopenharmony_ci{
44862306a36Sopenharmony_ci	int mode;
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	/* set x multiplier */
45162306a36Sopenharmony_ci	reg_w(gspca_dev, 0, 0x8001, xmult);
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	/* set y multiplier */
45462306a36Sopenharmony_ci	reg_w(gspca_dev, 0, 0x8002, ymult);
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	/* use compressed mode, VGA, with mode specific subsample */
45762306a36Sopenharmony_ci	mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
45862306a36Sopenharmony_ci	reg_w(gspca_dev, 0, 0x8003, mode << 4);
45962306a36Sopenharmony_ci}
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_cistatic int spca500_full_reset(struct gspca_dev *gspca_dev)
46262306a36Sopenharmony_ci{
46362306a36Sopenharmony_ci	int err;
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	/* send the reset command */
46662306a36Sopenharmony_ci	err = reg_w(gspca_dev, 0xe0, 0x0001, 0x0000);
46762306a36Sopenharmony_ci	if (err < 0)
46862306a36Sopenharmony_ci		return err;
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	/* wait for the reset to complete */
47162306a36Sopenharmony_ci	err = reg_r_wait(gspca_dev, 0x06, 0x0000, 0x0000);
47262306a36Sopenharmony_ci	if (err < 0)
47362306a36Sopenharmony_ci		return err;
47462306a36Sopenharmony_ci	err = reg_w(gspca_dev, 0xe0, 0x0000, 0x0000);
47562306a36Sopenharmony_ci	if (err < 0)
47662306a36Sopenharmony_ci		return err;
47762306a36Sopenharmony_ci	err = reg_r_wait(gspca_dev, 0x06, 0, 0);
47862306a36Sopenharmony_ci	if (err < 0) {
47962306a36Sopenharmony_ci		gspca_err(gspca_dev, "reg_r_wait() failed\n");
48062306a36Sopenharmony_ci		return err;
48162306a36Sopenharmony_ci	}
48262306a36Sopenharmony_ci	/* all ok */
48362306a36Sopenharmony_ci	return 0;
48462306a36Sopenharmony_ci}
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci/* Synchro the Bridge with sensor */
48762306a36Sopenharmony_ci/* Maybe that will work on all spca500 chip */
48862306a36Sopenharmony_ci/* because i only own a clicksmart310 try for that chip */
48962306a36Sopenharmony_ci/* using spca50x_set_packet_size() cause an Ooops here */
49062306a36Sopenharmony_ci/* usb_set_interface from kernel 2.6.x clear all the urb stuff */
49162306a36Sopenharmony_ci/* up-port the same feature as in 2.4.x kernel */
49262306a36Sopenharmony_cistatic int spca500_synch310(struct gspca_dev *gspca_dev)
49362306a36Sopenharmony_ci{
49462306a36Sopenharmony_ci	if (usb_set_interface(gspca_dev->dev, gspca_dev->iface, 0) < 0) {
49562306a36Sopenharmony_ci		gspca_err(gspca_dev, "Set packet size: set interface error\n");
49662306a36Sopenharmony_ci		goto error;
49762306a36Sopenharmony_ci	}
49862306a36Sopenharmony_ci	spca500_ping310(gspca_dev);
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	reg_r(gspca_dev, 0x0d00, 1);
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	/* need alt setting here */
50362306a36Sopenharmony_ci	gspca_dbg(gspca_dev, D_PACK, "ClickSmart310 sync alt: %d\n",
50462306a36Sopenharmony_ci		  gspca_dev->alt);
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	/* Windoze use pipe with altsetting 6 why 7 here */
50762306a36Sopenharmony_ci	if (usb_set_interface(gspca_dev->dev,
50862306a36Sopenharmony_ci				gspca_dev->iface,
50962306a36Sopenharmony_ci				gspca_dev->alt) < 0) {
51062306a36Sopenharmony_ci		gspca_err(gspca_dev, "Set packet size: set interface error\n");
51162306a36Sopenharmony_ci		goto error;
51262306a36Sopenharmony_ci	}
51362306a36Sopenharmony_ci	return 0;
51462306a36Sopenharmony_cierror:
51562306a36Sopenharmony_ci	return -EBUSY;
51662306a36Sopenharmony_ci}
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_cistatic void spca500_reinit(struct gspca_dev *gspca_dev)
51962306a36Sopenharmony_ci{
52062306a36Sopenharmony_ci	int err;
52162306a36Sopenharmony_ci	__u8 Data;
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	/* some unknown command from Aiptek pocket dv and family300 */
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x0d01, 0x01);
52662306a36Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x0d03, 0x00);
52762306a36Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x0d02, 0x01);
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	/* enable drop packet */
53062306a36Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x850a, 0x0001);
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	err = spca50x_setup_qtable(gspca_dev, 0x00, 0x8800, 0x8840,
53362306a36Sopenharmony_ci				 qtable_pocketdv);
53462306a36Sopenharmony_ci	if (err < 0)
53562306a36Sopenharmony_ci		gspca_err(gspca_dev, "spca50x_setup_qtable failed on init\n");
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	/* set qtable index */
53862306a36Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x8880, 2);
53962306a36Sopenharmony_ci	/* family cam Quicksmart stuff */
54062306a36Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x800a, 0x00);
54162306a36Sopenharmony_ci	/* Set agc transfer: synced between frames */
54262306a36Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x820f, 0x01);
54362306a36Sopenharmony_ci	/* Init SDRAM - needed for SDRAM access */
54462306a36Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x870a, 0x04);
54562306a36Sopenharmony_ci	/*Start init sequence or stream */
54662306a36Sopenharmony_ci	reg_w(gspca_dev, 0, 0x8003, 0x00);
54762306a36Sopenharmony_ci	/* switch to video camera mode */
54862306a36Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x8000, 0x0004);
54962306a36Sopenharmony_ci	msleep(2000);
55062306a36Sopenharmony_ci	if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0) {
55162306a36Sopenharmony_ci		reg_r(gspca_dev, 0x816b, 1);
55262306a36Sopenharmony_ci		Data = gspca_dev->usb_buf[0];
55362306a36Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x816b, Data);
55462306a36Sopenharmony_ci	}
55562306a36Sopenharmony_ci}
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci/* this function is called at probe time */
55862306a36Sopenharmony_cistatic int sd_config(struct gspca_dev *gspca_dev,
55962306a36Sopenharmony_ci			const struct usb_device_id *id)
56062306a36Sopenharmony_ci{
56162306a36Sopenharmony_ci	struct sd *sd = (struct sd *) gspca_dev;
56262306a36Sopenharmony_ci	struct cam *cam;
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	cam = &gspca_dev->cam;
56562306a36Sopenharmony_ci	sd->subtype = id->driver_info;
56662306a36Sopenharmony_ci	if (sd->subtype != LogitechClickSmart310) {
56762306a36Sopenharmony_ci		cam->cam_mode = vga_mode;
56862306a36Sopenharmony_ci		cam->nmodes = ARRAY_SIZE(vga_mode);
56962306a36Sopenharmony_ci	} else {
57062306a36Sopenharmony_ci		cam->cam_mode = sif_mode;
57162306a36Sopenharmony_ci		cam->nmodes = ARRAY_SIZE(sif_mode);
57262306a36Sopenharmony_ci	}
57362306a36Sopenharmony_ci	return 0;
57462306a36Sopenharmony_ci}
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci/* this function is called at probe and resume time */
57762306a36Sopenharmony_cistatic int sd_init(struct gspca_dev *gspca_dev)
57862306a36Sopenharmony_ci{
57962306a36Sopenharmony_ci	struct sd *sd = (struct sd *) gspca_dev;
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	/* initialisation of spca500 based cameras is deferred */
58262306a36Sopenharmony_ci	gspca_dbg(gspca_dev, D_STREAM, "SPCA500 init\n");
58362306a36Sopenharmony_ci	if (sd->subtype == LogitechClickSmart310)
58462306a36Sopenharmony_ci		spca500_clksmart310_init(gspca_dev);
58562306a36Sopenharmony_ci/*	else
58662306a36Sopenharmony_ci		spca500_initialise(gspca_dev); */
58762306a36Sopenharmony_ci	gspca_dbg(gspca_dev, D_STREAM, "SPCA500 init done\n");
58862306a36Sopenharmony_ci	return 0;
58962306a36Sopenharmony_ci}
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_cistatic int sd_start(struct gspca_dev *gspca_dev)
59262306a36Sopenharmony_ci{
59362306a36Sopenharmony_ci	struct sd *sd = (struct sd *) gspca_dev;
59462306a36Sopenharmony_ci	int err;
59562306a36Sopenharmony_ci	__u8 Data;
59662306a36Sopenharmony_ci	__u8 xmult, ymult;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	/* create the JPEG header */
59962306a36Sopenharmony_ci	jpeg_define(sd->jpeg_hdr, gspca_dev->pixfmt.height,
60062306a36Sopenharmony_ci			gspca_dev->pixfmt.width,
60162306a36Sopenharmony_ci			0x22);		/* JPEG 411 */
60262306a36Sopenharmony_ci	jpeg_set_qual(sd->jpeg_hdr, QUALITY);
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	if (sd->subtype == LogitechClickSmart310) {
60562306a36Sopenharmony_ci		xmult = 0x16;
60662306a36Sopenharmony_ci		ymult = 0x12;
60762306a36Sopenharmony_ci	} else {
60862306a36Sopenharmony_ci		xmult = 0x28;
60962306a36Sopenharmony_ci		ymult = 0x1e;
61062306a36Sopenharmony_ci	}
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	/* is there a sensor here ? */
61362306a36Sopenharmony_ci	reg_r(gspca_dev, 0x8a04, 1);
61462306a36Sopenharmony_ci	gspca_dbg(gspca_dev, D_STREAM, "Spca500 Sensor Address 0x%02x\n",
61562306a36Sopenharmony_ci		  gspca_dev->usb_buf[0]);
61662306a36Sopenharmony_ci	gspca_dbg(gspca_dev, D_STREAM, "Spca500 curr_mode: %d Xmult: 0x%02x, Ymult: 0x%02x",
61762306a36Sopenharmony_ci		  gspca_dev->curr_mode, xmult, ymult);
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	/* setup qtable */
62062306a36Sopenharmony_ci	switch (sd->subtype) {
62162306a36Sopenharmony_ci	case LogitechClickSmart310:
62262306a36Sopenharmony_ci		 spca500_setmode(gspca_dev, xmult, ymult);
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci		/* enable drop packet */
62562306a36Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x850a, 0x0001);
62662306a36Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x8880, 3);
62762306a36Sopenharmony_ci		err = spca50x_setup_qtable(gspca_dev,
62862306a36Sopenharmony_ci					   0x00, 0x8800, 0x8840,
62962306a36Sopenharmony_ci					   qtable_creative_pccam);
63062306a36Sopenharmony_ci		if (err < 0)
63162306a36Sopenharmony_ci			gspca_err(gspca_dev, "spca50x_setup_qtable failed\n");
63262306a36Sopenharmony_ci		/* Init SDRAM - needed for SDRAM access */
63362306a36Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x870a, 0x04);
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci		/* switch to video camera mode */
63662306a36Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x8000, 0x0004);
63762306a36Sopenharmony_ci		msleep(500);
63862306a36Sopenharmony_ci		if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0)
63962306a36Sopenharmony_ci			gspca_err(gspca_dev, "reg_r_wait() failed\n");
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci		reg_r(gspca_dev, 0x816b, 1);
64262306a36Sopenharmony_ci		Data = gspca_dev->usb_buf[0];
64362306a36Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x816b, Data);
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci		spca500_synch310(gspca_dev);
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci		write_vector(gspca_dev, spca500_visual_defaults);
64862306a36Sopenharmony_ci		spca500_setmode(gspca_dev, xmult, ymult);
64962306a36Sopenharmony_ci		/* enable drop packet */
65062306a36Sopenharmony_ci		err = reg_w(gspca_dev, 0x00, 0x850a, 0x0001);
65162306a36Sopenharmony_ci		if (err < 0)
65262306a36Sopenharmony_ci			gspca_err(gspca_dev, "failed to enable drop packet\n");
65362306a36Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x8880, 3);
65462306a36Sopenharmony_ci		err = spca50x_setup_qtable(gspca_dev,
65562306a36Sopenharmony_ci					   0x00, 0x8800, 0x8840,
65662306a36Sopenharmony_ci					   qtable_creative_pccam);
65762306a36Sopenharmony_ci		if (err < 0)
65862306a36Sopenharmony_ci			gspca_err(gspca_dev, "spca50x_setup_qtable failed\n");
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci		/* Init SDRAM - needed for SDRAM access */
66162306a36Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x870a, 0x04);
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci		/* switch to video camera mode */
66462306a36Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x8000, 0x0004);
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci		if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0)
66762306a36Sopenharmony_ci			gspca_err(gspca_dev, "reg_r_wait() failed\n");
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci		reg_r(gspca_dev, 0x816b, 1);
67062306a36Sopenharmony_ci		Data = gspca_dev->usb_buf[0];
67162306a36Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x816b, Data);
67262306a36Sopenharmony_ci		break;
67362306a36Sopenharmony_ci	case CreativePCCam300:		/* Creative PC-CAM 300 640x480 CCD */
67462306a36Sopenharmony_ci	case IntelPocketPCCamera:	/* FIXME: Temporary fix for
67562306a36Sopenharmony_ci					 *	Intel Pocket PC Camera
67662306a36Sopenharmony_ci					 *	- NWG (Sat 29th March 2003) */
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci		/* do a full reset */
67962306a36Sopenharmony_ci		err = spca500_full_reset(gspca_dev);
68062306a36Sopenharmony_ci		if (err < 0)
68162306a36Sopenharmony_ci			gspca_err(gspca_dev, "spca500_full_reset failed\n");
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci		/* enable drop packet */
68462306a36Sopenharmony_ci		err = reg_w(gspca_dev, 0x00, 0x850a, 0x0001);
68562306a36Sopenharmony_ci		if (err < 0)
68662306a36Sopenharmony_ci			gspca_err(gspca_dev, "failed to enable drop packet\n");
68762306a36Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x8880, 3);
68862306a36Sopenharmony_ci		err = spca50x_setup_qtable(gspca_dev,
68962306a36Sopenharmony_ci					   0x00, 0x8800, 0x8840,
69062306a36Sopenharmony_ci					   qtable_creative_pccam);
69162306a36Sopenharmony_ci		if (err < 0)
69262306a36Sopenharmony_ci			gspca_err(gspca_dev, "spca50x_setup_qtable failed\n");
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci		spca500_setmode(gspca_dev, xmult, ymult);
69562306a36Sopenharmony_ci		reg_w(gspca_dev, 0x20, 0x0001, 0x0004);
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci		/* switch to video camera mode */
69862306a36Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x8000, 0x0004);
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci		if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0)
70162306a36Sopenharmony_ci			gspca_err(gspca_dev, "reg_r_wait() failed\n");
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci		reg_r(gspca_dev, 0x816b, 1);
70462306a36Sopenharmony_ci		Data = gspca_dev->usb_buf[0];
70562306a36Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x816b, Data);
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci/*		write_vector(gspca_dev, spca500_visual_defaults); */
70862306a36Sopenharmony_ci		break;
70962306a36Sopenharmony_ci	case KodakEZ200:		/* Kodak EZ200 */
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci		/* do a full reset */
71262306a36Sopenharmony_ci		err = spca500_full_reset(gspca_dev);
71362306a36Sopenharmony_ci		if (err < 0)
71462306a36Sopenharmony_ci			gspca_err(gspca_dev, "spca500_full_reset failed\n");
71562306a36Sopenharmony_ci		/* enable drop packet */
71662306a36Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x850a, 0x0001);
71762306a36Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x8880, 0);
71862306a36Sopenharmony_ci		err = spca50x_setup_qtable(gspca_dev,
71962306a36Sopenharmony_ci					   0x00, 0x8800, 0x8840,
72062306a36Sopenharmony_ci					   qtable_kodak_ez200);
72162306a36Sopenharmony_ci		if (err < 0)
72262306a36Sopenharmony_ci			gspca_err(gspca_dev, "spca50x_setup_qtable failed\n");
72362306a36Sopenharmony_ci		spca500_setmode(gspca_dev, xmult, ymult);
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci		reg_w(gspca_dev, 0x20, 0x0001, 0x0004);
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci		/* switch to video camera mode */
72862306a36Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x8000, 0x0004);
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci		if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0)
73162306a36Sopenharmony_ci			gspca_err(gspca_dev, "reg_r_wait() failed\n");
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci		reg_r(gspca_dev, 0x816b, 1);
73462306a36Sopenharmony_ci		Data = gspca_dev->usb_buf[0];
73562306a36Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x816b, Data);
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci/*		write_vector(gspca_dev, spca500_visual_defaults); */
73862306a36Sopenharmony_ci		break;
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci	case BenqDC1016:
74162306a36Sopenharmony_ci	case DLinkDSC350:		/* FamilyCam 300 */
74262306a36Sopenharmony_ci	case AiptekPocketDV:		/* Aiptek PocketDV */
74362306a36Sopenharmony_ci	case Gsmartmini:		/*Mustek Gsmart Mini */
74462306a36Sopenharmony_ci	case MustekGsmart300:		/* Mustek Gsmart 300 */
74562306a36Sopenharmony_ci	case PalmPixDC85:
74662306a36Sopenharmony_ci	case Optimedia:
74762306a36Sopenharmony_ci	case ToptroIndus:
74862306a36Sopenharmony_ci	case AgfaCl20:
74962306a36Sopenharmony_ci		spca500_reinit(gspca_dev);
75062306a36Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x0d01, 0x01);
75162306a36Sopenharmony_ci		/* enable drop packet */
75262306a36Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x850a, 0x0001);
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci		err = spca50x_setup_qtable(gspca_dev,
75562306a36Sopenharmony_ci				   0x00, 0x8800, 0x8840, qtable_pocketdv);
75662306a36Sopenharmony_ci		if (err < 0)
75762306a36Sopenharmony_ci			gspca_err(gspca_dev, "spca50x_setup_qtable failed\n");
75862306a36Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x8880, 2);
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci		/* familycam Quicksmart pocketDV stuff */
76162306a36Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x800a, 0x00);
76262306a36Sopenharmony_ci		/* Set agc transfer: synced between frames */
76362306a36Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x820f, 0x01);
76462306a36Sopenharmony_ci		/* Init SDRAM - needed for SDRAM access */
76562306a36Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x870a, 0x04);
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci		spca500_setmode(gspca_dev, xmult, ymult);
76862306a36Sopenharmony_ci		/* switch to video camera mode */
76962306a36Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x8000, 0x0004);
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci		reg_r_wait(gspca_dev, 0, 0x8000, 0x44);
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci		reg_r(gspca_dev, 0x816b, 1);
77462306a36Sopenharmony_ci		Data = gspca_dev->usb_buf[0];
77562306a36Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x816b, Data);
77662306a36Sopenharmony_ci		break;
77762306a36Sopenharmony_ci	case LogitechTraveler:
77862306a36Sopenharmony_ci	case LogitechClickSmart510:
77962306a36Sopenharmony_ci		reg_w(gspca_dev, 0x02, 0x00, 0x00);
78062306a36Sopenharmony_ci		/* enable drop packet */
78162306a36Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x850a, 0x0001);
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci		err = spca50x_setup_qtable(gspca_dev,
78462306a36Sopenharmony_ci					0x00, 0x8800,
78562306a36Sopenharmony_ci					0x8840, qtable_creative_pccam);
78662306a36Sopenharmony_ci		if (err < 0)
78762306a36Sopenharmony_ci			gspca_err(gspca_dev, "spca50x_setup_qtable failed\n");
78862306a36Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x8880, 3);
78962306a36Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x800a, 0x00);
79062306a36Sopenharmony_ci		/* Init SDRAM - needed for SDRAM access */
79162306a36Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x870a, 0x04);
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci		spca500_setmode(gspca_dev, xmult, ymult);
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci		/* switch to video camera mode */
79662306a36Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x8000, 0x0004);
79762306a36Sopenharmony_ci		reg_r_wait(gspca_dev, 0, 0x8000, 0x44);
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci		reg_r(gspca_dev, 0x816b, 1);
80062306a36Sopenharmony_ci		Data = gspca_dev->usb_buf[0];
80162306a36Sopenharmony_ci		reg_w(gspca_dev, 0x00, 0x816b, Data);
80262306a36Sopenharmony_ci		write_vector(gspca_dev, Clicksmart510_defaults);
80362306a36Sopenharmony_ci		break;
80462306a36Sopenharmony_ci	}
80562306a36Sopenharmony_ci	return 0;
80662306a36Sopenharmony_ci}
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_cistatic void sd_stopN(struct gspca_dev *gspca_dev)
80962306a36Sopenharmony_ci{
81062306a36Sopenharmony_ci	reg_w(gspca_dev, 0, 0x8003, 0x00);
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	/* switch to video camera mode */
81362306a36Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x8000, 0x0004);
81462306a36Sopenharmony_ci	reg_r(gspca_dev, 0x8000, 1);
81562306a36Sopenharmony_ci	gspca_dbg(gspca_dev, D_STREAM, "stop SPCA500 done reg8000: 0x%2x\n",
81662306a36Sopenharmony_ci		  gspca_dev->usb_buf[0]);
81762306a36Sopenharmony_ci}
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_cistatic void sd_pkt_scan(struct gspca_dev *gspca_dev,
82062306a36Sopenharmony_ci			u8 *data,			/* isoc packet */
82162306a36Sopenharmony_ci			int len)			/* iso packet length */
82262306a36Sopenharmony_ci{
82362306a36Sopenharmony_ci	struct sd *sd = (struct sd *) gspca_dev;
82462306a36Sopenharmony_ci	int i;
82562306a36Sopenharmony_ci	static __u8 ffd9[] = {0xff, 0xd9};
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci/* frames are jpeg 4.1.1 without 0xff escape */
82862306a36Sopenharmony_ci	if (data[0] == 0xff) {
82962306a36Sopenharmony_ci		if (data[1] != 0x01) {	/* drop packet */
83062306a36Sopenharmony_ci/*			gspca_dev->last_packet_type = DISCARD_PACKET; */
83162306a36Sopenharmony_ci			return;
83262306a36Sopenharmony_ci		}
83362306a36Sopenharmony_ci		gspca_frame_add(gspca_dev, LAST_PACKET,
83462306a36Sopenharmony_ci					ffd9, 2);
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci		/* put the JPEG header in the new frame */
83762306a36Sopenharmony_ci		gspca_frame_add(gspca_dev, FIRST_PACKET,
83862306a36Sopenharmony_ci			sd->jpeg_hdr, JPEG_HDR_SZ);
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci		data += SPCA500_OFFSET_DATA;
84162306a36Sopenharmony_ci		len -= SPCA500_OFFSET_DATA;
84262306a36Sopenharmony_ci	} else {
84362306a36Sopenharmony_ci		data += 1;
84462306a36Sopenharmony_ci		len -= 1;
84562306a36Sopenharmony_ci	}
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci	/* add 0x00 after 0xff */
84862306a36Sopenharmony_ci	i = 0;
84962306a36Sopenharmony_ci	do {
85062306a36Sopenharmony_ci		if (data[i] == 0xff) {
85162306a36Sopenharmony_ci			gspca_frame_add(gspca_dev, INTER_PACKET,
85262306a36Sopenharmony_ci					data, i + 1);
85362306a36Sopenharmony_ci			len -= i;
85462306a36Sopenharmony_ci			data += i;
85562306a36Sopenharmony_ci			*data = 0x00;
85662306a36Sopenharmony_ci			i = 0;
85762306a36Sopenharmony_ci		}
85862306a36Sopenharmony_ci		i++;
85962306a36Sopenharmony_ci	} while (i < len);
86062306a36Sopenharmony_ci	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
86162306a36Sopenharmony_ci}
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_cistatic void setbrightness(struct gspca_dev *gspca_dev, s32 val)
86462306a36Sopenharmony_ci{
86562306a36Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x8167,
86662306a36Sopenharmony_ci			(__u8) (val - 128));
86762306a36Sopenharmony_ci}
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_cistatic void setcontrast(struct gspca_dev *gspca_dev, s32 val)
87062306a36Sopenharmony_ci{
87162306a36Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x8168, val);
87262306a36Sopenharmony_ci}
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_cistatic void setcolors(struct gspca_dev *gspca_dev, s32 val)
87562306a36Sopenharmony_ci{
87662306a36Sopenharmony_ci	reg_w(gspca_dev, 0x00, 0x8169, val);
87762306a36Sopenharmony_ci}
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_cistatic int sd_s_ctrl(struct v4l2_ctrl *ctrl)
88062306a36Sopenharmony_ci{
88162306a36Sopenharmony_ci	struct gspca_dev *gspca_dev =
88262306a36Sopenharmony_ci		container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci	gspca_dev->usb_err = 0;
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	if (!gspca_dev->streaming)
88762306a36Sopenharmony_ci		return 0;
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci	switch (ctrl->id) {
89062306a36Sopenharmony_ci	case V4L2_CID_BRIGHTNESS:
89162306a36Sopenharmony_ci		setbrightness(gspca_dev, ctrl->val);
89262306a36Sopenharmony_ci		break;
89362306a36Sopenharmony_ci	case V4L2_CID_CONTRAST:
89462306a36Sopenharmony_ci		setcontrast(gspca_dev, ctrl->val);
89562306a36Sopenharmony_ci		break;
89662306a36Sopenharmony_ci	case V4L2_CID_SATURATION:
89762306a36Sopenharmony_ci		setcolors(gspca_dev, ctrl->val);
89862306a36Sopenharmony_ci		break;
89962306a36Sopenharmony_ci	}
90062306a36Sopenharmony_ci	return gspca_dev->usb_err;
90162306a36Sopenharmony_ci}
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_cistatic const struct v4l2_ctrl_ops sd_ctrl_ops = {
90462306a36Sopenharmony_ci	.s_ctrl = sd_s_ctrl,
90562306a36Sopenharmony_ci};
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_cistatic int sd_init_controls(struct gspca_dev *gspca_dev)
90862306a36Sopenharmony_ci{
90962306a36Sopenharmony_ci	struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci	gspca_dev->vdev.ctrl_handler = hdl;
91262306a36Sopenharmony_ci	v4l2_ctrl_handler_init(hdl, 3);
91362306a36Sopenharmony_ci	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
91462306a36Sopenharmony_ci			V4L2_CID_BRIGHTNESS, 0, 255, 1, 127);
91562306a36Sopenharmony_ci	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
91662306a36Sopenharmony_ci			V4L2_CID_CONTRAST, 0, 63, 1, 31);
91762306a36Sopenharmony_ci	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
91862306a36Sopenharmony_ci			V4L2_CID_SATURATION, 0, 63, 1, 31);
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	if (hdl->error) {
92162306a36Sopenharmony_ci		pr_err("Could not initialize controls\n");
92262306a36Sopenharmony_ci		return hdl->error;
92362306a36Sopenharmony_ci	}
92462306a36Sopenharmony_ci	return 0;
92562306a36Sopenharmony_ci}
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci/* sub-driver description */
92862306a36Sopenharmony_cistatic const struct sd_desc sd_desc = {
92962306a36Sopenharmony_ci	.name = MODULE_NAME,
93062306a36Sopenharmony_ci	.config = sd_config,
93162306a36Sopenharmony_ci	.init = sd_init,
93262306a36Sopenharmony_ci	.init_controls = sd_init_controls,
93362306a36Sopenharmony_ci	.start = sd_start,
93462306a36Sopenharmony_ci	.stopN = sd_stopN,
93562306a36Sopenharmony_ci	.pkt_scan = sd_pkt_scan,
93662306a36Sopenharmony_ci};
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci/* -- module initialisation -- */
93962306a36Sopenharmony_cistatic const struct usb_device_id device_table[] = {
94062306a36Sopenharmony_ci	{USB_DEVICE(0x040a, 0x0300), .driver_info = KodakEZ200},
94162306a36Sopenharmony_ci	{USB_DEVICE(0x041e, 0x400a), .driver_info = CreativePCCam300},
94262306a36Sopenharmony_ci	{USB_DEVICE(0x046d, 0x0890), .driver_info = LogitechTraveler},
94362306a36Sopenharmony_ci	{USB_DEVICE(0x046d, 0x0900), .driver_info = LogitechClickSmart310},
94462306a36Sopenharmony_ci	{USB_DEVICE(0x046d, 0x0901), .driver_info = LogitechClickSmart510},
94562306a36Sopenharmony_ci	{USB_DEVICE(0x04a5, 0x300c), .driver_info = BenqDC1016},
94662306a36Sopenharmony_ci	{USB_DEVICE(0x04fc, 0x7333), .driver_info = PalmPixDC85},
94762306a36Sopenharmony_ci	{USB_DEVICE(0x055f, 0xc200), .driver_info = MustekGsmart300},
94862306a36Sopenharmony_ci	{USB_DEVICE(0x055f, 0xc220), .driver_info = Gsmartmini},
94962306a36Sopenharmony_ci	{USB_DEVICE(0x06bd, 0x0404), .driver_info = AgfaCl20},
95062306a36Sopenharmony_ci	{USB_DEVICE(0x06be, 0x0800), .driver_info = Optimedia},
95162306a36Sopenharmony_ci	{USB_DEVICE(0x084d, 0x0003), .driver_info = DLinkDSC350},
95262306a36Sopenharmony_ci	{USB_DEVICE(0x08ca, 0x0103), .driver_info = AiptekPocketDV},
95362306a36Sopenharmony_ci	{USB_DEVICE(0x2899, 0x012c), .driver_info = ToptroIndus},
95462306a36Sopenharmony_ci	{USB_DEVICE(0x8086, 0x0630), .driver_info = IntelPocketPCCamera},
95562306a36Sopenharmony_ci	{}
95662306a36Sopenharmony_ci};
95762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, device_table);
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci/* -- device connect -- */
96062306a36Sopenharmony_cistatic int sd_probe(struct usb_interface *intf,
96162306a36Sopenharmony_ci			const struct usb_device_id *id)
96262306a36Sopenharmony_ci{
96362306a36Sopenharmony_ci	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
96462306a36Sopenharmony_ci				THIS_MODULE);
96562306a36Sopenharmony_ci}
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_cistatic struct usb_driver sd_driver = {
96862306a36Sopenharmony_ci	.name = MODULE_NAME,
96962306a36Sopenharmony_ci	.id_table = device_table,
97062306a36Sopenharmony_ci	.probe = sd_probe,
97162306a36Sopenharmony_ci	.disconnect = gspca_disconnect,
97262306a36Sopenharmony_ci#ifdef CONFIG_PM
97362306a36Sopenharmony_ci	.suspend = gspca_suspend,
97462306a36Sopenharmony_ci	.resume = gspca_resume,
97562306a36Sopenharmony_ci	.reset_resume = gspca_resume,
97662306a36Sopenharmony_ci#endif
97762306a36Sopenharmony_ci};
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_cimodule_usb_driver(sd_driver);
980