blob: d125763650386f63208254bad5ea13002f8252db [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 Goede327c4ab2008-09-03 17:12:14 -030023
24 Register page 1:
25
26 Address Description
Hans de Goedeb053c1d2012-04-25 12:00:49 -030027 0x08 Unknown compressor related, must always be 8 except when not
Hans de Goede327c4ab2008-09-03 17:12:14 -030028 in 640x480 resolution and page 4 reg 2 <= 3 then set it to 9 !
Hans de Goedeb053c1d2012-04-25 12:00:49 -030029 0x1b Auto white balance related, bit 0 is AWB enable (inverted)
Hans de Goede327c4ab2008-09-03 17:12:14 -030030 bits 345 seem to toggle per color gains on/off (inverted)
31 0x78 Global control, bit 6 controls the LED (inverted)
Hans de Goedeb053c1d2012-04-25 12:00:49 -030032 0x80 JPEG compression ratio ? Best not touched
Hans de Goede327c4ab2008-09-03 17:12:14 -030033
Hans de Goedeb053c1d2012-04-25 12:00:49 -030034 Register page 4:
Hans de Goede327c4ab2008-09-03 17:12:14 -030035
36 Address Description
37 0x02 Clock divider 2-63, fps =~ 60 / val. Must be a multiple of 3 on
Hans de Goede038ec7c2008-09-03 17:12:18 -030038 the 7302, so one of 3, 6, 9, ..., except when between 6 and 12?
Hans de Goedeb053c1d2012-04-25 12:00:49 -030039 0x0f Master gain 1-245, low value = high gain
40 0x10 Another gain 0-15, limited influence (1-2x gain I guess)
Hans de Goede327c4ab2008-09-03 17:12:14 -030041 0x21 Bitfield: 0-1 unused, 2-3 vflip/hflip, 4-5 unknown, 6-7 unused
Hans de Goedeb053c1d2012-04-25 12:00:49 -030042 0x27 Seems to toggle various gains on / off, Setting bit 7 seems to
Hans de Goede8a5b2e92008-09-03 17:12:17 -030043 completely disable the analog amplification block. Set to 0x68
44 for max gain, 0x14 for minimal gain.
Hans de Goede327c4ab2008-09-03 17:12:14 -030045*/
46
Joe Perches133a9fe2011-08-21 19:56:57 -030047#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
48
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030049#define MODULE_NAME "pac7311"
50
Hans de Goede32ea3e42010-01-29 11:04:19 -030051#include <linux/input.h>
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030052#include "gspca.h"
53
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030054MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li");
55MODULE_DESCRIPTION("Pixart PAC7311");
56MODULE_LICENSE("GPL");
57
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030058struct sd {
59 struct gspca_dev gspca_dev; /* !! must be the first item */
60
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030061 unsigned char contrast;
Hans de Goede8a5b2e92008-09-03 17:12:17 -030062 unsigned char gain;
63 unsigned char exposure;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030064 unsigned char autogain;
Jean-Francois Moine41b46972008-09-03 16:47:58 -030065 __u8 hflip;
66 __u8 vflip;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -030067
Hans de Goede327c4ab2008-09-03 17:12:14 -030068 u8 sof_read;
Hans de Goede327c4ab2008-09-03 17:12:14 -030069 u8 autogain_ignore_frames;
70
71 atomic_t avg_lum;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030072};
73
74/* V4L2 controls supported by the driver */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030075static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
76static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030077static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
78static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
Jean-Francois Moine41b46972008-09-03 16:47:58 -030079static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val);
80static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val);
81static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
82static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
Hans de Goede8a5b2e92008-09-03 17:12:17 -030083static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
84static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
85static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
86static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030087
Marton Nemeth7e64dc42009-12-30 09:12:41 -030088static const struct ctrl sd_ctrls[] = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030089 {
90 {
91 .id = V4L2_CID_CONTRAST,
92 .type = V4L2_CTRL_TYPE_INTEGER,
93 .name = "Contrast",
94 .minimum = 0,
Jean-Francois Moinedff6d322008-09-03 16:47:57 -030095#define CONTRAST_MAX 255
96 .maximum = CONTRAST_MAX,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030097 .step = 1,
Hans de Goede327c4ab2008-09-03 17:12:14 -030098#define CONTRAST_DEF 127
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -030099 .default_value = CONTRAST_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300100 },
101 .set = sd_setcontrast,
102 .get = sd_getcontrast,
103 },
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300104 {
105 {
106 .id = V4L2_CID_GAIN,
107 .type = V4L2_CTRL_TYPE_INTEGER,
108 .name = "Gain",
109 .minimum = 0,
110#define GAIN_MAX 255
111 .maximum = GAIN_MAX,
112 .step = 1,
113#define GAIN_DEF 127
114#define GAIN_KNEE 255 /* Gain seems to cause little noise on the pac73xx */
115 .default_value = GAIN_DEF,
116 },
117 .set = sd_setgain,
118 .get = sd_getgain,
119 },
120 {
121 {
122 .id = V4L2_CID_EXPOSURE,
123 .type = V4L2_CTRL_TYPE_INTEGER,
124 .name = "Exposure",
125 .minimum = 0,
126#define EXPOSURE_MAX 255
127 .maximum = EXPOSURE_MAX,
128 .step = 1,
129#define EXPOSURE_DEF 16 /* 32 ms / 30 fps */
130#define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */
131 .default_value = EXPOSURE_DEF,
132 },
133 .set = sd_setexposure,
134 .get = sd_getexposure,
135 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300136 {
137 {
138 .id = V4L2_CID_AUTOGAIN,
139 .type = V4L2_CTRL_TYPE_BOOLEAN,
140 .name = "Auto Gain",
141 .minimum = 0,
142 .maximum = 1,
143 .step = 1,
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300144#define AUTOGAIN_DEF 1
145 .default_value = AUTOGAIN_DEF,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300146 },
147 .set = sd_setautogain,
148 .get = sd_getautogain,
149 },
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300150 {
151 {
152 .id = V4L2_CID_HFLIP,
153 .type = V4L2_CTRL_TYPE_BOOLEAN,
154 .name = "Mirror",
155 .minimum = 0,
156 .maximum = 1,
157 .step = 1,
158#define HFLIP_DEF 0
159 .default_value = HFLIP_DEF,
160 },
161 .set = sd_sethflip,
162 .get = sd_gethflip,
163 },
164 {
165 {
166 .id = V4L2_CID_VFLIP,
167 .type = V4L2_CTRL_TYPE_BOOLEAN,
168 .name = "Vflip",
169 .minimum = 0,
170 .maximum = 1,
171 .step = 1,
172#define VFLIP_DEF 0
173 .default_value = VFLIP_DEF,
174 },
175 .set = sd_setvflip,
176 .get = sd_getvflip,
177 },
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300178};
179
Jean-Francois Moinecc611b82008-12-29 07:49:41 -0300180static const struct v4l2_pix_format vga_mode[] = {
Jean-Francois Moinef75c4952008-09-03 16:47:35 -0300181 {160, 120, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300182 .bytesperline = 160,
183 .sizeimage = 160 * 120 * 3 / 8 + 590,
184 .colorspace = V4L2_COLORSPACE_JPEG,
185 .priv = 2},
Jean-Francois Moinef75c4952008-09-03 16:47:35 -0300186 {320, 240, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300187 .bytesperline = 320,
188 .sizeimage = 320 * 240 * 3 / 8 + 590,
189 .colorspace = V4L2_COLORSPACE_JPEG,
190 .priv = 1},
Jean-Francois Moinef75c4952008-09-03 16:47:35 -0300191 {640, 480, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300192 .bytesperline = 640,
193 .sizeimage = 640 * 480 * 3 / 8 + 590,
194 .colorspace = V4L2_COLORSPACE_JPEG,
195 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300196};
197
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300198#define LOAD_PAGE4 254
199#define END_OF_SEQUENCE 0
200
Hans de Goede271315a2008-09-03 17:12:19 -0300201static const __u8 init_7311[] = {
Hans de Goede327c4ab2008-09-03 17:12:14 -0300202 0x78, 0x40, /* Bit_0=start stream, Bit_6=LED */
203 0x78, 0x40, /* Bit_0=start stream, Bit_6=LED */
204 0x78, 0x44, /* Bit_0=start stream, Bit_6=LED */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300205 0xff, 0x04,
206 0x27, 0x80,
207 0x28, 0xca,
208 0x29, 0x53,
209 0x2a, 0x0e,
210 0xff, 0x01,
211 0x3e, 0x20,
212};
213
214static const __u8 start_7311[] = {
215/* index, len, [value]* */
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300216 0xff, 1, 0x01, /* page 1 */
217 0x02, 43, 0x48, 0x0a, 0x40, 0x08, 0x00, 0x00, 0x08, 0x00,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300218 0x06, 0xff, 0x11, 0xff, 0x5a, 0x30, 0x90, 0x4c,
219 0x00, 0x07, 0x00, 0x0a, 0x10, 0x00, 0xa0, 0x10,
220 0x02, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x01, 0x00,
221 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
222 0x00, 0x00, 0x00,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300223 0x3e, 42, 0x00, 0x00, 0x78, 0x52, 0x4a, 0x52, 0x78, 0x6e,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300224 0x48, 0x46, 0x48, 0x6e, 0x5f, 0x49, 0x42, 0x49,
225 0x5f, 0x5f, 0x49, 0x42, 0x49, 0x5f, 0x6e, 0x48,
226 0x46, 0x48, 0x6e, 0x78, 0x52, 0x4a, 0x52, 0x78,
227 0x00, 0x00, 0x09, 0x1b, 0x34, 0x49, 0x5c, 0x9b,
228 0xd0, 0xff,
229 0x78, 6, 0x44, 0x00, 0xf2, 0x01, 0x01, 0x80,
230 0x7f, 18, 0x2a, 0x1c, 0x00, 0xc8, 0x02, 0x58, 0x03, 0x84,
231 0x12, 0x00, 0x1a, 0x04, 0x08, 0x0c, 0x10, 0x14,
232 0x18, 0x20,
233 0x96, 3, 0x01, 0x08, 0x04,
234 0xa0, 4, 0x44, 0x44, 0x44, 0x04,
235 0xf0, 13, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x20, 0x00,
236 0x3f, 0x00, 0x0a, 0x01, 0x00,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300237 0xff, 1, 0x04, /* page 4 */
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300238 0, LOAD_PAGE4, /* load the page 4 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300239 0x11, 1, 0x01,
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300240 0, END_OF_SEQUENCE /* end of sequence */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300241};
242
Marton Nemeth1408b842009-11-02 08:13:21 -0300243#define SKIP 0xaa
Marton Nemethff75e992009-10-04 13:51:26 -0300244/* page 4 - the value SKIP says skip the index - see reg_w_page() */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300245static const __u8 page4_7311[] = {
Marton Nemethff75e992009-10-04 13:51:26 -0300246 SKIP, SKIP, 0x04, 0x54, 0x07, 0x2b, 0x09, 0x0f,
247 0x09, 0x00, SKIP, SKIP, 0x07, 0x00, 0x00, 0x62,
248 0x08, SKIP, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
249 0x00, 0x00, 0x00, 0x03, 0xa0, 0x01, 0xf4, SKIP,
250 SKIP, 0x00, 0x08, SKIP, 0x03, SKIP, 0x00, 0x68,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300251 0xca, 0x10, 0x06, 0x78, 0x00, 0x00, 0x00, 0x00,
252 0x23, 0x28, 0x04, 0x11, 0x00, 0x00
253};
254
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300255static void reg_w_buf(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300256 __u8 index,
Jean-François Moine0aeb5ec2010-12-28 06:59:04 -0300257 const u8 *buffer, int len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300258{
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300259 int ret;
260
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300261 if (gspca_dev->usb_err < 0)
262 return;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300263 memcpy(gspca_dev->usb_buf, buffer, len);
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300264 ret = usb_control_msg(gspca_dev->dev,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300265 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-François Moinea1317132010-06-24 04:50:26 -0300266 0, /* request */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300267 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300268 0, /* value */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300269 index, gspca_dev->usb_buf, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300270 500);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300271 if (ret < 0) {
Joe Perches133a9fe2011-08-21 19:56:57 -0300272 pr_err("reg_w_buf() failed index 0x%02x, error %d\n",
273 index, ret);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300274 gspca_dev->usb_err = ret;
275 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300276}
277
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300278
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300279static void reg_w(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300280 __u8 index,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300281 __u8 value)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300282{
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300283 int ret;
284
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300285 if (gspca_dev->usb_err < 0)
286 return;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300287 gspca_dev->usb_buf[0] = value;
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300288 ret = usb_control_msg(gspca_dev->dev,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300289 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300290 0, /* request */
291 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300292 0, index, gspca_dev->usb_buf, 1,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300293 500);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300294 if (ret < 0) {
Joe Perches133a9fe2011-08-21 19:56:57 -0300295 pr_err("reg_w() failed index 0x%02x, value 0x%02x, error %d\n",
296 index, value, ret);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300297 gspca_dev->usb_err = ret;
298 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300299}
300
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300301static void reg_w_seq(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300302 const __u8 *seq, int len)
303{
304 while (--len >= 0) {
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300305 reg_w(gspca_dev, seq[0], seq[1]);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300306 seq += 2;
307 }
308}
309
310/* load the beginning of a page */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300311static void reg_w_page(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300312 const __u8 *page, int len)
313{
314 int index;
Márton Némethb1784b32009-11-07 05:52:02 -0300315 int ret = 0;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300316
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300317 if (gspca_dev->usb_err < 0)
318 return;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300319 for (index = 0; index < len; index++) {
Marton Nemethff75e992009-10-04 13:51:26 -0300320 if (page[index] == SKIP) /* skip this index */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300321 continue;
322 gspca_dev->usb_buf[0] = page[index];
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300323 ret = usb_control_msg(gspca_dev->dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300324 usb_sndctrlpipe(gspca_dev->dev, 0),
325 0, /* request */
326 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
327 0, index, gspca_dev->usb_buf, 1,
328 500);
Márton Némethb1784b32009-11-07 05:52:02 -0300329 if (ret < 0) {
Joe Perches133a9fe2011-08-21 19:56:57 -0300330 pr_err("reg_w_page() failed index 0x%02x, value 0x%02x, error %d\n",
331 index, page[index], ret);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300332 gspca_dev->usb_err = ret;
Márton Némethb1784b32009-11-07 05:52:02 -0300333 break;
334 }
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300335 }
336}
337
338/* output a variable sequence */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300339static void reg_w_var(struct gspca_dev *gspca_dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300340 const __u8 *seq,
Marton Nemeth1408b842009-11-02 08:13:21 -0300341 const __u8 *page4, unsigned int page4_len)
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300342{
343 int index, len;
344
345 for (;;) {
346 index = *seq++;
347 len = *seq++;
348 switch (len) {
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300349 case END_OF_SEQUENCE:
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300350 return;
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300351 case LOAD_PAGE4:
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300352 reg_w_page(gspca_dev, page4, page4_len);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300353 break;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300354 default:
Marton Nemeth24067bb2009-10-04 13:54:48 -0300355 if (len > USB_BUF_SZ) {
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300356 PDEBUG(D_ERR|D_STREAM,
357 "Incorrect variable sequence");
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300358 return;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300359 }
360 while (len > 0) {
361 if (len < 8) {
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300362 reg_w_buf(gspca_dev,
Márton Némethb1784b32009-11-07 05:52:02 -0300363 index, seq, len);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300364 seq += len;
365 break;
366 }
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300367 reg_w_buf(gspca_dev, index, seq, 8);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300368 seq += 8;
369 index += 8;
370 len -= 8;
371 }
372 }
373 }
374 /* not reached */
375}
376
Marton Nemeth1408b842009-11-02 08:13:21 -0300377/* this function is called at probe time for pac7311 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300378static int sd_config(struct gspca_dev *gspca_dev,
379 const struct usb_device_id *id)
380{
381 struct sd *sd = (struct sd *) gspca_dev;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300382 struct cam *cam;
383
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300384 cam = &gspca_dev->cam;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300385
Marton Nemeth1408b842009-11-02 08:13:21 -0300386 cam->cam_mode = vga_mode;
387 cam->nmodes = ARRAY_SIZE(vga_mode);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300388
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300389 sd->contrast = CONTRAST_DEF;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300390 sd->gain = GAIN_DEF;
391 sd->exposure = EXPOSURE_DEF;
Jean-Francois Moinea5ae2062008-07-04 11:16:16 -0300392 sd->autogain = AUTOGAIN_DEF;
Jean-Francois Moine4a186252008-09-03 16:48:02 -0300393 sd->hflip = HFLIP_DEF;
394 sd->vflip = VFLIP_DEF;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300395 return 0;
396}
397
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300398static void setcontrast(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300399{
400 struct sd *sd = (struct sd *) gspca_dev;
401
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300402 reg_w(gspca_dev, 0xff, 0x04);
403 reg_w(gspca_dev, 0x10, sd->contrast >> 4);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300404 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300405 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300406}
407
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300408static void setgain(struct gspca_dev *gspca_dev)
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300409{
410 struct sd *sd = (struct sd *) gspca_dev;
Marton Nemeth1408b842009-11-02 08:13:21 -0300411 int gain = GAIN_MAX - sd->gain;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300412
Marton Nemeth1408b842009-11-02 08:13:21 -0300413 if (gain < 1)
414 gain = 1;
415 else if (gain > 245)
416 gain = 245;
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300417 reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
418 reg_w(gspca_dev, 0x0e, 0x00);
419 reg_w(gspca_dev, 0x0f, gain);
Marton Nemeth1408b842009-11-02 08:13:21 -0300420
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300421 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300422 reg_w(gspca_dev, 0x11, 0x01);
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300423}
424
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300425static void setexposure(struct gspca_dev *gspca_dev)
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300426{
427 struct sd *sd = (struct sd *) gspca_dev;
428 __u8 reg;
429
Hans de Goedeb053c1d2012-04-25 12:00:49 -0300430 /* register 2 of page 4 contains the clock divider configuring the
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300431 no fps according to the formula: 60 / reg. sd->exposure is the
432 desired exposure time in ms. */
433 reg = 120 * sd->exposure / 1000;
434 if (reg < 2)
435 reg = 2;
436 else if (reg > 63)
437 reg = 63;
438
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300439 reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
440 reg_w(gspca_dev, 0x02, reg);
441
Hans de Goede51ae23d2012-04-18 06:12:57 -0300442 /* load registers to sensor (Bit 0, auto clear) */
443 reg_w(gspca_dev, 0x11, 0x01);
444
Marton Nemeth1408b842009-11-02 08:13:21 -0300445 /* Page 1 register 8 must always be 0x08 except when not in
Hans de Goedeb053c1d2012-04-25 12:00:49 -0300446 640x480 mode and page 4 reg 2 <= 3 then it must be 9 */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300447 reg_w(gspca_dev, 0xff, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300448 if (gspca_dev->cam.cam_mode[(int)gspca_dev->curr_mode].priv &&
Márton Némethb1784b32009-11-07 05:52:02 -0300449 reg <= 3) {
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300450 reg_w(gspca_dev, 0x08, 0x09);
Márton Némethb1784b32009-11-07 05:52:02 -0300451 } else {
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300452 reg_w(gspca_dev, 0x08, 0x08);
Márton Némethb1784b32009-11-07 05:52:02 -0300453 }
Marton Nemeth1408b842009-11-02 08:13:21 -0300454
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300455 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300456 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300457}
458
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300459static void sethvflip(struct gspca_dev *gspca_dev)
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300460{
461 struct sd *sd = (struct sd *) gspca_dev;
462 __u8 data;
463
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300464 reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
Marton Nemeth1408b842009-11-02 08:13:21 -0300465 data = (sd->hflip ? 0x04 : 0x00) | (sd->vflip ? 0x08 : 0x00);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300466 reg_w(gspca_dev, 0x21, data);
467
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300468 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300469 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300470}
471
Marton Nemeth1408b842009-11-02 08:13:21 -0300472/* this function is called at probe and resume time for pac7311 */
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300473static int sd_init(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300474{
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300475 reg_w_seq(gspca_dev, init_7311, sizeof(init_7311)/2);
476 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300477}
478
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300479static int sd_start(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300480{
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300481 struct sd *sd = (struct sd *) gspca_dev;
482
Hans de Goede327c4ab2008-09-03 17:12:14 -0300483 sd->sof_read = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300484
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300485 reg_w_var(gspca_dev, start_7311,
Marton Nemeth1408b842009-11-02 08:13:21 -0300486 page4_7311, sizeof(page4_7311));
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300487 setcontrast(gspca_dev);
488 setgain(gspca_dev);
489 setexposure(gspca_dev);
490 sethvflip(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300491
492 /* set correct resolution */
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300493 switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
Hans de Goedeb053c1d2012-04-25 12:00:49 -0300494 case 2: /* 160x120 */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300495 reg_w(gspca_dev, 0xff, 0x01);
496 reg_w(gspca_dev, 0x17, 0x20);
497 reg_w(gspca_dev, 0x87, 0x10);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300498 break;
Hans de Goedeb053c1d2012-04-25 12:00:49 -0300499 case 1: /* 320x240 */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300500 reg_w(gspca_dev, 0xff, 0x01);
501 reg_w(gspca_dev, 0x17, 0x30);
502 reg_w(gspca_dev, 0x87, 0x11);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300503 break;
504 case 0: /* 640x480 */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300505 reg_w(gspca_dev, 0xff, 0x01);
506 reg_w(gspca_dev, 0x17, 0x00);
507 reg_w(gspca_dev, 0x87, 0x12);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300508 break;
509 }
510
Hans de Goede327c4ab2008-09-03 17:12:14 -0300511 sd->sof_read = 0;
512 sd->autogain_ignore_frames = 0;
513 atomic_set(&sd->avg_lum, -1);
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300514
515 /* start stream */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300516 reg_w(gspca_dev, 0xff, 0x01);
517 reg_w(gspca_dev, 0x78, 0x05);
Marton Nemeth1408b842009-11-02 08:13:21 -0300518
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300519 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300520}
521
522static void sd_stopN(struct gspca_dev *gspca_dev)
523{
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300524 reg_w(gspca_dev, 0xff, 0x04);
525 reg_w(gspca_dev, 0x27, 0x80);
526 reg_w(gspca_dev, 0x28, 0xca);
527 reg_w(gspca_dev, 0x29, 0x53);
528 reg_w(gspca_dev, 0x2a, 0x0e);
529 reg_w(gspca_dev, 0xff, 0x01);
530 reg_w(gspca_dev, 0x3e, 0x20);
531 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
532 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
533 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300534}
535
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300536/* Include pac common sof detection functions */
537#include "pac_common.h"
538
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300539static void do_autogain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300540{
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300541 struct sd *sd = (struct sd *) gspca_dev;
542 int avg_lum = atomic_read(&sd->avg_lum);
Hans de Goede038ec7c2008-09-03 17:12:18 -0300543 int desired_lum, deadzone;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300544
545 if (avg_lum == -1)
546 return;
547
Marton Nemeth1408b842009-11-02 08:13:21 -0300548 desired_lum = 200;
549 deadzone = 20;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300550
551 if (sd->autogain_ignore_frames > 0)
552 sd->autogain_ignore_frames--;
553 else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum,
Hans de Goede038ec7c2008-09-03 17:12:18 -0300554 deadzone, GAIN_KNEE, EXPOSURE_KNEE))
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300555 sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300556}
557
Marton Nemeth56f6f552009-10-04 13:58:19 -0300558/* JPEG header, part 1 */
Marton Nemethcc409c02009-11-02 08:09:34 -0300559static const unsigned char pac_jpeg_header1[] = {
Marton Nemeth56f6f552009-10-04 13:58:19 -0300560 0xff, 0xd8, /* SOI: Start of Image */
561
562 0xff, 0xc0, /* SOF0: Start of Frame (Baseline DCT) */
563 0x00, 0x11, /* length = 17 bytes (including this length field) */
564 0x08 /* Precision: 8 */
565 /* 2 bytes is placed here: number of image lines */
566 /* 2 bytes is placed here: samples per line */
Hans de Goede327c4ab2008-09-03 17:12:14 -0300567};
568
Marton Nemeth56f6f552009-10-04 13:58:19 -0300569/* JPEG header, continued */
Marton Nemethcc409c02009-11-02 08:09:34 -0300570static const unsigned char pac_jpeg_header2[] = {
Marton Nemeth56f6f552009-10-04 13:58:19 -0300571 0x03, /* Number of image components: 3 */
572 0x01, 0x21, 0x00, /* ID=1, Subsampling 1x1, Quantization table: 0 */
573 0x02, 0x11, 0x01, /* ID=2, Subsampling 2x1, Quantization table: 1 */
574 0x03, 0x11, 0x01, /* ID=3, Subsampling 2x1, Quantization table: 1 */
575
576 0xff, 0xda, /* SOS: Start Of Scan */
577 0x00, 0x0c, /* length = 12 bytes (including this length field) */
578 0x03, /* number of components: 3 */
579 0x01, 0x00, /* selector 1, table 0x00 */
580 0x02, 0x11, /* selector 2, table 0x11 */
581 0x03, 0x11, /* selector 3, table 0x11 */
582 0x00, 0x3f, /* Spectral selection: 0 .. 63 */
583 0x00 /* Successive approximation: 0 */
Hans de Goede327c4ab2008-09-03 17:12:14 -0300584};
585
Marton Nemethcc409c02009-11-02 08:09:34 -0300586static void pac_start_frame(struct gspca_dev *gspca_dev,
Marton Nemethcc409c02009-11-02 08:09:34 -0300587 __u16 lines, __u16 samples_per_line)
588{
589 unsigned char tmpbuf[4];
590
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300591 gspca_frame_add(gspca_dev, FIRST_PACKET,
Marton Nemethcc409c02009-11-02 08:09:34 -0300592 pac_jpeg_header1, sizeof(pac_jpeg_header1));
593
594 tmpbuf[0] = lines >> 8;
595 tmpbuf[1] = lines & 0xff;
596 tmpbuf[2] = samples_per_line >> 8;
597 tmpbuf[3] = samples_per_line & 0xff;
598
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300599 gspca_frame_add(gspca_dev, INTER_PACKET,
Marton Nemethcc409c02009-11-02 08:09:34 -0300600 tmpbuf, sizeof(tmpbuf));
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300601 gspca_frame_add(gspca_dev, INTER_PACKET,
Marton Nemethcc409c02009-11-02 08:09:34 -0300602 pac_jpeg_header2, sizeof(pac_jpeg_header2));
603}
604
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300605/* this function is run at interrupt level */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300606static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300607 u8 *data, /* isoc packet */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300608 int len) /* iso packet length */
609{
610 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moineb192ca92010-06-27 03:08:19 -0300611 u8 *image;
Hans de Goede327c4ab2008-09-03 17:12:14 -0300612 unsigned char *sof;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300613
Marton Nemetha6b69e42009-11-02 08:05:51 -0300614 sof = pac_find_sof(&sd->sof_read, data, len);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300615 if (sof) {
Hans de Goede327c4ab2008-09-03 17:12:14 -0300616 int n, lum_offset, footer_length;
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300617
Marton Nemeth1408b842009-11-02 08:13:21 -0300618 /* 6 bytes after the FF D9 EOF marker a number of lumination
619 bytes are send corresponding to different parts of the
620 image, the 14th and 15th byte after the EOF seem to
621 correspond to the center of the image */
622 lum_offset = 24 + sizeof pac_sof_marker;
623 footer_length = 26;
Hans de Goede327c4ab2008-09-03 17:12:14 -0300624
625 /* Finish decoding current frame */
626 n = (sof - data) - (footer_length + sizeof pac_sof_marker);
627 if (n < 0) {
Jean-François Moineb192ca92010-06-27 03:08:19 -0300628 gspca_dev->image_len += n;
Hans de Goede327c4ab2008-09-03 17:12:14 -0300629 n = 0;
Jean-François Moineb192ca92010-06-27 03:08:19 -0300630 } else {
631 gspca_frame_add(gspca_dev, INTER_PACKET, data, n);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300632 }
Jean-François Moinef7059ea2010-07-06 04:32:27 -0300633 image = gspca_dev->image;
634 if (image != NULL
Jean-François Moineb192ca92010-06-27 03:08:19 -0300635 && image[gspca_dev->image_len - 2] == 0xff
636 && image[gspca_dev->image_len - 1] == 0xd9)
637 gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300638
639 n = sof - data;
640 len -= n;
641 data = sof;
642
643 /* Get average lumination */
644 if (gspca_dev->last_packet_type == LAST_PACKET &&
Hans de Goede038ec7c2008-09-03 17:12:18 -0300645 n >= lum_offset)
646 atomic_set(&sd->avg_lum, data[-lum_offset] +
Hans de Goede327c4ab2008-09-03 17:12:14 -0300647 data[-lum_offset + 1]);
Hans de Goede038ec7c2008-09-03 17:12:18 -0300648 else
Hans de Goede327c4ab2008-09-03 17:12:14 -0300649 atomic_set(&sd->avg_lum, -1);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300650
651 /* Start the new frame with the jpeg header */
Jean-François Moineb192ca92010-06-27 03:08:19 -0300652 pac_start_frame(gspca_dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300653 gspca_dev->height, gspca_dev->width);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300654 }
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300655 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300656}
657
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300658static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
659{
660 struct sd *sd = (struct sd *) gspca_dev;
661
662 sd->contrast = val;
Jean-François Moine780e3122010-10-19 04:29:10 -0300663 if (gspca_dev->streaming)
Marton Nemeth1408b842009-11-02 08:13:21 -0300664 setcontrast(gspca_dev);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300665 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300666}
667
668static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
669{
670 struct sd *sd = (struct sd *) gspca_dev;
671
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300672 *val = sd->contrast;
673 return 0;
674}
675
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300676static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
677{
678 struct sd *sd = (struct sd *) gspca_dev;
679
680 sd->gain = val;
681 if (gspca_dev->streaming)
682 setgain(gspca_dev);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300683 return gspca_dev->usb_err;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300684}
685
686static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
687{
688 struct sd *sd = (struct sd *) gspca_dev;
689
690 *val = sd->gain;
691 return 0;
692}
693
694static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
695{
696 struct sd *sd = (struct sd *) gspca_dev;
697
698 sd->exposure = val;
699 if (gspca_dev->streaming)
700 setexposure(gspca_dev);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300701 return gspca_dev->usb_err;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300702}
703
704static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
705{
706 struct sd *sd = (struct sd *) gspca_dev;
707
708 *val = sd->exposure;
709 return 0;
710}
711
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300712static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
713{
714 struct sd *sd = (struct sd *) gspca_dev;
715
716 sd->autogain = val;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300717 /* when switching to autogain set defaults to make sure
718 we are on a valid point of the autogain gain /
719 exposure knee graph, and give this change time to
720 take effect before doing autogain. */
721 if (sd->autogain) {
722 sd->exposure = EXPOSURE_DEF;
723 sd->gain = GAIN_DEF;
724 if (gspca_dev->streaming) {
725 sd->autogain_ignore_frames =
726 PAC_AUTOGAIN_IGNORE_FRAMES;
727 setexposure(gspca_dev);
728 setgain(gspca_dev);
729 }
730 }
Hans de Goede327c4ab2008-09-03 17:12:14 -0300731
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300732 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300733}
734
735static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
736{
737 struct sd *sd = (struct sd *) gspca_dev;
738
739 *val = sd->autogain;
740 return 0;
741}
742
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300743static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
744{
745 struct sd *sd = (struct sd *) gspca_dev;
746
747 sd->hflip = val;
748 if (gspca_dev->streaming)
749 sethvflip(gspca_dev);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300750 return gspca_dev->usb_err;
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300751}
752
753static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
754{
755 struct sd *sd = (struct sd *) gspca_dev;
756
757 *val = sd->hflip;
758 return 0;
759}
760
761static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
762{
763 struct sd *sd = (struct sd *) gspca_dev;
764
765 sd->vflip = val;
766 if (gspca_dev->streaming)
767 sethvflip(gspca_dev);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300768 return gspca_dev->usb_err;
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300769}
770
771static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
772{
773 struct sd *sd = (struct sd *) gspca_dev;
774
775 *val = sd->vflip;
776 return 0;
777}
778
Jean-François Moine28566432010-10-01 07:33:26 -0300779#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
Hans de Goede32ea3e42010-01-29 11:04:19 -0300780static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
781 u8 *data, /* interrupt packet data */
782 int len) /* interrupt packet length */
783{
784 int ret = -EINVAL;
785 u8 data0, data1;
786
787 if (len == 2) {
788 data0 = data[0];
789 data1 = data[1];
790 if ((data0 == 0x00 && data1 == 0x11) ||
791 (data0 == 0x22 && data1 == 0x33) ||
792 (data0 == 0x44 && data1 == 0x55) ||
793 (data0 == 0x66 && data1 == 0x77) ||
794 (data0 == 0x88 && data1 == 0x99) ||
795 (data0 == 0xaa && data1 == 0xbb) ||
796 (data0 == 0xcc && data1 == 0xdd) ||
797 (data0 == 0xee && data1 == 0xff)) {
798 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
799 input_sync(gspca_dev->input_dev);
800 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
801 input_sync(gspca_dev->input_dev);
802 ret = 0;
803 }
804 }
805
806 return ret;
807}
808#endif
809
Márton Némethaabcdfb2010-01-05 12:39:02 -0300810static const struct sd_desc sd_desc = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300811 .name = MODULE_NAME,
812 .ctrls = sd_ctrls,
813 .nctrls = ARRAY_SIZE(sd_ctrls),
814 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300815 .init = sd_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300816 .start = sd_start,
817 .stopN = sd_stopN,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300818 .pkt_scan = sd_pkt_scan,
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300819 .dq_callback = do_autogain,
Jean-François Moine28566432010-10-01 07:33:26 -0300820#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
Hans de Goede32ea3e42010-01-29 11:04:19 -0300821 .int_pkt_scan = sd_int_pkt_scan,
822#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300823};
824
825/* -- module initialisation -- */
Jean-François Moine95c967c2011-01-13 05:20:29 -0300826static const struct usb_device_id device_table[] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300827 {USB_DEVICE(0x093a, 0x2600)},
828 {USB_DEVICE(0x093a, 0x2601)},
829 {USB_DEVICE(0x093a, 0x2603)},
830 {USB_DEVICE(0x093a, 0x2608)},
831 {USB_DEVICE(0x093a, 0x260e)},
832 {USB_DEVICE(0x093a, 0x260f)},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300833 {}
834};
835MODULE_DEVICE_TABLE(usb, device_table);
836
837/* -- device connect -- */
Jean-François Moine95c967c2011-01-13 05:20:29 -0300838static int sd_probe(struct usb_interface *intf,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300839 const struct usb_device_id *id)
840{
841 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
842 THIS_MODULE);
843}
844
845static struct usb_driver sd_driver = {
846 .name = MODULE_NAME,
847 .id_table = device_table,
848 .probe = sd_probe,
849 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -0300850#ifdef CONFIG_PM
851 .suspend = gspca_suspend,
852 .resume = gspca_resume,
853#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300854};
855
Greg Kroah-Hartmanecb3b2b2011-11-18 09:46:12 -0800856module_usb_driver(sd_driver);