2 * Pixart PAC7311 library
3 * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li
5 * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #define MODULE_NAME "pac7311"
26 MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li");
27 MODULE_DESCRIPTION("Pixart PAC7311");
28 MODULE_LICENSE("GPL");
30 /* specific webcam descriptor */
32 struct gspca_dev gspca_dev; /* !! must be the first item */
36 unsigned char brightness;
37 unsigned char contrast;
39 unsigned char autogain;
43 #define AG_CNT_START 13
46 /* V4L2 controls supported by the driver */
47 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
48 static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
49 static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
50 static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
51 static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
52 static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
53 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
54 static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
56 static struct ctrl sd_ctrls[] = {
59 .id = V4L2_CID_BRIGHTNESS,
60 .type = V4L2_CTRL_TYPE_INTEGER,
63 #define BRIGHTNESS_MAX 0x20
64 .maximum = BRIGHTNESS_MAX,
66 #define BRIGHTNESS_DEF 0x10
67 .default_value = BRIGHTNESS_DEF,
69 .set = sd_setbrightness,
70 .get = sd_getbrightness,
74 .id = V4L2_CID_CONTRAST,
75 .type = V4L2_CTRL_TYPE_INTEGER,
80 #define CONTRAST_DEF 127
81 .default_value = CONTRAST_DEF,
83 .set = sd_setcontrast,
84 .get = sd_getcontrast,
88 .id = V4L2_CID_SATURATION,
89 .type = V4L2_CTRL_TYPE_INTEGER,
95 .default_value = COLOR_DEF,
102 .id = V4L2_CID_AUTOGAIN,
103 .type = V4L2_CTRL_TYPE_BOOLEAN,
108 #define AUTOGAIN_DEF 1
109 .default_value = AUTOGAIN_DEF,
111 .set = sd_setautogain,
112 .get = sd_getautogain,
116 static struct v4l2_pix_format vga_mode[] = {
117 {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
119 .sizeimage = 160 * 120 * 3 / 8 + 590,
120 .colorspace = V4L2_COLORSPACE_JPEG,
122 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
124 .sizeimage = 320 * 240 * 3 / 8 + 590,
125 .colorspace = V4L2_COLORSPACE_JPEG,
127 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
129 .sizeimage = 640 * 480 * 3 / 8 + 590,
130 .colorspace = V4L2_COLORSPACE_JPEG,
134 #define PAC7311_JPEG_HEADER_SIZE (sizeof pac7311_jpeg_header) /* (594) */
136 static const __u8 pac7311_jpeg_header[] = {
138 0xff, 0xe0, 0x00, 0x03, 0x20,
139 0xff, 0xc0, 0x00, 0x11, 0x08,
140 0x01, 0xe0, /* 12: height */
141 0x02, 0x80, /* 14: width */
146 0xff, 0xdb, 0x00, 0x84,
147 0x00, 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, 0x0d,
148 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, 0x1a, 0x18, 0x16,
149 0x16, 0x18, 0x31, 0x23, 0x25, 0x1d, 0x28, 0x3a, 0x33, 0x3d,
150 0x3c, 0x39, 0x33, 0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40,
151 0x44, 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57, 0x5f,
152 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71, 0x79, 0x70, 0x64,
153 0x78, 0x5c, 0x65, 0x67, 0x63, 0x01, 0x11, 0x12, 0x12, 0x18,
154 0x15, 0x18, 0x2f, 0x1a, 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42,
155 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
156 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
157 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
158 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
159 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
160 0xff, 0xc4, 0x01, 0xa2, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01,
161 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
162 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
163 0x09, 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02,
164 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d,
165 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31,
166 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32,
167 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52,
168 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
169 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
170 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45,
171 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57,
172 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
173 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83,
174 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94,
175 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
176 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
177 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
178 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
179 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8,
180 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
181 0xf9, 0xfa, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01,
182 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
183 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
184 0x0b, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04,
185 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01,
186 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41,
187 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14,
188 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
189 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25,
190 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a,
191 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46,
192 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
193 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a,
194 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83,
195 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94,
196 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
197 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
198 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
199 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
200 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
201 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa,
202 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03,
203 0x11, 0x00, 0x3f, 0x00
206 static void reg_w_buf(struct gspca_dev *gspca_dev,
208 const char *buffer, __u16 len)
210 memcpy(gspca_dev->usb_buf, buffer, len);
211 usb_control_msg(gspca_dev->dev,
212 usb_sndctrlpipe(gspca_dev->dev, 0),
214 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
216 index, gspca_dev->usb_buf, len,
220 static __u8 reg_r(struct gspca_dev *gspca_dev,
223 usb_control_msg(gspca_dev->dev,
224 usb_rcvctrlpipe(gspca_dev->dev, 0),
226 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
228 index, gspca_dev->usb_buf, 1,
230 return gspca_dev->usb_buf[0];
233 static void reg_w(struct gspca_dev *gspca_dev,
237 gspca_dev->usb_buf[0] = value;
238 usb_control_msg(gspca_dev->dev,
239 usb_sndctrlpipe(gspca_dev->dev, 0),
241 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
242 value, index, gspca_dev->usb_buf, 1,
246 /* this function is called at probe time */
247 static int sd_config(struct gspca_dev *gspca_dev,
248 const struct usb_device_id *id)
250 struct sd *sd = (struct sd *) gspca_dev;
253 PDEBUG(D_CONF, "Find Sensor PAC7311");
254 reg_w(gspca_dev, 0x78, 0x40); /* Bit_0=start stream, Bit_7=LED */
255 reg_w(gspca_dev, 0x78, 0x40); /* Bit_0=start stream, Bit_7=LED */
256 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
257 reg_w(gspca_dev, 0xff, 0x04);
258 reg_w(gspca_dev, 0x27, 0x80);
259 reg_w(gspca_dev, 0x28, 0xca);
260 reg_w(gspca_dev, 0x29, 0x53);
261 reg_w(gspca_dev, 0x2a, 0x0e);
262 reg_w(gspca_dev, 0xff, 0x01);
263 reg_w(gspca_dev, 0x3e, 0x20);
265 cam = &gspca_dev->cam;
267 cam->cam_mode = vga_mode;
268 cam->nmodes = ARRAY_SIZE(vga_mode);
270 sd->brightness = BRIGHTNESS_DEF;
271 sd->contrast = CONTRAST_DEF;
272 sd->colors = COLOR_DEF;
273 sd->autogain = AUTOGAIN_DEF;
277 static void setbrightness(struct gspca_dev *gspca_dev)
279 struct sd *sd = (struct sd *) gspca_dev;
283 brightness = BRIGHTNESS_MAX - sd->brightness;
284 reg_w(gspca_dev, 0xff, 0x04);
285 /* reg_w(gspca_dev, 0x0e, 0x00); */
286 reg_w(gspca_dev, 0x0f, brightness);
287 /* load registers to sensor (Bit 0, auto clear) */
288 reg_w(gspca_dev, 0x11, 0x01);
289 PDEBUG(D_CONF|D_STREAM, "brightness: %i", brightness);
292 static void setcontrast(struct gspca_dev *gspca_dev)
294 struct sd *sd = (struct sd *) gspca_dev;
296 reg_w(gspca_dev, 0xff, 0x01);
297 reg_w(gspca_dev, 0x80, sd->contrast);
298 /* load registers to sensor (Bit 0, auto clear) */
299 reg_w(gspca_dev, 0x11, 0x01);
300 PDEBUG(D_CONF|D_STREAM, "contrast: %i", sd->contrast);
303 static void setcolors(struct gspca_dev *gspca_dev)
305 struct sd *sd = (struct sd *) gspca_dev;
307 reg_w(gspca_dev, 0xff, 0x01);
308 reg_w(gspca_dev, 0x10, sd->colors);
309 /* load registers to sensor (Bit 0, auto clear) */
310 reg_w(gspca_dev, 0x11, 0x01);
311 PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
314 /* this function is called at open time */
315 static int sd_open(struct gspca_dev *gspca_dev)
317 reg_w(gspca_dev, 0x78, 0x00); /* Turn on LED */
321 static void sd_start(struct gspca_dev *gspca_dev)
323 struct sd *sd = (struct sd *) gspca_dev;
325 reg_w(gspca_dev, 0xff, 0x01);
326 reg_w_buf(gspca_dev, 0x0002, "\x48\x0a\x40\x08\x00\x00\x08\x00", 8);
327 reg_w_buf(gspca_dev, 0x000a, "\x06\xff\x11\xff\x5a\x30\x90\x4c", 8);
328 reg_w_buf(gspca_dev, 0x0012, "\x00\x07\x00\x0a\x10\x00\xa0\x10", 8);
329 reg_w_buf(gspca_dev, 0x001a, "\x02\x00\x00\x00\x00\x0b\x01\x00", 8);
330 reg_w_buf(gspca_dev, 0x0022, "\x00\x00\x00\x00\x00\x00\x00\x00", 8);
331 reg_w_buf(gspca_dev, 0x002a, "\x00\x00\x00", 3);
332 reg_w_buf(gspca_dev, 0x003e, "\x00\x00\x78\x52\x4a\x52\x78\x6e", 8);
333 reg_w_buf(gspca_dev, 0x0046, "\x48\x46\x48\x6e\x5f\x49\x42\x49", 8);
334 reg_w_buf(gspca_dev, 0x004e, "\x5f\x5f\x49\x42\x49\x5f\x6e\x48", 8);
335 reg_w_buf(gspca_dev, 0x0056, "\x46\x48\x6e\x78\x52\x4a\x52\x78", 8);
336 reg_w_buf(gspca_dev, 0x005e, "\x00\x00\x09\x1b\x34\x49\x5c\x9b", 8);
337 reg_w_buf(gspca_dev, 0x0066, "\xd0\xff", 2);
338 reg_w_buf(gspca_dev, 0x0078, "\x44\x00\xf2\x01\x01\x80", 6);
339 reg_w_buf(gspca_dev, 0x007f, "\x2a\x1c\x00\xc8\x02\x58\x03\x84", 8);
340 reg_w_buf(gspca_dev, 0x0087, "\x12\x00\x1a\x04\x08\x0c\x10\x14", 8);
341 reg_w_buf(gspca_dev, 0x008f, "\x18\x20", 2);
342 reg_w_buf(gspca_dev, 0x0096, "\x01\x08\x04", 3);
343 reg_w_buf(gspca_dev, 0x00a0, "\x44\x44\x44\x04", 4);
344 reg_w_buf(gspca_dev, 0x00f0, "\x01\x00\x00\x00\x22\x00\x20\x00", 8);
345 reg_w_buf(gspca_dev, 0x00f8, "\x3f\x00\x0a\x01\x00", 5);
347 reg_w(gspca_dev, 0xff, 0x04);
348 reg_w(gspca_dev, 0x02, 0x04);
349 reg_w(gspca_dev, 0x03, 0x54);
350 reg_w(gspca_dev, 0x04, 0x07);
351 reg_w(gspca_dev, 0x05, 0x2b);
352 reg_w(gspca_dev, 0x06, 0x09);
353 reg_w(gspca_dev, 0x07, 0x0f);
354 reg_w(gspca_dev, 0x08, 0x09);
355 reg_w(gspca_dev, 0x09, 0x00);
356 reg_w(gspca_dev, 0x0c, 0x07);
357 reg_w(gspca_dev, 0x0d, 0x00);
358 reg_w(gspca_dev, 0x0e, 0x00);
359 reg_w(gspca_dev, 0x0f, 0x62);
360 reg_w(gspca_dev, 0x10, 0x08);
361 reg_w(gspca_dev, 0x12, 0x07);
362 reg_w(gspca_dev, 0x13, 0x00);
363 reg_w(gspca_dev, 0x14, 0x00);
364 reg_w(gspca_dev, 0x15, 0x00);
365 reg_w(gspca_dev, 0x16, 0x00);
366 reg_w(gspca_dev, 0x17, 0x00);
367 reg_w(gspca_dev, 0x18, 0x00);
368 reg_w(gspca_dev, 0x19, 0x00);
369 reg_w(gspca_dev, 0x1a, 0x00);
370 reg_w(gspca_dev, 0x1b, 0x03);
371 reg_w(gspca_dev, 0x1c, 0xa0);
372 reg_w(gspca_dev, 0x1d, 0x01);
373 reg_w(gspca_dev, 0x1e, 0xf4);
374 reg_w(gspca_dev, 0x21, 0x00);
375 reg_w(gspca_dev, 0x22, 0x08);
376 reg_w(gspca_dev, 0x24, 0x03);
377 reg_w(gspca_dev, 0x26, 0x00);
378 reg_w(gspca_dev, 0x27, 0x01);
379 reg_w(gspca_dev, 0x28, 0xca);
380 reg_w(gspca_dev, 0x29, 0x10);
381 reg_w(gspca_dev, 0x2a, 0x06);
382 reg_w(gspca_dev, 0x2b, 0x78);
383 reg_w(gspca_dev, 0x2c, 0x00);
384 reg_w(gspca_dev, 0x2d, 0x00);
385 reg_w(gspca_dev, 0x2e, 0x00);
386 reg_w(gspca_dev, 0x2f, 0x00);
387 reg_w(gspca_dev, 0x30, 0x23);
388 reg_w(gspca_dev, 0x31, 0x28);
389 reg_w(gspca_dev, 0x32, 0x04);
390 reg_w(gspca_dev, 0x33, 0x11);
391 reg_w(gspca_dev, 0x34, 0x00);
392 reg_w(gspca_dev, 0x35, 0x00);
393 reg_w(gspca_dev, 0x11, 0x01);
394 setcontrast(gspca_dev);
395 setbrightness(gspca_dev);
396 setcolors(gspca_dev);
398 /* set correct resolution */
399 switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
400 case 2: /* 160x120 */
401 reg_w(gspca_dev, 0xff, 0x04);
402 reg_w(gspca_dev, 0x02, 0x03);
403 reg_w(gspca_dev, 0xff, 0x01);
404 reg_w(gspca_dev, 0x08, 0x09);
405 reg_w(gspca_dev, 0x17, 0x20);
406 reg_w(gspca_dev, 0x1b, 0x00);
407 /* reg_w(gspca_dev, 0x80, 0x69); */
408 reg_w(gspca_dev, 0x87, 0x10);
410 case 1: /* 320x240 */
411 reg_w(gspca_dev, 0xff, 0x04);
412 reg_w(gspca_dev, 0x02, 0x03);
413 reg_w(gspca_dev, 0xff, 0x01);
414 reg_w(gspca_dev, 0x08, 0x09);
415 reg_w(gspca_dev, 0x17, 0x30);
416 /* reg_w(gspca_dev, 0x80, 0x3f); */
417 reg_w(gspca_dev, 0x87, 0x11);
419 case 0: /* 640x480 */
420 reg_w(gspca_dev, 0xff, 0x04);
421 reg_w(gspca_dev, 0x02, 0x03);
422 reg_w(gspca_dev, 0xff, 0x01);
423 reg_w(gspca_dev, 0x08, 0x08);
424 reg_w(gspca_dev, 0x17, 0x00);
425 /* reg_w(gspca_dev, 0x80, 0x1c); */
426 reg_w(gspca_dev, 0x87, 0x12);
431 reg_w(gspca_dev, 0xff, 0x01);
432 reg_w(gspca_dev, 0x78, 0x04);
433 reg_w(gspca_dev, 0x78, 0x05);
436 sd->ag_cnt = AG_CNT_START;
443 static void sd_stopN(struct gspca_dev *gspca_dev)
445 reg_w(gspca_dev, 0xff, 0x04);
446 reg_w(gspca_dev, 0x27, 0x80);
447 reg_w(gspca_dev, 0x28, 0xca);
448 reg_w(gspca_dev, 0x29, 0x53);
449 reg_w(gspca_dev, 0x2a, 0x0e);
450 reg_w(gspca_dev, 0xff, 0x01);
451 reg_w(gspca_dev, 0x3e, 0x20);
452 reg_w(gspca_dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */
453 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
454 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
457 static void sd_stop0(struct gspca_dev *gspca_dev)
461 /* this function is called at close time */
462 static void sd_close(struct gspca_dev *gspca_dev)
464 reg_w(gspca_dev, 0xff, 0x04);
465 reg_w(gspca_dev, 0x27, 0x80);
466 reg_w(gspca_dev, 0x28, 0xca);
467 reg_w(gspca_dev, 0x29, 0x53);
468 reg_w(gspca_dev, 0x2a, 0x0e);
469 reg_w(gspca_dev, 0xff, 0x01);
470 reg_w(gspca_dev, 0x3e, 0x20);
471 reg_w(gspca_dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */
472 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
473 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
476 static void setautogain(struct gspca_dev *gspca_dev, int luma)
483 Gbright = reg_r(gspca_dev, 0x02);
484 PDEBUG(D_FRAM, "luma mean %d", luma);
485 if (luma < luma_mean - luma_delta ||
486 luma > luma_mean + luma_delta) {
487 Gbright += (luma_mean - luma) >> spring;
490 else if (Gbright < 4)
492 PDEBUG(D_FRAM, "gbright %d", Gbright);
493 reg_w(gspca_dev, 0xff, 0x04);
494 reg_w(gspca_dev, 0x0f, Gbright);
495 /* load registers to sensor (Bit 0, auto clear) */
496 reg_w(gspca_dev, 0x11, 0x01);
500 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
501 struct gspca_frame *frame, /* target */
502 __u8 *data, /* isoc packet */
503 int len) /* iso packet length */
505 struct sd *sd = (struct sd *) gspca_dev;
506 unsigned char tmpbuf[4];
511 /* gspca_dev->last_packet_type = DISCARD_PACKET; */
517 for (p = 0; p < len - 6; p++) {
518 if ((data[0 + p] == 0xff)
519 && (data[1 + p] == 0xff)
520 && (data[2 + p] == 0x00)
521 && (data[3 + p] == 0xff)
522 && (data[4 + p] == 0x96)) {
525 if (sd->ag_cnt >= 0 && p > 28) {
526 sd->avg_lum += data[p - 23];
527 if (--sd->ag_cnt < 0) {
528 sd->ag_cnt = AG_CNT_START;
529 setautogain(gspca_dev,
530 sd->avg_lum / AG_CNT_START);
535 /* copy the end of data to the current frame */
536 frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
539 /* put the JPEG header in the new frame */
540 gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
541 (unsigned char *) pac7311_jpeg_header,
543 tmpbuf[0] = gspca_dev->height >> 8;
544 tmpbuf[1] = gspca_dev->height & 0xff;
545 tmpbuf[2] = gspca_dev->width >> 8;
546 tmpbuf[3] = gspca_dev->width & 0xff;
547 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
549 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
550 (unsigned char *) &pac7311_jpeg_header[16],
551 PAC7311_JPEG_HEADER_SIZE - 16);
560 /* remove the 'ff ff ff xx' sequences */
567 if (data[0] == 0xff) {
570 frame->data_end -= 2;
575 && data[1] == 0xff) {
578 frame->data_end -= 1;
582 for (i = 0; i < len - 4; i++) {
584 && data[i + 1] == 0xff
585 && data[i + 2] == 0xff) {
586 memmove(&data[i], &data[i + 4], len - i - 4);
591 if (data[len - 4] == 0xff) {
592 if (data[len - 3] == 0xff
593 && data[len - 2] == 0xff) {
596 } else if (data[len - 3] == 0xff) {
597 if (data[len - 2] == 0xff
598 && data[len - 1] == 0xff)
600 } else if (data[len - 2] == 0xff) {
601 if (data[len - 1] == 0xff)
603 } else if (data[len - 1] == 0xff)
606 gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
609 static void getbrightness(struct gspca_dev *gspca_dev)
611 /* sd->brightness = reg_r(gspca_dev, 0x08);
612 return sd->brightness; */
613 /* PDEBUG(D_CONF, "Called pac7311_getbrightness: Not implemented yet"); */
618 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
620 struct sd *sd = (struct sd *) gspca_dev;
622 sd->brightness = val;
623 if (gspca_dev->streaming)
624 setbrightness(gspca_dev);
628 static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
630 struct sd *sd = (struct sd *) gspca_dev;
632 getbrightness(gspca_dev);
633 *val = sd->brightness;
637 static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
639 struct sd *sd = (struct sd *) gspca_dev;
642 if (gspca_dev->streaming)
643 setcontrast(gspca_dev);
647 static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
649 struct sd *sd = (struct sd *) gspca_dev;
651 /* getcontrast(gspca_dev); */
656 static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
658 struct sd *sd = (struct sd *) gspca_dev;
661 if (gspca_dev->streaming)
662 setcolors(gspca_dev);
666 static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
668 struct sd *sd = (struct sd *) gspca_dev;
670 /* getcolors(gspca_dev); */
675 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
677 struct sd *sd = (struct sd *) gspca_dev;
681 sd->ag_cnt = AG_CNT_START;
689 static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
691 struct sd *sd = (struct sd *) gspca_dev;
697 /* sub-driver description */
698 static struct sd_desc sd_desc = {
701 .nctrls = ARRAY_SIZE(sd_ctrls),
708 .pkt_scan = sd_pkt_scan,
711 /* -- module initialisation -- */
712 static __devinitdata struct usb_device_id device_table[] = {
713 {USB_DEVICE(0x093a, 0x2600)},
714 {USB_DEVICE(0x093a, 0x2601)},
715 {USB_DEVICE(0x093a, 0x2603)},
716 {USB_DEVICE(0x093a, 0x2608)},
717 {USB_DEVICE(0x093a, 0x260e)},
718 {USB_DEVICE(0x093a, 0x260f)},
719 {USB_DEVICE(0x093a, 0x2621)},
722 MODULE_DEVICE_TABLE(usb, device_table);
724 /* -- device connect -- */
725 static int sd_probe(struct usb_interface *intf,
726 const struct usb_device_id *id)
728 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
732 static struct usb_driver sd_driver = {
734 .id_table = device_table,
736 .disconnect = gspca_disconnect,
739 /* -- module insert / remove -- */
740 static int __init sd_mod_init(void)
742 if (usb_register(&sd_driver) < 0)
744 PDEBUG(D_PROBE, "registered");
747 static void __exit sd_mod_exit(void)
749 usb_deregister(&sd_driver);
750 PDEBUG(D_PROBE, "deregistered");
753 module_init(sd_mod_init);
754 module_exit(sd_mod_exit);