blob: 85d9ddbc5b7fa254be373ccfd6027a477ca3cab2 [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]* */
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300223 0xff, 1, 0x00, /* page 0 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300224 0x00, 12, 0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80,
225 0x00, 0x00, 0x00, 0x00,
226 0x0d, 24, 0x03, 0x01, 0x00, 0xb5, 0x07, 0xcb, 0x00, 0x00,
227 0x07, 0xc8, 0x00, 0xea, 0x07, 0xcf, 0x07, 0xf7,
228 0x07, 0x7e, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x11,
229 0x26, 2, 0xaa, 0xaa,
230 0x2e, 1, 0x31,
231 0x38, 1, 0x01,
232 0x3a, 3, 0x14, 0xff, 0x5a,
233 0x43, 11, 0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11,
234 0x00, 0x54, 0x11,
235 0x55, 1, 0x00,
236 0x62, 4, 0x10, 0x1e, 0x1e, 0x18,
237 0x6b, 1, 0x00,
238 0x6e, 3, 0x08, 0x06, 0x00,
239 0x72, 3, 0x00, 0xff, 0x00,
240 0x7d, 23, 0x01, 0x01, 0x58, 0x46, 0x50, 0x3c, 0x50, 0x3c,
241 0x54, 0x46, 0x54, 0x56, 0x52, 0x50, 0x52, 0x50,
242 0x56, 0x64, 0xa4, 0x00, 0xda, 0x00, 0x00,
243 0xa2, 10, 0x22, 0x2c, 0x3c, 0x54, 0x69, 0x7c, 0x9c, 0xb9,
244 0xd2, 0xeb,
245 0xaf, 1, 0x02,
246 0xb5, 2, 0x08, 0x08,
247 0xb8, 2, 0x08, 0x88,
248 0xc4, 4, 0xae, 0x01, 0x04, 0x01,
249 0xcc, 1, 0x00,
250 0xd1, 11, 0x01, 0x30, 0x49, 0x5e, 0x6f, 0x7f, 0x8e, 0xa9,
251 0xc1, 0xd7, 0xec,
252 0xdc, 1, 0x01,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300253 0xff, 1, 0x01, /* page 1 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300254 0x12, 3, 0x02, 0x00, 0x01,
255 0x3e, 2, 0x00, 0x00,
256 0x76, 5, 0x01, 0x20, 0x40, 0x00, 0xf2,
257 0x7c, 1, 0x00,
258 0x7f, 10, 0x4b, 0x0f, 0x01, 0x2c, 0x02, 0x58, 0x03, 0x20,
259 0x02, 0x00,
260 0x96, 5, 0x01, 0x10, 0x04, 0x01, 0x04,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300261 0xc8, 14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300262 0x07, 0x00, 0x01, 0x07, 0x04, 0x01,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300263 0xd8, 1, 0x01,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300264 0xdb, 2, 0x00, 0x01,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300265 0xde, 7, 0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x00,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300266 0xe6, 4, 0x00, 0x00, 0x00, 0x01,
267 0xeb, 1, 0x00,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300268 0xff, 1, 0x02, /* page 2 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300269 0x22, 1, 0x00,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300270 0xff, 1, 0x03, /* page 3 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300271 0x00, 255, /* load the page 3 */
272 0x11, 1, 0x01,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300273 0xff, 1, 0x02, /* page 2 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300274 0x13, 1, 0x00,
275 0x22, 4, 0x1f, 0xa4, 0xf0, 0x96,
276 0x27, 2, 0x14, 0x0c,
277 0x2a, 5, 0xc8, 0x00, 0x18, 0x12, 0x22,
278 0x64, 8, 0x00, 0x00, 0xf0, 0x01, 0x14, 0x44, 0x44, 0x44,
279 0x6e, 1, 0x08,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300280 0xff, 1, 0x03, /* page 1 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300281 0x78, 1, 0x00,
282 0, 0 /* end of sequence */
283};
284
285/* page 3 - the value 0xaa says skip the index - see reg_w_page() */
286static const __u8 page3_7302[] = {
287 0x90, 0x40, 0x03, 0x50, 0xc2, 0x01, 0x14, 0x16,
288 0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00,
289 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
290 0x00, 0x00, 0x00, 0x47, 0x01, 0xb3, 0x01, 0x00,
291 0x00, 0x08, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x21,
292 0x00, 0x00, 0x00, 0x54, 0xf4, 0x02, 0x52, 0x54,
293 0xa4, 0xb8, 0xe0, 0x2a, 0xf6, 0x00, 0x00, 0x00,
294 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
295 0x00, 0xfc, 0x00, 0xf2, 0x1f, 0x04, 0x00, 0x00,
296 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x10, 0x00, 0x00,
297 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
298 0x00, 0x40, 0xff, 0x03, 0x19, 0x00, 0x00, 0x00,
299 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
300 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0xc8, 0xc8,
301 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,
302 0x08, 0x10, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00,
303 0x01, 0x00, 0x02, 0x47, 0x00, 0x00, 0x00, 0x00,
304 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
305 0x00, 0x02, 0xfa, 0x00, 0x64, 0x5a, 0x28, 0x00,
306 0x00
307};
308
309/* pac 7311 */
310static const __u8 probe_7311[] = {
311 0x78, 0x40, /* Bit_0=start stream, Bit_7=LED */
312 0x78, 0x40, /* Bit_0=start stream, Bit_7=LED */
313 0x78, 0x44, /* Bit_0=start stream, Bit_7=LED */
314 0xff, 0x04,
315 0x27, 0x80,
316 0x28, 0xca,
317 0x29, 0x53,
318 0x2a, 0x0e,
319 0xff, 0x01,
320 0x3e, 0x20,
321};
322
323static const __u8 start_7311[] = {
324/* index, len, [value]* */
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300325 0xff, 1, 0x01, /* page 1 */
326 0x02, 43, 0x48, 0x0a, 0x40, 0x08, 0x00, 0x00, 0x08, 0x00,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300327 0x06, 0xff, 0x11, 0xff, 0x5a, 0x30, 0x90, 0x4c,
328 0x00, 0x07, 0x00, 0x0a, 0x10, 0x00, 0xa0, 0x10,
329 0x02, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x01, 0x00,
330 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
331 0x00, 0x00, 0x00,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300332 0x3e, 42, 0x00, 0x00, 0x78, 0x52, 0x4a, 0x52, 0x78, 0x6e,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300333 0x48, 0x46, 0x48, 0x6e, 0x5f, 0x49, 0x42, 0x49,
334 0x5f, 0x5f, 0x49, 0x42, 0x49, 0x5f, 0x6e, 0x48,
335 0x46, 0x48, 0x6e, 0x78, 0x52, 0x4a, 0x52, 0x78,
336 0x00, 0x00, 0x09, 0x1b, 0x34, 0x49, 0x5c, 0x9b,
337 0xd0, 0xff,
338 0x78, 6, 0x44, 0x00, 0xf2, 0x01, 0x01, 0x80,
339 0x7f, 18, 0x2a, 0x1c, 0x00, 0xc8, 0x02, 0x58, 0x03, 0x84,
340 0x12, 0x00, 0x1a, 0x04, 0x08, 0x0c, 0x10, 0x14,
341 0x18, 0x20,
342 0x96, 3, 0x01, 0x08, 0x04,
343 0xa0, 4, 0x44, 0x44, 0x44, 0x04,
344 0xf0, 13, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x20, 0x00,
345 0x3f, 0x00, 0x0a, 0x01, 0x00,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300346 0xff, 1, 0x04, /* page 4 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300347 0x00, 254, /* load the page 4 */
348 0x11, 1, 0x01,
349 0, 0 /* end of sequence */
350};
351
352/* page 4 - the value 0xaa says skip the index - see reg_w_page() */
353static const __u8 page4_7311[] = {
354 0xaa, 0xaa, 0x04, 0x54, 0x07, 0x2b, 0x09, 0x0f,
355 0x09, 0x00, 0xaa, 0xaa, 0x07, 0x00, 0x00, 0x62,
356 0x08, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
357 0x00, 0x00, 0x00, 0x03, 0xa0, 0x01, 0xf4, 0xaa,
358 0xaa, 0x00, 0x08, 0xaa, 0x03, 0xaa, 0x00, 0x01,
359 0xca, 0x10, 0x06, 0x78, 0x00, 0x00, 0x00, 0x00,
360 0x23, 0x28, 0x04, 0x11, 0x00, 0x00
361};
362
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300363static void reg_w_buf(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300364 __u8 index,
365 const char *buffer, int len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300366{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300367 memcpy(gspca_dev->usb_buf, buffer, len);
368 usb_control_msg(gspca_dev->dev,
369 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300370 1, /* request */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300371 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300372 0, /* value */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300373 index, gspca_dev->usb_buf, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300374 500);
375}
376
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300377static __u8 reg_r(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300378 __u8 index)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300379{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300380 usb_control_msg(gspca_dev->dev,
381 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300382 0, /* request */
383 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
384 0, /* value */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300385 index, gspca_dev->usb_buf, 1,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300386 500);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300387 return gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300388}
389
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300390static void reg_w(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300391 __u8 index,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300392 __u8 value)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300393{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300394 gspca_dev->usb_buf[0] = value;
395 usb_control_msg(gspca_dev->dev,
396 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300397 0, /* request */
398 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300399 value, index, gspca_dev->usb_buf, 1,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300400 500);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300401}
402
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300403static void reg_w_seq(struct gspca_dev *gspca_dev,
404 const __u8 *seq, int len)
405{
406 while (--len >= 0) {
407 reg_w(gspca_dev, seq[0], seq[1]);
408 seq += 2;
409 }
410}
411
412/* load the beginning of a page */
413static void reg_w_page(struct gspca_dev *gspca_dev,
414 const __u8 *page, int len)
415{
416 int index;
417
418 for (index = 0; index < len; index++) {
419 if (page[index] == 0xaa) /* skip this index */
420 continue;
421 gspca_dev->usb_buf[0] = page[index];
422 usb_control_msg(gspca_dev->dev,
423 usb_sndctrlpipe(gspca_dev->dev, 0),
424 0, /* request */
425 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
426 0, index, gspca_dev->usb_buf, 1,
427 500);
428 }
429}
430
431/* output a variable sequence */
432static void reg_w_var(struct gspca_dev *gspca_dev,
433 const __u8 *seq)
434{
435 int index, len;
436
437 for (;;) {
438 index = *seq++;
439 len = *seq++;
440 switch (len) {
441 case 0:
442 return;
443 case 254:
444 reg_w_page(gspca_dev, page4_7311, sizeof page4_7311);
445 break;
446 case 255:
447 reg_w_page(gspca_dev, page3_7302, sizeof page3_7302);
448 break;
449 default:
450 if (len > 32) {
451 PDEBUG(D_ERR|D_STREAM,
452 "Incorrect variable sequence");
453 return;
454 }
455 while (len > 0) {
456 if (len < 8) {
457 reg_w_buf(gspca_dev, index, seq, len);
458 seq += len;
459 break;
460 }
461 reg_w_buf(gspca_dev, index, seq, 8);
462 seq += 8;
463 index += 8;
464 len -= 8;
465 }
466 }
467 }
468 /* not reached */
469}
470
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300471/* this function is called at probe time */
472static int sd_config(struct gspca_dev *gspca_dev,
473 const struct usb_device_id *id)
474{
475 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300476 struct cam *cam;
477
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300478 cam = &gspca_dev->cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300479 cam->epaddr = 0x05;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300480
481 sd->sensor = id->driver_info;
482 if (sd->sensor == SENSOR_PAC7302) {
483 PDEBUG(D_CONF, "Find Sensor PAC7302");
484 reg_w_seq(gspca_dev, probe_7302, sizeof probe_7302);
485
486 cam->cam_mode = &vga_mode[2]; /* only 640x480 */
487 cam->nmodes = 1;
488 } else {
489 PDEBUG(D_CONF, "Find Sensor PAC7311");
490 reg_w_seq(gspca_dev, probe_7302, sizeof probe_7302);
491
492 cam->cam_mode = vga_mode;
493 cam->nmodes = ARRAY_SIZE(vga_mode);
494 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300495
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300496 sd->brightness = BRIGHTNESS_DEF;
497 sd->contrast = CONTRAST_DEF;
498 sd->colors = COLOR_DEF;
499 sd->autogain = AUTOGAIN_DEF;
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300500 sd->ag_cnt = -1;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300501 return 0;
502}
503
504static void setbrightness(struct gspca_dev *gspca_dev)
505{
506 struct sd *sd = (struct sd *) gspca_dev;
507 int brightness;
508
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300509 if (sd->sensor == SENSOR_PAC7302)
510 return;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300511/*jfm: inverted?*/
512 brightness = BRIGHTNESS_MAX - sd->brightness;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300513 reg_w(gspca_dev, 0xff, 0x04);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300514 reg_w(gspca_dev, 0x0f, brightness);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300515 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300516 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300517 PDEBUG(D_CONF|D_STREAM, "brightness: %i", brightness);
518}
519
520static void setcontrast(struct gspca_dev *gspca_dev)
521{
522 struct sd *sd = (struct sd *) gspca_dev;
523
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300524 if (sd->sensor == SENSOR_PAC7302)
525 return;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300526 reg_w(gspca_dev, 0xff, 0x01);
527 reg_w(gspca_dev, 0x80, sd->contrast);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300528 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300529 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300530 PDEBUG(D_CONF|D_STREAM, "contrast: %i", sd->contrast);
531}
532
533static void setcolors(struct gspca_dev *gspca_dev)
534{
535 struct sd *sd = (struct sd *) gspca_dev;
536
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300537 if (sd->sensor == SENSOR_PAC7302)
538 return;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300539 reg_w(gspca_dev, 0xff, 0x01);
540 reg_w(gspca_dev, 0x10, sd->colors);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300541 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300542 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300543 PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
544}
545
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300546static void setautogain(struct gspca_dev *gspca_dev)
547{
548 struct sd *sd = (struct sd *) gspca_dev;
549
550 if (sd->autogain) {
551 sd->lum_sum = 0;
552 sd->ag_cnt = AG_CNT_START;
553 } else {
554 sd->ag_cnt = -1;
555 }
556}
557
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300558/* this function is called at open time */
559static int sd_open(struct gspca_dev *gspca_dev)
560{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300561 reg_w(gspca_dev, 0x78, 0x00); /* Turn on LED */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300562 return 0;
563}
564
565static void sd_start(struct gspca_dev *gspca_dev)
566{
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300567 struct sd *sd = (struct sd *) gspca_dev;
568
569 sd->ffnb = 0;
570 sd->tosof = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300571
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300572 if (sd->sensor == SENSOR_PAC7302)
573 reg_w_var(gspca_dev, start_7302);
574 else
575 reg_w_var(gspca_dev, start_7311);
576
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300577 setcontrast(gspca_dev);
578 setbrightness(gspca_dev);
579 setcolors(gspca_dev);
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300580 setautogain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300581
582 /* set correct resolution */
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300583 switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300584 case 2: /* 160x120 pac7311 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300585 reg_w(gspca_dev, 0xff, 0x04);
586 reg_w(gspca_dev, 0x02, 0x03);
587 reg_w(gspca_dev, 0xff, 0x01);
588 reg_w(gspca_dev, 0x08, 0x09);
589 reg_w(gspca_dev, 0x17, 0x20);
590 reg_w(gspca_dev, 0x1b, 0x00);
591/* reg_w(gspca_dev, 0x80, 0x69); */
592 reg_w(gspca_dev, 0x87, 0x10);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300593 break;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300594 case 1: /* 320x240 pac7311 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300595 reg_w(gspca_dev, 0xff, 0x04);
596 reg_w(gspca_dev, 0x02, 0x03);
597 reg_w(gspca_dev, 0xff, 0x01);
598 reg_w(gspca_dev, 0x08, 0x09);
599 reg_w(gspca_dev, 0x17, 0x30);
600/* reg_w(gspca_dev, 0x80, 0x3f); */
601 reg_w(gspca_dev, 0x87, 0x11);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300602 break;
603 case 0: /* 640x480 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300604 if (sd->sensor == SENSOR_PAC7302)
605 break;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300606 reg_w(gspca_dev, 0xff, 0x04);
607 reg_w(gspca_dev, 0x02, 0x03);
608 reg_w(gspca_dev, 0xff, 0x01);
609 reg_w(gspca_dev, 0x08, 0x08);
610 reg_w(gspca_dev, 0x17, 0x00);
611/* reg_w(gspca_dev, 0x80, 0x1c); */
612 reg_w(gspca_dev, 0x87, 0x12);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300613 break;
614 }
615
616 /* start stream */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300617 reg_w(gspca_dev, 0xff, 0x01);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300618 if (sd->sensor == SENSOR_PAC7302) {
619 reg_w(gspca_dev, 0x78, 0x01);
620 reg_w(gspca_dev, 0xff, 0x01);
621 reg_w(gspca_dev, 0x78, 0x01);
622 } else {
623 reg_w(gspca_dev, 0x78, 0x04);
624 reg_w(gspca_dev, 0x78, 0x05);
625 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300626}
627
628static void sd_stopN(struct gspca_dev *gspca_dev)
629{
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300630 struct sd *sd = (struct sd *) gspca_dev;
631
632 if (sd->sensor == SENSOR_PAC7302) {
633 reg_w(gspca_dev, 0x78, 0x00);
634 reg_w(gspca_dev, 0x78, 0x00);
635 return;
636 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300637 reg_w(gspca_dev, 0xff, 0x04);
638 reg_w(gspca_dev, 0x27, 0x80);
639 reg_w(gspca_dev, 0x28, 0xca);
640 reg_w(gspca_dev, 0x29, 0x53);
641 reg_w(gspca_dev, 0x2a, 0x0e);
642 reg_w(gspca_dev, 0xff, 0x01);
643 reg_w(gspca_dev, 0x3e, 0x20);
644 reg_w(gspca_dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */
645 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
646 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300647}
648
649static void sd_stop0(struct gspca_dev *gspca_dev)
650{
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300651 struct sd *sd = (struct sd *) gspca_dev;
652
653 if (sd->sensor == SENSOR_PAC7302) {
654 reg_w(gspca_dev, 0xff, 0x01);
655 reg_w(gspca_dev, 0x78, 0x40);
656 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300657}
658
659/* this function is called at close time */
660static void sd_close(struct gspca_dev *gspca_dev)
661{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300662}
663
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300664static void do_autogain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300665{
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300666 struct sd *sd = (struct sd *) gspca_dev;
667 int luma;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300668 int luma_mean = 128;
669 int luma_delta = 20;
670 __u8 spring = 5;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300671 int Gbright;
672
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300673 if (!atomic_read(&sd->do_gain))
674 return;
675 atomic_set(&sd->do_gain, 0);
676
677 luma = atomic_read(&sd->avg_lum);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300678 Gbright = reg_r(gspca_dev, 0x02);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300679 PDEBUG(D_FRAM, "luma mean %d", luma);
680 if (luma < luma_mean - luma_delta ||
681 luma > luma_mean + luma_delta) {
682 Gbright += (luma_mean - luma) >> spring;
683 if (Gbright > 0x1a)
684 Gbright = 0x1a;
685 else if (Gbright < 4)
686 Gbright = 4;
687 PDEBUG(D_FRAM, "gbright %d", Gbright);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300688 if (sd->sensor == SENSOR_PAC7302) {
689 reg_w(gspca_dev, 0xff, 0x03);
690 reg_w(gspca_dev, 0x10, Gbright);
691 /* load registers to sensor (Bit 0, auto clear) */
692 reg_w(gspca_dev, 0x11, 0x01);
693 } else {
694 reg_w(gspca_dev, 0xff, 0x04);
695 reg_w(gspca_dev, 0x0f, Gbright);
696 /* load registers to sensor (Bit 0, auto clear) */
697 reg_w(gspca_dev, 0x11, 0x01);
698 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300699 }
700}
701
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300702/* output the jpeg header */
703static void put_jpeg_head(struct gspca_dev *gspca_dev,
704 struct gspca_frame *frame)
705{
Jean-Francois Moine8559e8d2008-09-03 16:47:27 -0300706 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300707 unsigned char tmpbuf[4];
708
Jean-Francois Moine8559e8d2008-09-03 16:47:27 -0300709 if (sd->ag_cnt >= 0) {
710 if (--sd->ag_cnt < 0) {
711 sd->ag_cnt = AG_CNT_START;
712 atomic_set(&sd->avg_lum, sd->lum_sum / AG_CNT_START);
713 atomic_set(&sd->do_gain, 1);
714 }
715 }
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300716 gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
717 (__u8 *) pac7311_jpeg_header,
718 12);
719 tmpbuf[0] = gspca_dev->height >> 8;
720 tmpbuf[1] = gspca_dev->height & 0xff;
721 tmpbuf[2] = gspca_dev->width >> 8;
722 tmpbuf[3] = gspca_dev->width & 0xff;
723 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
724 tmpbuf, 4);
725 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
726 (__u8 *) &pac7311_jpeg_header[16],
727 PAC7311_JPEG_HEADER_SIZE - 16);
728}
729
730/* this function is run at interrupt level */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300731static void sd_pkt_scan(struct gspca_dev *gspca_dev,
732 struct gspca_frame *frame, /* target */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300733 __u8 *data, /* isoc packet */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300734 int len) /* iso packet length */
735{
736 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300737 int i;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300738
Jean-Francois Moine8559e8d2008-09-03 16:47:27 -0300739#define INTER_FRAME 0x53 /* eof + inter frame + sof */
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300740#define LUM_OFFSET 0x1e /* reverse offset / start of frame */
741
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300742/*fixme:test+*/
743/* dump the packet */
744 if (gspca_debug & 0x200) {
745 static char tmp[50];
746
747 PDEBUG(0x200, "pkt_scan");
748 tmp[0] = 0;
749 for (i = 0; i < len; i++) {
750 if (i % 16 == 0 && i != 0) {
751 PDEBUG(0x200, "%s", tmp);
752 tmp[0] = 0;
753 }
754 sprintf(&tmp[(i % 16) * 3], "%02x ", data[i]);
755 }
756 if (tmp[0] != 0)
757 PDEBUG(0x200, "%s", tmp);
758 }
759/*fixme:test-*/
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300760 /*
761 * inside a frame, there may be:
762 * escaped ff ('ff 00')
763 * sequences'ff ff ff xx' to remove
764 * end of frame ('ff d9')
765 * at the end of frame, there are:
766 * ff d9 end of frame
767 * 0x33 bytes
768 * one byte luminosity
769 * 0x16 bytes
770 * ff ff 00 ff 96 62 44 start of frame header
771 */
772
773 if (sd->tosof == 0) { /* if inside a frame */
774
775 /* check for 'ff ff ff xx' at start and at end of packet */
Jean-Francois Moine8559e8d2008-09-03 16:47:27 -0300776 /* (len is always >= 3 and xx never ff) */
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300777 switch (sd->ffnb) {
778 case 1:
Jean-Francois Moine8559e8d2008-09-03 16:47:27 -0300779 if (data[0] != 0xff) { /* can be '00' only */
780 __u8 ff;
781
782 sd->ffnb = 0;
783 ff = 0xff;
784 gspca_frame_add(gspca_dev, INTER_PACKET,
785 frame, &ff, 1);
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300786 break; /* keep 'ff 00' */
Jean-Francois Moine8559e8d2008-09-03 16:47:27 -0300787 }
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300788 /* fall thru */
789 case 2:
790 case 3:
791 data += 4 - sd->ffnb;
792 len -= 4 - sd->ffnb;
793 sd->ffnb = 0;
794 break;
795 }
796 if (data[len - 1] == 0xff) {
797 if (data[len - 2] == 0xff) {
798 if (data[len - 3] == 0xff) {
799 sd->ffnb = 3;
800 len -= 3;
801 } else {
802 sd->ffnb = 2;
803 len -= 2;
804 }
805 } else {
806 sd->ffnb = 1;
807 len--;
808 }
809 }
810 } else { /* outside a frame */
811
Jean-Francois Moine8559e8d2008-09-03 16:47:27 -0300812 /* get the luminosity and go to the start of frame */
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300813 data += sd->tosof;
814 len -= sd->tosof;
815 if (sd->tosof > LUM_OFFSET)
816 sd->lum_sum += data[-LUM_OFFSET];
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300817 sd->tosof = 0;
Jean-Francois Moine8559e8d2008-09-03 16:47:27 -0300818 put_jpeg_head(gspca_dev, frame);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300819 }
820
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300821 for (i = 0; i < len; i++) {
822 if (data[i] != 0xff)
823 continue;
824 switch (data[i + 1]) {
825 case 0xd9: /* end of frame */
826 frame = gspca_frame_add(gspca_dev,
827 LAST_PACKET,
Jean-Francois Moine8559e8d2008-09-03 16:47:27 -0300828 frame, data, i + 2);
Jean-Francois Moine23d9e472008-09-03 16:47:22 -0300829 data += i + INTER_FRAME;
830 len -= i + INTER_FRAME;
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300831 i = 0;
Jean-Francois Moine23d9e472008-09-03 16:47:22 -0300832 if (len > -LUM_OFFSET)
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300833 sd->lum_sum += data[-LUM_OFFSET];
834 if (len < 0) {
835 sd->tosof = -len;
836 break;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300837 }
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300838 put_jpeg_head(gspca_dev, frame);
839 break;
840 case 0xff: /* 'ff ff ff xx' */
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300841/*fixme:test+*/
842/* is there a start of frame ? */
843 if (data[i + 2] == 0x00) {
844 static __u8 ffd9[2] = {0xff, 0xd9};
845
846 gspca_frame_add(gspca_dev,
847 INTER_PACKET,
848 frame, data,
849 i + 7 - INTER_FRAME);
850 frame = gspca_frame_add(gspca_dev,
851 LAST_PACKET,
852 frame, ffd9, 2);
853 data += i + 7;
854 len -= i + 7;
855 i = 0;
856 put_jpeg_head(gspca_dev, frame);
857 break;
858 }
859/*fixme:test-*/
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300860 gspca_frame_add(gspca_dev, INTER_PACKET,
861 frame, data, i);
862 data += i + 4;
863 len -= i + 4;
864 i = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300865 break;
866 }
867 }
Jean-Francois Moine8559e8d2008-09-03 16:47:27 -0300868 gspca_frame_add(gspca_dev, INTER_PACKET,
869 frame, data, i);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300870}
871
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300872static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
873{
874 struct sd *sd = (struct sd *) gspca_dev;
875
876 sd->brightness = val;
877 if (gspca_dev->streaming)
878 setbrightness(gspca_dev);
879 return 0;
880}
881
882static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
883{
884 struct sd *sd = (struct sd *) gspca_dev;
885
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300886 *val = sd->brightness;
887 return 0;
888}
889
890static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
891{
892 struct sd *sd = (struct sd *) gspca_dev;
893
894 sd->contrast = val;
895 if (gspca_dev->streaming)
896 setcontrast(gspca_dev);
897 return 0;
898}
899
900static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
901{
902 struct sd *sd = (struct sd *) gspca_dev;
903
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300904 *val = sd->contrast;
905 return 0;
906}
907
908static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
909{
910 struct sd *sd = (struct sd *) gspca_dev;
911
912 sd->colors = val;
913 if (gspca_dev->streaming)
914 setcolors(gspca_dev);
915 return 0;
916}
917
918static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
919{
920 struct sd *sd = (struct sd *) gspca_dev;
921
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300922 *val = sd->colors;
923 return 0;
924}
925
926static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
927{
928 struct sd *sd = (struct sd *) gspca_dev;
929
930 sd->autogain = val;
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300931 if (gspca_dev->streaming)
932 setautogain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300933 return 0;
934}
935
936static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
937{
938 struct sd *sd = (struct sd *) gspca_dev;
939
940 *val = sd->autogain;
941 return 0;
942}
943
944/* sub-driver description */
945static struct sd_desc sd_desc = {
946 .name = MODULE_NAME,
947 .ctrls = sd_ctrls,
948 .nctrls = ARRAY_SIZE(sd_ctrls),
949 .config = sd_config,
950 .open = sd_open,
951 .start = sd_start,
952 .stopN = sd_stopN,
953 .stop0 = sd_stop0,
954 .close = sd_close,
955 .pkt_scan = sd_pkt_scan,
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300956 .dq_callback = do_autogain,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300957};
958
959/* -- module initialisation -- */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300960static __devinitdata struct usb_device_id device_table[] = {
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300961 {USB_DEVICE(0x093a, 0x2600), .driver_info = SENSOR_PAC7311},
962 {USB_DEVICE(0x093a, 0x2601), .driver_info = SENSOR_PAC7311},
963 {USB_DEVICE(0x093a, 0x2603), .driver_info = SENSOR_PAC7311},
964 {USB_DEVICE(0x093a, 0x2608), .driver_info = SENSOR_PAC7311},
965 {USB_DEVICE(0x093a, 0x260e), .driver_info = SENSOR_PAC7311},
966 {USB_DEVICE(0x093a, 0x260f), .driver_info = SENSOR_PAC7311},
967 {USB_DEVICE(0x093a, 0x2621), .driver_info = SENSOR_PAC7302},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300968 {}
969};
970MODULE_DEVICE_TABLE(usb, device_table);
971
972/* -- device connect -- */
973static int sd_probe(struct usb_interface *intf,
974 const struct usb_device_id *id)
975{
976 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
977 THIS_MODULE);
978}
979
980static struct usb_driver sd_driver = {
981 .name = MODULE_NAME,
982 .id_table = device_table,
983 .probe = sd_probe,
984 .disconnect = gspca_disconnect,
985};
986
987/* -- module insert / remove -- */
988static int __init sd_mod_init(void)
989{
990 if (usb_register(&sd_driver) < 0)
991 return -1;
Jean-Francois Moine10b0e962008-07-22 05:35:10 -0300992 PDEBUG(D_PROBE, "registered");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300993 return 0;
994}
995static void __exit sd_mod_exit(void)
996{
997 usb_deregister(&sd_driver);
998 PDEBUG(D_PROBE, "deregistered");
999}
1000
1001module_init(sd_mod_init);
1002module_exit(sd_mod_exit);