aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/gspca/pac7311.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/gspca/pac7311.c')
-rw-r--r--drivers/media/video/gspca/pac7311.c760
1 files changed, 760 insertions, 0 deletions
diff --git a/drivers/media/video/gspca/pac7311.c b/drivers/media/video/gspca/pac7311.c
new file mode 100644
index 000000000000..5c052e31be4a
--- /dev/null
+++ b/drivers/media/video/gspca/pac7311.c
@@ -0,0 +1,760 @@
1/*
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
26#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7)
27static const char version[] = "2.1.7";
28
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 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[] = {
60 {
61 {
62 .id = V4L2_CID_BRIGHTNESS,
63 .type = V4L2_CTRL_TYPE_INTEGER,
64 .name = "Brightness",
65 .minimum = 0,
66#define BRIGHTNESS_MAX 0x20
67 .maximum = BRIGHTNESS_MAX,
68 .step = 1,
69#define BRIGHTNESS_DEF 0x10
70 .default_value = BRIGHTNESS_DEF,
71 },
72 .set = sd_setbrightness,
73 .get = sd_getbrightness,
74 },
75 {
76 {
77 .id = V4L2_CID_CONTRAST,
78 .type = V4L2_CTRL_TYPE_INTEGER,
79 .name = "Contrast",
80 .minimum = 0,
81 .maximum = 255,
82 .step = 1,
83#define CONTRAST_DEF 127
84 .default_value = CONTRAST_DEF,
85 },
86 .set = sd_setcontrast,
87 .get = sd_getcontrast,
88 },
89 {
90 {
91 .id = V4L2_CID_SATURATION,
92 .type = V4L2_CTRL_TYPE_INTEGER,
93 .name = "Color",
94 .minimum = 0,
95 .maximum = 255,
96 .step = 1,
97#define COLOR_DEF 127
98 .default_value = COLOR_DEF,
99 },
100 .set = sd_setcolors,
101 .get = sd_getcolors,
102 },
103 {
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,
111#define AUTOGAIN_DEF 1
112 .default_value = AUTOGAIN_DEF,
113 },
114 .set = sd_setautogain,
115 .get = sd_getautogain,
116 },
117};
118
119static 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},
135};
136
137#define PAC7311_JPEG_HEADER_SIZE (sizeof pac7311_jpeg_header) /* (594) */
138
139static const __u8 pac7311_jpeg_header[] = {
140 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_buf(struct gspca_dev *gspca_dev,
210 __u16 index,
211 const char *buffer, __u16 len)
212{
213 memcpy(gspca_dev->usb_buf, buffer, len);
214 usb_control_msg(gspca_dev->dev,
215 usb_sndctrlpipe(gspca_dev->dev, 0),
216 1, /* request */
217 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
218 0, /* value */
219 index, gspca_dev->usb_buf, len,
220 500);
221}
222
223static __u8 reg_r(struct gspca_dev *gspca_dev,
224 __u16 index)
225{
226 usb_control_msg(gspca_dev->dev,
227 usb_rcvctrlpipe(gspca_dev->dev, 0),
228 0, /* request */
229 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
230 0, /* value */
231 index, gspca_dev->usb_buf, 1,
232 500);
233 return gspca_dev->usb_buf[0];
234}
235
236static void reg_w(struct gspca_dev *gspca_dev,
237 __u16 index,
238 __u8 value)
239{
240 gspca_dev->usb_buf[0] = value;
241 usb_control_msg(gspca_dev->dev,
242 usb_sndctrlpipe(gspca_dev->dev, 0),
243 0, /* request */
244 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
245 value, index, gspca_dev->usb_buf, 1,
246 500);
247}
248
249/* this function is called at probe time */
250static int sd_config(struct gspca_dev *gspca_dev,
251 const struct usb_device_id *id)
252{
253 struct sd *sd = (struct sd *) gspca_dev;
254 struct cam *cam;
255
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);
267
268 cam = &gspca_dev->cam;
269 cam->dev_name = (char *) id->driver_info;
270 cam->epaddr = 0x05;
271 cam->cam_mode = vga_mode;
272 cam->nmodes = ARRAY_SIZE(vga_mode);
273
274 sd->brightness = BRIGHTNESS_DEF;
275 sd->contrast = CONTRAST_DEF;
276 sd->colors = COLOR_DEF;
277 sd->autogain = AUTOGAIN_DEF;
278 return 0;
279}
280
281static void setbrightness(struct gspca_dev *gspca_dev)
282{
283 struct sd *sd = (struct sd *) gspca_dev;
284 int brightness;
285
286/*jfm: inverted?*/
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);
294}
295
296static void setcontrast(struct gspca_dev *gspca_dev)
297{
298 struct sd *sd = (struct sd *) gspca_dev;
299
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);
305}
306
307static void setcolors(struct gspca_dev *gspca_dev)
308{
309 struct sd *sd = (struct sd *) gspca_dev;
310
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);
316}
317
318/* this function is called at open time */
319static int sd_open(struct gspca_dev *gspca_dev)
320{
321 reg_w(gspca_dev, 0x78, 0x00); /* Turn on LED */
322 return 0;
323}
324
325static void sd_start(struct gspca_dev *gspca_dev)
326{
327 struct sd *sd = (struct sd *) gspca_dev;
328
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);
350
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);
401
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);
413 break;
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);
422 break;
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);
431 break;
432 }
433
434 /* start stream */
435 reg_w(gspca_dev, 0xff, 0x01);
436 reg_w(gspca_dev, 0x78, 0x04);
437 reg_w(gspca_dev, 0x78, 0x05);
438
439 if (sd->autogain) {
440 sd->ag_cnt = AG_CNT_START;
441 sd->avg_lum = 0;
442 } else {
443 sd->ag_cnt = -1;
444 }
445}
446
447static void sd_stopN(struct gspca_dev *gspca_dev)
448{
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 */
459}
460
461static void sd_stop0(struct gspca_dev *gspca_dev)
462{
463}
464
465/* this function is called at close time */
466static void sd_close(struct gspca_dev *gspca_dev)
467{
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 */
478}
479
480static void setautogain(struct gspca_dev *gspca_dev, int luma)
481{
482 int luma_mean = 128;
483 int luma_delta = 20;
484 __u8 spring = 5;
485 int Gbright;
486
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;
492 if (Gbright > 0x1a)
493 Gbright = 0x1a;
494 else if (Gbright < 4)
495 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);
501 }
502}
503
504static 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 */
508{
509 struct sd *sd = (struct sd *) gspca_dev;
510 unsigned char tmpbuf[4];
511 int i, p, ffseq;
512
513/* if (len < 5) { */
514 if (len < 6) {
515/* gspca_dev->last_packet_type = DISCARD_PACKET; */
516 return;
517 }
518
519 ffseq = sd->ffseq;
520
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)) {
527
528 /* start of frame */
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);
535 sd->avg_lum = 0;
536 }
537 }
538
539 /* copy the end of data to the current frame */
540 frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
541 data, p);
542
543 /* put the JPEG header in the new frame */
544 gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
545 (unsigned char *) pac7311_jpeg_header,
546 12);
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,
552 tmpbuf, 4);
553 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
554 (unsigned char *) &pac7311_jpeg_header[16],
555 PAC7311_JPEG_HEADER_SIZE - 16);
556
557 data += p + 7;
558 len -= p + 7;
559 ffseq = 0;
560 break;
561 }
562 }
563
564 /* remove the 'ff ff ff xx' sequences */
565 switch (ffseq) {
566 case 3:
567 data += 1;
568 len -= 1;
569 break;
570 case 2:
571 if (data[0] == 0xff) {
572 data += 2;
573 len -= 2;
574 frame->data_end -= 2;
575 }
576 break;
577 case 1:
578 if (data[0] == 0xff
579 && data[1] == 0xff) {
580 data += 3;
581 len -= 3;
582 frame->data_end -= 1;
583 }
584 break;
585 }
586 for (i = 0; i < len - 4; i++) {
587 if (data[i] == 0xff
588 && data[i + 1] == 0xff
589 && data[i + 2] == 0xff) {
590 memmove(&data[i], &data[i + 4], len - i - 4);
591 len -= 4;
592 }
593 }
594 ffseq = 0;
595 if (data[len - 4] == 0xff) {
596 if (data[len - 3] == 0xff
597 && data[len - 2] == 0xff) {
598 len -= 4;
599 }
600 } else if (data[len - 3] == 0xff) {
601 if (data[len - 2] == 0xff
602 && data[len - 1] == 0xff)
603 ffseq = 3;
604 } else if (data[len - 2] == 0xff) {
605 if (data[len - 1] == 0xff)
606 ffseq = 2;
607 } else if (data[len - 1] == 0xff)
608 ffseq = 1;
609 sd->ffseq = ffseq;
610 gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
611}
612
613static void getbrightness(struct gspca_dev *gspca_dev)
614{
615/* sd->brightness = reg_r(gspca_dev, 0x08);
616 return sd->brightness; */
617/* PDEBUG(D_CONF, "Called pac7311_getbrightness: Not implemented yet"); */
618}
619
620
621
622static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
623{
624 struct sd *sd = (struct sd *) gspca_dev;
625
626 sd->brightness = val;
627 if (gspca_dev->streaming)
628 setbrightness(gspca_dev);
629 return 0;
630}
631
632static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
633{
634 struct sd *sd = (struct sd *) gspca_dev;
635
636 getbrightness(gspca_dev);
637 *val = sd->brightness;
638 return 0;
639}
640
641static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
642{
643 struct sd *sd = (struct sd *) gspca_dev;
644
645 sd->contrast = val;
646 if (gspca_dev->streaming)
647 setcontrast(gspca_dev);
648 return 0;
649}
650
651static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
652{
653 struct sd *sd = (struct sd *) gspca_dev;
654
655/* getcontrast(gspca_dev); */
656 *val = sd->contrast;
657 return 0;
658}
659
660static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
661{
662 struct sd *sd = (struct sd *) gspca_dev;
663
664 sd->colors = val;
665 if (gspca_dev->streaming)
666 setcolors(gspca_dev);
667 return 0;
668}
669
670static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
671{
672 struct sd *sd = (struct sd *) gspca_dev;
673
674/* getcolors(gspca_dev); */
675 *val = sd->colors;
676 return 0;
677}
678
679static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
680{
681 struct sd *sd = (struct sd *) gspca_dev;
682
683 sd->autogain = val;
684 if (val) {
685 sd->ag_cnt = AG_CNT_START;
686 sd->avg_lum = 0;
687 } else {
688 sd->ag_cnt = -1;
689 }
690 return 0;
691}
692
693static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
694{
695 struct sd *sd = (struct sd *) gspca_dev;
696
697 *val = sd->autogain;
698 return 0;
699}
700
701/* sub-driver description */
702static struct sd_desc sd_desc = {
703 .name = MODULE_NAME,
704 .ctrls = sd_ctrls,
705 .nctrls = ARRAY_SIZE(sd_ctrls),
706 .config = sd_config,
707 .open = sd_open,
708 .start = sd_start,
709 .stopN = sd_stopN,
710 .stop0 = sd_stop0,
711 .close = sd_close,
712 .pkt_scan = sd_pkt_scan,
713};
714
715/* -- module initialisation -- */
716#define DVNM(name) .driver_info = (kernel_ulong_t) name
717static __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")},
726 {}
727};
728MODULE_DEVICE_TABLE(usb, device_table);
729
730/* -- device connect -- */
731static int sd_probe(struct usb_interface *intf,
732 const struct usb_device_id *id)
733{
734 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
735 THIS_MODULE);
736}
737
738static struct usb_driver sd_driver = {
739 .name = MODULE_NAME,
740 .id_table = device_table,
741 .probe = sd_probe,
742 .disconnect = gspca_disconnect,
743};
744
745/* -- module insert / remove -- */
746static int __init sd_mod_init(void)
747{
748 if (usb_register(&sd_driver) < 0)
749 return -1;
750 PDEBUG(D_PROBE, "v%s registered", version);
751 return 0;
752}
753static void __exit sd_mod_exit(void)
754{
755 usb_deregister(&sd_driver);
756 PDEBUG(D_PROBE, "deregistered");
757}
758
759module_init(sd_mod_init);
760module_exit(sd_mod_exit);