blob: 815bea6edc448f989ac9a8f4df41ea7067b1dc29 [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
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -030034 int lum_sum;
35 atomic_t avg_lum;
36 atomic_t do_gain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030037
38 unsigned char brightness;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030039 unsigned char contrast;
40 unsigned char colors;
41 unsigned char autogain;
42
43 char ffseq;
44 signed char ag_cnt;
45#define AG_CNT_START 13
46};
47
48/* V4L2 controls supported by the driver */
49static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
50static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
51static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
52static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
53static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
54static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
55static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
56static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
57
58static struct ctrl sd_ctrls[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030059 {
60 {
61 .id = V4L2_CID_BRIGHTNESS,
62 .type = V4L2_CTRL_TYPE_INTEGER,
63 .name = "Brightness",
64 .minimum = 0,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -030065#define BRIGHTNESS_MAX 0x20
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030066 .maximum = BRIGHTNESS_MAX,
67 .step = 1,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -030068#define BRIGHTNESS_DEF 0x10
69 .default_value = BRIGHTNESS_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030070 },
71 .set = sd_setbrightness,
72 .get = sd_getbrightness,
73 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030074 {
75 {
76 .id = V4L2_CID_CONTRAST,
77 .type = V4L2_CTRL_TYPE_INTEGER,
78 .name = "Contrast",
79 .minimum = 0,
80 .maximum = 255,
81 .step = 1,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -030082#define CONTRAST_DEF 127
83 .default_value = CONTRAST_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030084 },
85 .set = sd_setcontrast,
86 .get = sd_getcontrast,
87 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030088 {
89 {
90 .id = V4L2_CID_SATURATION,
91 .type = V4L2_CTRL_TYPE_INTEGER,
92 .name = "Color",
93 .minimum = 0,
94 .maximum = 255,
95 .step = 1,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -030096#define COLOR_DEF 127
97 .default_value = COLOR_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030098 },
99 .set = sd_setcolors,
100 .get = sd_getcolors,
101 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300102 {
103 {
104 .id = V4L2_CID_AUTOGAIN,
105 .type = V4L2_CTRL_TYPE_BOOLEAN,
106 .name = "Auto Gain",
107 .minimum = 0,
108 .maximum = 1,
109 .step = 1,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300110#define AUTOGAIN_DEF 1
111 .default_value = AUTOGAIN_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300112 },
113 .set = sd_setautogain,
114 .get = sd_getautogain,
115 },
116};
117
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300118static struct v4l2_pix_format vga_mode[] = {
119 {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
120 .bytesperline = 160,
121 .sizeimage = 160 * 120 * 3 / 8 + 590,
122 .colorspace = V4L2_COLORSPACE_JPEG,
123 .priv = 2},
124 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
125 .bytesperline = 320,
126 .sizeimage = 320 * 240 * 3 / 8 + 590,
127 .colorspace = V4L2_COLORSPACE_JPEG,
128 .priv = 1},
129 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
130 .bytesperline = 640,
131 .sizeimage = 640 * 480 * 3 / 8 + 590,
132 .colorspace = V4L2_COLORSPACE_JPEG,
133 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300134};
135
136#define PAC7311_JPEG_HEADER_SIZE (sizeof pac7311_jpeg_header) /* (594) */
137
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300138static const __u8 pac7311_jpeg_header[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300139 0xff, 0xd8,
140 0xff, 0xe0, 0x00, 0x03, 0x20,
141 0xff, 0xc0, 0x00, 0x11, 0x08,
142 0x01, 0xe0, /* 12: height */
143 0x02, 0x80, /* 14: width */
144 0x03, /* 16 */
145 0x01, 0x21, 0x00,
146 0x02, 0x11, 0x01,
147 0x03, 0x11, 0x01,
148 0xff, 0xdb, 0x00, 0x84,
149 0x00, 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, 0x0d,
150 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, 0x1a, 0x18, 0x16,
151 0x16, 0x18, 0x31, 0x23, 0x25, 0x1d, 0x28, 0x3a, 0x33, 0x3d,
152 0x3c, 0x39, 0x33, 0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40,
153 0x44, 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57, 0x5f,
154 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71, 0x79, 0x70, 0x64,
155 0x78, 0x5c, 0x65, 0x67, 0x63, 0x01, 0x11, 0x12, 0x12, 0x18,
156 0x15, 0x18, 0x2f, 0x1a, 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42,
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 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
161 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
162 0xff, 0xc4, 0x01, 0xa2, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01,
163 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
164 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
165 0x09, 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02,
166 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d,
167 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31,
168 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32,
169 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52,
170 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
171 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
172 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45,
173 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57,
174 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
175 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83,
176 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94,
177 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
178 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
179 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
180 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
181 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8,
182 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
183 0xf9, 0xfa, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01,
184 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
185 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
186 0x0b, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04,
187 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01,
188 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41,
189 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14,
190 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
191 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25,
192 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a,
193 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46,
194 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
195 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a,
196 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83,
197 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94,
198 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
199 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
200 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
201 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
202 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
203 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa,
204 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03,
205 0x11, 0x00, 0x3f, 0x00
206};
207
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300208static void reg_w_buf(struct gspca_dev *gspca_dev,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300209 __u16 index,
210 const char *buffer, __u16 len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300211{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300212 memcpy(gspca_dev->usb_buf, buffer, len);
213 usb_control_msg(gspca_dev->dev,
214 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300215 1, /* request */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300216 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300217 0, /* value */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300218 index, gspca_dev->usb_buf, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300219 500);
220}
221
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300222static __u8 reg_r(struct gspca_dev *gspca_dev,
223 __u16 index)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300224{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300225 usb_control_msg(gspca_dev->dev,
226 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300227 0, /* request */
228 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
229 0, /* value */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300230 index, gspca_dev->usb_buf, 1,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300231 500);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300232 return gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300233}
234
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300235static void reg_w(struct gspca_dev *gspca_dev,
236 __u16 index,
237 __u8 value)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300238{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300239 gspca_dev->usb_buf[0] = value;
240 usb_control_msg(gspca_dev->dev,
241 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300242 0, /* request */
243 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300244 value, index, gspca_dev->usb_buf, 1,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300245 500);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300246}
247
248/* this function is called at probe time */
249static int sd_config(struct gspca_dev *gspca_dev,
250 const struct usb_device_id *id)
251{
252 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300253 struct cam *cam;
254
255 PDEBUG(D_CONF, "Find Sensor PAC7311");
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300256 reg_w(gspca_dev, 0x78, 0x40); /* Bit_0=start stream, Bit_7=LED */
257 reg_w(gspca_dev, 0x78, 0x40); /* Bit_0=start stream, Bit_7=LED */
258 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
259 reg_w(gspca_dev, 0xff, 0x04);
260 reg_w(gspca_dev, 0x27, 0x80);
261 reg_w(gspca_dev, 0x28, 0xca);
262 reg_w(gspca_dev, 0x29, 0x53);
263 reg_w(gspca_dev, 0x2a, 0x0e);
264 reg_w(gspca_dev, 0xff, 0x01);
265 reg_w(gspca_dev, 0x3e, 0x20);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300266
267 cam = &gspca_dev->cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300268 cam->epaddr = 0x05;
269 cam->cam_mode = vga_mode;
270 cam->nmodes = ARRAY_SIZE(vga_mode);
271
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300272 sd->brightness = BRIGHTNESS_DEF;
273 sd->contrast = CONTRAST_DEF;
274 sd->colors = COLOR_DEF;
275 sd->autogain = AUTOGAIN_DEF;
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300276 sd->ag_cnt = -1;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300277 return 0;
278}
279
280static void setbrightness(struct gspca_dev *gspca_dev)
281{
282 struct sd *sd = (struct sd *) gspca_dev;
283 int brightness;
284
285/*jfm: inverted?*/
286 brightness = BRIGHTNESS_MAX - sd->brightness;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300287 reg_w(gspca_dev, 0xff, 0x04);
288/* reg_w(gspca_dev, 0x0e, 0x00); */
289 reg_w(gspca_dev, 0x0f, brightness);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300290 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300291 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300292 PDEBUG(D_CONF|D_STREAM, "brightness: %i", brightness);
293}
294
295static void setcontrast(struct gspca_dev *gspca_dev)
296{
297 struct sd *sd = (struct sd *) gspca_dev;
298
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300299 reg_w(gspca_dev, 0xff, 0x01);
300 reg_w(gspca_dev, 0x80, sd->contrast);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300301 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300302 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300303 PDEBUG(D_CONF|D_STREAM, "contrast: %i", sd->contrast);
304}
305
306static void setcolors(struct gspca_dev *gspca_dev)
307{
308 struct sd *sd = (struct sd *) gspca_dev;
309
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300310 reg_w(gspca_dev, 0xff, 0x01);
311 reg_w(gspca_dev, 0x10, sd->colors);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300312 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300313 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300314 PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
315}
316
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300317static void setautogain(struct gspca_dev *gspca_dev)
318{
319 struct sd *sd = (struct sd *) gspca_dev;
320
321 if (sd->autogain) {
322 sd->lum_sum = 0;
323 sd->ag_cnt = AG_CNT_START;
324 } else {
325 sd->ag_cnt = -1;
326 }
327}
328
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300329/* this function is called at open time */
330static int sd_open(struct gspca_dev *gspca_dev)
331{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300332 reg_w(gspca_dev, 0x78, 0x00); /* Turn on LED */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300333 return 0;
334}
335
336static void sd_start(struct gspca_dev *gspca_dev)
337{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300338 reg_w(gspca_dev, 0xff, 0x01);
339 reg_w_buf(gspca_dev, 0x0002, "\x48\x0a\x40\x08\x00\x00\x08\x00", 8);
340 reg_w_buf(gspca_dev, 0x000a, "\x06\xff\x11\xff\x5a\x30\x90\x4c", 8);
341 reg_w_buf(gspca_dev, 0x0012, "\x00\x07\x00\x0a\x10\x00\xa0\x10", 8);
342 reg_w_buf(gspca_dev, 0x001a, "\x02\x00\x00\x00\x00\x0b\x01\x00", 8);
343 reg_w_buf(gspca_dev, 0x0022, "\x00\x00\x00\x00\x00\x00\x00\x00", 8);
344 reg_w_buf(gspca_dev, 0x002a, "\x00\x00\x00", 3);
345 reg_w_buf(gspca_dev, 0x003e, "\x00\x00\x78\x52\x4a\x52\x78\x6e", 8);
346 reg_w_buf(gspca_dev, 0x0046, "\x48\x46\x48\x6e\x5f\x49\x42\x49", 8);
347 reg_w_buf(gspca_dev, 0x004e, "\x5f\x5f\x49\x42\x49\x5f\x6e\x48", 8);
348 reg_w_buf(gspca_dev, 0x0056, "\x46\x48\x6e\x78\x52\x4a\x52\x78", 8);
349 reg_w_buf(gspca_dev, 0x005e, "\x00\x00\x09\x1b\x34\x49\x5c\x9b", 8);
350 reg_w_buf(gspca_dev, 0x0066, "\xd0\xff", 2);
351 reg_w_buf(gspca_dev, 0x0078, "\x44\x00\xf2\x01\x01\x80", 6);
352 reg_w_buf(gspca_dev, 0x007f, "\x2a\x1c\x00\xc8\x02\x58\x03\x84", 8);
353 reg_w_buf(gspca_dev, 0x0087, "\x12\x00\x1a\x04\x08\x0c\x10\x14", 8);
354 reg_w_buf(gspca_dev, 0x008f, "\x18\x20", 2);
355 reg_w_buf(gspca_dev, 0x0096, "\x01\x08\x04", 3);
356 reg_w_buf(gspca_dev, 0x00a0, "\x44\x44\x44\x04", 4);
357 reg_w_buf(gspca_dev, 0x00f0, "\x01\x00\x00\x00\x22\x00\x20\x00", 8);
358 reg_w_buf(gspca_dev, 0x00f8, "\x3f\x00\x0a\x01\x00", 5);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300359
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300360 reg_w(gspca_dev, 0xff, 0x04);
361 reg_w(gspca_dev, 0x02, 0x04);
362 reg_w(gspca_dev, 0x03, 0x54);
363 reg_w(gspca_dev, 0x04, 0x07);
364 reg_w(gspca_dev, 0x05, 0x2b);
365 reg_w(gspca_dev, 0x06, 0x09);
366 reg_w(gspca_dev, 0x07, 0x0f);
367 reg_w(gspca_dev, 0x08, 0x09);
368 reg_w(gspca_dev, 0x09, 0x00);
369 reg_w(gspca_dev, 0x0c, 0x07);
370 reg_w(gspca_dev, 0x0d, 0x00);
371 reg_w(gspca_dev, 0x0e, 0x00);
372 reg_w(gspca_dev, 0x0f, 0x62);
373 reg_w(gspca_dev, 0x10, 0x08);
374 reg_w(gspca_dev, 0x12, 0x07);
375 reg_w(gspca_dev, 0x13, 0x00);
376 reg_w(gspca_dev, 0x14, 0x00);
377 reg_w(gspca_dev, 0x15, 0x00);
378 reg_w(gspca_dev, 0x16, 0x00);
379 reg_w(gspca_dev, 0x17, 0x00);
380 reg_w(gspca_dev, 0x18, 0x00);
381 reg_w(gspca_dev, 0x19, 0x00);
382 reg_w(gspca_dev, 0x1a, 0x00);
383 reg_w(gspca_dev, 0x1b, 0x03);
384 reg_w(gspca_dev, 0x1c, 0xa0);
385 reg_w(gspca_dev, 0x1d, 0x01);
386 reg_w(gspca_dev, 0x1e, 0xf4);
387 reg_w(gspca_dev, 0x21, 0x00);
388 reg_w(gspca_dev, 0x22, 0x08);
389 reg_w(gspca_dev, 0x24, 0x03);
390 reg_w(gspca_dev, 0x26, 0x00);
391 reg_w(gspca_dev, 0x27, 0x01);
392 reg_w(gspca_dev, 0x28, 0xca);
393 reg_w(gspca_dev, 0x29, 0x10);
394 reg_w(gspca_dev, 0x2a, 0x06);
395 reg_w(gspca_dev, 0x2b, 0x78);
396 reg_w(gspca_dev, 0x2c, 0x00);
397 reg_w(gspca_dev, 0x2d, 0x00);
398 reg_w(gspca_dev, 0x2e, 0x00);
399 reg_w(gspca_dev, 0x2f, 0x00);
400 reg_w(gspca_dev, 0x30, 0x23);
401 reg_w(gspca_dev, 0x31, 0x28);
402 reg_w(gspca_dev, 0x32, 0x04);
403 reg_w(gspca_dev, 0x33, 0x11);
404 reg_w(gspca_dev, 0x34, 0x00);
405 reg_w(gspca_dev, 0x35, 0x00);
406 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300407 setcontrast(gspca_dev);
408 setbrightness(gspca_dev);
409 setcolors(gspca_dev);
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300410 setautogain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300411
412 /* set correct resolution */
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300413 switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300414 case 2: /* 160x120 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300415 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, 0x20);
420 reg_w(gspca_dev, 0x1b, 0x00);
421/* reg_w(gspca_dev, 0x80, 0x69); */
422 reg_w(gspca_dev, 0x87, 0x10);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300423 break;
424 case 1: /* 320x240 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300425 reg_w(gspca_dev, 0xff, 0x04);
426 reg_w(gspca_dev, 0x02, 0x03);
427 reg_w(gspca_dev, 0xff, 0x01);
428 reg_w(gspca_dev, 0x08, 0x09);
429 reg_w(gspca_dev, 0x17, 0x30);
430/* reg_w(gspca_dev, 0x80, 0x3f); */
431 reg_w(gspca_dev, 0x87, 0x11);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300432 break;
433 case 0: /* 640x480 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300434 reg_w(gspca_dev, 0xff, 0x04);
435 reg_w(gspca_dev, 0x02, 0x03);
436 reg_w(gspca_dev, 0xff, 0x01);
437 reg_w(gspca_dev, 0x08, 0x08);
438 reg_w(gspca_dev, 0x17, 0x00);
439/* reg_w(gspca_dev, 0x80, 0x1c); */
440 reg_w(gspca_dev, 0x87, 0x12);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300441 break;
442 }
443
444 /* start stream */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300445 reg_w(gspca_dev, 0xff, 0x01);
446 reg_w(gspca_dev, 0x78, 0x04);
447 reg_w(gspca_dev, 0x78, 0x05);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300448}
449
450static void sd_stopN(struct gspca_dev *gspca_dev)
451{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300452 reg_w(gspca_dev, 0xff, 0x04);
453 reg_w(gspca_dev, 0x27, 0x80);
454 reg_w(gspca_dev, 0x28, 0xca);
455 reg_w(gspca_dev, 0x29, 0x53);
456 reg_w(gspca_dev, 0x2a, 0x0e);
457 reg_w(gspca_dev, 0xff, 0x01);
458 reg_w(gspca_dev, 0x3e, 0x20);
459 reg_w(gspca_dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */
460 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
461 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300462}
463
464static void sd_stop0(struct gspca_dev *gspca_dev)
465{
466}
467
468/* this function is called at close time */
469static void sd_close(struct gspca_dev *gspca_dev)
470{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300471 reg_w(gspca_dev, 0xff, 0x04);
472 reg_w(gspca_dev, 0x27, 0x80);
473 reg_w(gspca_dev, 0x28, 0xca);
474 reg_w(gspca_dev, 0x29, 0x53);
475 reg_w(gspca_dev, 0x2a, 0x0e);
476 reg_w(gspca_dev, 0xff, 0x01);
477 reg_w(gspca_dev, 0x3e, 0x20);
478 reg_w(gspca_dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */
479 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
480 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300481}
482
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300483static void do_autogain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300484{
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300485 struct sd *sd = (struct sd *) gspca_dev;
486 int luma;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300487 int luma_mean = 128;
488 int luma_delta = 20;
489 __u8 spring = 5;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300490 int Gbright;
491
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300492 if (!atomic_read(&sd->do_gain))
493 return;
494 atomic_set(&sd->do_gain, 0);
495
496 luma = atomic_read(&sd->avg_lum);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300497 Gbright = reg_r(gspca_dev, 0x02);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300498 PDEBUG(D_FRAM, "luma mean %d", luma);
499 if (luma < luma_mean - luma_delta ||
500 luma > luma_mean + luma_delta) {
501 Gbright += (luma_mean - luma) >> spring;
502 if (Gbright > 0x1a)
503 Gbright = 0x1a;
504 else if (Gbright < 4)
505 Gbright = 4;
506 PDEBUG(D_FRAM, "gbright %d", Gbright);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300507 reg_w(gspca_dev, 0xff, 0x04);
508 reg_w(gspca_dev, 0x0f, Gbright);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300509 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300510 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300511 }
512}
513
514static void sd_pkt_scan(struct gspca_dev *gspca_dev,
515 struct gspca_frame *frame, /* target */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300516 __u8 *data, /* isoc packet */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300517 int len) /* iso packet length */
518{
519 struct sd *sd = (struct sd *) gspca_dev;
520 unsigned char tmpbuf[4];
521 int i, p, ffseq;
522
523/* if (len < 5) { */
524 if (len < 6) {
525/* gspca_dev->last_packet_type = DISCARD_PACKET; */
526 return;
527 }
528
529 ffseq = sd->ffseq;
530
531 for (p = 0; p < len - 6; p++) {
532 if ((data[0 + p] == 0xff)
533 && (data[1 + p] == 0xff)
534 && (data[2 + p] == 0x00)
535 && (data[3 + p] == 0xff)
536 && (data[4 + p] == 0x96)) {
537
538 /* start of frame */
539 if (sd->ag_cnt >= 0 && p > 28) {
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300540 sd->lum_sum += data[p - 23];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300541 if (--sd->ag_cnt < 0) {
542 sd->ag_cnt = AG_CNT_START;
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300543 atomic_set(&sd->avg_lum,
544 sd->lum_sum / AG_CNT_START);
545 sd->lum_sum = 0;
546 atomic_set(&sd->do_gain, 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300547 }
548 }
549
550 /* copy the end of data to the current frame */
551 frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
552 data, p);
553
554 /* put the JPEG header in the new frame */
555 gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
556 (unsigned char *) pac7311_jpeg_header,
557 12);
558 tmpbuf[0] = gspca_dev->height >> 8;
559 tmpbuf[1] = gspca_dev->height & 0xff;
560 tmpbuf[2] = gspca_dev->width >> 8;
561 tmpbuf[3] = gspca_dev->width & 0xff;
562 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
563 tmpbuf, 4);
564 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
565 (unsigned char *) &pac7311_jpeg_header[16],
566 PAC7311_JPEG_HEADER_SIZE - 16);
567
568 data += p + 7;
569 len -= p + 7;
570 ffseq = 0;
571 break;
572 }
573 }
574
575 /* remove the 'ff ff ff xx' sequences */
576 switch (ffseq) {
577 case 3:
578 data += 1;
579 len -= 1;
580 break;
581 case 2:
582 if (data[0] == 0xff) {
583 data += 2;
584 len -= 2;
585 frame->data_end -= 2;
586 }
587 break;
588 case 1:
589 if (data[0] == 0xff
590 && data[1] == 0xff) {
591 data += 3;
592 len -= 3;
593 frame->data_end -= 1;
594 }
595 break;
596 }
597 for (i = 0; i < len - 4; i++) {
598 if (data[i] == 0xff
599 && data[i + 1] == 0xff
600 && data[i + 2] == 0xff) {
601 memmove(&data[i], &data[i + 4], len - i - 4);
602 len -= 4;
603 }
604 }
605 ffseq = 0;
606 if (data[len - 4] == 0xff) {
607 if (data[len - 3] == 0xff
608 && data[len - 2] == 0xff) {
609 len -= 4;
610 }
611 } else if (data[len - 3] == 0xff) {
612 if (data[len - 2] == 0xff
613 && data[len - 1] == 0xff)
614 ffseq = 3;
615 } else if (data[len - 2] == 0xff) {
616 if (data[len - 1] == 0xff)
617 ffseq = 2;
618 } else if (data[len - 1] == 0xff)
619 ffseq = 1;
620 sd->ffseq = ffseq;
621 gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
622}
623
624static void getbrightness(struct gspca_dev *gspca_dev)
625{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300626/* sd->brightness = reg_r(gspca_dev, 0x08);
627 return sd->brightness; */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300628/* PDEBUG(D_CONF, "Called pac7311_getbrightness: Not implemented yet"); */
629}
630
631
632
633static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
634{
635 struct sd *sd = (struct sd *) gspca_dev;
636
637 sd->brightness = val;
638 if (gspca_dev->streaming)
639 setbrightness(gspca_dev);
640 return 0;
641}
642
643static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
644{
645 struct sd *sd = (struct sd *) gspca_dev;
646
647 getbrightness(gspca_dev);
648 *val = sd->brightness;
649 return 0;
650}
651
652static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
653{
654 struct sd *sd = (struct sd *) gspca_dev;
655
656 sd->contrast = val;
657 if (gspca_dev->streaming)
658 setcontrast(gspca_dev);
659 return 0;
660}
661
662static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
663{
664 struct sd *sd = (struct sd *) gspca_dev;
665
666/* getcontrast(gspca_dev); */
667 *val = sd->contrast;
668 return 0;
669}
670
671static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
672{
673 struct sd *sd = (struct sd *) gspca_dev;
674
675 sd->colors = val;
676 if (gspca_dev->streaming)
677 setcolors(gspca_dev);
678 return 0;
679}
680
681static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
682{
683 struct sd *sd = (struct sd *) gspca_dev;
684
685/* getcolors(gspca_dev); */
686 *val = sd->colors;
687 return 0;
688}
689
690static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
691{
692 struct sd *sd = (struct sd *) gspca_dev;
693
694 sd->autogain = val;
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300695 if (gspca_dev->streaming)
696 setautogain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300697 return 0;
698}
699
700static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
701{
702 struct sd *sd = (struct sd *) gspca_dev;
703
704 *val = sd->autogain;
705 return 0;
706}
707
708/* sub-driver description */
709static struct sd_desc sd_desc = {
710 .name = MODULE_NAME,
711 .ctrls = sd_ctrls,
712 .nctrls = ARRAY_SIZE(sd_ctrls),
713 .config = sd_config,
714 .open = sd_open,
715 .start = sd_start,
716 .stopN = sd_stopN,
717 .stop0 = sd_stop0,
718 .close = sd_close,
719 .pkt_scan = sd_pkt_scan,
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300720 .dq_callback = do_autogain,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300721};
722
723/* -- module initialisation -- */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300724static __devinitdata struct usb_device_id device_table[] = {
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300725 {USB_DEVICE(0x093a, 0x2600)},
726 {USB_DEVICE(0x093a, 0x2601)},
727 {USB_DEVICE(0x093a, 0x2603)},
728 {USB_DEVICE(0x093a, 0x2608)},
729 {USB_DEVICE(0x093a, 0x260e)},
730 {USB_DEVICE(0x093a, 0x260f)},
731 {USB_DEVICE(0x093a, 0x2621)},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300732 {}
733};
734MODULE_DEVICE_TABLE(usb, device_table);
735
736/* -- device connect -- */
737static int sd_probe(struct usb_interface *intf,
738 const struct usb_device_id *id)
739{
740 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
741 THIS_MODULE);
742}
743
744static struct usb_driver sd_driver = {
745 .name = MODULE_NAME,
746 .id_table = device_table,
747 .probe = sd_probe,
748 .disconnect = gspca_disconnect,
749};
750
751/* -- module insert / remove -- */
752static int __init sd_mod_init(void)
753{
754 if (usb_register(&sd_driver) < 0)
755 return -1;
Jean-Francois Moine10b0e962008-07-22 05:35:10 -0300756 PDEBUG(D_PROBE, "registered");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300757 return 0;
758}
759static void __exit sd_mod_exit(void)
760{
761 usb_deregister(&sd_driver);
762 PDEBUG(D_PROBE, "deregistered");
763}
764
765module_init(sd_mod_init);
766module_exit(sd_mod_exit);