blob: 4cc9379ee4110647c5389d88714bdb95941f616c [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 Moine4a186252008-09-03 16:48:02 -030045 __u8 qindex;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030046
Jean-Francois Moinee52a5572008-09-03 16:47:21 -030047 char tosof; /* number of bytes before next start of frame */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030048 signed char ag_cnt;
49#define AG_CNT_START 13
Jean-Francois Moine49b57db2008-09-03 16:47:25 -030050
51 __u8 sensor;
52#define SENSOR_PAC7302 0
53#define SENSOR_PAC7311 1
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030054};
55
56/* V4L2 controls supported by the driver */
57static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
58static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
59static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
60static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
61static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
62static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
63static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
64static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
Jean-Francois Moine41b46972008-09-03 16:47:58 -030065static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val);
66static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val);
67static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
68static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030069
70static struct ctrl sd_ctrls[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030071 {
72 {
73 .id = V4L2_CID_BRIGHTNESS,
74 .type = V4L2_CTRL_TYPE_INTEGER,
75 .name = "Brightness",
76 .minimum = 0,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -030077#define BRIGHTNESS_MAX 0x20
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030078 .maximum = BRIGHTNESS_MAX,
79 .step = 1,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -030080#define BRIGHTNESS_DEF 0x10
81 .default_value = BRIGHTNESS_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030082 },
83 .set = sd_setbrightness,
84 .get = sd_getbrightness,
85 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030086 {
87 {
88 .id = V4L2_CID_CONTRAST,
89 .type = V4L2_CTRL_TYPE_INTEGER,
90 .name = "Contrast",
91 .minimum = 0,
Jean-Francois Moinedff6d322008-09-03 16:47:57 -030092#define CONTRAST_MAX 255
93 .maximum = CONTRAST_MAX,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030094 .step = 1,
Jean-Francois Moinedff6d322008-09-03 16:47:57 -030095#define CONTRAST_DEF 60
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -030096 .default_value = CONTRAST_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030097 },
98 .set = sd_setcontrast,
99 .get = sd_getcontrast,
100 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300101 {
102 {
103 .id = V4L2_CID_SATURATION,
104 .type = V4L2_CTRL_TYPE_INTEGER,
Jean-Francois Moinedff6d322008-09-03 16:47:57 -0300105 .name = "Saturation",
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300106 .minimum = 0,
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300107#define COLOR_MAX 255
108 .maximum = COLOR_MAX,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300109 .step = 1,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300110#define COLOR_DEF 127
111 .default_value = COLOR_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300112 },
113 .set = sd_setcolors,
114 .get = sd_getcolors,
115 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300116 {
117 {
118 .id = V4L2_CID_AUTOGAIN,
119 .type = V4L2_CTRL_TYPE_BOOLEAN,
120 .name = "Auto Gain",
121 .minimum = 0,
122 .maximum = 1,
123 .step = 1,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300124#define AUTOGAIN_DEF 1
125 .default_value = AUTOGAIN_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300126 },
127 .set = sd_setautogain,
128 .get = sd_getautogain,
129 },
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300130/* next controls work with pac7302 only */
131 {
132 {
133 .id = V4L2_CID_HFLIP,
134 .type = V4L2_CTRL_TYPE_BOOLEAN,
135 .name = "Mirror",
136 .minimum = 0,
137 .maximum = 1,
138 .step = 1,
139#define HFLIP_DEF 0
140 .default_value = HFLIP_DEF,
141 },
142 .set = sd_sethflip,
143 .get = sd_gethflip,
144 },
145 {
146 {
147 .id = V4L2_CID_VFLIP,
148 .type = V4L2_CTRL_TYPE_BOOLEAN,
149 .name = "Vflip",
150 .minimum = 0,
151 .maximum = 1,
152 .step = 1,
153#define VFLIP_DEF 0
154 .default_value = VFLIP_DEF,
155 },
156 .set = sd_setvflip,
157 .get = sd_getvflip,
158 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300159};
160
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300161static struct v4l2_pix_format vga_mode[] = {
Jean-Francois Moinef75c4952008-09-03 16:47:35 -0300162 {160, 120, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300163 .bytesperline = 160,
164 .sizeimage = 160 * 120 * 3 / 8 + 590,
165 .colorspace = V4L2_COLORSPACE_JPEG,
166 .priv = 2},
Jean-Francois Moinef75c4952008-09-03 16:47:35 -0300167 {320, 240, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300168 .bytesperline = 320,
169 .sizeimage = 320 * 240 * 3 / 8 + 590,
170 .colorspace = V4L2_COLORSPACE_JPEG,
171 .priv = 1},
Jean-Francois Moinef75c4952008-09-03 16:47:35 -0300172 {640, 480, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300173 .bytesperline = 640,
174 .sizeimage = 640 * 480 * 3 / 8 + 590,
175 .colorspace = V4L2_COLORSPACE_JPEG,
176 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300177};
178
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300179/* pac 7302 */
180static const __u8 probe_7302[] = {
181/* index,value */
182 0xff, 0x01, /* page 1 */
183 0x78, 0x00, /* deactivate */
184 0xff, 0x01,
185 0x78, 0x40, /* led off */
186};
187static const __u8 start_7302[] = {
188/* index, len, [value]* */
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300189 0xff, 1, 0x00, /* page 0 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300190 0x00, 12, 0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80,
191 0x00, 0x00, 0x00, 0x00,
192 0x0d, 24, 0x03, 0x01, 0x00, 0xb5, 0x07, 0xcb, 0x00, 0x00,
193 0x07, 0xc8, 0x00, 0xea, 0x07, 0xcf, 0x07, 0xf7,
194 0x07, 0x7e, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x11,
195 0x26, 2, 0xaa, 0xaa,
196 0x2e, 1, 0x31,
197 0x38, 1, 0x01,
198 0x3a, 3, 0x14, 0xff, 0x5a,
199 0x43, 11, 0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11,
200 0x00, 0x54, 0x11,
201 0x55, 1, 0x00,
202 0x62, 4, 0x10, 0x1e, 0x1e, 0x18,
203 0x6b, 1, 0x00,
204 0x6e, 3, 0x08, 0x06, 0x00,
205 0x72, 3, 0x00, 0xff, 0x00,
206 0x7d, 23, 0x01, 0x01, 0x58, 0x46, 0x50, 0x3c, 0x50, 0x3c,
207 0x54, 0x46, 0x54, 0x56, 0x52, 0x50, 0x52, 0x50,
208 0x56, 0x64, 0xa4, 0x00, 0xda, 0x00, 0x00,
209 0xa2, 10, 0x22, 0x2c, 0x3c, 0x54, 0x69, 0x7c, 0x9c, 0xb9,
210 0xd2, 0xeb,
211 0xaf, 1, 0x02,
212 0xb5, 2, 0x08, 0x08,
213 0xb8, 2, 0x08, 0x88,
214 0xc4, 4, 0xae, 0x01, 0x04, 0x01,
215 0xcc, 1, 0x00,
216 0xd1, 11, 0x01, 0x30, 0x49, 0x5e, 0x6f, 0x7f, 0x8e, 0xa9,
217 0xc1, 0xd7, 0xec,
218 0xdc, 1, 0x01,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300219 0xff, 1, 0x01, /* page 1 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300220 0x12, 3, 0x02, 0x00, 0x01,
221 0x3e, 2, 0x00, 0x00,
222 0x76, 5, 0x01, 0x20, 0x40, 0x00, 0xf2,
223 0x7c, 1, 0x00,
224 0x7f, 10, 0x4b, 0x0f, 0x01, 0x2c, 0x02, 0x58, 0x03, 0x20,
225 0x02, 0x00,
226 0x96, 5, 0x01, 0x10, 0x04, 0x01, 0x04,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300227 0xc8, 14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300228 0x07, 0x00, 0x01, 0x07, 0x04, 0x01,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300229 0xd8, 1, 0x01,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300230 0xdb, 2, 0x00, 0x01,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300231 0xde, 7, 0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x00,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300232 0xe6, 4, 0x00, 0x00, 0x00, 0x01,
233 0xeb, 1, 0x00,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300234 0xff, 1, 0x02, /* page 2 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300235 0x22, 1, 0x00,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300236 0xff, 1, 0x03, /* page 3 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300237 0x00, 255, /* load the page 3 */
238 0x11, 1, 0x01,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300239 0xff, 1, 0x02, /* page 2 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300240 0x13, 1, 0x00,
241 0x22, 4, 0x1f, 0xa4, 0xf0, 0x96,
242 0x27, 2, 0x14, 0x0c,
243 0x2a, 5, 0xc8, 0x00, 0x18, 0x12, 0x22,
244 0x64, 8, 0x00, 0x00, 0xf0, 0x01, 0x14, 0x44, 0x44, 0x44,
245 0x6e, 1, 0x08,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300246 0xff, 1, 0x03, /* page 1 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300247 0x78, 1, 0x00,
248 0, 0 /* end of sequence */
249};
250
251/* page 3 - the value 0xaa says skip the index - see reg_w_page() */
252static const __u8 page3_7302[] = {
253 0x90, 0x40, 0x03, 0x50, 0xc2, 0x01, 0x14, 0x16,
254 0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00,
255 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
256 0x00, 0x00, 0x00, 0x47, 0x01, 0xb3, 0x01, 0x00,
257 0x00, 0x08, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x21,
258 0x00, 0x00, 0x00, 0x54, 0xf4, 0x02, 0x52, 0x54,
259 0xa4, 0xb8, 0xe0, 0x2a, 0xf6, 0x00, 0x00, 0x00,
260 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
261 0x00, 0xfc, 0x00, 0xf2, 0x1f, 0x04, 0x00, 0x00,
262 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x10, 0x00, 0x00,
263 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
264 0x00, 0x40, 0xff, 0x03, 0x19, 0x00, 0x00, 0x00,
265 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
266 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0xc8, 0xc8,
267 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,
268 0x08, 0x10, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00,
269 0x01, 0x00, 0x02, 0x47, 0x00, 0x00, 0x00, 0x00,
270 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
271 0x00, 0x02, 0xfa, 0x00, 0x64, 0x5a, 0x28, 0x00,
272 0x00
273};
274
275/* pac 7311 */
276static const __u8 probe_7311[] = {
277 0x78, 0x40, /* Bit_0=start stream, Bit_7=LED */
278 0x78, 0x40, /* Bit_0=start stream, Bit_7=LED */
279 0x78, 0x44, /* Bit_0=start stream, Bit_7=LED */
280 0xff, 0x04,
281 0x27, 0x80,
282 0x28, 0xca,
283 0x29, 0x53,
284 0x2a, 0x0e,
285 0xff, 0x01,
286 0x3e, 0x20,
287};
288
289static const __u8 start_7311[] = {
290/* index, len, [value]* */
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300291 0xff, 1, 0x01, /* page 1 */
292 0x02, 43, 0x48, 0x0a, 0x40, 0x08, 0x00, 0x00, 0x08, 0x00,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300293 0x06, 0xff, 0x11, 0xff, 0x5a, 0x30, 0x90, 0x4c,
294 0x00, 0x07, 0x00, 0x0a, 0x10, 0x00, 0xa0, 0x10,
295 0x02, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x01, 0x00,
296 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
297 0x00, 0x00, 0x00,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300298 0x3e, 42, 0x00, 0x00, 0x78, 0x52, 0x4a, 0x52, 0x78, 0x6e,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300299 0x48, 0x46, 0x48, 0x6e, 0x5f, 0x49, 0x42, 0x49,
300 0x5f, 0x5f, 0x49, 0x42, 0x49, 0x5f, 0x6e, 0x48,
301 0x46, 0x48, 0x6e, 0x78, 0x52, 0x4a, 0x52, 0x78,
302 0x00, 0x00, 0x09, 0x1b, 0x34, 0x49, 0x5c, 0x9b,
303 0xd0, 0xff,
304 0x78, 6, 0x44, 0x00, 0xf2, 0x01, 0x01, 0x80,
305 0x7f, 18, 0x2a, 0x1c, 0x00, 0xc8, 0x02, 0x58, 0x03, 0x84,
306 0x12, 0x00, 0x1a, 0x04, 0x08, 0x0c, 0x10, 0x14,
307 0x18, 0x20,
308 0x96, 3, 0x01, 0x08, 0x04,
309 0xa0, 4, 0x44, 0x44, 0x44, 0x04,
310 0xf0, 13, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x20, 0x00,
311 0x3f, 0x00, 0x0a, 0x01, 0x00,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300312 0xff, 1, 0x04, /* page 4 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300313 0x00, 254, /* load the page 4 */
314 0x11, 1, 0x01,
315 0, 0 /* end of sequence */
316};
317
318/* page 4 - the value 0xaa says skip the index - see reg_w_page() */
319static const __u8 page4_7311[] = {
320 0xaa, 0xaa, 0x04, 0x54, 0x07, 0x2b, 0x09, 0x0f,
321 0x09, 0x00, 0xaa, 0xaa, 0x07, 0x00, 0x00, 0x62,
322 0x08, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
323 0x00, 0x00, 0x00, 0x03, 0xa0, 0x01, 0xf4, 0xaa,
324 0xaa, 0x00, 0x08, 0xaa, 0x03, 0xaa, 0x00, 0x01,
325 0xca, 0x10, 0x06, 0x78, 0x00, 0x00, 0x00, 0x00,
326 0x23, 0x28, 0x04, 0x11, 0x00, 0x00
327};
328
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300329static void reg_w_buf(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300330 __u8 index,
331 const char *buffer, int len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300332{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300333 memcpy(gspca_dev->usb_buf, buffer, len);
334 usb_control_msg(gspca_dev->dev,
335 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300336 1, /* request */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300337 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300338 0, /* value */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300339 index, gspca_dev->usb_buf, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300340 500);
341}
342
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300343static __u8 reg_r(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300344 __u8 index)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300345{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300346 usb_control_msg(gspca_dev->dev,
347 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300348 0, /* request */
349 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
350 0, /* value */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300351 index, gspca_dev->usb_buf, 1,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300352 500);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300353 return gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300354}
355
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300356static void reg_w(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300357 __u8 index,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300358 __u8 value)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300359{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300360 gspca_dev->usb_buf[0] = value;
361 usb_control_msg(gspca_dev->dev,
362 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300363 0, /* request */
364 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300365 value, index, gspca_dev->usb_buf, 1,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300366 500);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300367}
368
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300369static void reg_w_seq(struct gspca_dev *gspca_dev,
370 const __u8 *seq, int len)
371{
372 while (--len >= 0) {
373 reg_w(gspca_dev, seq[0], seq[1]);
374 seq += 2;
375 }
376}
377
378/* load the beginning of a page */
379static void reg_w_page(struct gspca_dev *gspca_dev,
380 const __u8 *page, int len)
381{
382 int index;
383
384 for (index = 0; index < len; index++) {
385 if (page[index] == 0xaa) /* skip this index */
386 continue;
387 gspca_dev->usb_buf[0] = page[index];
388 usb_control_msg(gspca_dev->dev,
389 usb_sndctrlpipe(gspca_dev->dev, 0),
390 0, /* request */
391 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
392 0, index, gspca_dev->usb_buf, 1,
393 500);
394 }
395}
396
397/* output a variable sequence */
398static void reg_w_var(struct gspca_dev *gspca_dev,
399 const __u8 *seq)
400{
401 int index, len;
402
403 for (;;) {
404 index = *seq++;
405 len = *seq++;
406 switch (len) {
407 case 0:
408 return;
409 case 254:
410 reg_w_page(gspca_dev, page4_7311, sizeof page4_7311);
411 break;
412 case 255:
413 reg_w_page(gspca_dev, page3_7302, sizeof page3_7302);
414 break;
415 default:
416 if (len > 32) {
417 PDEBUG(D_ERR|D_STREAM,
418 "Incorrect variable sequence");
419 return;
420 }
421 while (len > 0) {
422 if (len < 8) {
423 reg_w_buf(gspca_dev, index, seq, len);
424 seq += len;
425 break;
426 }
427 reg_w_buf(gspca_dev, index, seq, 8);
428 seq += 8;
429 index += 8;
430 len -= 8;
431 }
432 }
433 }
434 /* not reached */
435}
436
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300437/* this function is called at probe time */
438static int sd_config(struct gspca_dev *gspca_dev,
439 const struct usb_device_id *id)
440{
441 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300442 struct cam *cam;
443
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300444 cam = &gspca_dev->cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300445 cam->epaddr = 0x05;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300446
447 sd->sensor = id->driver_info;
448 if (sd->sensor == SENSOR_PAC7302) {
449 PDEBUG(D_CONF, "Find Sensor PAC7302");
450 reg_w_seq(gspca_dev, probe_7302, sizeof probe_7302);
451
452 cam->cam_mode = &vga_mode[2]; /* only 640x480 */
453 cam->nmodes = 1;
454 } else {
455 PDEBUG(D_CONF, "Find Sensor PAC7311");
456 reg_w_seq(gspca_dev, probe_7302, sizeof probe_7302);
457
458 cam->cam_mode = vga_mode;
459 cam->nmodes = ARRAY_SIZE(vga_mode);
460 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300461
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300462 sd->brightness = BRIGHTNESS_DEF;
463 sd->contrast = CONTRAST_DEF;
464 sd->colors = COLOR_DEF;
465 sd->autogain = AUTOGAIN_DEF;
Jean-Francois Moine4a186252008-09-03 16:48:02 -0300466 sd->hflip = HFLIP_DEF;
467 sd->vflip = VFLIP_DEF;
468 sd->qindex = 3;
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300469 sd->ag_cnt = -1;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300470 return 0;
471}
472
Jean-Francois Moinedff6d322008-09-03 16:47:57 -0300473/* rev 12a only */
474static void setbrightcont(struct gspca_dev *gspca_dev)
475{
476 struct sd *sd = (struct sd *) gspca_dev;
477 int i, v;
478 static const __u8 max[10] =
479 {0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb,
480 0xd4, 0xec};
481 static const __u8 delta[10] =
482 {0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17,
483 0x11, 0x0b};
484
485 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
486 for (i = 0; i < 10; i++) {
487 v = max[i];
488 v += (sd->brightness - BRIGHTNESS_MAX)
489 * 150 / BRIGHTNESS_MAX; /* 200 ? */
490 v -= delta[i] * sd->contrast / CONTRAST_MAX;
491 if (v < 0)
492 v = 0;
493 else if (v > 0xff)
494 v = 0xff;
495 reg_w(gspca_dev, 0xa2 + i, v);
496 }
497 reg_w(gspca_dev, 0xdc, 0x01);
498}
499
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300500static void setbrightness(struct gspca_dev *gspca_dev)
501{
502 struct sd *sd = (struct sd *) gspca_dev;
503 int brightness;
504
Jean-Francois Moinedff6d322008-09-03 16:47:57 -0300505 if (sd->sensor == SENSOR_PAC7302) {
506 setbrightcont(gspca_dev);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300507 return;
Jean-Francois Moinedff6d322008-09-03 16:47:57 -0300508 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300509/*jfm: inverted?*/
510 brightness = BRIGHTNESS_MAX - sd->brightness;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300511 reg_w(gspca_dev, 0xff, 0x04);
Jean-Francois Moine4a186252008-09-03 16:48:02 -0300512 reg_w(gspca_dev, 0x0e, 0x00);
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 Moinedff6d322008-09-03 16:47:57 -0300523 if (sd->sensor == SENSOR_PAC7302) {
524 setbrightcont(gspca_dev);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300525 return;
Jean-Francois Moinedff6d322008-09-03 16:47:57 -0300526 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300527 reg_w(gspca_dev, 0xff, 0x01);
Jean-Francois Moine4a186252008-09-03 16:48:02 -0300528 reg_w(gspca_dev, 0x10, sd->contrast);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300529 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300530 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300531}
532
533static void setcolors(struct gspca_dev *gspca_dev)
534{
535 struct sd *sd = (struct sd *) gspca_dev;
536
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300537 if (sd->sensor == SENSOR_PAC7302) {
538 int i, v;
539 static const int a[9] =
540 {217, -212, 0, -101, 170, -67, -38, -315, 355};
541 static const int b[9] =
542 {19, 106, 0, 19, 106, 1, 19, 106, 1};
543
544 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
545 reg_w(gspca_dev, 0x11, 0x01);
546 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
547 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
548 for (i = 0; i < 9; i++) {
549 v = a[i] * sd->colors / COLOR_MAX + b[i];
550 reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07);
551 reg_w(gspca_dev, 0x0f + 2 * i + 1, v);
552 }
553 reg_w(gspca_dev, 0xdc, 0x01);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300554 return;
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300555 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300556 reg_w(gspca_dev, 0xff, 0x01);
Jean-Francois Moine4a186252008-09-03 16:48:02 -0300557 reg_w(gspca_dev, 0x80, sd->colors);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300558 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300559 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300560 PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
561}
562
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300563static void setautogain(struct gspca_dev *gspca_dev)
564{
565 struct sd *sd = (struct sd *) gspca_dev;
566
567 if (sd->autogain) {
568 sd->lum_sum = 0;
569 sd->ag_cnt = AG_CNT_START;
570 } else {
571 sd->ag_cnt = -1;
572 }
573}
574
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300575/* this function is used by pac7302 only */
576static void sethvflip(struct gspca_dev *gspca_dev)
577{
578 struct sd *sd = (struct sd *) gspca_dev;
579 __u8 data;
580
581 reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
582 data = (sd->hflip ? 0x00 : 0x08)
583 | (sd->vflip ? 0x04 : 0x00);
584 reg_w(gspca_dev, 0x21, data);
585 reg_w(gspca_dev, 0x11, 0x01);
586}
587
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300588/* this function is called at open time */
589static int sd_open(struct gspca_dev *gspca_dev)
590{
Jean-Francois Moine4a186252008-09-03 16:48:02 -0300591 reg_w(gspca_dev, 0x78, 0x44); /* Turn on LED */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300592 return 0;
593}
594
595static void sd_start(struct gspca_dev *gspca_dev)
596{
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300597 struct sd *sd = (struct sd *) gspca_dev;
598
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300599 sd->tosof = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300600
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300601 if (sd->sensor == SENSOR_PAC7302)
602 reg_w_var(gspca_dev, start_7302);
603 else
604 reg_w_var(gspca_dev, start_7311);
605
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300606 setcontrast(gspca_dev);
607 setbrightness(gspca_dev);
608 setcolors(gspca_dev);
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300609 setautogain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300610
611 /* set correct resolution */
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300612 switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300613 case 2: /* 160x120 pac7311 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300614 reg_w(gspca_dev, 0xff, 0x04);
615 reg_w(gspca_dev, 0x02, 0x03);
616 reg_w(gspca_dev, 0xff, 0x01);
617 reg_w(gspca_dev, 0x08, 0x09);
618 reg_w(gspca_dev, 0x17, 0x20);
619 reg_w(gspca_dev, 0x1b, 0x00);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300620 reg_w(gspca_dev, 0x87, 0x10);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300621 break;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300622 case 1: /* 320x240 pac7311 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300623 reg_w(gspca_dev, 0xff, 0x04);
Jean-Francois Moine4a186252008-09-03 16:48:02 -0300624 reg_w(gspca_dev, 0x02, 0x07);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300625 reg_w(gspca_dev, 0xff, 0x01);
626 reg_w(gspca_dev, 0x08, 0x09);
627 reg_w(gspca_dev, 0x17, 0x30);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300628 reg_w(gspca_dev, 0x87, 0x11);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300629 break;
630 case 0: /* 640x480 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300631 if (sd->sensor == SENSOR_PAC7302)
632 break;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300633 reg_w(gspca_dev, 0xff, 0x04);
Jean-Francois Moine4a186252008-09-03 16:48:02 -0300634 reg_w(gspca_dev, 0x02, 0x07);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300635 reg_w(gspca_dev, 0xff, 0x01);
636 reg_w(gspca_dev, 0x08, 0x08);
637 reg_w(gspca_dev, 0x17, 0x00);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300638 reg_w(gspca_dev, 0x87, 0x12);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300639 break;
640 }
641
642 /* start stream */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300643 reg_w(gspca_dev, 0xff, 0x01);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300644 if (sd->sensor == SENSOR_PAC7302) {
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300645 sethvflip(gspca_dev);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300646 reg_w(gspca_dev, 0x78, 0x01);
647 reg_w(gspca_dev, 0xff, 0x01);
648 reg_w(gspca_dev, 0x78, 0x01);
649 } else {
Jean-Francois Moine4a186252008-09-03 16:48:02 -0300650 reg_w(gspca_dev, 0x78, 0x44);
651 reg_w(gspca_dev, 0x78, 0x45);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300652 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300653}
654
655static void sd_stopN(struct gspca_dev *gspca_dev)
656{
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300657 struct sd *sd = (struct sd *) gspca_dev;
658
659 if (sd->sensor == SENSOR_PAC7302) {
660 reg_w(gspca_dev, 0x78, 0x00);
661 reg_w(gspca_dev, 0x78, 0x00);
662 return;
663 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300664 reg_w(gspca_dev, 0xff, 0x04);
665 reg_w(gspca_dev, 0x27, 0x80);
666 reg_w(gspca_dev, 0x28, 0xca);
667 reg_w(gspca_dev, 0x29, 0x53);
668 reg_w(gspca_dev, 0x2a, 0x0e);
669 reg_w(gspca_dev, 0xff, 0x01);
670 reg_w(gspca_dev, 0x3e, 0x20);
Jean-Francois Moine4a186252008-09-03 16:48:02 -0300671 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300672 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
673 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300674}
675
676static void sd_stop0(struct gspca_dev *gspca_dev)
677{
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300678 struct sd *sd = (struct sd *) gspca_dev;
679
680 if (sd->sensor == SENSOR_PAC7302) {
681 reg_w(gspca_dev, 0xff, 0x01);
682 reg_w(gspca_dev, 0x78, 0x40);
683 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300684}
685
686/* this function is called at close time */
687static void sd_close(struct gspca_dev *gspca_dev)
688{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300689}
690
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300691static void do_autogain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300692{
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300693 struct sd *sd = (struct sd *) gspca_dev;
694 int luma;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300695 int luma_mean = 128;
696 int luma_delta = 20;
697 __u8 spring = 5;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300698 int Gbright;
699
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300700 if (!atomic_read(&sd->do_gain))
701 return;
702 atomic_set(&sd->do_gain, 0);
703
704 luma = atomic_read(&sd->avg_lum);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300705 Gbright = reg_r(gspca_dev, 0x02);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300706 PDEBUG(D_FRAM, "luma mean %d", luma);
707 if (luma < luma_mean - luma_delta ||
708 luma > luma_mean + luma_delta) {
709 Gbright += (luma_mean - luma) >> spring;
710 if (Gbright > 0x1a)
711 Gbright = 0x1a;
712 else if (Gbright < 4)
713 Gbright = 4;
714 PDEBUG(D_FRAM, "gbright %d", Gbright);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300715 if (sd->sensor == SENSOR_PAC7302) {
716 reg_w(gspca_dev, 0xff, 0x03);
717 reg_w(gspca_dev, 0x10, Gbright);
718 /* load registers to sensor (Bit 0, auto clear) */
719 reg_w(gspca_dev, 0x11, 0x01);
720 } else {
721 reg_w(gspca_dev, 0xff, 0x04);
722 reg_w(gspca_dev, 0x0f, Gbright);
723 /* load registers to sensor (Bit 0, auto clear) */
724 reg_w(gspca_dev, 0x11, 0x01);
725 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300726 }
727}
728
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300729/* this function is run at interrupt level */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300730static void sd_pkt_scan(struct gspca_dev *gspca_dev,
731 struct gspca_frame *frame, /* target */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300732 __u8 *data, /* isoc packet */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300733 int len) /* iso packet length */
734{
735 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300736 int i;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300737
Jean-Francois Moine8559e8d2008-09-03 16:47:27 -0300738#define INTER_FRAME 0x53 /* eof + inter frame + sof */
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300739#define LUM_OFFSET 0x1e /* reverse offset / start of frame */
740
741 /*
742 * inside a frame, there may be:
743 * escaped ff ('ff 00')
744 * sequences'ff ff ff xx' to remove
745 * end of frame ('ff d9')
746 * at the end of frame, there are:
747 * ff d9 end of frame
748 * 0x33 bytes
749 * one byte luminosity
750 * 0x16 bytes
Jean-Francois Moinef75c4952008-09-03 16:47:35 -0300751 * ff ff 00 ff 96 62 44 start of frame
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300752 */
753
Jean-Francois Moinef75c4952008-09-03 16:47:35 -0300754 if (sd->tosof != 0) { /* if outside a frame */
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300755
Jean-Francois Moine8559e8d2008-09-03 16:47:27 -0300756 /* get the luminosity and go to the start of frame */
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300757 data += sd->tosof;
758 len -= sd->tosof;
759 if (sd->tosof > LUM_OFFSET)
760 sd->lum_sum += data[-LUM_OFFSET];
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300761 sd->tosof = 0;
Jean-Francois Moine4a186252008-09-03 16:48:02 -0300762 jpeg_put_header(gspca_dev, frame, sd->qindex, 0x21);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300763 }
764
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300765 for (i = 0; i < len; i++) {
766 if (data[i] != 0xff)
767 continue;
768 switch (data[i + 1]) {
Jean-Francois Moinef75c4952008-09-03 16:47:35 -0300769 case 0xd9: /* 'ff d9' end of frame */
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300770 frame = gspca_frame_add(gspca_dev,
771 LAST_PACKET,
Jean-Francois Moine8559e8d2008-09-03 16:47:27 -0300772 frame, data, i + 2);
Jean-Francois Moine23d9e472008-09-03 16:47:22 -0300773 data += i + INTER_FRAME;
774 len -= i + INTER_FRAME;
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300775 i = 0;
Jean-Francois Moine23d9e472008-09-03 16:47:22 -0300776 if (len > -LUM_OFFSET)
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300777 sd->lum_sum += data[-LUM_OFFSET];
778 if (len < 0) {
779 sd->tosof = -len;
780 break;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300781 }
Jean-Francois Moine4a186252008-09-03 16:48:02 -0300782 jpeg_put_header(gspca_dev, frame, sd->qindex, 0x21);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300783 break;
784 }
785 }
Jean-Francois Moine8559e8d2008-09-03 16:47:27 -0300786 gspca_frame_add(gspca_dev, INTER_PACKET,
787 frame, data, i);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300788}
789
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300790static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
791{
792 struct sd *sd = (struct sd *) gspca_dev;
793
794 sd->brightness = val;
795 if (gspca_dev->streaming)
796 setbrightness(gspca_dev);
797 return 0;
798}
799
800static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
801{
802 struct sd *sd = (struct sd *) gspca_dev;
803
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300804 *val = sd->brightness;
805 return 0;
806}
807
808static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
809{
810 struct sd *sd = (struct sd *) gspca_dev;
811
812 sd->contrast = val;
813 if (gspca_dev->streaming)
814 setcontrast(gspca_dev);
815 return 0;
816}
817
818static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
819{
820 struct sd *sd = (struct sd *) gspca_dev;
821
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300822 *val = sd->contrast;
823 return 0;
824}
825
826static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
827{
828 struct sd *sd = (struct sd *) gspca_dev;
829
830 sd->colors = val;
831 if (gspca_dev->streaming)
832 setcolors(gspca_dev);
833 return 0;
834}
835
836static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
837{
838 struct sd *sd = (struct sd *) gspca_dev;
839
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300840 *val = sd->colors;
841 return 0;
842}
843
844static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
845{
846 struct sd *sd = (struct sd *) gspca_dev;
847
848 sd->autogain = val;
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300849 if (gspca_dev->streaming)
850 setautogain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300851 return 0;
852}
853
854static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
855{
856 struct sd *sd = (struct sd *) gspca_dev;
857
858 *val = sd->autogain;
859 return 0;
860}
861
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300862static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
863{
864 struct sd *sd = (struct sd *) gspca_dev;
865
866 sd->hflip = val;
867 if (gspca_dev->streaming)
868 sethvflip(gspca_dev);
869 return 0;
870}
871
872static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
873{
874 struct sd *sd = (struct sd *) gspca_dev;
875
876 *val = sd->hflip;
877 return 0;
878}
879
880static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
881{
882 struct sd *sd = (struct sd *) gspca_dev;
883
884 sd->vflip = val;
885 if (gspca_dev->streaming)
886 sethvflip(gspca_dev);
887 return 0;
888}
889
890static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
891{
892 struct sd *sd = (struct sd *) gspca_dev;
893
894 *val = sd->vflip;
895 return 0;
896}
897
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300898/* sub-driver description */
899static struct sd_desc sd_desc = {
900 .name = MODULE_NAME,
901 .ctrls = sd_ctrls,
902 .nctrls = ARRAY_SIZE(sd_ctrls),
903 .config = sd_config,
904 .open = sd_open,
905 .start = sd_start,
906 .stopN = sd_stopN,
907 .stop0 = sd_stop0,
908 .close = sd_close,
909 .pkt_scan = sd_pkt_scan,
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300910 .dq_callback = do_autogain,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300911};
912
913/* -- module initialisation -- */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300914static __devinitdata struct usb_device_id device_table[] = {
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300915 {USB_DEVICE(0x093a, 0x2600), .driver_info = SENSOR_PAC7311},
916 {USB_DEVICE(0x093a, 0x2601), .driver_info = SENSOR_PAC7311},
917 {USB_DEVICE(0x093a, 0x2603), .driver_info = SENSOR_PAC7311},
918 {USB_DEVICE(0x093a, 0x2608), .driver_info = SENSOR_PAC7311},
919 {USB_DEVICE(0x093a, 0x260e), .driver_info = SENSOR_PAC7311},
920 {USB_DEVICE(0x093a, 0x260f), .driver_info = SENSOR_PAC7311},
921 {USB_DEVICE(0x093a, 0x2621), .driver_info = SENSOR_PAC7302},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300922 {}
923};
924MODULE_DEVICE_TABLE(usb, device_table);
925
926/* -- device connect -- */
927static int sd_probe(struct usb_interface *intf,
928 const struct usb_device_id *id)
929{
930 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
931 THIS_MODULE);
932}
933
934static struct usb_driver sd_driver = {
935 .name = MODULE_NAME,
936 .id_table = device_table,
937 .probe = sd_probe,
938 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -0300939#ifdef CONFIG_PM
940 .suspend = gspca_suspend,
941 .resume = gspca_resume,
942#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300943};
944
945/* -- module insert / remove -- */
946static int __init sd_mod_init(void)
947{
948 if (usb_register(&sd_driver) < 0)
949 return -1;
Jean-Francois Moine10b0e962008-07-22 05:35:10 -0300950 PDEBUG(D_PROBE, "registered");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300951 return 0;
952}
953static void __exit sd_mod_exit(void)
954{
955 usb_deregister(&sd_driver);
956 PDEBUG(D_PROBE, "deregistered");
957}
958
959module_init(sd_mod_init);
960module_exit(sd_mod_exit);