blob: 3abc018f96906f891d7c3bc0cff1b362f19f8e6d [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;
43
Jean-Francois Moinee52a5572008-09-03 16:47:21 -030044 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,
Jean-Francois Moinedff6d322008-09-03 16:47:57 -030085#define CONTRAST_MAX 255
86 .maximum = CONTRAST_MAX,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030087 .step = 1,
Jean-Francois Moinedff6d322008-09-03 16:47:57 -030088#define CONTRAST_DEF 60
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -030089 .default_value = CONTRAST_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030090 },
91 .set = sd_setcontrast,
92 .get = sd_getcontrast,
93 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030094 {
95 {
96 .id = V4L2_CID_SATURATION,
97 .type = V4L2_CTRL_TYPE_INTEGER,
Jean-Francois Moinedff6d322008-09-03 16:47:57 -030098 .name = "Saturation",
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030099 .minimum = 0,
100 .maximum = 255,
101 .step = 1,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300102#define COLOR_DEF 127
103 .default_value = COLOR_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300104 },
105 .set = sd_setcolors,
106 .get = sd_getcolors,
107 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300108 {
109 {
110 .id = V4L2_CID_AUTOGAIN,
111 .type = V4L2_CTRL_TYPE_BOOLEAN,
112 .name = "Auto Gain",
113 .minimum = 0,
114 .maximum = 1,
115 .step = 1,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300116#define AUTOGAIN_DEF 1
117 .default_value = AUTOGAIN_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300118 },
119 .set = sd_setautogain,
120 .get = sd_getautogain,
121 },
122};
123
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300124static struct v4l2_pix_format vga_mode[] = {
Jean-Francois Moinef75c4952008-09-03 16:47:35 -0300125 {160, 120, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300126 .bytesperline = 160,
127 .sizeimage = 160 * 120 * 3 / 8 + 590,
128 .colorspace = V4L2_COLORSPACE_JPEG,
129 .priv = 2},
Jean-Francois Moinef75c4952008-09-03 16:47:35 -0300130 {320, 240, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300131 .bytesperline = 320,
132 .sizeimage = 320 * 240 * 3 / 8 + 590,
133 .colorspace = V4L2_COLORSPACE_JPEG,
134 .priv = 1},
Jean-Francois Moinef75c4952008-09-03 16:47:35 -0300135 {640, 480, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300136 .bytesperline = 640,
137 .sizeimage = 640 * 480 * 3 / 8 + 590,
138 .colorspace = V4L2_COLORSPACE_JPEG,
139 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300140};
141
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300142/* pac 7302 */
143static const __u8 probe_7302[] = {
144/* index,value */
145 0xff, 0x01, /* page 1 */
146 0x78, 0x00, /* deactivate */
147 0xff, 0x01,
148 0x78, 0x40, /* led off */
149};
150static const __u8 start_7302[] = {
151/* index, len, [value]* */
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300152 0xff, 1, 0x00, /* page 0 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300153 0x00, 12, 0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80,
154 0x00, 0x00, 0x00, 0x00,
155 0x0d, 24, 0x03, 0x01, 0x00, 0xb5, 0x07, 0xcb, 0x00, 0x00,
156 0x07, 0xc8, 0x00, 0xea, 0x07, 0xcf, 0x07, 0xf7,
157 0x07, 0x7e, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x11,
158 0x26, 2, 0xaa, 0xaa,
159 0x2e, 1, 0x31,
160 0x38, 1, 0x01,
161 0x3a, 3, 0x14, 0xff, 0x5a,
162 0x43, 11, 0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11,
163 0x00, 0x54, 0x11,
164 0x55, 1, 0x00,
165 0x62, 4, 0x10, 0x1e, 0x1e, 0x18,
166 0x6b, 1, 0x00,
167 0x6e, 3, 0x08, 0x06, 0x00,
168 0x72, 3, 0x00, 0xff, 0x00,
169 0x7d, 23, 0x01, 0x01, 0x58, 0x46, 0x50, 0x3c, 0x50, 0x3c,
170 0x54, 0x46, 0x54, 0x56, 0x52, 0x50, 0x52, 0x50,
171 0x56, 0x64, 0xa4, 0x00, 0xda, 0x00, 0x00,
172 0xa2, 10, 0x22, 0x2c, 0x3c, 0x54, 0x69, 0x7c, 0x9c, 0xb9,
173 0xd2, 0xeb,
174 0xaf, 1, 0x02,
175 0xb5, 2, 0x08, 0x08,
176 0xb8, 2, 0x08, 0x88,
177 0xc4, 4, 0xae, 0x01, 0x04, 0x01,
178 0xcc, 1, 0x00,
179 0xd1, 11, 0x01, 0x30, 0x49, 0x5e, 0x6f, 0x7f, 0x8e, 0xa9,
180 0xc1, 0xd7, 0xec,
181 0xdc, 1, 0x01,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300182 0xff, 1, 0x01, /* page 1 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300183 0x12, 3, 0x02, 0x00, 0x01,
184 0x3e, 2, 0x00, 0x00,
185 0x76, 5, 0x01, 0x20, 0x40, 0x00, 0xf2,
186 0x7c, 1, 0x00,
187 0x7f, 10, 0x4b, 0x0f, 0x01, 0x2c, 0x02, 0x58, 0x03, 0x20,
188 0x02, 0x00,
189 0x96, 5, 0x01, 0x10, 0x04, 0x01, 0x04,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300190 0xc8, 14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300191 0x07, 0x00, 0x01, 0x07, 0x04, 0x01,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300192 0xd8, 1, 0x01,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300193 0xdb, 2, 0x00, 0x01,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300194 0xde, 7, 0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x00,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300195 0xe6, 4, 0x00, 0x00, 0x00, 0x01,
196 0xeb, 1, 0x00,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300197 0xff, 1, 0x02, /* page 2 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300198 0x22, 1, 0x00,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300199 0xff, 1, 0x03, /* page 3 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300200 0x00, 255, /* load the page 3 */
201 0x11, 1, 0x01,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300202 0xff, 1, 0x02, /* page 2 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300203 0x13, 1, 0x00,
204 0x22, 4, 0x1f, 0xa4, 0xf0, 0x96,
205 0x27, 2, 0x14, 0x0c,
206 0x2a, 5, 0xc8, 0x00, 0x18, 0x12, 0x22,
207 0x64, 8, 0x00, 0x00, 0xf0, 0x01, 0x14, 0x44, 0x44, 0x44,
208 0x6e, 1, 0x08,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300209 0xff, 1, 0x03, /* page 1 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300210 0x78, 1, 0x00,
211 0, 0 /* end of sequence */
212};
213
214/* page 3 - the value 0xaa says skip the index - see reg_w_page() */
215static const __u8 page3_7302[] = {
216 0x90, 0x40, 0x03, 0x50, 0xc2, 0x01, 0x14, 0x16,
217 0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00,
218 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
219 0x00, 0x00, 0x00, 0x47, 0x01, 0xb3, 0x01, 0x00,
220 0x00, 0x08, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x21,
221 0x00, 0x00, 0x00, 0x54, 0xf4, 0x02, 0x52, 0x54,
222 0xa4, 0xb8, 0xe0, 0x2a, 0xf6, 0x00, 0x00, 0x00,
223 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
224 0x00, 0xfc, 0x00, 0xf2, 0x1f, 0x04, 0x00, 0x00,
225 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x10, 0x00, 0x00,
226 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
227 0x00, 0x40, 0xff, 0x03, 0x19, 0x00, 0x00, 0x00,
228 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
229 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0xc8, 0xc8,
230 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,
231 0x08, 0x10, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00,
232 0x01, 0x00, 0x02, 0x47, 0x00, 0x00, 0x00, 0x00,
233 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
234 0x00, 0x02, 0xfa, 0x00, 0x64, 0x5a, 0x28, 0x00,
235 0x00
236};
237
238/* pac 7311 */
239static const __u8 probe_7311[] = {
240 0x78, 0x40, /* Bit_0=start stream, Bit_7=LED */
241 0x78, 0x40, /* Bit_0=start stream, Bit_7=LED */
242 0x78, 0x44, /* Bit_0=start stream, Bit_7=LED */
243 0xff, 0x04,
244 0x27, 0x80,
245 0x28, 0xca,
246 0x29, 0x53,
247 0x2a, 0x0e,
248 0xff, 0x01,
249 0x3e, 0x20,
250};
251
252static const __u8 start_7311[] = {
253/* index, len, [value]* */
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300254 0xff, 1, 0x01, /* page 1 */
255 0x02, 43, 0x48, 0x0a, 0x40, 0x08, 0x00, 0x00, 0x08, 0x00,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300256 0x06, 0xff, 0x11, 0xff, 0x5a, 0x30, 0x90, 0x4c,
257 0x00, 0x07, 0x00, 0x0a, 0x10, 0x00, 0xa0, 0x10,
258 0x02, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x01, 0x00,
259 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
260 0x00, 0x00, 0x00,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300261 0x3e, 42, 0x00, 0x00, 0x78, 0x52, 0x4a, 0x52, 0x78, 0x6e,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300262 0x48, 0x46, 0x48, 0x6e, 0x5f, 0x49, 0x42, 0x49,
263 0x5f, 0x5f, 0x49, 0x42, 0x49, 0x5f, 0x6e, 0x48,
264 0x46, 0x48, 0x6e, 0x78, 0x52, 0x4a, 0x52, 0x78,
265 0x00, 0x00, 0x09, 0x1b, 0x34, 0x49, 0x5c, 0x9b,
266 0xd0, 0xff,
267 0x78, 6, 0x44, 0x00, 0xf2, 0x01, 0x01, 0x80,
268 0x7f, 18, 0x2a, 0x1c, 0x00, 0xc8, 0x02, 0x58, 0x03, 0x84,
269 0x12, 0x00, 0x1a, 0x04, 0x08, 0x0c, 0x10, 0x14,
270 0x18, 0x20,
271 0x96, 3, 0x01, 0x08, 0x04,
272 0xa0, 4, 0x44, 0x44, 0x44, 0x04,
273 0xf0, 13, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x20, 0x00,
274 0x3f, 0x00, 0x0a, 0x01, 0x00,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300275 0xff, 1, 0x04, /* page 4 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300276 0x00, 254, /* load the page 4 */
277 0x11, 1, 0x01,
278 0, 0 /* end of sequence */
279};
280
281/* page 4 - the value 0xaa says skip the index - see reg_w_page() */
282static const __u8 page4_7311[] = {
283 0xaa, 0xaa, 0x04, 0x54, 0x07, 0x2b, 0x09, 0x0f,
284 0x09, 0x00, 0xaa, 0xaa, 0x07, 0x00, 0x00, 0x62,
285 0x08, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
286 0x00, 0x00, 0x00, 0x03, 0xa0, 0x01, 0xf4, 0xaa,
287 0xaa, 0x00, 0x08, 0xaa, 0x03, 0xaa, 0x00, 0x01,
288 0xca, 0x10, 0x06, 0x78, 0x00, 0x00, 0x00, 0x00,
289 0x23, 0x28, 0x04, 0x11, 0x00, 0x00
290};
291
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300292static void reg_w_buf(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300293 __u8 index,
294 const char *buffer, int len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300295{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300296 memcpy(gspca_dev->usb_buf, buffer, len);
297 usb_control_msg(gspca_dev->dev,
298 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300299 1, /* request */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300300 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300301 0, /* value */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300302 index, gspca_dev->usb_buf, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300303 500);
304}
305
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300306static __u8 reg_r(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300307 __u8 index)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300308{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300309 usb_control_msg(gspca_dev->dev,
310 usb_rcvctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300311 0, /* request */
312 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
313 0, /* value */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300314 index, gspca_dev->usb_buf, 1,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300315 500);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300316 return gspca_dev->usb_buf[0];
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300317}
318
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300319static void reg_w(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300320 __u8 index,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300321 __u8 value)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300322{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300323 gspca_dev->usb_buf[0] = value;
324 usb_control_msg(gspca_dev->dev,
325 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300326 0, /* request */
327 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300328 value, index, gspca_dev->usb_buf, 1,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300329 500);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300330}
331
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300332static void reg_w_seq(struct gspca_dev *gspca_dev,
333 const __u8 *seq, int len)
334{
335 while (--len >= 0) {
336 reg_w(gspca_dev, seq[0], seq[1]);
337 seq += 2;
338 }
339}
340
341/* load the beginning of a page */
342static void reg_w_page(struct gspca_dev *gspca_dev,
343 const __u8 *page, int len)
344{
345 int index;
346
347 for (index = 0; index < len; index++) {
348 if (page[index] == 0xaa) /* skip this index */
349 continue;
350 gspca_dev->usb_buf[0] = page[index];
351 usb_control_msg(gspca_dev->dev,
352 usb_sndctrlpipe(gspca_dev->dev, 0),
353 0, /* request */
354 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
355 0, index, gspca_dev->usb_buf, 1,
356 500);
357 }
358}
359
360/* output a variable sequence */
361static void reg_w_var(struct gspca_dev *gspca_dev,
362 const __u8 *seq)
363{
364 int index, len;
365
366 for (;;) {
367 index = *seq++;
368 len = *seq++;
369 switch (len) {
370 case 0:
371 return;
372 case 254:
373 reg_w_page(gspca_dev, page4_7311, sizeof page4_7311);
374 break;
375 case 255:
376 reg_w_page(gspca_dev, page3_7302, sizeof page3_7302);
377 break;
378 default:
379 if (len > 32) {
380 PDEBUG(D_ERR|D_STREAM,
381 "Incorrect variable sequence");
382 return;
383 }
384 while (len > 0) {
385 if (len < 8) {
386 reg_w_buf(gspca_dev, index, seq, len);
387 seq += len;
388 break;
389 }
390 reg_w_buf(gspca_dev, index, seq, 8);
391 seq += 8;
392 index += 8;
393 len -= 8;
394 }
395 }
396 }
397 /* not reached */
398}
399
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300400/* this function is called at probe time */
401static int sd_config(struct gspca_dev *gspca_dev,
402 const struct usb_device_id *id)
403{
404 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300405 struct cam *cam;
406
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300407 cam = &gspca_dev->cam;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300408 cam->epaddr = 0x05;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300409
410 sd->sensor = id->driver_info;
411 if (sd->sensor == SENSOR_PAC7302) {
412 PDEBUG(D_CONF, "Find Sensor PAC7302");
413 reg_w_seq(gspca_dev, probe_7302, sizeof probe_7302);
414
415 cam->cam_mode = &vga_mode[2]; /* only 640x480 */
416 cam->nmodes = 1;
417 } else {
418 PDEBUG(D_CONF, "Find Sensor PAC7311");
419 reg_w_seq(gspca_dev, probe_7302, sizeof probe_7302);
420
421 cam->cam_mode = vga_mode;
422 cam->nmodes = ARRAY_SIZE(vga_mode);
423 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300424
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300425 sd->brightness = BRIGHTNESS_DEF;
426 sd->contrast = CONTRAST_DEF;
427 sd->colors = COLOR_DEF;
428 sd->autogain = AUTOGAIN_DEF;
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300429 sd->ag_cnt = -1;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300430 return 0;
431}
432
Jean-Francois Moinedff6d322008-09-03 16:47:57 -0300433/* rev 12a only */
434static void setbrightcont(struct gspca_dev *gspca_dev)
435{
436 struct sd *sd = (struct sd *) gspca_dev;
437 int i, v;
438 static const __u8 max[10] =
439 {0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb,
440 0xd4, 0xec};
441 static const __u8 delta[10] =
442 {0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17,
443 0x11, 0x0b};
444
445 reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
446 for (i = 0; i < 10; i++) {
447 v = max[i];
448 v += (sd->brightness - BRIGHTNESS_MAX)
449 * 150 / BRIGHTNESS_MAX; /* 200 ? */
450 v -= delta[i] * sd->contrast / CONTRAST_MAX;
451 if (v < 0)
452 v = 0;
453 else if (v > 0xff)
454 v = 0xff;
455 reg_w(gspca_dev, 0xa2 + i, v);
456 }
457 reg_w(gspca_dev, 0xdc, 0x01);
458}
459
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300460static void setbrightness(struct gspca_dev *gspca_dev)
461{
462 struct sd *sd = (struct sd *) gspca_dev;
463 int brightness;
464
Jean-Francois Moinedff6d322008-09-03 16:47:57 -0300465 if (sd->sensor == SENSOR_PAC7302) {
466 setbrightcont(gspca_dev);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300467 return;
Jean-Francois Moinedff6d322008-09-03 16:47:57 -0300468 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300469/*jfm: inverted?*/
470 brightness = BRIGHTNESS_MAX - sd->brightness;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300471 reg_w(gspca_dev, 0xff, 0x04);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300472 reg_w(gspca_dev, 0x0f, brightness);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300473 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300474 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300475 PDEBUG(D_CONF|D_STREAM, "brightness: %i", brightness);
476}
477
478static void setcontrast(struct gspca_dev *gspca_dev)
479{
480 struct sd *sd = (struct sd *) gspca_dev;
481
Jean-Francois Moinedff6d322008-09-03 16:47:57 -0300482 if (sd->sensor == SENSOR_PAC7302) {
483 setbrightcont(gspca_dev);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300484 return;
Jean-Francois Moinedff6d322008-09-03 16:47:57 -0300485 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300486 reg_w(gspca_dev, 0xff, 0x01);
487 reg_w(gspca_dev, 0x80, sd->contrast);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300488 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300489 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300490}
491
492static void setcolors(struct gspca_dev *gspca_dev)
493{
494 struct sd *sd = (struct sd *) gspca_dev;
495
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300496 if (sd->sensor == SENSOR_PAC7302)
497 return;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300498 reg_w(gspca_dev, 0xff, 0x01);
499 reg_w(gspca_dev, 0x10, sd->colors);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300500 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300501 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300502 PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
503}
504
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300505static void setautogain(struct gspca_dev *gspca_dev)
506{
507 struct sd *sd = (struct sd *) gspca_dev;
508
509 if (sd->autogain) {
510 sd->lum_sum = 0;
511 sd->ag_cnt = AG_CNT_START;
512 } else {
513 sd->ag_cnt = -1;
514 }
515}
516
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300517/* this function is called at open time */
518static int sd_open(struct gspca_dev *gspca_dev)
519{
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300520 reg_w(gspca_dev, 0x78, 0x00); /* Turn on LED */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300521 return 0;
522}
523
524static void sd_start(struct gspca_dev *gspca_dev)
525{
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300526 struct sd *sd = (struct sd *) gspca_dev;
527
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300528 sd->tosof = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300529
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300530 if (sd->sensor == SENSOR_PAC7302)
531 reg_w_var(gspca_dev, start_7302);
532 else
533 reg_w_var(gspca_dev, start_7311);
534
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300535 setcontrast(gspca_dev);
536 setbrightness(gspca_dev);
537 setcolors(gspca_dev);
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300538 setautogain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300539
540 /* set correct resolution */
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300541 switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300542 case 2: /* 160x120 pac7311 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300543 reg_w(gspca_dev, 0xff, 0x04);
544 reg_w(gspca_dev, 0x02, 0x03);
545 reg_w(gspca_dev, 0xff, 0x01);
546 reg_w(gspca_dev, 0x08, 0x09);
547 reg_w(gspca_dev, 0x17, 0x20);
548 reg_w(gspca_dev, 0x1b, 0x00);
549/* reg_w(gspca_dev, 0x80, 0x69); */
550 reg_w(gspca_dev, 0x87, 0x10);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300551 break;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300552 case 1: /* 320x240 pac7311 */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300553 reg_w(gspca_dev, 0xff, 0x04);
554 reg_w(gspca_dev, 0x02, 0x03);
555 reg_w(gspca_dev, 0xff, 0x01);
556 reg_w(gspca_dev, 0x08, 0x09);
557 reg_w(gspca_dev, 0x17, 0x30);
558/* reg_w(gspca_dev, 0x80, 0x3f); */
559 reg_w(gspca_dev, 0x87, 0x11);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300560 break;
561 case 0: /* 640x480 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300562 if (sd->sensor == SENSOR_PAC7302)
563 break;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300564 reg_w(gspca_dev, 0xff, 0x04);
565 reg_w(gspca_dev, 0x02, 0x03);
566 reg_w(gspca_dev, 0xff, 0x01);
567 reg_w(gspca_dev, 0x08, 0x08);
568 reg_w(gspca_dev, 0x17, 0x00);
569/* reg_w(gspca_dev, 0x80, 0x1c); */
570 reg_w(gspca_dev, 0x87, 0x12);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300571 break;
572 }
573
574 /* start stream */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300575 reg_w(gspca_dev, 0xff, 0x01);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300576 if (sd->sensor == SENSOR_PAC7302) {
577 reg_w(gspca_dev, 0x78, 0x01);
578 reg_w(gspca_dev, 0xff, 0x01);
579 reg_w(gspca_dev, 0x78, 0x01);
580 } else {
581 reg_w(gspca_dev, 0x78, 0x04);
582 reg_w(gspca_dev, 0x78, 0x05);
583 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300584}
585
586static void sd_stopN(struct gspca_dev *gspca_dev)
587{
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300588 struct sd *sd = (struct sd *) gspca_dev;
589
590 if (sd->sensor == SENSOR_PAC7302) {
591 reg_w(gspca_dev, 0x78, 0x00);
592 reg_w(gspca_dev, 0x78, 0x00);
593 return;
594 }
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300595 reg_w(gspca_dev, 0xff, 0x04);
596 reg_w(gspca_dev, 0x27, 0x80);
597 reg_w(gspca_dev, 0x28, 0xca);
598 reg_w(gspca_dev, 0x29, 0x53);
599 reg_w(gspca_dev, 0x2a, 0x0e);
600 reg_w(gspca_dev, 0xff, 0x01);
601 reg_w(gspca_dev, 0x3e, 0x20);
602 reg_w(gspca_dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */
603 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
604 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300605}
606
607static void sd_stop0(struct gspca_dev *gspca_dev)
608{
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300609 struct sd *sd = (struct sd *) gspca_dev;
610
611 if (sd->sensor == SENSOR_PAC7302) {
612 reg_w(gspca_dev, 0xff, 0x01);
613 reg_w(gspca_dev, 0x78, 0x40);
614 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300615}
616
617/* this function is called at close time */
618static void sd_close(struct gspca_dev *gspca_dev)
619{
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300620}
621
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300622static void do_autogain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300623{
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300624 struct sd *sd = (struct sd *) gspca_dev;
625 int luma;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300626 int luma_mean = 128;
627 int luma_delta = 20;
628 __u8 spring = 5;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300629 int Gbright;
630
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300631 if (!atomic_read(&sd->do_gain))
632 return;
633 atomic_set(&sd->do_gain, 0);
634
635 luma = atomic_read(&sd->avg_lum);
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300636 Gbright = reg_r(gspca_dev, 0x02);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300637 PDEBUG(D_FRAM, "luma mean %d", luma);
638 if (luma < luma_mean - luma_delta ||
639 luma > luma_mean + luma_delta) {
640 Gbright += (luma_mean - luma) >> spring;
641 if (Gbright > 0x1a)
642 Gbright = 0x1a;
643 else if (Gbright < 4)
644 Gbright = 4;
645 PDEBUG(D_FRAM, "gbright %d", Gbright);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300646 if (sd->sensor == SENSOR_PAC7302) {
647 reg_w(gspca_dev, 0xff, 0x03);
648 reg_w(gspca_dev, 0x10, Gbright);
649 /* load registers to sensor (Bit 0, auto clear) */
650 reg_w(gspca_dev, 0x11, 0x01);
651 } else {
652 reg_w(gspca_dev, 0xff, 0x04);
653 reg_w(gspca_dev, 0x0f, Gbright);
654 /* load registers to sensor (Bit 0, auto clear) */
655 reg_w(gspca_dev, 0x11, 0x01);
656 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300657 }
658}
659
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300660/* this function is run at interrupt level */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300661static void sd_pkt_scan(struct gspca_dev *gspca_dev,
662 struct gspca_frame *frame, /* target */
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300663 __u8 *data, /* isoc packet */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300664 int len) /* iso packet length */
665{
666 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300667 int i;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300668
Jean-Francois Moine8559e8d2008-09-03 16:47:27 -0300669#define INTER_FRAME 0x53 /* eof + inter frame + sof */
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300670#define LUM_OFFSET 0x1e /* reverse offset / start of frame */
671
672 /*
673 * inside a frame, there may be:
674 * escaped ff ('ff 00')
675 * sequences'ff ff ff xx' to remove
676 * end of frame ('ff d9')
677 * at the end of frame, there are:
678 * ff d9 end of frame
679 * 0x33 bytes
680 * one byte luminosity
681 * 0x16 bytes
Jean-Francois Moinef75c4952008-09-03 16:47:35 -0300682 * ff ff 00 ff 96 62 44 start of frame
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300683 */
684
Jean-Francois Moinef75c4952008-09-03 16:47:35 -0300685 if (sd->tosof != 0) { /* if outside a frame */
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300686
Jean-Francois Moine8559e8d2008-09-03 16:47:27 -0300687 /* get the luminosity and go to the start of frame */
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300688 data += sd->tosof;
689 len -= sd->tosof;
690 if (sd->tosof > LUM_OFFSET)
691 sd->lum_sum += data[-LUM_OFFSET];
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300692 sd->tosof = 0;
Jean-Francois Moinef75c4952008-09-03 16:47:35 -0300693 jpeg_put_header(gspca_dev, frame, 1, 0x21);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300694 }
695
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300696 for (i = 0; i < len; i++) {
697 if (data[i] != 0xff)
698 continue;
699 switch (data[i + 1]) {
Jean-Francois Moinef75c4952008-09-03 16:47:35 -0300700 case 0xd9: /* 'ff d9' end of frame */
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300701 frame = gspca_frame_add(gspca_dev,
702 LAST_PACKET,
Jean-Francois Moine8559e8d2008-09-03 16:47:27 -0300703 frame, data, i + 2);
Jean-Francois Moine23d9e472008-09-03 16:47:22 -0300704 data += i + INTER_FRAME;
705 len -= i + INTER_FRAME;
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300706 i = 0;
Jean-Francois Moine23d9e472008-09-03 16:47:22 -0300707 if (len > -LUM_OFFSET)
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300708 sd->lum_sum += data[-LUM_OFFSET];
709 if (len < 0) {
710 sd->tosof = -len;
711 break;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300712 }
Jean-Francois Moinef75c4952008-09-03 16:47:35 -0300713 jpeg_put_header(gspca_dev, frame, 1, 0x21);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300714 break;
715 }
716 }
Jean-Francois Moine8559e8d2008-09-03 16:47:27 -0300717 gspca_frame_add(gspca_dev, INTER_PACKET,
718 frame, data, i);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300719}
720
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300721static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
722{
723 struct sd *sd = (struct sd *) gspca_dev;
724
725 sd->brightness = val;
726 if (gspca_dev->streaming)
727 setbrightness(gspca_dev);
728 return 0;
729}
730
731static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
732{
733 struct sd *sd = (struct sd *) gspca_dev;
734
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300735 *val = sd->brightness;
736 return 0;
737}
738
739static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
740{
741 struct sd *sd = (struct sd *) gspca_dev;
742
743 sd->contrast = val;
744 if (gspca_dev->streaming)
745 setcontrast(gspca_dev);
746 return 0;
747}
748
749static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
750{
751 struct sd *sd = (struct sd *) gspca_dev;
752
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300753 *val = sd->contrast;
754 return 0;
755}
756
757static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
758{
759 struct sd *sd = (struct sd *) gspca_dev;
760
761 sd->colors = val;
762 if (gspca_dev->streaming)
763 setcolors(gspca_dev);
764 return 0;
765}
766
767static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
768{
769 struct sd *sd = (struct sd *) gspca_dev;
770
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300771 *val = sd->colors;
772 return 0;
773}
774
775static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
776{
777 struct sd *sd = (struct sd *) gspca_dev;
778
779 sd->autogain = val;
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300780 if (gspca_dev->streaming)
781 setautogain(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300782 return 0;
783}
784
785static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
786{
787 struct sd *sd = (struct sd *) gspca_dev;
788
789 *val = sd->autogain;
790 return 0;
791}
792
793/* sub-driver description */
794static struct sd_desc sd_desc = {
795 .name = MODULE_NAME,
796 .ctrls = sd_ctrls,
797 .nctrls = ARRAY_SIZE(sd_ctrls),
798 .config = sd_config,
799 .open = sd_open,
800 .start = sd_start,
801 .stopN = sd_stopN,
802 .stop0 = sd_stop0,
803 .close = sd_close,
804 .pkt_scan = sd_pkt_scan,
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300805 .dq_callback = do_autogain,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300806};
807
808/* -- module initialisation -- */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300809static __devinitdata struct usb_device_id device_table[] = {
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300810 {USB_DEVICE(0x093a, 0x2600), .driver_info = SENSOR_PAC7311},
811 {USB_DEVICE(0x093a, 0x2601), .driver_info = SENSOR_PAC7311},
812 {USB_DEVICE(0x093a, 0x2603), .driver_info = SENSOR_PAC7311},
813 {USB_DEVICE(0x093a, 0x2608), .driver_info = SENSOR_PAC7311},
814 {USB_DEVICE(0x093a, 0x260e), .driver_info = SENSOR_PAC7311},
815 {USB_DEVICE(0x093a, 0x260f), .driver_info = SENSOR_PAC7311},
816 {USB_DEVICE(0x093a, 0x2621), .driver_info = SENSOR_PAC7302},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300817 {}
818};
819MODULE_DEVICE_TABLE(usb, device_table);
820
821/* -- device connect -- */
822static int sd_probe(struct usb_interface *intf,
823 const struct usb_device_id *id)
824{
825 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
826 THIS_MODULE);
827}
828
829static struct usb_driver sd_driver = {
830 .name = MODULE_NAME,
831 .id_table = device_table,
832 .probe = sd_probe,
833 .disconnect = gspca_disconnect,
834};
835
836/* -- module insert / remove -- */
837static int __init sd_mod_init(void)
838{
839 if (usb_register(&sd_driver) < 0)
840 return -1;
Jean-Francois Moine10b0e962008-07-22 05:35:10 -0300841 PDEBUG(D_PROBE, "registered");
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300842 return 0;
843}
844static void __exit sd_mod_exit(void)
845{
846 usb_deregister(&sd_driver);
847 PDEBUG(D_PROBE, "deregistered");
848}
849
850module_init(sd_mod_init);
851module_exit(sd_mod_exit);