blob: 1a2347aa7157215a8fb444d085b71b8ac87658c0 [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 Moinec2446b32008-07-05 11:49:20 -030026#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 5)
27static const char version[] = "2.1.5";
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;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030040 unsigned char contrast;
41 unsigned char colors;
42 unsigned char autogain;
43
44 char ffseq;
45 signed char ag_cnt;
46#define AG_CNT_START 13
47};
48
49/* V4L2 controls supported by the driver */
50static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
51static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
52static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
53static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
54static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
55static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
56static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
57static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
58
59static struct ctrl sd_ctrls[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030060 {
61 {
62 .id = V4L2_CID_BRIGHTNESS,
63 .type = V4L2_CTRL_TYPE_INTEGER,
64 .name = "Brightness",
65 .minimum = 0,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -030066#define BRIGHTNESS_MAX 0x20
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030067 .maximum = BRIGHTNESS_MAX,
68 .step = 1,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -030069#define BRIGHTNESS_DEF 0x10
70 .default_value = BRIGHTNESS_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030071 },
72 .set = sd_setbrightness,
73 .get = sd_getbrightness,
74 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030075 {
76 {
77 .id = V4L2_CID_CONTRAST,
78 .type = V4L2_CTRL_TYPE_INTEGER,
79 .name = "Contrast",
80 .minimum = 0,
81 .maximum = 255,
82 .step = 1,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -030083#define CONTRAST_DEF 127
84 .default_value = CONTRAST_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030085 },
86 .set = sd_setcontrast,
87 .get = sd_getcontrast,
88 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030089 {
90 {
91 .id = V4L2_CID_SATURATION,
92 .type = V4L2_CTRL_TYPE_INTEGER,
93 .name = "Color",
94 .minimum = 0,
95 .maximum = 255,
96 .step = 1,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -030097#define COLOR_DEF 127
98 .default_value = COLOR_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030099 },
100 .set = sd_setcolors,
101 .get = sd_getcolors,
102 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300103 {
104 {
105 .id = V4L2_CID_AUTOGAIN,
106 .type = V4L2_CTRL_TYPE_BOOLEAN,
107 .name = "Auto Gain",
108 .minimum = 0,
109 .maximum = 1,
110 .step = 1,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300111#define AUTOGAIN_DEF 1
112 .default_value = AUTOGAIN_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300113 },
114 .set = sd_setautogain,
115 .get = sd_getautogain,
116 },
117};
118
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300119static struct v4l2_pix_format vga_mode[] = {
120 {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
121 .bytesperline = 160,
122 .sizeimage = 160 * 120 * 3 / 8 + 590,
123 .colorspace = V4L2_COLORSPACE_JPEG,
124 .priv = 2},
125 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
126 .bytesperline = 320,
127 .sizeimage = 320 * 240 * 3 / 8 + 590,
128 .colorspace = V4L2_COLORSPACE_JPEG,
129 .priv = 1},
130 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
131 .bytesperline = 640,
132 .sizeimage = 640 * 480 * 3 / 8 + 590,
133 .colorspace = V4L2_COLORSPACE_JPEG,
134 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300135};
136
137#define PAC7311_JPEG_HEADER_SIZE (sizeof pac7311_jpeg_header) /* (594) */
138
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300139static const __u8 pac7311_jpeg_header[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300140 0xff, 0xd8,
141 0xff, 0xe0, 0x00, 0x03, 0x20,
142 0xff, 0xc0, 0x00, 0x11, 0x08,
143 0x01, 0xe0, /* 12: height */
144 0x02, 0x80, /* 14: width */
145 0x03, /* 16 */
146 0x01, 0x21, 0x00,
147 0x02, 0x11, 0x01,
148 0x03, 0x11, 0x01,
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
207};
208
209static void reg_w(struct usb_device *dev,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300210 __u16 index,
211 const char *buffer, __u16 len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300212{
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300213 __u8 tmpbuf[8];
214
215 memcpy(tmpbuf, buffer, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300216 usb_control_msg(dev,
217 usb_sndctrlpipe(dev, 0),
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300218 1, /* request */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300219 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300220 0, /* value */
221 index, tmpbuf, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300222 500);
223}
224
225static void pac7311_reg_read(struct usb_device *dev, __u16 index,
226 __u8 *buffer)
227{
228 usb_control_msg(dev,
229 usb_rcvctrlpipe(dev, 0),
230 0, /* request */
231 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
232 0, /* value */
233 index, buffer, 1,
234 500);
235}
236
237static void pac7311_reg_write(struct usb_device *dev,
238 __u16 index,
239 __u8 value)
240{
241 __u8 buf;
242
243 buf = value;
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300244 usb_control_msg(dev,
245 usb_sndctrlpipe(dev, 0),
246 0, /* request */
247 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
248 value, index, &buf, 1,
249 500);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300250}
251
252/* this function is called at probe time */
253static int sd_config(struct gspca_dev *gspca_dev,
254 const struct usb_device_id *id)
255{
256 struct sd *sd = (struct sd *) gspca_dev;
257 struct usb_device *dev = gspca_dev->dev;
258 struct cam *cam;
259
260 PDEBUG(D_CONF, "Find Sensor PAC7311");
261 pac7311_reg_write(dev, 0x78, 0x40); /* Bit_0=start stream, Bit_7=LED */
262 pac7311_reg_write(dev, 0x78, 0x40); /* Bit_0=start stream, Bit_7=LED */
263 pac7311_reg_write(dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
264 pac7311_reg_write(dev, 0xff, 0x04);
265 pac7311_reg_write(dev, 0x27, 0x80);
266 pac7311_reg_write(dev, 0x28, 0xca);
267 pac7311_reg_write(dev, 0x29, 0x53);
268 pac7311_reg_write(dev, 0x2a, 0x0e);
269 pac7311_reg_write(dev, 0xff, 0x01);
270 pac7311_reg_write(dev, 0x3e, 0x20);
271
272 cam = &gspca_dev->cam;
273 cam->dev_name = (char *) id->driver_info;
274 cam->epaddr = 0x05;
275 cam->cam_mode = vga_mode;
276 cam->nmodes = ARRAY_SIZE(vga_mode);
277
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300278 sd->brightness = BRIGHTNESS_DEF;
279 sd->contrast = CONTRAST_DEF;
280 sd->colors = COLOR_DEF;
281 sd->autogain = AUTOGAIN_DEF;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300282 return 0;
283}
284
285static void setbrightness(struct gspca_dev *gspca_dev)
286{
287 struct sd *sd = (struct sd *) gspca_dev;
288 int brightness;
289
290/*jfm: inverted?*/
291 brightness = BRIGHTNESS_MAX - sd->brightness;
292 pac7311_reg_write(gspca_dev->dev, 0xff, 0x04);
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300293/* pac7311_reg_write(gspca_dev->dev, 0x0e, 0x00); */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300294 pac7311_reg_write(gspca_dev->dev, 0x0f, brightness);
295 /* load registers to sensor (Bit 0, auto clear) */
296 pac7311_reg_write(gspca_dev->dev, 0x11, 0x01);
297 PDEBUG(D_CONF|D_STREAM, "brightness: %i", brightness);
298}
299
300static void setcontrast(struct gspca_dev *gspca_dev)
301{
302 struct sd *sd = (struct sd *) gspca_dev;
303
304 pac7311_reg_write(gspca_dev->dev, 0xff, 0x01);
305 pac7311_reg_write(gspca_dev->dev, 0x80, sd->contrast);
306 /* load registers to sensor (Bit 0, auto clear) */
307 pac7311_reg_write(gspca_dev->dev, 0x11, 0x01);
308 PDEBUG(D_CONF|D_STREAM, "contrast: %i", sd->contrast);
309}
310
311static void setcolors(struct gspca_dev *gspca_dev)
312{
313 struct sd *sd = (struct sd *) gspca_dev;
314
315 pac7311_reg_write(gspca_dev->dev, 0xff, 0x01);
316 pac7311_reg_write(gspca_dev->dev, 0x10, sd->colors);
317 /* load registers to sensor (Bit 0, auto clear) */
318 pac7311_reg_write(gspca_dev->dev, 0x11, 0x01);
319 PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
320}
321
322/* this function is called at open time */
323static int sd_open(struct gspca_dev *gspca_dev)
324{
325 pac7311_reg_write(gspca_dev->dev, 0x78, 0x00); /* Turn on LED */
326 return 0;
327}
328
329static void sd_start(struct gspca_dev *gspca_dev)
330{
331 struct usb_device *dev = gspca_dev->dev;
332 struct sd *sd = (struct sd *) gspca_dev;
333
334 pac7311_reg_write(dev, 0xff, 0x01);
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300335 reg_w(dev, 0x0002, "\x48\x0a\x40\x08\x00\x00\x08\x00", 8);
336 reg_w(dev, 0x000a, "\x06\xff\x11\xff\x5a\x30\x90\x4c", 8);
337 reg_w(dev, 0x0012, "\x00\x07\x00\x0a\x10\x00\xa0\x10", 8);
338 reg_w(dev, 0x001a, "\x02\x00\x00\x00\x00\x0b\x01\x00", 8);
339 reg_w(dev, 0x0022, "\x00\x00\x00\x00\x00\x00\x00\x00", 8);
340 reg_w(dev, 0x002a, "\x00\x00\x00", 3);
341 reg_w(dev, 0x003e, "\x00\x00\x78\x52\x4a\x52\x78\x6e", 8);
342 reg_w(dev, 0x0046, "\x48\x46\x48\x6e\x5f\x49\x42\x49", 8);
343 reg_w(dev, 0x004e, "\x5f\x5f\x49\x42\x49\x5f\x6e\x48", 8);
344 reg_w(dev, 0x0056, "\x46\x48\x6e\x78\x52\x4a\x52\x78", 8);
345 reg_w(dev, 0x005e, "\x00\x00\x09\x1b\x34\x49\x5c\x9b", 8);
346 reg_w(dev, 0x0066, "\xd0\xff", 2);
347 reg_w(dev, 0x0078, "\x44\x00\xf2\x01\x01\x80", 6);
348 reg_w(dev, 0x007f, "\x2a\x1c\x00\xc8\x02\x58\x03\x84", 8);
349 reg_w(dev, 0x0087, "\x12\x00\x1a\x04\x08\x0c\x10\x14", 8);
350 reg_w(dev, 0x008f, "\x18\x20", 2);
351 reg_w(dev, 0x0096, "\x01\x08\x04", 3);
352 reg_w(dev, 0x00a0, "\x44\x44\x44\x04", 4);
353 reg_w(dev, 0x00f0, "\x01\x00\x00\x00\x22\x00\x20\x00", 8);
354 reg_w(dev, 0x00f8, "\x3f\x00\x0a\x01\x00", 5);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300355
356 pac7311_reg_write(dev, 0xff, 0x04);
357 pac7311_reg_write(dev, 0x02, 0x04);
358 pac7311_reg_write(dev, 0x03, 0x54);
359 pac7311_reg_write(dev, 0x04, 0x07);
360 pac7311_reg_write(dev, 0x05, 0x2b);
361 pac7311_reg_write(dev, 0x06, 0x09);
362 pac7311_reg_write(dev, 0x07, 0x0f);
363 pac7311_reg_write(dev, 0x08, 0x09);
364 pac7311_reg_write(dev, 0x09, 0x00);
365 pac7311_reg_write(dev, 0x0c, 0x07);
366 pac7311_reg_write(dev, 0x0d, 0x00);
367 pac7311_reg_write(dev, 0x0e, 0x00);
368 pac7311_reg_write(dev, 0x0f, 0x62);
369 pac7311_reg_write(dev, 0x10, 0x08);
370 pac7311_reg_write(dev, 0x12, 0x07);
371 pac7311_reg_write(dev, 0x13, 0x00);
372 pac7311_reg_write(dev, 0x14, 0x00);
373 pac7311_reg_write(dev, 0x15, 0x00);
374 pac7311_reg_write(dev, 0x16, 0x00);
375 pac7311_reg_write(dev, 0x17, 0x00);
376 pac7311_reg_write(dev, 0x18, 0x00);
377 pac7311_reg_write(dev, 0x19, 0x00);
378 pac7311_reg_write(dev, 0x1a, 0x00);
379 pac7311_reg_write(dev, 0x1b, 0x03);
380 pac7311_reg_write(dev, 0x1c, 0xa0);
381 pac7311_reg_write(dev, 0x1d, 0x01);
382 pac7311_reg_write(dev, 0x1e, 0xf4);
383 pac7311_reg_write(dev, 0x21, 0x00);
384 pac7311_reg_write(dev, 0x22, 0x08);
385 pac7311_reg_write(dev, 0x24, 0x03);
386 pac7311_reg_write(dev, 0x26, 0x00);
387 pac7311_reg_write(dev, 0x27, 0x01);
388 pac7311_reg_write(dev, 0x28, 0xca);
389 pac7311_reg_write(dev, 0x29, 0x10);
390 pac7311_reg_write(dev, 0x2a, 0x06);
391 pac7311_reg_write(dev, 0x2b, 0x78);
392 pac7311_reg_write(dev, 0x2c, 0x00);
393 pac7311_reg_write(dev, 0x2d, 0x00);
394 pac7311_reg_write(dev, 0x2e, 0x00);
395 pac7311_reg_write(dev, 0x2f, 0x00);
396 pac7311_reg_write(dev, 0x30, 0x23);
397 pac7311_reg_write(dev, 0x31, 0x28);
398 pac7311_reg_write(dev, 0x32, 0x04);
399 pac7311_reg_write(dev, 0x33, 0x11);
400 pac7311_reg_write(dev, 0x34, 0x00);
401 pac7311_reg_write(dev, 0x35, 0x00);
402 pac7311_reg_write(dev, 0x11, 0x01);
403 setcontrast(gspca_dev);
404 setbrightness(gspca_dev);
405 setcolors(gspca_dev);
406
407 /* set correct resolution */
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300408 switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300409 case 2: /* 160x120 */
410 pac7311_reg_write(dev, 0xff, 0x04);
411 pac7311_reg_write(dev, 0x02, 0x03);
412 pac7311_reg_write(dev, 0xff, 0x01);
413 pac7311_reg_write(dev, 0x08, 0x09);
414 pac7311_reg_write(dev, 0x17, 0x20);
415 pac7311_reg_write(dev, 0x1b, 0x00);
416/* pac7311_reg_write(dev, 0x80, 0x69); */
417 pac7311_reg_write(dev, 0x87, 0x10);
418 break;
419 case 1: /* 320x240 */
420 pac7311_reg_write(dev, 0xff, 0x04);
421 pac7311_reg_write(dev, 0x02, 0x03);
422 pac7311_reg_write(dev, 0xff, 0x01);
423 pac7311_reg_write(dev, 0x08, 0x09);
424 pac7311_reg_write(dev, 0x17, 0x30);
425/* pac7311_reg_write(dev, 0x80, 0x3f); */
426 pac7311_reg_write(dev, 0x87, 0x11);
427 break;
428 case 0: /* 640x480 */
429 pac7311_reg_write(dev, 0xff, 0x04);
430 pac7311_reg_write(dev, 0x02, 0x03);
431 pac7311_reg_write(dev, 0xff, 0x01);
432 pac7311_reg_write(dev, 0x08, 0x08);
433 pac7311_reg_write(dev, 0x17, 0x00);
434/* pac7311_reg_write(dev, 0x80, 0x1c); */
435 pac7311_reg_write(dev, 0x87, 0x12);
436 break;
437 }
438
439 /* start stream */
440 pac7311_reg_write(dev, 0xff, 0x01);
441 pac7311_reg_write(dev, 0x78, 0x04);
442 pac7311_reg_write(dev, 0x78, 0x05);
443
444 if (sd->autogain) {
445 sd->ag_cnt = AG_CNT_START;
446 sd->avg_lum = 0;
447 } else {
448 sd->ag_cnt = -1;
449 }
450}
451
452static void sd_stopN(struct gspca_dev *gspca_dev)
453{
454 struct usb_device *dev = gspca_dev->dev;
455
456 pac7311_reg_write(dev, 0xff, 0x04);
457 pac7311_reg_write(dev, 0x27, 0x80);
458 pac7311_reg_write(dev, 0x28, 0xca);
459 pac7311_reg_write(dev, 0x29, 0x53);
460 pac7311_reg_write(dev, 0x2a, 0x0e);
461 pac7311_reg_write(dev, 0xff, 0x01);
462 pac7311_reg_write(dev, 0x3e, 0x20);
463 pac7311_reg_write(dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */
464 pac7311_reg_write(dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
465 pac7311_reg_write(dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
466}
467
468static void sd_stop0(struct gspca_dev *gspca_dev)
469{
470}
471
472/* this function is called at close time */
473static void sd_close(struct gspca_dev *gspca_dev)
474{
475 struct usb_device *dev = gspca_dev->dev;
476
477 pac7311_reg_write(dev, 0xff, 0x04);
478 pac7311_reg_write(dev, 0x27, 0x80);
479 pac7311_reg_write(dev, 0x28, 0xca);
480 pac7311_reg_write(dev, 0x29, 0x53);
481 pac7311_reg_write(dev, 0x2a, 0x0e);
482 pac7311_reg_write(dev, 0xff, 0x01);
483 pac7311_reg_write(dev, 0x3e, 0x20);
484 pac7311_reg_write(dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */
485 pac7311_reg_write(dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
486 pac7311_reg_write(dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
487}
488
489static void setautogain(struct gspca_dev *gspca_dev, int luma)
490{
491 int luma_mean = 128;
492 int luma_delta = 20;
493 __u8 spring = 5;
494 __u8 Pxclk;
495 int Gbright;
496
497 pac7311_reg_read(gspca_dev->dev, 0x02, &Pxclk);
498 Gbright = Pxclk;
499 PDEBUG(D_FRAM, "luma mean %d", luma);
500 if (luma < luma_mean - luma_delta ||
501 luma > luma_mean + luma_delta) {
502 Gbright += (luma_mean - luma) >> spring;
503 if (Gbright > 0x1a)
504 Gbright = 0x1a;
505 else if (Gbright < 4)
506 Gbright = 4;
507 PDEBUG(D_FRAM, "gbright %d", Gbright);
508 pac7311_reg_write(gspca_dev->dev, 0xff, 0x04);
509 pac7311_reg_write(gspca_dev->dev, 0x0f, Gbright);
510 /* load registers to sensor (Bit 0, auto clear) */
511 pac7311_reg_write(gspca_dev->dev, 0x11, 0x01);
512 }
513}
514
515static void sd_pkt_scan(struct gspca_dev *gspca_dev,
516 struct gspca_frame *frame, /* target */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300517 __u8 *data, /* isoc packet */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300518 int len) /* iso packet length */
519{
520 struct sd *sd = (struct sd *) gspca_dev;
521 unsigned char tmpbuf[4];
522 int i, p, ffseq;
523
524/* if (len < 5) { */
525 if (len < 6) {
526/* gspca_dev->last_packet_type = DISCARD_PACKET; */
527 return;
528 }
529
530 ffseq = sd->ffseq;
531
532 for (p = 0; p < len - 6; p++) {
533 if ((data[0 + p] == 0xff)
534 && (data[1 + p] == 0xff)
535 && (data[2 + p] == 0x00)
536 && (data[3 + p] == 0xff)
537 && (data[4 + p] == 0x96)) {
538
539 /* start of frame */
540 if (sd->ag_cnt >= 0 && p > 28) {
541 sd->avg_lum += data[p - 23];
542 if (--sd->ag_cnt < 0) {
543 sd->ag_cnt = AG_CNT_START;
544 setautogain(gspca_dev,
545 sd->avg_lum / AG_CNT_START);
546 sd->avg_lum = 0;
547 }
548 }
549
550 /* copy the end of data to the current frame */
551 frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
552 data, p);
553
554 /* put the JPEG header in the new frame */
555 gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
556 (unsigned char *) pac7311_jpeg_header,
557 12);
558 tmpbuf[0] = gspca_dev->height >> 8;
559 tmpbuf[1] = gspca_dev->height & 0xff;
560 tmpbuf[2] = gspca_dev->width >> 8;
561 tmpbuf[3] = gspca_dev->width & 0xff;
562 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
563 tmpbuf, 4);
564 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
565 (unsigned char *) &pac7311_jpeg_header[16],
566 PAC7311_JPEG_HEADER_SIZE - 16);
567
568 data += p + 7;
569 len -= p + 7;
570 ffseq = 0;
571 break;
572 }
573 }
574
575 /* remove the 'ff ff ff xx' sequences */
576 switch (ffseq) {
577 case 3:
578 data += 1;
579 len -= 1;
580 break;
581 case 2:
582 if (data[0] == 0xff) {
583 data += 2;
584 len -= 2;
585 frame->data_end -= 2;
586 }
587 break;
588 case 1:
589 if (data[0] == 0xff
590 && data[1] == 0xff) {
591 data += 3;
592 len -= 3;
593 frame->data_end -= 1;
594 }
595 break;
596 }
597 for (i = 0; i < len - 4; i++) {
598 if (data[i] == 0xff
599 && data[i + 1] == 0xff
600 && data[i + 2] == 0xff) {
601 memmove(&data[i], &data[i + 4], len - i - 4);
602 len -= 4;
603 }
604 }
605 ffseq = 0;
606 if (data[len - 4] == 0xff) {
607 if (data[len - 3] == 0xff
608 && data[len - 2] == 0xff) {
609 len -= 4;
610 }
611 } else if (data[len - 3] == 0xff) {
612 if (data[len - 2] == 0xff
613 && data[len - 1] == 0xff)
614 ffseq = 3;
615 } else if (data[len - 2] == 0xff) {
616 if (data[len - 1] == 0xff)
617 ffseq = 2;
618 } else if (data[len - 1] == 0xff)
619 ffseq = 1;
620 sd->ffseq = ffseq;
621 gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
622}
623
624static void getbrightness(struct gspca_dev *gspca_dev)
625{
626/* __u8 brightness = 0;
627
628 pac7311_reg_read(gspca_dev->dev, 0x0008, &brightness);
629 spca50x->brightness = brightness;
630 return spca50x->brightness; */
631/* PDEBUG(D_CONF, "Called pac7311_getbrightness: Not implemented yet"); */
632}
633
634
635
636static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
637{
638 struct sd *sd = (struct sd *) gspca_dev;
639
640 sd->brightness = val;
641 if (gspca_dev->streaming)
642 setbrightness(gspca_dev);
643 return 0;
644}
645
646static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
647{
648 struct sd *sd = (struct sd *) gspca_dev;
649
650 getbrightness(gspca_dev);
651 *val = sd->brightness;
652 return 0;
653}
654
655static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
656{
657 struct sd *sd = (struct sd *) gspca_dev;
658
659 sd->contrast = val;
660 if (gspca_dev->streaming)
661 setcontrast(gspca_dev);
662 return 0;
663}
664
665static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
666{
667 struct sd *sd = (struct sd *) gspca_dev;
668
669/* getcontrast(gspca_dev); */
670 *val = sd->contrast;
671 return 0;
672}
673
674static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
675{
676 struct sd *sd = (struct sd *) gspca_dev;
677
678 sd->colors = val;
679 if (gspca_dev->streaming)
680 setcolors(gspca_dev);
681 return 0;
682}
683
684static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
685{
686 struct sd *sd = (struct sd *) gspca_dev;
687
688/* getcolors(gspca_dev); */
689 *val = sd->colors;
690 return 0;
691}
692
693static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
694{
695 struct sd *sd = (struct sd *) gspca_dev;
696
697 sd->autogain = val;
698 if (val) {
699 sd->ag_cnt = AG_CNT_START;
700 sd->avg_lum = 0;
701 } else {
702 sd->ag_cnt = -1;
703 }
704 return 0;
705}
706
707static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
708{
709 struct sd *sd = (struct sd *) gspca_dev;
710
711 *val = sd->autogain;
712 return 0;
713}
714
715/* sub-driver description */
716static struct sd_desc sd_desc = {
717 .name = MODULE_NAME,
718 .ctrls = sd_ctrls,
719 .nctrls = ARRAY_SIZE(sd_ctrls),
720 .config = sd_config,
721 .open = sd_open,
722 .start = sd_start,
723 .stopN = sd_stopN,
724 .stop0 = sd_stop0,
725 .close = sd_close,
726 .pkt_scan = sd_pkt_scan,
727};
728
729/* -- module initialisation -- */
730#define DVNM(name) .driver_info = (kernel_ulong_t) name
731static __devinitdata struct usb_device_id device_table[] = {
732 {USB_DEVICE(0x093a, 0x2600), DVNM("Typhoon")},
733 {USB_DEVICE(0x093a, 0x2601), DVNM("Philips SPC610NC")},
734 {USB_DEVICE(0x093a, 0x2603), DVNM("PAC7312")},
735 {USB_DEVICE(0x093a, 0x2608), DVNM("Trust WB-3300p")},
Jean-Francois Moine956e42d2008-07-01 10:03:42 -0300736 {USB_DEVICE(0x093a, 0x260e), DVNM("Gigaware VGA PC Camera")},
737 /* and also ', Trust WB-3350p, SIGMA cam 2350' */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300738 {USB_DEVICE(0x093a, 0x260f), DVNM("SnakeCam")},
739 {USB_DEVICE(0x093a, 0x2621), DVNM("PAC731x")},
740 {}
741};
742MODULE_DEVICE_TABLE(usb, device_table);
743
744/* -- device connect -- */
745static int sd_probe(struct usb_interface *intf,
746 const struct usb_device_id *id)
747{
748 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
749 THIS_MODULE);
750}
751
752static struct usb_driver sd_driver = {
753 .name = MODULE_NAME,
754 .id_table = device_table,
755 .probe = sd_probe,
756 .disconnect = gspca_disconnect,
757};
758
759/* -- module insert / remove -- */
760static int __init sd_mod_init(void)
761{
762 if (usb_register(&sd_driver) < 0)
763 return -1;
764 PDEBUG(D_PROBE, "v%s registered", version);
765 return 0;
766}
767static void __exit sd_mod_exit(void)
768{
769 usb_deregister(&sd_driver);
770 PDEBUG(D_PROBE, "deregistered");
771}
772
773module_init(sd_mod_init);
774module_exit(sd_mod_exit);