blob: caa33292a08a90f899bd2952341154c2f87bff3a [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
Jean-Francois Moinee52a5572008-09-03 16:47:21 -030043 char ffnb; /* number of 'ff' in the previous frame */
44 char tosof; /* number of bytes before next start of frame */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030045 signed char ag_cnt;
46#define AG_CNT_START 13
47};
48
49/* V4L2 controls supported by the driver */
50static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
51static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
52static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
53static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
54static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
55static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
56static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
57static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
58
59static struct ctrl sd_ctrls[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030060 {
61 {
62 .id = V4L2_CID_BRIGHTNESS,
63 .type = V4L2_CTRL_TYPE_INTEGER,
64 .name = "Brightness",
65 .minimum = 0,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -030066#define BRIGHTNESS_MAX 0x20
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030067 .maximum = BRIGHTNESS_MAX,
68 .step = 1,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -030069#define BRIGHTNESS_DEF 0x10
70 .default_value = BRIGHTNESS_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030071 },
72 .set = sd_setbrightness,
73 .get = sd_getbrightness,
74 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030075 {
76 {
77 .id = V4L2_CID_CONTRAST,
78 .type = V4L2_CTRL_TYPE_INTEGER,
79 .name = "Contrast",
80 .minimum = 0,
81 .maximum = 255,
82 .step = 1,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -030083#define CONTRAST_DEF 127
84 .default_value = CONTRAST_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030085 },
86 .set = sd_setcontrast,
87 .get = sd_getcontrast,
88 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030089 {
90 {
91 .id = V4L2_CID_SATURATION,
92 .type = V4L2_CTRL_TYPE_INTEGER,
93 .name = "Color",
94 .minimum = 0,
95 .maximum = 255,
96 .step = 1,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -030097#define COLOR_DEF 127
98 .default_value = COLOR_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030099 },
100 .set = sd_setcolors,
101 .get = sd_getcolors,
102 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300103 {
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,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300111#define AUTOGAIN_DEF 1
112 .default_value = AUTOGAIN_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300113 },
114 .set = sd_setautogain,
115 .get = sd_getautogain,
116 },
117};
118
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300119static 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},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300135};
136
137#define PAC7311_JPEG_HEADER_SIZE (sizeof pac7311_jpeg_header) /* (594) */
138
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300139static const __u8 pac7311_jpeg_header[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300140 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
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300209static void reg_w_buf(struct gspca_dev *gspca_dev,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300210 __u16 index,
211 const char *buffer, __u16 len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300212{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300213 memcpy(gspca_dev->usb_buf, buffer, len);
214 usb_control_msg(gspca_dev->dev,
215 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300216 1, /* request */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300217 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300218 0, /* value */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300219 index, gspca_dev->usb_buf, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300220 500);
221}
222
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300223static __u8 reg_r(struct gspca_dev *gspca_dev,
224 __u16 index)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300225{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300226 usb_control_msg(gspca_dev->dev,
227 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300228 0, /* request */
229 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
230 0, /* value */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300231 index, gspca_dev->usb_buf, 1,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300232 500);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300233 return gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300234}
235
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300236static void reg_w(struct gspca_dev *gspca_dev,
237 __u16 index,
238 __u8 value)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300239{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300240 gspca_dev->usb_buf[0] = value;
241 usb_control_msg(gspca_dev->dev,
242 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300243 0, /* request */
244 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300245 value, index, gspca_dev->usb_buf, 1,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300246 500);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300247}
248
249/* this function is called at probe time */
250static int sd_config(struct gspca_dev *gspca_dev,
251 const struct usb_device_id *id)
252{
253 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300254 struct cam *cam;
255
256 PDEBUG(D_CONF, "Find Sensor PAC7311");
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300257 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);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300267
268 cam = &gspca_dev->cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300269 cam->epaddr = 0x05;
270 cam->cam_mode = vga_mode;
271 cam->nmodes = ARRAY_SIZE(vga_mode);
272
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300273 sd->brightness = BRIGHTNESS_DEF;
274 sd->contrast = CONTRAST_DEF;
275 sd->colors = COLOR_DEF;
276 sd->autogain = AUTOGAIN_DEF;
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300277 sd->ag_cnt = -1;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300278 return 0;
279}
280
281static void setbrightness(struct gspca_dev *gspca_dev)
282{
283 struct sd *sd = (struct sd *) gspca_dev;
284 int brightness;
285
286/*jfm: inverted?*/
287 brightness = BRIGHTNESS_MAX - sd->brightness;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300288 reg_w(gspca_dev, 0xff, 0x04);
289/* reg_w(gspca_dev, 0x0e, 0x00); */
290 reg_w(gspca_dev, 0x0f, brightness);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300291 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300292 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300293 PDEBUG(D_CONF|D_STREAM, "brightness: %i", brightness);
294}
295
296static void setcontrast(struct gspca_dev *gspca_dev)
297{
298 struct sd *sd = (struct sd *) gspca_dev;
299
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300300 reg_w(gspca_dev, 0xff, 0x01);
301 reg_w(gspca_dev, 0x80, sd->contrast);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300302 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300303 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300304 PDEBUG(D_CONF|D_STREAM, "contrast: %i", sd->contrast);
305}
306
307static void setcolors(struct gspca_dev *gspca_dev)
308{
309 struct sd *sd = (struct sd *) gspca_dev;
310
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300311 reg_w(gspca_dev, 0xff, 0x01);
312 reg_w(gspca_dev, 0x10, sd->colors);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300313 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300314 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300315 PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
316}
317
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300318static void setautogain(struct gspca_dev *gspca_dev)
319{
320 struct sd *sd = (struct sd *) gspca_dev;
321
322 if (sd->autogain) {
323 sd->lum_sum = 0;
324 sd->ag_cnt = AG_CNT_START;
325 } else {
326 sd->ag_cnt = -1;
327 }
328}
329
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300330/* this function is called at open time */
331static int sd_open(struct gspca_dev *gspca_dev)
332{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300333 reg_w(gspca_dev, 0x78, 0x00); /* Turn on LED */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300334 return 0;
335}
336
337static void sd_start(struct gspca_dev *gspca_dev)
338{
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300339 struct sd *sd = (struct sd *) gspca_dev;
340
341 sd->ffnb = 0;
342 sd->tosof = 0;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300343 reg_w(gspca_dev, 0xff, 0x01);
344 reg_w_buf(gspca_dev, 0x0002, "\x48\x0a\x40\x08\x00\x00\x08\x00", 8);
345 reg_w_buf(gspca_dev, 0x000a, "\x06\xff\x11\xff\x5a\x30\x90\x4c", 8);
346 reg_w_buf(gspca_dev, 0x0012, "\x00\x07\x00\x0a\x10\x00\xa0\x10", 8);
347 reg_w_buf(gspca_dev, 0x001a, "\x02\x00\x00\x00\x00\x0b\x01\x00", 8);
348 reg_w_buf(gspca_dev, 0x0022, "\x00\x00\x00\x00\x00\x00\x00\x00", 8);
349 reg_w_buf(gspca_dev, 0x002a, "\x00\x00\x00", 3);
350 reg_w_buf(gspca_dev, 0x003e, "\x00\x00\x78\x52\x4a\x52\x78\x6e", 8);
351 reg_w_buf(gspca_dev, 0x0046, "\x48\x46\x48\x6e\x5f\x49\x42\x49", 8);
352 reg_w_buf(gspca_dev, 0x004e, "\x5f\x5f\x49\x42\x49\x5f\x6e\x48", 8);
353 reg_w_buf(gspca_dev, 0x0056, "\x46\x48\x6e\x78\x52\x4a\x52\x78", 8);
354 reg_w_buf(gspca_dev, 0x005e, "\x00\x00\x09\x1b\x34\x49\x5c\x9b", 8);
355 reg_w_buf(gspca_dev, 0x0066, "\xd0\xff", 2);
356 reg_w_buf(gspca_dev, 0x0078, "\x44\x00\xf2\x01\x01\x80", 6);
357 reg_w_buf(gspca_dev, 0x007f, "\x2a\x1c\x00\xc8\x02\x58\x03\x84", 8);
358 reg_w_buf(gspca_dev, 0x0087, "\x12\x00\x1a\x04\x08\x0c\x10\x14", 8);
359 reg_w_buf(gspca_dev, 0x008f, "\x18\x20", 2);
360 reg_w_buf(gspca_dev, 0x0096, "\x01\x08\x04", 3);
361 reg_w_buf(gspca_dev, 0x00a0, "\x44\x44\x44\x04", 4);
362 reg_w_buf(gspca_dev, 0x00f0, "\x01\x00\x00\x00\x22\x00\x20\x00", 8);
363 reg_w_buf(gspca_dev, 0x00f8, "\x3f\x00\x0a\x01\x00", 5);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300364
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300365 reg_w(gspca_dev, 0xff, 0x04);
366 reg_w(gspca_dev, 0x02, 0x04);
367 reg_w(gspca_dev, 0x03, 0x54);
368 reg_w(gspca_dev, 0x04, 0x07);
369 reg_w(gspca_dev, 0x05, 0x2b);
370 reg_w(gspca_dev, 0x06, 0x09);
371 reg_w(gspca_dev, 0x07, 0x0f);
372 reg_w(gspca_dev, 0x08, 0x09);
373 reg_w(gspca_dev, 0x09, 0x00);
374 reg_w(gspca_dev, 0x0c, 0x07);
375 reg_w(gspca_dev, 0x0d, 0x00);
376 reg_w(gspca_dev, 0x0e, 0x00);
377 reg_w(gspca_dev, 0x0f, 0x62);
378 reg_w(gspca_dev, 0x10, 0x08);
379 reg_w(gspca_dev, 0x12, 0x07);
380 reg_w(gspca_dev, 0x13, 0x00);
381 reg_w(gspca_dev, 0x14, 0x00);
382 reg_w(gspca_dev, 0x15, 0x00);
383 reg_w(gspca_dev, 0x16, 0x00);
384 reg_w(gspca_dev, 0x17, 0x00);
385 reg_w(gspca_dev, 0x18, 0x00);
386 reg_w(gspca_dev, 0x19, 0x00);
387 reg_w(gspca_dev, 0x1a, 0x00);
388 reg_w(gspca_dev, 0x1b, 0x03);
389 reg_w(gspca_dev, 0x1c, 0xa0);
390 reg_w(gspca_dev, 0x1d, 0x01);
391 reg_w(gspca_dev, 0x1e, 0xf4);
392 reg_w(gspca_dev, 0x21, 0x00);
393 reg_w(gspca_dev, 0x22, 0x08);
394 reg_w(gspca_dev, 0x24, 0x03);
395 reg_w(gspca_dev, 0x26, 0x00);
396 reg_w(gspca_dev, 0x27, 0x01);
397 reg_w(gspca_dev, 0x28, 0xca);
398 reg_w(gspca_dev, 0x29, 0x10);
399 reg_w(gspca_dev, 0x2a, 0x06);
400 reg_w(gspca_dev, 0x2b, 0x78);
401 reg_w(gspca_dev, 0x2c, 0x00);
402 reg_w(gspca_dev, 0x2d, 0x00);
403 reg_w(gspca_dev, 0x2e, 0x00);
404 reg_w(gspca_dev, 0x2f, 0x00);
405 reg_w(gspca_dev, 0x30, 0x23);
406 reg_w(gspca_dev, 0x31, 0x28);
407 reg_w(gspca_dev, 0x32, 0x04);
408 reg_w(gspca_dev, 0x33, 0x11);
409 reg_w(gspca_dev, 0x34, 0x00);
410 reg_w(gspca_dev, 0x35, 0x00);
411 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300412 setcontrast(gspca_dev);
413 setbrightness(gspca_dev);
414 setcolors(gspca_dev);
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300415 setautogain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300416
417 /* set correct resolution */
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300418 switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300419 case 2: /* 160x120 */
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, 0x09);
424 reg_w(gspca_dev, 0x17, 0x20);
425 reg_w(gspca_dev, 0x1b, 0x00);
426/* reg_w(gspca_dev, 0x80, 0x69); */
427 reg_w(gspca_dev, 0x87, 0x10);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300428 break;
429 case 1: /* 320x240 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300430 reg_w(gspca_dev, 0xff, 0x04);
431 reg_w(gspca_dev, 0x02, 0x03);
432 reg_w(gspca_dev, 0xff, 0x01);
433 reg_w(gspca_dev, 0x08, 0x09);
434 reg_w(gspca_dev, 0x17, 0x30);
435/* reg_w(gspca_dev, 0x80, 0x3f); */
436 reg_w(gspca_dev, 0x87, 0x11);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300437 break;
438 case 0: /* 640x480 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300439 reg_w(gspca_dev, 0xff, 0x04);
440 reg_w(gspca_dev, 0x02, 0x03);
441 reg_w(gspca_dev, 0xff, 0x01);
442 reg_w(gspca_dev, 0x08, 0x08);
443 reg_w(gspca_dev, 0x17, 0x00);
444/* reg_w(gspca_dev, 0x80, 0x1c); */
445 reg_w(gspca_dev, 0x87, 0x12);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300446 break;
447 }
448
449 /* start stream */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300450 reg_w(gspca_dev, 0xff, 0x01);
451 reg_w(gspca_dev, 0x78, 0x04);
452 reg_w(gspca_dev, 0x78, 0x05);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300453}
454
455static void sd_stopN(struct gspca_dev *gspca_dev)
456{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300457 reg_w(gspca_dev, 0xff, 0x04);
458 reg_w(gspca_dev, 0x27, 0x80);
459 reg_w(gspca_dev, 0x28, 0xca);
460 reg_w(gspca_dev, 0x29, 0x53);
461 reg_w(gspca_dev, 0x2a, 0x0e);
462 reg_w(gspca_dev, 0xff, 0x01);
463 reg_w(gspca_dev, 0x3e, 0x20);
464 reg_w(gspca_dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */
465 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
466 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300467}
468
469static void sd_stop0(struct gspca_dev *gspca_dev)
470{
471}
472
473/* this function is called at close time */
474static void sd_close(struct gspca_dev *gspca_dev)
475{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300476 reg_w(gspca_dev, 0xff, 0x04);
477 reg_w(gspca_dev, 0x27, 0x80);
478 reg_w(gspca_dev, 0x28, 0xca);
479 reg_w(gspca_dev, 0x29, 0x53);
480 reg_w(gspca_dev, 0x2a, 0x0e);
481 reg_w(gspca_dev, 0xff, 0x01);
482 reg_w(gspca_dev, 0x3e, 0x20);
483 reg_w(gspca_dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */
484 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
485 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300486}
487
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300488static void do_autogain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300489{
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300490 struct sd *sd = (struct sd *) gspca_dev;
491 int luma;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300492 int luma_mean = 128;
493 int luma_delta = 20;
494 __u8 spring = 5;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300495 int Gbright;
496
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300497 if (!atomic_read(&sd->do_gain))
498 return;
499 atomic_set(&sd->do_gain, 0);
500
501 luma = atomic_read(&sd->avg_lum);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300502 Gbright = reg_r(gspca_dev, 0x02);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300503 PDEBUG(D_FRAM, "luma mean %d", luma);
504 if (luma < luma_mean - luma_delta ||
505 luma > luma_mean + luma_delta) {
506 Gbright += (luma_mean - luma) >> spring;
507 if (Gbright > 0x1a)
508 Gbright = 0x1a;
509 else if (Gbright < 4)
510 Gbright = 4;
511 PDEBUG(D_FRAM, "gbright %d", Gbright);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300512 reg_w(gspca_dev, 0xff, 0x04);
513 reg_w(gspca_dev, 0x0f, Gbright);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300514 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300515 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300516 }
517}
518
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300519/* output the jpeg header */
520static void put_jpeg_head(struct gspca_dev *gspca_dev,
521 struct gspca_frame *frame)
522{
523 unsigned char tmpbuf[4];
524
525 gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
526 (__u8 *) pac7311_jpeg_header,
527 12);
528 tmpbuf[0] = gspca_dev->height >> 8;
529 tmpbuf[1] = gspca_dev->height & 0xff;
530 tmpbuf[2] = gspca_dev->width >> 8;
531 tmpbuf[3] = gspca_dev->width & 0xff;
532 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
533 tmpbuf, 4);
534 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
535 (__u8 *) &pac7311_jpeg_header[16],
536 PAC7311_JPEG_HEADER_SIZE - 16);
537}
538
539/* this function is run at interrupt level */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300540static void sd_pkt_scan(struct gspca_dev *gspca_dev,
541 struct gspca_frame *frame, /* target */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300542 __u8 *data, /* isoc packet */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300543 int len) /* iso packet length */
544{
545 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300546 int i;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300547
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300548#define INTER_FRAME 0x53
549#define LUM_OFFSET 0x1e /* reverse offset / start of frame */
550
551 /*
552 * inside a frame, there may be:
553 * escaped ff ('ff 00')
554 * sequences'ff ff ff xx' to remove
555 * end of frame ('ff d9')
556 * at the end of frame, there are:
557 * ff d9 end of frame
558 * 0x33 bytes
559 * one byte luminosity
560 * 0x16 bytes
561 * ff ff 00 ff 96 62 44 start of frame header
562 */
563
564 if (sd->tosof == 0) { /* if inside a frame */
565
566 /* check for 'ff ff ff xx' at start and at end of packet */
567 /* (len is always >= 3) */
568 switch (sd->ffnb) {
569 case 1:
570 if (data[0] != 0xff)
571 break; /* keep 'ff 00' */
572 /* fall thru */
573 case 2:
574 case 3:
575 data += 4 - sd->ffnb;
576 len -= 4 - sd->ffnb;
577 sd->ffnb = 0;
578 break;
579 }
580 if (data[len - 1] == 0xff) {
581 if (data[len - 2] == 0xff) {
582 if (data[len - 3] == 0xff) {
583 sd->ffnb = 3;
584 len -= 3;
585 } else {
586 sd->ffnb = 2;
587 len -= 2;
588 }
589 } else {
590 sd->ffnb = 1;
591 len--;
592 }
593 }
594 } else { /* outside a frame */
595
596 /*
597 * get the luminosity
598 * and go to the start of frame
599 */
600 data += sd->tosof;
601 len -= sd->tosof;
602 if (sd->tosof > LUM_OFFSET)
603 sd->lum_sum += data[-LUM_OFFSET];
604 put_jpeg_head(gspca_dev, frame);
605 sd->tosof = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300606 }
607
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300608 for (i = 0; i < len; i++) {
609 if (data[i] != 0xff)
610 continue;
611 switch (data[i + 1]) {
612 case 0xd9: /* end of frame */
613 frame = gspca_frame_add(gspca_dev,
614 LAST_PACKET,
615 frame, data, i + 1);
616 data += INTER_FRAME;
617 len -= INTER_FRAME;
618 i = 0;
619 if (len > LUM_OFFSET)
620 sd->lum_sum += data[-LUM_OFFSET];
621 if (len < 0) {
622 sd->tosof = -len;
623 break;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300624 }
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300625 put_jpeg_head(gspca_dev, frame);
626 break;
627 case 0xff: /* 'ff ff ff xx' */
628 gspca_frame_add(gspca_dev, INTER_PACKET,
629 frame, data, i);
630 data += i + 4;
631 len -= i + 4;
632 i = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300633 break;
634 }
635 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300636}
637
638static void getbrightness(struct gspca_dev *gspca_dev)
639{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300640/* sd->brightness = reg_r(gspca_dev, 0x08);
641 return sd->brightness; */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300642/* PDEBUG(D_CONF, "Called pac7311_getbrightness: Not implemented yet"); */
643}
644
645
646
647static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
648{
649 struct sd *sd = (struct sd *) gspca_dev;
650
651 sd->brightness = val;
652 if (gspca_dev->streaming)
653 setbrightness(gspca_dev);
654 return 0;
655}
656
657static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
658{
659 struct sd *sd = (struct sd *) gspca_dev;
660
661 getbrightness(gspca_dev);
662 *val = sd->brightness;
663 return 0;
664}
665
666static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
667{
668 struct sd *sd = (struct sd *) gspca_dev;
669
670 sd->contrast = val;
671 if (gspca_dev->streaming)
672 setcontrast(gspca_dev);
673 return 0;
674}
675
676static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
677{
678 struct sd *sd = (struct sd *) gspca_dev;
679
680/* getcontrast(gspca_dev); */
681 *val = sd->contrast;
682 return 0;
683}
684
685static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
686{
687 struct sd *sd = (struct sd *) gspca_dev;
688
689 sd->colors = val;
690 if (gspca_dev->streaming)
691 setcolors(gspca_dev);
692 return 0;
693}
694
695static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
696{
697 struct sd *sd = (struct sd *) gspca_dev;
698
699/* getcolors(gspca_dev); */
700 *val = sd->colors;
701 return 0;
702}
703
704static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
705{
706 struct sd *sd = (struct sd *) gspca_dev;
707
708 sd->autogain = val;
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300709 if (gspca_dev->streaming)
710 setautogain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300711 return 0;
712}
713
714static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
715{
716 struct sd *sd = (struct sd *) gspca_dev;
717
718 *val = sd->autogain;
719 return 0;
720}
721
722/* sub-driver description */
723static struct sd_desc sd_desc = {
724 .name = MODULE_NAME,
725 .ctrls = sd_ctrls,
726 .nctrls = ARRAY_SIZE(sd_ctrls),
727 .config = sd_config,
728 .open = sd_open,
729 .start = sd_start,
730 .stopN = sd_stopN,
731 .stop0 = sd_stop0,
732 .close = sd_close,
733 .pkt_scan = sd_pkt_scan,
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300734 .dq_callback = do_autogain,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300735};
736
737/* -- module initialisation -- */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300738static __devinitdata struct usb_device_id device_table[] = {
Jean-Francois Moine9d64fdb2008-07-25 08:53:03 -0300739 {USB_DEVICE(0x093a, 0x2600)},
740 {USB_DEVICE(0x093a, 0x2601)},
741 {USB_DEVICE(0x093a, 0x2603)},
742 {USB_DEVICE(0x093a, 0x2608)},
743 {USB_DEVICE(0x093a, 0x260e)},
744 {USB_DEVICE(0x093a, 0x260f)},
745 {USB_DEVICE(0x093a, 0x2621)},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300746 {}
747};
748MODULE_DEVICE_TABLE(usb, device_table);
749
750/* -- device connect -- */
751static int sd_probe(struct usb_interface *intf,
752 const struct usb_device_id *id)
753{
754 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
755 THIS_MODULE);
756}
757
758static struct usb_driver sd_driver = {
759 .name = MODULE_NAME,
760 .id_table = device_table,
761 .probe = sd_probe,
762 .disconnect = gspca_disconnect,
763};
764
765/* -- module insert / remove -- */
766static int __init sd_mod_init(void)
767{
768 if (usb_register(&sd_driver) < 0)
769 return -1;
Jean-Francois Moine10b0e962008-07-22 05:35:10 -0300770 PDEBUG(D_PROBE, "registered");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300771 return 0;
772}
773static void __exit sd_mod_exit(void)
774{
775 usb_deregister(&sd_driver);
776 PDEBUG(D_PROBE, "deregistered");
777}
778
779module_init(sd_mod_init);
780module_exit(sd_mod_exit);