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 */
38 unsigned char brightness;
39 unsigned char contrast;
41 unsigned char autogain;
43 char ffnb; /* number of 'ff' in the previous frame */
44 char tosof; /* number of bytes before next start of frame */
46 #define AG_CNT_START 13
49 #define SENSOR_PAC7302 0
50 #define SENSOR_PAC7311 1
53 /* V4L2 controls supported by the driver */
54 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
55 static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
56 static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
57 static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
58 static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
59 static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
60 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
61 static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
63 static struct ctrl sd_ctrls[] = {
66 .id = V4L2_CID_BRIGHTNESS,
67 .type = V4L2_CTRL_TYPE_INTEGER,
70 #define BRIGHTNESS_MAX 0x20
71 .maximum = BRIGHTNESS_MAX,
73 #define BRIGHTNESS_DEF 0x10
74 .default_value = BRIGHTNESS_DEF,
76 .set = sd_setbrightness,
77 .get = sd_getbrightness,
81 .id = V4L2_CID_CONTRAST,
82 .type = V4L2_CTRL_TYPE_INTEGER,
87 #define CONTRAST_DEF 127
88 .default_value = CONTRAST_DEF,
90 .set = sd_setcontrast,
91 .get = sd_getcontrast,
95 .id = V4L2_CID_SATURATION,
96 .type = V4L2_CTRL_TYPE_INTEGER,
101 #define COLOR_DEF 127
102 .default_value = COLOR_DEF,
109 .id = V4L2_CID_AUTOGAIN,
110 .type = V4L2_CTRL_TYPE_BOOLEAN,
115 #define AUTOGAIN_DEF 1
116 .default_value = AUTOGAIN_DEF,
118 .set = sd_setautogain,
119 .get = sd_getautogain,
123 static struct v4l2_pix_format vga_mode[] = {
124 {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
126 .sizeimage = 160 * 120 * 3 / 8 + 590,
127 .colorspace = V4L2_COLORSPACE_JPEG,
129 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
131 .sizeimage = 320 * 240 * 3 / 8 + 590,
132 .colorspace = V4L2_COLORSPACE_JPEG,
134 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
136 .sizeimage = 640 * 480 * 3 / 8 + 590,
137 .colorspace = V4L2_COLORSPACE_JPEG,
141 #define PAC7311_JPEG_HEADER_SIZE (sizeof pac7311_jpeg_header) /* (594) */
143 static const __u8 pac7311_jpeg_header[] = {
145 0xff, 0xe0, 0x00, 0x03, 0x20,
146 0xff, 0xc0, 0x00, 0x11, 0x08,
147 0x01, 0xe0, /* 12: height */
148 0x02, 0x80, /* 14: width */
153 0xff, 0xdb, 0x00, 0x84,
154 0x00, 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, 0x0d,
155 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, 0x1a, 0x18, 0x16,
156 0x16, 0x18, 0x31, 0x23, 0x25, 0x1d, 0x28, 0x3a, 0x33, 0x3d,
157 0x3c, 0x39, 0x33, 0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40,
158 0x44, 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57, 0x5f,
159 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71, 0x79, 0x70, 0x64,
160 0x78, 0x5c, 0x65, 0x67, 0x63, 0x01, 0x11, 0x12, 0x12, 0x18,
161 0x15, 0x18, 0x2f, 0x1a, 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42,
162 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
163 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
164 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
165 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
166 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
167 0xff, 0xc4, 0x01, 0xa2, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01,
168 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
169 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
170 0x09, 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02,
171 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d,
172 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31,
173 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32,
174 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52,
175 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
176 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
177 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45,
178 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57,
179 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
180 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83,
181 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94,
182 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
183 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
184 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
185 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
186 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8,
187 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
188 0xf9, 0xfa, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01,
189 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
190 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
191 0x0b, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04,
192 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01,
193 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41,
194 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14,
195 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
196 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25,
197 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a,
198 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46,
199 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
200 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a,
201 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83,
202 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94,
203 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
204 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
205 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
206 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
207 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
208 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa,
209 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03,
210 0x11, 0x00, 0x3f, 0x00
214 static const __u8 probe_7302[] = {
216 0xff, 0x01, /* page 1 */
217 0x78, 0x00, /* deactivate */
219 0x78, 0x40, /* led off */
221 static const __u8 start_7302[] = {
222 /* index, len, [value]* */
223 0x00, 12, 0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80,
224 0x00, 0x00, 0x00, 0x00,
225 0x0d, 24, 0x03, 0x01, 0x00, 0xb5, 0x07, 0xcb, 0x00, 0x00,
226 0x07, 0xc8, 0x00, 0xea, 0x07, 0xcf, 0x07, 0xf7,
227 0x07, 0x7e, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x11,
231 0x3a, 3, 0x14, 0xff, 0x5a,
232 0x43, 11, 0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11,
235 0x62, 4, 0x10, 0x1e, 0x1e, 0x18,
237 0x6e, 3, 0x08, 0x06, 0x00,
238 0x72, 3, 0x00, 0xff, 0x00,
239 0x7d, 23, 0x01, 0x01, 0x58, 0x46, 0x50, 0x3c, 0x50, 0x3c,
240 0x54, 0x46, 0x54, 0x56, 0x52, 0x50, 0x52, 0x50,
241 0x56, 0x64, 0xa4, 0x00, 0xda, 0x00, 0x00,
242 0xa2, 10, 0x22, 0x2c, 0x3c, 0x54, 0x69, 0x7c, 0x9c, 0xb9,
247 0xc4, 4, 0xae, 0x01, 0x04, 0x01,
249 0xd1, 11, 0x01, 0x30, 0x49, 0x5e, 0x6f, 0x7f, 0x8e, 0xa9,
253 0x12, 3, 0x02, 0x00, 0x01,
255 0x76, 5, 0x01, 0x20, 0x40, 0x00, 0xf2,
257 0x7f, 10, 0x4b, 0x0f, 0x01, 0x2c, 0x02, 0x58, 0x03, 0x20,
259 0x96, 5, 0x01, 0x10, 0x04, 0x01, 0x04,
260 0xc8, 17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
261 0x07, 0x00, 0x01, 0x07, 0x04, 0x01,
264 0xde, 8, 0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x00,
265 0xe6, 4, 0x00, 0x00, 0x00, 0x01,
270 0x00, 255, /* load the page 3 */
274 0x22, 4, 0x1f, 0xa4, 0xf0, 0x96,
276 0x2a, 5, 0xc8, 0x00, 0x18, 0x12, 0x22,
277 0x64, 8, 0x00, 0x00, 0xf0, 0x01, 0x14, 0x44, 0x44, 0x44,
281 0, 0 /* end of sequence */
284 /* page 3 - the value 0xaa says skip the index - see reg_w_page() */
285 static const __u8 page3_7302[] = {
286 0x90, 0x40, 0x03, 0x50, 0xc2, 0x01, 0x14, 0x16,
287 0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00,
288 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
289 0x00, 0x00, 0x00, 0x47, 0x01, 0xb3, 0x01, 0x00,
290 0x00, 0x08, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x21,
291 0x00, 0x00, 0x00, 0x54, 0xf4, 0x02, 0x52, 0x54,
292 0xa4, 0xb8, 0xe0, 0x2a, 0xf6, 0x00, 0x00, 0x00,
293 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
294 0x00, 0xfc, 0x00, 0xf2, 0x1f, 0x04, 0x00, 0x00,
295 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x10, 0x00, 0x00,
296 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
297 0x00, 0x40, 0xff, 0x03, 0x19, 0x00, 0x00, 0x00,
298 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
299 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0xc8, 0xc8,
300 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,
301 0x08, 0x10, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00,
302 0x01, 0x00, 0x02, 0x47, 0x00, 0x00, 0x00, 0x00,
303 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
304 0x00, 0x02, 0xfa, 0x00, 0x64, 0x5a, 0x28, 0x00,
309 static const __u8 probe_7311[] = {
310 0x78, 0x40, /* Bit_0=start stream, Bit_7=LED */
311 0x78, 0x40, /* Bit_0=start stream, Bit_7=LED */
312 0x78, 0x44, /* Bit_0=start stream, Bit_7=LED */
322 static const __u8 start_7311[] = {
323 /* index, len, [value]* */
325 0x02, 53, 0x48, 0x0a, 0x40, 0x08, 0x00, 0x00, 0x08, 0x00,
326 0x06, 0xff, 0x11, 0xff, 0x5a, 0x30, 0x90, 0x4c,
327 0x00, 0x07, 0x00, 0x0a, 0x10, 0x00, 0xa0, 0x10,
328 0x02, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x01, 0x00,
329 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
331 0x3e, 52, 0x00, 0x00, 0x78, 0x52, 0x4a, 0x52, 0x78, 0x6e,
332 0x48, 0x46, 0x48, 0x6e, 0x5f, 0x49, 0x42, 0x49,
333 0x5f, 0x5f, 0x49, 0x42, 0x49, 0x5f, 0x6e, 0x48,
334 0x46, 0x48, 0x6e, 0x78, 0x52, 0x4a, 0x52, 0x78,
335 0x00, 0x00, 0x09, 0x1b, 0x34, 0x49, 0x5c, 0x9b,
337 0x78, 6, 0x44, 0x00, 0xf2, 0x01, 0x01, 0x80,
338 0x7f, 18, 0x2a, 0x1c, 0x00, 0xc8, 0x02, 0x58, 0x03, 0x84,
339 0x12, 0x00, 0x1a, 0x04, 0x08, 0x0c, 0x10, 0x14,
341 0x96, 3, 0x01, 0x08, 0x04,
342 0xa0, 4, 0x44, 0x44, 0x44, 0x04,
343 0xf0, 13, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x20, 0x00,
344 0x3f, 0x00, 0x0a, 0x01, 0x00,
346 0x00, 254, /* load the page 4 */
348 0, 0 /* end of sequence */
351 /* page 4 - the value 0xaa says skip the index - see reg_w_page() */
352 static const __u8 page4_7311[] = {
353 0xaa, 0xaa, 0x04, 0x54, 0x07, 0x2b, 0x09, 0x0f,
354 0x09, 0x00, 0xaa, 0xaa, 0x07, 0x00, 0x00, 0x62,
355 0x08, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
356 0x00, 0x00, 0x00, 0x03, 0xa0, 0x01, 0xf4, 0xaa,
357 0xaa, 0x00, 0x08, 0xaa, 0x03, 0xaa, 0x00, 0x01,
358 0xca, 0x10, 0x06, 0x78, 0x00, 0x00, 0x00, 0x00,
359 0x23, 0x28, 0x04, 0x11, 0x00, 0x00
362 static void reg_w_buf(struct gspca_dev *gspca_dev,
364 const char *buffer, int len)
366 memcpy(gspca_dev->usb_buf, buffer, len);
367 usb_control_msg(gspca_dev->dev,
368 usb_sndctrlpipe(gspca_dev->dev, 0),
370 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
372 index, gspca_dev->usb_buf, len,
376 static __u8 reg_r(struct gspca_dev *gspca_dev,
379 usb_control_msg(gspca_dev->dev,
380 usb_rcvctrlpipe(gspca_dev->dev, 0),
382 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
384 index, gspca_dev->usb_buf, 1,
386 return gspca_dev->usb_buf[0];
389 static void reg_w(struct gspca_dev *gspca_dev,
393 gspca_dev->usb_buf[0] = value;
394 usb_control_msg(gspca_dev->dev,
395 usb_sndctrlpipe(gspca_dev->dev, 0),
397 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
398 value, index, gspca_dev->usb_buf, 1,
402 static void reg_w_seq(struct gspca_dev *gspca_dev,
403 const __u8 *seq, int len)
406 reg_w(gspca_dev, seq[0], seq[1]);
411 /* load the beginning of a page */
412 static void reg_w_page(struct gspca_dev *gspca_dev,
413 const __u8 *page, int len)
417 for (index = 0; index < len; index++) {
418 if (page[index] == 0xaa) /* skip this index */
420 gspca_dev->usb_buf[0] = page[index];
421 usb_control_msg(gspca_dev->dev,
422 usb_sndctrlpipe(gspca_dev->dev, 0),
424 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
425 0, index, gspca_dev->usb_buf, 1,
430 /* output a variable sequence */
431 static void reg_w_var(struct gspca_dev *gspca_dev,
443 reg_w_page(gspca_dev, page4_7311, sizeof page4_7311);
446 reg_w_page(gspca_dev, page3_7302, sizeof page3_7302);
450 PDEBUG(D_ERR|D_STREAM,
451 "Incorrect variable sequence");
456 reg_w_buf(gspca_dev, index, seq, len);
460 reg_w_buf(gspca_dev, index, seq, 8);
470 /* this function is called at probe time */
471 static int sd_config(struct gspca_dev *gspca_dev,
472 const struct usb_device_id *id)
474 struct sd *sd = (struct sd *) gspca_dev;
477 cam = &gspca_dev->cam;
480 sd->sensor = id->driver_info;
481 if (sd->sensor == SENSOR_PAC7302) {
482 PDEBUG(D_CONF, "Find Sensor PAC7302");
483 reg_w_seq(gspca_dev, probe_7302, sizeof probe_7302);
485 cam->cam_mode = &vga_mode[2]; /* only 640x480 */
488 PDEBUG(D_CONF, "Find Sensor PAC7311");
489 reg_w_seq(gspca_dev, probe_7302, sizeof probe_7302);
491 cam->cam_mode = vga_mode;
492 cam->nmodes = ARRAY_SIZE(vga_mode);
495 sd->brightness = BRIGHTNESS_DEF;
496 sd->contrast = CONTRAST_DEF;
497 sd->colors = COLOR_DEF;
498 sd->autogain = AUTOGAIN_DEF;
503 static void setbrightness(struct gspca_dev *gspca_dev)
505 struct sd *sd = (struct sd *) gspca_dev;
508 if (sd->sensor == SENSOR_PAC7302)
511 brightness = BRIGHTNESS_MAX - sd->brightness;
512 reg_w(gspca_dev, 0xff, 0x04);
513 reg_w(gspca_dev, 0x0f, brightness);
514 /* load registers to sensor (Bit 0, auto clear) */
515 reg_w(gspca_dev, 0x11, 0x01);
516 PDEBUG(D_CONF|D_STREAM, "brightness: %i", brightness);
519 static void setcontrast(struct gspca_dev *gspca_dev)
521 struct sd *sd = (struct sd *) gspca_dev;
523 if (sd->sensor == SENSOR_PAC7302)
525 reg_w(gspca_dev, 0xff, 0x01);
526 reg_w(gspca_dev, 0x80, sd->contrast);
527 /* load registers to sensor (Bit 0, auto clear) */
528 reg_w(gspca_dev, 0x11, 0x01);
529 PDEBUG(D_CONF|D_STREAM, "contrast: %i", sd->contrast);
532 static void setcolors(struct gspca_dev *gspca_dev)
534 struct sd *sd = (struct sd *) gspca_dev;
536 if (sd->sensor == SENSOR_PAC7302)
538 reg_w(gspca_dev, 0xff, 0x01);
539 reg_w(gspca_dev, 0x10, sd->colors);
540 /* load registers to sensor (Bit 0, auto clear) */
541 reg_w(gspca_dev, 0x11, 0x01);
542 PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
545 static void setautogain(struct gspca_dev *gspca_dev)
547 struct sd *sd = (struct sd *) gspca_dev;
551 sd->ag_cnt = AG_CNT_START;
557 /* this function is called at open time */
558 static int sd_open(struct gspca_dev *gspca_dev)
560 reg_w(gspca_dev, 0x78, 0x00); /* Turn on LED */
564 static void sd_start(struct gspca_dev *gspca_dev)
566 struct sd *sd = (struct sd *) gspca_dev;
571 if (sd->sensor == SENSOR_PAC7302)
572 reg_w_var(gspca_dev, start_7302);
574 reg_w_var(gspca_dev, start_7311);
576 setcontrast(gspca_dev);
577 setbrightness(gspca_dev);
578 setcolors(gspca_dev);
579 setautogain(gspca_dev);
581 /* set correct resolution */
582 switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
583 case 2: /* 160x120 pac7311 */
584 reg_w(gspca_dev, 0xff, 0x04);
585 reg_w(gspca_dev, 0x02, 0x03);
586 reg_w(gspca_dev, 0xff, 0x01);
587 reg_w(gspca_dev, 0x08, 0x09);
588 reg_w(gspca_dev, 0x17, 0x20);
589 reg_w(gspca_dev, 0x1b, 0x00);
590 /* reg_w(gspca_dev, 0x80, 0x69); */
591 reg_w(gspca_dev, 0x87, 0x10);
593 case 1: /* 320x240 pac7311 */
594 reg_w(gspca_dev, 0xff, 0x04);
595 reg_w(gspca_dev, 0x02, 0x03);
596 reg_w(gspca_dev, 0xff, 0x01);
597 reg_w(gspca_dev, 0x08, 0x09);
598 reg_w(gspca_dev, 0x17, 0x30);
599 /* reg_w(gspca_dev, 0x80, 0x3f); */
600 reg_w(gspca_dev, 0x87, 0x11);
602 case 0: /* 640x480 */
603 if (sd->sensor == SENSOR_PAC7302)
605 reg_w(gspca_dev, 0xff, 0x04);
606 reg_w(gspca_dev, 0x02, 0x03);
607 reg_w(gspca_dev, 0xff, 0x01);
608 reg_w(gspca_dev, 0x08, 0x08);
609 reg_w(gspca_dev, 0x17, 0x00);
610 /* reg_w(gspca_dev, 0x80, 0x1c); */
611 reg_w(gspca_dev, 0x87, 0x12);
616 reg_w(gspca_dev, 0xff, 0x01);
617 if (sd->sensor == SENSOR_PAC7302) {
618 reg_w(gspca_dev, 0x78, 0x01);
619 reg_w(gspca_dev, 0xff, 0x01);
620 reg_w(gspca_dev, 0x78, 0x01);
622 reg_w(gspca_dev, 0x78, 0x04);
623 reg_w(gspca_dev, 0x78, 0x05);
627 static void sd_stopN(struct gspca_dev *gspca_dev)
629 struct sd *sd = (struct sd *) gspca_dev;
631 if (sd->sensor == SENSOR_PAC7302) {
632 reg_w(gspca_dev, 0x78, 0x00);
633 reg_w(gspca_dev, 0x78, 0x00);
636 reg_w(gspca_dev, 0xff, 0x04);
637 reg_w(gspca_dev, 0x27, 0x80);
638 reg_w(gspca_dev, 0x28, 0xca);
639 reg_w(gspca_dev, 0x29, 0x53);
640 reg_w(gspca_dev, 0x2a, 0x0e);
641 reg_w(gspca_dev, 0xff, 0x01);
642 reg_w(gspca_dev, 0x3e, 0x20);
643 reg_w(gspca_dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */
644 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
645 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
648 static void sd_stop0(struct gspca_dev *gspca_dev)
650 struct sd *sd = (struct sd *) gspca_dev;
652 if (sd->sensor == SENSOR_PAC7302) {
653 reg_w(gspca_dev, 0xff, 0x01);
654 reg_w(gspca_dev, 0x78, 0x40);
658 /* this function is called at close time */
659 static void sd_close(struct gspca_dev *gspca_dev)
663 static void do_autogain(struct gspca_dev *gspca_dev)
665 struct sd *sd = (struct sd *) gspca_dev;
672 if (!atomic_read(&sd->do_gain))
674 atomic_set(&sd->do_gain, 0);
676 luma = atomic_read(&sd->avg_lum);
677 Gbright = reg_r(gspca_dev, 0x02);
678 PDEBUG(D_FRAM, "luma mean %d", luma);
679 if (luma < luma_mean - luma_delta ||
680 luma > luma_mean + luma_delta) {
681 Gbright += (luma_mean - luma) >> spring;
684 else if (Gbright < 4)
686 PDEBUG(D_FRAM, "gbright %d", Gbright);
687 if (sd->sensor == SENSOR_PAC7302) {
688 reg_w(gspca_dev, 0xff, 0x03);
689 reg_w(gspca_dev, 0x10, Gbright);
690 /* load registers to sensor (Bit 0, auto clear) */
691 reg_w(gspca_dev, 0x11, 0x01);
693 reg_w(gspca_dev, 0xff, 0x04);
694 reg_w(gspca_dev, 0x0f, Gbright);
695 /* load registers to sensor (Bit 0, auto clear) */
696 reg_w(gspca_dev, 0x11, 0x01);
701 /* output the jpeg header */
702 static void put_jpeg_head(struct gspca_dev *gspca_dev,
703 struct gspca_frame *frame)
705 unsigned char tmpbuf[4];
707 gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
708 (__u8 *) pac7311_jpeg_header,
710 tmpbuf[0] = gspca_dev->height >> 8;
711 tmpbuf[1] = gspca_dev->height & 0xff;
712 tmpbuf[2] = gspca_dev->width >> 8;
713 tmpbuf[3] = gspca_dev->width & 0xff;
714 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
716 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
717 (__u8 *) &pac7311_jpeg_header[16],
718 PAC7311_JPEG_HEADER_SIZE - 16);
721 /* this function is run at interrupt level */
722 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
723 struct gspca_frame *frame, /* target */
724 __u8 *data, /* isoc packet */
725 int len) /* iso packet length */
727 struct sd *sd = (struct sd *) gspca_dev;
730 #define INTER_FRAME 0x53
731 #define LUM_OFFSET 0x1e /* reverse offset / start of frame */
734 * inside a frame, there may be:
735 * escaped ff ('ff 00')
736 * sequences'ff ff ff xx' to remove
737 * end of frame ('ff d9')
738 * at the end of frame, there are:
741 * one byte luminosity
743 * ff ff 00 ff 96 62 44 start of frame header
746 if (sd->tosof == 0) { /* if inside a frame */
748 /* check for 'ff ff ff xx' at start and at end of packet */
749 /* (len is always >= 3) */
753 break; /* keep 'ff 00' */
757 data += 4 - sd->ffnb;
762 if (data[len - 1] == 0xff) {
763 if (data[len - 2] == 0xff) {
764 if (data[len - 3] == 0xff) {
776 } else { /* outside a frame */
780 * and go to the start of frame
784 if (sd->tosof > LUM_OFFSET)
785 sd->lum_sum += data[-LUM_OFFSET];
786 put_jpeg_head(gspca_dev, frame);
790 for (i = 0; i < len; i++) {
793 switch (data[i + 1]) {
794 case 0xd9: /* end of frame */
796 frame = gspca_frame_add(gspca_dev,
799 data += i + INTER_FRAME;
800 len -= i + INTER_FRAME;
802 if (len > -LUM_OFFSET)
803 sd->lum_sum += data[-LUM_OFFSET];
808 put_jpeg_head(gspca_dev, frame);
810 case 0xff: /* 'ff ff ff xx' */
811 gspca_frame_add(gspca_dev, INTER_PACKET,
821 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
823 struct sd *sd = (struct sd *) gspca_dev;
825 sd->brightness = val;
826 if (gspca_dev->streaming)
827 setbrightness(gspca_dev);
831 static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
833 struct sd *sd = (struct sd *) gspca_dev;
835 *val = sd->brightness;
839 static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
841 struct sd *sd = (struct sd *) gspca_dev;
844 if (gspca_dev->streaming)
845 setcontrast(gspca_dev);
849 static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
851 struct sd *sd = (struct sd *) gspca_dev;
857 static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
859 struct sd *sd = (struct sd *) gspca_dev;
862 if (gspca_dev->streaming)
863 setcolors(gspca_dev);
867 static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
869 struct sd *sd = (struct sd *) gspca_dev;
875 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
877 struct sd *sd = (struct sd *) gspca_dev;
880 if (gspca_dev->streaming)
881 setautogain(gspca_dev);
885 static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
887 struct sd *sd = (struct sd *) gspca_dev;
893 /* sub-driver description */
894 static struct sd_desc sd_desc = {
897 .nctrls = ARRAY_SIZE(sd_ctrls),
904 .pkt_scan = sd_pkt_scan,
905 .dq_callback = do_autogain,
908 /* -- module initialisation -- */
909 static __devinitdata struct usb_device_id device_table[] = {
910 {USB_DEVICE(0x093a, 0x2600), .driver_info = SENSOR_PAC7311},
911 {USB_DEVICE(0x093a, 0x2601), .driver_info = SENSOR_PAC7311},
912 {USB_DEVICE(0x093a, 0x2603), .driver_info = SENSOR_PAC7311},
913 {USB_DEVICE(0x093a, 0x2608), .driver_info = SENSOR_PAC7311},
914 {USB_DEVICE(0x093a, 0x260e), .driver_info = SENSOR_PAC7311},
915 {USB_DEVICE(0x093a, 0x260f), .driver_info = SENSOR_PAC7311},
916 {USB_DEVICE(0x093a, 0x2621), .driver_info = SENSOR_PAC7302},
919 MODULE_DEVICE_TABLE(usb, device_table);
921 /* -- device connect -- */
922 static int sd_probe(struct usb_interface *intf,
923 const struct usb_device_id *id)
925 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
929 static struct usb_driver sd_driver = {
931 .id_table = device_table,
933 .disconnect = gspca_disconnect,
936 /* -- module insert / remove -- */
937 static int __init sd_mod_init(void)
939 if (usb_register(&sd_driver) < 0)
941 PDEBUG(D_PROBE, "registered");
944 static void __exit sd_mod_exit(void)
946 usb_deregister(&sd_driver);
947 PDEBUG(D_PROBE, "deregistered");
950 module_init(sd_mod_init);
951 module_exit(sd_mod_exit);