blob: 25f86b1e74a80b9c9d6f4d856b8156a216d47102 [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
Hans de Goede6a6c70b2012-05-10 12:13:16 -030053 * Note setting vflip disabled leads to a much lower image quality,
54 * so we always vflip, and tell userspace to flip it back
Hans de Goede4b8ceb62012-04-28 10:20:50 -030055 * 0x27 Seems to toggle various gains on / off, Setting bit 7 seems to
56 * completely disable the analog amplification block. Set to 0x68
57 * for max gain, 0x14 for minimal gain.
58 */
Hans de Goede327c4ab2008-09-03 17:12:14 -030059
Joe Perches133a9fe2011-08-21 19:56:57 -030060#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
61
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030062#define MODULE_NAME "pac7311"
63
Hans de Goede32ea3e42010-01-29 11:04:19 -030064#include <linux/input.h>
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030065#include "gspca.h"
Hans de Goedea5340ce2012-04-27 11:40:28 -030066/* Include pac common sof detection functions */
67#include "pac_common.h"
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030068
Hans de Goede43f52bf2012-05-10 10:52:54 -030069#define PAC7311_GAIN_DEFAULT 122
70#define PAC7311_EXPOSURE_DEFAULT 3 /* 20 fps, avoid using high compr. */
71
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030072MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li");
73MODULE_DESCRIPTION("Pixart PAC7311");
74MODULE_LICENSE("GPL");
75
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030076struct sd {
77 struct gspca_dev gspca_dev; /* !! must be the first item */
Hans de Goede43f52bf2012-05-10 10:52:54 -030078
79 struct v4l2_ctrl *contrast;
Hans de Goede6a6c70b2012-05-10 12:13:16 -030080 struct v4l2_ctrl *hflip;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -030081
Hans de Goede327c4ab2008-09-03 17:12:14 -030082 u8 sof_read;
Hans de Goede327c4ab2008-09-03 17:12:14 -030083 u8 autogain_ignore_frames;
84
85 atomic_t avg_lum;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -030086};
87
Jean-Francois Moinecc611b82008-12-29 07:49:41 -030088static const struct v4l2_pix_format vga_mode[] = {
Jean-Francois Moinef75c4952008-09-03 16:47:35 -030089 {160, 120, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -030090 .bytesperline = 160,
91 .sizeimage = 160 * 120 * 3 / 8 + 590,
92 .colorspace = V4L2_COLORSPACE_JPEG,
93 .priv = 2},
Jean-Francois Moinef75c4952008-09-03 16:47:35 -030094 {320, 240, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -030095 .bytesperline = 320,
96 .sizeimage = 320 * 240 * 3 / 8 + 590,
97 .colorspace = V4L2_COLORSPACE_JPEG,
98 .priv = 1},
Jean-Francois Moinef75c4952008-09-03 16:47:35 -030099 {640, 480, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300100 .bytesperline = 640,
101 .sizeimage = 640 * 480 * 3 / 8 + 590,
102 .colorspace = V4L2_COLORSPACE_JPEG,
103 .priv = 0},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300104};
105
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300106#define LOAD_PAGE4 254
107#define END_OF_SEQUENCE 0
108
Hans de Goede271315a2008-09-03 17:12:19 -0300109static const __u8 init_7311[] = {
Hans de Goede42f85d02012-05-10 12:10:56 -0300110 0xff, 0x01,
Hans de Goede327c4ab2008-09-03 17:12:14 -0300111 0x78, 0x40, /* Bit_0=start stream, Bit_6=LED */
112 0x78, 0x40, /* Bit_0=start stream, Bit_6=LED */
113 0x78, 0x44, /* Bit_0=start stream, Bit_6=LED */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300114 0xff, 0x04,
115 0x27, 0x80,
116 0x28, 0xca,
117 0x29, 0x53,
118 0x2a, 0x0e,
119 0xff, 0x01,
120 0x3e, 0x20,
121};
122
123static const __u8 start_7311[] = {
124/* index, len, [value]* */
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300125 0xff, 1, 0x01, /* page 1 */
126 0x02, 43, 0x48, 0x0a, 0x40, 0x08, 0x00, 0x00, 0x08, 0x00,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300127 0x06, 0xff, 0x11, 0xff, 0x5a, 0x30, 0x90, 0x4c,
128 0x00, 0x07, 0x00, 0x0a, 0x10, 0x00, 0xa0, 0x10,
129 0x02, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x01, 0x00,
130 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
131 0x00, 0x00, 0x00,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300132 0x3e, 42, 0x00, 0x00, 0x78, 0x52, 0x4a, 0x52, 0x78, 0x6e,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300133 0x48, 0x46, 0x48, 0x6e, 0x5f, 0x49, 0x42, 0x49,
134 0x5f, 0x5f, 0x49, 0x42, 0x49, 0x5f, 0x6e, 0x48,
135 0x46, 0x48, 0x6e, 0x78, 0x52, 0x4a, 0x52, 0x78,
136 0x00, 0x00, 0x09, 0x1b, 0x34, 0x49, 0x5c, 0x9b,
137 0xd0, 0xff,
138 0x78, 6, 0x44, 0x00, 0xf2, 0x01, 0x01, 0x80,
139 0x7f, 18, 0x2a, 0x1c, 0x00, 0xc8, 0x02, 0x58, 0x03, 0x84,
140 0x12, 0x00, 0x1a, 0x04, 0x08, 0x0c, 0x10, 0x14,
141 0x18, 0x20,
142 0x96, 3, 0x01, 0x08, 0x04,
143 0xa0, 4, 0x44, 0x44, 0x44, 0x04,
144 0xf0, 13, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x20, 0x00,
145 0x3f, 0x00, 0x0a, 0x01, 0x00,
Jean-Francois Moine285a4f62008-09-03 16:47:33 -0300146 0xff, 1, 0x04, /* page 4 */
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300147 0, LOAD_PAGE4, /* load the page 4 */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300148 0x11, 1, 0x01,
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300149 0, END_OF_SEQUENCE /* end of sequence */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300150};
151
Marton Nemeth1408b842009-11-02 08:13:21 -0300152#define SKIP 0xaa
Marton Nemethff75e992009-10-04 13:51:26 -0300153/* page 4 - the value SKIP says skip the index - see reg_w_page() */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300154static const __u8 page4_7311[] = {
Marton Nemethff75e992009-10-04 13:51:26 -0300155 SKIP, SKIP, 0x04, 0x54, 0x07, 0x2b, 0x09, 0x0f,
156 0x09, 0x00, SKIP, SKIP, 0x07, 0x00, 0x00, 0x62,
157 0x08, SKIP, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
158 0x00, 0x00, 0x00, 0x03, 0xa0, 0x01, 0xf4, SKIP,
159 SKIP, 0x00, 0x08, SKIP, 0x03, SKIP, 0x00, 0x68,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300160 0xca, 0x10, 0x06, 0x78, 0x00, 0x00, 0x00, 0x00,
161 0x23, 0x28, 0x04, 0x11, 0x00, 0x00
162};
163
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300164static void reg_w_buf(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300165 __u8 index,
Jean-François Moine0aeb5ec2010-12-28 06:59:04 -0300166 const u8 *buffer, int len)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300167{
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300168 int ret;
169
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300170 if (gspca_dev->usb_err < 0)
171 return;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300172 memcpy(gspca_dev->usb_buf, buffer, len);
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300173 ret = usb_control_msg(gspca_dev->dev,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300174 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-François Moinea1317132010-06-24 04:50:26 -0300175 0, /* request */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300176 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300177 0, /* value */
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300178 index, gspca_dev->usb_buf, len,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300179 500);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300180 if (ret < 0) {
Joe Perches133a9fe2011-08-21 19:56:57 -0300181 pr_err("reg_w_buf() failed index 0x%02x, error %d\n",
182 index, ret);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300183 gspca_dev->usb_err = ret;
184 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300185}
186
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300187
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300188static void reg_w(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300189 __u8 index,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300190 __u8 value)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300191{
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300192 int ret;
193
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300194 if (gspca_dev->usb_err < 0)
195 return;
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300196 gspca_dev->usb_buf[0] = value;
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300197 ret = usb_control_msg(gspca_dev->dev,
Jean-Francois Moine739570b2008-07-14 09:38:29 -0300198 usb_sndctrlpipe(gspca_dev->dev, 0),
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300199 0, /* request */
200 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300201 0, index, gspca_dev->usb_buf, 1,
Jean-Francois Moinebf7f0b92008-07-03 11:09:12 -0300202 500);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300203 if (ret < 0) {
Joe Perches133a9fe2011-08-21 19:56:57 -0300204 pr_err("reg_w() failed index 0x%02x, value 0x%02x, error %d\n",
205 index, value, ret);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300206 gspca_dev->usb_err = ret;
207 }
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300208}
209
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300210static void reg_w_seq(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300211 const __u8 *seq, int len)
212{
213 while (--len >= 0) {
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300214 reg_w(gspca_dev, seq[0], seq[1]);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300215 seq += 2;
216 }
217}
218
219/* load the beginning of a page */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300220static void reg_w_page(struct gspca_dev *gspca_dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300221 const __u8 *page, int len)
222{
223 int index;
Márton Némethb1784b32009-11-07 05:52:02 -0300224 int ret = 0;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300225
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300226 if (gspca_dev->usb_err < 0)
227 return;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300228 for (index = 0; index < len; index++) {
Marton Nemethff75e992009-10-04 13:51:26 -0300229 if (page[index] == SKIP) /* skip this index */
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300230 continue;
231 gspca_dev->usb_buf[0] = page[index];
Marton Nemeth4f7309e2009-11-05 05:35:08 -0300232 ret = usb_control_msg(gspca_dev->dev,
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300233 usb_sndctrlpipe(gspca_dev->dev, 0),
234 0, /* request */
235 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
236 0, index, gspca_dev->usb_buf, 1,
237 500);
Márton Némethb1784b32009-11-07 05:52:02 -0300238 if (ret < 0) {
Joe Perches133a9fe2011-08-21 19:56:57 -0300239 pr_err("reg_w_page() failed index 0x%02x, value 0x%02x, error %d\n",
240 index, page[index], ret);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300241 gspca_dev->usb_err = ret;
Márton Némethb1784b32009-11-07 05:52:02 -0300242 break;
243 }
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300244 }
245}
246
247/* output a variable sequence */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300248static void reg_w_var(struct gspca_dev *gspca_dev,
Marton Nemeth1408b842009-11-02 08:13:21 -0300249 const __u8 *seq,
Marton Nemeth1408b842009-11-02 08:13:21 -0300250 const __u8 *page4, unsigned int page4_len)
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300251{
252 int index, len;
253
254 for (;;) {
255 index = *seq++;
256 len = *seq++;
257 switch (len) {
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300258 case END_OF_SEQUENCE:
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300259 return;
Marton Nemeth5a2e8d92009-10-04 13:53:22 -0300260 case LOAD_PAGE4:
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300261 reg_w_page(gspca_dev, page4, page4_len);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300262 break;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300263 default:
Marton Nemeth24067bb2009-10-04 13:54:48 -0300264 if (len > USB_BUF_SZ) {
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300265 PERR("Incorrect variable sequence");
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300266 return;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300267 }
268 while (len > 0) {
269 if (len < 8) {
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300270 reg_w_buf(gspca_dev,
Márton Némethb1784b32009-11-07 05:52:02 -0300271 index, seq, len);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300272 seq += len;
273 break;
274 }
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300275 reg_w_buf(gspca_dev, index, seq, 8);
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300276 seq += 8;
277 index += 8;
278 len -= 8;
279 }
280 }
281 }
282 /* not reached */
283}
284
Marton Nemeth1408b842009-11-02 08:13:21 -0300285/* this function is called at probe time for pac7311 */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300286static int sd_config(struct gspca_dev *gspca_dev,
287 const struct usb_device_id *id)
288{
Hans de Goedea5340ce2012-04-27 11:40:28 -0300289 struct cam *cam = &gspca_dev->cam;
Jean-Francois Moine49b57db2008-09-03 16:47:25 -0300290
Marton Nemeth1408b842009-11-02 08:13:21 -0300291 cam->cam_mode = vga_mode;
292 cam->nmodes = ARRAY_SIZE(vga_mode);
Hans de Goede6a6c70b2012-05-10 12:13:16 -0300293 cam->input_flags = V4L2_IN_ST_VFLIP;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300294
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300295 return 0;
296}
297
Hans de Goede43f52bf2012-05-10 10:52:54 -0300298static void setcontrast(struct gspca_dev *gspca_dev, s32 val)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300299{
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300300 reg_w(gspca_dev, 0xff, 0x04);
Hans de Goede43f52bf2012-05-10 10:52:54 -0300301 reg_w(gspca_dev, 0x10, val);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300302 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300303 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300304}
305
Hans de Goede43f52bf2012-05-10 10:52:54 -0300306static void setgain(struct gspca_dev *gspca_dev, s32 val)
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300307{
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300308 reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
309 reg_w(gspca_dev, 0x0e, 0x00);
Hans de Goede43f52bf2012-05-10 10:52:54 -0300310 reg_w(gspca_dev, 0x0f, gspca_dev->gain->maximum - val + 1);
Marton Nemeth1408b842009-11-02 08:13:21 -0300311
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300312 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300313 reg_w(gspca_dev, 0x11, 0x01);
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300314}
315
Hans de Goede43f52bf2012-05-10 10:52:54 -0300316static void setexposure(struct gspca_dev *gspca_dev, s32 val)
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300317{
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300318 reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
Hans de Goede43f52bf2012-05-10 10:52:54 -0300319 reg_w(gspca_dev, 0x02, val);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300320
Hans de Goede51ae23d2012-04-18 06:12:57 -0300321 /* load registers to sensor (Bit 0, auto clear) */
322 reg_w(gspca_dev, 0x11, 0x01);
323
Hans de Goede4b8ceb62012-04-28 10:20:50 -0300324 /*
325 * Page 1 register 8 must always be 0x08 except when not in
326 * 640x480 mode and page 4 reg 2 <= 3 then it must be 9
327 */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300328 reg_w(gspca_dev, 0xff, 0x01);
Ondrej Zary1966bc22013-08-30 17:54:23 -0300329 if (gspca_dev->pixfmt.width != 640 && val <= 3)
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300330 reg_w(gspca_dev, 0x08, 0x09);
Hans de Goede282ddfb2012-04-27 12:56:59 -0300331 else
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300332 reg_w(gspca_dev, 0x08, 0x08);
Hans de Goede282ddfb2012-04-27 12:56:59 -0300333
334 /*
335 * Page1 register 80 sets the compression balance, normally we
336 * want / use 0x1c, but for 640x480@30fps we must allow the
337 * camera to use higher compression or we may run out of
338 * bandwidth.
339 */
Ondrej Zary1966bc22013-08-30 17:54:23 -0300340 if (gspca_dev->pixfmt.width == 640 && val == 2)
Hans de Goede282ddfb2012-04-27 12:56:59 -0300341 reg_w(gspca_dev, 0x80, 0x01);
342 else
343 reg_w(gspca_dev, 0x80, 0x1c);
Marton Nemeth1408b842009-11-02 08:13:21 -0300344
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300345 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300346 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300347}
348
Hans de Goede43f52bf2012-05-10 10:52:54 -0300349static void sethvflip(struct gspca_dev *gspca_dev, s32 hflip, s32 vflip)
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300350{
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300351 __u8 data;
352
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300353 reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
Hans de Goede43f52bf2012-05-10 10:52:54 -0300354 data = (hflip ? 0x04 : 0x00) |
355 (vflip ? 0x08 : 0x00);
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300356 reg_w(gspca_dev, 0x21, data);
357
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300358 /* load registers to sensor (Bit 0, auto clear) */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300359 reg_w(gspca_dev, 0x11, 0x01);
Jean-Francois Moine41b46972008-09-03 16:47:58 -0300360}
361
Marton Nemeth1408b842009-11-02 08:13:21 -0300362/* this function is called at probe and resume time for pac7311 */
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300363static int sd_init(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300364{
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300365 reg_w_seq(gspca_dev, init_7311, sizeof(init_7311)/2);
366 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300367}
368
Hans de Goede43f52bf2012-05-10 10:52:54 -0300369static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
370{
371 struct gspca_dev *gspca_dev =
372 container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
373 struct sd *sd = (struct sd *)gspca_dev;
374
375 gspca_dev->usb_err = 0;
376
377 if (ctrl->id == V4L2_CID_AUTOGAIN && ctrl->is_new && ctrl->val) {
378 /* when switching to autogain set defaults to make sure
379 we are on a valid point of the autogain gain /
380 exposure knee graph, and give this change time to
381 take effect before doing autogain. */
382 gspca_dev->exposure->val = PAC7311_EXPOSURE_DEFAULT;
383 gspca_dev->gain->val = PAC7311_GAIN_DEFAULT;
384 sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
385 }
386
387 if (!gspca_dev->streaming)
388 return 0;
389
390 switch (ctrl->id) {
391 case V4L2_CID_CONTRAST:
392 setcontrast(gspca_dev, ctrl->val);
393 break;
394 case V4L2_CID_AUTOGAIN:
395 if (gspca_dev->exposure->is_new || (ctrl->is_new && ctrl->val))
396 setexposure(gspca_dev, gspca_dev->exposure->val);
397 if (gspca_dev->gain->is_new || (ctrl->is_new && ctrl->val))
398 setgain(gspca_dev, gspca_dev->gain->val);
399 break;
400 case V4L2_CID_HFLIP:
Hans de Goede6a6c70b2012-05-10 12:13:16 -0300401 sethvflip(gspca_dev, sd->hflip->val, 1);
Hans de Goede43f52bf2012-05-10 10:52:54 -0300402 break;
403 default:
404 return -EINVAL;
405 }
406 return gspca_dev->usb_err;
407}
408
409static const struct v4l2_ctrl_ops sd_ctrl_ops = {
410 .s_ctrl = sd_s_ctrl,
411};
412
413/* this function is called at probe time */
414static int sd_init_controls(struct gspca_dev *gspca_dev)
415{
416 struct sd *sd = (struct sd *) gspca_dev;
417 struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
418
419 gspca_dev->vdev.ctrl_handler = hdl;
Hans de Goedeb6fc2eb2012-05-14 14:51:22 -0300420 v4l2_ctrl_handler_init(hdl, 5);
Hans de Goede43f52bf2012-05-10 10:52:54 -0300421
422 sd->contrast = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
423 V4L2_CID_CONTRAST, 0, 15, 1, 7);
424 gspca_dev->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
425 V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
426 gspca_dev->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
427 V4L2_CID_EXPOSURE, 2, 63, 1,
428 PAC7311_EXPOSURE_DEFAULT);
429 gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
430 V4L2_CID_GAIN, 0, 244, 1,
431 PAC7311_GAIN_DEFAULT);
432 sd->hflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
433 V4L2_CID_HFLIP, 0, 1, 1, 0);
Hans de Goede43f52bf2012-05-10 10:52:54 -0300434
435 if (hdl->error) {
436 pr_err("Could not initialize controls\n");
437 return hdl->error;
438 }
439
440 v4l2_ctrl_auto_cluster(3, &gspca_dev->autogain, 0, false);
Hans de Goede43f52bf2012-05-10 10:52:54 -0300441 return 0;
442}
443
444/* -- start the camera -- */
Jean-Francois Moine72ab97c2008-09-20 06:39:08 -0300445static int sd_start(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300446{
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300447 struct sd *sd = (struct sd *) gspca_dev;
448
Hans de Goede327c4ab2008-09-03 17:12:14 -0300449 sd->sof_read = 0;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300450
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300451 reg_w_var(gspca_dev, start_7311,
Marton Nemeth1408b842009-11-02 08:13:21 -0300452 page4_7311, sizeof(page4_7311));
Hans de Goede43f52bf2012-05-10 10:52:54 -0300453 setcontrast(gspca_dev, v4l2_ctrl_g_ctrl(sd->contrast));
454 setgain(gspca_dev, v4l2_ctrl_g_ctrl(gspca_dev->gain));
455 setexposure(gspca_dev, v4l2_ctrl_g_ctrl(gspca_dev->exposure));
Hans de Goede6a6c70b2012-05-10 12:13:16 -0300456 sethvflip(gspca_dev, v4l2_ctrl_g_ctrl(sd->hflip), 1);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300457
458 /* set correct resolution */
Jean-Francois Moinec2446b32008-07-05 11:49:20 -0300459 switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
Hans de Goedeb053c1d2012-04-25 12:00:49 -0300460 case 2: /* 160x120 */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300461 reg_w(gspca_dev, 0xff, 0x01);
462 reg_w(gspca_dev, 0x17, 0x20);
463 reg_w(gspca_dev, 0x87, 0x10);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300464 break;
Hans de Goedeb053c1d2012-04-25 12:00:49 -0300465 case 1: /* 320x240 */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300466 reg_w(gspca_dev, 0xff, 0x01);
467 reg_w(gspca_dev, 0x17, 0x30);
468 reg_w(gspca_dev, 0x87, 0x11);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300469 break;
470 case 0: /* 640x480 */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300471 reg_w(gspca_dev, 0xff, 0x01);
472 reg_w(gspca_dev, 0x17, 0x00);
473 reg_w(gspca_dev, 0x87, 0x12);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300474 break;
475 }
476
Hans de Goede327c4ab2008-09-03 17:12:14 -0300477 sd->sof_read = 0;
478 sd->autogain_ignore_frames = 0;
479 atomic_set(&sd->avg_lum, -1);
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300480
481 /* start stream */
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300482 reg_w(gspca_dev, 0xff, 0x01);
483 reg_w(gspca_dev, 0x78, 0x05);
Marton Nemeth1408b842009-11-02 08:13:21 -0300484
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300485 return gspca_dev->usb_err;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300486}
487
488static void sd_stopN(struct gspca_dev *gspca_dev)
489{
Jean-Francois Moine14799f62010-01-13 15:28:22 -0300490 reg_w(gspca_dev, 0xff, 0x04);
491 reg_w(gspca_dev, 0x27, 0x80);
492 reg_w(gspca_dev, 0x28, 0xca);
493 reg_w(gspca_dev, 0x29, 0x53);
494 reg_w(gspca_dev, 0x2a, 0x0e);
495 reg_w(gspca_dev, 0xff, 0x01);
496 reg_w(gspca_dev, 0x3e, 0x20);
497 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
498 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
499 reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300500}
501
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300502static void do_autogain(struct gspca_dev *gspca_dev)
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300503{
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300504 struct sd *sd = (struct sd *) gspca_dev;
505 int avg_lum = atomic_read(&sd->avg_lum);
Hans de Goede038ec7c2008-09-03 17:12:18 -0300506 int desired_lum, deadzone;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300507
Hans de Goede43f52bf2012-05-10 10:52:54 -0300508 if (avg_lum == -1)
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300509 return;
510
Hans de Goede6a6c70b2012-05-10 12:13:16 -0300511 desired_lum = 170;
Marton Nemeth1408b842009-11-02 08:13:21 -0300512 deadzone = 20;
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300513
514 if (sd->autogain_ignore_frames > 0)
515 sd->autogain_ignore_frames--;
Hans de Goede43f52bf2012-05-10 10:52:54 -0300516 else if (gspca_coarse_grained_expo_autogain(gspca_dev, avg_lum,
517 desired_lum, deadzone))
Hans de Goede8a5b2e92008-09-03 17:12:17 -0300518 sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300519}
520
Marton Nemeth56f6f552009-10-04 13:58:19 -0300521/* JPEG header, part 1 */
Marton Nemethcc409c02009-11-02 08:09:34 -0300522static const unsigned char pac_jpeg_header1[] = {
Marton Nemeth56f6f552009-10-04 13:58:19 -0300523 0xff, 0xd8, /* SOI: Start of Image */
524
525 0xff, 0xc0, /* SOF0: Start of Frame (Baseline DCT) */
526 0x00, 0x11, /* length = 17 bytes (including this length field) */
527 0x08 /* Precision: 8 */
528 /* 2 bytes is placed here: number of image lines */
529 /* 2 bytes is placed here: samples per line */
Hans de Goede327c4ab2008-09-03 17:12:14 -0300530};
531
Marton Nemeth56f6f552009-10-04 13:58:19 -0300532/* JPEG header, continued */
Marton Nemethcc409c02009-11-02 08:09:34 -0300533static const unsigned char pac_jpeg_header2[] = {
Marton Nemeth56f6f552009-10-04 13:58:19 -0300534 0x03, /* Number of image components: 3 */
535 0x01, 0x21, 0x00, /* ID=1, Subsampling 1x1, Quantization table: 0 */
536 0x02, 0x11, 0x01, /* ID=2, Subsampling 2x1, Quantization table: 1 */
537 0x03, 0x11, 0x01, /* ID=3, Subsampling 2x1, Quantization table: 1 */
538
539 0xff, 0xda, /* SOS: Start Of Scan */
540 0x00, 0x0c, /* length = 12 bytes (including this length field) */
541 0x03, /* number of components: 3 */
542 0x01, 0x00, /* selector 1, table 0x00 */
543 0x02, 0x11, /* selector 2, table 0x11 */
544 0x03, 0x11, /* selector 3, table 0x11 */
545 0x00, 0x3f, /* Spectral selection: 0 .. 63 */
546 0x00 /* Successive approximation: 0 */
Hans de Goede327c4ab2008-09-03 17:12:14 -0300547};
548
Marton Nemethcc409c02009-11-02 08:09:34 -0300549static void pac_start_frame(struct gspca_dev *gspca_dev,
Marton Nemethcc409c02009-11-02 08:09:34 -0300550 __u16 lines, __u16 samples_per_line)
551{
552 unsigned char tmpbuf[4];
553
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300554 gspca_frame_add(gspca_dev, FIRST_PACKET,
Marton Nemethcc409c02009-11-02 08:09:34 -0300555 pac_jpeg_header1, sizeof(pac_jpeg_header1));
556
557 tmpbuf[0] = lines >> 8;
558 tmpbuf[1] = lines & 0xff;
559 tmpbuf[2] = samples_per_line >> 8;
560 tmpbuf[3] = samples_per_line & 0xff;
561
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300562 gspca_frame_add(gspca_dev, INTER_PACKET,
Marton Nemethcc409c02009-11-02 08:09:34 -0300563 tmpbuf, sizeof(tmpbuf));
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300564 gspca_frame_add(gspca_dev, INTER_PACKET,
Marton Nemethcc409c02009-11-02 08:09:34 -0300565 pac_jpeg_header2, sizeof(pac_jpeg_header2));
566}
567
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300568/* this function is run at interrupt level */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300569static void sd_pkt_scan(struct gspca_dev *gspca_dev,
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300570 u8 *data, /* isoc packet */
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300571 int len) /* iso packet length */
572{
573 struct sd *sd = (struct sd *) gspca_dev;
Jean-François Moineb192ca92010-06-27 03:08:19 -0300574 u8 *image;
Hans de Goede327c4ab2008-09-03 17:12:14 -0300575 unsigned char *sof;
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300576
Theodore Kilgorec93396e2013-02-04 13:17:55 -0300577 sof = pac_find_sof(gspca_dev, &sd->sof_read, data, len);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300578 if (sof) {
Hans de Goede327c4ab2008-09-03 17:12:14 -0300579 int n, lum_offset, footer_length;
Jean-Francois Moinee52a5572008-09-03 16:47:21 -0300580
Hans de Goede4b8ceb62012-04-28 10:20:50 -0300581 /*
582 * 6 bytes after the FF D9 EOF marker a number of lumination
583 * bytes are send corresponding to different parts of the
584 * image, the 14th and 15th byte after the EOF seem to
585 * correspond to the center of the image.
586 */
Marton Nemeth1408b842009-11-02 08:13:21 -0300587 lum_offset = 24 + sizeof pac_sof_marker;
588 footer_length = 26;
Hans de Goede327c4ab2008-09-03 17:12:14 -0300589
590 /* Finish decoding current frame */
591 n = (sof - data) - (footer_length + sizeof pac_sof_marker);
592 if (n < 0) {
Jean-François Moineb192ca92010-06-27 03:08:19 -0300593 gspca_dev->image_len += n;
Hans de Goede327c4ab2008-09-03 17:12:14 -0300594 n = 0;
Jean-François Moineb192ca92010-06-27 03:08:19 -0300595 } else {
596 gspca_frame_add(gspca_dev, INTER_PACKET, data, n);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300597 }
Jean-François Moinef7059ea2010-07-06 04:32:27 -0300598 image = gspca_dev->image;
599 if (image != NULL
Jean-François Moineb192ca92010-06-27 03:08:19 -0300600 && image[gspca_dev->image_len - 2] == 0xff
601 && image[gspca_dev->image_len - 1] == 0xd9)
602 gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300603
604 n = sof - data;
605 len -= n;
606 data = sof;
607
608 /* Get average lumination */
609 if (gspca_dev->last_packet_type == LAST_PACKET &&
Hans de Goede038ec7c2008-09-03 17:12:18 -0300610 n >= lum_offset)
611 atomic_set(&sd->avg_lum, data[-lum_offset] +
Hans de Goede327c4ab2008-09-03 17:12:14 -0300612 data[-lum_offset + 1]);
Hans de Goede038ec7c2008-09-03 17:12:18 -0300613 else
Hans de Goede327c4ab2008-09-03 17:12:14 -0300614 atomic_set(&sd->avg_lum, -1);
Hans de Goede327c4ab2008-09-03 17:12:14 -0300615
616 /* Start the new frame with the jpeg header */
Jean-François Moineb192ca92010-06-27 03:08:19 -0300617 pac_start_frame(gspca_dev,
Ondrej Zary1966bc22013-08-30 17:54:23 -0300618 gspca_dev->pixfmt.height, gspca_dev->pixfmt.width);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300619 }
Jean-Francois Moine76dd2722009-11-13 09:21:03 -0300620 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300621}
622
Peter Senna Tschudin2d622e92013-01-24 19:29:04 -0300623#if IS_ENABLED(CONFIG_INPUT)
Hans de Goede32ea3e42010-01-29 11:04:19 -0300624static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
625 u8 *data, /* interrupt packet data */
626 int len) /* interrupt packet length */
627{
628 int ret = -EINVAL;
629 u8 data0, data1;
630
631 if (len == 2) {
632 data0 = data[0];
633 data1 = data[1];
634 if ((data0 == 0x00 && data1 == 0x11) ||
635 (data0 == 0x22 && data1 == 0x33) ||
636 (data0 == 0x44 && data1 == 0x55) ||
637 (data0 == 0x66 && data1 == 0x77) ||
638 (data0 == 0x88 && data1 == 0x99) ||
639 (data0 == 0xaa && data1 == 0xbb) ||
640 (data0 == 0xcc && data1 == 0xdd) ||
641 (data0 == 0xee && data1 == 0xff)) {
642 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
643 input_sync(gspca_dev->input_dev);
644 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
645 input_sync(gspca_dev->input_dev);
646 ret = 0;
647 }
648 }
649
650 return ret;
651}
652#endif
653
Márton Némethaabcdfb2010-01-05 12:39:02 -0300654static const struct sd_desc sd_desc = {
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300655 .name = MODULE_NAME,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300656 .config = sd_config,
Jean-Francois Moine012d6b02008-09-03 17:12:16 -0300657 .init = sd_init,
Hans de Goede43f52bf2012-05-10 10:52:54 -0300658 .init_controls = sd_init_controls,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300659 .start = sd_start,
660 .stopN = sd_stopN,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300661 .pkt_scan = sd_pkt_scan,
Jean-Francois Moinecebf3b62008-08-03 07:52:53 -0300662 .dq_callback = do_autogain,
Peter Senna Tschudin2d622e92013-01-24 19:29:04 -0300663#if IS_ENABLED(CONFIG_INPUT)
Hans de Goede32ea3e42010-01-29 11:04:19 -0300664 .int_pkt_scan = sd_int_pkt_scan,
665#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300666};
667
668/* -- module initialisation -- */
Jean-François Moine95c967c2011-01-13 05:20:29 -0300669static const struct usb_device_id device_table[] = {
Marton Nemeth1408b842009-11-02 08:13:21 -0300670 {USB_DEVICE(0x093a, 0x2600)},
671 {USB_DEVICE(0x093a, 0x2601)},
672 {USB_DEVICE(0x093a, 0x2603)},
673 {USB_DEVICE(0x093a, 0x2608)},
674 {USB_DEVICE(0x093a, 0x260e)},
675 {USB_DEVICE(0x093a, 0x260f)},
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300676 {}
677};
678MODULE_DEVICE_TABLE(usb, device_table);
679
680/* -- device connect -- */
Jean-François Moine95c967c2011-01-13 05:20:29 -0300681static int sd_probe(struct usb_interface *intf,
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300682 const struct usb_device_id *id)
683{
684 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
685 THIS_MODULE);
686}
687
688static struct usb_driver sd_driver = {
689 .name = MODULE_NAME,
690 .id_table = device_table,
691 .probe = sd_probe,
692 .disconnect = gspca_disconnect,
Jean-Francois Moine6a709742008-09-03 16:48:10 -0300693#ifdef CONFIG_PM
694 .suspend = gspca_suspend,
695 .resume = gspca_resume,
Hans de Goede8bb58962012-06-30 06:44:47 -0300696 .reset_resume = gspca_resume,
Jean-Francois Moine6a709742008-09-03 16:48:10 -0300697#endif
Jean-Francois Moine6a7eba22008-06-30 15:50:11 -0300698};
699
Greg Kroah-Hartmanecb3b2b2011-11-18 09:46:12 -0800700module_usb_driver(sd_driver);