diff options
Diffstat (limited to 'drivers/media/video/gspca/pac7311.c')
-rw-r--r-- | drivers/media/video/gspca/pac7311.c | 760 |
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) | ||
27 | static const char version[] = "2.1.7"; | ||
28 | |||
29 | MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li"); | ||
30 | MODULE_DESCRIPTION("Pixart PAC7311"); | ||
31 | MODULE_LICENSE("GPL"); | ||
32 | |||
33 | /* specific webcam descriptor */ | ||
34 | struct 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 */ | ||
50 | static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); | ||
51 | static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); | ||
52 | static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); | ||
53 | static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); | ||
54 | static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); | ||
55 | static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); | ||
56 | static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); | ||
57 | static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); | ||
58 | |||
59 | static 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 | |||
119 | static 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 | |||
139 | static 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 | |||
209 | static 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 | |||
223 | static __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 | |||
236 | static 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 */ | ||
250 | static 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 | |||
281 | static 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 | |||
296 | static 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 | |||
307 | static 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 */ | ||
319 | static int sd_open(struct gspca_dev *gspca_dev) | ||
320 | { | ||
321 | reg_w(gspca_dev, 0x78, 0x00); /* Turn on LED */ | ||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | static 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 | |||
447 | static 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 | |||
461 | static void sd_stop0(struct gspca_dev *gspca_dev) | ||
462 | { | ||
463 | } | ||
464 | |||
465 | /* this function is called at close time */ | ||
466 | static 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 | |||
480 | static 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 | |||
504 | static void sd_pkt_scan(struct gspca_dev *gspca_dev, | ||
505 | struct gspca_frame *frame, /* target */ | ||
506 | __u8 *data, /* isoc packet */ | ||
507 | int len) /* iso packet length */ | ||
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 | |||
613 | static 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 | |||
622 | static 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 | |||
632 | static 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 | |||
641 | static 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 | |||
651 | static 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 | |||
660 | static 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 | |||
670 | static 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 | |||
679 | static 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 | |||
693 | static 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 */ | ||
702 | static 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 | ||
717 | static __devinitdata struct usb_device_id device_table[] = { | ||
718 | {USB_DEVICE(0x093a, 0x2600), DVNM("Typhoon")}, | ||
719 | {USB_DEVICE(0x093a, 0x2601), DVNM("Philips SPC610NC")}, | ||
720 | {USB_DEVICE(0x093a, 0x2603), DVNM("PAC7312")}, | ||
721 | {USB_DEVICE(0x093a, 0x2608), DVNM("Trust WB-3300p")}, | ||
722 | {USB_DEVICE(0x093a, 0x260e), DVNM("Gigaware VGA PC Camera")}, | ||
723 | /* and also ', Trust WB-3350p, SIGMA cam 2350' */ | ||
724 | {USB_DEVICE(0x093a, 0x260f), DVNM("SnakeCam")}, | ||
725 | {USB_DEVICE(0x093a, 0x2621), DVNM("PAC731x")}, | ||
726 | {} | ||
727 | }; | ||
728 | MODULE_DEVICE_TABLE(usb, device_table); | ||
729 | |||
730 | /* -- device connect -- */ | ||
731 | static 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 | |||
738 | static 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 -- */ | ||
746 | static 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 | } | ||
753 | static void __exit sd_mod_exit(void) | ||
754 | { | ||
755 | usb_deregister(&sd_driver); | ||
756 | PDEBUG(D_PROBE, "deregistered"); | ||
757 | } | ||
758 | |||
759 | module_init(sd_mod_init); | ||
760 | module_exit(sd_mod_exit); | ||