1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Mars MR97310A library
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * The original mr97310a driver, which supported the Aiptek Pencam VGA+, is
6*4882a593Smuzhiyun * Copyright (C) 2009 Kyle Guinn <elyk03@gmail.com>
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * Support for the MR97310A cameras in addition to the Aiptek Pencam VGA+
9*4882a593Smuzhiyun * and for the routines for detecting and classifying these various cameras,
10*4882a593Smuzhiyun * is Copyright (C) 2009 Theodore Kilgore <kilgota@auburn.edu>
11*4882a593Smuzhiyun *
12*4882a593Smuzhiyun * Support for the control settings for the CIF cameras is
13*4882a593Smuzhiyun * Copyright (C) 2009 Hans de Goede <hdegoede@redhat.com> and
14*4882a593Smuzhiyun * Thomas Kaiser <thomas@kaiser-linux.li>
15*4882a593Smuzhiyun *
16*4882a593Smuzhiyun * Support for the control settings for the VGA cameras is
17*4882a593Smuzhiyun * Copyright (C) 2009 Theodore Kilgore <kilgota@auburn.edu>
18*4882a593Smuzhiyun *
19*4882a593Smuzhiyun * Several previously unsupported cameras are owned and have been tested by
20*4882a593Smuzhiyun * Hans de Goede <hdegoede@redhat.com> and
21*4882a593Smuzhiyun * Thomas Kaiser <thomas@kaiser-linux.li> and
22*4882a593Smuzhiyun * Theodore Kilgore <kilgota@auburn.edu> and
23*4882a593Smuzhiyun * Edmond Rodriguez <erodrig_97@yahoo.com> and
24*4882a593Smuzhiyun * Aurelien Jacobs <aurel@gnuage.org>
25*4882a593Smuzhiyun *
26*4882a593Smuzhiyun * The MR97311A support in gspca/mars.c has been helpful in understanding some
27*4882a593Smuzhiyun * of the registers in these cameras.
28*4882a593Smuzhiyun */
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun #define MODULE_NAME "mr97310a"
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun #include "gspca.h"
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun #define CAM_TYPE_CIF 0
37*4882a593Smuzhiyun #define CAM_TYPE_VGA 1
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun #define MR97310A_BRIGHTNESS_DEFAULT 0
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun #define MR97310A_EXPOSURE_MIN 0
42*4882a593Smuzhiyun #define MR97310A_EXPOSURE_MAX 4095
43*4882a593Smuzhiyun #define MR97310A_EXPOSURE_DEFAULT 1000
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun #define MR97310A_GAIN_MIN 0
46*4882a593Smuzhiyun #define MR97310A_GAIN_MAX 31
47*4882a593Smuzhiyun #define MR97310A_GAIN_DEFAULT 25
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun #define MR97310A_CONTRAST_MIN 0
50*4882a593Smuzhiyun #define MR97310A_CONTRAST_MAX 31
51*4882a593Smuzhiyun #define MR97310A_CONTRAST_DEFAULT 23
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun #define MR97310A_CS_GAIN_MIN 0
54*4882a593Smuzhiyun #define MR97310A_CS_GAIN_MAX 0x7ff
55*4882a593Smuzhiyun #define MR97310A_CS_GAIN_DEFAULT 0x110
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun #define MR97310A_CID_CLOCKDIV (V4L2_CTRL_CLASS_USER + 0x1000)
58*4882a593Smuzhiyun #define MR97310A_MIN_CLOCKDIV_MIN 3
59*4882a593Smuzhiyun #define MR97310A_MIN_CLOCKDIV_MAX 8
60*4882a593Smuzhiyun #define MR97310A_MIN_CLOCKDIV_DEFAULT 3
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun MODULE_AUTHOR("Kyle Guinn <elyk03@gmail.com>,Theodore Kilgore <kilgota@auburn.edu>");
63*4882a593Smuzhiyun MODULE_DESCRIPTION("GSPCA/Mars-Semi MR97310A USB Camera Driver");
64*4882a593Smuzhiyun MODULE_LICENSE("GPL");
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun /* global parameters */
67*4882a593Smuzhiyun static int force_sensor_type = -1;
68*4882a593Smuzhiyun module_param(force_sensor_type, int, 0644);
69*4882a593Smuzhiyun MODULE_PARM_DESC(force_sensor_type, "Force sensor type (-1 (auto), 0 or 1)");
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun /* specific webcam descriptor */
72*4882a593Smuzhiyun struct sd {
73*4882a593Smuzhiyun struct gspca_dev gspca_dev; /* !! must be the first item */
74*4882a593Smuzhiyun struct { /* exposure/min_clockdiv control cluster */
75*4882a593Smuzhiyun struct v4l2_ctrl *exposure;
76*4882a593Smuzhiyun struct v4l2_ctrl *min_clockdiv;
77*4882a593Smuzhiyun };
78*4882a593Smuzhiyun u8 sof_read;
79*4882a593Smuzhiyun u8 cam_type; /* 0 is CIF and 1 is VGA */
80*4882a593Smuzhiyun u8 sensor_type; /* We use 0 and 1 here, too. */
81*4882a593Smuzhiyun u8 do_lcd_stop;
82*4882a593Smuzhiyun u8 adj_colors;
83*4882a593Smuzhiyun };
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun struct sensor_w_data {
86*4882a593Smuzhiyun u8 reg;
87*4882a593Smuzhiyun u8 flags;
88*4882a593Smuzhiyun u8 data[16];
89*4882a593Smuzhiyun int len;
90*4882a593Smuzhiyun };
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun static void sd_stopN(struct gspca_dev *gspca_dev);
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun static const struct v4l2_pix_format vga_mode[] = {
95*4882a593Smuzhiyun {160, 120, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE,
96*4882a593Smuzhiyun .bytesperline = 160,
97*4882a593Smuzhiyun .sizeimage = 160 * 120,
98*4882a593Smuzhiyun .colorspace = V4L2_COLORSPACE_SRGB,
99*4882a593Smuzhiyun .priv = 4},
100*4882a593Smuzhiyun {176, 144, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE,
101*4882a593Smuzhiyun .bytesperline = 176,
102*4882a593Smuzhiyun .sizeimage = 176 * 144,
103*4882a593Smuzhiyun .colorspace = V4L2_COLORSPACE_SRGB,
104*4882a593Smuzhiyun .priv = 3},
105*4882a593Smuzhiyun {320, 240, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE,
106*4882a593Smuzhiyun .bytesperline = 320,
107*4882a593Smuzhiyun .sizeimage = 320 * 240,
108*4882a593Smuzhiyun .colorspace = V4L2_COLORSPACE_SRGB,
109*4882a593Smuzhiyun .priv = 2},
110*4882a593Smuzhiyun {352, 288, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE,
111*4882a593Smuzhiyun .bytesperline = 352,
112*4882a593Smuzhiyun .sizeimage = 352 * 288,
113*4882a593Smuzhiyun .colorspace = V4L2_COLORSPACE_SRGB,
114*4882a593Smuzhiyun .priv = 1},
115*4882a593Smuzhiyun {640, 480, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE,
116*4882a593Smuzhiyun .bytesperline = 640,
117*4882a593Smuzhiyun .sizeimage = 640 * 480,
118*4882a593Smuzhiyun .colorspace = V4L2_COLORSPACE_SRGB,
119*4882a593Smuzhiyun .priv = 0},
120*4882a593Smuzhiyun };
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun /* the bytes to write are in gspca_dev->usb_buf */
mr_write(struct gspca_dev * gspca_dev,int len)123*4882a593Smuzhiyun static int mr_write(struct gspca_dev *gspca_dev, int len)
124*4882a593Smuzhiyun {
125*4882a593Smuzhiyun int rc;
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun rc = usb_bulk_msg(gspca_dev->dev,
128*4882a593Smuzhiyun usb_sndbulkpipe(gspca_dev->dev, 4),
129*4882a593Smuzhiyun gspca_dev->usb_buf, len, NULL, 500);
130*4882a593Smuzhiyun if (rc < 0)
131*4882a593Smuzhiyun pr_err("reg write [%02x] error %d\n",
132*4882a593Smuzhiyun gspca_dev->usb_buf[0], rc);
133*4882a593Smuzhiyun return rc;
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun /* the bytes are read into gspca_dev->usb_buf */
mr_read(struct gspca_dev * gspca_dev,int len)137*4882a593Smuzhiyun static int mr_read(struct gspca_dev *gspca_dev, int len)
138*4882a593Smuzhiyun {
139*4882a593Smuzhiyun int rc;
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun rc = usb_bulk_msg(gspca_dev->dev,
142*4882a593Smuzhiyun usb_rcvbulkpipe(gspca_dev->dev, 3),
143*4882a593Smuzhiyun gspca_dev->usb_buf, len, NULL, 500);
144*4882a593Smuzhiyun if (rc < 0)
145*4882a593Smuzhiyun pr_err("reg read [%02x] error %d\n",
146*4882a593Smuzhiyun gspca_dev->usb_buf[0], rc);
147*4882a593Smuzhiyun return rc;
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun
sensor_write_reg(struct gspca_dev * gspca_dev,u8 reg,u8 flags,const u8 * data,int len)150*4882a593Smuzhiyun static int sensor_write_reg(struct gspca_dev *gspca_dev, u8 reg, u8 flags,
151*4882a593Smuzhiyun const u8 *data, int len)
152*4882a593Smuzhiyun {
153*4882a593Smuzhiyun gspca_dev->usb_buf[0] = 0x1f;
154*4882a593Smuzhiyun gspca_dev->usb_buf[1] = flags;
155*4882a593Smuzhiyun gspca_dev->usb_buf[2] = reg;
156*4882a593Smuzhiyun memcpy(gspca_dev->usb_buf + 3, data, len);
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun return mr_write(gspca_dev, len + 3);
159*4882a593Smuzhiyun }
160*4882a593Smuzhiyun
sensor_write_regs(struct gspca_dev * gspca_dev,const struct sensor_w_data * data,int len)161*4882a593Smuzhiyun static int sensor_write_regs(struct gspca_dev *gspca_dev,
162*4882a593Smuzhiyun const struct sensor_w_data *data, int len)
163*4882a593Smuzhiyun {
164*4882a593Smuzhiyun int i, rc;
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun for (i = 0; i < len; i++) {
167*4882a593Smuzhiyun rc = sensor_write_reg(gspca_dev, data[i].reg, data[i].flags,
168*4882a593Smuzhiyun data[i].data, data[i].len);
169*4882a593Smuzhiyun if (rc < 0)
170*4882a593Smuzhiyun return rc;
171*4882a593Smuzhiyun }
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun return 0;
174*4882a593Smuzhiyun }
175*4882a593Smuzhiyun
sensor_write1(struct gspca_dev * gspca_dev,u8 reg,u8 data)176*4882a593Smuzhiyun static int sensor_write1(struct gspca_dev *gspca_dev, u8 reg, u8 data)
177*4882a593Smuzhiyun {
178*4882a593Smuzhiyun struct sd *sd = (struct sd *) gspca_dev;
179*4882a593Smuzhiyun u8 buf, confirm_reg;
180*4882a593Smuzhiyun int rc;
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun buf = data;
183*4882a593Smuzhiyun if (sd->cam_type == CAM_TYPE_CIF) {
184*4882a593Smuzhiyun rc = sensor_write_reg(gspca_dev, reg, 0x01, &buf, 1);
185*4882a593Smuzhiyun confirm_reg = sd->sensor_type ? 0x13 : 0x11;
186*4882a593Smuzhiyun } else {
187*4882a593Smuzhiyun rc = sensor_write_reg(gspca_dev, reg, 0x00, &buf, 1);
188*4882a593Smuzhiyun confirm_reg = 0x11;
189*4882a593Smuzhiyun }
190*4882a593Smuzhiyun if (rc < 0)
191*4882a593Smuzhiyun return rc;
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun buf = 0x01;
194*4882a593Smuzhiyun rc = sensor_write_reg(gspca_dev, confirm_reg, 0x00, &buf, 1);
195*4882a593Smuzhiyun if (rc < 0)
196*4882a593Smuzhiyun return rc;
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun return 0;
199*4882a593Smuzhiyun }
200*4882a593Smuzhiyun
cam_get_response16(struct gspca_dev * gspca_dev,u8 reg,int verbose)201*4882a593Smuzhiyun static int cam_get_response16(struct gspca_dev *gspca_dev, u8 reg, int verbose)
202*4882a593Smuzhiyun {
203*4882a593Smuzhiyun int err_code;
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun gspca_dev->usb_buf[0] = reg;
206*4882a593Smuzhiyun err_code = mr_write(gspca_dev, 1);
207*4882a593Smuzhiyun if (err_code < 0)
208*4882a593Smuzhiyun return err_code;
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun err_code = mr_read(gspca_dev, 16);
211*4882a593Smuzhiyun if (err_code < 0)
212*4882a593Smuzhiyun return err_code;
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun if (verbose)
215*4882a593Smuzhiyun gspca_dbg(gspca_dev, D_PROBE, "Register: %02x reads %02x%02x%02x\n",
216*4882a593Smuzhiyun reg,
217*4882a593Smuzhiyun gspca_dev->usb_buf[0],
218*4882a593Smuzhiyun gspca_dev->usb_buf[1],
219*4882a593Smuzhiyun gspca_dev->usb_buf[2]);
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun return 0;
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun
zero_the_pointer(struct gspca_dev * gspca_dev)224*4882a593Smuzhiyun static int zero_the_pointer(struct gspca_dev *gspca_dev)
225*4882a593Smuzhiyun {
226*4882a593Smuzhiyun __u8 *data = gspca_dev->usb_buf;
227*4882a593Smuzhiyun int err_code;
228*4882a593Smuzhiyun u8 status = 0;
229*4882a593Smuzhiyun int tries = 0;
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun err_code = cam_get_response16(gspca_dev, 0x21, 0);
232*4882a593Smuzhiyun if (err_code < 0)
233*4882a593Smuzhiyun return err_code;
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun data[0] = 0x19;
236*4882a593Smuzhiyun data[1] = 0x51;
237*4882a593Smuzhiyun err_code = mr_write(gspca_dev, 2);
238*4882a593Smuzhiyun if (err_code < 0)
239*4882a593Smuzhiyun return err_code;
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun err_code = cam_get_response16(gspca_dev, 0x21, 0);
242*4882a593Smuzhiyun if (err_code < 0)
243*4882a593Smuzhiyun return err_code;
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun data[0] = 0x19;
246*4882a593Smuzhiyun data[1] = 0xba;
247*4882a593Smuzhiyun err_code = mr_write(gspca_dev, 2);
248*4882a593Smuzhiyun if (err_code < 0)
249*4882a593Smuzhiyun return err_code;
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun err_code = cam_get_response16(gspca_dev, 0x21, 0);
252*4882a593Smuzhiyun if (err_code < 0)
253*4882a593Smuzhiyun return err_code;
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun data[0] = 0x19;
256*4882a593Smuzhiyun data[1] = 0x00;
257*4882a593Smuzhiyun err_code = mr_write(gspca_dev, 2);
258*4882a593Smuzhiyun if (err_code < 0)
259*4882a593Smuzhiyun return err_code;
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun err_code = cam_get_response16(gspca_dev, 0x21, 0);
262*4882a593Smuzhiyun if (err_code < 0)
263*4882a593Smuzhiyun return err_code;
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun data[0] = 0x19;
266*4882a593Smuzhiyun data[1] = 0x00;
267*4882a593Smuzhiyun err_code = mr_write(gspca_dev, 2);
268*4882a593Smuzhiyun if (err_code < 0)
269*4882a593Smuzhiyun return err_code;
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun while (status != 0x0a && tries < 256) {
272*4882a593Smuzhiyun err_code = cam_get_response16(gspca_dev, 0x21, 0);
273*4882a593Smuzhiyun status = data[0];
274*4882a593Smuzhiyun tries++;
275*4882a593Smuzhiyun if (err_code < 0)
276*4882a593Smuzhiyun return err_code;
277*4882a593Smuzhiyun }
278*4882a593Smuzhiyun if (status != 0x0a)
279*4882a593Smuzhiyun gspca_err(gspca_dev, "status is %02x\n", status);
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun tries = 0;
282*4882a593Smuzhiyun while (tries < 4) {
283*4882a593Smuzhiyun data[0] = 0x19;
284*4882a593Smuzhiyun data[1] = 0x00;
285*4882a593Smuzhiyun err_code = mr_write(gspca_dev, 2);
286*4882a593Smuzhiyun if (err_code < 0)
287*4882a593Smuzhiyun return err_code;
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun err_code = cam_get_response16(gspca_dev, 0x21, 0);
290*4882a593Smuzhiyun tries++;
291*4882a593Smuzhiyun if (err_code < 0)
292*4882a593Smuzhiyun return err_code;
293*4882a593Smuzhiyun }
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun data[0] = 0x19;
296*4882a593Smuzhiyun err_code = mr_write(gspca_dev, 1);
297*4882a593Smuzhiyun if (err_code < 0)
298*4882a593Smuzhiyun return err_code;
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun err_code = mr_read(gspca_dev, 16);
301*4882a593Smuzhiyun if (err_code < 0)
302*4882a593Smuzhiyun return err_code;
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun return 0;
305*4882a593Smuzhiyun }
306*4882a593Smuzhiyun
stream_start(struct gspca_dev * gspca_dev)307*4882a593Smuzhiyun static int stream_start(struct gspca_dev *gspca_dev)
308*4882a593Smuzhiyun {
309*4882a593Smuzhiyun gspca_dev->usb_buf[0] = 0x01;
310*4882a593Smuzhiyun gspca_dev->usb_buf[1] = 0x01;
311*4882a593Smuzhiyun return mr_write(gspca_dev, 2);
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun
stream_stop(struct gspca_dev * gspca_dev)314*4882a593Smuzhiyun static void stream_stop(struct gspca_dev *gspca_dev)
315*4882a593Smuzhiyun {
316*4882a593Smuzhiyun gspca_dev->usb_buf[0] = 0x01;
317*4882a593Smuzhiyun gspca_dev->usb_buf[1] = 0x00;
318*4882a593Smuzhiyun if (mr_write(gspca_dev, 2) < 0)
319*4882a593Smuzhiyun gspca_err(gspca_dev, "Stream Stop failed\n");
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun
lcd_stop(struct gspca_dev * gspca_dev)322*4882a593Smuzhiyun static void lcd_stop(struct gspca_dev *gspca_dev)
323*4882a593Smuzhiyun {
324*4882a593Smuzhiyun gspca_dev->usb_buf[0] = 0x19;
325*4882a593Smuzhiyun gspca_dev->usb_buf[1] = 0x54;
326*4882a593Smuzhiyun if (mr_write(gspca_dev, 2) < 0)
327*4882a593Smuzhiyun gspca_err(gspca_dev, "LCD Stop failed\n");
328*4882a593Smuzhiyun }
329*4882a593Smuzhiyun
isoc_enable(struct gspca_dev * gspca_dev)330*4882a593Smuzhiyun static int isoc_enable(struct gspca_dev *gspca_dev)
331*4882a593Smuzhiyun {
332*4882a593Smuzhiyun gspca_dev->usb_buf[0] = 0x00;
333*4882a593Smuzhiyun gspca_dev->usb_buf[1] = 0x4d; /* ISOC transferring enable... */
334*4882a593Smuzhiyun return mr_write(gspca_dev, 2);
335*4882a593Smuzhiyun }
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun /* This function is called at probe time */
sd_config(struct gspca_dev * gspca_dev,const struct usb_device_id * id)338*4882a593Smuzhiyun static int sd_config(struct gspca_dev *gspca_dev,
339*4882a593Smuzhiyun const struct usb_device_id *id)
340*4882a593Smuzhiyun {
341*4882a593Smuzhiyun struct sd *sd = (struct sd *) gspca_dev;
342*4882a593Smuzhiyun struct cam *cam;
343*4882a593Smuzhiyun int err_code;
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun cam = &gspca_dev->cam;
346*4882a593Smuzhiyun cam->cam_mode = vga_mode;
347*4882a593Smuzhiyun cam->nmodes = ARRAY_SIZE(vga_mode);
348*4882a593Smuzhiyun sd->do_lcd_stop = 0;
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun /* Several of the supported CIF cameras share the same USB ID but
351*4882a593Smuzhiyun * require different initializations and different control settings.
352*4882a593Smuzhiyun * The same is true of the VGA cameras. Therefore, we are forced
353*4882a593Smuzhiyun * to start the initialization process in order to determine which
354*4882a593Smuzhiyun * camera is present. Some of the supported cameras require the
355*4882a593Smuzhiyun * memory pointer to be set to 0 as the very first item of business
356*4882a593Smuzhiyun * or else they will not stream. So we do that immediately.
357*4882a593Smuzhiyun */
358*4882a593Smuzhiyun err_code = zero_the_pointer(gspca_dev);
359*4882a593Smuzhiyun if (err_code < 0)
360*4882a593Smuzhiyun return err_code;
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun err_code = stream_start(gspca_dev);
363*4882a593Smuzhiyun if (err_code < 0)
364*4882a593Smuzhiyun return err_code;
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun /* Now, the query for sensor type. */
367*4882a593Smuzhiyun err_code = cam_get_response16(gspca_dev, 0x07, 1);
368*4882a593Smuzhiyun if (err_code < 0)
369*4882a593Smuzhiyun return err_code;
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun if (id->idProduct == 0x0110 || id->idProduct == 0x010e) {
372*4882a593Smuzhiyun sd->cam_type = CAM_TYPE_CIF;
373*4882a593Smuzhiyun cam->nmodes--;
374*4882a593Smuzhiyun /*
375*4882a593Smuzhiyun * All but one of the known CIF cameras share the same USB ID,
376*4882a593Smuzhiyun * but two different init routines are in use, and the control
377*4882a593Smuzhiyun * settings are different, too. We need to detect which camera
378*4882a593Smuzhiyun * of the two known varieties is connected!
379*4882a593Smuzhiyun *
380*4882a593Smuzhiyun * A list of known CIF cameras follows. They all report either
381*4882a593Smuzhiyun * 0200 for type 0 or 0300 for type 1.
382*4882a593Smuzhiyun * If you have another to report, please do
383*4882a593Smuzhiyun *
384*4882a593Smuzhiyun * Name sd->sensor_type reported by
385*4882a593Smuzhiyun *
386*4882a593Smuzhiyun * Sakar 56379 Spy-shot 0 T. Kilgore
387*4882a593Smuzhiyun * Innovage 0 T. Kilgore
388*4882a593Smuzhiyun * Vivitar Mini 0 H. De Goede
389*4882a593Smuzhiyun * Vivitar Mini 0 E. Rodriguez
390*4882a593Smuzhiyun * Vivitar Mini 1 T. Kilgore
391*4882a593Smuzhiyun * Elta-Media 8212dc 1 T. Kaiser
392*4882a593Smuzhiyun * Philips dig. keych. 1 T. Kilgore
393*4882a593Smuzhiyun * Trust Spyc@m 100 1 A. Jacobs
394*4882a593Smuzhiyun */
395*4882a593Smuzhiyun switch (gspca_dev->usb_buf[0]) {
396*4882a593Smuzhiyun case 2:
397*4882a593Smuzhiyun sd->sensor_type = 0;
398*4882a593Smuzhiyun break;
399*4882a593Smuzhiyun case 3:
400*4882a593Smuzhiyun sd->sensor_type = 1;
401*4882a593Smuzhiyun break;
402*4882a593Smuzhiyun default:
403*4882a593Smuzhiyun pr_err("Unknown CIF Sensor id : %02x\n",
404*4882a593Smuzhiyun gspca_dev->usb_buf[1]);
405*4882a593Smuzhiyun return -ENODEV;
406*4882a593Smuzhiyun }
407*4882a593Smuzhiyun gspca_dbg(gspca_dev, D_PROBE, "MR97310A CIF camera detected, sensor: %d\n",
408*4882a593Smuzhiyun sd->sensor_type);
409*4882a593Smuzhiyun } else {
410*4882a593Smuzhiyun sd->cam_type = CAM_TYPE_VGA;
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun /*
413*4882a593Smuzhiyun * Here is a table of the responses to the query for sensor
414*4882a593Smuzhiyun * type, from the known MR97310A VGA cameras. Six different
415*4882a593Smuzhiyun * cameras of which five share the same USB ID.
416*4882a593Smuzhiyun *
417*4882a593Smuzhiyun * Name gspca_dev->usb_buf[] sd->sensor_type
418*4882a593Smuzhiyun * sd->do_lcd_stop
419*4882a593Smuzhiyun * Aiptek Pencam VGA+ 0300 0 1
420*4882a593Smuzhiyun * ION digital 0300 0 1
421*4882a593Smuzhiyun * Argus DC-1620 0450 1 0
422*4882a593Smuzhiyun * Argus QuickClix 0420 1 1
423*4882a593Smuzhiyun * Sakar 77379 Digital 0350 0 1
424*4882a593Smuzhiyun * Sakar 1638x CyberPix 0120 0 2
425*4882a593Smuzhiyun *
426*4882a593Smuzhiyun * Based upon these results, we assume default settings
427*4882a593Smuzhiyun * and then correct as necessary, as follows.
428*4882a593Smuzhiyun *
429*4882a593Smuzhiyun */
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun sd->sensor_type = 1;
432*4882a593Smuzhiyun sd->do_lcd_stop = 0;
433*4882a593Smuzhiyun sd->adj_colors = 0;
434*4882a593Smuzhiyun if (gspca_dev->usb_buf[0] == 0x01) {
435*4882a593Smuzhiyun sd->sensor_type = 2;
436*4882a593Smuzhiyun } else if ((gspca_dev->usb_buf[0] != 0x03) &&
437*4882a593Smuzhiyun (gspca_dev->usb_buf[0] != 0x04)) {
438*4882a593Smuzhiyun pr_err("Unknown VGA Sensor id Byte 0: %02x\n",
439*4882a593Smuzhiyun gspca_dev->usb_buf[0]);
440*4882a593Smuzhiyun pr_err("Defaults assumed, may not work\n");
441*4882a593Smuzhiyun pr_err("Please report this\n");
442*4882a593Smuzhiyun }
443*4882a593Smuzhiyun /* Sakar Digital color needs to be adjusted. */
444*4882a593Smuzhiyun if ((gspca_dev->usb_buf[0] == 0x03) &&
445*4882a593Smuzhiyun (gspca_dev->usb_buf[1] == 0x50))
446*4882a593Smuzhiyun sd->adj_colors = 1;
447*4882a593Smuzhiyun if (gspca_dev->usb_buf[0] == 0x04) {
448*4882a593Smuzhiyun sd->do_lcd_stop = 1;
449*4882a593Smuzhiyun switch (gspca_dev->usb_buf[1]) {
450*4882a593Smuzhiyun case 0x50:
451*4882a593Smuzhiyun sd->sensor_type = 0;
452*4882a593Smuzhiyun gspca_dbg(gspca_dev, D_PROBE, "sensor_type corrected to 0\n");
453*4882a593Smuzhiyun break;
454*4882a593Smuzhiyun case 0x20:
455*4882a593Smuzhiyun /* Nothing to do here. */
456*4882a593Smuzhiyun break;
457*4882a593Smuzhiyun default:
458*4882a593Smuzhiyun pr_err("Unknown VGA Sensor id Byte 1: %02x\n",
459*4882a593Smuzhiyun gspca_dev->usb_buf[1]);
460*4882a593Smuzhiyun pr_err("Defaults assumed, may not work\n");
461*4882a593Smuzhiyun pr_err("Please report this\n");
462*4882a593Smuzhiyun }
463*4882a593Smuzhiyun }
464*4882a593Smuzhiyun gspca_dbg(gspca_dev, D_PROBE, "MR97310A VGA camera detected, sensor: %d\n",
465*4882a593Smuzhiyun sd->sensor_type);
466*4882a593Smuzhiyun }
467*4882a593Smuzhiyun /* Stop streaming as we've started it only to probe the sensor type. */
468*4882a593Smuzhiyun sd_stopN(gspca_dev);
469*4882a593Smuzhiyun
470*4882a593Smuzhiyun if (force_sensor_type != -1) {
471*4882a593Smuzhiyun sd->sensor_type = !!force_sensor_type;
472*4882a593Smuzhiyun gspca_dbg(gspca_dev, D_PROBE, "Forcing sensor type to: %d\n",
473*4882a593Smuzhiyun sd->sensor_type);
474*4882a593Smuzhiyun }
475*4882a593Smuzhiyun
476*4882a593Smuzhiyun return 0;
477*4882a593Smuzhiyun }
478*4882a593Smuzhiyun
479*4882a593Smuzhiyun /* this function is called at probe and resume time */
sd_init(struct gspca_dev * gspca_dev)480*4882a593Smuzhiyun static int sd_init(struct gspca_dev *gspca_dev)
481*4882a593Smuzhiyun {
482*4882a593Smuzhiyun return 0;
483*4882a593Smuzhiyun }
484*4882a593Smuzhiyun
start_cif_cam(struct gspca_dev * gspca_dev)485*4882a593Smuzhiyun static int start_cif_cam(struct gspca_dev *gspca_dev)
486*4882a593Smuzhiyun {
487*4882a593Smuzhiyun struct sd *sd = (struct sd *) gspca_dev;
488*4882a593Smuzhiyun __u8 *data = gspca_dev->usb_buf;
489*4882a593Smuzhiyun int err_code;
490*4882a593Smuzhiyun static const __u8 startup_string[] = {
491*4882a593Smuzhiyun 0x00,
492*4882a593Smuzhiyun 0x0d,
493*4882a593Smuzhiyun 0x01,
494*4882a593Smuzhiyun 0x00, /* Hsize/8 for 352 or 320 */
495*4882a593Smuzhiyun 0x00, /* Vsize/4 for 288 or 240 */
496*4882a593Smuzhiyun 0x13, /* or 0xbb, depends on sensor */
497*4882a593Smuzhiyun 0x00, /* Hstart, depends on res. */
498*4882a593Smuzhiyun 0x00, /* reserved ? */
499*4882a593Smuzhiyun 0x00, /* Vstart, depends on res. and sensor */
500*4882a593Smuzhiyun 0x50, /* 0x54 to get 176 or 160 */
501*4882a593Smuzhiyun 0xc0
502*4882a593Smuzhiyun };
503*4882a593Smuzhiyun
504*4882a593Smuzhiyun /* Note: Some of the above descriptions guessed from MR97113A driver */
505*4882a593Smuzhiyun
506*4882a593Smuzhiyun memcpy(data, startup_string, 11);
507*4882a593Smuzhiyun if (sd->sensor_type)
508*4882a593Smuzhiyun data[5] = 0xbb;
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun switch (gspca_dev->pixfmt.width) {
511*4882a593Smuzhiyun case 160:
512*4882a593Smuzhiyun data[9] |= 0x04; /* reg 8, 2:1 scale down from 320 */
513*4882a593Smuzhiyun fallthrough;
514*4882a593Smuzhiyun case 320:
515*4882a593Smuzhiyun default:
516*4882a593Smuzhiyun data[3] = 0x28; /* reg 2, H size/8 */
517*4882a593Smuzhiyun data[4] = 0x3c; /* reg 3, V size/4 */
518*4882a593Smuzhiyun data[6] = 0x14; /* reg 5, H start */
519*4882a593Smuzhiyun data[8] = 0x1a + sd->sensor_type; /* reg 7, V start */
520*4882a593Smuzhiyun break;
521*4882a593Smuzhiyun case 176:
522*4882a593Smuzhiyun data[9] |= 0x04; /* reg 8, 2:1 scale down from 352 */
523*4882a593Smuzhiyun fallthrough;
524*4882a593Smuzhiyun case 352:
525*4882a593Smuzhiyun data[3] = 0x2c; /* reg 2, H size/8 */
526*4882a593Smuzhiyun data[4] = 0x48; /* reg 3, V size/4 */
527*4882a593Smuzhiyun data[6] = 0x06; /* reg 5, H start */
528*4882a593Smuzhiyun data[8] = 0x06 - sd->sensor_type; /* reg 7, V start */
529*4882a593Smuzhiyun break;
530*4882a593Smuzhiyun }
531*4882a593Smuzhiyun err_code = mr_write(gspca_dev, 11);
532*4882a593Smuzhiyun if (err_code < 0)
533*4882a593Smuzhiyun return err_code;
534*4882a593Smuzhiyun
535*4882a593Smuzhiyun if (!sd->sensor_type) {
536*4882a593Smuzhiyun static const struct sensor_w_data cif_sensor0_init_data[] = {
537*4882a593Smuzhiyun {0x02, 0x00, {0x03, 0x5a, 0xb5, 0x01,
538*4882a593Smuzhiyun 0x0f, 0x14, 0x0f, 0x10}, 8},
539*4882a593Smuzhiyun {0x0c, 0x00, {0x04, 0x01, 0x01, 0x00, 0x1f}, 5},
540*4882a593Smuzhiyun {0x12, 0x00, {0x07}, 1},
541*4882a593Smuzhiyun {0x1f, 0x00, {0x06}, 1},
542*4882a593Smuzhiyun {0x27, 0x00, {0x04}, 1},
543*4882a593Smuzhiyun {0x29, 0x00, {0x0c}, 1},
544*4882a593Smuzhiyun {0x40, 0x00, {0x40, 0x00, 0x04}, 3},
545*4882a593Smuzhiyun {0x50, 0x00, {0x60}, 1},
546*4882a593Smuzhiyun {0x60, 0x00, {0x06}, 1},
547*4882a593Smuzhiyun {0x6b, 0x00, {0x85, 0x85, 0xc8, 0xc8, 0xc8, 0xc8}, 6},
548*4882a593Smuzhiyun {0x72, 0x00, {0x1e, 0x56}, 2},
549*4882a593Smuzhiyun {0x75, 0x00, {0x58, 0x40, 0xa2, 0x02, 0x31, 0x02,
550*4882a593Smuzhiyun 0x31, 0x80, 0x00}, 9},
551*4882a593Smuzhiyun {0x11, 0x00, {0x01}, 1},
552*4882a593Smuzhiyun {0, 0, {0}, 0}
553*4882a593Smuzhiyun };
554*4882a593Smuzhiyun err_code = sensor_write_regs(gspca_dev, cif_sensor0_init_data,
555*4882a593Smuzhiyun ARRAY_SIZE(cif_sensor0_init_data));
556*4882a593Smuzhiyun } else { /* sd->sensor_type = 1 */
557*4882a593Smuzhiyun static const struct sensor_w_data cif_sensor1_init_data[] = {
558*4882a593Smuzhiyun /* Reg 3,4, 7,8 get set by the controls */
559*4882a593Smuzhiyun {0x02, 0x00, {0x10}, 1},
560*4882a593Smuzhiyun {0x05, 0x01, {0x22}, 1}, /* 5/6 also seen as 65h/32h */
561*4882a593Smuzhiyun {0x06, 0x01, {0x00}, 1},
562*4882a593Smuzhiyun {0x09, 0x02, {0x0e}, 1},
563*4882a593Smuzhiyun {0x0a, 0x02, {0x05}, 1},
564*4882a593Smuzhiyun {0x0b, 0x02, {0x05}, 1},
565*4882a593Smuzhiyun {0x0c, 0x02, {0x0f}, 1},
566*4882a593Smuzhiyun {0x0d, 0x02, {0x07}, 1},
567*4882a593Smuzhiyun {0x0e, 0x02, {0x0c}, 1},
568*4882a593Smuzhiyun {0x0f, 0x00, {0x00}, 1},
569*4882a593Smuzhiyun {0x10, 0x00, {0x06}, 1},
570*4882a593Smuzhiyun {0x11, 0x00, {0x07}, 1},
571*4882a593Smuzhiyun {0x12, 0x00, {0x00}, 1},
572*4882a593Smuzhiyun {0x13, 0x00, {0x01}, 1},
573*4882a593Smuzhiyun {0, 0, {0}, 0}
574*4882a593Smuzhiyun };
575*4882a593Smuzhiyun /* Without this command the cam won't work with USB-UHCI */
576*4882a593Smuzhiyun gspca_dev->usb_buf[0] = 0x0a;
577*4882a593Smuzhiyun gspca_dev->usb_buf[1] = 0x00;
578*4882a593Smuzhiyun err_code = mr_write(gspca_dev, 2);
579*4882a593Smuzhiyun if (err_code < 0)
580*4882a593Smuzhiyun return err_code;
581*4882a593Smuzhiyun err_code = sensor_write_regs(gspca_dev, cif_sensor1_init_data,
582*4882a593Smuzhiyun ARRAY_SIZE(cif_sensor1_init_data));
583*4882a593Smuzhiyun }
584*4882a593Smuzhiyun return err_code;
585*4882a593Smuzhiyun }
586*4882a593Smuzhiyun
start_vga_cam(struct gspca_dev * gspca_dev)587*4882a593Smuzhiyun static int start_vga_cam(struct gspca_dev *gspca_dev)
588*4882a593Smuzhiyun {
589*4882a593Smuzhiyun struct sd *sd = (struct sd *) gspca_dev;
590*4882a593Smuzhiyun __u8 *data = gspca_dev->usb_buf;
591*4882a593Smuzhiyun int err_code;
592*4882a593Smuzhiyun static const __u8 startup_string[] =
593*4882a593Smuzhiyun {0x00, 0x0d, 0x01, 0x00, 0x00, 0x2b, 0x00, 0x00,
594*4882a593Smuzhiyun 0x00, 0x50, 0xc0};
595*4882a593Smuzhiyun /* What some of these mean is explained in start_cif_cam(), above */
596*4882a593Smuzhiyun
597*4882a593Smuzhiyun memcpy(data, startup_string, 11);
598*4882a593Smuzhiyun if (!sd->sensor_type) {
599*4882a593Smuzhiyun data[5] = 0x00;
600*4882a593Smuzhiyun data[10] = 0x91;
601*4882a593Smuzhiyun }
602*4882a593Smuzhiyun if (sd->sensor_type == 2) {
603*4882a593Smuzhiyun data[5] = 0x00;
604*4882a593Smuzhiyun data[10] = 0x18;
605*4882a593Smuzhiyun }
606*4882a593Smuzhiyun
607*4882a593Smuzhiyun switch (gspca_dev->pixfmt.width) {
608*4882a593Smuzhiyun case 160:
609*4882a593Smuzhiyun data[9] |= 0x0c; /* reg 8, 4:1 scale down */
610*4882a593Smuzhiyun fallthrough;
611*4882a593Smuzhiyun case 320:
612*4882a593Smuzhiyun data[9] |= 0x04; /* reg 8, 2:1 scale down */
613*4882a593Smuzhiyun fallthrough;
614*4882a593Smuzhiyun case 640:
615*4882a593Smuzhiyun default:
616*4882a593Smuzhiyun data[3] = 0x50; /* reg 2, H size/8 */
617*4882a593Smuzhiyun data[4] = 0x78; /* reg 3, V size/4 */
618*4882a593Smuzhiyun data[6] = 0x04; /* reg 5, H start */
619*4882a593Smuzhiyun data[8] = 0x03; /* reg 7, V start */
620*4882a593Smuzhiyun if (sd->sensor_type == 2) {
621*4882a593Smuzhiyun data[6] = 2;
622*4882a593Smuzhiyun data[8] = 1;
623*4882a593Smuzhiyun }
624*4882a593Smuzhiyun if (sd->do_lcd_stop)
625*4882a593Smuzhiyun data[8] = 0x04; /* Bayer tile shifted */
626*4882a593Smuzhiyun break;
627*4882a593Smuzhiyun
628*4882a593Smuzhiyun case 176:
629*4882a593Smuzhiyun data[9] |= 0x04; /* reg 8, 2:1 scale down */
630*4882a593Smuzhiyun fallthrough;
631*4882a593Smuzhiyun case 352:
632*4882a593Smuzhiyun data[3] = 0x2c; /* reg 2, H size */
633*4882a593Smuzhiyun data[4] = 0x48; /* reg 3, V size */
634*4882a593Smuzhiyun data[6] = 0x94; /* reg 5, H start */
635*4882a593Smuzhiyun data[8] = 0x63; /* reg 7, V start */
636*4882a593Smuzhiyun if (sd->do_lcd_stop)
637*4882a593Smuzhiyun data[8] = 0x64; /* Bayer tile shifted */
638*4882a593Smuzhiyun break;
639*4882a593Smuzhiyun }
640*4882a593Smuzhiyun
641*4882a593Smuzhiyun err_code = mr_write(gspca_dev, 11);
642*4882a593Smuzhiyun if (err_code < 0)
643*4882a593Smuzhiyun return err_code;
644*4882a593Smuzhiyun
645*4882a593Smuzhiyun if (!sd->sensor_type) {
646*4882a593Smuzhiyun static const struct sensor_w_data vga_sensor0_init_data[] = {
647*4882a593Smuzhiyun {0x01, 0x00, {0x0c, 0x00, 0x04}, 3},
648*4882a593Smuzhiyun {0x14, 0x00, {0x01, 0xe4, 0x02, 0x84}, 4},
649*4882a593Smuzhiyun {0x20, 0x00, {0x00, 0x80, 0x00, 0x08}, 4},
650*4882a593Smuzhiyun {0x25, 0x00, {0x03, 0xa9, 0x80}, 3},
651*4882a593Smuzhiyun {0x30, 0x00, {0x30, 0x18, 0x10, 0x18}, 4},
652*4882a593Smuzhiyun {0, 0, {0}, 0}
653*4882a593Smuzhiyun };
654*4882a593Smuzhiyun err_code = sensor_write_regs(gspca_dev, vga_sensor0_init_data,
655*4882a593Smuzhiyun ARRAY_SIZE(vga_sensor0_init_data));
656*4882a593Smuzhiyun } else if (sd->sensor_type == 1) {
657*4882a593Smuzhiyun static const struct sensor_w_data color_adj[] = {
658*4882a593Smuzhiyun {0x02, 0x00, {0x06, 0x59, 0x0c, 0x16, 0x00,
659*4882a593Smuzhiyun /* adjusted blue, green, red gain correct
660*4882a593Smuzhiyun too much blue from the Sakar Digital */
661*4882a593Smuzhiyun 0x05, 0x01, 0x04}, 8}
662*4882a593Smuzhiyun };
663*4882a593Smuzhiyun
664*4882a593Smuzhiyun static const struct sensor_w_data color_no_adj[] = {
665*4882a593Smuzhiyun {0x02, 0x00, {0x06, 0x59, 0x0c, 0x16, 0x00,
666*4882a593Smuzhiyun /* default blue, green, red gain settings */
667*4882a593Smuzhiyun 0x07, 0x00, 0x01}, 8}
668*4882a593Smuzhiyun };
669*4882a593Smuzhiyun
670*4882a593Smuzhiyun static const struct sensor_w_data vga_sensor1_init_data[] = {
671*4882a593Smuzhiyun {0x11, 0x04, {0x01}, 1},
672*4882a593Smuzhiyun {0x0a, 0x00, {0x00, 0x01, 0x00, 0x00, 0x01,
673*4882a593Smuzhiyun /* These settings may be better for some cameras */
674*4882a593Smuzhiyun /* {0x0a, 0x00, {0x01, 0x06, 0x00, 0x00, 0x01, */
675*4882a593Smuzhiyun 0x00, 0x0a}, 7},
676*4882a593Smuzhiyun {0x11, 0x04, {0x01}, 1},
677*4882a593Smuzhiyun {0x12, 0x00, {0x00, 0x63, 0x00, 0x70, 0x00, 0x00}, 6},
678*4882a593Smuzhiyun {0x11, 0x04, {0x01}, 1},
679*4882a593Smuzhiyun {0, 0, {0}, 0}
680*4882a593Smuzhiyun };
681*4882a593Smuzhiyun
682*4882a593Smuzhiyun if (sd->adj_colors)
683*4882a593Smuzhiyun err_code = sensor_write_regs(gspca_dev, color_adj,
684*4882a593Smuzhiyun ARRAY_SIZE(color_adj));
685*4882a593Smuzhiyun else
686*4882a593Smuzhiyun err_code = sensor_write_regs(gspca_dev, color_no_adj,
687*4882a593Smuzhiyun ARRAY_SIZE(color_no_adj));
688*4882a593Smuzhiyun
689*4882a593Smuzhiyun if (err_code < 0)
690*4882a593Smuzhiyun return err_code;
691*4882a593Smuzhiyun
692*4882a593Smuzhiyun err_code = sensor_write_regs(gspca_dev, vga_sensor1_init_data,
693*4882a593Smuzhiyun ARRAY_SIZE(vga_sensor1_init_data));
694*4882a593Smuzhiyun } else { /* sensor type == 2 */
695*4882a593Smuzhiyun static const struct sensor_w_data vga_sensor2_init_data[] = {
696*4882a593Smuzhiyun
697*4882a593Smuzhiyun {0x01, 0x00, {0x48}, 1},
698*4882a593Smuzhiyun {0x02, 0x00, {0x22}, 1},
699*4882a593Smuzhiyun /* Reg 3 msb and 4 is lsb of the exposure setting*/
700*4882a593Smuzhiyun {0x05, 0x00, {0x10}, 1},
701*4882a593Smuzhiyun {0x06, 0x00, {0x00}, 1},
702*4882a593Smuzhiyun {0x07, 0x00, {0x00}, 1},
703*4882a593Smuzhiyun {0x08, 0x00, {0x00}, 1},
704*4882a593Smuzhiyun {0x09, 0x00, {0x00}, 1},
705*4882a593Smuzhiyun /* The following are used in the gain control
706*4882a593Smuzhiyun * which is BTW completely borked in the OEM driver
707*4882a593Smuzhiyun * The values for each color go from 0 to 0x7ff
708*4882a593Smuzhiyun *{0x0a, 0x00, {0x01}, 1}, green1 gain msb
709*4882a593Smuzhiyun *{0x0b, 0x00, {0x10}, 1}, green1 gain lsb
710*4882a593Smuzhiyun *{0x0c, 0x00, {0x01}, 1}, red gain msb
711*4882a593Smuzhiyun *{0x0d, 0x00, {0x10}, 1}, red gain lsb
712*4882a593Smuzhiyun *{0x0e, 0x00, {0x01}, 1}, blue gain msb
713*4882a593Smuzhiyun *{0x0f, 0x00, {0x10}, 1}, blue gain lsb
714*4882a593Smuzhiyun *{0x10, 0x00, {0x01}, 1}, green2 gain msb
715*4882a593Smuzhiyun *{0x11, 0x00, {0x10}, 1}, green2 gain lsb
716*4882a593Smuzhiyun */
717*4882a593Smuzhiyun {0x12, 0x00, {0x00}, 1},
718*4882a593Smuzhiyun {0x13, 0x00, {0x04}, 1}, /* weird effect on colors */
719*4882a593Smuzhiyun {0x14, 0x00, {0x00}, 1},
720*4882a593Smuzhiyun {0x15, 0x00, {0x06}, 1},
721*4882a593Smuzhiyun {0x16, 0x00, {0x01}, 1},
722*4882a593Smuzhiyun {0x17, 0x00, {0xe2}, 1}, /* vertical alignment */
723*4882a593Smuzhiyun {0x18, 0x00, {0x02}, 1},
724*4882a593Smuzhiyun {0x19, 0x00, {0x82}, 1}, /* don't mess with */
725*4882a593Smuzhiyun {0x1a, 0x00, {0x00}, 1},
726*4882a593Smuzhiyun {0x1b, 0x00, {0x20}, 1},
727*4882a593Smuzhiyun /* {0x1c, 0x00, {0x17}, 1}, contrast control */
728*4882a593Smuzhiyun {0x1d, 0x00, {0x80}, 1}, /* moving causes a mess */
729*4882a593Smuzhiyun {0x1e, 0x00, {0x08}, 1}, /* moving jams the camera */
730*4882a593Smuzhiyun {0x1f, 0x00, {0x0c}, 1},
731*4882a593Smuzhiyun {0x20, 0x00, {0x00}, 1},
732*4882a593Smuzhiyun {0, 0, {0}, 0}
733*4882a593Smuzhiyun };
734*4882a593Smuzhiyun err_code = sensor_write_regs(gspca_dev, vga_sensor2_init_data,
735*4882a593Smuzhiyun ARRAY_SIZE(vga_sensor2_init_data));
736*4882a593Smuzhiyun }
737*4882a593Smuzhiyun return err_code;
738*4882a593Smuzhiyun }
739*4882a593Smuzhiyun
sd_start(struct gspca_dev * gspca_dev)740*4882a593Smuzhiyun static int sd_start(struct gspca_dev *gspca_dev)
741*4882a593Smuzhiyun {
742*4882a593Smuzhiyun struct sd *sd = (struct sd *) gspca_dev;
743*4882a593Smuzhiyun int err_code;
744*4882a593Smuzhiyun
745*4882a593Smuzhiyun sd->sof_read = 0;
746*4882a593Smuzhiyun
747*4882a593Smuzhiyun /* Some of the VGA cameras require the memory pointer
748*4882a593Smuzhiyun * to be set to 0 again. We have been forced to start the
749*4882a593Smuzhiyun * stream in sd_config() to detect the hardware, and closed it.
750*4882a593Smuzhiyun * Thus, we need here to do a completely fresh and clean start. */
751*4882a593Smuzhiyun err_code = zero_the_pointer(gspca_dev);
752*4882a593Smuzhiyun if (err_code < 0)
753*4882a593Smuzhiyun return err_code;
754*4882a593Smuzhiyun
755*4882a593Smuzhiyun err_code = stream_start(gspca_dev);
756*4882a593Smuzhiyun if (err_code < 0)
757*4882a593Smuzhiyun return err_code;
758*4882a593Smuzhiyun
759*4882a593Smuzhiyun if (sd->cam_type == CAM_TYPE_CIF) {
760*4882a593Smuzhiyun err_code = start_cif_cam(gspca_dev);
761*4882a593Smuzhiyun } else {
762*4882a593Smuzhiyun err_code = start_vga_cam(gspca_dev);
763*4882a593Smuzhiyun }
764*4882a593Smuzhiyun if (err_code < 0)
765*4882a593Smuzhiyun return err_code;
766*4882a593Smuzhiyun
767*4882a593Smuzhiyun return isoc_enable(gspca_dev);
768*4882a593Smuzhiyun }
769*4882a593Smuzhiyun
sd_stopN(struct gspca_dev * gspca_dev)770*4882a593Smuzhiyun static void sd_stopN(struct gspca_dev *gspca_dev)
771*4882a593Smuzhiyun {
772*4882a593Smuzhiyun struct sd *sd = (struct sd *) gspca_dev;
773*4882a593Smuzhiyun
774*4882a593Smuzhiyun stream_stop(gspca_dev);
775*4882a593Smuzhiyun /* Not all the cams need this, but even if not, probably a good idea */
776*4882a593Smuzhiyun zero_the_pointer(gspca_dev);
777*4882a593Smuzhiyun if (sd->do_lcd_stop)
778*4882a593Smuzhiyun lcd_stop(gspca_dev);
779*4882a593Smuzhiyun }
780*4882a593Smuzhiyun
setbrightness(struct gspca_dev * gspca_dev,s32 val)781*4882a593Smuzhiyun static void setbrightness(struct gspca_dev *gspca_dev, s32 val)
782*4882a593Smuzhiyun {
783*4882a593Smuzhiyun struct sd *sd = (struct sd *) gspca_dev;
784*4882a593Smuzhiyun u8 sign_reg = 7; /* This reg and the next one used on CIF cams. */
785*4882a593Smuzhiyun u8 value_reg = 8; /* VGA cams seem to use regs 0x0b and 0x0c */
786*4882a593Smuzhiyun static const u8 quick_clix_table[] =
787*4882a593Smuzhiyun /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */
788*4882a593Smuzhiyun { 0, 4, 8, 12, 1, 2, 3, 5, 6, 9, 7, 10, 13, 11, 14, 15};
789*4882a593Smuzhiyun if (sd->cam_type == CAM_TYPE_VGA) {
790*4882a593Smuzhiyun sign_reg += 4;
791*4882a593Smuzhiyun value_reg += 4;
792*4882a593Smuzhiyun }
793*4882a593Smuzhiyun
794*4882a593Smuzhiyun /* Note register 7 is also seen as 0x8x or 0xCx in some dumps */
795*4882a593Smuzhiyun if (val > 0) {
796*4882a593Smuzhiyun sensor_write1(gspca_dev, sign_reg, 0x00);
797*4882a593Smuzhiyun } else {
798*4882a593Smuzhiyun sensor_write1(gspca_dev, sign_reg, 0x01);
799*4882a593Smuzhiyun val = 257 - val;
800*4882a593Smuzhiyun }
801*4882a593Smuzhiyun /* Use lookup table for funky Argus QuickClix brightness */
802*4882a593Smuzhiyun if (sd->do_lcd_stop)
803*4882a593Smuzhiyun val = quick_clix_table[val];
804*4882a593Smuzhiyun
805*4882a593Smuzhiyun sensor_write1(gspca_dev, value_reg, val);
806*4882a593Smuzhiyun }
807*4882a593Smuzhiyun
setexposure(struct gspca_dev * gspca_dev,s32 expo,s32 min_clockdiv)808*4882a593Smuzhiyun static void setexposure(struct gspca_dev *gspca_dev, s32 expo, s32 min_clockdiv)
809*4882a593Smuzhiyun {
810*4882a593Smuzhiyun struct sd *sd = (struct sd *) gspca_dev;
811*4882a593Smuzhiyun int exposure = MR97310A_EXPOSURE_DEFAULT;
812*4882a593Smuzhiyun u8 buf[2];
813*4882a593Smuzhiyun
814*4882a593Smuzhiyun if (sd->cam_type == CAM_TYPE_CIF && sd->sensor_type == 1) {
815*4882a593Smuzhiyun /* This cam does not like exposure settings < 300,
816*4882a593Smuzhiyun so scale 0 - 4095 to 300 - 4095 */
817*4882a593Smuzhiyun exposure = (expo * 9267) / 10000 + 300;
818*4882a593Smuzhiyun sensor_write1(gspca_dev, 3, exposure >> 4);
819*4882a593Smuzhiyun sensor_write1(gspca_dev, 4, exposure & 0x0f);
820*4882a593Smuzhiyun } else if (sd->sensor_type == 2) {
821*4882a593Smuzhiyun exposure = expo;
822*4882a593Smuzhiyun exposure >>= 3;
823*4882a593Smuzhiyun sensor_write1(gspca_dev, 3, exposure >> 8);
824*4882a593Smuzhiyun sensor_write1(gspca_dev, 4, exposure & 0xff);
825*4882a593Smuzhiyun } else {
826*4882a593Smuzhiyun /* We have both a clock divider and an exposure register.
827*4882a593Smuzhiyun We first calculate the clock divider, as that determines
828*4882a593Smuzhiyun the maximum exposure and then we calculate the exposure
829*4882a593Smuzhiyun register setting (which goes from 0 - 511).
830*4882a593Smuzhiyun
831*4882a593Smuzhiyun Note our 0 - 4095 exposure is mapped to 0 - 511
832*4882a593Smuzhiyun milliseconds exposure time */
833*4882a593Smuzhiyun u8 clockdiv = (60 * expo + 7999) / 8000;
834*4882a593Smuzhiyun
835*4882a593Smuzhiyun /* Limit framerate to not exceed usb bandwidth */
836*4882a593Smuzhiyun if (clockdiv < min_clockdiv && gspca_dev->pixfmt.width >= 320)
837*4882a593Smuzhiyun clockdiv = min_clockdiv;
838*4882a593Smuzhiyun else if (clockdiv < 2)
839*4882a593Smuzhiyun clockdiv = 2;
840*4882a593Smuzhiyun
841*4882a593Smuzhiyun if (sd->cam_type == CAM_TYPE_VGA && clockdiv < 4)
842*4882a593Smuzhiyun clockdiv = 4;
843*4882a593Smuzhiyun
844*4882a593Smuzhiyun /* Frame exposure time in ms = 1000 * clockdiv / 60 ->
845*4882a593Smuzhiyun exposure = (sd->exposure / 8) * 511 / (1000 * clockdiv / 60) */
846*4882a593Smuzhiyun exposure = (60 * 511 * expo) / (8000 * clockdiv);
847*4882a593Smuzhiyun if (exposure > 511)
848*4882a593Smuzhiyun exposure = 511;
849*4882a593Smuzhiyun
850*4882a593Smuzhiyun /* exposure register value is reversed! */
851*4882a593Smuzhiyun exposure = 511 - exposure;
852*4882a593Smuzhiyun
853*4882a593Smuzhiyun buf[0] = exposure & 0xff;
854*4882a593Smuzhiyun buf[1] = exposure >> 8;
855*4882a593Smuzhiyun sensor_write_reg(gspca_dev, 0x0e, 0, buf, 2);
856*4882a593Smuzhiyun sensor_write1(gspca_dev, 0x02, clockdiv);
857*4882a593Smuzhiyun }
858*4882a593Smuzhiyun }
859*4882a593Smuzhiyun
setgain(struct gspca_dev * gspca_dev,s32 val)860*4882a593Smuzhiyun static void setgain(struct gspca_dev *gspca_dev, s32 val)
861*4882a593Smuzhiyun {
862*4882a593Smuzhiyun struct sd *sd = (struct sd *) gspca_dev;
863*4882a593Smuzhiyun u8 gainreg;
864*4882a593Smuzhiyun
865*4882a593Smuzhiyun if (sd->cam_type == CAM_TYPE_CIF && sd->sensor_type == 1)
866*4882a593Smuzhiyun sensor_write1(gspca_dev, 0x0e, val);
867*4882a593Smuzhiyun else if (sd->cam_type == CAM_TYPE_VGA && sd->sensor_type == 2)
868*4882a593Smuzhiyun for (gainreg = 0x0a; gainreg < 0x11; gainreg += 2) {
869*4882a593Smuzhiyun sensor_write1(gspca_dev, gainreg, val >> 8);
870*4882a593Smuzhiyun sensor_write1(gspca_dev, gainreg + 1, val & 0xff);
871*4882a593Smuzhiyun }
872*4882a593Smuzhiyun else
873*4882a593Smuzhiyun sensor_write1(gspca_dev, 0x10, val);
874*4882a593Smuzhiyun }
875*4882a593Smuzhiyun
setcontrast(struct gspca_dev * gspca_dev,s32 val)876*4882a593Smuzhiyun static void setcontrast(struct gspca_dev *gspca_dev, s32 val)
877*4882a593Smuzhiyun {
878*4882a593Smuzhiyun sensor_write1(gspca_dev, 0x1c, val);
879*4882a593Smuzhiyun }
880*4882a593Smuzhiyun
sd_s_ctrl(struct v4l2_ctrl * ctrl)881*4882a593Smuzhiyun static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
882*4882a593Smuzhiyun {
883*4882a593Smuzhiyun struct gspca_dev *gspca_dev =
884*4882a593Smuzhiyun container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
885*4882a593Smuzhiyun struct sd *sd = (struct sd *)gspca_dev;
886*4882a593Smuzhiyun
887*4882a593Smuzhiyun gspca_dev->usb_err = 0;
888*4882a593Smuzhiyun
889*4882a593Smuzhiyun if (!gspca_dev->streaming)
890*4882a593Smuzhiyun return 0;
891*4882a593Smuzhiyun
892*4882a593Smuzhiyun switch (ctrl->id) {
893*4882a593Smuzhiyun case V4L2_CID_BRIGHTNESS:
894*4882a593Smuzhiyun setbrightness(gspca_dev, ctrl->val);
895*4882a593Smuzhiyun break;
896*4882a593Smuzhiyun case V4L2_CID_CONTRAST:
897*4882a593Smuzhiyun setcontrast(gspca_dev, ctrl->val);
898*4882a593Smuzhiyun break;
899*4882a593Smuzhiyun case V4L2_CID_EXPOSURE:
900*4882a593Smuzhiyun setexposure(gspca_dev, sd->exposure->val,
901*4882a593Smuzhiyun sd->min_clockdiv ? sd->min_clockdiv->val : 0);
902*4882a593Smuzhiyun break;
903*4882a593Smuzhiyun case V4L2_CID_GAIN:
904*4882a593Smuzhiyun setgain(gspca_dev, ctrl->val);
905*4882a593Smuzhiyun break;
906*4882a593Smuzhiyun }
907*4882a593Smuzhiyun return gspca_dev->usb_err;
908*4882a593Smuzhiyun }
909*4882a593Smuzhiyun
910*4882a593Smuzhiyun static const struct v4l2_ctrl_ops sd_ctrl_ops = {
911*4882a593Smuzhiyun .s_ctrl = sd_s_ctrl,
912*4882a593Smuzhiyun };
913*4882a593Smuzhiyun
sd_init_controls(struct gspca_dev * gspca_dev)914*4882a593Smuzhiyun static int sd_init_controls(struct gspca_dev *gspca_dev)
915*4882a593Smuzhiyun {
916*4882a593Smuzhiyun struct sd *sd = (struct sd *)gspca_dev;
917*4882a593Smuzhiyun struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
918*4882a593Smuzhiyun static const struct v4l2_ctrl_config clockdiv = {
919*4882a593Smuzhiyun .ops = &sd_ctrl_ops,
920*4882a593Smuzhiyun .id = MR97310A_CID_CLOCKDIV,
921*4882a593Smuzhiyun .type = V4L2_CTRL_TYPE_INTEGER,
922*4882a593Smuzhiyun .name = "Minimum Clock Divider",
923*4882a593Smuzhiyun .min = MR97310A_MIN_CLOCKDIV_MIN,
924*4882a593Smuzhiyun .max = MR97310A_MIN_CLOCKDIV_MAX,
925*4882a593Smuzhiyun .step = 1,
926*4882a593Smuzhiyun .def = MR97310A_MIN_CLOCKDIV_DEFAULT,
927*4882a593Smuzhiyun };
928*4882a593Smuzhiyun bool has_brightness = false;
929*4882a593Smuzhiyun bool has_argus_brightness = false;
930*4882a593Smuzhiyun bool has_contrast = false;
931*4882a593Smuzhiyun bool has_gain = false;
932*4882a593Smuzhiyun bool has_cs_gain = false;
933*4882a593Smuzhiyun bool has_exposure = false;
934*4882a593Smuzhiyun bool has_clockdiv = false;
935*4882a593Smuzhiyun
936*4882a593Smuzhiyun gspca_dev->vdev.ctrl_handler = hdl;
937*4882a593Smuzhiyun v4l2_ctrl_handler_init(hdl, 4);
938*4882a593Smuzhiyun
939*4882a593Smuzhiyun /* Setup controls depending on camera type */
940*4882a593Smuzhiyun if (sd->cam_type == CAM_TYPE_CIF) {
941*4882a593Smuzhiyun /* No brightness for sensor_type 0 */
942*4882a593Smuzhiyun if (sd->sensor_type == 0)
943*4882a593Smuzhiyun has_exposure = has_gain = has_clockdiv = true;
944*4882a593Smuzhiyun else
945*4882a593Smuzhiyun has_exposure = has_gain = has_brightness = true;
946*4882a593Smuzhiyun } else {
947*4882a593Smuzhiyun /* All controls need to be disabled if VGA sensor_type is 0 */
948*4882a593Smuzhiyun if (sd->sensor_type == 0)
949*4882a593Smuzhiyun ; /* no controls! */
950*4882a593Smuzhiyun else if (sd->sensor_type == 2)
951*4882a593Smuzhiyun has_exposure = has_cs_gain = has_contrast = true;
952*4882a593Smuzhiyun else if (sd->do_lcd_stop)
953*4882a593Smuzhiyun has_exposure = has_gain = has_argus_brightness =
954*4882a593Smuzhiyun has_clockdiv = true;
955*4882a593Smuzhiyun else
956*4882a593Smuzhiyun has_exposure = has_gain = has_brightness =
957*4882a593Smuzhiyun has_clockdiv = true;
958*4882a593Smuzhiyun }
959*4882a593Smuzhiyun
960*4882a593Smuzhiyun /* Separate brightness control description for Argus QuickClix as it has
961*4882a593Smuzhiyun * different limits from the other mr97310a cameras, and separate gain
962*4882a593Smuzhiyun * control for Sakar CyberPix camera. */
963*4882a593Smuzhiyun /*
964*4882a593Smuzhiyun * This control is disabled for CIF type 1 and VGA type 0 cameras.
965*4882a593Smuzhiyun * It does not quite act linearly for the Argus QuickClix camera,
966*4882a593Smuzhiyun * but it does control brightness. The values are 0 - 15 only, and
967*4882a593Smuzhiyun * the table above makes them act consecutively.
968*4882a593Smuzhiyun */
969*4882a593Smuzhiyun if (has_brightness)
970*4882a593Smuzhiyun v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
971*4882a593Smuzhiyun V4L2_CID_BRIGHTNESS, -254, 255, 1,
972*4882a593Smuzhiyun MR97310A_BRIGHTNESS_DEFAULT);
973*4882a593Smuzhiyun else if (has_argus_brightness)
974*4882a593Smuzhiyun v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
975*4882a593Smuzhiyun V4L2_CID_BRIGHTNESS, 0, 15, 1,
976*4882a593Smuzhiyun MR97310A_BRIGHTNESS_DEFAULT);
977*4882a593Smuzhiyun if (has_contrast)
978*4882a593Smuzhiyun v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
979*4882a593Smuzhiyun V4L2_CID_CONTRAST, MR97310A_CONTRAST_MIN,
980*4882a593Smuzhiyun MR97310A_CONTRAST_MAX, 1, MR97310A_CONTRAST_DEFAULT);
981*4882a593Smuzhiyun if (has_gain)
982*4882a593Smuzhiyun v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
983*4882a593Smuzhiyun V4L2_CID_GAIN, MR97310A_GAIN_MIN, MR97310A_GAIN_MAX,
984*4882a593Smuzhiyun 1, MR97310A_GAIN_DEFAULT);
985*4882a593Smuzhiyun else if (has_cs_gain)
986*4882a593Smuzhiyun v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, V4L2_CID_GAIN,
987*4882a593Smuzhiyun MR97310A_CS_GAIN_MIN, MR97310A_CS_GAIN_MAX,
988*4882a593Smuzhiyun 1, MR97310A_CS_GAIN_DEFAULT);
989*4882a593Smuzhiyun if (has_exposure)
990*4882a593Smuzhiyun sd->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
991*4882a593Smuzhiyun V4L2_CID_EXPOSURE, MR97310A_EXPOSURE_MIN,
992*4882a593Smuzhiyun MR97310A_EXPOSURE_MAX, 1, MR97310A_EXPOSURE_DEFAULT);
993*4882a593Smuzhiyun if (has_clockdiv)
994*4882a593Smuzhiyun sd->min_clockdiv = v4l2_ctrl_new_custom(hdl, &clockdiv, NULL);
995*4882a593Smuzhiyun
996*4882a593Smuzhiyun if (hdl->error) {
997*4882a593Smuzhiyun pr_err("Could not initialize controls\n");
998*4882a593Smuzhiyun return hdl->error;
999*4882a593Smuzhiyun }
1000*4882a593Smuzhiyun if (has_exposure && has_clockdiv)
1001*4882a593Smuzhiyun v4l2_ctrl_cluster(2, &sd->exposure);
1002*4882a593Smuzhiyun return 0;
1003*4882a593Smuzhiyun }
1004*4882a593Smuzhiyun
1005*4882a593Smuzhiyun /* Include pac common sof detection functions */
1006*4882a593Smuzhiyun #include "pac_common.h"
1007*4882a593Smuzhiyun
sd_pkt_scan(struct gspca_dev * gspca_dev,u8 * data,int len)1008*4882a593Smuzhiyun static void sd_pkt_scan(struct gspca_dev *gspca_dev,
1009*4882a593Smuzhiyun u8 *data, /* isoc packet */
1010*4882a593Smuzhiyun int len) /* iso packet length */
1011*4882a593Smuzhiyun {
1012*4882a593Smuzhiyun struct sd *sd = (struct sd *) gspca_dev;
1013*4882a593Smuzhiyun unsigned char *sof;
1014*4882a593Smuzhiyun
1015*4882a593Smuzhiyun sof = pac_find_sof(gspca_dev, &sd->sof_read, data, len);
1016*4882a593Smuzhiyun if (sof) {
1017*4882a593Smuzhiyun int n;
1018*4882a593Smuzhiyun
1019*4882a593Smuzhiyun /* finish decoding current frame */
1020*4882a593Smuzhiyun n = sof - data;
1021*4882a593Smuzhiyun if (n > sizeof pac_sof_marker)
1022*4882a593Smuzhiyun n -= sizeof pac_sof_marker;
1023*4882a593Smuzhiyun else
1024*4882a593Smuzhiyun n = 0;
1025*4882a593Smuzhiyun gspca_frame_add(gspca_dev, LAST_PACKET,
1026*4882a593Smuzhiyun data, n);
1027*4882a593Smuzhiyun /* Start next frame. */
1028*4882a593Smuzhiyun gspca_frame_add(gspca_dev, FIRST_PACKET,
1029*4882a593Smuzhiyun pac_sof_marker, sizeof pac_sof_marker);
1030*4882a593Smuzhiyun len -= sof - data;
1031*4882a593Smuzhiyun data = sof;
1032*4882a593Smuzhiyun }
1033*4882a593Smuzhiyun gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
1034*4882a593Smuzhiyun }
1035*4882a593Smuzhiyun
1036*4882a593Smuzhiyun /* sub-driver description */
1037*4882a593Smuzhiyun static const struct sd_desc sd_desc = {
1038*4882a593Smuzhiyun .name = MODULE_NAME,
1039*4882a593Smuzhiyun .config = sd_config,
1040*4882a593Smuzhiyun .init = sd_init,
1041*4882a593Smuzhiyun .init_controls = sd_init_controls,
1042*4882a593Smuzhiyun .start = sd_start,
1043*4882a593Smuzhiyun .stopN = sd_stopN,
1044*4882a593Smuzhiyun .pkt_scan = sd_pkt_scan,
1045*4882a593Smuzhiyun };
1046*4882a593Smuzhiyun
1047*4882a593Smuzhiyun /* -- module initialisation -- */
1048*4882a593Smuzhiyun static const struct usb_device_id device_table[] = {
1049*4882a593Smuzhiyun {USB_DEVICE(0x08ca, 0x0110)}, /* Trust Spyc@m 100 */
1050*4882a593Smuzhiyun {USB_DEVICE(0x08ca, 0x0111)}, /* Aiptek Pencam VGA+ */
1051*4882a593Smuzhiyun {USB_DEVICE(0x093a, 0x010f)}, /* All other known MR97310A VGA cams */
1052*4882a593Smuzhiyun {USB_DEVICE(0x093a, 0x010e)}, /* All known MR97310A CIF cams */
1053*4882a593Smuzhiyun {}
1054*4882a593Smuzhiyun };
1055*4882a593Smuzhiyun MODULE_DEVICE_TABLE(usb, device_table);
1056*4882a593Smuzhiyun
1057*4882a593Smuzhiyun /* -- device connect -- */
sd_probe(struct usb_interface * intf,const struct usb_device_id * id)1058*4882a593Smuzhiyun static int sd_probe(struct usb_interface *intf,
1059*4882a593Smuzhiyun const struct usb_device_id *id)
1060*4882a593Smuzhiyun {
1061*4882a593Smuzhiyun return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1062*4882a593Smuzhiyun THIS_MODULE);
1063*4882a593Smuzhiyun }
1064*4882a593Smuzhiyun
1065*4882a593Smuzhiyun static struct usb_driver sd_driver = {
1066*4882a593Smuzhiyun .name = MODULE_NAME,
1067*4882a593Smuzhiyun .id_table = device_table,
1068*4882a593Smuzhiyun .probe = sd_probe,
1069*4882a593Smuzhiyun .disconnect = gspca_disconnect,
1070*4882a593Smuzhiyun #ifdef CONFIG_PM
1071*4882a593Smuzhiyun .suspend = gspca_suspend,
1072*4882a593Smuzhiyun .resume = gspca_resume,
1073*4882a593Smuzhiyun .reset_resume = gspca_resume,
1074*4882a593Smuzhiyun #endif
1075*4882a593Smuzhiyun };
1076*4882a593Smuzhiyun
1077*4882a593Smuzhiyun module_usb_driver(sd_driver);
1078