blob: 5ccf0b41ffc5f0c054e7d17c84e843f73f4dd74b [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
Hans de Goede327c4ab2008-09-03 17:12:14 -030022/* Some documentation about various registers as determined by trial and error.
Hans de Goede4b8ceb62012-04-28 10:20:50 -030023 *
24 * Register page 1:
25 *
26 * Address Description
27 * 0x08 Unknown compressor related, must always be 8 except when not
28 * in 640x480 resolution and page 4 reg 2 <= 3 then set it to 9 !
29 * 0x1b Auto white balance related, bit 0 is AWB enable (inverted)
30 * bits 345 seem to toggle per color gains on/off (inverted)
31 * 0x78 Global control, bit 6 controls the LED (inverted)
Hans de Goede282ddfb2012-04-27 12:56:59 -030032 * 0x80 Compression balance, interesting settings:
33 * 0x01 Use this to allow the camera to switch to higher compr.
34 * on the fly. Needed to stay within bandwidth @ 640x480@30
35 * 0x1c From usb captures under Windows for 640x480
36 * 0x2a Values >= this switch the camera to a lower compression,
37 * using the same table for both luminance and chrominance.
38 * This gives a sharper picture. Usable only at 640x480@ <
39 * 15 fps or 320x240 / 160x120. Note currently the driver
40 * does not use this as the quality gain is small and the
41 * generated JPG-s are only understood by v4l-utils >= 0.8.9
42 * 0x3f From usb captures under Windows for 320x240
43 * 0x69 From usb captures under Windows for 160x120
Hans de Goede4b8ceb62012-04-28 10:20:50 -030044 *
45 * Register page 4:
46 *
47 * Address Description
48 * 0x02 Clock divider 2-63, fps =~ 60 / val. Must be a multiple of 3 on
49 * the 7302, so one of 3, 6, 9, ..., except when between 6 and 12?
50 * 0x0f Master gain 1-245, low value = high gain
51 * 0x10 Another gain 0-15, limited influence (1-2x gain I guess)
52 * 0x21 Bitfield: 0-1 unused, 2-3 vflip/hflip, 4-5 unknown, 6-7 unused
53 * 0x27 Seems to toggle various gains on / off, Setting bit 7 seems to
54 * completely disable the analog amplification block. Set to 0x68
55 * for max gain, 0x14 for minimal gain.
56 */
Hans de Goede327c4ab2008-09-03 17:12:14 -030057
Joe Perches133a9fe2011-08-21 19:56:57 -030058#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
59
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030060#define MODULE_NAME "pac7311"
61
Hans de Goede32ea3e42010-01-29 11:04:19 -030062#include <linux/input.h>
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030063#include "gspca.h"
Hans de Goedea5340ce2012-04-27 11:40:28 -030064/* Include pac common sof detection functions */
65#include "pac_common.h"
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030066
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030067MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li");
68MODULE_DESCRIPTION("Pixart PAC7311");
69MODULE_LICENSE("GPL");
70
Hans de Goedea5340ce2012-04-27 11:40:28 -030071enum e_ctrl {
72 CONTRAST,
73 GAIN,
74 EXPOSURE,
75 AUTOGAIN,
76 HFLIP,
77 VFLIP,
78 NCTRLS /* number of controls */
79};
80
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030081struct sd {
82 struct gspca_dev gspca_dev; /* !! must be the first item */
Hans de Goedea5340ce2012-04-27 11:40:28 -030083 struct gspca_ctrl ctrls[NCTRLS];
Hans de Goedeccab75e2012-04-27 13:06:26 -030084 int exp_too_low_cnt;
85 int exp_too_high_cnt;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -030086
Hans de Goede327c4ab2008-09-03 17:12:14 -030087 u8 sof_read;
Hans de Goede327c4ab2008-09-03 17:12:14 -030088 u8 autogain_ignore_frames;
89
90 atomic_t avg_lum;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030091};
92
93/* V4L2 controls supported by the driver */
Hans de Goedea5340ce2012-04-27 11:40:28 -030094static void setcontrast(struct gspca_dev *gspca_dev);
95static void setgain(struct gspca_dev *gspca_dev);
96static void setexposure(struct gspca_dev *gspca_dev);
Hans de Goedea5340ce2012-04-27 11:40:28 -030097static void sethvflip(struct gspca_dev *gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030098
Marton Nemeth7e64dc42009-12-30 09:12:41 -030099static const struct ctrl sd_ctrls[] = {
Hans de Goedea5340ce2012-04-27 11:40:28 -0300100[CONTRAST] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300101 {
102 .id = V4L2_CID_CONTRAST,
103 .type = V4L2_CTRL_TYPE_INTEGER,
104 .name = "Contrast",
105 .minimum = 0,
Hans de Goedea5340ce2012-04-27 11:40:28 -0300106 .maximum = 15,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300107 .step = 1,
Hans de Goedea5340ce2012-04-27 11:40:28 -0300108 .default_value = 7,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300109 },
Hans de Goedea5340ce2012-04-27 11:40:28 -0300110 .set_control = setcontrast
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300111 },
Hans de Goedea5340ce2012-04-27 11:40:28 -0300112[GAIN] = {
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300113 {
114 .id = V4L2_CID_GAIN,
115 .type = V4L2_CTRL_TYPE_INTEGER,
116 .name = "Gain",
117 .minimum = 0,
Hans de Goedea5340ce2012-04-27 11:40:28 -0300118 .maximum = 244,
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300119 .step = 1,
Hans de Goedea5340ce2012-04-27 11:40:28 -0300120 .default_value = 122,
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300121 },
Hans de Goedea5340ce2012-04-27 11:40:28 -0300122 .set_control = setgain,
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300123 },
Hans de Goedea5340ce2012-04-27 11:40:28 -0300124[EXPOSURE] = {
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300125 {
126 .id = V4L2_CID_EXPOSURE,
127 .type = V4L2_CTRL_TYPE_INTEGER,
128 .name = "Exposure",
Hans de Goedec894d262012-04-25 12:17:19 -0300129 .minimum = 2,
Hans de Goedea5340ce2012-04-27 11:40:28 -0300130 .maximum = 63,
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300131 .step = 1,
Hans de Goedeccab75e2012-04-27 13:06:26 -0300132 .default_value = 3, /* 20 fps, avoid using high compr. */
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300133 },
Hans de Goedea5340ce2012-04-27 11:40:28 -0300134 .set_control = setexposure,
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300135 },
Hans de Goedea5340ce2012-04-27 11:40:28 -0300136[AUTOGAIN] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300137 {
138 .id = V4L2_CID_AUTOGAIN,
139 .type = V4L2_CTRL_TYPE_BOOLEAN,
140 .name = "Auto Gain",
141 .minimum = 0,
142 .maximum = 1,
143 .step = 1,
Hans de Goedea5340ce2012-04-27 11:40:28 -0300144 .default_value = 1,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300145 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300146 },
Hans de Goedea5340ce2012-04-27 11:40:28 -0300147[HFLIP] = {
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300148 {
149 .id = V4L2_CID_HFLIP,
150 .type = V4L2_CTRL_TYPE_BOOLEAN,
151 .name = "Mirror",
152 .minimum = 0,
153 .maximum = 1,
154 .step = 1,
Hans de Goedea5340ce2012-04-27 11:40:28 -0300155 .default_value = 0,
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300156 },
Hans de Goedea5340ce2012-04-27 11:40:28 -0300157 .set_control = sethvflip,
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300158 },
Hans de Goedea5340ce2012-04-27 11:40:28 -0300159[VFLIP] = {
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300160 {
161 .id = V4L2_CID_VFLIP,
162 .type = V4L2_CTRL_TYPE_BOOLEAN,
163 .name = "Vflip",
164 .minimum = 0,
165 .maximum = 1,
166 .step = 1,
Hans de Goedea5340ce2012-04-27 11:40:28 -0300167 .default_value = 0,
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300168 },
Hans de Goedea5340ce2012-04-27 11:40:28 -0300169 .set_control = sethvflip,
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300170 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300171};
172
Jean-Francois Moinecc611b82008-12-29 07:49:41 -0300173static const struct v4l2_pix_format vga_mode[] = {
Jean-Francois Moinef75c4952008-09-03 16:47:35 -0300174 {160, 120, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300175 .bytesperline = 160,
176 .sizeimage = 160 * 120 * 3 / 8 + 590,
177 .colorspace = V4L2_COLORSPACE_JPEG,
178 .priv = 2},
Jean-Francois Moinef75c4952008-09-03 16:47:35 -0300179 {320, 240, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300180 .bytesperline = 320,
181 .sizeimage = 320 * 240 * 3 / 8 + 590,
182 .colorspace = V4L2_COLORSPACE_JPEG,
183 .priv = 1},
Jean-Francois Moinef75c4952008-09-03 16:47:35 -0300184 {640, 480, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300185 .bytesperline = 640,
186 .sizeimage = 640 * 480 * 3 / 8 + 590,
187 .colorspace = V4L2_COLORSPACE_JPEG,
188 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300189};
190
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300191#define LOAD_PAGE4 254
192#define END_OF_SEQUENCE 0
193
Hans de Goede271315a2008-09-03 17:12:19 -0300194static const __u8 init_7311[] = {
Hans de Goede327c4ab2008-09-03 17:12:14 -0300195 0x78, 0x40, /* Bit_0=start stream, Bit_6=LED */
196 0x78, 0x40, /* Bit_0=start stream, Bit_6=LED */
197 0x78, 0x44, /* Bit_0=start stream, Bit_6=LED */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300198 0xff, 0x04,
199 0x27, 0x80,
200 0x28, 0xca,
201 0x29, 0x53,
202 0x2a, 0x0e,
203 0xff, 0x01,
204 0x3e, 0x20,
205};
206
207static const __u8 start_7311[] = {
208/* index, len, [value]* */
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300209 0xff, 1, 0x01, /* page 1 */
210 0x02, 43, 0x48, 0x0a, 0x40, 0x08, 0x00, 0x00, 0x08, 0x00,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300211 0x06, 0xff, 0x11, 0xff, 0x5a, 0x30, 0x90, 0x4c,
212 0x00, 0x07, 0x00, 0x0a, 0x10, 0x00, 0xa0, 0x10,
213 0x02, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x01, 0x00,
214 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
215 0x00, 0x00, 0x00,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300216 0x3e, 42, 0x00, 0x00, 0x78, 0x52, 0x4a, 0x52, 0x78, 0x6e,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300217 0x48, 0x46, 0x48, 0x6e, 0x5f, 0x49, 0x42, 0x49,
218 0x5f, 0x5f, 0x49, 0x42, 0x49, 0x5f, 0x6e, 0x48,
219 0x46, 0x48, 0x6e, 0x78, 0x52, 0x4a, 0x52, 0x78,
220 0x00, 0x00, 0x09, 0x1b, 0x34, 0x49, 0x5c, 0x9b,
221 0xd0, 0xff,
222 0x78, 6, 0x44, 0x00, 0xf2, 0x01, 0x01, 0x80,
223 0x7f, 18, 0x2a, 0x1c, 0x00, 0xc8, 0x02, 0x58, 0x03, 0x84,
224 0x12, 0x00, 0x1a, 0x04, 0x08, 0x0c, 0x10, 0x14,
225 0x18, 0x20,
226 0x96, 3, 0x01, 0x08, 0x04,
227 0xa0, 4, 0x44, 0x44, 0x44, 0x04,
228 0xf0, 13, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x20, 0x00,
229 0x3f, 0x00, 0x0a, 0x01, 0x00,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300230 0xff, 1, 0x04, /* page 4 */
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300231 0, LOAD_PAGE4, /* load the page 4 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300232 0x11, 1, 0x01,
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300233 0, END_OF_SEQUENCE /* end of sequence */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300234};
235
Marton Nemeth1408b842009-11-02 08:13:21 -0300236#define SKIP 0xaa
Marton Nemethff75e992009-10-04 13:51:26 -0300237/* page 4 - the value SKIP says skip the index - see reg_w_page() */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300238static const __u8 page4_7311[] = {
Marton Nemethff75e992009-10-04 13:51:26 -0300239 SKIP, SKIP, 0x04, 0x54, 0x07, 0x2b, 0x09, 0x0f,
240 0x09, 0x00, SKIP, SKIP, 0x07, 0x00, 0x00, 0x62,
241 0x08, SKIP, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
242 0x00, 0x00, 0x00, 0x03, 0xa0, 0x01, 0xf4, SKIP,
243 SKIP, 0x00, 0x08, SKIP, 0x03, SKIP, 0x00, 0x68,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300244 0xca, 0x10, 0x06, 0x78, 0x00, 0x00, 0x00, 0x00,
245 0x23, 0x28, 0x04, 0x11, 0x00, 0x00
246};
247
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300248static void reg_w_buf(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300249 __u8 index,
Jean-François Moine0aeb5ec2010-12-28 06:59:04 -0300250 const u8 *buffer, int len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300251{
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300252 int ret;
253
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300254 if (gspca_dev->usb_err < 0)
255 return;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300256 memcpy(gspca_dev->usb_buf, buffer, len);
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300257 ret = usb_control_msg(gspca_dev->dev,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300258 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-François Moinea1317132010-06-24 04:50:26 -0300259 0, /* request */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300260 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300261 0, /* value */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300262 index, gspca_dev->usb_buf, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300263 500);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300264 if (ret < 0) {
Joe Perches133a9fe2011-08-21 19:56:57 -0300265 pr_err("reg_w_buf() failed index 0x%02x, error %d\n",
266 index, ret);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300267 gspca_dev->usb_err = ret;
268 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300269}
270
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300271
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300272static void reg_w(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300273 __u8 index,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300274 __u8 value)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300275{
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300276 int ret;
277
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300278 if (gspca_dev->usb_err < 0)
279 return;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300280 gspca_dev->usb_buf[0] = value;
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300281 ret = usb_control_msg(gspca_dev->dev,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300282 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300283 0, /* request */
284 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300285 0, index, gspca_dev->usb_buf, 1,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300286 500);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300287 if (ret < 0) {
Joe Perches133a9fe2011-08-21 19:56:57 -0300288 pr_err("reg_w() failed index 0x%02x, value 0x%02x, error %d\n",
289 index, value, ret);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300290 gspca_dev->usb_err = ret;
291 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300292}
293
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300294static void reg_w_seq(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300295 const __u8 *seq, int len)
296{
297 while (--len >= 0) {
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300298 reg_w(gspca_dev, seq[0], seq[1]);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300299 seq += 2;
300 }
301}
302
303/* load the beginning of a page */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300304static void reg_w_page(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300305 const __u8 *page, int len)
306{
307 int index;
Márton Némethb1784b32009-11-07 05:52:02 -0300308 int ret = 0;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300309
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300310 if (gspca_dev->usb_err < 0)
311 return;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300312 for (index = 0; index < len; index++) {
Marton Nemethff75e992009-10-04 13:51:26 -0300313 if (page[index] == SKIP) /* skip this index */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300314 continue;
315 gspca_dev->usb_buf[0] = page[index];
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300316 ret = usb_control_msg(gspca_dev->dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300317 usb_sndctrlpipe(gspca_dev->dev, 0),
318 0, /* request */
319 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
320 0, index, gspca_dev->usb_buf, 1,
321 500);
Márton Némethb1784b32009-11-07 05:52:02 -0300322 if (ret < 0) {
Joe Perches133a9fe2011-08-21 19:56:57 -0300323 pr_err("reg_w_page() failed index 0x%02x, value 0x%02x, error %d\n",
324 index, page[index], ret);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300325 gspca_dev->usb_err = ret;
Márton Némethb1784b32009-11-07 05:52:02 -0300326 break;
327 }
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300328 }
329}
330
331/* output a variable sequence */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300332static void reg_w_var(struct gspca_dev *gspca_dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300333 const __u8 *seq,
Marton Nemeth1408b842009-11-02 08:13:21 -0300334 const __u8 *page4, unsigned int page4_len)
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300335{
336 int index, len;
337
338 for (;;) {
339 index = *seq++;
340 len = *seq++;
341 switch (len) {
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300342 case END_OF_SEQUENCE:
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300343 return;
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300344 case LOAD_PAGE4:
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300345 reg_w_page(gspca_dev, page4, page4_len);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300346 break;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300347 default:
Marton Nemeth24067bb2009-10-04 13:54:48 -0300348 if (len > USB_BUF_SZ) {
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300349 PDEBUG(D_ERR|D_STREAM,
350 "Incorrect variable sequence");
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300351 return;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300352 }
353 while (len > 0) {
354 if (len < 8) {
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300355 reg_w_buf(gspca_dev,
Márton Némethb1784b32009-11-07 05:52:02 -0300356 index, seq, len);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300357 seq += len;
358 break;
359 }
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300360 reg_w_buf(gspca_dev, index, seq, 8);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300361 seq += 8;
362 index += 8;
363 len -= 8;
364 }
365 }
366 }
367 /* not reached */
368}
369
Marton Nemeth1408b842009-11-02 08:13:21 -0300370/* this function is called at probe time for pac7311 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300371static int sd_config(struct gspca_dev *gspca_dev,
372 const struct usb_device_id *id)
373{
374 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goedea5340ce2012-04-27 11:40:28 -0300375 struct cam *cam = &gspca_dev->cam;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300376
Marton Nemeth1408b842009-11-02 08:13:21 -0300377 cam->cam_mode = vga_mode;
378 cam->nmodes = ARRAY_SIZE(vga_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300379
Hans de Goedea5340ce2012-04-27 11:40:28 -0300380 gspca_dev->cam.ctrls = sd->ctrls;
381
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300382 return 0;
383}
384
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300385static void setcontrast(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300386{
387 struct sd *sd = (struct sd *) gspca_dev;
388
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300389 reg_w(gspca_dev, 0xff, 0x04);
Hans de Goedea5340ce2012-04-27 11:40:28 -0300390 reg_w(gspca_dev, 0x10, sd->ctrls[CONTRAST].val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300391 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300392 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300393}
394
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300395static void setgain(struct gspca_dev *gspca_dev)
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300396{
397 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300398
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300399 reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
400 reg_w(gspca_dev, 0x0e, 0x00);
Hans de Goedea5340ce2012-04-27 11:40:28 -0300401 reg_w(gspca_dev, 0x0f, sd->ctrls[GAIN].max - sd->ctrls[GAIN].val + 1);
Marton Nemeth1408b842009-11-02 08:13:21 -0300402
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300403 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300404 reg_w(gspca_dev, 0x11, 0x01);
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300405}
406
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300407static void setexposure(struct gspca_dev *gspca_dev)
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300408{
409 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300410
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300411 reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
Hans de Goedea5340ce2012-04-27 11:40:28 -0300412 reg_w(gspca_dev, 0x02, sd->ctrls[EXPOSURE].val);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300413
Hans de Goede51ae23d2012-04-18 06:12:57 -0300414 /* load registers to sensor (Bit 0, auto clear) */
415 reg_w(gspca_dev, 0x11, 0x01);
416
Hans de Goede4b8ceb62012-04-28 10:20:50 -0300417 /*
418 * Page 1 register 8 must always be 0x08 except when not in
419 * 640x480 mode and page 4 reg 2 <= 3 then it must be 9
420 */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300421 reg_w(gspca_dev, 0xff, 0x01);
Hans de Goede282ddfb2012-04-27 12:56:59 -0300422 if (gspca_dev->width != 640 && sd->ctrls[EXPOSURE].val <= 3)
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300423 reg_w(gspca_dev, 0x08, 0x09);
Hans de Goede282ddfb2012-04-27 12:56:59 -0300424 else
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300425 reg_w(gspca_dev, 0x08, 0x08);
Hans de Goede282ddfb2012-04-27 12:56:59 -0300426
427 /*
428 * Page1 register 80 sets the compression balance, normally we
429 * want / use 0x1c, but for 640x480@30fps we must allow the
430 * camera to use higher compression or we may run out of
431 * bandwidth.
432 */
433 if (gspca_dev->width == 640 && sd->ctrls[EXPOSURE].val == 2)
434 reg_w(gspca_dev, 0x80, 0x01);
435 else
436 reg_w(gspca_dev, 0x80, 0x1c);
Marton Nemeth1408b842009-11-02 08:13:21 -0300437
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300438 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300439 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300440}
441
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300442static void sethvflip(struct gspca_dev *gspca_dev)
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300443{
444 struct sd *sd = (struct sd *) gspca_dev;
445 __u8 data;
446
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300447 reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
Hans de Goedea5340ce2012-04-27 11:40:28 -0300448 data = (sd->ctrls[HFLIP].val ? 0x04 : 0x00) |
449 (sd->ctrls[VFLIP].val ? 0x08 : 0x00);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300450 reg_w(gspca_dev, 0x21, data);
451
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300452 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300453 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300454}
455
Marton Nemeth1408b842009-11-02 08:13:21 -0300456/* this function is called at probe and resume time for pac7311 */
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300457static int sd_init(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300458{
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300459 reg_w_seq(gspca_dev, init_7311, sizeof(init_7311)/2);
460 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300461}
462
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300463static int sd_start(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300464{
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300465 struct sd *sd = (struct sd *) gspca_dev;
466
Hans de Goede327c4ab2008-09-03 17:12:14 -0300467 sd->sof_read = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300468
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300469 reg_w_var(gspca_dev, start_7311,
Marton Nemeth1408b842009-11-02 08:13:21 -0300470 page4_7311, sizeof(page4_7311));
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300471 setcontrast(gspca_dev);
472 setgain(gspca_dev);
473 setexposure(gspca_dev);
474 sethvflip(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300475
476 /* set correct resolution */
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300477 switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
Hans de Goedeb053c1d2012-04-25 12:00:49 -0300478 case 2: /* 160x120 */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300479 reg_w(gspca_dev, 0xff, 0x01);
480 reg_w(gspca_dev, 0x17, 0x20);
481 reg_w(gspca_dev, 0x87, 0x10);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300482 break;
Hans de Goedeb053c1d2012-04-25 12:00:49 -0300483 case 1: /* 320x240 */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300484 reg_w(gspca_dev, 0xff, 0x01);
485 reg_w(gspca_dev, 0x17, 0x30);
486 reg_w(gspca_dev, 0x87, 0x11);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300487 break;
488 case 0: /* 640x480 */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300489 reg_w(gspca_dev, 0xff, 0x01);
490 reg_w(gspca_dev, 0x17, 0x00);
491 reg_w(gspca_dev, 0x87, 0x12);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300492 break;
493 }
494
Hans de Goede327c4ab2008-09-03 17:12:14 -0300495 sd->sof_read = 0;
496 sd->autogain_ignore_frames = 0;
497 atomic_set(&sd->avg_lum, -1);
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300498
499 /* start stream */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300500 reg_w(gspca_dev, 0xff, 0x01);
501 reg_w(gspca_dev, 0x78, 0x05);
Marton Nemeth1408b842009-11-02 08:13:21 -0300502
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300503 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300504}
505
506static void sd_stopN(struct gspca_dev *gspca_dev)
507{
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300508 reg_w(gspca_dev, 0xff, 0x04);
509 reg_w(gspca_dev, 0x27, 0x80);
510 reg_w(gspca_dev, 0x28, 0xca);
511 reg_w(gspca_dev, 0x29, 0x53);
512 reg_w(gspca_dev, 0x2a, 0x0e);
513 reg_w(gspca_dev, 0xff, 0x01);
514 reg_w(gspca_dev, 0x3e, 0x20);
515 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
516 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
517 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300518}
519
Hans de Goedeccab75e2012-04-27 13:06:26 -0300520#define WANT_COARSE_EXPO_AUTOGAIN
Hans de Goedea5340ce2012-04-27 11:40:28 -0300521#include "autogain_functions.h"
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300522
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300523static void do_autogain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300524{
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300525 struct sd *sd = (struct sd *) gspca_dev;
526 int avg_lum = atomic_read(&sd->avg_lum);
Hans de Goede038ec7c2008-09-03 17:12:18 -0300527 int desired_lum, deadzone;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300528
Hans de Goedea5340ce2012-04-27 11:40:28 -0300529 if (sd->ctrls[AUTOGAIN].val == 0 || avg_lum == -1)
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300530 return;
531
Marton Nemeth1408b842009-11-02 08:13:21 -0300532 desired_lum = 200;
533 deadzone = 20;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300534
535 if (sd->autogain_ignore_frames > 0)
536 sd->autogain_ignore_frames--;
Hans de Goedeccab75e2012-04-27 13:06:26 -0300537 else if (coarse_grained_expo_autogain(gspca_dev, avg_lum, desired_lum,
538 deadzone))
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300539 sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300540}
541
Marton Nemeth56f6f552009-10-04 13:58:19 -0300542/* JPEG header, part 1 */
Marton Nemethcc409c02009-11-02 08:09:34 -0300543static const unsigned char pac_jpeg_header1[] = {
Marton Nemeth56f6f552009-10-04 13:58:19 -0300544 0xff, 0xd8, /* SOI: Start of Image */
545
546 0xff, 0xc0, /* SOF0: Start of Frame (Baseline DCT) */
547 0x00, 0x11, /* length = 17 bytes (including this length field) */
548 0x08 /* Precision: 8 */
549 /* 2 bytes is placed here: number of image lines */
550 /* 2 bytes is placed here: samples per line */
Hans de Goede327c4ab2008-09-03 17:12:14 -0300551};
552
Marton Nemeth56f6f552009-10-04 13:58:19 -0300553/* JPEG header, continued */
Marton Nemethcc409c02009-11-02 08:09:34 -0300554static const unsigned char pac_jpeg_header2[] = {
Marton Nemeth56f6f552009-10-04 13:58:19 -0300555 0x03, /* Number of image components: 3 */
556 0x01, 0x21, 0x00, /* ID=1, Subsampling 1x1, Quantization table: 0 */
557 0x02, 0x11, 0x01, /* ID=2, Subsampling 2x1, Quantization table: 1 */
558 0x03, 0x11, 0x01, /* ID=3, Subsampling 2x1, Quantization table: 1 */
559
560 0xff, 0xda, /* SOS: Start Of Scan */
561 0x00, 0x0c, /* length = 12 bytes (including this length field) */
562 0x03, /* number of components: 3 */
563 0x01, 0x00, /* selector 1, table 0x00 */
564 0x02, 0x11, /* selector 2, table 0x11 */
565 0x03, 0x11, /* selector 3, table 0x11 */
566 0x00, 0x3f, /* Spectral selection: 0 .. 63 */
567 0x00 /* Successive approximation: 0 */
Hans de Goede327c4ab2008-09-03 17:12:14 -0300568};
569
Marton Nemethcc409c02009-11-02 08:09:34 -0300570static void pac_start_frame(struct gspca_dev *gspca_dev,
Marton Nemethcc409c02009-11-02 08:09:34 -0300571 __u16 lines, __u16 samples_per_line)
572{
573 unsigned char tmpbuf[4];
574
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300575 gspca_frame_add(gspca_dev, FIRST_PACKET,
Marton Nemethcc409c02009-11-02 08:09:34 -0300576 pac_jpeg_header1, sizeof(pac_jpeg_header1));
577
578 tmpbuf[0] = lines >> 8;
579 tmpbuf[1] = lines & 0xff;
580 tmpbuf[2] = samples_per_line >> 8;
581 tmpbuf[3] = samples_per_line & 0xff;
582
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300583 gspca_frame_add(gspca_dev, INTER_PACKET,
Marton Nemethcc409c02009-11-02 08:09:34 -0300584 tmpbuf, sizeof(tmpbuf));
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300585 gspca_frame_add(gspca_dev, INTER_PACKET,
Marton Nemethcc409c02009-11-02 08:09:34 -0300586 pac_jpeg_header2, sizeof(pac_jpeg_header2));
587}
588
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300589/* this function is run at interrupt level */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300590static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300591 u8 *data, /* isoc packet */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300592 int len) /* iso packet length */
593{
594 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moineb192ca92010-06-27 03:08:19 -0300595 u8 *image;
Hans de Goede327c4ab2008-09-03 17:12:14 -0300596 unsigned char *sof;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300597
Marton Nemetha6b69e42009-11-02 08:05:51 -0300598 sof = pac_find_sof(&sd->sof_read, data, len);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300599 if (sof) {
Hans de Goede327c4ab2008-09-03 17:12:14 -0300600 int n, lum_offset, footer_length;
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300601
Hans de Goede4b8ceb62012-04-28 10:20:50 -0300602 /*
603 * 6 bytes after the FF D9 EOF marker a number of lumination
604 * bytes are send corresponding to different parts of the
605 * image, the 14th and 15th byte after the EOF seem to
606 * correspond to the center of the image.
607 */
Marton Nemeth1408b842009-11-02 08:13:21 -0300608 lum_offset = 24 + sizeof pac_sof_marker;
609 footer_length = 26;
Hans de Goede327c4ab2008-09-03 17:12:14 -0300610
611 /* Finish decoding current frame */
612 n = (sof - data) - (footer_length + sizeof pac_sof_marker);
613 if (n < 0) {
Jean-François Moineb192ca92010-06-27 03:08:19 -0300614 gspca_dev->image_len += n;
Hans de Goede327c4ab2008-09-03 17:12:14 -0300615 n = 0;
Jean-François Moineb192ca92010-06-27 03:08:19 -0300616 } else {
617 gspca_frame_add(gspca_dev, INTER_PACKET, data, n);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300618 }
Jean-François Moinef7059ea2010-07-06 04:32:27 -0300619 image = gspca_dev->image;
620 if (image != NULL
Jean-François Moineb192ca92010-06-27 03:08:19 -0300621 && image[gspca_dev->image_len - 2] == 0xff
622 && image[gspca_dev->image_len - 1] == 0xd9)
623 gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300624
625 n = sof - data;
626 len -= n;
627 data = sof;
628
629 /* Get average lumination */
630 if (gspca_dev->last_packet_type == LAST_PACKET &&
Hans de Goede038ec7c2008-09-03 17:12:18 -0300631 n >= lum_offset)
632 atomic_set(&sd->avg_lum, data[-lum_offset] +
Hans de Goede327c4ab2008-09-03 17:12:14 -0300633 data[-lum_offset + 1]);
Hans de Goede038ec7c2008-09-03 17:12:18 -0300634 else
Hans de Goede327c4ab2008-09-03 17:12:14 -0300635 atomic_set(&sd->avg_lum, -1);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300636
637 /* Start the new frame with the jpeg header */
Jean-François Moineb192ca92010-06-27 03:08:19 -0300638 pac_start_frame(gspca_dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300639 gspca_dev->height, gspca_dev->width);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300640 }
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300641 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300642}
643
Jean-François Moine28566432010-10-01 07:33:26 -0300644#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
Hans de Goede32ea3e42010-01-29 11:04:19 -0300645static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
646 u8 *data, /* interrupt packet data */
647 int len) /* interrupt packet length */
648{
649 int ret = -EINVAL;
650 u8 data0, data1;
651
652 if (len == 2) {
653 data0 = data[0];
654 data1 = data[1];
655 if ((data0 == 0x00 && data1 == 0x11) ||
656 (data0 == 0x22 && data1 == 0x33) ||
657 (data0 == 0x44 && data1 == 0x55) ||
658 (data0 == 0x66 && data1 == 0x77) ||
659 (data0 == 0x88 && data1 == 0x99) ||
660 (data0 == 0xaa && data1 == 0xbb) ||
661 (data0 == 0xcc && data1 == 0xdd) ||
662 (data0 == 0xee && data1 == 0xff)) {
663 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
664 input_sync(gspca_dev->input_dev);
665 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
666 input_sync(gspca_dev->input_dev);
667 ret = 0;
668 }
669 }
670
671 return ret;
672}
673#endif
674
Márton Némethaabcdfb2010-01-05 12:39:02 -0300675static const struct sd_desc sd_desc = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300676 .name = MODULE_NAME,
677 .ctrls = sd_ctrls,
678 .nctrls = ARRAY_SIZE(sd_ctrls),
679 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300680 .init = sd_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300681 .start = sd_start,
682 .stopN = sd_stopN,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300683 .pkt_scan = sd_pkt_scan,
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300684 .dq_callback = do_autogain,
Jean-François Moine28566432010-10-01 07:33:26 -0300685#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
Hans de Goede32ea3e42010-01-29 11:04:19 -0300686 .int_pkt_scan = sd_int_pkt_scan,
687#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300688};
689
690/* -- module initialisation -- */
Jean-François Moine95c967c2011-01-13 05:20:29 -0300691static const struct usb_device_id device_table[] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300692 {USB_DEVICE(0x093a, 0x2600)},
693 {USB_DEVICE(0x093a, 0x2601)},
694 {USB_DEVICE(0x093a, 0x2603)},
695 {USB_DEVICE(0x093a, 0x2608)},
696 {USB_DEVICE(0x093a, 0x260e)},
697 {USB_DEVICE(0x093a, 0x260f)},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300698 {}
699};
700MODULE_DEVICE_TABLE(usb, device_table);
701
702/* -- device connect -- */
Jean-François Moine95c967c2011-01-13 05:20:29 -0300703static int sd_probe(struct usb_interface *intf,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300704 const struct usb_device_id *id)
705{
706 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
707 THIS_MODULE);
708}
709
710static struct usb_driver sd_driver = {
711 .name = MODULE_NAME,
712 .id_table = device_table,
713 .probe = sd_probe,
714 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -0300715#ifdef CONFIG_PM
716 .suspend = gspca_suspend,
717 .resume = gspca_resume,
718#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300719};
720
Greg Kroah-Hartmanecb3b2b2011-11-18 09:46:12 -0800721module_usb_driver(sd_driver);