blob: 4efa110e69320e9c505eb7b1b727200db598fc8b [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,
Hans de Goedec894d262012-04-25 12:17:19 -030095#define CONTRAST_MAX 15
Jean-Francois Moinedff6d322008-09-03 16:47:57 -030096 .maximum = CONTRAST_MAX,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030097 .step = 1,
Hans de Goedec894d262012-04-25 12:17:19 -030098#define CONTRAST_DEF 7
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,
Hans de Goedec894d262012-04-25 12:17:19 -0300110#define GAIN_MAX 244
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300111 .maximum = GAIN_MAX,
112 .step = 1,
Hans de Goedec894d262012-04-25 12:17:19 -0300113#define GAIN_DEF 122
114#define GAIN_KNEE GAIN_MAX /* Gain seems to cause little noise on the 7311 */
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300115 .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",
Hans de Goedec894d262012-04-25 12:17:19 -0300125 .minimum = 2,
126#define EXPOSURE_MAX 63
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300127 .maximum = EXPOSURE_MAX,
128 .step = 1,
Hans de Goedec894d262012-04-25 12:17:19 -0300129#define EXPOSURE_DEF 2 /* 30 fps */
130#define EXPOSURE_KNEE 6 /* 10 fps */
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300131 .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);
Hans de Goedec894d262012-04-25 12:17:19 -0300403 reg_w(gspca_dev, 0x10, sd->contrast);
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;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300411
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300412 reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
413 reg_w(gspca_dev, 0x0e, 0x00);
Hans de Goedec894d262012-04-25 12:17:19 -0300414 reg_w(gspca_dev, 0x0f, GAIN_MAX - sd->gain + 1);
Marton Nemeth1408b842009-11-02 08:13:21 -0300415
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300416 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300417 reg_w(gspca_dev, 0x11, 0x01);
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300418}
419
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300420static void setexposure(struct gspca_dev *gspca_dev)
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300421{
422 struct sd *sd = (struct sd *) gspca_dev;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300423
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300424 reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
Hans de Goedec894d262012-04-25 12:17:19 -0300425 reg_w(gspca_dev, 0x02, sd->exposure);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300426
Hans de Goede51ae23d2012-04-18 06:12:57 -0300427 /* load registers to sensor (Bit 0, auto clear) */
428 reg_w(gspca_dev, 0x11, 0x01);
429
Marton Nemeth1408b842009-11-02 08:13:21 -0300430 /* Page 1 register 8 must always be 0x08 except when not in
Hans de Goedeb053c1d2012-04-25 12:00:49 -0300431 640x480 mode and page 4 reg 2 <= 3 then it must be 9 */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300432 reg_w(gspca_dev, 0xff, 0x01);
Marton Nemeth1408b842009-11-02 08:13:21 -0300433 if (gspca_dev->cam.cam_mode[(int)gspca_dev->curr_mode].priv &&
Hans de Goedec894d262012-04-25 12:17:19 -0300434 sd->exposure <= 3) {
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300435 reg_w(gspca_dev, 0x08, 0x09);
Márton Némethb1784b32009-11-07 05:52:02 -0300436 } else {
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300437 reg_w(gspca_dev, 0x08, 0x08);
Márton Némethb1784b32009-11-07 05:52:02 -0300438 }
Marton Nemeth1408b842009-11-02 08:13:21 -0300439
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300440 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300441 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300442}
443
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300444static void sethvflip(struct gspca_dev *gspca_dev)
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300445{
446 struct sd *sd = (struct sd *) gspca_dev;
447 __u8 data;
448
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300449 reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
Marton Nemeth1408b842009-11-02 08:13:21 -0300450 data = (sd->hflip ? 0x04 : 0x00) | (sd->vflip ? 0x08 : 0x00);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300451 reg_w(gspca_dev, 0x21, data);
452
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300453 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300454 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300455}
456
Marton Nemeth1408b842009-11-02 08:13:21 -0300457/* this function is called at probe and resume time for pac7311 */
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300458static int sd_init(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300459{
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300460 reg_w_seq(gspca_dev, init_7311, sizeof(init_7311)/2);
461 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300462}
463
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300464static int sd_start(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300465{
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300466 struct sd *sd = (struct sd *) gspca_dev;
467
Hans de Goede327c4ab2008-09-03 17:12:14 -0300468 sd->sof_read = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300469
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300470 reg_w_var(gspca_dev, start_7311,
Marton Nemeth1408b842009-11-02 08:13:21 -0300471 page4_7311, sizeof(page4_7311));
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300472 setcontrast(gspca_dev);
473 setgain(gspca_dev);
474 setexposure(gspca_dev);
475 sethvflip(gspca_dev);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300476
477 /* set correct resolution */
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300478 switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
Hans de Goedeb053c1d2012-04-25 12:00:49 -0300479 case 2: /* 160x120 */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300480 reg_w(gspca_dev, 0xff, 0x01);
481 reg_w(gspca_dev, 0x17, 0x20);
482 reg_w(gspca_dev, 0x87, 0x10);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300483 break;
Hans de Goedeb053c1d2012-04-25 12:00:49 -0300484 case 1: /* 320x240 */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300485 reg_w(gspca_dev, 0xff, 0x01);
486 reg_w(gspca_dev, 0x17, 0x30);
487 reg_w(gspca_dev, 0x87, 0x11);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300488 break;
489 case 0: /* 640x480 */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300490 reg_w(gspca_dev, 0xff, 0x01);
491 reg_w(gspca_dev, 0x17, 0x00);
492 reg_w(gspca_dev, 0x87, 0x12);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300493 break;
494 }
495
Hans de Goede327c4ab2008-09-03 17:12:14 -0300496 sd->sof_read = 0;
497 sd->autogain_ignore_frames = 0;
498 atomic_set(&sd->avg_lum, -1);
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300499
500 /* start stream */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300501 reg_w(gspca_dev, 0xff, 0x01);
502 reg_w(gspca_dev, 0x78, 0x05);
Marton Nemeth1408b842009-11-02 08:13:21 -0300503
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300504 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300505}
506
507static void sd_stopN(struct gspca_dev *gspca_dev)
508{
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300509 reg_w(gspca_dev, 0xff, 0x04);
510 reg_w(gspca_dev, 0x27, 0x80);
511 reg_w(gspca_dev, 0x28, 0xca);
512 reg_w(gspca_dev, 0x29, 0x53);
513 reg_w(gspca_dev, 0x2a, 0x0e);
514 reg_w(gspca_dev, 0xff, 0x01);
515 reg_w(gspca_dev, 0x3e, 0x20);
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 */
518 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300519}
520
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300521/* Include pac common sof detection functions */
522#include "pac_common.h"
523
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300524static void do_autogain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300525{
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300526 struct sd *sd = (struct sd *) gspca_dev;
527 int avg_lum = atomic_read(&sd->avg_lum);
Hans de Goede038ec7c2008-09-03 17:12:18 -0300528 int desired_lum, deadzone;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300529
530 if (avg_lum == -1)
531 return;
532
Marton Nemeth1408b842009-11-02 08:13:21 -0300533 desired_lum = 200;
534 deadzone = 20;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300535
536 if (sd->autogain_ignore_frames > 0)
537 sd->autogain_ignore_frames--;
538 else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum,
Hans de Goede038ec7c2008-09-03 17:12:18 -0300539 deadzone, GAIN_KNEE, EXPOSURE_KNEE))
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300540 sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300541}
542
Marton Nemeth56f6f552009-10-04 13:58:19 -0300543/* JPEG header, part 1 */
Marton Nemethcc409c02009-11-02 08:09:34 -0300544static const unsigned char pac_jpeg_header1[] = {
Marton Nemeth56f6f552009-10-04 13:58:19 -0300545 0xff, 0xd8, /* SOI: Start of Image */
546
547 0xff, 0xc0, /* SOF0: Start of Frame (Baseline DCT) */
548 0x00, 0x11, /* length = 17 bytes (including this length field) */
549 0x08 /* Precision: 8 */
550 /* 2 bytes is placed here: number of image lines */
551 /* 2 bytes is placed here: samples per line */
Hans de Goede327c4ab2008-09-03 17:12:14 -0300552};
553
Marton Nemeth56f6f552009-10-04 13:58:19 -0300554/* JPEG header, continued */
Marton Nemethcc409c02009-11-02 08:09:34 -0300555static const unsigned char pac_jpeg_header2[] = {
Marton Nemeth56f6f552009-10-04 13:58:19 -0300556 0x03, /* Number of image components: 3 */
557 0x01, 0x21, 0x00, /* ID=1, Subsampling 1x1, Quantization table: 0 */
558 0x02, 0x11, 0x01, /* ID=2, Subsampling 2x1, Quantization table: 1 */
559 0x03, 0x11, 0x01, /* ID=3, Subsampling 2x1, Quantization table: 1 */
560
561 0xff, 0xda, /* SOS: Start Of Scan */
562 0x00, 0x0c, /* length = 12 bytes (including this length field) */
563 0x03, /* number of components: 3 */
564 0x01, 0x00, /* selector 1, table 0x00 */
565 0x02, 0x11, /* selector 2, table 0x11 */
566 0x03, 0x11, /* selector 3, table 0x11 */
567 0x00, 0x3f, /* Spectral selection: 0 .. 63 */
568 0x00 /* Successive approximation: 0 */
Hans de Goede327c4ab2008-09-03 17:12:14 -0300569};
570
Marton Nemethcc409c02009-11-02 08:09:34 -0300571static void pac_start_frame(struct gspca_dev *gspca_dev,
Marton Nemethcc409c02009-11-02 08:09:34 -0300572 __u16 lines, __u16 samples_per_line)
573{
574 unsigned char tmpbuf[4];
575
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300576 gspca_frame_add(gspca_dev, FIRST_PACKET,
Marton Nemethcc409c02009-11-02 08:09:34 -0300577 pac_jpeg_header1, sizeof(pac_jpeg_header1));
578
579 tmpbuf[0] = lines >> 8;
580 tmpbuf[1] = lines & 0xff;
581 tmpbuf[2] = samples_per_line >> 8;
582 tmpbuf[3] = samples_per_line & 0xff;
583
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300584 gspca_frame_add(gspca_dev, INTER_PACKET,
Marton Nemethcc409c02009-11-02 08:09:34 -0300585 tmpbuf, sizeof(tmpbuf));
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300586 gspca_frame_add(gspca_dev, INTER_PACKET,
Marton Nemethcc409c02009-11-02 08:09:34 -0300587 pac_jpeg_header2, sizeof(pac_jpeg_header2));
588}
589
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300590/* this function is run at interrupt level */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300591static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300592 u8 *data, /* isoc packet */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300593 int len) /* iso packet length */
594{
595 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moineb192ca92010-06-27 03:08:19 -0300596 u8 *image;
Hans de Goede327c4ab2008-09-03 17:12:14 -0300597 unsigned char *sof;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300598
Marton Nemetha6b69e42009-11-02 08:05:51 -0300599 sof = pac_find_sof(&sd->sof_read, data, len);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300600 if (sof) {
Hans de Goede327c4ab2008-09-03 17:12:14 -0300601 int n, lum_offset, footer_length;
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300602
Marton Nemeth1408b842009-11-02 08:13:21 -0300603 /* 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 lum_offset = 24 + sizeof pac_sof_marker;
608 footer_length = 26;
Hans de Goede327c4ab2008-09-03 17:12:14 -0300609
610 /* Finish decoding current frame */
611 n = (sof - data) - (footer_length + sizeof pac_sof_marker);
612 if (n < 0) {
Jean-François Moineb192ca92010-06-27 03:08:19 -0300613 gspca_dev->image_len += n;
Hans de Goede327c4ab2008-09-03 17:12:14 -0300614 n = 0;
Jean-François Moineb192ca92010-06-27 03:08:19 -0300615 } else {
616 gspca_frame_add(gspca_dev, INTER_PACKET, data, n);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300617 }
Jean-François Moinef7059ea2010-07-06 04:32:27 -0300618 image = gspca_dev->image;
619 if (image != NULL
Jean-François Moineb192ca92010-06-27 03:08:19 -0300620 && image[gspca_dev->image_len - 2] == 0xff
621 && image[gspca_dev->image_len - 1] == 0xd9)
622 gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300623
624 n = sof - data;
625 len -= n;
626 data = sof;
627
628 /* Get average lumination */
629 if (gspca_dev->last_packet_type == LAST_PACKET &&
Hans de Goede038ec7c2008-09-03 17:12:18 -0300630 n >= lum_offset)
631 atomic_set(&sd->avg_lum, data[-lum_offset] +
Hans de Goede327c4ab2008-09-03 17:12:14 -0300632 data[-lum_offset + 1]);
Hans de Goede038ec7c2008-09-03 17:12:18 -0300633 else
Hans de Goede327c4ab2008-09-03 17:12:14 -0300634 atomic_set(&sd->avg_lum, -1);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300635
636 /* Start the new frame with the jpeg header */
Jean-François Moineb192ca92010-06-27 03:08:19 -0300637 pac_start_frame(gspca_dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300638 gspca_dev->height, gspca_dev->width);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300639 }
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300640 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300641}
642
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300643static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
644{
645 struct sd *sd = (struct sd *) gspca_dev;
646
647 sd->contrast = val;
Jean-François Moine780e3122010-10-19 04:29:10 -0300648 if (gspca_dev->streaming)
Marton Nemeth1408b842009-11-02 08:13:21 -0300649 setcontrast(gspca_dev);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300650 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300651}
652
653static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
654{
655 struct sd *sd = (struct sd *) gspca_dev;
656
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300657 *val = sd->contrast;
658 return 0;
659}
660
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300661static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
662{
663 struct sd *sd = (struct sd *) gspca_dev;
664
665 sd->gain = val;
666 if (gspca_dev->streaming)
667 setgain(gspca_dev);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300668 return gspca_dev->usb_err;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300669}
670
671static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
672{
673 struct sd *sd = (struct sd *) gspca_dev;
674
675 *val = sd->gain;
676 return 0;
677}
678
679static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
680{
681 struct sd *sd = (struct sd *) gspca_dev;
682
683 sd->exposure = val;
684 if (gspca_dev->streaming)
685 setexposure(gspca_dev);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300686 return gspca_dev->usb_err;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300687}
688
689static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
690{
691 struct sd *sd = (struct sd *) gspca_dev;
692
693 *val = sd->exposure;
694 return 0;
695}
696
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300697static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
698{
699 struct sd *sd = (struct sd *) gspca_dev;
700
701 sd->autogain = val;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300702 /* when switching to autogain set defaults to make sure
703 we are on a valid point of the autogain gain /
704 exposure knee graph, and give this change time to
705 take effect before doing autogain. */
706 if (sd->autogain) {
707 sd->exposure = EXPOSURE_DEF;
708 sd->gain = GAIN_DEF;
709 if (gspca_dev->streaming) {
710 sd->autogain_ignore_frames =
711 PAC_AUTOGAIN_IGNORE_FRAMES;
712 setexposure(gspca_dev);
713 setgain(gspca_dev);
714 }
715 }
Hans de Goede327c4ab2008-09-03 17:12:14 -0300716
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300717 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300718}
719
720static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
721{
722 struct sd *sd = (struct sd *) gspca_dev;
723
724 *val = sd->autogain;
725 return 0;
726}
727
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300728static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
729{
730 struct sd *sd = (struct sd *) gspca_dev;
731
732 sd->hflip = val;
733 if (gspca_dev->streaming)
734 sethvflip(gspca_dev);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300735 return gspca_dev->usb_err;
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300736}
737
738static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
739{
740 struct sd *sd = (struct sd *) gspca_dev;
741
742 *val = sd->hflip;
743 return 0;
744}
745
746static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
747{
748 struct sd *sd = (struct sd *) gspca_dev;
749
750 sd->vflip = val;
751 if (gspca_dev->streaming)
752 sethvflip(gspca_dev);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300753 return gspca_dev->usb_err;
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300754}
755
756static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
757{
758 struct sd *sd = (struct sd *) gspca_dev;
759
760 *val = sd->vflip;
761 return 0;
762}
763
Jean-François Moine28566432010-10-01 07:33:26 -0300764#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
Hans de Goede32ea3e42010-01-29 11:04:19 -0300765static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
766 u8 *data, /* interrupt packet data */
767 int len) /* interrupt packet length */
768{
769 int ret = -EINVAL;
770 u8 data0, data1;
771
772 if (len == 2) {
773 data0 = data[0];
774 data1 = data[1];
775 if ((data0 == 0x00 && data1 == 0x11) ||
776 (data0 == 0x22 && data1 == 0x33) ||
777 (data0 == 0x44 && data1 == 0x55) ||
778 (data0 == 0x66 && data1 == 0x77) ||
779 (data0 == 0x88 && data1 == 0x99) ||
780 (data0 == 0xaa && data1 == 0xbb) ||
781 (data0 == 0xcc && data1 == 0xdd) ||
782 (data0 == 0xee && data1 == 0xff)) {
783 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
784 input_sync(gspca_dev->input_dev);
785 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
786 input_sync(gspca_dev->input_dev);
787 ret = 0;
788 }
789 }
790
791 return ret;
792}
793#endif
794
Márton Némethaabcdfb2010-01-05 12:39:02 -0300795static const struct sd_desc sd_desc = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300796 .name = MODULE_NAME,
797 .ctrls = sd_ctrls,
798 .nctrls = ARRAY_SIZE(sd_ctrls),
799 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300800 .init = sd_init,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300801 .start = sd_start,
802 .stopN = sd_stopN,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300803 .pkt_scan = sd_pkt_scan,
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300804 .dq_callback = do_autogain,
Jean-François Moine28566432010-10-01 07:33:26 -0300805#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
Hans de Goede32ea3e42010-01-29 11:04:19 -0300806 .int_pkt_scan = sd_int_pkt_scan,
807#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300808};
809
810/* -- module initialisation -- */
Jean-François Moine95c967c2011-01-13 05:20:29 -0300811static const struct usb_device_id device_table[] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300812 {USB_DEVICE(0x093a, 0x2600)},
813 {USB_DEVICE(0x093a, 0x2601)},
814 {USB_DEVICE(0x093a, 0x2603)},
815 {USB_DEVICE(0x093a, 0x2608)},
816 {USB_DEVICE(0x093a, 0x260e)},
817 {USB_DEVICE(0x093a, 0x260f)},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300818 {}
819};
820MODULE_DEVICE_TABLE(usb, device_table);
821
822/* -- device connect -- */
Jean-François Moine95c967c2011-01-13 05:20:29 -0300823static int sd_probe(struct usb_interface *intf,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300824 const struct usb_device_id *id)
825{
826 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
827 THIS_MODULE);
828}
829
830static struct usb_driver sd_driver = {
831 .name = MODULE_NAME,
832 .id_table = device_table,
833 .probe = sd_probe,
834 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -0300835#ifdef CONFIG_PM
836 .suspend = gspca_suspend,
837 .resume = gspca_resume,
838#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300839};
840
Greg Kroah-Hartmanecb3b2b2011-11-18 09:46:12 -0800841module_usb_driver(sd_driver);