1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Sunplus spca504(abc) spca533 spca536 library
4*4882a593Smuzhiyun * Copyright (C) 2005 Michel Xhaard mxhaard@magic.fr
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun #define MODULE_NAME "sunplus"
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun #include "gspca.h"
14*4882a593Smuzhiyun #include "jpeg.h"
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
17*4882a593Smuzhiyun MODULE_DESCRIPTION("GSPCA/SPCA5xx USB Camera Driver");
18*4882a593Smuzhiyun MODULE_LICENSE("GPL");
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun #define QUALITY 85
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun /* specific webcam descriptor */
23*4882a593Smuzhiyun struct sd {
24*4882a593Smuzhiyun struct gspca_dev gspca_dev; /* !! must be the first item */
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun bool autogain;
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun u8 bridge;
29*4882a593Smuzhiyun #define BRIDGE_SPCA504 0
30*4882a593Smuzhiyun #define BRIDGE_SPCA504B 1
31*4882a593Smuzhiyun #define BRIDGE_SPCA504C 2
32*4882a593Smuzhiyun #define BRIDGE_SPCA533 3
33*4882a593Smuzhiyun #define BRIDGE_SPCA536 4
34*4882a593Smuzhiyun u8 subtype;
35*4882a593Smuzhiyun #define AiptekMiniPenCam13 1
36*4882a593Smuzhiyun #define LogitechClickSmart420 2
37*4882a593Smuzhiyun #define LogitechClickSmart820 3
38*4882a593Smuzhiyun #define MegapixV4 4
39*4882a593Smuzhiyun #define MegaImageVI 5
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun u8 jpeg_hdr[JPEG_HDR_SZ];
42*4882a593Smuzhiyun };
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun static const struct v4l2_pix_format vga_mode[] = {
45*4882a593Smuzhiyun {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
46*4882a593Smuzhiyun .bytesperline = 320,
47*4882a593Smuzhiyun .sizeimage = 320 * 240 * 3 / 8 + 590,
48*4882a593Smuzhiyun .colorspace = V4L2_COLORSPACE_JPEG,
49*4882a593Smuzhiyun .priv = 2},
50*4882a593Smuzhiyun {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
51*4882a593Smuzhiyun .bytesperline = 640,
52*4882a593Smuzhiyun .sizeimage = 640 * 480 * 3 / 8 + 590,
53*4882a593Smuzhiyun .colorspace = V4L2_COLORSPACE_JPEG,
54*4882a593Smuzhiyun .priv = 1},
55*4882a593Smuzhiyun };
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun static const struct v4l2_pix_format custom_mode[] = {
58*4882a593Smuzhiyun {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
59*4882a593Smuzhiyun .bytesperline = 320,
60*4882a593Smuzhiyun .sizeimage = 320 * 240 * 3 / 8 + 590,
61*4882a593Smuzhiyun .colorspace = V4L2_COLORSPACE_JPEG,
62*4882a593Smuzhiyun .priv = 2},
63*4882a593Smuzhiyun {464, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
64*4882a593Smuzhiyun .bytesperline = 464,
65*4882a593Smuzhiyun .sizeimage = 464 * 480 * 3 / 8 + 590,
66*4882a593Smuzhiyun .colorspace = V4L2_COLORSPACE_JPEG,
67*4882a593Smuzhiyun .priv = 1},
68*4882a593Smuzhiyun };
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun static const struct v4l2_pix_format vga_mode2[] = {
71*4882a593Smuzhiyun {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
72*4882a593Smuzhiyun .bytesperline = 176,
73*4882a593Smuzhiyun .sizeimage = 176 * 144 * 3 / 8 + 590,
74*4882a593Smuzhiyun .colorspace = V4L2_COLORSPACE_JPEG,
75*4882a593Smuzhiyun .priv = 4},
76*4882a593Smuzhiyun {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
77*4882a593Smuzhiyun .bytesperline = 320,
78*4882a593Smuzhiyun .sizeimage = 320 * 240 * 3 / 8 + 590,
79*4882a593Smuzhiyun .colorspace = V4L2_COLORSPACE_JPEG,
80*4882a593Smuzhiyun .priv = 3},
81*4882a593Smuzhiyun {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
82*4882a593Smuzhiyun .bytesperline = 352,
83*4882a593Smuzhiyun .sizeimage = 352 * 288 * 3 / 8 + 590,
84*4882a593Smuzhiyun .colorspace = V4L2_COLORSPACE_JPEG,
85*4882a593Smuzhiyun .priv = 2},
86*4882a593Smuzhiyun {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
87*4882a593Smuzhiyun .bytesperline = 640,
88*4882a593Smuzhiyun .sizeimage = 640 * 480 * 3 / 8 + 590,
89*4882a593Smuzhiyun .colorspace = V4L2_COLORSPACE_JPEG,
90*4882a593Smuzhiyun .priv = 1},
91*4882a593Smuzhiyun };
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun #define SPCA50X_OFFSET_DATA 10
94*4882a593Smuzhiyun #define SPCA504_PCCAM600_OFFSET_SNAPSHOT 3
95*4882a593Smuzhiyun #define SPCA504_PCCAM600_OFFSET_COMPRESS 4
96*4882a593Smuzhiyun #define SPCA504_PCCAM600_OFFSET_MODE 5
97*4882a593Smuzhiyun #define SPCA504_PCCAM600_OFFSET_DATA 14
98*4882a593Smuzhiyun /* Frame packet header offsets for the spca533 */
99*4882a593Smuzhiyun #define SPCA533_OFFSET_DATA 16
100*4882a593Smuzhiyun #define SPCA533_OFFSET_FRAMSEQ 15
101*4882a593Smuzhiyun /* Frame packet header offsets for the spca536 */
102*4882a593Smuzhiyun #define SPCA536_OFFSET_DATA 4
103*4882a593Smuzhiyun #define SPCA536_OFFSET_FRAMSEQ 1
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun struct cmd {
106*4882a593Smuzhiyun u8 req;
107*4882a593Smuzhiyun u16 val;
108*4882a593Smuzhiyun u16 idx;
109*4882a593Smuzhiyun };
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun /* Initialisation data for the Creative PC-CAM 600 */
112*4882a593Smuzhiyun static const struct cmd spca504_pccam600_init_data[] = {
113*4882a593Smuzhiyun /* {0xa0, 0x0000, 0x0503}, * capture mode */
114*4882a593Smuzhiyun {0x00, 0x0000, 0x2000},
115*4882a593Smuzhiyun {0x00, 0x0013, 0x2301},
116*4882a593Smuzhiyun {0x00, 0x0003, 0x2000},
117*4882a593Smuzhiyun {0x00, 0x0001, 0x21ac},
118*4882a593Smuzhiyun {0x00, 0x0001, 0x21a6},
119*4882a593Smuzhiyun {0x00, 0x0000, 0x21a7}, /* brightness */
120*4882a593Smuzhiyun {0x00, 0x0020, 0x21a8}, /* contrast */
121*4882a593Smuzhiyun {0x00, 0x0001, 0x21ac}, /* sat/hue */
122*4882a593Smuzhiyun {0x00, 0x0000, 0x21ad}, /* hue */
123*4882a593Smuzhiyun {0x00, 0x001a, 0x21ae}, /* saturation */
124*4882a593Smuzhiyun {0x00, 0x0002, 0x21a3}, /* gamma */
125*4882a593Smuzhiyun {0x30, 0x0154, 0x0008},
126*4882a593Smuzhiyun {0x30, 0x0004, 0x0006},
127*4882a593Smuzhiyun {0x30, 0x0258, 0x0009},
128*4882a593Smuzhiyun {0x30, 0x0004, 0x0000},
129*4882a593Smuzhiyun {0x30, 0x0093, 0x0004},
130*4882a593Smuzhiyun {0x30, 0x0066, 0x0005},
131*4882a593Smuzhiyun {0x00, 0x0000, 0x2000},
132*4882a593Smuzhiyun {0x00, 0x0013, 0x2301},
133*4882a593Smuzhiyun {0x00, 0x0003, 0x2000},
134*4882a593Smuzhiyun {0x00, 0x0013, 0x2301},
135*4882a593Smuzhiyun {0x00, 0x0003, 0x2000},
136*4882a593Smuzhiyun };
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun /* Creative PC-CAM 600 specific open data, sent before using the
139*4882a593Smuzhiyun * generic initialisation data from spca504_open_data.
140*4882a593Smuzhiyun */
141*4882a593Smuzhiyun static const struct cmd spca504_pccam600_open_data[] = {
142*4882a593Smuzhiyun {0x00, 0x0001, 0x2501},
143*4882a593Smuzhiyun {0x20, 0x0500, 0x0001}, /* snapshot mode */
144*4882a593Smuzhiyun {0x00, 0x0003, 0x2880},
145*4882a593Smuzhiyun {0x00, 0x0001, 0x2881},
146*4882a593Smuzhiyun };
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun /* Initialisation data for the logitech clicksmart 420 */
149*4882a593Smuzhiyun static const struct cmd spca504A_clicksmart420_init_data[] = {
150*4882a593Smuzhiyun /* {0xa0, 0x0000, 0x0503}, * capture mode */
151*4882a593Smuzhiyun {0x00, 0x0000, 0x2000},
152*4882a593Smuzhiyun {0x00, 0x0013, 0x2301},
153*4882a593Smuzhiyun {0x00, 0x0003, 0x2000},
154*4882a593Smuzhiyun {0x00, 0x0001, 0x21ac},
155*4882a593Smuzhiyun {0x00, 0x0001, 0x21a6},
156*4882a593Smuzhiyun {0x00, 0x0000, 0x21a7}, /* brightness */
157*4882a593Smuzhiyun {0x00, 0x0020, 0x21a8}, /* contrast */
158*4882a593Smuzhiyun {0x00, 0x0001, 0x21ac}, /* sat/hue */
159*4882a593Smuzhiyun {0x00, 0x0000, 0x21ad}, /* hue */
160*4882a593Smuzhiyun {0x00, 0x001a, 0x21ae}, /* saturation */
161*4882a593Smuzhiyun {0x00, 0x0002, 0x21a3}, /* gamma */
162*4882a593Smuzhiyun {0x30, 0x0004, 0x000a},
163*4882a593Smuzhiyun {0xb0, 0x0001, 0x0000},
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun {0xa1, 0x0080, 0x0001},
166*4882a593Smuzhiyun {0x30, 0x0049, 0x0000},
167*4882a593Smuzhiyun {0x30, 0x0060, 0x0005},
168*4882a593Smuzhiyun {0x0c, 0x0004, 0x0000},
169*4882a593Smuzhiyun {0x00, 0x0000, 0x0000},
170*4882a593Smuzhiyun {0x00, 0x0000, 0x2000},
171*4882a593Smuzhiyun {0x00, 0x0013, 0x2301},
172*4882a593Smuzhiyun {0x00, 0x0003, 0x2000},
173*4882a593Smuzhiyun };
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun /* clicksmart 420 open data ? */
176*4882a593Smuzhiyun static const struct cmd spca504A_clicksmart420_open_data[] = {
177*4882a593Smuzhiyun {0x00, 0x0001, 0x2501},
178*4882a593Smuzhiyun {0x20, 0x0502, 0x0000},
179*4882a593Smuzhiyun {0x06, 0x0000, 0x0000},
180*4882a593Smuzhiyun {0x00, 0x0004, 0x2880},
181*4882a593Smuzhiyun {0x00, 0x0001, 0x2881},
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun {0xa0, 0x0000, 0x0503},
184*4882a593Smuzhiyun };
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun static const u8 qtable_creative_pccam[2][64] = {
187*4882a593Smuzhiyun { /* Q-table Y-components */
188*4882a593Smuzhiyun 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
189*4882a593Smuzhiyun 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
190*4882a593Smuzhiyun 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
191*4882a593Smuzhiyun 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
192*4882a593Smuzhiyun 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
193*4882a593Smuzhiyun 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
194*4882a593Smuzhiyun 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
195*4882a593Smuzhiyun 0x16, 0x1c, 0x1d, 0x1d, 0x22, 0x1e, 0x1f, 0x1e},
196*4882a593Smuzhiyun { /* Q-table C-components */
197*4882a593Smuzhiyun 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
198*4882a593Smuzhiyun 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
199*4882a593Smuzhiyun 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
200*4882a593Smuzhiyun 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
201*4882a593Smuzhiyun 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
202*4882a593Smuzhiyun 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
203*4882a593Smuzhiyun 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
204*4882a593Smuzhiyun 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
205*4882a593Smuzhiyun };
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun /* FIXME: This Q-table is identical to the Creative PC-CAM one,
208*4882a593Smuzhiyun * except for one byte. Possibly a typo?
209*4882a593Smuzhiyun * NWG: 18/05/2003.
210*4882a593Smuzhiyun */
211*4882a593Smuzhiyun static const u8 qtable_spca504_default[2][64] = {
212*4882a593Smuzhiyun { /* Q-table Y-components */
213*4882a593Smuzhiyun 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
214*4882a593Smuzhiyun 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
215*4882a593Smuzhiyun 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
216*4882a593Smuzhiyun 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
217*4882a593Smuzhiyun 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
218*4882a593Smuzhiyun 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
219*4882a593Smuzhiyun 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
220*4882a593Smuzhiyun 0x16, 0x1c, 0x1d, 0x1d, 0x1d /* 0x22 */ , 0x1e, 0x1f, 0x1e,
221*4882a593Smuzhiyun },
222*4882a593Smuzhiyun { /* Q-table C-components */
223*4882a593Smuzhiyun 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
224*4882a593Smuzhiyun 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
225*4882a593Smuzhiyun 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
226*4882a593Smuzhiyun 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
227*4882a593Smuzhiyun 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
228*4882a593Smuzhiyun 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
229*4882a593Smuzhiyun 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
230*4882a593Smuzhiyun 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
231*4882a593Smuzhiyun };
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun /* read <len> bytes to gspca_dev->usb_buf */
reg_r(struct gspca_dev * gspca_dev,u8 req,u16 index,u16 len)234*4882a593Smuzhiyun static void reg_r(struct gspca_dev *gspca_dev,
235*4882a593Smuzhiyun u8 req,
236*4882a593Smuzhiyun u16 index,
237*4882a593Smuzhiyun u16 len)
238*4882a593Smuzhiyun {
239*4882a593Smuzhiyun int ret;
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun if (len > USB_BUF_SZ) {
242*4882a593Smuzhiyun gspca_err(gspca_dev, "reg_r: buffer overflow\n");
243*4882a593Smuzhiyun return;
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun if (len == 0) {
246*4882a593Smuzhiyun gspca_err(gspca_dev, "reg_r: zero-length read\n");
247*4882a593Smuzhiyun return;
248*4882a593Smuzhiyun }
249*4882a593Smuzhiyun if (gspca_dev->usb_err < 0)
250*4882a593Smuzhiyun return;
251*4882a593Smuzhiyun ret = usb_control_msg(gspca_dev->dev,
252*4882a593Smuzhiyun usb_rcvctrlpipe(gspca_dev->dev, 0),
253*4882a593Smuzhiyun req,
254*4882a593Smuzhiyun USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
255*4882a593Smuzhiyun 0, /* value */
256*4882a593Smuzhiyun index,
257*4882a593Smuzhiyun gspca_dev->usb_buf, len,
258*4882a593Smuzhiyun 500);
259*4882a593Smuzhiyun if (ret < 0) {
260*4882a593Smuzhiyun pr_err("reg_r err %d\n", ret);
261*4882a593Smuzhiyun gspca_dev->usb_err = ret;
262*4882a593Smuzhiyun /*
263*4882a593Smuzhiyun * Make sure the buffer is zeroed to avoid uninitialized
264*4882a593Smuzhiyun * values.
265*4882a593Smuzhiyun */
266*4882a593Smuzhiyun memset(gspca_dev->usb_buf, 0, USB_BUF_SZ);
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun /* write one byte */
reg_w_1(struct gspca_dev * gspca_dev,u8 req,u16 value,u16 index,u16 byte)271*4882a593Smuzhiyun static void reg_w_1(struct gspca_dev *gspca_dev,
272*4882a593Smuzhiyun u8 req,
273*4882a593Smuzhiyun u16 value,
274*4882a593Smuzhiyun u16 index,
275*4882a593Smuzhiyun u16 byte)
276*4882a593Smuzhiyun {
277*4882a593Smuzhiyun int ret;
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun if (gspca_dev->usb_err < 0)
280*4882a593Smuzhiyun return;
281*4882a593Smuzhiyun gspca_dev->usb_buf[0] = byte;
282*4882a593Smuzhiyun ret = usb_control_msg(gspca_dev->dev,
283*4882a593Smuzhiyun usb_sndctrlpipe(gspca_dev->dev, 0),
284*4882a593Smuzhiyun req,
285*4882a593Smuzhiyun USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
286*4882a593Smuzhiyun value, index,
287*4882a593Smuzhiyun gspca_dev->usb_buf, 1,
288*4882a593Smuzhiyun 500);
289*4882a593Smuzhiyun if (ret < 0) {
290*4882a593Smuzhiyun pr_err("reg_w_1 err %d\n", ret);
291*4882a593Smuzhiyun gspca_dev->usb_err = ret;
292*4882a593Smuzhiyun }
293*4882a593Smuzhiyun }
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun /* write req / index / value */
reg_w_riv(struct gspca_dev * gspca_dev,u8 req,u16 index,u16 value)296*4882a593Smuzhiyun static void reg_w_riv(struct gspca_dev *gspca_dev,
297*4882a593Smuzhiyun u8 req, u16 index, u16 value)
298*4882a593Smuzhiyun {
299*4882a593Smuzhiyun struct usb_device *dev = gspca_dev->dev;
300*4882a593Smuzhiyun int ret;
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun if (gspca_dev->usb_err < 0)
303*4882a593Smuzhiyun return;
304*4882a593Smuzhiyun ret = usb_control_msg(dev,
305*4882a593Smuzhiyun usb_sndctrlpipe(dev, 0),
306*4882a593Smuzhiyun req,
307*4882a593Smuzhiyun USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
308*4882a593Smuzhiyun value, index, NULL, 0, 500);
309*4882a593Smuzhiyun if (ret < 0) {
310*4882a593Smuzhiyun pr_err("reg_w_riv err %d\n", ret);
311*4882a593Smuzhiyun gspca_dev->usb_err = ret;
312*4882a593Smuzhiyun return;
313*4882a593Smuzhiyun }
314*4882a593Smuzhiyun gspca_dbg(gspca_dev, D_USBO, "reg_w_riv: 0x%02x,0x%04x:0x%04x\n",
315*4882a593Smuzhiyun req, index, value);
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun
write_vector(struct gspca_dev * gspca_dev,const struct cmd * data,int ncmds)318*4882a593Smuzhiyun static void write_vector(struct gspca_dev *gspca_dev,
319*4882a593Smuzhiyun const struct cmd *data, int ncmds)
320*4882a593Smuzhiyun {
321*4882a593Smuzhiyun while (--ncmds >= 0) {
322*4882a593Smuzhiyun reg_w_riv(gspca_dev, data->req, data->idx, data->val);
323*4882a593Smuzhiyun data++;
324*4882a593Smuzhiyun }
325*4882a593Smuzhiyun }
326*4882a593Smuzhiyun
setup_qtable(struct gspca_dev * gspca_dev,const u8 qtable[2][64])327*4882a593Smuzhiyun static void setup_qtable(struct gspca_dev *gspca_dev,
328*4882a593Smuzhiyun const u8 qtable[2][64])
329*4882a593Smuzhiyun {
330*4882a593Smuzhiyun int i;
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun /* loop over y components */
333*4882a593Smuzhiyun for (i = 0; i < 64; i++)
334*4882a593Smuzhiyun reg_w_riv(gspca_dev, 0x00, 0x2800 + i, qtable[0][i]);
335*4882a593Smuzhiyun
336*4882a593Smuzhiyun /* loop over c components */
337*4882a593Smuzhiyun for (i = 0; i < 64; i++)
338*4882a593Smuzhiyun reg_w_riv(gspca_dev, 0x00, 0x2840 + i, qtable[1][i]);
339*4882a593Smuzhiyun }
340*4882a593Smuzhiyun
spca504_acknowledged_command(struct gspca_dev * gspca_dev,u8 req,u16 idx,u16 val)341*4882a593Smuzhiyun static void spca504_acknowledged_command(struct gspca_dev *gspca_dev,
342*4882a593Smuzhiyun u8 req, u16 idx, u16 val)
343*4882a593Smuzhiyun {
344*4882a593Smuzhiyun reg_w_riv(gspca_dev, req, idx, val);
345*4882a593Smuzhiyun reg_r(gspca_dev, 0x01, 0x0001, 1);
346*4882a593Smuzhiyun gspca_dbg(gspca_dev, D_FRAM, "before wait 0x%04x\n",
347*4882a593Smuzhiyun gspca_dev->usb_buf[0]);
348*4882a593Smuzhiyun reg_w_riv(gspca_dev, req, idx, val);
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun msleep(200);
351*4882a593Smuzhiyun reg_r(gspca_dev, 0x01, 0x0001, 1);
352*4882a593Smuzhiyun gspca_dbg(gspca_dev, D_FRAM, "after wait 0x%04x\n",
353*4882a593Smuzhiyun gspca_dev->usb_buf[0]);
354*4882a593Smuzhiyun }
355*4882a593Smuzhiyun
spca504_read_info(struct gspca_dev * gspca_dev)356*4882a593Smuzhiyun static void spca504_read_info(struct gspca_dev *gspca_dev)
357*4882a593Smuzhiyun {
358*4882a593Smuzhiyun int i;
359*4882a593Smuzhiyun u8 info[6];
360*4882a593Smuzhiyun
361*4882a593Smuzhiyun if (gspca_debug < D_STREAM)
362*4882a593Smuzhiyun return;
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun for (i = 0; i < 6; i++) {
365*4882a593Smuzhiyun reg_r(gspca_dev, 0, i, 1);
366*4882a593Smuzhiyun info[i] = gspca_dev->usb_buf[0];
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun gspca_dbg(gspca_dev, D_STREAM,
369*4882a593Smuzhiyun "Read info: %d %d %d %d %d %d. Should be 1,0,2,2,0,0\n",
370*4882a593Smuzhiyun info[0], info[1], info[2],
371*4882a593Smuzhiyun info[3], info[4], info[5]);
372*4882a593Smuzhiyun }
373*4882a593Smuzhiyun
spca504A_acknowledged_command(struct gspca_dev * gspca_dev,u8 req,u16 idx,u16 val,u8 endcode,u8 count)374*4882a593Smuzhiyun static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev,
375*4882a593Smuzhiyun u8 req,
376*4882a593Smuzhiyun u16 idx, u16 val, u8 endcode, u8 count)
377*4882a593Smuzhiyun {
378*4882a593Smuzhiyun u16 status;
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun reg_w_riv(gspca_dev, req, idx, val);
381*4882a593Smuzhiyun reg_r(gspca_dev, 0x01, 0x0001, 1);
382*4882a593Smuzhiyun if (gspca_dev->usb_err < 0)
383*4882a593Smuzhiyun return;
384*4882a593Smuzhiyun gspca_dbg(gspca_dev, D_FRAM, "Status 0x%02x Need 0x%02x\n",
385*4882a593Smuzhiyun gspca_dev->usb_buf[0], endcode);
386*4882a593Smuzhiyun if (!count)
387*4882a593Smuzhiyun return;
388*4882a593Smuzhiyun count = 200;
389*4882a593Smuzhiyun while (--count > 0) {
390*4882a593Smuzhiyun msleep(10);
391*4882a593Smuzhiyun /* gsmart mini2 write a each wait setting 1 ms is enough */
392*4882a593Smuzhiyun /* reg_w_riv(gspca_dev, req, idx, val); */
393*4882a593Smuzhiyun reg_r(gspca_dev, 0x01, 0x0001, 1);
394*4882a593Smuzhiyun status = gspca_dev->usb_buf[0];
395*4882a593Smuzhiyun if (status == endcode) {
396*4882a593Smuzhiyun gspca_dbg(gspca_dev, D_FRAM, "status 0x%04x after wait %d\n",
397*4882a593Smuzhiyun status, 200 - count);
398*4882a593Smuzhiyun break;
399*4882a593Smuzhiyun }
400*4882a593Smuzhiyun }
401*4882a593Smuzhiyun }
402*4882a593Smuzhiyun
spca504B_PollingDataReady(struct gspca_dev * gspca_dev)403*4882a593Smuzhiyun static void spca504B_PollingDataReady(struct gspca_dev *gspca_dev)
404*4882a593Smuzhiyun {
405*4882a593Smuzhiyun int count = 10;
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun while (--count > 0) {
408*4882a593Smuzhiyun reg_r(gspca_dev, 0x21, 0, 1);
409*4882a593Smuzhiyun if ((gspca_dev->usb_buf[0] & 0x01) == 0)
410*4882a593Smuzhiyun break;
411*4882a593Smuzhiyun msleep(10);
412*4882a593Smuzhiyun }
413*4882a593Smuzhiyun }
414*4882a593Smuzhiyun
spca504B_WaitCmdStatus(struct gspca_dev * gspca_dev)415*4882a593Smuzhiyun static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev)
416*4882a593Smuzhiyun {
417*4882a593Smuzhiyun int count = 50;
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun while (--count > 0) {
420*4882a593Smuzhiyun reg_r(gspca_dev, 0x21, 1, 1);
421*4882a593Smuzhiyun if (gspca_dev->usb_buf[0] != 0) {
422*4882a593Smuzhiyun reg_w_1(gspca_dev, 0x21, 0, 1, 0);
423*4882a593Smuzhiyun reg_r(gspca_dev, 0x21, 1, 1);
424*4882a593Smuzhiyun spca504B_PollingDataReady(gspca_dev);
425*4882a593Smuzhiyun break;
426*4882a593Smuzhiyun }
427*4882a593Smuzhiyun msleep(10);
428*4882a593Smuzhiyun }
429*4882a593Smuzhiyun }
430*4882a593Smuzhiyun
spca50x_GetFirmware(struct gspca_dev * gspca_dev)431*4882a593Smuzhiyun static void spca50x_GetFirmware(struct gspca_dev *gspca_dev)
432*4882a593Smuzhiyun {
433*4882a593Smuzhiyun u8 *data;
434*4882a593Smuzhiyun
435*4882a593Smuzhiyun if (gspca_debug < D_STREAM)
436*4882a593Smuzhiyun return;
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun data = gspca_dev->usb_buf;
439*4882a593Smuzhiyun reg_r(gspca_dev, 0x20, 0, 5);
440*4882a593Smuzhiyun gspca_dbg(gspca_dev, D_STREAM, "FirmWare: %d %d %d %d %d\n",
441*4882a593Smuzhiyun data[0], data[1], data[2], data[3], data[4]);
442*4882a593Smuzhiyun reg_r(gspca_dev, 0x23, 0, 64);
443*4882a593Smuzhiyun reg_r(gspca_dev, 0x23, 1, 64);
444*4882a593Smuzhiyun }
445*4882a593Smuzhiyun
spca504B_SetSizeType(struct gspca_dev * gspca_dev)446*4882a593Smuzhiyun static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
447*4882a593Smuzhiyun {
448*4882a593Smuzhiyun struct sd *sd = (struct sd *) gspca_dev;
449*4882a593Smuzhiyun u8 Size;
450*4882a593Smuzhiyun
451*4882a593Smuzhiyun Size = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
452*4882a593Smuzhiyun switch (sd->bridge) {
453*4882a593Smuzhiyun case BRIDGE_SPCA533:
454*4882a593Smuzhiyun reg_w_riv(gspca_dev, 0x31, 0, 0);
455*4882a593Smuzhiyun spca504B_WaitCmdStatus(gspca_dev);
456*4882a593Smuzhiyun spca504B_PollingDataReady(gspca_dev);
457*4882a593Smuzhiyun spca50x_GetFirmware(gspca_dev);
458*4882a593Smuzhiyun
459*4882a593Smuzhiyun reg_w_1(gspca_dev, 0x24, 0, 8, 2); /* type */
460*4882a593Smuzhiyun reg_r(gspca_dev, 0x24, 8, 1);
461*4882a593Smuzhiyun
462*4882a593Smuzhiyun reg_w_1(gspca_dev, 0x25, 0, 4, Size);
463*4882a593Smuzhiyun reg_r(gspca_dev, 0x25, 4, 1); /* size */
464*4882a593Smuzhiyun spca504B_PollingDataReady(gspca_dev);
465*4882a593Smuzhiyun
466*4882a593Smuzhiyun /* Init the cam width height with some values get on init ? */
467*4882a593Smuzhiyun reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00);
468*4882a593Smuzhiyun spca504B_WaitCmdStatus(gspca_dev);
469*4882a593Smuzhiyun spca504B_PollingDataReady(gspca_dev);
470*4882a593Smuzhiyun break;
471*4882a593Smuzhiyun default:
472*4882a593Smuzhiyun /* case BRIDGE_SPCA504B: */
473*4882a593Smuzhiyun /* case BRIDGE_SPCA536: */
474*4882a593Smuzhiyun reg_w_1(gspca_dev, 0x25, 0, 4, Size);
475*4882a593Smuzhiyun reg_r(gspca_dev, 0x25, 4, 1); /* size */
476*4882a593Smuzhiyun reg_w_1(gspca_dev, 0x27, 0, 0, 6);
477*4882a593Smuzhiyun reg_r(gspca_dev, 0x27, 0, 1); /* type */
478*4882a593Smuzhiyun spca504B_PollingDataReady(gspca_dev);
479*4882a593Smuzhiyun break;
480*4882a593Smuzhiyun case BRIDGE_SPCA504:
481*4882a593Smuzhiyun Size += 3;
482*4882a593Smuzhiyun if (sd->subtype == AiptekMiniPenCam13) {
483*4882a593Smuzhiyun /* spca504a aiptek */
484*4882a593Smuzhiyun spca504A_acknowledged_command(gspca_dev,
485*4882a593Smuzhiyun 0x08, Size, 0,
486*4882a593Smuzhiyun 0x80 | (Size & 0x0f), 1);
487*4882a593Smuzhiyun spca504A_acknowledged_command(gspca_dev,
488*4882a593Smuzhiyun 1, 3, 0, 0x9f, 0);
489*4882a593Smuzhiyun } else {
490*4882a593Smuzhiyun spca504_acknowledged_command(gspca_dev, 0x08, Size, 0);
491*4882a593Smuzhiyun }
492*4882a593Smuzhiyun break;
493*4882a593Smuzhiyun case BRIDGE_SPCA504C:
494*4882a593Smuzhiyun /* capture mode */
495*4882a593Smuzhiyun reg_w_riv(gspca_dev, 0xa0, (0x0500 | (Size & 0x0f)), 0x00);
496*4882a593Smuzhiyun reg_w_riv(gspca_dev, 0x20, 0x01, 0x0500 | (Size & 0x0f));
497*4882a593Smuzhiyun break;
498*4882a593Smuzhiyun }
499*4882a593Smuzhiyun }
500*4882a593Smuzhiyun
spca504_wait_status(struct gspca_dev * gspca_dev)501*4882a593Smuzhiyun static void spca504_wait_status(struct gspca_dev *gspca_dev)
502*4882a593Smuzhiyun {
503*4882a593Smuzhiyun int cnt;
504*4882a593Smuzhiyun
505*4882a593Smuzhiyun cnt = 256;
506*4882a593Smuzhiyun while (--cnt > 0) {
507*4882a593Smuzhiyun /* With this we get the status, when return 0 it's all ok */
508*4882a593Smuzhiyun reg_r(gspca_dev, 0x06, 0x00, 1);
509*4882a593Smuzhiyun if (gspca_dev->usb_buf[0] == 0)
510*4882a593Smuzhiyun return;
511*4882a593Smuzhiyun msleep(10);
512*4882a593Smuzhiyun }
513*4882a593Smuzhiyun }
514*4882a593Smuzhiyun
spca504B_setQtable(struct gspca_dev * gspca_dev)515*4882a593Smuzhiyun static void spca504B_setQtable(struct gspca_dev *gspca_dev)
516*4882a593Smuzhiyun {
517*4882a593Smuzhiyun reg_w_1(gspca_dev, 0x26, 0, 0, 3);
518*4882a593Smuzhiyun reg_r(gspca_dev, 0x26, 0, 1);
519*4882a593Smuzhiyun spca504B_PollingDataReady(gspca_dev);
520*4882a593Smuzhiyun }
521*4882a593Smuzhiyun
setbrightness(struct gspca_dev * gspca_dev,s32 val)522*4882a593Smuzhiyun static void setbrightness(struct gspca_dev *gspca_dev, s32 val)
523*4882a593Smuzhiyun {
524*4882a593Smuzhiyun struct sd *sd = (struct sd *) gspca_dev;
525*4882a593Smuzhiyun u16 reg;
526*4882a593Smuzhiyun
527*4882a593Smuzhiyun reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f0 : 0x21a7;
528*4882a593Smuzhiyun reg_w_riv(gspca_dev, 0x00, reg, val);
529*4882a593Smuzhiyun }
530*4882a593Smuzhiyun
setcontrast(struct gspca_dev * gspca_dev,s32 val)531*4882a593Smuzhiyun static void setcontrast(struct gspca_dev *gspca_dev, s32 val)
532*4882a593Smuzhiyun {
533*4882a593Smuzhiyun struct sd *sd = (struct sd *) gspca_dev;
534*4882a593Smuzhiyun u16 reg;
535*4882a593Smuzhiyun
536*4882a593Smuzhiyun reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f1 : 0x21a8;
537*4882a593Smuzhiyun reg_w_riv(gspca_dev, 0x00, reg, val);
538*4882a593Smuzhiyun }
539*4882a593Smuzhiyun
setcolors(struct gspca_dev * gspca_dev,s32 val)540*4882a593Smuzhiyun static void setcolors(struct gspca_dev *gspca_dev, s32 val)
541*4882a593Smuzhiyun {
542*4882a593Smuzhiyun struct sd *sd = (struct sd *) gspca_dev;
543*4882a593Smuzhiyun u16 reg;
544*4882a593Smuzhiyun
545*4882a593Smuzhiyun reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f6 : 0x21ae;
546*4882a593Smuzhiyun reg_w_riv(gspca_dev, 0x00, reg, val);
547*4882a593Smuzhiyun }
548*4882a593Smuzhiyun
init_ctl_reg(struct gspca_dev * gspca_dev)549*4882a593Smuzhiyun static void init_ctl_reg(struct gspca_dev *gspca_dev)
550*4882a593Smuzhiyun {
551*4882a593Smuzhiyun struct sd *sd = (struct sd *) gspca_dev;
552*4882a593Smuzhiyun int pollreg = 1;
553*4882a593Smuzhiyun
554*4882a593Smuzhiyun switch (sd->bridge) {
555*4882a593Smuzhiyun case BRIDGE_SPCA504:
556*4882a593Smuzhiyun case BRIDGE_SPCA504C:
557*4882a593Smuzhiyun pollreg = 0;
558*4882a593Smuzhiyun fallthrough;
559*4882a593Smuzhiyun default:
560*4882a593Smuzhiyun /* case BRIDGE_SPCA533: */
561*4882a593Smuzhiyun /* case BRIDGE_SPCA504B: */
562*4882a593Smuzhiyun reg_w_riv(gspca_dev, 0, 0x21ad, 0x00); /* hue */
563*4882a593Smuzhiyun reg_w_riv(gspca_dev, 0, 0x21ac, 0x01); /* sat/hue */
564*4882a593Smuzhiyun reg_w_riv(gspca_dev, 0, 0x21a3, 0x00); /* gamma */
565*4882a593Smuzhiyun break;
566*4882a593Smuzhiyun case BRIDGE_SPCA536:
567*4882a593Smuzhiyun reg_w_riv(gspca_dev, 0, 0x20f5, 0x40);
568*4882a593Smuzhiyun reg_w_riv(gspca_dev, 0, 0x20f4, 0x01);
569*4882a593Smuzhiyun reg_w_riv(gspca_dev, 0, 0x2089, 0x00);
570*4882a593Smuzhiyun break;
571*4882a593Smuzhiyun }
572*4882a593Smuzhiyun if (pollreg)
573*4882a593Smuzhiyun spca504B_PollingDataReady(gspca_dev);
574*4882a593Smuzhiyun }
575*4882a593Smuzhiyun
576*4882a593Smuzhiyun /* this function is called at probe time */
sd_config(struct gspca_dev * gspca_dev,const struct usb_device_id * id)577*4882a593Smuzhiyun static int sd_config(struct gspca_dev *gspca_dev,
578*4882a593Smuzhiyun const struct usb_device_id *id)
579*4882a593Smuzhiyun {
580*4882a593Smuzhiyun struct sd *sd = (struct sd *) gspca_dev;
581*4882a593Smuzhiyun struct cam *cam;
582*4882a593Smuzhiyun
583*4882a593Smuzhiyun cam = &gspca_dev->cam;
584*4882a593Smuzhiyun
585*4882a593Smuzhiyun sd->bridge = id->driver_info >> 8;
586*4882a593Smuzhiyun sd->subtype = id->driver_info;
587*4882a593Smuzhiyun
588*4882a593Smuzhiyun if (sd->subtype == AiptekMiniPenCam13) {
589*4882a593Smuzhiyun
590*4882a593Smuzhiyun /* try to get the firmware as some cam answer 2.0.1.2.2
591*4882a593Smuzhiyun * and should be a spca504b then overwrite that setting */
592*4882a593Smuzhiyun reg_r(gspca_dev, 0x20, 0, 1);
593*4882a593Smuzhiyun switch (gspca_dev->usb_buf[0]) {
594*4882a593Smuzhiyun case 1:
595*4882a593Smuzhiyun break; /* (right bridge/subtype) */
596*4882a593Smuzhiyun case 2:
597*4882a593Smuzhiyun sd->bridge = BRIDGE_SPCA504B;
598*4882a593Smuzhiyun sd->subtype = 0;
599*4882a593Smuzhiyun break;
600*4882a593Smuzhiyun default:
601*4882a593Smuzhiyun return -ENODEV;
602*4882a593Smuzhiyun }
603*4882a593Smuzhiyun }
604*4882a593Smuzhiyun
605*4882a593Smuzhiyun switch (sd->bridge) {
606*4882a593Smuzhiyun default:
607*4882a593Smuzhiyun /* case BRIDGE_SPCA504B: */
608*4882a593Smuzhiyun /* case BRIDGE_SPCA504: */
609*4882a593Smuzhiyun /* case BRIDGE_SPCA536: */
610*4882a593Smuzhiyun cam->cam_mode = vga_mode;
611*4882a593Smuzhiyun cam->nmodes = ARRAY_SIZE(vga_mode);
612*4882a593Smuzhiyun break;
613*4882a593Smuzhiyun case BRIDGE_SPCA533:
614*4882a593Smuzhiyun cam->cam_mode = custom_mode;
615*4882a593Smuzhiyun if (sd->subtype == MegaImageVI) /* 320x240 only */
616*4882a593Smuzhiyun cam->nmodes = ARRAY_SIZE(custom_mode) - 1;
617*4882a593Smuzhiyun else
618*4882a593Smuzhiyun cam->nmodes = ARRAY_SIZE(custom_mode);
619*4882a593Smuzhiyun break;
620*4882a593Smuzhiyun case BRIDGE_SPCA504C:
621*4882a593Smuzhiyun cam->cam_mode = vga_mode2;
622*4882a593Smuzhiyun cam->nmodes = ARRAY_SIZE(vga_mode2);
623*4882a593Smuzhiyun break;
624*4882a593Smuzhiyun }
625*4882a593Smuzhiyun return 0;
626*4882a593Smuzhiyun }
627*4882a593Smuzhiyun
628*4882a593Smuzhiyun /* this function is called at probe and resume time */
sd_init(struct gspca_dev * gspca_dev)629*4882a593Smuzhiyun static int sd_init(struct gspca_dev *gspca_dev)
630*4882a593Smuzhiyun {
631*4882a593Smuzhiyun struct sd *sd = (struct sd *) gspca_dev;
632*4882a593Smuzhiyun
633*4882a593Smuzhiyun switch (sd->bridge) {
634*4882a593Smuzhiyun case BRIDGE_SPCA504B:
635*4882a593Smuzhiyun reg_w_riv(gspca_dev, 0x1d, 0x00, 0);
636*4882a593Smuzhiyun reg_w_riv(gspca_dev, 0x00, 0x2306, 0x01);
637*4882a593Smuzhiyun reg_w_riv(gspca_dev, 0x00, 0x0d04, 0x00);
638*4882a593Smuzhiyun reg_w_riv(gspca_dev, 0x00, 0x2000, 0x00);
639*4882a593Smuzhiyun reg_w_riv(gspca_dev, 0x00, 0x2301, 0x13);
640*4882a593Smuzhiyun reg_w_riv(gspca_dev, 0x00, 0x2306, 0x00);
641*4882a593Smuzhiyun fallthrough;
642*4882a593Smuzhiyun case BRIDGE_SPCA533:
643*4882a593Smuzhiyun spca504B_PollingDataReady(gspca_dev);
644*4882a593Smuzhiyun spca50x_GetFirmware(gspca_dev);
645*4882a593Smuzhiyun break;
646*4882a593Smuzhiyun case BRIDGE_SPCA536:
647*4882a593Smuzhiyun spca50x_GetFirmware(gspca_dev);
648*4882a593Smuzhiyun reg_r(gspca_dev, 0x00, 0x5002, 1);
649*4882a593Smuzhiyun reg_w_1(gspca_dev, 0x24, 0, 0, 0);
650*4882a593Smuzhiyun reg_r(gspca_dev, 0x24, 0, 1);
651*4882a593Smuzhiyun spca504B_PollingDataReady(gspca_dev);
652*4882a593Smuzhiyun reg_w_riv(gspca_dev, 0x34, 0, 0);
653*4882a593Smuzhiyun spca504B_WaitCmdStatus(gspca_dev);
654*4882a593Smuzhiyun break;
655*4882a593Smuzhiyun case BRIDGE_SPCA504C: /* pccam600 */
656*4882a593Smuzhiyun gspca_dbg(gspca_dev, D_STREAM, "Opening SPCA504 (PC-CAM 600)\n");
657*4882a593Smuzhiyun reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0000);
658*4882a593Smuzhiyun reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0001); /* reset */
659*4882a593Smuzhiyun spca504_wait_status(gspca_dev);
660*4882a593Smuzhiyun if (sd->subtype == LogitechClickSmart420)
661*4882a593Smuzhiyun write_vector(gspca_dev,
662*4882a593Smuzhiyun spca504A_clicksmart420_open_data,
663*4882a593Smuzhiyun ARRAY_SIZE(spca504A_clicksmart420_open_data));
664*4882a593Smuzhiyun else
665*4882a593Smuzhiyun write_vector(gspca_dev, spca504_pccam600_open_data,
666*4882a593Smuzhiyun ARRAY_SIZE(spca504_pccam600_open_data));
667*4882a593Smuzhiyun setup_qtable(gspca_dev, qtable_creative_pccam);
668*4882a593Smuzhiyun break;
669*4882a593Smuzhiyun default:
670*4882a593Smuzhiyun /* case BRIDGE_SPCA504: */
671*4882a593Smuzhiyun gspca_dbg(gspca_dev, D_STREAM, "Opening SPCA504\n");
672*4882a593Smuzhiyun if (sd->subtype == AiptekMiniPenCam13) {
673*4882a593Smuzhiyun spca504_read_info(gspca_dev);
674*4882a593Smuzhiyun
675*4882a593Smuzhiyun /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
676*4882a593Smuzhiyun spca504A_acknowledged_command(gspca_dev, 0x24,
677*4882a593Smuzhiyun 8, 3, 0x9e, 1);
678*4882a593Smuzhiyun /* Twice sequential need status 0xff->0x9e->0x9d */
679*4882a593Smuzhiyun spca504A_acknowledged_command(gspca_dev, 0x24,
680*4882a593Smuzhiyun 8, 3, 0x9e, 0);
681*4882a593Smuzhiyun
682*4882a593Smuzhiyun spca504A_acknowledged_command(gspca_dev, 0x24,
683*4882a593Smuzhiyun 0, 0, 0x9d, 1);
684*4882a593Smuzhiyun /******************************/
685*4882a593Smuzhiyun /* spca504a aiptek */
686*4882a593Smuzhiyun spca504A_acknowledged_command(gspca_dev, 0x08,
687*4882a593Smuzhiyun 6, 0, 0x86, 1);
688*4882a593Smuzhiyun /* reg_write (dev, 0, 0x2000, 0); */
689*4882a593Smuzhiyun /* reg_write (dev, 0, 0x2883, 1); */
690*4882a593Smuzhiyun /* spca504A_acknowledged_command (gspca_dev, 0x08,
691*4882a593Smuzhiyun 6, 0, 0x86, 1); */
692*4882a593Smuzhiyun /* spca504A_acknowledged_command (gspca_dev, 0x24,
693*4882a593Smuzhiyun 0, 0, 0x9D, 1); */
694*4882a593Smuzhiyun reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05);
695*4882a593Smuzhiyun /* L92 sno1t.txt */
696*4882a593Smuzhiyun reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05);
697*4882a593Smuzhiyun spca504A_acknowledged_command(gspca_dev, 0x01,
698*4882a593Smuzhiyun 0x0f, 0, 0xff, 0);
699*4882a593Smuzhiyun }
700*4882a593Smuzhiyun /* setup qtable */
701*4882a593Smuzhiyun reg_w_riv(gspca_dev, 0, 0x2000, 0);
702*4882a593Smuzhiyun reg_w_riv(gspca_dev, 0, 0x2883, 1);
703*4882a593Smuzhiyun setup_qtable(gspca_dev, qtable_spca504_default);
704*4882a593Smuzhiyun break;
705*4882a593Smuzhiyun }
706*4882a593Smuzhiyun return gspca_dev->usb_err;
707*4882a593Smuzhiyun }
708*4882a593Smuzhiyun
sd_start(struct gspca_dev * gspca_dev)709*4882a593Smuzhiyun static int sd_start(struct gspca_dev *gspca_dev)
710*4882a593Smuzhiyun {
711*4882a593Smuzhiyun struct sd *sd = (struct sd *) gspca_dev;
712*4882a593Smuzhiyun int enable;
713*4882a593Smuzhiyun
714*4882a593Smuzhiyun /* create the JPEG header */
715*4882a593Smuzhiyun jpeg_define(sd->jpeg_hdr, gspca_dev->pixfmt.height,
716*4882a593Smuzhiyun gspca_dev->pixfmt.width,
717*4882a593Smuzhiyun 0x22); /* JPEG 411 */
718*4882a593Smuzhiyun jpeg_set_qual(sd->jpeg_hdr, QUALITY);
719*4882a593Smuzhiyun
720*4882a593Smuzhiyun if (sd->bridge == BRIDGE_SPCA504B)
721*4882a593Smuzhiyun spca504B_setQtable(gspca_dev);
722*4882a593Smuzhiyun spca504B_SetSizeType(gspca_dev);
723*4882a593Smuzhiyun switch (sd->bridge) {
724*4882a593Smuzhiyun default:
725*4882a593Smuzhiyun /* case BRIDGE_SPCA504B: */
726*4882a593Smuzhiyun /* case BRIDGE_SPCA533: */
727*4882a593Smuzhiyun /* case BRIDGE_SPCA536: */
728*4882a593Smuzhiyun switch (sd->subtype) {
729*4882a593Smuzhiyun case MegapixV4:
730*4882a593Smuzhiyun case LogitechClickSmart820:
731*4882a593Smuzhiyun case MegaImageVI:
732*4882a593Smuzhiyun reg_w_riv(gspca_dev, 0xf0, 0, 0);
733*4882a593Smuzhiyun spca504B_WaitCmdStatus(gspca_dev);
734*4882a593Smuzhiyun reg_w_riv(gspca_dev, 0xf0, 4, 0);
735*4882a593Smuzhiyun spca504B_WaitCmdStatus(gspca_dev);
736*4882a593Smuzhiyun break;
737*4882a593Smuzhiyun default:
738*4882a593Smuzhiyun reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00);
739*4882a593Smuzhiyun spca504B_WaitCmdStatus(gspca_dev);
740*4882a593Smuzhiyun spca504B_PollingDataReady(gspca_dev);
741*4882a593Smuzhiyun break;
742*4882a593Smuzhiyun }
743*4882a593Smuzhiyun break;
744*4882a593Smuzhiyun case BRIDGE_SPCA504:
745*4882a593Smuzhiyun if (sd->subtype == AiptekMiniPenCam13) {
746*4882a593Smuzhiyun spca504_read_info(gspca_dev);
747*4882a593Smuzhiyun
748*4882a593Smuzhiyun /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
749*4882a593Smuzhiyun spca504A_acknowledged_command(gspca_dev, 0x24,
750*4882a593Smuzhiyun 8, 3, 0x9e, 1);
751*4882a593Smuzhiyun /* Twice sequential need status 0xff->0x9e->0x9d */
752*4882a593Smuzhiyun spca504A_acknowledged_command(gspca_dev, 0x24,
753*4882a593Smuzhiyun 8, 3, 0x9e, 0);
754*4882a593Smuzhiyun spca504A_acknowledged_command(gspca_dev, 0x24,
755*4882a593Smuzhiyun 0, 0, 0x9d, 1);
756*4882a593Smuzhiyun } else {
757*4882a593Smuzhiyun spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
758*4882a593Smuzhiyun spca504_read_info(gspca_dev);
759*4882a593Smuzhiyun spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
760*4882a593Smuzhiyun spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
761*4882a593Smuzhiyun }
762*4882a593Smuzhiyun spca504B_SetSizeType(gspca_dev);
763*4882a593Smuzhiyun reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05);
764*4882a593Smuzhiyun /* L92 sno1t.txt */
765*4882a593Smuzhiyun reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05);
766*4882a593Smuzhiyun break;
767*4882a593Smuzhiyun case BRIDGE_SPCA504C:
768*4882a593Smuzhiyun if (sd->subtype == LogitechClickSmart420) {
769*4882a593Smuzhiyun write_vector(gspca_dev,
770*4882a593Smuzhiyun spca504A_clicksmart420_init_data,
771*4882a593Smuzhiyun ARRAY_SIZE(spca504A_clicksmart420_init_data));
772*4882a593Smuzhiyun } else {
773*4882a593Smuzhiyun write_vector(gspca_dev, spca504_pccam600_init_data,
774*4882a593Smuzhiyun ARRAY_SIZE(spca504_pccam600_init_data));
775*4882a593Smuzhiyun }
776*4882a593Smuzhiyun enable = (sd->autogain ? 0x04 : 0x01);
777*4882a593Smuzhiyun reg_w_riv(gspca_dev, 0x0c, 0x0000, enable);
778*4882a593Smuzhiyun /* auto exposure */
779*4882a593Smuzhiyun reg_w_riv(gspca_dev, 0xb0, 0x0000, enable);
780*4882a593Smuzhiyun /* auto whiteness */
781*4882a593Smuzhiyun
782*4882a593Smuzhiyun /* set default exposure compensation and whiteness balance */
783*4882a593Smuzhiyun reg_w_riv(gspca_dev, 0x30, 0x0001, 800); /* ~ 20 fps */
784*4882a593Smuzhiyun reg_w_riv(gspca_dev, 0x30, 0x0002, 1600);
785*4882a593Smuzhiyun spca504B_SetSizeType(gspca_dev);
786*4882a593Smuzhiyun break;
787*4882a593Smuzhiyun }
788*4882a593Smuzhiyun init_ctl_reg(gspca_dev);
789*4882a593Smuzhiyun return gspca_dev->usb_err;
790*4882a593Smuzhiyun }
791*4882a593Smuzhiyun
sd_stopN(struct gspca_dev * gspca_dev)792*4882a593Smuzhiyun static void sd_stopN(struct gspca_dev *gspca_dev)
793*4882a593Smuzhiyun {
794*4882a593Smuzhiyun struct sd *sd = (struct sd *) gspca_dev;
795*4882a593Smuzhiyun
796*4882a593Smuzhiyun switch (sd->bridge) {
797*4882a593Smuzhiyun default:
798*4882a593Smuzhiyun /* case BRIDGE_SPCA533: */
799*4882a593Smuzhiyun /* case BRIDGE_SPCA536: */
800*4882a593Smuzhiyun /* case BRIDGE_SPCA504B: */
801*4882a593Smuzhiyun reg_w_riv(gspca_dev, 0x31, 0, 0);
802*4882a593Smuzhiyun spca504B_WaitCmdStatus(gspca_dev);
803*4882a593Smuzhiyun spca504B_PollingDataReady(gspca_dev);
804*4882a593Smuzhiyun break;
805*4882a593Smuzhiyun case BRIDGE_SPCA504:
806*4882a593Smuzhiyun case BRIDGE_SPCA504C:
807*4882a593Smuzhiyun reg_w_riv(gspca_dev, 0x00, 0x2000, 0x0000);
808*4882a593Smuzhiyun
809*4882a593Smuzhiyun if (sd->subtype == AiptekMiniPenCam13) {
810*4882a593Smuzhiyun /* spca504a aiptek */
811*4882a593Smuzhiyun /* spca504A_acknowledged_command(gspca_dev, 0x08,
812*4882a593Smuzhiyun 6, 0, 0x86, 1); */
813*4882a593Smuzhiyun spca504A_acknowledged_command(gspca_dev, 0x24,
814*4882a593Smuzhiyun 0x00, 0x00, 0x9d, 1);
815*4882a593Smuzhiyun spca504A_acknowledged_command(gspca_dev, 0x01,
816*4882a593Smuzhiyun 0x0f, 0x00, 0xff, 1);
817*4882a593Smuzhiyun } else {
818*4882a593Smuzhiyun spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
819*4882a593Smuzhiyun reg_w_riv(gspca_dev, 0x01, 0x000f, 0x0000);
820*4882a593Smuzhiyun }
821*4882a593Smuzhiyun break;
822*4882a593Smuzhiyun }
823*4882a593Smuzhiyun }
824*4882a593Smuzhiyun
sd_pkt_scan(struct gspca_dev * gspca_dev,u8 * data,int len)825*4882a593Smuzhiyun static void sd_pkt_scan(struct gspca_dev *gspca_dev,
826*4882a593Smuzhiyun u8 *data, /* isoc packet */
827*4882a593Smuzhiyun int len) /* iso packet length */
828*4882a593Smuzhiyun {
829*4882a593Smuzhiyun struct sd *sd = (struct sd *) gspca_dev;
830*4882a593Smuzhiyun int i, sof = 0;
831*4882a593Smuzhiyun static u8 ffd9[] = {0xff, 0xd9};
832*4882a593Smuzhiyun
833*4882a593Smuzhiyun /* frames are jpeg 4.1.1 without 0xff escape */
834*4882a593Smuzhiyun switch (sd->bridge) {
835*4882a593Smuzhiyun case BRIDGE_SPCA533:
836*4882a593Smuzhiyun if (data[0] == 0xff) {
837*4882a593Smuzhiyun if (data[1] != 0x01) { /* drop packet */
838*4882a593Smuzhiyun /* gspca_dev->last_packet_type = DISCARD_PACKET; */
839*4882a593Smuzhiyun return;
840*4882a593Smuzhiyun }
841*4882a593Smuzhiyun sof = 1;
842*4882a593Smuzhiyun data += SPCA533_OFFSET_DATA;
843*4882a593Smuzhiyun len -= SPCA533_OFFSET_DATA;
844*4882a593Smuzhiyun } else {
845*4882a593Smuzhiyun data += 1;
846*4882a593Smuzhiyun len -= 1;
847*4882a593Smuzhiyun }
848*4882a593Smuzhiyun break;
849*4882a593Smuzhiyun case BRIDGE_SPCA536:
850*4882a593Smuzhiyun if (data[0] == 0xff) {
851*4882a593Smuzhiyun sof = 1;
852*4882a593Smuzhiyun data += SPCA536_OFFSET_DATA;
853*4882a593Smuzhiyun len -= SPCA536_OFFSET_DATA;
854*4882a593Smuzhiyun } else {
855*4882a593Smuzhiyun data += 2;
856*4882a593Smuzhiyun len -= 2;
857*4882a593Smuzhiyun }
858*4882a593Smuzhiyun break;
859*4882a593Smuzhiyun default:
860*4882a593Smuzhiyun /* case BRIDGE_SPCA504: */
861*4882a593Smuzhiyun /* case BRIDGE_SPCA504B: */
862*4882a593Smuzhiyun switch (data[0]) {
863*4882a593Smuzhiyun case 0xfe: /* start of frame */
864*4882a593Smuzhiyun sof = 1;
865*4882a593Smuzhiyun data += SPCA50X_OFFSET_DATA;
866*4882a593Smuzhiyun len -= SPCA50X_OFFSET_DATA;
867*4882a593Smuzhiyun break;
868*4882a593Smuzhiyun case 0xff: /* drop packet */
869*4882a593Smuzhiyun /* gspca_dev->last_packet_type = DISCARD_PACKET; */
870*4882a593Smuzhiyun return;
871*4882a593Smuzhiyun default:
872*4882a593Smuzhiyun data += 1;
873*4882a593Smuzhiyun len -= 1;
874*4882a593Smuzhiyun break;
875*4882a593Smuzhiyun }
876*4882a593Smuzhiyun break;
877*4882a593Smuzhiyun case BRIDGE_SPCA504C:
878*4882a593Smuzhiyun switch (data[0]) {
879*4882a593Smuzhiyun case 0xfe: /* start of frame */
880*4882a593Smuzhiyun sof = 1;
881*4882a593Smuzhiyun data += SPCA504_PCCAM600_OFFSET_DATA;
882*4882a593Smuzhiyun len -= SPCA504_PCCAM600_OFFSET_DATA;
883*4882a593Smuzhiyun break;
884*4882a593Smuzhiyun case 0xff: /* drop packet */
885*4882a593Smuzhiyun /* gspca_dev->last_packet_type = DISCARD_PACKET; */
886*4882a593Smuzhiyun return;
887*4882a593Smuzhiyun default:
888*4882a593Smuzhiyun data += 1;
889*4882a593Smuzhiyun len -= 1;
890*4882a593Smuzhiyun break;
891*4882a593Smuzhiyun }
892*4882a593Smuzhiyun break;
893*4882a593Smuzhiyun }
894*4882a593Smuzhiyun if (sof) { /* start of frame */
895*4882a593Smuzhiyun gspca_frame_add(gspca_dev, LAST_PACKET,
896*4882a593Smuzhiyun ffd9, 2);
897*4882a593Smuzhiyun
898*4882a593Smuzhiyun /* put the JPEG header in the new frame */
899*4882a593Smuzhiyun gspca_frame_add(gspca_dev, FIRST_PACKET,
900*4882a593Smuzhiyun sd->jpeg_hdr, JPEG_HDR_SZ);
901*4882a593Smuzhiyun }
902*4882a593Smuzhiyun
903*4882a593Smuzhiyun /* add 0x00 after 0xff */
904*4882a593Smuzhiyun i = 0;
905*4882a593Smuzhiyun do {
906*4882a593Smuzhiyun if (data[i] == 0xff) {
907*4882a593Smuzhiyun gspca_frame_add(gspca_dev, INTER_PACKET,
908*4882a593Smuzhiyun data, i + 1);
909*4882a593Smuzhiyun len -= i;
910*4882a593Smuzhiyun data += i;
911*4882a593Smuzhiyun *data = 0x00;
912*4882a593Smuzhiyun i = 0;
913*4882a593Smuzhiyun }
914*4882a593Smuzhiyun i++;
915*4882a593Smuzhiyun } while (i < len);
916*4882a593Smuzhiyun gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
917*4882a593Smuzhiyun }
918*4882a593Smuzhiyun
sd_s_ctrl(struct v4l2_ctrl * ctrl)919*4882a593Smuzhiyun static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
920*4882a593Smuzhiyun {
921*4882a593Smuzhiyun struct gspca_dev *gspca_dev =
922*4882a593Smuzhiyun container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
923*4882a593Smuzhiyun struct sd *sd = (struct sd *)gspca_dev;
924*4882a593Smuzhiyun
925*4882a593Smuzhiyun gspca_dev->usb_err = 0;
926*4882a593Smuzhiyun
927*4882a593Smuzhiyun if (!gspca_dev->streaming)
928*4882a593Smuzhiyun return 0;
929*4882a593Smuzhiyun
930*4882a593Smuzhiyun switch (ctrl->id) {
931*4882a593Smuzhiyun case V4L2_CID_BRIGHTNESS:
932*4882a593Smuzhiyun setbrightness(gspca_dev, ctrl->val);
933*4882a593Smuzhiyun break;
934*4882a593Smuzhiyun case V4L2_CID_CONTRAST:
935*4882a593Smuzhiyun setcontrast(gspca_dev, ctrl->val);
936*4882a593Smuzhiyun break;
937*4882a593Smuzhiyun case V4L2_CID_SATURATION:
938*4882a593Smuzhiyun setcolors(gspca_dev, ctrl->val);
939*4882a593Smuzhiyun break;
940*4882a593Smuzhiyun case V4L2_CID_AUTOGAIN:
941*4882a593Smuzhiyun sd->autogain = ctrl->val;
942*4882a593Smuzhiyun break;
943*4882a593Smuzhiyun }
944*4882a593Smuzhiyun return gspca_dev->usb_err;
945*4882a593Smuzhiyun }
946*4882a593Smuzhiyun
947*4882a593Smuzhiyun static const struct v4l2_ctrl_ops sd_ctrl_ops = {
948*4882a593Smuzhiyun .s_ctrl = sd_s_ctrl,
949*4882a593Smuzhiyun };
950*4882a593Smuzhiyun
sd_init_controls(struct gspca_dev * gspca_dev)951*4882a593Smuzhiyun static int sd_init_controls(struct gspca_dev *gspca_dev)
952*4882a593Smuzhiyun {
953*4882a593Smuzhiyun struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
954*4882a593Smuzhiyun
955*4882a593Smuzhiyun gspca_dev->vdev.ctrl_handler = hdl;
956*4882a593Smuzhiyun v4l2_ctrl_handler_init(hdl, 4);
957*4882a593Smuzhiyun v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
958*4882a593Smuzhiyun V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
959*4882a593Smuzhiyun v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
960*4882a593Smuzhiyun V4L2_CID_CONTRAST, 0, 255, 1, 0x20);
961*4882a593Smuzhiyun v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
962*4882a593Smuzhiyun V4L2_CID_SATURATION, 0, 255, 1, 0x1a);
963*4882a593Smuzhiyun v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
964*4882a593Smuzhiyun V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
965*4882a593Smuzhiyun
966*4882a593Smuzhiyun if (hdl->error) {
967*4882a593Smuzhiyun pr_err("Could not initialize controls\n");
968*4882a593Smuzhiyun return hdl->error;
969*4882a593Smuzhiyun }
970*4882a593Smuzhiyun return 0;
971*4882a593Smuzhiyun }
972*4882a593Smuzhiyun
973*4882a593Smuzhiyun /* sub-driver description */
974*4882a593Smuzhiyun static const struct sd_desc sd_desc = {
975*4882a593Smuzhiyun .name = MODULE_NAME,
976*4882a593Smuzhiyun .config = sd_config,
977*4882a593Smuzhiyun .init = sd_init,
978*4882a593Smuzhiyun .init_controls = sd_init_controls,
979*4882a593Smuzhiyun .start = sd_start,
980*4882a593Smuzhiyun .stopN = sd_stopN,
981*4882a593Smuzhiyun .pkt_scan = sd_pkt_scan,
982*4882a593Smuzhiyun };
983*4882a593Smuzhiyun
984*4882a593Smuzhiyun /* -- module initialisation -- */
985*4882a593Smuzhiyun #define BS(bridge, subtype) \
986*4882a593Smuzhiyun .driver_info = (BRIDGE_ ## bridge << 8) \
987*4882a593Smuzhiyun | (subtype)
988*4882a593Smuzhiyun static const struct usb_device_id device_table[] = {
989*4882a593Smuzhiyun {USB_DEVICE(0x041e, 0x400b), BS(SPCA504C, 0)},
990*4882a593Smuzhiyun {USB_DEVICE(0x041e, 0x4012), BS(SPCA504C, 0)},
991*4882a593Smuzhiyun {USB_DEVICE(0x041e, 0x4013), BS(SPCA504C, 0)},
992*4882a593Smuzhiyun {USB_DEVICE(0x0458, 0x7006), BS(SPCA504B, 0)},
993*4882a593Smuzhiyun {USB_DEVICE(0x0461, 0x0821), BS(SPCA533, 0)},
994*4882a593Smuzhiyun {USB_DEVICE(0x046d, 0x0905), BS(SPCA533, LogitechClickSmart820)},
995*4882a593Smuzhiyun {USB_DEVICE(0x046d, 0x0960), BS(SPCA504C, LogitechClickSmart420)},
996*4882a593Smuzhiyun {USB_DEVICE(0x0471, 0x0322), BS(SPCA504B, 0)},
997*4882a593Smuzhiyun {USB_DEVICE(0x04a5, 0x3003), BS(SPCA504B, 0)},
998*4882a593Smuzhiyun {USB_DEVICE(0x04a5, 0x3008), BS(SPCA533, 0)},
999*4882a593Smuzhiyun {USB_DEVICE(0x04a5, 0x300a), BS(SPCA533, 0)},
1000*4882a593Smuzhiyun {USB_DEVICE(0x04f1, 0x1001), BS(SPCA504B, 0)},
1001*4882a593Smuzhiyun {USB_DEVICE(0x04fc, 0x500c), BS(SPCA504B, 0)},
1002*4882a593Smuzhiyun {USB_DEVICE(0x04fc, 0x504a), BS(SPCA504, AiptekMiniPenCam13)},
1003*4882a593Smuzhiyun {USB_DEVICE(0x04fc, 0x504b), BS(SPCA504B, 0)},
1004*4882a593Smuzhiyun {USB_DEVICE(0x04fc, 0x5330), BS(SPCA533, 0)},
1005*4882a593Smuzhiyun {USB_DEVICE(0x04fc, 0x5360), BS(SPCA536, 0)},
1006*4882a593Smuzhiyun {USB_DEVICE(0x04fc, 0xffff), BS(SPCA504B, 0)},
1007*4882a593Smuzhiyun {USB_DEVICE(0x052b, 0x1507), BS(SPCA533, MegapixV4)},
1008*4882a593Smuzhiyun {USB_DEVICE(0x052b, 0x1513), BS(SPCA533, MegapixV4)},
1009*4882a593Smuzhiyun {USB_DEVICE(0x052b, 0x1803), BS(SPCA533, MegaImageVI)},
1010*4882a593Smuzhiyun {USB_DEVICE(0x0546, 0x3155), BS(SPCA533, 0)},
1011*4882a593Smuzhiyun {USB_DEVICE(0x0546, 0x3191), BS(SPCA504B, 0)},
1012*4882a593Smuzhiyun {USB_DEVICE(0x0546, 0x3273), BS(SPCA504B, 0)},
1013*4882a593Smuzhiyun {USB_DEVICE(0x055f, 0xc211), BS(SPCA536, 0)},
1014*4882a593Smuzhiyun {USB_DEVICE(0x055f, 0xc230), BS(SPCA533, 0)},
1015*4882a593Smuzhiyun {USB_DEVICE(0x055f, 0xc232), BS(SPCA533, 0)},
1016*4882a593Smuzhiyun {USB_DEVICE(0x055f, 0xc360), BS(SPCA536, 0)},
1017*4882a593Smuzhiyun {USB_DEVICE(0x055f, 0xc420), BS(SPCA504, 0)},
1018*4882a593Smuzhiyun {USB_DEVICE(0x055f, 0xc430), BS(SPCA533, 0)},
1019*4882a593Smuzhiyun {USB_DEVICE(0x055f, 0xc440), BS(SPCA533, 0)},
1020*4882a593Smuzhiyun {USB_DEVICE(0x055f, 0xc520), BS(SPCA504, 0)},
1021*4882a593Smuzhiyun {USB_DEVICE(0x055f, 0xc530), BS(SPCA533, 0)},
1022*4882a593Smuzhiyun {USB_DEVICE(0x055f, 0xc540), BS(SPCA533, 0)},
1023*4882a593Smuzhiyun {USB_DEVICE(0x055f, 0xc630), BS(SPCA533, 0)},
1024*4882a593Smuzhiyun {USB_DEVICE(0x055f, 0xc650), BS(SPCA533, 0)},
1025*4882a593Smuzhiyun {USB_DEVICE(0x05da, 0x1018), BS(SPCA504B, 0)},
1026*4882a593Smuzhiyun {USB_DEVICE(0x06d6, 0x0031), BS(SPCA533, 0)},
1027*4882a593Smuzhiyun {USB_DEVICE(0x06d6, 0x0041), BS(SPCA504B, 0)},
1028*4882a593Smuzhiyun {USB_DEVICE(0x0733, 0x1311), BS(SPCA533, 0)},
1029*4882a593Smuzhiyun {USB_DEVICE(0x0733, 0x1314), BS(SPCA533, 0)},
1030*4882a593Smuzhiyun {USB_DEVICE(0x0733, 0x2211), BS(SPCA533, 0)},
1031*4882a593Smuzhiyun {USB_DEVICE(0x0733, 0x2221), BS(SPCA533, 0)},
1032*4882a593Smuzhiyun {USB_DEVICE(0x0733, 0x3261), BS(SPCA536, 0)},
1033*4882a593Smuzhiyun {USB_DEVICE(0x0733, 0x3281), BS(SPCA536, 0)},
1034*4882a593Smuzhiyun {USB_DEVICE(0x08ca, 0x0104), BS(SPCA533, 0)},
1035*4882a593Smuzhiyun {USB_DEVICE(0x08ca, 0x0106), BS(SPCA533, 0)},
1036*4882a593Smuzhiyun {USB_DEVICE(0x08ca, 0x2008), BS(SPCA504B, 0)},
1037*4882a593Smuzhiyun {USB_DEVICE(0x08ca, 0x2010), BS(SPCA533, 0)},
1038*4882a593Smuzhiyun {USB_DEVICE(0x08ca, 0x2016), BS(SPCA504B, 0)},
1039*4882a593Smuzhiyun {USB_DEVICE(0x08ca, 0x2018), BS(SPCA504B, 0)},
1040*4882a593Smuzhiyun {USB_DEVICE(0x08ca, 0x2020), BS(SPCA533, 0)},
1041*4882a593Smuzhiyun {USB_DEVICE(0x08ca, 0x2022), BS(SPCA533, 0)},
1042*4882a593Smuzhiyun {USB_DEVICE(0x08ca, 0x2024), BS(SPCA536, 0)},
1043*4882a593Smuzhiyun {USB_DEVICE(0x08ca, 0x2028), BS(SPCA533, 0)},
1044*4882a593Smuzhiyun {USB_DEVICE(0x08ca, 0x2040), BS(SPCA536, 0)},
1045*4882a593Smuzhiyun {USB_DEVICE(0x08ca, 0x2042), BS(SPCA536, 0)},
1046*4882a593Smuzhiyun {USB_DEVICE(0x08ca, 0x2050), BS(SPCA536, 0)},
1047*4882a593Smuzhiyun {USB_DEVICE(0x08ca, 0x2060), BS(SPCA536, 0)},
1048*4882a593Smuzhiyun {USB_DEVICE(0x0d64, 0x0303), BS(SPCA536, 0)},
1049*4882a593Smuzhiyun {}
1050*4882a593Smuzhiyun };
1051*4882a593Smuzhiyun MODULE_DEVICE_TABLE(usb, device_table);
1052*4882a593Smuzhiyun
1053*4882a593Smuzhiyun /* -- device connect -- */
sd_probe(struct usb_interface * intf,const struct usb_device_id * id)1054*4882a593Smuzhiyun static int sd_probe(struct usb_interface *intf,
1055*4882a593Smuzhiyun const struct usb_device_id *id)
1056*4882a593Smuzhiyun {
1057*4882a593Smuzhiyun return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1058*4882a593Smuzhiyun THIS_MODULE);
1059*4882a593Smuzhiyun }
1060*4882a593Smuzhiyun
1061*4882a593Smuzhiyun static struct usb_driver sd_driver = {
1062*4882a593Smuzhiyun .name = MODULE_NAME,
1063*4882a593Smuzhiyun .id_table = device_table,
1064*4882a593Smuzhiyun .probe = sd_probe,
1065*4882a593Smuzhiyun .disconnect = gspca_disconnect,
1066*4882a593Smuzhiyun #ifdef CONFIG_PM
1067*4882a593Smuzhiyun .suspend = gspca_suspend,
1068*4882a593Smuzhiyun .resume = gspca_resume,
1069*4882a593Smuzhiyun .reset_resume = gspca_resume,
1070*4882a593Smuzhiyun #endif
1071*4882a593Smuzhiyun };
1072*4882a593Smuzhiyun
1073*4882a593Smuzhiyun module_usb_driver(sd_driver);
1074