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