blob: 14cc49a4c2cc46a907969f87d899a9babd0e5e56 [file] [log] [blame]
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -03001/*
2 * Pixart PAC7311 library
3 * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li
4 *
5 * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
6 *
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
10 * any later version.
11 *
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.
16 *
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
20 */
21
22#define MODULE_NAME "pac7311"
23
24#include "gspca.h"
25
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -030026#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 3)
27static const char version[] = "2.1.3";
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030028
29MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li");
30MODULE_DESCRIPTION("Pixart PAC7311");
31MODULE_LICENSE("GPL");
32
33/* specific webcam descriptor */
34struct sd {
35 struct gspca_dev gspca_dev; /* !! must be the first item */
36
37 int avg_lum;
38
39 unsigned char brightness;
40#define BRIGHTNESS_MAX 0x20
41 unsigned char contrast;
42 unsigned char colors;
43 unsigned char autogain;
44
45 char ffseq;
46 signed char ag_cnt;
47#define AG_CNT_START 13
48};
49
50/* V4L2 controls supported by the driver */
51static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
52static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
53static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
54static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
55static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
56static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
57static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
58static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
59
60static struct ctrl sd_ctrls[] = {
61#define SD_BRIGHTNESS 0
62 {
63 {
64 .id = V4L2_CID_BRIGHTNESS,
65 .type = V4L2_CTRL_TYPE_INTEGER,
66 .name = "Brightness",
67 .minimum = 0,
68 .maximum = BRIGHTNESS_MAX,
69 .step = 1,
70 .default_value = 0x10,
71 },
72 .set = sd_setbrightness,
73 .get = sd_getbrightness,
74 },
75#define SD_CONTRAST 1
76 {
77 {
78 .id = V4L2_CID_CONTRAST,
79 .type = V4L2_CTRL_TYPE_INTEGER,
80 .name = "Contrast",
81 .minimum = 0,
82 .maximum = 255,
83 .step = 1,
84 .default_value = 127,
85 },
86 .set = sd_setcontrast,
87 .get = sd_getcontrast,
88 },
89#define SD_COLOR 2
90 {
91 {
92 .id = V4L2_CID_SATURATION,
93 .type = V4L2_CTRL_TYPE_INTEGER,
94 .name = "Color",
95 .minimum = 0,
96 .maximum = 255,
97 .step = 1,
98 .default_value = 127,
99 },
100 .set = sd_setcolors,
101 .get = sd_getcolors,
102 },
103#define SD_AUTOGAIN 3
104 {
105 {
106 .id = V4L2_CID_AUTOGAIN,
107 .type = V4L2_CTRL_TYPE_BOOLEAN,
108 .name = "Auto Gain",
109 .minimum = 0,
110 .maximum = 1,
111 .step = 1,
112 .default_value = 1,
113 },
114 .set = sd_setautogain,
115 .get = sd_getautogain,
116 },
117};
118
119static struct cam_mode vga_mode[] = {
120 {V4L2_PIX_FMT_JPEG, 160, 120, 2},
121 {V4L2_PIX_FMT_JPEG, 320, 240, 1},
122 {V4L2_PIX_FMT_JPEG, 640, 480, 0},
123};
124
125#define PAC7311_JPEG_HEADER_SIZE (sizeof pac7311_jpeg_header) /* (594) */
126
127const unsigned char pac7311_jpeg_header[] = {
128 0xff, 0xd8,
129 0xff, 0xe0, 0x00, 0x03, 0x20,
130 0xff, 0xc0, 0x00, 0x11, 0x08,
131 0x01, 0xe0, /* 12: height */
132 0x02, 0x80, /* 14: width */
133 0x03, /* 16 */
134 0x01, 0x21, 0x00,
135 0x02, 0x11, 0x01,
136 0x03, 0x11, 0x01,
137 0xff, 0xdb, 0x00, 0x84,
138 0x00, 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, 0x0d,
139 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, 0x1a, 0x18, 0x16,
140 0x16, 0x18, 0x31, 0x23, 0x25, 0x1d, 0x28, 0x3a, 0x33, 0x3d,
141 0x3c, 0x39, 0x33, 0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40,
142 0x44, 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57, 0x5f,
143 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71, 0x79, 0x70, 0x64,
144 0x78, 0x5c, 0x65, 0x67, 0x63, 0x01, 0x11, 0x12, 0x12, 0x18,
145 0x15, 0x18, 0x2f, 0x1a, 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42,
146 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
147 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
148 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
149 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
150 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
151 0xff, 0xc4, 0x01, 0xa2, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01,
152 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
153 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
154 0x09, 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02,
155 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d,
156 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31,
157 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32,
158 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52,
159 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
160 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
161 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45,
162 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57,
163 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
164 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83,
165 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94,
166 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
167 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
168 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
169 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
170 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8,
171 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
172 0xf9, 0xfa, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01,
173 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
174 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
175 0x0b, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04,
176 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01,
177 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41,
178 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14,
179 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
180 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25,
181 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a,
182 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46,
183 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
184 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a,
185 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83,
186 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94,
187 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
188 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
189 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
190 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
191 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
192 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa,
193 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03,
194 0x11, 0x00, 0x3f, 0x00
195};
196
197static void reg_w(struct usb_device *dev,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300198 __u16 index,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300199 char *buffer, __u16 len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300200{
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300201 __u8 tmpbuf[8];
202
203 memcpy(tmpbuf, buffer, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300204 usb_control_msg(dev,
205 usb_sndctrlpipe(dev, 0),
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300206 1, /* request */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300207 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300208 0, /* value */
209 index, tmpbuf, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300210 500);
211}
212
213static void pac7311_reg_read(struct usb_device *dev, __u16 index,
214 __u8 *buffer)
215{
216 usb_control_msg(dev,
217 usb_rcvctrlpipe(dev, 0),
218 0, /* request */
219 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
220 0, /* value */
221 index, buffer, 1,
222 500);
223}
224
225static void pac7311_reg_write(struct usb_device *dev,
226 __u16 index,
227 __u8 value)
228{
229 __u8 buf;
230
231 buf = value;
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300232 usb_control_msg(dev,
233 usb_sndctrlpipe(dev, 0),
234 0, /* request */
235 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
236 value, index, &buf, 1,
237 500);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300238}
239
240/* this function is called at probe time */
241static int sd_config(struct gspca_dev *gspca_dev,
242 const struct usb_device_id *id)
243{
244 struct sd *sd = (struct sd *) gspca_dev;
245 struct usb_device *dev = gspca_dev->dev;
246 struct cam *cam;
247
248 PDEBUG(D_CONF, "Find Sensor PAC7311");
249 pac7311_reg_write(dev, 0x78, 0x40); /* Bit_0=start stream, Bit_7=LED */
250 pac7311_reg_write(dev, 0x78, 0x40); /* Bit_0=start stream, Bit_7=LED */
251 pac7311_reg_write(dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
252 pac7311_reg_write(dev, 0xff, 0x04);
253 pac7311_reg_write(dev, 0x27, 0x80);
254 pac7311_reg_write(dev, 0x28, 0xca);
255 pac7311_reg_write(dev, 0x29, 0x53);
256 pac7311_reg_write(dev, 0x2a, 0x0e);
257 pac7311_reg_write(dev, 0xff, 0x01);
258 pac7311_reg_write(dev, 0x3e, 0x20);
259
260 cam = &gspca_dev->cam;
261 cam->dev_name = (char *) id->driver_info;
262 cam->epaddr = 0x05;
263 cam->cam_mode = vga_mode;
264 cam->nmodes = ARRAY_SIZE(vga_mode);
265
266 sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
267 sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
268 sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
269 sd->autogain = sd_ctrls[SD_AUTOGAIN].qctrl.default_value;
270 return 0;
271}
272
273static void setbrightness(struct gspca_dev *gspca_dev)
274{
275 struct sd *sd = (struct sd *) gspca_dev;
276 int brightness;
277
278/*jfm: inverted?*/
279 brightness = BRIGHTNESS_MAX - sd->brightness;
280 pac7311_reg_write(gspca_dev->dev, 0xff, 0x04);
281 /* pac7311_reg_write(gspca_dev->dev, 0x0e, 0x00); */
282 pac7311_reg_write(gspca_dev->dev, 0x0f, brightness);
283 /* load registers to sensor (Bit 0, auto clear) */
284 pac7311_reg_write(gspca_dev->dev, 0x11, 0x01);
285 PDEBUG(D_CONF|D_STREAM, "brightness: %i", brightness);
286}
287
288static void setcontrast(struct gspca_dev *gspca_dev)
289{
290 struct sd *sd = (struct sd *) gspca_dev;
291
292 pac7311_reg_write(gspca_dev->dev, 0xff, 0x01);
293 pac7311_reg_write(gspca_dev->dev, 0x80, sd->contrast);
294 /* load registers to sensor (Bit 0, auto clear) */
295 pac7311_reg_write(gspca_dev->dev, 0x11, 0x01);
296 PDEBUG(D_CONF|D_STREAM, "contrast: %i", sd->contrast);
297}
298
299static void setcolors(struct gspca_dev *gspca_dev)
300{
301 struct sd *sd = (struct sd *) gspca_dev;
302
303 pac7311_reg_write(gspca_dev->dev, 0xff, 0x01);
304 pac7311_reg_write(gspca_dev->dev, 0x10, sd->colors);
305 /* load registers to sensor (Bit 0, auto clear) */
306 pac7311_reg_write(gspca_dev->dev, 0x11, 0x01);
307 PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
308}
309
310/* this function is called at open time */
311static int sd_open(struct gspca_dev *gspca_dev)
312{
313 pac7311_reg_write(gspca_dev->dev, 0x78, 0x00); /* Turn on LED */
314 return 0;
315}
316
317static void sd_start(struct gspca_dev *gspca_dev)
318{
319 struct usb_device *dev = gspca_dev->dev;
320 struct sd *sd = (struct sd *) gspca_dev;
321
322 pac7311_reg_write(dev, 0xff, 0x01);
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300323 reg_w(dev, 0x0002, "\x48\x0a\x40\x08\x00\x00\x08\x00", 8);
324 reg_w(dev, 0x000a, "\x06\xff\x11\xff\x5a\x30\x90\x4c", 8);
325 reg_w(dev, 0x0012, "\x00\x07\x00\x0a\x10\x00\xa0\x10", 8);
326 reg_w(dev, 0x001a, "\x02\x00\x00\x00\x00\x0b\x01\x00", 8);
327 reg_w(dev, 0x0022, "\x00\x00\x00\x00\x00\x00\x00\x00", 8);
328 reg_w(dev, 0x002a, "\x00\x00\x00", 3);
329 reg_w(dev, 0x003e, "\x00\x00\x78\x52\x4a\x52\x78\x6e", 8);
330 reg_w(dev, 0x0046, "\x48\x46\x48\x6e\x5f\x49\x42\x49", 8);
331 reg_w(dev, 0x004e, "\x5f\x5f\x49\x42\x49\x5f\x6e\x48", 8);
332 reg_w(dev, 0x0056, "\x46\x48\x6e\x78\x52\x4a\x52\x78", 8);
333 reg_w(dev, 0x005e, "\x00\x00\x09\x1b\x34\x49\x5c\x9b", 8);
334 reg_w(dev, 0x0066, "\xd0\xff", 2);
335 reg_w(dev, 0x0078, "\x44\x00\xf2\x01\x01\x80", 6);
336 reg_w(dev, 0x007f, "\x2a\x1c\x00\xc8\x02\x58\x03\x84", 8);
337 reg_w(dev, 0x0087, "\x12\x00\x1a\x04\x08\x0c\x10\x14", 8);
338 reg_w(dev, 0x008f, "\x18\x20", 2);
339 reg_w(dev, 0x0096, "\x01\x08\x04", 3);
340 reg_w(dev, 0x00a0, "\x44\x44\x44\x04", 4);
341 reg_w(dev, 0x00f0, "\x01\x00\x00\x00\x22\x00\x20\x00", 8);
342 reg_w(dev, 0x00f8, "\x3f\x00\x0a\x01\x00", 5);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300343
344 pac7311_reg_write(dev, 0xff, 0x04);
345 pac7311_reg_write(dev, 0x02, 0x04);
346 pac7311_reg_write(dev, 0x03, 0x54);
347 pac7311_reg_write(dev, 0x04, 0x07);
348 pac7311_reg_write(dev, 0x05, 0x2b);
349 pac7311_reg_write(dev, 0x06, 0x09);
350 pac7311_reg_write(dev, 0x07, 0x0f);
351 pac7311_reg_write(dev, 0x08, 0x09);
352 pac7311_reg_write(dev, 0x09, 0x00);
353 pac7311_reg_write(dev, 0x0c, 0x07);
354 pac7311_reg_write(dev, 0x0d, 0x00);
355 pac7311_reg_write(dev, 0x0e, 0x00);
356 pac7311_reg_write(dev, 0x0f, 0x62);
357 pac7311_reg_write(dev, 0x10, 0x08);
358 pac7311_reg_write(dev, 0x12, 0x07);
359 pac7311_reg_write(dev, 0x13, 0x00);
360 pac7311_reg_write(dev, 0x14, 0x00);
361 pac7311_reg_write(dev, 0x15, 0x00);
362 pac7311_reg_write(dev, 0x16, 0x00);
363 pac7311_reg_write(dev, 0x17, 0x00);
364 pac7311_reg_write(dev, 0x18, 0x00);
365 pac7311_reg_write(dev, 0x19, 0x00);
366 pac7311_reg_write(dev, 0x1a, 0x00);
367 pac7311_reg_write(dev, 0x1b, 0x03);
368 pac7311_reg_write(dev, 0x1c, 0xa0);
369 pac7311_reg_write(dev, 0x1d, 0x01);
370 pac7311_reg_write(dev, 0x1e, 0xf4);
371 pac7311_reg_write(dev, 0x21, 0x00);
372 pac7311_reg_write(dev, 0x22, 0x08);
373 pac7311_reg_write(dev, 0x24, 0x03);
374 pac7311_reg_write(dev, 0x26, 0x00);
375 pac7311_reg_write(dev, 0x27, 0x01);
376 pac7311_reg_write(dev, 0x28, 0xca);
377 pac7311_reg_write(dev, 0x29, 0x10);
378 pac7311_reg_write(dev, 0x2a, 0x06);
379 pac7311_reg_write(dev, 0x2b, 0x78);
380 pac7311_reg_write(dev, 0x2c, 0x00);
381 pac7311_reg_write(dev, 0x2d, 0x00);
382 pac7311_reg_write(dev, 0x2e, 0x00);
383 pac7311_reg_write(dev, 0x2f, 0x00);
384 pac7311_reg_write(dev, 0x30, 0x23);
385 pac7311_reg_write(dev, 0x31, 0x28);
386 pac7311_reg_write(dev, 0x32, 0x04);
387 pac7311_reg_write(dev, 0x33, 0x11);
388 pac7311_reg_write(dev, 0x34, 0x00);
389 pac7311_reg_write(dev, 0x35, 0x00);
390 pac7311_reg_write(dev, 0x11, 0x01);
391 setcontrast(gspca_dev);
392 setbrightness(gspca_dev);
393 setcolors(gspca_dev);
394
395 /* set correct resolution */
396 switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].mode) {
397 case 2: /* 160x120 */
398 pac7311_reg_write(dev, 0xff, 0x04);
399 pac7311_reg_write(dev, 0x02, 0x03);
400 pac7311_reg_write(dev, 0xff, 0x01);
401 pac7311_reg_write(dev, 0x08, 0x09);
402 pac7311_reg_write(dev, 0x17, 0x20);
403 pac7311_reg_write(dev, 0x1b, 0x00);
404/* pac7311_reg_write(dev, 0x80, 0x69); */
405 pac7311_reg_write(dev, 0x87, 0x10);
406 break;
407 case 1: /* 320x240 */
408 pac7311_reg_write(dev, 0xff, 0x04);
409 pac7311_reg_write(dev, 0x02, 0x03);
410 pac7311_reg_write(dev, 0xff, 0x01);
411 pac7311_reg_write(dev, 0x08, 0x09);
412 pac7311_reg_write(dev, 0x17, 0x30);
413/* pac7311_reg_write(dev, 0x80, 0x3f); */
414 pac7311_reg_write(dev, 0x87, 0x11);
415 break;
416 case 0: /* 640x480 */
417 pac7311_reg_write(dev, 0xff, 0x04);
418 pac7311_reg_write(dev, 0x02, 0x03);
419 pac7311_reg_write(dev, 0xff, 0x01);
420 pac7311_reg_write(dev, 0x08, 0x08);
421 pac7311_reg_write(dev, 0x17, 0x00);
422/* pac7311_reg_write(dev, 0x80, 0x1c); */
423 pac7311_reg_write(dev, 0x87, 0x12);
424 break;
425 }
426
427 /* start stream */
428 pac7311_reg_write(dev, 0xff, 0x01);
429 pac7311_reg_write(dev, 0x78, 0x04);
430 pac7311_reg_write(dev, 0x78, 0x05);
431
432 if (sd->autogain) {
433 sd->ag_cnt = AG_CNT_START;
434 sd->avg_lum = 0;
435 } else {
436 sd->ag_cnt = -1;
437 }
438}
439
440static void sd_stopN(struct gspca_dev *gspca_dev)
441{
442 struct usb_device *dev = gspca_dev->dev;
443
444 pac7311_reg_write(dev, 0xff, 0x04);
445 pac7311_reg_write(dev, 0x27, 0x80);
446 pac7311_reg_write(dev, 0x28, 0xca);
447 pac7311_reg_write(dev, 0x29, 0x53);
448 pac7311_reg_write(dev, 0x2a, 0x0e);
449 pac7311_reg_write(dev, 0xff, 0x01);
450 pac7311_reg_write(dev, 0x3e, 0x20);
451 pac7311_reg_write(dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */
452 pac7311_reg_write(dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
453 pac7311_reg_write(dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
454}
455
456static void sd_stop0(struct gspca_dev *gspca_dev)
457{
458}
459
460/* this function is called at close time */
461static void sd_close(struct gspca_dev *gspca_dev)
462{
463 struct usb_device *dev = gspca_dev->dev;
464
465 pac7311_reg_write(dev, 0xff, 0x04);
466 pac7311_reg_write(dev, 0x27, 0x80);
467 pac7311_reg_write(dev, 0x28, 0xca);
468 pac7311_reg_write(dev, 0x29, 0x53);
469 pac7311_reg_write(dev, 0x2a, 0x0e);
470 pac7311_reg_write(dev, 0xff, 0x01);
471 pac7311_reg_write(dev, 0x3e, 0x20);
472 pac7311_reg_write(dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */
473 pac7311_reg_write(dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
474 pac7311_reg_write(dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
475}
476
477static void setautogain(struct gspca_dev *gspca_dev, int luma)
478{
479 int luma_mean = 128;
480 int luma_delta = 20;
481 __u8 spring = 5;
482 __u8 Pxclk;
483 int Gbright;
484
485 pac7311_reg_read(gspca_dev->dev, 0x02, &Pxclk);
486 Gbright = Pxclk;
487 PDEBUG(D_FRAM, "luma mean %d", luma);
488 if (luma < luma_mean - luma_delta ||
489 luma > luma_mean + luma_delta) {
490 Gbright += (luma_mean - luma) >> spring;
491 if (Gbright > 0x1a)
492 Gbright = 0x1a;
493 else if (Gbright < 4)
494 Gbright = 4;
495 PDEBUG(D_FRAM, "gbright %d", Gbright);
496 pac7311_reg_write(gspca_dev->dev, 0xff, 0x04);
497 pac7311_reg_write(gspca_dev->dev, 0x0f, Gbright);
498 /* load registers to sensor (Bit 0, auto clear) */
499 pac7311_reg_write(gspca_dev->dev, 0x11, 0x01);
500 }
501}
502
503static void sd_pkt_scan(struct gspca_dev *gspca_dev,
504 struct gspca_frame *frame, /* target */
505 unsigned char *data, /* isoc packet */
506 int len) /* iso packet length */
507{
508 struct sd *sd = (struct sd *) gspca_dev;
509 unsigned char tmpbuf[4];
510 int i, p, ffseq;
511
512/* if (len < 5) { */
513 if (len < 6) {
514/* gspca_dev->last_packet_type = DISCARD_PACKET; */
515 return;
516 }
517
518 ffseq = sd->ffseq;
519
520 for (p = 0; p < len - 6; p++) {
521 if ((data[0 + p] == 0xff)
522 && (data[1 + p] == 0xff)
523 && (data[2 + p] == 0x00)
524 && (data[3 + p] == 0xff)
525 && (data[4 + p] == 0x96)) {
526
527 /* start of frame */
528 if (sd->ag_cnt >= 0 && p > 28) {
529 sd->avg_lum += data[p - 23];
530 if (--sd->ag_cnt < 0) {
531 sd->ag_cnt = AG_CNT_START;
532 setautogain(gspca_dev,
533 sd->avg_lum / AG_CNT_START);
534 sd->avg_lum = 0;
535 }
536 }
537
538 /* copy the end of data to the current frame */
539 frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
540 data, p);
541
542 /* put the JPEG header in the new frame */
543 gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
544 (unsigned char *) pac7311_jpeg_header,
545 12);
546 tmpbuf[0] = gspca_dev->height >> 8;
547 tmpbuf[1] = gspca_dev->height & 0xff;
548 tmpbuf[2] = gspca_dev->width >> 8;
549 tmpbuf[3] = gspca_dev->width & 0xff;
550 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
551 tmpbuf, 4);
552 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
553 (unsigned char *) &pac7311_jpeg_header[16],
554 PAC7311_JPEG_HEADER_SIZE - 16);
555
556 data += p + 7;
557 len -= p + 7;
558 ffseq = 0;
559 break;
560 }
561 }
562
563 /* remove the 'ff ff ff xx' sequences */
564 switch (ffseq) {
565 case 3:
566 data += 1;
567 len -= 1;
568 break;
569 case 2:
570 if (data[0] == 0xff) {
571 data += 2;
572 len -= 2;
573 frame->data_end -= 2;
574 }
575 break;
576 case 1:
577 if (data[0] == 0xff
578 && data[1] == 0xff) {
579 data += 3;
580 len -= 3;
581 frame->data_end -= 1;
582 }
583 break;
584 }
585 for (i = 0; i < len - 4; i++) {
586 if (data[i] == 0xff
587 && data[i + 1] == 0xff
588 && data[i + 2] == 0xff) {
589 memmove(&data[i], &data[i + 4], len - i - 4);
590 len -= 4;
591 }
592 }
593 ffseq = 0;
594 if (data[len - 4] == 0xff) {
595 if (data[len - 3] == 0xff
596 && data[len - 2] == 0xff) {
597 len -= 4;
598 }
599 } else if (data[len - 3] == 0xff) {
600 if (data[len - 2] == 0xff
601 && data[len - 1] == 0xff)
602 ffseq = 3;
603 } else if (data[len - 2] == 0xff) {
604 if (data[len - 1] == 0xff)
605 ffseq = 2;
606 } else if (data[len - 1] == 0xff)
607 ffseq = 1;
608 sd->ffseq = ffseq;
609 gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
610}
611
612static void getbrightness(struct gspca_dev *gspca_dev)
613{
614/* __u8 brightness = 0;
615
616 pac7311_reg_read(gspca_dev->dev, 0x0008, &brightness);
617 spca50x->brightness = brightness;
618 return spca50x->brightness; */
619/* PDEBUG(D_CONF, "Called pac7311_getbrightness: Not implemented yet"); */
620}
621
622
623
624static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
625{
626 struct sd *sd = (struct sd *) gspca_dev;
627
628 sd->brightness = val;
629 if (gspca_dev->streaming)
630 setbrightness(gspca_dev);
631 return 0;
632}
633
634static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
635{
636 struct sd *sd = (struct sd *) gspca_dev;
637
638 getbrightness(gspca_dev);
639 *val = sd->brightness;
640 return 0;
641}
642
643static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
644{
645 struct sd *sd = (struct sd *) gspca_dev;
646
647 sd->contrast = val;
648 if (gspca_dev->streaming)
649 setcontrast(gspca_dev);
650 return 0;
651}
652
653static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
654{
655 struct sd *sd = (struct sd *) gspca_dev;
656
657/* getcontrast(gspca_dev); */
658 *val = sd->contrast;
659 return 0;
660}
661
662static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
663{
664 struct sd *sd = (struct sd *) gspca_dev;
665
666 sd->colors = val;
667 if (gspca_dev->streaming)
668 setcolors(gspca_dev);
669 return 0;
670}
671
672static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
673{
674 struct sd *sd = (struct sd *) gspca_dev;
675
676/* getcolors(gspca_dev); */
677 *val = sd->colors;
678 return 0;
679}
680
681static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
682{
683 struct sd *sd = (struct sd *) gspca_dev;
684
685 sd->autogain = val;
686 if (val) {
687 sd->ag_cnt = AG_CNT_START;
688 sd->avg_lum = 0;
689 } else {
690 sd->ag_cnt = -1;
691 }
692 return 0;
693}
694
695static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
696{
697 struct sd *sd = (struct sd *) gspca_dev;
698
699 *val = sd->autogain;
700 return 0;
701}
702
703/* sub-driver description */
704static struct sd_desc sd_desc = {
705 .name = MODULE_NAME,
706 .ctrls = sd_ctrls,
707 .nctrls = ARRAY_SIZE(sd_ctrls),
708 .config = sd_config,
709 .open = sd_open,
710 .start = sd_start,
711 .stopN = sd_stopN,
712 .stop0 = sd_stop0,
713 .close = sd_close,
714 .pkt_scan = sd_pkt_scan,
715};
716
717/* -- module initialisation -- */
718#define DVNM(name) .driver_info = (kernel_ulong_t) name
719static __devinitdata struct usb_device_id device_table[] = {
720 {USB_DEVICE(0x093a, 0x2600), DVNM("Typhoon")},
721 {USB_DEVICE(0x093a, 0x2601), DVNM("Philips SPC610NC")},
722 {USB_DEVICE(0x093a, 0x2603), DVNM("PAC7312")},
723 {USB_DEVICE(0x093a, 0x2608), DVNM("Trust WB-3300p")},
Jean-Francois Moine956e42d2008-07-01 10:03:42 -0300724 {USB_DEVICE(0x093a, 0x260e), DVNM("Gigaware VGA PC Camera")},
725 /* and also ', Trust WB-3350p, SIGMA cam 2350' */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300726 {USB_DEVICE(0x093a, 0x260f), DVNM("SnakeCam")},
727 {USB_DEVICE(0x093a, 0x2621), DVNM("PAC731x")},
728 {}
729};
730MODULE_DEVICE_TABLE(usb, device_table);
731
732/* -- device connect -- */
733static int sd_probe(struct usb_interface *intf,
734 const struct usb_device_id *id)
735{
736 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
737 THIS_MODULE);
738}
739
740static struct usb_driver sd_driver = {
741 .name = MODULE_NAME,
742 .id_table = device_table,
743 .probe = sd_probe,
744 .disconnect = gspca_disconnect,
745};
746
747/* -- module insert / remove -- */
748static int __init sd_mod_init(void)
749{
750 if (usb_register(&sd_driver) < 0)
751 return -1;
752 PDEBUG(D_PROBE, "v%s registered", version);
753 return 0;
754}
755static void __exit sd_mod_exit(void)
756{
757 usb_deregister(&sd_driver);
758 PDEBUG(D_PROBE, "deregistered");
759}
760
761module_init(sd_mod_init);
762module_exit(sd_mod_exit);