blob: ea3d7021f40181287177df3b48d2f84f20b61dca [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;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300266 cam->epaddr = 0x05;
267 cam->cam_mode = vga_mode;
268 cam->nmodes = ARRAY_SIZE(vga_mode);
269
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300270 sd->brightness = BRIGHTNESS_DEF;
271 sd->contrast = CONTRAST_DEF;
272 sd->colors = COLOR_DEF;
273 sd->autogain = AUTOGAIN_DEF;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300274 return 0;
275}
276
277static void setbrightness(struct gspca_dev *gspca_dev)
278{
279 struct sd *sd = (struct sd *) gspca_dev;
280 int brightness;
281
282/*jfm: inverted?*/
283 brightness = BRIGHTNESS_MAX - sd->brightness;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300284 reg_w(gspca_dev, 0xff, 0x04);
285/* reg_w(gspca_dev, 0x0e, 0x00); */
286 reg_w(gspca_dev, 0x0f, brightness);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300287 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300288 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300289 PDEBUG(D_CONF|D_STREAM, "brightness: %i", brightness);
290}
291
292static void setcontrast(struct gspca_dev *gspca_dev)
293{
294 struct sd *sd = (struct sd *) gspca_dev;
295
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300296 reg_w(gspca_dev, 0xff, 0x01);
297 reg_w(gspca_dev, 0x80, sd->contrast);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300298 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300299 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300300 PDEBUG(D_CONF|D_STREAM, "contrast: %i", sd->contrast);
301}
302
303static void setcolors(struct gspca_dev *gspca_dev)
304{
305 struct sd *sd = (struct sd *) gspca_dev;
306
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300307 reg_w(gspca_dev, 0xff, 0x01);
308 reg_w(gspca_dev, 0x10, sd->colors);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300309 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300310 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300311 PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
312}
313
314/* this function is called at open time */
315static int sd_open(struct gspca_dev *gspca_dev)
316{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300317 reg_w(gspca_dev, 0x78, 0x00); /* Turn on LED */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300318 return 0;
319}
320
321static void sd_start(struct gspca_dev *gspca_dev)
322{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300323 struct sd *sd = (struct sd *) gspca_dev;
324
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300325 reg_w(gspca_dev, 0xff, 0x01);
326 reg_w_buf(gspca_dev, 0x0002, "\x48\x0a\x40\x08\x00\x00\x08\x00", 8);
327 reg_w_buf(gspca_dev, 0x000a, "\x06\xff\x11\xff\x5a\x30\x90\x4c", 8);
328 reg_w_buf(gspca_dev, 0x0012, "\x00\x07\x00\x0a\x10\x00\xa0\x10", 8);
329 reg_w_buf(gspca_dev, 0x001a, "\x02\x00\x00\x00\x00\x0b\x01\x00", 8);
330 reg_w_buf(gspca_dev, 0x0022, "\x00\x00\x00\x00\x00\x00\x00\x00", 8);
331 reg_w_buf(gspca_dev, 0x002a, "\x00\x00\x00", 3);
332 reg_w_buf(gspca_dev, 0x003e, "\x00\x00\x78\x52\x4a\x52\x78\x6e", 8);
333 reg_w_buf(gspca_dev, 0x0046, "\x48\x46\x48\x6e\x5f\x49\x42\x49", 8);
334 reg_w_buf(gspca_dev, 0x004e, "\x5f\x5f\x49\x42\x49\x5f\x6e\x48", 8);
335 reg_w_buf(gspca_dev, 0x0056, "\x46\x48\x6e\x78\x52\x4a\x52\x78", 8);
336 reg_w_buf(gspca_dev, 0x005e, "\x00\x00\x09\x1b\x34\x49\x5c\x9b", 8);
337 reg_w_buf(gspca_dev, 0x0066, "\xd0\xff", 2);
338 reg_w_buf(gspca_dev, 0x0078, "\x44\x00\xf2\x01\x01\x80", 6);
339 reg_w_buf(gspca_dev, 0x007f, "\x2a\x1c\x00\xc8\x02\x58\x03\x84", 8);
340 reg_w_buf(gspca_dev, 0x0087, "\x12\x00\x1a\x04\x08\x0c\x10\x14", 8);
341 reg_w_buf(gspca_dev, 0x008f, "\x18\x20", 2);
342 reg_w_buf(gspca_dev, 0x0096, "\x01\x08\x04", 3);
343 reg_w_buf(gspca_dev, 0x00a0, "\x44\x44\x44\x04", 4);
344 reg_w_buf(gspca_dev, 0x00f0, "\x01\x00\x00\x00\x22\x00\x20\x00", 8);
345 reg_w_buf(gspca_dev, 0x00f8, "\x3f\x00\x0a\x01\x00", 5);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300346
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300347 reg_w(gspca_dev, 0xff, 0x04);
348 reg_w(gspca_dev, 0x02, 0x04);
349 reg_w(gspca_dev, 0x03, 0x54);
350 reg_w(gspca_dev, 0x04, 0x07);
351 reg_w(gspca_dev, 0x05, 0x2b);
352 reg_w(gspca_dev, 0x06, 0x09);
353 reg_w(gspca_dev, 0x07, 0x0f);
354 reg_w(gspca_dev, 0x08, 0x09);
355 reg_w(gspca_dev, 0x09, 0x00);
356 reg_w(gspca_dev, 0x0c, 0x07);
357 reg_w(gspca_dev, 0x0d, 0x00);
358 reg_w(gspca_dev, 0x0e, 0x00);
359 reg_w(gspca_dev, 0x0f, 0x62);
360 reg_w(gspca_dev, 0x10, 0x08);
361 reg_w(gspca_dev, 0x12, 0x07);
362 reg_w(gspca_dev, 0x13, 0x00);
363 reg_w(gspca_dev, 0x14, 0x00);
364 reg_w(gspca_dev, 0x15, 0x00);
365 reg_w(gspca_dev, 0x16, 0x00);
366 reg_w(gspca_dev, 0x17, 0x00);
367 reg_w(gspca_dev, 0x18, 0x00);
368 reg_w(gspca_dev, 0x19, 0x00);
369 reg_w(gspca_dev, 0x1a, 0x00);
370 reg_w(gspca_dev, 0x1b, 0x03);
371 reg_w(gspca_dev, 0x1c, 0xa0);
372 reg_w(gspca_dev, 0x1d, 0x01);
373 reg_w(gspca_dev, 0x1e, 0xf4);
374 reg_w(gspca_dev, 0x21, 0x00);
375 reg_w(gspca_dev, 0x22, 0x08);
376 reg_w(gspca_dev, 0x24, 0x03);
377 reg_w(gspca_dev, 0x26, 0x00);
378 reg_w(gspca_dev, 0x27, 0x01);
379 reg_w(gspca_dev, 0x28, 0xca);
380 reg_w(gspca_dev, 0x29, 0x10);
381 reg_w(gspca_dev, 0x2a, 0x06);
382 reg_w(gspca_dev, 0x2b, 0x78);
383 reg_w(gspca_dev, 0x2c, 0x00);
384 reg_w(gspca_dev, 0x2d, 0x00);
385 reg_w(gspca_dev, 0x2e, 0x00);
386 reg_w(gspca_dev, 0x2f, 0x00);
387 reg_w(gspca_dev, 0x30, 0x23);
388 reg_w(gspca_dev, 0x31, 0x28);
389 reg_w(gspca_dev, 0x32, 0x04);
390 reg_w(gspca_dev, 0x33, 0x11);
391 reg_w(gspca_dev, 0x34, 0x00);
392 reg_w(gspca_dev, 0x35, 0x00);
393 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300394 setcontrast(gspca_dev);
395 setbrightness(gspca_dev);
396 setcolors(gspca_dev);
397
398 /* set correct resolution */
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300399 switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300400 case 2: /* 160x120 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300401 reg_w(gspca_dev, 0xff, 0x04);
402 reg_w(gspca_dev, 0x02, 0x03);
403 reg_w(gspca_dev, 0xff, 0x01);
404 reg_w(gspca_dev, 0x08, 0x09);
405 reg_w(gspca_dev, 0x17, 0x20);
406 reg_w(gspca_dev, 0x1b, 0x00);
407/* reg_w(gspca_dev, 0x80, 0x69); */
408 reg_w(gspca_dev, 0x87, 0x10);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300409 break;
410 case 1: /* 320x240 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300411 reg_w(gspca_dev, 0xff, 0x04);
412 reg_w(gspca_dev, 0x02, 0x03);
413 reg_w(gspca_dev, 0xff, 0x01);
414 reg_w(gspca_dev, 0x08, 0x09);
415 reg_w(gspca_dev, 0x17, 0x30);
416/* reg_w(gspca_dev, 0x80, 0x3f); */
417 reg_w(gspca_dev, 0x87, 0x11);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300418 break;
419 case 0: /* 640x480 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300420 reg_w(gspca_dev, 0xff, 0x04);
421 reg_w(gspca_dev, 0x02, 0x03);
422 reg_w(gspca_dev, 0xff, 0x01);
423 reg_w(gspca_dev, 0x08, 0x08);
424 reg_w(gspca_dev, 0x17, 0x00);
425/* reg_w(gspca_dev, 0x80, 0x1c); */
426 reg_w(gspca_dev, 0x87, 0x12);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300427 break;
428 }
429
430 /* start stream */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300431 reg_w(gspca_dev, 0xff, 0x01);
432 reg_w(gspca_dev, 0x78, 0x04);
433 reg_w(gspca_dev, 0x78, 0x05);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300434
435 if (sd->autogain) {
436 sd->ag_cnt = AG_CNT_START;
437 sd->avg_lum = 0;
438 } else {
439 sd->ag_cnt = -1;
440 }
441}
442
443static void sd_stopN(struct gspca_dev *gspca_dev)
444{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300445 reg_w(gspca_dev, 0xff, 0x04);
446 reg_w(gspca_dev, 0x27, 0x80);
447 reg_w(gspca_dev, 0x28, 0xca);
448 reg_w(gspca_dev, 0x29, 0x53);
449 reg_w(gspca_dev, 0x2a, 0x0e);
450 reg_w(gspca_dev, 0xff, 0x01);
451 reg_w(gspca_dev, 0x3e, 0x20);
452 reg_w(gspca_dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */
453 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
454 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300455}
456
457static void sd_stop0(struct gspca_dev *gspca_dev)
458{
459}
460
461/* this function is called at close time */
462static void sd_close(struct gspca_dev *gspca_dev)
463{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300464 reg_w(gspca_dev, 0xff, 0x04);
465 reg_w(gspca_dev, 0x27, 0x80);
466 reg_w(gspca_dev, 0x28, 0xca);
467 reg_w(gspca_dev, 0x29, 0x53);
468 reg_w(gspca_dev, 0x2a, 0x0e);
469 reg_w(gspca_dev, 0xff, 0x01);
470 reg_w(gspca_dev, 0x3e, 0x20);
471 reg_w(gspca_dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */
472 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
473 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300474}
475
476static void setautogain(struct gspca_dev *gspca_dev, int luma)
477{
478 int luma_mean = 128;
479 int luma_delta = 20;
480 __u8 spring = 5;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300481 int Gbright;
482
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300483 Gbright = reg_r(gspca_dev, 0x02);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300484 PDEBUG(D_FRAM, "luma mean %d", luma);
485 if (luma < luma_mean - luma_delta ||
486 luma > luma_mean + luma_delta) {
487 Gbright += (luma_mean - luma) >> spring;
488 if (Gbright > 0x1a)
489 Gbright = 0x1a;
490 else if (Gbright < 4)
491 Gbright = 4;
492 PDEBUG(D_FRAM, "gbright %d", Gbright);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300493 reg_w(gspca_dev, 0xff, 0x04);
494 reg_w(gspca_dev, 0x0f, Gbright);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300495 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300496 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300497 }
498}
499
500static void sd_pkt_scan(struct gspca_dev *gspca_dev,
501 struct gspca_frame *frame, /* target */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300502 __u8 *data, /* isoc packet */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300503 int len) /* iso packet length */
504{
505 struct sd *sd = (struct sd *) gspca_dev;
506 unsigned char tmpbuf[4];
507 int i, p, ffseq;
508
509/* if (len < 5) { */
510 if (len < 6) {
511/* gspca_dev->last_packet_type = DISCARD_PACKET; */
512 return;
513 }
514
515 ffseq = sd->ffseq;
516
517 for (p = 0; p < len - 6; p++) {
518 if ((data[0 + p] == 0xff)
519 && (data[1 + p] == 0xff)
520 && (data[2 + p] == 0x00)
521 && (data[3 + p] == 0xff)
522 && (data[4 + p] == 0x96)) {
523
524 /* start of frame */
525 if (sd->ag_cnt >= 0 && p > 28) {
526 sd->avg_lum += data[p - 23];
527 if (--sd->ag_cnt < 0) {
528 sd->ag_cnt = AG_CNT_START;
529 setautogain(gspca_dev,
530 sd->avg_lum / AG_CNT_START);
531 sd->avg_lum = 0;
532 }
533 }
534
535 /* copy the end of data to the current frame */
536 frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
537 data, p);
538
539 /* put the JPEG header in the new frame */
540 gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
541 (unsigned char *) pac7311_jpeg_header,
542 12);
543 tmpbuf[0] = gspca_dev->height >> 8;
544 tmpbuf[1] = gspca_dev->height & 0xff;
545 tmpbuf[2] = gspca_dev->width >> 8;
546 tmpbuf[3] = gspca_dev->width & 0xff;
547 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
548 tmpbuf, 4);
549 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
550 (unsigned char *) &pac7311_jpeg_header[16],
551 PAC7311_JPEG_HEADER_SIZE - 16);
552
553 data += p + 7;
554 len -= p + 7;
555 ffseq = 0;
556 break;
557 }
558 }
559
560 /* remove the 'ff ff ff xx' sequences */
561 switch (ffseq) {
562 case 3:
563 data += 1;
564 len -= 1;
565 break;
566 case 2:
567 if (data[0] == 0xff) {
568 data += 2;
569 len -= 2;
570 frame->data_end -= 2;
571 }
572 break;
573 case 1:
574 if (data[0] == 0xff
575 && data[1] == 0xff) {
576 data += 3;
577 len -= 3;
578 frame->data_end -= 1;
579 }
580 break;
581 }
582 for (i = 0; i < len - 4; i++) {
583 if (data[i] == 0xff
584 && data[i + 1] == 0xff
585 && data[i + 2] == 0xff) {
586 memmove(&data[i], &data[i + 4], len - i - 4);
587 len -= 4;
588 }
589 }
590 ffseq = 0;
591 if (data[len - 4] == 0xff) {
592 if (data[len - 3] == 0xff
593 && data[len - 2] == 0xff) {
594 len -= 4;
595 }
596 } else if (data[len - 3] == 0xff) {
597 if (data[len - 2] == 0xff
598 && data[len - 1] == 0xff)
599 ffseq = 3;
600 } else if (data[len - 2] == 0xff) {
601 if (data[len - 1] == 0xff)
602 ffseq = 2;
603 } else if (data[len - 1] == 0xff)
604 ffseq = 1;
605 sd->ffseq = ffseq;
606 gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
607}
608
609static void getbrightness(struct gspca_dev *gspca_dev)
610{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300611/* sd->brightness = reg_r(gspca_dev, 0x08);
612 return sd->brightness; */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300613/* PDEBUG(D_CONF, "Called pac7311_getbrightness: Not implemented yet"); */
614}
615
616
617
618static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
619{
620 struct sd *sd = (struct sd *) gspca_dev;
621
622 sd->brightness = val;
623 if (gspca_dev->streaming)
624 setbrightness(gspca_dev);
625 return 0;
626}
627
628static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
629{
630 struct sd *sd = (struct sd *) gspca_dev;
631
632 getbrightness(gspca_dev);
633 *val = sd->brightness;
634 return 0;
635}
636
637static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
638{
639 struct sd *sd = (struct sd *) gspca_dev;
640
641 sd->contrast = val;
642 if (gspca_dev->streaming)
643 setcontrast(gspca_dev);
644 return 0;
645}
646
647static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
648{
649 struct sd *sd = (struct sd *) gspca_dev;
650
651/* getcontrast(gspca_dev); */
652 *val = sd->contrast;
653 return 0;
654}
655
656static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
657{
658 struct sd *sd = (struct sd *) gspca_dev;
659
660 sd->colors = val;
661 if (gspca_dev->streaming)
662 setcolors(gspca_dev);
663 return 0;
664}
665
666static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
667{
668 struct sd *sd = (struct sd *) gspca_dev;
669
670/* getcolors(gspca_dev); */
671 *val = sd->colors;
672 return 0;
673}
674
675static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
676{
677 struct sd *sd = (struct sd *) gspca_dev;
678
679 sd->autogain = val;
680 if (val) {
681 sd->ag_cnt = AG_CNT_START;
682 sd->avg_lum = 0;
683 } else {
684 sd->ag_cnt = -1;
685 }
686 return 0;
687}
688
689static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
690{
691 struct sd *sd = (struct sd *) gspca_dev;
692
693 *val = sd->autogain;
694 return 0;
695}
696
697/* sub-driver description */
698static struct sd_desc sd_desc = {
699 .name = MODULE_NAME,
700 .ctrls = sd_ctrls,
701 .nctrls = ARRAY_SIZE(sd_ctrls),
702 .config = sd_config,
703 .open = sd_open,
704 .start = sd_start,
705 .stopN = sd_stopN,
706 .stop0 = sd_stop0,
707 .close = sd_close,
708 .pkt_scan = sd_pkt_scan,
709};
710
711/* -- module initialisation -- */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300712static __devinitdata struct usb_device_id device_table[] = {
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300713 {USB_DEVICE(0x093a, 0x2600)},
714 {USB_DEVICE(0x093a, 0x2601)},
715 {USB_DEVICE(0x093a, 0x2603)},
716 {USB_DEVICE(0x093a, 0x2608)},
717 {USB_DEVICE(0x093a, 0x260e)},
718 {USB_DEVICE(0x093a, 0x260f)},
719 {USB_DEVICE(0x093a, 0x2621)},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300720 {}
721};
722MODULE_DEVICE_TABLE(usb, device_table);
723
724/* -- device connect -- */
725static int sd_probe(struct usb_interface *intf,
726 const struct usb_device_id *id)
727{
728 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
729 THIS_MODULE);
730}
731
732static struct usb_driver sd_driver = {
733 .name = MODULE_NAME,
734 .id_table = device_table,
735 .probe = sd_probe,
736 .disconnect = gspca_disconnect,
737};
738
739/* -- module insert / remove -- */
740static int __init sd_mod_init(void)
741{
742 if (usb_register(&sd_driver) < 0)
743 return -1;
Jean-Francois Moine10b0e962008-07-22 05:35:10 -0300744 PDEBUG(D_PROBE, "registered");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300745 return 0;
746}
747static void __exit sd_mod_exit(void)
748{
749 usb_deregister(&sd_driver);
750 PDEBUG(D_PROBE, "deregistered");
751}
752
753module_init(sd_mod_init);
754module_exit(sd_mod_exit);