blob: a89cc9fd153158103731622528747f94cd3fedf5 [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"
Jean-Francois Moinef75c4952008-09-03 16:47:35 -030025#include "jpeg.h"
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030026
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030027MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li");
28MODULE_DESCRIPTION("Pixart PAC7311");
29MODULE_LICENSE("GPL");
30
31/* specific webcam descriptor */
32struct sd {
33 struct gspca_dev gspca_dev; /* !! must be the first item */
34
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -030035 int lum_sum;
36 atomic_t avg_lum;
37 atomic_t do_gain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030038
39 unsigned char brightness;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030040 unsigned char contrast;
41 unsigned char colors;
42 unsigned char autogain;
Jean-Francois Moine41b46972008-09-03 16:47:58 -030043 __u8 hflip;
44 __u8 vflip;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030045
Jean-Francois Moinee52a5572008-09-03 16:47:21 -030046 char tosof; /* number of bytes before next start of frame */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030047 signed char ag_cnt;
48#define AG_CNT_START 13
Jean-Francois Moine49b57db2008-09-03 16:47:25 -030049
50 __u8 sensor;
51#define SENSOR_PAC7302 0
52#define SENSOR_PAC7311 1
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030053};
54
55/* V4L2 controls supported by the driver */
56static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
57static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
58static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
59static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
60static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
61static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
62static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
63static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
Jean-Francois Moine41b46972008-09-03 16:47:58 -030064static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val);
65static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val);
66static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
67static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030068
69static struct ctrl sd_ctrls[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030070 {
71 {
72 .id = V4L2_CID_BRIGHTNESS,
73 .type = V4L2_CTRL_TYPE_INTEGER,
74 .name = "Brightness",
75 .minimum = 0,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -030076#define BRIGHTNESS_MAX 0x20
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030077 .maximum = BRIGHTNESS_MAX,
78 .step = 1,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -030079#define BRIGHTNESS_DEF 0x10
80 .default_value = BRIGHTNESS_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030081 },
82 .set = sd_setbrightness,
83 .get = sd_getbrightness,
84 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030085 {
86 {
87 .id = V4L2_CID_CONTRAST,
88 .type = V4L2_CTRL_TYPE_INTEGER,
89 .name = "Contrast",
90 .minimum = 0,
Jean-Francois Moinedff6d322008-09-03 16:47:57 -030091#define CONTRAST_MAX 255
92 .maximum = CONTRAST_MAX,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030093 .step = 1,
Jean-Francois Moinedff6d322008-09-03 16:47:57 -030094#define CONTRAST_DEF 60
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -030095 .default_value = CONTRAST_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030096 },
97 .set = sd_setcontrast,
98 .get = sd_getcontrast,
99 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300100 {
101 {
102 .id = V4L2_CID_SATURATION,
103 .type = V4L2_CTRL_TYPE_INTEGER,
Jean-Francois Moinedff6d322008-09-03 16:47:57 -0300104 .name = "Saturation",
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300105 .minimum = 0,
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300106#define COLOR_MAX 255
107 .maximum = COLOR_MAX,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300108 .step = 1,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300109#define COLOR_DEF 127
110 .default_value = COLOR_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300111 },
112 .set = sd_setcolors,
113 .get = sd_getcolors,
114 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300115 {
116 {
117 .id = V4L2_CID_AUTOGAIN,
118 .type = V4L2_CTRL_TYPE_BOOLEAN,
119 .name = "Auto Gain",
120 .minimum = 0,
121 .maximum = 1,
122 .step = 1,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300123#define AUTOGAIN_DEF 1
124 .default_value = AUTOGAIN_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300125 },
126 .set = sd_setautogain,
127 .get = sd_getautogain,
128 },
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300129/* next controls work with pac7302 only */
130 {
131 {
132 .id = V4L2_CID_HFLIP,
133 .type = V4L2_CTRL_TYPE_BOOLEAN,
134 .name = "Mirror",
135 .minimum = 0,
136 .maximum = 1,
137 .step = 1,
138#define HFLIP_DEF 0
139 .default_value = HFLIP_DEF,
140 },
141 .set = sd_sethflip,
142 .get = sd_gethflip,
143 },
144 {
145 {
146 .id = V4L2_CID_VFLIP,
147 .type = V4L2_CTRL_TYPE_BOOLEAN,
148 .name = "Vflip",
149 .minimum = 0,
150 .maximum = 1,
151 .step = 1,
152#define VFLIP_DEF 0
153 .default_value = VFLIP_DEF,
154 },
155 .set = sd_setvflip,
156 .get = sd_getvflip,
157 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300158};
159
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300160static struct v4l2_pix_format vga_mode[] = {
Jean-Francois Moinef75c4952008-09-03 16:47:35 -0300161 {160, 120, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300162 .bytesperline = 160,
163 .sizeimage = 160 * 120 * 3 / 8 + 590,
164 .colorspace = V4L2_COLORSPACE_JPEG,
165 .priv = 2},
Jean-Francois Moinef75c4952008-09-03 16:47:35 -0300166 {320, 240, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300167 .bytesperline = 320,
168 .sizeimage = 320 * 240 * 3 / 8 + 590,
169 .colorspace = V4L2_COLORSPACE_JPEG,
170 .priv = 1},
Jean-Francois Moinef75c4952008-09-03 16:47:35 -0300171 {640, 480, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300172 .bytesperline = 640,
173 .sizeimage = 640 * 480 * 3 / 8 + 590,
174 .colorspace = V4L2_COLORSPACE_JPEG,
175 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300176};
177
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300178/* pac 7302 */
179static const __u8 probe_7302[] = {
180/* index,value */
181 0xff, 0x01, /* page 1 */
182 0x78, 0x00, /* deactivate */
183 0xff, 0x01,
184 0x78, 0x40, /* led off */
185};
186static const __u8 start_7302[] = {
187/* index, len, [value]* */
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300188 0xff, 1, 0x00, /* page 0 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300189 0x00, 12, 0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80,
190 0x00, 0x00, 0x00, 0x00,
191 0x0d, 24, 0x03, 0x01, 0x00, 0xb5, 0x07, 0xcb, 0x00, 0x00,
192 0x07, 0xc8, 0x00, 0xea, 0x07, 0xcf, 0x07, 0xf7,
193 0x07, 0x7e, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x11,
194 0x26, 2, 0xaa, 0xaa,
195 0x2e, 1, 0x31,
196 0x38, 1, 0x01,
197 0x3a, 3, 0x14, 0xff, 0x5a,
198 0x43, 11, 0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11,
199 0x00, 0x54, 0x11,
200 0x55, 1, 0x00,
201 0x62, 4, 0x10, 0x1e, 0x1e, 0x18,
202 0x6b, 1, 0x00,
203 0x6e, 3, 0x08, 0x06, 0x00,
204 0x72, 3, 0x00, 0xff, 0x00,
205 0x7d, 23, 0x01, 0x01, 0x58, 0x46, 0x50, 0x3c, 0x50, 0x3c,
206 0x54, 0x46, 0x54, 0x56, 0x52, 0x50, 0x52, 0x50,
207 0x56, 0x64, 0xa4, 0x00, 0xda, 0x00, 0x00,
208 0xa2, 10, 0x22, 0x2c, 0x3c, 0x54, 0x69, 0x7c, 0x9c, 0xb9,
209 0xd2, 0xeb,
210 0xaf, 1, 0x02,
211 0xb5, 2, 0x08, 0x08,
212 0xb8, 2, 0x08, 0x88,
213 0xc4, 4, 0xae, 0x01, 0x04, 0x01,
214 0xcc, 1, 0x00,
215 0xd1, 11, 0x01, 0x30, 0x49, 0x5e, 0x6f, 0x7f, 0x8e, 0xa9,
216 0xc1, 0xd7, 0xec,
217 0xdc, 1, 0x01,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300218 0xff, 1, 0x01, /* page 1 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300219 0x12, 3, 0x02, 0x00, 0x01,
220 0x3e, 2, 0x00, 0x00,
221 0x76, 5, 0x01, 0x20, 0x40, 0x00, 0xf2,
222 0x7c, 1, 0x00,
223 0x7f, 10, 0x4b, 0x0f, 0x01, 0x2c, 0x02, 0x58, 0x03, 0x20,
224 0x02, 0x00,
225 0x96, 5, 0x01, 0x10, 0x04, 0x01, 0x04,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300226 0xc8, 14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300227 0x07, 0x00, 0x01, 0x07, 0x04, 0x01,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300228 0xd8, 1, 0x01,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300229 0xdb, 2, 0x00, 0x01,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300230 0xde, 7, 0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x00,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300231 0xe6, 4, 0x00, 0x00, 0x00, 0x01,
232 0xeb, 1, 0x00,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300233 0xff, 1, 0x02, /* page 2 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300234 0x22, 1, 0x00,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300235 0xff, 1, 0x03, /* page 3 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300236 0x00, 255, /* load the page 3 */
237 0x11, 1, 0x01,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300238 0xff, 1, 0x02, /* page 2 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300239 0x13, 1, 0x00,
240 0x22, 4, 0x1f, 0xa4, 0xf0, 0x96,
241 0x27, 2, 0x14, 0x0c,
242 0x2a, 5, 0xc8, 0x00, 0x18, 0x12, 0x22,
243 0x64, 8, 0x00, 0x00, 0xf0, 0x01, 0x14, 0x44, 0x44, 0x44,
244 0x6e, 1, 0x08,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300245 0xff, 1, 0x03, /* page 1 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300246 0x78, 1, 0x00,
247 0, 0 /* end of sequence */
248};
249
250/* page 3 - the value 0xaa says skip the index - see reg_w_page() */
251static const __u8 page3_7302[] = {
252 0x90, 0x40, 0x03, 0x50, 0xc2, 0x01, 0x14, 0x16,
253 0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00,
254 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
255 0x00, 0x00, 0x00, 0x47, 0x01, 0xb3, 0x01, 0x00,
256 0x00, 0x08, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x21,
257 0x00, 0x00, 0x00, 0x54, 0xf4, 0x02, 0x52, 0x54,
258 0xa4, 0xb8, 0xe0, 0x2a, 0xf6, 0x00, 0x00, 0x00,
259 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
260 0x00, 0xfc, 0x00, 0xf2, 0x1f, 0x04, 0x00, 0x00,
261 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x10, 0x00, 0x00,
262 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
263 0x00, 0x40, 0xff, 0x03, 0x19, 0x00, 0x00, 0x00,
264 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
265 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0xc8, 0xc8,
266 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,
267 0x08, 0x10, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00,
268 0x01, 0x00, 0x02, 0x47, 0x00, 0x00, 0x00, 0x00,
269 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
270 0x00, 0x02, 0xfa, 0x00, 0x64, 0x5a, 0x28, 0x00,
271 0x00
272};
273
274/* pac 7311 */
275static const __u8 probe_7311[] = {
276 0x78, 0x40, /* Bit_0=start stream, Bit_7=LED */
277 0x78, 0x40, /* Bit_0=start stream, Bit_7=LED */
278 0x78, 0x44, /* Bit_0=start stream, Bit_7=LED */
279 0xff, 0x04,
280 0x27, 0x80,
281 0x28, 0xca,
282 0x29, 0x53,
283 0x2a, 0x0e,
284 0xff, 0x01,
285 0x3e, 0x20,
286};
287
288static const __u8 start_7311[] = {
289/* index, len, [value]* */
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300290 0xff, 1, 0x01, /* page 1 */
291 0x02, 43, 0x48, 0x0a, 0x40, 0x08, 0x00, 0x00, 0x08, 0x00,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300292 0x06, 0xff, 0x11, 0xff, 0x5a, 0x30, 0x90, 0x4c,
293 0x00, 0x07, 0x00, 0x0a, 0x10, 0x00, 0xa0, 0x10,
294 0x02, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x01, 0x00,
295 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
296 0x00, 0x00, 0x00,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300297 0x3e, 42, 0x00, 0x00, 0x78, 0x52, 0x4a, 0x52, 0x78, 0x6e,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300298 0x48, 0x46, 0x48, 0x6e, 0x5f, 0x49, 0x42, 0x49,
299 0x5f, 0x5f, 0x49, 0x42, 0x49, 0x5f, 0x6e, 0x48,
300 0x46, 0x48, 0x6e, 0x78, 0x52, 0x4a, 0x52, 0x78,
301 0x00, 0x00, 0x09, 0x1b, 0x34, 0x49, 0x5c, 0x9b,
302 0xd0, 0xff,
303 0x78, 6, 0x44, 0x00, 0xf2, 0x01, 0x01, 0x80,
304 0x7f, 18, 0x2a, 0x1c, 0x00, 0xc8, 0x02, 0x58, 0x03, 0x84,
305 0x12, 0x00, 0x1a, 0x04, 0x08, 0x0c, 0x10, 0x14,
306 0x18, 0x20,
307 0x96, 3, 0x01, 0x08, 0x04,
308 0xa0, 4, 0x44, 0x44, 0x44, 0x04,
309 0xf0, 13, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x20, 0x00,
310 0x3f, 0x00, 0x0a, 0x01, 0x00,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300311 0xff, 1, 0x04, /* page 4 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300312 0x00, 254, /* load the page 4 */
313 0x11, 1, 0x01,
314 0, 0 /* end of sequence */
315};
316
317/* page 4 - the value 0xaa says skip the index - see reg_w_page() */
318static const __u8 page4_7311[] = {
319 0xaa, 0xaa, 0x04, 0x54, 0x07, 0x2b, 0x09, 0x0f,
320 0x09, 0x00, 0xaa, 0xaa, 0x07, 0x00, 0x00, 0x62,
321 0x08, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
322 0x00, 0x00, 0x00, 0x03, 0xa0, 0x01, 0xf4, 0xaa,
323 0xaa, 0x00, 0x08, 0xaa, 0x03, 0xaa, 0x00, 0x01,
324 0xca, 0x10, 0x06, 0x78, 0x00, 0x00, 0x00, 0x00,
325 0x23, 0x28, 0x04, 0x11, 0x00, 0x00
326};
327
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300328static void reg_w_buf(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300329 __u8 index,
330 const char *buffer, int len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300331{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300332 memcpy(gspca_dev->usb_buf, buffer, len);
333 usb_control_msg(gspca_dev->dev,
334 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300335 1, /* request */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300336 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300337 0, /* value */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300338 index, gspca_dev->usb_buf, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300339 500);
340}
341
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300342static __u8 reg_r(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300343 __u8 index)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300344{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300345 usb_control_msg(gspca_dev->dev,
346 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300347 0, /* request */
348 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
349 0, /* value */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300350 index, gspca_dev->usb_buf, 1,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300351 500);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300352 return gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300353}
354
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300355static void reg_w(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300356 __u8 index,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300357 __u8 value)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300358{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300359 gspca_dev->usb_buf[0] = value;
360 usb_control_msg(gspca_dev->dev,
361 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300362 0, /* request */
363 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300364 value, index, gspca_dev->usb_buf, 1,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300365 500);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300366}
367
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300368static void reg_w_seq(struct gspca_dev *gspca_dev,
369 const __u8 *seq, int len)
370{
371 while (--len >= 0) {
372 reg_w(gspca_dev, seq[0], seq[1]);
373 seq += 2;
374 }
375}
376
377/* load the beginning of a page */
378static void reg_w_page(struct gspca_dev *gspca_dev,
379 const __u8 *page, int len)
380{
381 int index;
382
383 for (index = 0; index < len; index++) {
384 if (page[index] == 0xaa) /* skip this index */
385 continue;
386 gspca_dev->usb_buf[0] = page[index];
387 usb_control_msg(gspca_dev->dev,
388 usb_sndctrlpipe(gspca_dev->dev, 0),
389 0, /* request */
390 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
391 0, index, gspca_dev->usb_buf, 1,
392 500);
393 }
394}
395
396/* output a variable sequence */
397static void reg_w_var(struct gspca_dev *gspca_dev,
398 const __u8 *seq)
399{
400 int index, len;
401
402 for (;;) {
403 index = *seq++;
404 len = *seq++;
405 switch (len) {
406 case 0:
407 return;
408 case 254:
409 reg_w_page(gspca_dev, page4_7311, sizeof page4_7311);
410 break;
411 case 255:
412 reg_w_page(gspca_dev, page3_7302, sizeof page3_7302);
413 break;
414 default:
415 if (len > 32) {
416 PDEBUG(D_ERR|D_STREAM,
417 "Incorrect variable sequence");
418 return;
419 }
420 while (len > 0) {
421 if (len < 8) {
422 reg_w_buf(gspca_dev, index, seq, len);
423 seq += len;
424 break;
425 }
426 reg_w_buf(gspca_dev, index, seq, 8);
427 seq += 8;
428 index += 8;
429 len -= 8;
430 }
431 }
432 }
433 /* not reached */
434}
435
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300436/* this function is called at probe time */
437static int sd_config(struct gspca_dev *gspca_dev,
438 const struct usb_device_id *id)
439{
440 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300441 struct cam *cam;
442
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300443 cam = &gspca_dev->cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300444 cam->epaddr = 0x05;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300445
446 sd->sensor = id->driver_info;
447 if (sd->sensor == SENSOR_PAC7302) {
448 PDEBUG(D_CONF, "Find Sensor PAC7302");
449 reg_w_seq(gspca_dev, probe_7302, sizeof probe_7302);
450
451 cam->cam_mode = &vga_mode[2]; /* only 640x480 */
452 cam->nmodes = 1;
453 } else {
454 PDEBUG(D_CONF, "Find Sensor PAC7311");
455 reg_w_seq(gspca_dev, probe_7302, sizeof probe_7302);
456
457 cam->cam_mode = vga_mode;
458 cam->nmodes = ARRAY_SIZE(vga_mode);
459 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300460
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300461 sd->brightness = BRIGHTNESS_DEF;
462 sd->contrast = CONTRAST_DEF;
463 sd->colors = COLOR_DEF;
464 sd->autogain = AUTOGAIN_DEF;
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300465 sd->ag_cnt = -1;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300466 return 0;
467}
468
Jean-Francois Moinedff6d322008-09-03 16:47:57 -0300469/* rev 12a only */
470static void setbrightcont(struct gspca_dev *gspca_dev)
471{
472 struct sd *sd = (struct sd *) gspca_dev;
473 int i, v;
474 static const __u8 max[10] =
475 {0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb,
476 0xd4, 0xec};
477 static const __u8 delta[10] =
478 {0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17,
479 0x11, 0x0b};
480
481 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
482 for (i = 0; i < 10; i++) {
483 v = max[i];
484 v += (sd->brightness - BRIGHTNESS_MAX)
485 * 150 / BRIGHTNESS_MAX; /* 200 ? */
486 v -= delta[i] * sd->contrast / CONTRAST_MAX;
487 if (v < 0)
488 v = 0;
489 else if (v > 0xff)
490 v = 0xff;
491 reg_w(gspca_dev, 0xa2 + i, v);
492 }
493 reg_w(gspca_dev, 0xdc, 0x01);
494}
495
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300496static void setbrightness(struct gspca_dev *gspca_dev)
497{
498 struct sd *sd = (struct sd *) gspca_dev;
499 int brightness;
500
Jean-Francois Moinedff6d322008-09-03 16:47:57 -0300501 if (sd->sensor == SENSOR_PAC7302) {
502 setbrightcont(gspca_dev);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300503 return;
Jean-Francois Moinedff6d322008-09-03 16:47:57 -0300504 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300505/*jfm: inverted?*/
506 brightness = BRIGHTNESS_MAX - sd->brightness;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300507 reg_w(gspca_dev, 0xff, 0x04);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300508 reg_w(gspca_dev, 0x0f, brightness);
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 PDEBUG(D_CONF|D_STREAM, "brightness: %i", brightness);
512}
513
514static void setcontrast(struct gspca_dev *gspca_dev)
515{
516 struct sd *sd = (struct sd *) gspca_dev;
517
Jean-Francois Moinedff6d322008-09-03 16:47:57 -0300518 if (sd->sensor == SENSOR_PAC7302) {
519 setbrightcont(gspca_dev);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300520 return;
Jean-Francois Moinedff6d322008-09-03 16:47:57 -0300521 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300522 reg_w(gspca_dev, 0xff, 0x01);
523 reg_w(gspca_dev, 0x80, sd->contrast);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300524 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300525 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300526}
527
528static void setcolors(struct gspca_dev *gspca_dev)
529{
530 struct sd *sd = (struct sd *) gspca_dev;
531
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300532 if (sd->sensor == SENSOR_PAC7302) {
533 int i, v;
534 static const int a[9] =
535 {217, -212, 0, -101, 170, -67, -38, -315, 355};
536 static const int b[9] =
537 {19, 106, 0, 19, 106, 1, 19, 106, 1};
538
539 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
540 reg_w(gspca_dev, 0x11, 0x01);
541 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
542 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
543 for (i = 0; i < 9; i++) {
544 v = a[i] * sd->colors / COLOR_MAX + b[i];
545 reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07);
546 reg_w(gspca_dev, 0x0f + 2 * i + 1, v);
547 }
548 reg_w(gspca_dev, 0xdc, 0x01);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300549 return;
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300550 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300551 reg_w(gspca_dev, 0xff, 0x01);
552 reg_w(gspca_dev, 0x10, sd->colors);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300553 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300554 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300555 PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
556}
557
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300558static void setautogain(struct gspca_dev *gspca_dev)
559{
560 struct sd *sd = (struct sd *) gspca_dev;
561
562 if (sd->autogain) {
563 sd->lum_sum = 0;
564 sd->ag_cnt = AG_CNT_START;
565 } else {
566 sd->ag_cnt = -1;
567 }
568}
569
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300570/* this function is used by pac7302 only */
571static void sethvflip(struct gspca_dev *gspca_dev)
572{
573 struct sd *sd = (struct sd *) gspca_dev;
574 __u8 data;
575
576 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
577 data = (sd->hflip ? 0x00 : 0x08)
578 | (sd->vflip ? 0x04 : 0x00);
579 reg_w(gspca_dev, 0x21, data);
580 reg_w(gspca_dev, 0x11, 0x01);
581}
582
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300583/* this function is called at open time */
584static int sd_open(struct gspca_dev *gspca_dev)
585{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300586 reg_w(gspca_dev, 0x78, 0x00); /* Turn on LED */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300587 return 0;
588}
589
590static void sd_start(struct gspca_dev *gspca_dev)
591{
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300592 struct sd *sd = (struct sd *) gspca_dev;
593
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300594 sd->tosof = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300595
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300596 if (sd->sensor == SENSOR_PAC7302)
597 reg_w_var(gspca_dev, start_7302);
598 else
599 reg_w_var(gspca_dev, start_7311);
600
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300601 setcontrast(gspca_dev);
602 setbrightness(gspca_dev);
603 setcolors(gspca_dev);
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300604 setautogain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300605
606 /* set correct resolution */
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300607 switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300608 case 2: /* 160x120 pac7311 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300609 reg_w(gspca_dev, 0xff, 0x04);
610 reg_w(gspca_dev, 0x02, 0x03);
611 reg_w(gspca_dev, 0xff, 0x01);
612 reg_w(gspca_dev, 0x08, 0x09);
613 reg_w(gspca_dev, 0x17, 0x20);
614 reg_w(gspca_dev, 0x1b, 0x00);
615/* reg_w(gspca_dev, 0x80, 0x69); */
616 reg_w(gspca_dev, 0x87, 0x10);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300617 break;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300618 case 1: /* 320x240 pac7311 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300619 reg_w(gspca_dev, 0xff, 0x04);
620 reg_w(gspca_dev, 0x02, 0x03);
621 reg_w(gspca_dev, 0xff, 0x01);
622 reg_w(gspca_dev, 0x08, 0x09);
623 reg_w(gspca_dev, 0x17, 0x30);
624/* reg_w(gspca_dev, 0x80, 0x3f); */
625 reg_w(gspca_dev, 0x87, 0x11);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300626 break;
627 case 0: /* 640x480 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300628 if (sd->sensor == SENSOR_PAC7302)
629 break;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300630 reg_w(gspca_dev, 0xff, 0x04);
631 reg_w(gspca_dev, 0x02, 0x03);
632 reg_w(gspca_dev, 0xff, 0x01);
633 reg_w(gspca_dev, 0x08, 0x08);
634 reg_w(gspca_dev, 0x17, 0x00);
635/* reg_w(gspca_dev, 0x80, 0x1c); */
636 reg_w(gspca_dev, 0x87, 0x12);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300637 break;
638 }
639
640 /* start stream */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300641 reg_w(gspca_dev, 0xff, 0x01);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300642 if (sd->sensor == SENSOR_PAC7302) {
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300643 sethvflip(gspca_dev);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300644 reg_w(gspca_dev, 0x78, 0x01);
645 reg_w(gspca_dev, 0xff, 0x01);
646 reg_w(gspca_dev, 0x78, 0x01);
647 } else {
648 reg_w(gspca_dev, 0x78, 0x04);
649 reg_w(gspca_dev, 0x78, 0x05);
650 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300651}
652
653static void sd_stopN(struct gspca_dev *gspca_dev)
654{
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300655 struct sd *sd = (struct sd *) gspca_dev;
656
657 if (sd->sensor == SENSOR_PAC7302) {
658 reg_w(gspca_dev, 0x78, 0x00);
659 reg_w(gspca_dev, 0x78, 0x00);
660 return;
661 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300662 reg_w(gspca_dev, 0xff, 0x04);
663 reg_w(gspca_dev, 0x27, 0x80);
664 reg_w(gspca_dev, 0x28, 0xca);
665 reg_w(gspca_dev, 0x29, 0x53);
666 reg_w(gspca_dev, 0x2a, 0x0e);
667 reg_w(gspca_dev, 0xff, 0x01);
668 reg_w(gspca_dev, 0x3e, 0x20);
669 reg_w(gspca_dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */
670 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
671 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300672}
673
674static void sd_stop0(struct gspca_dev *gspca_dev)
675{
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300676 struct sd *sd = (struct sd *) gspca_dev;
677
678 if (sd->sensor == SENSOR_PAC7302) {
679 reg_w(gspca_dev, 0xff, 0x01);
680 reg_w(gspca_dev, 0x78, 0x40);
681 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300682}
683
684/* this function is called at close time */
685static void sd_close(struct gspca_dev *gspca_dev)
686{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300687}
688
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300689static void do_autogain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300690{
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300691 struct sd *sd = (struct sd *) gspca_dev;
692 int luma;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300693 int luma_mean = 128;
694 int luma_delta = 20;
695 __u8 spring = 5;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300696 int Gbright;
697
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300698 if (!atomic_read(&sd->do_gain))
699 return;
700 atomic_set(&sd->do_gain, 0);
701
702 luma = atomic_read(&sd->avg_lum);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300703 Gbright = reg_r(gspca_dev, 0x02);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300704 PDEBUG(D_FRAM, "luma mean %d", luma);
705 if (luma < luma_mean - luma_delta ||
706 luma > luma_mean + luma_delta) {
707 Gbright += (luma_mean - luma) >> spring;
708 if (Gbright > 0x1a)
709 Gbright = 0x1a;
710 else if (Gbright < 4)
711 Gbright = 4;
712 PDEBUG(D_FRAM, "gbright %d", Gbright);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300713 if (sd->sensor == SENSOR_PAC7302) {
714 reg_w(gspca_dev, 0xff, 0x03);
715 reg_w(gspca_dev, 0x10, Gbright);
716 /* load registers to sensor (Bit 0, auto clear) */
717 reg_w(gspca_dev, 0x11, 0x01);
718 } else {
719 reg_w(gspca_dev, 0xff, 0x04);
720 reg_w(gspca_dev, 0x0f, Gbright);
721 /* load registers to sensor (Bit 0, auto clear) */
722 reg_w(gspca_dev, 0x11, 0x01);
723 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300724 }
725}
726
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300727/* this function is run at interrupt level */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300728static void sd_pkt_scan(struct gspca_dev *gspca_dev,
729 struct gspca_frame *frame, /* target */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300730 __u8 *data, /* isoc packet */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300731 int len) /* iso packet length */
732{
733 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300734 int i;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300735
Jean-Francois Moine8559e8d2008-09-03 16:47:27 -0300736#define INTER_FRAME 0x53 /* eof + inter frame + sof */
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300737#define LUM_OFFSET 0x1e /* reverse offset / start of frame */
738
739 /*
740 * inside a frame, there may be:
741 * escaped ff ('ff 00')
742 * sequences'ff ff ff xx' to remove
743 * end of frame ('ff d9')
744 * at the end of frame, there are:
745 * ff d9 end of frame
746 * 0x33 bytes
747 * one byte luminosity
748 * 0x16 bytes
Jean-Francois Moinef75c4952008-09-03 16:47:35 -0300749 * ff ff 00 ff 96 62 44 start of frame
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300750 */
751
Jean-Francois Moinef75c4952008-09-03 16:47:35 -0300752 if (sd->tosof != 0) { /* if outside a frame */
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300753
Jean-Francois Moine8559e8d2008-09-03 16:47:27 -0300754 /* get the luminosity and go to the start of frame */
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300755 data += sd->tosof;
756 len -= sd->tosof;
757 if (sd->tosof > LUM_OFFSET)
758 sd->lum_sum += data[-LUM_OFFSET];
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300759 sd->tosof = 0;
Jean-Francois Moinef75c4952008-09-03 16:47:35 -0300760 jpeg_put_header(gspca_dev, frame, 1, 0x21);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300761 }
762
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300763 for (i = 0; i < len; i++) {
764 if (data[i] != 0xff)
765 continue;
766 switch (data[i + 1]) {
Jean-Francois Moinef75c4952008-09-03 16:47:35 -0300767 case 0xd9: /* 'ff d9' end of frame */
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300768 frame = gspca_frame_add(gspca_dev,
769 LAST_PACKET,
Jean-Francois Moine8559e8d2008-09-03 16:47:27 -0300770 frame, data, i + 2);
Jean-Francois Moine23d9e472008-09-03 16:47:22 -0300771 data += i + INTER_FRAME;
772 len -= i + INTER_FRAME;
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300773 i = 0;
Jean-Francois Moine23d9e472008-09-03 16:47:22 -0300774 if (len > -LUM_OFFSET)
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300775 sd->lum_sum += data[-LUM_OFFSET];
776 if (len < 0) {
777 sd->tosof = -len;
778 break;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300779 }
Jean-Francois Moinef75c4952008-09-03 16:47:35 -0300780 jpeg_put_header(gspca_dev, frame, 1, 0x21);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300781 break;
782 }
783 }
Jean-Francois Moine8559e8d2008-09-03 16:47:27 -0300784 gspca_frame_add(gspca_dev, INTER_PACKET,
785 frame, data, i);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300786}
787
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300788static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
789{
790 struct sd *sd = (struct sd *) gspca_dev;
791
792 sd->brightness = val;
793 if (gspca_dev->streaming)
794 setbrightness(gspca_dev);
795 return 0;
796}
797
798static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
799{
800 struct sd *sd = (struct sd *) gspca_dev;
801
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300802 *val = sd->brightness;
803 return 0;
804}
805
806static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
807{
808 struct sd *sd = (struct sd *) gspca_dev;
809
810 sd->contrast = val;
811 if (gspca_dev->streaming)
812 setcontrast(gspca_dev);
813 return 0;
814}
815
816static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
817{
818 struct sd *sd = (struct sd *) gspca_dev;
819
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300820 *val = sd->contrast;
821 return 0;
822}
823
824static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
825{
826 struct sd *sd = (struct sd *) gspca_dev;
827
828 sd->colors = val;
829 if (gspca_dev->streaming)
830 setcolors(gspca_dev);
831 return 0;
832}
833
834static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
835{
836 struct sd *sd = (struct sd *) gspca_dev;
837
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300838 *val = sd->colors;
839 return 0;
840}
841
842static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
843{
844 struct sd *sd = (struct sd *) gspca_dev;
845
846 sd->autogain = val;
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300847 if (gspca_dev->streaming)
848 setautogain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300849 return 0;
850}
851
852static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
853{
854 struct sd *sd = (struct sd *) gspca_dev;
855
856 *val = sd->autogain;
857 return 0;
858}
859
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300860static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
861{
862 struct sd *sd = (struct sd *) gspca_dev;
863
864 sd->hflip = val;
865 if (gspca_dev->streaming)
866 sethvflip(gspca_dev);
867 return 0;
868}
869
870static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
871{
872 struct sd *sd = (struct sd *) gspca_dev;
873
874 *val = sd->hflip;
875 return 0;
876}
877
878static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
879{
880 struct sd *sd = (struct sd *) gspca_dev;
881
882 sd->vflip = val;
883 if (gspca_dev->streaming)
884 sethvflip(gspca_dev);
885 return 0;
886}
887
888static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
889{
890 struct sd *sd = (struct sd *) gspca_dev;
891
892 *val = sd->vflip;
893 return 0;
894}
895
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300896/* sub-driver description */
897static struct sd_desc sd_desc = {
898 .name = MODULE_NAME,
899 .ctrls = sd_ctrls,
900 .nctrls = ARRAY_SIZE(sd_ctrls),
901 .config = sd_config,
902 .open = sd_open,
903 .start = sd_start,
904 .stopN = sd_stopN,
905 .stop0 = sd_stop0,
906 .close = sd_close,
907 .pkt_scan = sd_pkt_scan,
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300908 .dq_callback = do_autogain,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300909};
910
911/* -- module initialisation -- */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300912static __devinitdata struct usb_device_id device_table[] = {
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300913 {USB_DEVICE(0x093a, 0x2600), .driver_info = SENSOR_PAC7311},
914 {USB_DEVICE(0x093a, 0x2601), .driver_info = SENSOR_PAC7311},
915 {USB_DEVICE(0x093a, 0x2603), .driver_info = SENSOR_PAC7311},
916 {USB_DEVICE(0x093a, 0x2608), .driver_info = SENSOR_PAC7311},
917 {USB_DEVICE(0x093a, 0x260e), .driver_info = SENSOR_PAC7311},
918 {USB_DEVICE(0x093a, 0x260f), .driver_info = SENSOR_PAC7311},
919 {USB_DEVICE(0x093a, 0x2621), .driver_info = SENSOR_PAC7302},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300920 {}
921};
922MODULE_DEVICE_TABLE(usb, device_table);
923
924/* -- device connect -- */
925static int sd_probe(struct usb_interface *intf,
926 const struct usb_device_id *id)
927{
928 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
929 THIS_MODULE);
930}
931
932static struct usb_driver sd_driver = {
933 .name = MODULE_NAME,
934 .id_table = device_table,
935 .probe = sd_probe,
936 .disconnect = gspca_disconnect,
937};
938
939/* -- module insert / remove -- */
940static int __init sd_mod_init(void)
941{
942 if (usb_register(&sd_driver) < 0)
943 return -1;
Jean-Francois Moine10b0e962008-07-22 05:35:10 -0300944 PDEBUG(D_PROBE, "registered");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300945 return 0;
946}
947static void __exit sd_mod_exit(void)
948{
949 usb_deregister(&sd_driver);
950 PDEBUG(D_PROBE, "deregistered");
951}
952
953module_init(sd_mod_init);
954module_exit(sd_mod_exit);