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 #define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7)
27 static const char version[] = "2.1.7";
29 MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li");
30 MODULE_DESCRIPTION("Pixart PAC7311");
31 MODULE_LICENSE("GPL");
33 /* specific webcam descriptor */
35 struct gspca_dev gspca_dev; /* !! must be the first item */
39 unsigned char brightness;
40 unsigned char contrast;
42 unsigned char autogain;
46 #define AG_CNT_START 13
49 /* V4L2 controls supported by the driver */
50 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
51 static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
52 static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
53 static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
54 static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
55 static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
56 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
57 static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
59 static struct ctrl sd_ctrls[] = {
62 .id = V4L2_CID_BRIGHTNESS,
63 .type = V4L2_CTRL_TYPE_INTEGER,
66 #define BRIGHTNESS_MAX 0x20
67 .maximum = BRIGHTNESS_MAX,
69 #define BRIGHTNESS_DEF 0x10
70 .default_value = BRIGHTNESS_DEF,
72 .set = sd_setbrightness,
73 .get = sd_getbrightness,
77 .id = V4L2_CID_CONTRAST,
78 .type = V4L2_CTRL_TYPE_INTEGER,
83 #define CONTRAST_DEF 127
84 .default_value = CONTRAST_DEF,
86 .set = sd_setcontrast,
87 .get = sd_getcontrast,
91 .id = V4L2_CID_SATURATION,
92 .type = V4L2_CTRL_TYPE_INTEGER,
98 .default_value = COLOR_DEF,
105 .id = V4L2_CID_AUTOGAIN,
106 .type = V4L2_CTRL_TYPE_BOOLEAN,
111 #define AUTOGAIN_DEF 1
112 .default_value = AUTOGAIN_DEF,
114 .set = sd_setautogain,
115 .get = sd_getautogain,
119 static struct v4l2_pix_format vga_mode[] = {
120 {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
122 .sizeimage = 160 * 120 * 3 / 8 + 590,
123 .colorspace = V4L2_COLORSPACE_JPEG,
125 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
127 .sizeimage = 320 * 240 * 3 / 8 + 590,
128 .colorspace = V4L2_COLORSPACE_JPEG,
130 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
132 .sizeimage = 640 * 480 * 3 / 8 + 590,
133 .colorspace = V4L2_COLORSPACE_JPEG,
137 #define PAC7311_JPEG_HEADER_SIZE (sizeof pac7311_jpeg_header) /* (594) */
139 static const __u8 pac7311_jpeg_header[] = {
141 0xff, 0xe0, 0x00, 0x03, 0x20,
142 0xff, 0xc0, 0x00, 0x11, 0x08,
143 0x01, 0xe0, /* 12: height */
144 0x02, 0x80, /* 14: width */
149 0xff, 0xdb, 0x00, 0x84,
150 0x00, 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, 0x0d,
151 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, 0x1a, 0x18, 0x16,
152 0x16, 0x18, 0x31, 0x23, 0x25, 0x1d, 0x28, 0x3a, 0x33, 0x3d,
153 0x3c, 0x39, 0x33, 0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40,
154 0x44, 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57, 0x5f,
155 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71, 0x79, 0x70, 0x64,
156 0x78, 0x5c, 0x65, 0x67, 0x63, 0x01, 0x11, 0x12, 0x12, 0x18,
157 0x15, 0x18, 0x2f, 0x1a, 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42,
158 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
159 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
160 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
161 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
162 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
163 0xff, 0xc4, 0x01, 0xa2, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01,
164 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
165 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
166 0x09, 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02,
167 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d,
168 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31,
169 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32,
170 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52,
171 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
172 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
173 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45,
174 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57,
175 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
176 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83,
177 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94,
178 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
179 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
180 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
181 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
182 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8,
183 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
184 0xf9, 0xfa, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01,
185 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
186 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
187 0x0b, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04,
188 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01,
189 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41,
190 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14,
191 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
192 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25,
193 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a,
194 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46,
195 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
196 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a,
197 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83,
198 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94,
199 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
200 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
201 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
202 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
203 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
204 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa,
205 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03,
206 0x11, 0x00, 0x3f, 0x00
209 static void reg_w_buf(struct gspca_dev *gspca_dev,
211 const char *buffer, __u16 len)
213 memcpy(gspca_dev->usb_buf, buffer, len);
214 usb_control_msg(gspca_dev->dev,
215 usb_sndctrlpipe(gspca_dev->dev, 0),
217 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
219 index, gspca_dev->usb_buf, len,
223 static __u8 reg_r(struct gspca_dev *gspca_dev,
226 usb_control_msg(gspca_dev->dev,
227 usb_rcvctrlpipe(gspca_dev->dev, 0),
229 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
231 index, gspca_dev->usb_buf, 1,
233 return gspca_dev->usb_buf[0];
236 static void reg_w(struct gspca_dev *gspca_dev,
240 gspca_dev->usb_buf[0] = value;
241 usb_control_msg(gspca_dev->dev,
242 usb_sndctrlpipe(gspca_dev->dev, 0),
244 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
245 value, index, gspca_dev->usb_buf, 1,
249 /* this function is called at probe time */
250 static int sd_config(struct gspca_dev *gspca_dev,
251 const struct usb_device_id *id)
253 struct sd *sd = (struct sd *) gspca_dev;
256 PDEBUG(D_CONF, "Find Sensor PAC7311");
257 reg_w(gspca_dev, 0x78, 0x40); /* Bit_0=start stream, Bit_7=LED */
258 reg_w(gspca_dev, 0x78, 0x40); /* Bit_0=start stream, Bit_7=LED */
259 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
260 reg_w(gspca_dev, 0xff, 0x04);
261 reg_w(gspca_dev, 0x27, 0x80);
262 reg_w(gspca_dev, 0x28, 0xca);
263 reg_w(gspca_dev, 0x29, 0x53);
264 reg_w(gspca_dev, 0x2a, 0x0e);
265 reg_w(gspca_dev, 0xff, 0x01);
266 reg_w(gspca_dev, 0x3e, 0x20);
268 cam = &gspca_dev->cam;
269 cam->dev_name = (char *) id->driver_info;
271 cam->cam_mode = vga_mode;
272 cam->nmodes = ARRAY_SIZE(vga_mode);
274 sd->brightness = BRIGHTNESS_DEF;
275 sd->contrast = CONTRAST_DEF;
276 sd->colors = COLOR_DEF;
277 sd->autogain = AUTOGAIN_DEF;
281 static void setbrightness(struct gspca_dev *gspca_dev)
283 struct sd *sd = (struct sd *) gspca_dev;
287 brightness = BRIGHTNESS_MAX - sd->brightness;
288 reg_w(gspca_dev, 0xff, 0x04);
289 /* reg_w(gspca_dev, 0x0e, 0x00); */
290 reg_w(gspca_dev, 0x0f, brightness);
291 /* load registers to sensor (Bit 0, auto clear) */
292 reg_w(gspca_dev, 0x11, 0x01);
293 PDEBUG(D_CONF|D_STREAM, "brightness: %i", brightness);
296 static void setcontrast(struct gspca_dev *gspca_dev)
298 struct sd *sd = (struct sd *) gspca_dev;
300 reg_w(gspca_dev, 0xff, 0x01);
301 reg_w(gspca_dev, 0x80, sd->contrast);
302 /* load registers to sensor (Bit 0, auto clear) */
303 reg_w(gspca_dev, 0x11, 0x01);
304 PDEBUG(D_CONF|D_STREAM, "contrast: %i", sd->contrast);
307 static void setcolors(struct gspca_dev *gspca_dev)
309 struct sd *sd = (struct sd *) gspca_dev;
311 reg_w(gspca_dev, 0xff, 0x01);
312 reg_w(gspca_dev, 0x10, sd->colors);
313 /* load registers to sensor (Bit 0, auto clear) */
314 reg_w(gspca_dev, 0x11, 0x01);
315 PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
318 /* this function is called at open time */
319 static int sd_open(struct gspca_dev *gspca_dev)
321 reg_w(gspca_dev, 0x78, 0x00); /* Turn on LED */
325 static void sd_start(struct gspca_dev *gspca_dev)
327 struct sd *sd = (struct sd *) gspca_dev;
329 reg_w(gspca_dev, 0xff, 0x01);
330 reg_w_buf(gspca_dev, 0x0002, "\x48\x0a\x40\x08\x00\x00\x08\x00", 8);
331 reg_w_buf(gspca_dev, 0x000a, "\x06\xff\x11\xff\x5a\x30\x90\x4c", 8);
332 reg_w_buf(gspca_dev, 0x0012, "\x00\x07\x00\x0a\x10\x00\xa0\x10", 8);
333 reg_w_buf(gspca_dev, 0x001a, "\x02\x00\x00\x00\x00\x0b\x01\x00", 8);
334 reg_w_buf(gspca_dev, 0x0022, "\x00\x00\x00\x00\x00\x00\x00\x00", 8);
335 reg_w_buf(gspca_dev, 0x002a, "\x00\x00\x00", 3);
336 reg_w_buf(gspca_dev, 0x003e, "\x00\x00\x78\x52\x4a\x52\x78\x6e", 8);
337 reg_w_buf(gspca_dev, 0x0046, "\x48\x46\x48\x6e\x5f\x49\x42\x49", 8);
338 reg_w_buf(gspca_dev, 0x004e, "\x5f\x5f\x49\x42\x49\x5f\x6e\x48", 8);
339 reg_w_buf(gspca_dev, 0x0056, "\x46\x48\x6e\x78\x52\x4a\x52\x78", 8);
340 reg_w_buf(gspca_dev, 0x005e, "\x00\x00\x09\x1b\x34\x49\x5c\x9b", 8);
341 reg_w_buf(gspca_dev, 0x0066, "\xd0\xff", 2);
342 reg_w_buf(gspca_dev, 0x0078, "\x44\x00\xf2\x01\x01\x80", 6);
343 reg_w_buf(gspca_dev, 0x007f, "\x2a\x1c\x00\xc8\x02\x58\x03\x84", 8);
344 reg_w_buf(gspca_dev, 0x0087, "\x12\x00\x1a\x04\x08\x0c\x10\x14", 8);
345 reg_w_buf(gspca_dev, 0x008f, "\x18\x20", 2);
346 reg_w_buf(gspca_dev, 0x0096, "\x01\x08\x04", 3);
347 reg_w_buf(gspca_dev, 0x00a0, "\x44\x44\x44\x04", 4);
348 reg_w_buf(gspca_dev, 0x00f0, "\x01\x00\x00\x00\x22\x00\x20\x00", 8);
349 reg_w_buf(gspca_dev, 0x00f8, "\x3f\x00\x0a\x01\x00", 5);
351 reg_w(gspca_dev, 0xff, 0x04);
352 reg_w(gspca_dev, 0x02, 0x04);
353 reg_w(gspca_dev, 0x03, 0x54);
354 reg_w(gspca_dev, 0x04, 0x07);
355 reg_w(gspca_dev, 0x05, 0x2b);
356 reg_w(gspca_dev, 0x06, 0x09);
357 reg_w(gspca_dev, 0x07, 0x0f);
358 reg_w(gspca_dev, 0x08, 0x09);
359 reg_w(gspca_dev, 0x09, 0x00);
360 reg_w(gspca_dev, 0x0c, 0x07);
361 reg_w(gspca_dev, 0x0d, 0x00);
362 reg_w(gspca_dev, 0x0e, 0x00);
363 reg_w(gspca_dev, 0x0f, 0x62);
364 reg_w(gspca_dev, 0x10, 0x08);
365 reg_w(gspca_dev, 0x12, 0x07);
366 reg_w(gspca_dev, 0x13, 0x00);
367 reg_w(gspca_dev, 0x14, 0x00);
368 reg_w(gspca_dev, 0x15, 0x00);
369 reg_w(gspca_dev, 0x16, 0x00);
370 reg_w(gspca_dev, 0x17, 0x00);
371 reg_w(gspca_dev, 0x18, 0x00);
372 reg_w(gspca_dev, 0x19, 0x00);
373 reg_w(gspca_dev, 0x1a, 0x00);
374 reg_w(gspca_dev, 0x1b, 0x03);
375 reg_w(gspca_dev, 0x1c, 0xa0);
376 reg_w(gspca_dev, 0x1d, 0x01);
377 reg_w(gspca_dev, 0x1e, 0xf4);
378 reg_w(gspca_dev, 0x21, 0x00);
379 reg_w(gspca_dev, 0x22, 0x08);
380 reg_w(gspca_dev, 0x24, 0x03);
381 reg_w(gspca_dev, 0x26, 0x00);
382 reg_w(gspca_dev, 0x27, 0x01);
383 reg_w(gspca_dev, 0x28, 0xca);
384 reg_w(gspca_dev, 0x29, 0x10);
385 reg_w(gspca_dev, 0x2a, 0x06);
386 reg_w(gspca_dev, 0x2b, 0x78);
387 reg_w(gspca_dev, 0x2c, 0x00);
388 reg_w(gspca_dev, 0x2d, 0x00);
389 reg_w(gspca_dev, 0x2e, 0x00);
390 reg_w(gspca_dev, 0x2f, 0x00);
391 reg_w(gspca_dev, 0x30, 0x23);
392 reg_w(gspca_dev, 0x31, 0x28);
393 reg_w(gspca_dev, 0x32, 0x04);
394 reg_w(gspca_dev, 0x33, 0x11);
395 reg_w(gspca_dev, 0x34, 0x00);
396 reg_w(gspca_dev, 0x35, 0x00);
397 reg_w(gspca_dev, 0x11, 0x01);
398 setcontrast(gspca_dev);
399 setbrightness(gspca_dev);
400 setcolors(gspca_dev);
402 /* set correct resolution */
403 switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
404 case 2: /* 160x120 */
405 reg_w(gspca_dev, 0xff, 0x04);
406 reg_w(gspca_dev, 0x02, 0x03);
407 reg_w(gspca_dev, 0xff, 0x01);
408 reg_w(gspca_dev, 0x08, 0x09);
409 reg_w(gspca_dev, 0x17, 0x20);
410 reg_w(gspca_dev, 0x1b, 0x00);
411 /* reg_w(gspca_dev, 0x80, 0x69); */
412 reg_w(gspca_dev, 0x87, 0x10);
414 case 1: /* 320x240 */
415 reg_w(gspca_dev, 0xff, 0x04);
416 reg_w(gspca_dev, 0x02, 0x03);
417 reg_w(gspca_dev, 0xff, 0x01);
418 reg_w(gspca_dev, 0x08, 0x09);
419 reg_w(gspca_dev, 0x17, 0x30);
420 /* reg_w(gspca_dev, 0x80, 0x3f); */
421 reg_w(gspca_dev, 0x87, 0x11);
423 case 0: /* 640x480 */
424 reg_w(gspca_dev, 0xff, 0x04);
425 reg_w(gspca_dev, 0x02, 0x03);
426 reg_w(gspca_dev, 0xff, 0x01);
427 reg_w(gspca_dev, 0x08, 0x08);
428 reg_w(gspca_dev, 0x17, 0x00);
429 /* reg_w(gspca_dev, 0x80, 0x1c); */
430 reg_w(gspca_dev, 0x87, 0x12);
435 reg_w(gspca_dev, 0xff, 0x01);
436 reg_w(gspca_dev, 0x78, 0x04);
437 reg_w(gspca_dev, 0x78, 0x05);
440 sd->ag_cnt = AG_CNT_START;
447 static void sd_stopN(struct gspca_dev *gspca_dev)
449 reg_w(gspca_dev, 0xff, 0x04);
450 reg_w(gspca_dev, 0x27, 0x80);
451 reg_w(gspca_dev, 0x28, 0xca);
452 reg_w(gspca_dev, 0x29, 0x53);
453 reg_w(gspca_dev, 0x2a, 0x0e);
454 reg_w(gspca_dev, 0xff, 0x01);
455 reg_w(gspca_dev, 0x3e, 0x20);
456 reg_w(gspca_dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */
457 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
458 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
461 static void sd_stop0(struct gspca_dev *gspca_dev)
465 /* this function is called at close time */
466 static void sd_close(struct gspca_dev *gspca_dev)
468 reg_w(gspca_dev, 0xff, 0x04);
469 reg_w(gspca_dev, 0x27, 0x80);
470 reg_w(gspca_dev, 0x28, 0xca);
471 reg_w(gspca_dev, 0x29, 0x53);
472 reg_w(gspca_dev, 0x2a, 0x0e);
473 reg_w(gspca_dev, 0xff, 0x01);
474 reg_w(gspca_dev, 0x3e, 0x20);
475 reg_w(gspca_dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */
476 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
477 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
480 static void setautogain(struct gspca_dev *gspca_dev, int luma)
487 Gbright = reg_r(gspca_dev, 0x02);
488 PDEBUG(D_FRAM, "luma mean %d", luma);
489 if (luma < luma_mean - luma_delta ||
490 luma > luma_mean + luma_delta) {
491 Gbright += (luma_mean - luma) >> spring;
494 else if (Gbright < 4)
496 PDEBUG(D_FRAM, "gbright %d", Gbright);
497 reg_w(gspca_dev, 0xff, 0x04);
498 reg_w(gspca_dev, 0x0f, Gbright);
499 /* load registers to sensor (Bit 0, auto clear) */
500 reg_w(gspca_dev, 0x11, 0x01);
504 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
505 struct gspca_frame *frame, /* target */
506 __u8 *data, /* isoc packet */
507 int len) /* iso packet length */
509 struct sd *sd = (struct sd *) gspca_dev;
510 unsigned char tmpbuf[4];
515 /* gspca_dev->last_packet_type = DISCARD_PACKET; */
521 for (p = 0; p < len - 6; p++) {
522 if ((data[0 + p] == 0xff)
523 && (data[1 + p] == 0xff)
524 && (data[2 + p] == 0x00)
525 && (data[3 + p] == 0xff)
526 && (data[4 + p] == 0x96)) {
529 if (sd->ag_cnt >= 0 && p > 28) {
530 sd->avg_lum += data[p - 23];
531 if (--sd->ag_cnt < 0) {
532 sd->ag_cnt = AG_CNT_START;
533 setautogain(gspca_dev,
534 sd->avg_lum / AG_CNT_START);
539 /* copy the end of data to the current frame */
540 frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
543 /* put the JPEG header in the new frame */
544 gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
545 (unsigned char *) pac7311_jpeg_header,
547 tmpbuf[0] = gspca_dev->height >> 8;
548 tmpbuf[1] = gspca_dev->height & 0xff;
549 tmpbuf[2] = gspca_dev->width >> 8;
550 tmpbuf[3] = gspca_dev->width & 0xff;
551 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
553 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
554 (unsigned char *) &pac7311_jpeg_header[16],
555 PAC7311_JPEG_HEADER_SIZE - 16);
564 /* remove the 'ff ff ff xx' sequences */
571 if (data[0] == 0xff) {
574 frame->data_end -= 2;
579 && data[1] == 0xff) {
582 frame->data_end -= 1;
586 for (i = 0; i < len - 4; i++) {
588 && data[i + 1] == 0xff
589 && data[i + 2] == 0xff) {
590 memmove(&data[i], &data[i + 4], len - i - 4);
595 if (data[len - 4] == 0xff) {
596 if (data[len - 3] == 0xff
597 && data[len - 2] == 0xff) {
600 } else if (data[len - 3] == 0xff) {
601 if (data[len - 2] == 0xff
602 && data[len - 1] == 0xff)
604 } else if (data[len - 2] == 0xff) {
605 if (data[len - 1] == 0xff)
607 } else if (data[len - 1] == 0xff)
610 gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
613 static void getbrightness(struct gspca_dev *gspca_dev)
615 /* sd->brightness = reg_r(gspca_dev, 0x08);
616 return sd->brightness; */
617 /* PDEBUG(D_CONF, "Called pac7311_getbrightness: Not implemented yet"); */
622 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
624 struct sd *sd = (struct sd *) gspca_dev;
626 sd->brightness = val;
627 if (gspca_dev->streaming)
628 setbrightness(gspca_dev);
632 static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
634 struct sd *sd = (struct sd *) gspca_dev;
636 getbrightness(gspca_dev);
637 *val = sd->brightness;
641 static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
643 struct sd *sd = (struct sd *) gspca_dev;
646 if (gspca_dev->streaming)
647 setcontrast(gspca_dev);
651 static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
653 struct sd *sd = (struct sd *) gspca_dev;
655 /* getcontrast(gspca_dev); */
660 static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
662 struct sd *sd = (struct sd *) gspca_dev;
665 if (gspca_dev->streaming)
666 setcolors(gspca_dev);
670 static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
672 struct sd *sd = (struct sd *) gspca_dev;
674 /* getcolors(gspca_dev); */
679 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
681 struct sd *sd = (struct sd *) gspca_dev;
685 sd->ag_cnt = AG_CNT_START;
693 static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
695 struct sd *sd = (struct sd *) gspca_dev;
701 /* sub-driver description */
702 static struct sd_desc sd_desc = {
705 .nctrls = ARRAY_SIZE(sd_ctrls),
712 .pkt_scan = sd_pkt_scan,
715 /* -- module initialisation -- */
716 #define DVNM(name) .driver_info = (kernel_ulong_t) name
717 static __devinitdata struct usb_device_id device_table[] = {
718 {USB_DEVICE(0x093a, 0x2600), DVNM("Typhoon")},
719 {USB_DEVICE(0x093a, 0x2601), DVNM("Philips SPC610NC")},
720 {USB_DEVICE(0x093a, 0x2603), DVNM("PAC7312")},
721 {USB_DEVICE(0x093a, 0x2608), DVNM("Trust WB-3300p")},
722 {USB_DEVICE(0x093a, 0x260e), DVNM("Gigaware VGA PC Camera")},
723 /* and also ', Trust WB-3350p, SIGMA cam 2350' */
724 {USB_DEVICE(0x093a, 0x260f), DVNM("SnakeCam")},
725 {USB_DEVICE(0x093a, 0x2621), DVNM("PAC731x")},
728 MODULE_DEVICE_TABLE(usb, device_table);
730 /* -- device connect -- */
731 static int sd_probe(struct usb_interface *intf,
732 const struct usb_device_id *id)
734 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
738 static struct usb_driver sd_driver = {
740 .id_table = device_table,
742 .disconnect = gspca_disconnect,
745 /* -- module insert / remove -- */
746 static int __init sd_mod_init(void)
748 if (usb_register(&sd_driver) < 0)
750 PDEBUG(D_PROBE, "v%s registered", version);
753 static void __exit sd_mod_exit(void)
755 usb_deregister(&sd_driver);
756 PDEBUG(D_PROBE, "deregistered");
759 module_init(sd_mod_init);
760 module_exit(sd_mod_exit);