blob: 034c00d6c0aba26a2d0de5e63f54c378a7cb7d64 [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
Jean-Francois Moine49b57db2008-09-03 16:47:25 -030047
48 __u8 sensor;
49#define SENSOR_PAC7302 0
50#define SENSOR_PAC7311 1
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030051};
52
53/* V4L2 controls supported by the driver */
54static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
55static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
56static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
57static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
58static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
59static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
60static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
61static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
62
63static struct ctrl sd_ctrls[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030064 {
65 {
66 .id = V4L2_CID_BRIGHTNESS,
67 .type = V4L2_CTRL_TYPE_INTEGER,
68 .name = "Brightness",
69 .minimum = 0,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -030070#define BRIGHTNESS_MAX 0x20
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030071 .maximum = BRIGHTNESS_MAX,
72 .step = 1,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -030073#define BRIGHTNESS_DEF 0x10
74 .default_value = BRIGHTNESS_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030075 },
76 .set = sd_setbrightness,
77 .get = sd_getbrightness,
78 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030079 {
80 {
81 .id = V4L2_CID_CONTRAST,
82 .type = V4L2_CTRL_TYPE_INTEGER,
83 .name = "Contrast",
84 .minimum = 0,
85 .maximum = 255,
86 .step = 1,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -030087#define CONTRAST_DEF 127
88 .default_value = CONTRAST_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030089 },
90 .set = sd_setcontrast,
91 .get = sd_getcontrast,
92 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030093 {
94 {
95 .id = V4L2_CID_SATURATION,
96 .type = V4L2_CTRL_TYPE_INTEGER,
97 .name = "Color",
98 .minimum = 0,
99 .maximum = 255,
100 .step = 1,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300101#define COLOR_DEF 127
102 .default_value = COLOR_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300103 },
104 .set = sd_setcolors,
105 .get = sd_getcolors,
106 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300107 {
108 {
109 .id = V4L2_CID_AUTOGAIN,
110 .type = V4L2_CTRL_TYPE_BOOLEAN,
111 .name = "Auto Gain",
112 .minimum = 0,
113 .maximum = 1,
114 .step = 1,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300115#define AUTOGAIN_DEF 1
116 .default_value = AUTOGAIN_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300117 },
118 .set = sd_setautogain,
119 .get = sd_getautogain,
120 },
121};
122
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300123static struct v4l2_pix_format vga_mode[] = {
124 {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
125 .bytesperline = 160,
126 .sizeimage = 160 * 120 * 3 / 8 + 590,
127 .colorspace = V4L2_COLORSPACE_JPEG,
128 .priv = 2},
129 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
130 .bytesperline = 320,
131 .sizeimage = 320 * 240 * 3 / 8 + 590,
132 .colorspace = V4L2_COLORSPACE_JPEG,
133 .priv = 1},
134 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
135 .bytesperline = 640,
136 .sizeimage = 640 * 480 * 3 / 8 + 590,
137 .colorspace = V4L2_COLORSPACE_JPEG,
138 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300139};
140
141#define PAC7311_JPEG_HEADER_SIZE (sizeof pac7311_jpeg_header) /* (594) */
142
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300143static const __u8 pac7311_jpeg_header[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300144 0xff, 0xd8,
145 0xff, 0xe0, 0x00, 0x03, 0x20,
146 0xff, 0xc0, 0x00, 0x11, 0x08,
147 0x01, 0xe0, /* 12: height */
148 0x02, 0x80, /* 14: width */
149 0x03, /* 16 */
150 0x01, 0x21, 0x00,
151 0x02, 0x11, 0x01,
152 0x03, 0x11, 0x01,
153 0xff, 0xdb, 0x00, 0x84,
154 0x00, 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, 0x0d,
155 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, 0x1a, 0x18, 0x16,
156 0x16, 0x18, 0x31, 0x23, 0x25, 0x1d, 0x28, 0x3a, 0x33, 0x3d,
157 0x3c, 0x39, 0x33, 0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40,
158 0x44, 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57, 0x5f,
159 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71, 0x79, 0x70, 0x64,
160 0x78, 0x5c, 0x65, 0x67, 0x63, 0x01, 0x11, 0x12, 0x12, 0x18,
161 0x15, 0x18, 0x2f, 0x1a, 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42,
162 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
163 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
164 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
165 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
166 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
167 0xff, 0xc4, 0x01, 0xa2, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01,
168 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
169 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
170 0x09, 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02,
171 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d,
172 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31,
173 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32,
174 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52,
175 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
176 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
177 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45,
178 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57,
179 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
180 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83,
181 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94,
182 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
183 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
184 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
185 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
186 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8,
187 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
188 0xf9, 0xfa, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01,
189 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
190 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
191 0x0b, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04,
192 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01,
193 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41,
194 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14,
195 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
196 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25,
197 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a,
198 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46,
199 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
200 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a,
201 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83,
202 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94,
203 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
204 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
205 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
206 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
207 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
208 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa,
209 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03,
210 0x11, 0x00, 0x3f, 0x00
211};
212
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300213/* pac 7302 */
214static const __u8 probe_7302[] = {
215/* index,value */
216 0xff, 0x01, /* page 1 */
217 0x78, 0x00, /* deactivate */
218 0xff, 0x01,
219 0x78, 0x40, /* led off */
220};
221static const __u8 start_7302[] = {
222/* index, len, [value]* */
223 0x00, 12, 0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80,
224 0x00, 0x00, 0x00, 0x00,
225 0x0d, 24, 0x03, 0x01, 0x00, 0xb5, 0x07, 0xcb, 0x00, 0x00,
226 0x07, 0xc8, 0x00, 0xea, 0x07, 0xcf, 0x07, 0xf7,
227 0x07, 0x7e, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x11,
228 0x26, 2, 0xaa, 0xaa,
229 0x2e, 1, 0x31,
230 0x38, 1, 0x01,
231 0x3a, 3, 0x14, 0xff, 0x5a,
232 0x43, 11, 0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11,
233 0x00, 0x54, 0x11,
234 0x55, 1, 0x00,
235 0x62, 4, 0x10, 0x1e, 0x1e, 0x18,
236 0x6b, 1, 0x00,
237 0x6e, 3, 0x08, 0x06, 0x00,
238 0x72, 3, 0x00, 0xff, 0x00,
239 0x7d, 23, 0x01, 0x01, 0x58, 0x46, 0x50, 0x3c, 0x50, 0x3c,
240 0x54, 0x46, 0x54, 0x56, 0x52, 0x50, 0x52, 0x50,
241 0x56, 0x64, 0xa4, 0x00, 0xda, 0x00, 0x00,
242 0xa2, 10, 0x22, 0x2c, 0x3c, 0x54, 0x69, 0x7c, 0x9c, 0xb9,
243 0xd2, 0xeb,
244 0xaf, 1, 0x02,
245 0xb5, 2, 0x08, 0x08,
246 0xb8, 2, 0x08, 0x88,
247 0xc4, 4, 0xae, 0x01, 0x04, 0x01,
248 0xcc, 1, 0x00,
249 0xd1, 11, 0x01, 0x30, 0x49, 0x5e, 0x6f, 0x7f, 0x8e, 0xa9,
250 0xc1, 0xd7, 0xec,
251 0xdc, 1, 0x01,
252 0xff, 1, 0x01,
253 0x12, 3, 0x02, 0x00, 0x01,
254 0x3e, 2, 0x00, 0x00,
255 0x76, 5, 0x01, 0x20, 0x40, 0x00, 0xf2,
256 0x7c, 1, 0x00,
257 0x7f, 10, 0x4b, 0x0f, 0x01, 0x2c, 0x02, 0x58, 0x03, 0x20,
258 0x02, 0x00,
259 0x96, 5, 0x01, 0x10, 0x04, 0x01, 0x04,
260 0xc8, 17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
261 0x07, 0x00, 0x01, 0x07, 0x04, 0x01,
262 0x01,
263 0xdb, 2, 0x00, 0x01,
264 0xde, 8, 0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x00,
265 0xe6, 4, 0x00, 0x00, 0x00, 0x01,
266 0xeb, 1, 0x00,
267 0xff, 1, 0x02,
268 0x22, 1, 0x00,
269 0xff, 1, 0x03,
270 0x00, 255, /* load the page 3 */
271 0x11, 1, 0x01,
272 0xff, 1, 0x02,
273 0x13, 1, 0x00,
274 0x22, 4, 0x1f, 0xa4, 0xf0, 0x96,
275 0x27, 2, 0x14, 0x0c,
276 0x2a, 5, 0xc8, 0x00, 0x18, 0x12, 0x22,
277 0x64, 8, 0x00, 0x00, 0xf0, 0x01, 0x14, 0x44, 0x44, 0x44,
278 0x6e, 1, 0x08,
279 0xff, 1, 0x03,
280 0x78, 1, 0x00,
281 0, 0 /* end of sequence */
282};
283
284/* page 3 - the value 0xaa says skip the index - see reg_w_page() */
285static const __u8 page3_7302[] = {
286 0x90, 0x40, 0x03, 0x50, 0xc2, 0x01, 0x14, 0x16,
287 0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00,
288 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
289 0x00, 0x00, 0x00, 0x47, 0x01, 0xb3, 0x01, 0x00,
290 0x00, 0x08, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x21,
291 0x00, 0x00, 0x00, 0x54, 0xf4, 0x02, 0x52, 0x54,
292 0xa4, 0xb8, 0xe0, 0x2a, 0xf6, 0x00, 0x00, 0x00,
293 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
294 0x00, 0xfc, 0x00, 0xf2, 0x1f, 0x04, 0x00, 0x00,
295 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x10, 0x00, 0x00,
296 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
297 0x00, 0x40, 0xff, 0x03, 0x19, 0x00, 0x00, 0x00,
298 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
299 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0xc8, 0xc8,
300 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,
301 0x08, 0x10, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00,
302 0x01, 0x00, 0x02, 0x47, 0x00, 0x00, 0x00, 0x00,
303 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
304 0x00, 0x02, 0xfa, 0x00, 0x64, 0x5a, 0x28, 0x00,
305 0x00
306};
307
308/* pac 7311 */
309static const __u8 probe_7311[] = {
310 0x78, 0x40, /* Bit_0=start stream, Bit_7=LED */
311 0x78, 0x40, /* Bit_0=start stream, Bit_7=LED */
312 0x78, 0x44, /* Bit_0=start stream, Bit_7=LED */
313 0xff, 0x04,
314 0x27, 0x80,
315 0x28, 0xca,
316 0x29, 0x53,
317 0x2a, 0x0e,
318 0xff, 0x01,
319 0x3e, 0x20,
320};
321
322static const __u8 start_7311[] = {
323/* index, len, [value]* */
324 0xff, 1, 0x01,
325 0x02, 53, 0x48, 0x0a, 0x40, 0x08, 0x00, 0x00, 0x08, 0x00,
326 0x06, 0xff, 0x11, 0xff, 0x5a, 0x30, 0x90, 0x4c,
327 0x00, 0x07, 0x00, 0x0a, 0x10, 0x00, 0xa0, 0x10,
328 0x02, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x01, 0x00,
329 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
330 0x00, 0x00, 0x00,
331 0x3e, 52, 0x00, 0x00, 0x78, 0x52, 0x4a, 0x52, 0x78, 0x6e,
332 0x48, 0x46, 0x48, 0x6e, 0x5f, 0x49, 0x42, 0x49,
333 0x5f, 0x5f, 0x49, 0x42, 0x49, 0x5f, 0x6e, 0x48,
334 0x46, 0x48, 0x6e, 0x78, 0x52, 0x4a, 0x52, 0x78,
335 0x00, 0x00, 0x09, 0x1b, 0x34, 0x49, 0x5c, 0x9b,
336 0xd0, 0xff,
337 0x78, 6, 0x44, 0x00, 0xf2, 0x01, 0x01, 0x80,
338 0x7f, 18, 0x2a, 0x1c, 0x00, 0xc8, 0x02, 0x58, 0x03, 0x84,
339 0x12, 0x00, 0x1a, 0x04, 0x08, 0x0c, 0x10, 0x14,
340 0x18, 0x20,
341 0x96, 3, 0x01, 0x08, 0x04,
342 0xa0, 4, 0x44, 0x44, 0x44, 0x04,
343 0xf0, 13, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x20, 0x00,
344 0x3f, 0x00, 0x0a, 0x01, 0x00,
345 0xff, 1, 0x04,
346 0x00, 254, /* load the page 4 */
347 0x11, 1, 0x01,
348 0, 0 /* end of sequence */
349};
350
351/* page 4 - the value 0xaa says skip the index - see reg_w_page() */
352static const __u8 page4_7311[] = {
353 0xaa, 0xaa, 0x04, 0x54, 0x07, 0x2b, 0x09, 0x0f,
354 0x09, 0x00, 0xaa, 0xaa, 0x07, 0x00, 0x00, 0x62,
355 0x08, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
356 0x00, 0x00, 0x00, 0x03, 0xa0, 0x01, 0xf4, 0xaa,
357 0xaa, 0x00, 0x08, 0xaa, 0x03, 0xaa, 0x00, 0x01,
358 0xca, 0x10, 0x06, 0x78, 0x00, 0x00, 0x00, 0x00,
359 0x23, 0x28, 0x04, 0x11, 0x00, 0x00
360};
361
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300362static void reg_w_buf(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300363 __u8 index,
364 const char *buffer, int len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300365{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300366 memcpy(gspca_dev->usb_buf, buffer, len);
367 usb_control_msg(gspca_dev->dev,
368 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300369 1, /* request */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300370 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300371 0, /* value */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300372 index, gspca_dev->usb_buf, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300373 500);
374}
375
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300376static __u8 reg_r(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300377 __u8 index)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300378{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300379 usb_control_msg(gspca_dev->dev,
380 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300381 0, /* request */
382 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
383 0, /* value */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300384 index, gspca_dev->usb_buf, 1,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300385 500);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300386 return gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300387}
388
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300389static void reg_w(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300390 __u8 index,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300391 __u8 value)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300392{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300393 gspca_dev->usb_buf[0] = value;
394 usb_control_msg(gspca_dev->dev,
395 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300396 0, /* request */
397 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300398 value, index, gspca_dev->usb_buf, 1,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300399 500);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300400}
401
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300402static void reg_w_seq(struct gspca_dev *gspca_dev,
403 const __u8 *seq, int len)
404{
405 while (--len >= 0) {
406 reg_w(gspca_dev, seq[0], seq[1]);
407 seq += 2;
408 }
409}
410
411/* load the beginning of a page */
412static void reg_w_page(struct gspca_dev *gspca_dev,
413 const __u8 *page, int len)
414{
415 int index;
416
417 for (index = 0; index < len; index++) {
418 if (page[index] == 0xaa) /* skip this index */
419 continue;
420 gspca_dev->usb_buf[0] = page[index];
421 usb_control_msg(gspca_dev->dev,
422 usb_sndctrlpipe(gspca_dev->dev, 0),
423 0, /* request */
424 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
425 0, index, gspca_dev->usb_buf, 1,
426 500);
427 }
428}
429
430/* output a variable sequence */
431static void reg_w_var(struct gspca_dev *gspca_dev,
432 const __u8 *seq)
433{
434 int index, len;
435
436 for (;;) {
437 index = *seq++;
438 len = *seq++;
439 switch (len) {
440 case 0:
441 return;
442 case 254:
443 reg_w_page(gspca_dev, page4_7311, sizeof page4_7311);
444 break;
445 case 255:
446 reg_w_page(gspca_dev, page3_7302, sizeof page3_7302);
447 break;
448 default:
449 if (len > 32) {
450 PDEBUG(D_ERR|D_STREAM,
451 "Incorrect variable sequence");
452 return;
453 }
454 while (len > 0) {
455 if (len < 8) {
456 reg_w_buf(gspca_dev, index, seq, len);
457 seq += len;
458 break;
459 }
460 reg_w_buf(gspca_dev, index, seq, 8);
461 seq += 8;
462 index += 8;
463 len -= 8;
464 }
465 }
466 }
467 /* not reached */
468}
469
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300470/* this function is called at probe time */
471static int sd_config(struct gspca_dev *gspca_dev,
472 const struct usb_device_id *id)
473{
474 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300475 struct cam *cam;
476
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300477 cam = &gspca_dev->cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300478 cam->epaddr = 0x05;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300479
480 sd->sensor = id->driver_info;
481 if (sd->sensor == SENSOR_PAC7302) {
482 PDEBUG(D_CONF, "Find Sensor PAC7302");
483 reg_w_seq(gspca_dev, probe_7302, sizeof probe_7302);
484
485 cam->cam_mode = &vga_mode[2]; /* only 640x480 */
486 cam->nmodes = 1;
487 } else {
488 PDEBUG(D_CONF, "Find Sensor PAC7311");
489 reg_w_seq(gspca_dev, probe_7302, sizeof probe_7302);
490
491 cam->cam_mode = vga_mode;
492 cam->nmodes = ARRAY_SIZE(vga_mode);
493 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300494
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300495 sd->brightness = BRIGHTNESS_DEF;
496 sd->contrast = CONTRAST_DEF;
497 sd->colors = COLOR_DEF;
498 sd->autogain = AUTOGAIN_DEF;
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300499 sd->ag_cnt = -1;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300500 return 0;
501}
502
503static void setbrightness(struct gspca_dev *gspca_dev)
504{
505 struct sd *sd = (struct sd *) gspca_dev;
506 int brightness;
507
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300508 if (sd->sensor == SENSOR_PAC7302)
509 return;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300510/*jfm: inverted?*/
511 brightness = BRIGHTNESS_MAX - sd->brightness;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300512 reg_w(gspca_dev, 0xff, 0x04);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300513 reg_w(gspca_dev, 0x0f, brightness);
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 PDEBUG(D_CONF|D_STREAM, "brightness: %i", brightness);
517}
518
519static void setcontrast(struct gspca_dev *gspca_dev)
520{
521 struct sd *sd = (struct sd *) gspca_dev;
522
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300523 if (sd->sensor == SENSOR_PAC7302)
524 return;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300525 reg_w(gspca_dev, 0xff, 0x01);
526 reg_w(gspca_dev, 0x80, sd->contrast);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300527 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300528 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300529 PDEBUG(D_CONF|D_STREAM, "contrast: %i", sd->contrast);
530}
531
532static void setcolors(struct gspca_dev *gspca_dev)
533{
534 struct sd *sd = (struct sd *) gspca_dev;
535
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300536 if (sd->sensor == SENSOR_PAC7302)
537 return;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300538 reg_w(gspca_dev, 0xff, 0x01);
539 reg_w(gspca_dev, 0x10, sd->colors);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300540 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300541 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300542 PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
543}
544
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300545static void setautogain(struct gspca_dev *gspca_dev)
546{
547 struct sd *sd = (struct sd *) gspca_dev;
548
549 if (sd->autogain) {
550 sd->lum_sum = 0;
551 sd->ag_cnt = AG_CNT_START;
552 } else {
553 sd->ag_cnt = -1;
554 }
555}
556
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300557/* this function is called at open time */
558static int sd_open(struct gspca_dev *gspca_dev)
559{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300560 reg_w(gspca_dev, 0x78, 0x00); /* Turn on LED */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300561 return 0;
562}
563
564static void sd_start(struct gspca_dev *gspca_dev)
565{
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300566 struct sd *sd = (struct sd *) gspca_dev;
567
568 sd->ffnb = 0;
569 sd->tosof = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300570
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300571 if (sd->sensor == SENSOR_PAC7302)
572 reg_w_var(gspca_dev, start_7302);
573 else
574 reg_w_var(gspca_dev, start_7311);
575
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300576 setcontrast(gspca_dev);
577 setbrightness(gspca_dev);
578 setcolors(gspca_dev);
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300579 setautogain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300580
581 /* set correct resolution */
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300582 switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300583 case 2: /* 160x120 pac7311 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300584 reg_w(gspca_dev, 0xff, 0x04);
585 reg_w(gspca_dev, 0x02, 0x03);
586 reg_w(gspca_dev, 0xff, 0x01);
587 reg_w(gspca_dev, 0x08, 0x09);
588 reg_w(gspca_dev, 0x17, 0x20);
589 reg_w(gspca_dev, 0x1b, 0x00);
590/* reg_w(gspca_dev, 0x80, 0x69); */
591 reg_w(gspca_dev, 0x87, 0x10);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300592 break;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300593 case 1: /* 320x240 pac7311 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300594 reg_w(gspca_dev, 0xff, 0x04);
595 reg_w(gspca_dev, 0x02, 0x03);
596 reg_w(gspca_dev, 0xff, 0x01);
597 reg_w(gspca_dev, 0x08, 0x09);
598 reg_w(gspca_dev, 0x17, 0x30);
599/* reg_w(gspca_dev, 0x80, 0x3f); */
600 reg_w(gspca_dev, 0x87, 0x11);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300601 break;
602 case 0: /* 640x480 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300603 if (sd->sensor == SENSOR_PAC7302)
604 break;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300605 reg_w(gspca_dev, 0xff, 0x04);
606 reg_w(gspca_dev, 0x02, 0x03);
607 reg_w(gspca_dev, 0xff, 0x01);
608 reg_w(gspca_dev, 0x08, 0x08);
609 reg_w(gspca_dev, 0x17, 0x00);
610/* reg_w(gspca_dev, 0x80, 0x1c); */
611 reg_w(gspca_dev, 0x87, 0x12);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300612 break;
613 }
614
615 /* start stream */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300616 reg_w(gspca_dev, 0xff, 0x01);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300617 if (sd->sensor == SENSOR_PAC7302) {
618 reg_w(gspca_dev, 0x78, 0x01);
619 reg_w(gspca_dev, 0xff, 0x01);
620 reg_w(gspca_dev, 0x78, 0x01);
621 } else {
622 reg_w(gspca_dev, 0x78, 0x04);
623 reg_w(gspca_dev, 0x78, 0x05);
624 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300625}
626
627static void sd_stopN(struct gspca_dev *gspca_dev)
628{
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300629 struct sd *sd = (struct sd *) gspca_dev;
630
631 if (sd->sensor == SENSOR_PAC7302) {
632 reg_w(gspca_dev, 0x78, 0x00);
633 reg_w(gspca_dev, 0x78, 0x00);
634 return;
635 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300636 reg_w(gspca_dev, 0xff, 0x04);
637 reg_w(gspca_dev, 0x27, 0x80);
638 reg_w(gspca_dev, 0x28, 0xca);
639 reg_w(gspca_dev, 0x29, 0x53);
640 reg_w(gspca_dev, 0x2a, 0x0e);
641 reg_w(gspca_dev, 0xff, 0x01);
642 reg_w(gspca_dev, 0x3e, 0x20);
643 reg_w(gspca_dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */
644 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
645 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300646}
647
648static void sd_stop0(struct gspca_dev *gspca_dev)
649{
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300650 struct sd *sd = (struct sd *) gspca_dev;
651
652 if (sd->sensor == SENSOR_PAC7302) {
653 reg_w(gspca_dev, 0xff, 0x01);
654 reg_w(gspca_dev, 0x78, 0x40);
655 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300656}
657
658/* this function is called at close time */
659static void sd_close(struct gspca_dev *gspca_dev)
660{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300661}
662
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300663static void do_autogain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300664{
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300665 struct sd *sd = (struct sd *) gspca_dev;
666 int luma;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300667 int luma_mean = 128;
668 int luma_delta = 20;
669 __u8 spring = 5;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300670 int Gbright;
671
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300672 if (!atomic_read(&sd->do_gain))
673 return;
674 atomic_set(&sd->do_gain, 0);
675
676 luma = atomic_read(&sd->avg_lum);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300677 Gbright = reg_r(gspca_dev, 0x02);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300678 PDEBUG(D_FRAM, "luma mean %d", luma);
679 if (luma < luma_mean - luma_delta ||
680 luma > luma_mean + luma_delta) {
681 Gbright += (luma_mean - luma) >> spring;
682 if (Gbright > 0x1a)
683 Gbright = 0x1a;
684 else if (Gbright < 4)
685 Gbright = 4;
686 PDEBUG(D_FRAM, "gbright %d", Gbright);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300687 if (sd->sensor == SENSOR_PAC7302) {
688 reg_w(gspca_dev, 0xff, 0x03);
689 reg_w(gspca_dev, 0x10, Gbright);
690 /* load registers to sensor (Bit 0, auto clear) */
691 reg_w(gspca_dev, 0x11, 0x01);
692 } else {
693 reg_w(gspca_dev, 0xff, 0x04);
694 reg_w(gspca_dev, 0x0f, Gbright);
695 /* load registers to sensor (Bit 0, auto clear) */
696 reg_w(gspca_dev, 0x11, 0x01);
697 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300698 }
699}
700
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300701/* output the jpeg header */
702static void put_jpeg_head(struct gspca_dev *gspca_dev,
703 struct gspca_frame *frame)
704{
705 unsigned char tmpbuf[4];
706
707 gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
708 (__u8 *) pac7311_jpeg_header,
709 12);
710 tmpbuf[0] = gspca_dev->height >> 8;
711 tmpbuf[1] = gspca_dev->height & 0xff;
712 tmpbuf[2] = gspca_dev->width >> 8;
713 tmpbuf[3] = gspca_dev->width & 0xff;
714 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
715 tmpbuf, 4);
716 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
717 (__u8 *) &pac7311_jpeg_header[16],
718 PAC7311_JPEG_HEADER_SIZE - 16);
719}
720
721/* this function is run at interrupt level */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300722static void sd_pkt_scan(struct gspca_dev *gspca_dev,
723 struct gspca_frame *frame, /* target */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300724 __u8 *data, /* isoc packet */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300725 int len) /* iso packet length */
726{
727 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300728 int i;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300729
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300730#define INTER_FRAME 0x53
731#define LUM_OFFSET 0x1e /* reverse offset / start of frame */
732
733 /*
734 * inside a frame, there may be:
735 * escaped ff ('ff 00')
736 * sequences'ff ff ff xx' to remove
737 * end of frame ('ff d9')
738 * at the end of frame, there are:
739 * ff d9 end of frame
740 * 0x33 bytes
741 * one byte luminosity
742 * 0x16 bytes
743 * ff ff 00 ff 96 62 44 start of frame header
744 */
745
746 if (sd->tosof == 0) { /* if inside a frame */
747
748 /* check for 'ff ff ff xx' at start and at end of packet */
749 /* (len is always >= 3) */
750 switch (sd->ffnb) {
751 case 1:
752 if (data[0] != 0xff)
753 break; /* keep 'ff 00' */
754 /* fall thru */
755 case 2:
756 case 3:
757 data += 4 - sd->ffnb;
758 len -= 4 - sd->ffnb;
759 sd->ffnb = 0;
760 break;
761 }
762 if (data[len - 1] == 0xff) {
763 if (data[len - 2] == 0xff) {
764 if (data[len - 3] == 0xff) {
765 sd->ffnb = 3;
766 len -= 3;
767 } else {
768 sd->ffnb = 2;
769 len -= 2;
770 }
771 } else {
772 sd->ffnb = 1;
773 len--;
774 }
775 }
776 } else { /* outside a frame */
777
778 /*
779 * get the luminosity
780 * and go to the start of frame
781 */
782 data += sd->tosof;
783 len -= sd->tosof;
784 if (sd->tosof > LUM_OFFSET)
785 sd->lum_sum += data[-LUM_OFFSET];
786 put_jpeg_head(gspca_dev, frame);
787 sd->tosof = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300788 }
789
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300790 for (i = 0; i < len; i++) {
791 if (data[i] != 0xff)
792 continue;
793 switch (data[i + 1]) {
794 case 0xd9: /* end of frame */
Jean-Francois Moine23d9e472008-09-03 16:47:22 -0300795 i += 2;
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300796 frame = gspca_frame_add(gspca_dev,
797 LAST_PACKET,
Jean-Francois Moine23d9e472008-09-03 16:47:22 -0300798 frame, data, i);
799 data += i + INTER_FRAME;
800 len -= i + INTER_FRAME;
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300801 i = 0;
Jean-Francois Moine23d9e472008-09-03 16:47:22 -0300802 if (len > -LUM_OFFSET)
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300803 sd->lum_sum += data[-LUM_OFFSET];
804 if (len < 0) {
805 sd->tosof = -len;
806 break;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300807 }
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300808 put_jpeg_head(gspca_dev, frame);
809 break;
810 case 0xff: /* 'ff ff ff xx' */
811 gspca_frame_add(gspca_dev, INTER_PACKET,
812 frame, data, i);
813 data += i + 4;
814 len -= i + 4;
815 i = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300816 break;
817 }
818 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300819}
820
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300821static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
822{
823 struct sd *sd = (struct sd *) gspca_dev;
824
825 sd->brightness = val;
826 if (gspca_dev->streaming)
827 setbrightness(gspca_dev);
828 return 0;
829}
830
831static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
832{
833 struct sd *sd = (struct sd *) gspca_dev;
834
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300835 *val = sd->brightness;
836 return 0;
837}
838
839static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
840{
841 struct sd *sd = (struct sd *) gspca_dev;
842
843 sd->contrast = val;
844 if (gspca_dev->streaming)
845 setcontrast(gspca_dev);
846 return 0;
847}
848
849static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
850{
851 struct sd *sd = (struct sd *) gspca_dev;
852
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300853 *val = sd->contrast;
854 return 0;
855}
856
857static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
858{
859 struct sd *sd = (struct sd *) gspca_dev;
860
861 sd->colors = val;
862 if (gspca_dev->streaming)
863 setcolors(gspca_dev);
864 return 0;
865}
866
867static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
868{
869 struct sd *sd = (struct sd *) gspca_dev;
870
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300871 *val = sd->colors;
872 return 0;
873}
874
875static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
876{
877 struct sd *sd = (struct sd *) gspca_dev;
878
879 sd->autogain = val;
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300880 if (gspca_dev->streaming)
881 setautogain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300882 return 0;
883}
884
885static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
886{
887 struct sd *sd = (struct sd *) gspca_dev;
888
889 *val = sd->autogain;
890 return 0;
891}
892
893/* sub-driver description */
894static struct sd_desc sd_desc = {
895 .name = MODULE_NAME,
896 .ctrls = sd_ctrls,
897 .nctrls = ARRAY_SIZE(sd_ctrls),
898 .config = sd_config,
899 .open = sd_open,
900 .start = sd_start,
901 .stopN = sd_stopN,
902 .stop0 = sd_stop0,
903 .close = sd_close,
904 .pkt_scan = sd_pkt_scan,
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300905 .dq_callback = do_autogain,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300906};
907
908/* -- module initialisation -- */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300909static __devinitdata struct usb_device_id device_table[] = {
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300910 {USB_DEVICE(0x093a, 0x2600), .driver_info = SENSOR_PAC7311},
911 {USB_DEVICE(0x093a, 0x2601), .driver_info = SENSOR_PAC7311},
912 {USB_DEVICE(0x093a, 0x2603), .driver_info = SENSOR_PAC7311},
913 {USB_DEVICE(0x093a, 0x2608), .driver_info = SENSOR_PAC7311},
914 {USB_DEVICE(0x093a, 0x260e), .driver_info = SENSOR_PAC7311},
915 {USB_DEVICE(0x093a, 0x260f), .driver_info = SENSOR_PAC7311},
916 {USB_DEVICE(0x093a, 0x2621), .driver_info = SENSOR_PAC7302},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300917 {}
918};
919MODULE_DEVICE_TABLE(usb, device_table);
920
921/* -- device connect -- */
922static int sd_probe(struct usb_interface *intf,
923 const struct usb_device_id *id)
924{
925 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
926 THIS_MODULE);
927}
928
929static struct usb_driver sd_driver = {
930 .name = MODULE_NAME,
931 .id_table = device_table,
932 .probe = sd_probe,
933 .disconnect = gspca_disconnect,
934};
935
936/* -- module insert / remove -- */
937static int __init sd_mod_init(void)
938{
939 if (usb_register(&sd_driver) < 0)
940 return -1;
Jean-Francois Moine10b0e962008-07-22 05:35:10 -0300941 PDEBUG(D_PROBE, "registered");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300942 return 0;
943}
944static void __exit sd_mod_exit(void)
945{
946 usb_deregister(&sd_driver);
947 PDEBUG(D_PROBE, "deregistered");
948}
949
950module_init(sd_mod_init);
951module_exit(sd_mod_exit);