diff options
author | Jean-François Moine <moinejf@free.fr> | 2010-06-05 06:45:04 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-08-02 13:44:38 -0400 |
commit | 618a864ee7b720aa3560796e0dfad0e674366e60 (patch) | |
tree | 663c4bf3ebdd122f391baaf9aaa0727eae634dba | |
parent | e9b156532ec4d3c0a248ec958a8378f769297fcd (diff) |
V4L/DVB: gspca - sq930x: New subdriver
Signed-off-by: Jean-François Moine <moinejf@free.fr>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r-- | Documentation/video4linux/gspca.txt | 6 | ||||
-rw-r--r-- | drivers/media/video/gspca/Kconfig | 9 | ||||
-rw-r--r-- | drivers/media/video/gspca/Makefile | 2 | ||||
-rw-r--r-- | drivers/media/video/gspca/sq930x.c | 1140 |
4 files changed, 1157 insertions, 0 deletions
diff --git a/Documentation/video4linux/gspca.txt b/Documentation/video4linux/gspca.txt index f13eb036c439..a258107f8126 100644 --- a/Documentation/video4linux/gspca.txt +++ b/Documentation/video4linux/gspca.txt | |||
@@ -29,8 +29,12 @@ zc3xx 041e:4029 Creative WebCam Vista Pro | |||
29 | zc3xx 041e:4034 Creative Instant P0620 | 29 | zc3xx 041e:4034 Creative Instant P0620 |
30 | zc3xx 041e:4035 Creative Instant P0620D | 30 | zc3xx 041e:4035 Creative Instant P0620D |
31 | zc3xx 041e:4036 Creative Live ! | 31 | zc3xx 041e:4036 Creative Live ! |
32 | sq930x 041e:4038 Creative Joy-IT | ||
32 | zc3xx 041e:403a Creative Nx Pro 2 | 33 | zc3xx 041e:403a Creative Nx Pro 2 |
33 | spca561 041e:403b Creative Webcam Vista (VF0010) | 34 | spca561 041e:403b Creative Webcam Vista (VF0010) |
35 | sq930x 041e:403c Creative Live! Ultra | ||
36 | sq930x 041e:403d Creative Live! Ultra for Notebooks | ||
37 | sq930x 041e:4041 Creative Live! Motion | ||
34 | zc3xx 041e:4051 Creative Live!Cam Notebook Pro (VF0250) | 38 | zc3xx 041e:4051 Creative Live!Cam Notebook Pro (VF0250) |
35 | ov519 041e:4052 Creative Live! VISTA IM | 39 | ov519 041e:4052 Creative Live! VISTA IM |
36 | zc3xx 041e:4053 Creative Live!Cam Video IM | 40 | zc3xx 041e:4053 Creative Live!Cam Video IM |
@@ -362,6 +366,8 @@ sq905c 2770:9052 Disney pix micro 2 (VGA) | |||
362 | sq905c 2770:905c All 11 known cameras with this ID | 366 | sq905c 2770:905c All 11 known cameras with this ID |
363 | sq905 2770:9120 All 24 known cameras with this ID | 367 | sq905 2770:9120 All 24 known cameras with this ID |
364 | sq905c 2770:913d All 4 known cameras with this ID | 368 | sq905c 2770:913d All 4 known cameras with this ID |
369 | sq930x 2770:930b Sweex Motion Tracking / I-Tec iCam Tracer | ||
370 | sq930x 2770:930c Trust WB-3500T / NSG Robbie 2.0 | ||
365 | spca500 2899:012c Toptro Industrial | 371 | spca500 2899:012c Toptro Industrial |
366 | ov519 8020:ef04 ov519 | 372 | ov519 8020:ef04 ov519 |
367 | spca508 8086:0110 Intel Easy PC Camera | 373 | spca508 8086:0110 Intel Easy PC Camera |
diff --git a/drivers/media/video/gspca/Kconfig b/drivers/media/video/gspca/Kconfig index 5d920e584de7..f805d9772ba0 100644 --- a/drivers/media/video/gspca/Kconfig +++ b/drivers/media/video/gspca/Kconfig | |||
@@ -264,6 +264,15 @@ config USB_GSPCA_SQ905C | |||
264 | To compile this driver as a module, choose M here: the | 264 | To compile this driver as a module, choose M here: the |
265 | module will be called gspca_sq905c. | 265 | module will be called gspca_sq905c. |
266 | 266 | ||
267 | config USB_GSPCA_SQ930X | ||
268 | tristate "SQ Technologies SQ930X based USB Camera Driver" | ||
269 | depends on VIDEO_V4L2 && USB_GSPCA | ||
270 | help | ||
271 | Say Y here if you want support for cameras based on the SQ930X chip. | ||
272 | |||
273 | To compile this driver as a module, choose M here: the | ||
274 | module will be called gspca_sq930x. | ||
275 | |||
267 | config USB_GSPCA_STK014 | 276 | config USB_GSPCA_STK014 |
268 | tristate "Syntek DV4000 (STK014) USB Camera Driver" | 277 | tristate "Syntek DV4000 (STK014) USB Camera Driver" |
269 | depends on VIDEO_V4L2 && USB_GSPCA | 278 | depends on VIDEO_V4L2 && USB_GSPCA |
diff --git a/drivers/media/video/gspca/Makefile b/drivers/media/video/gspca/Makefile index 6e4cf1ce01c9..0900c0e70473 100644 --- a/drivers/media/video/gspca/Makefile +++ b/drivers/media/video/gspca/Makefile | |||
@@ -25,6 +25,7 @@ obj-$(CONFIG_USB_GSPCA_SPCA508) += gspca_spca508.o | |||
25 | obj-$(CONFIG_USB_GSPCA_SPCA561) += gspca_spca561.o | 25 | obj-$(CONFIG_USB_GSPCA_SPCA561) += gspca_spca561.o |
26 | obj-$(CONFIG_USB_GSPCA_SQ905) += gspca_sq905.o | 26 | obj-$(CONFIG_USB_GSPCA_SQ905) += gspca_sq905.o |
27 | obj-$(CONFIG_USB_GSPCA_SQ905C) += gspca_sq905c.o | 27 | obj-$(CONFIG_USB_GSPCA_SQ905C) += gspca_sq905c.o |
28 | obj-$(CONFIG_USB_GSPCA_SQ930X) += gspca_sq930x.o | ||
28 | obj-$(CONFIG_USB_GSPCA_SUNPLUS) += gspca_sunplus.o | 29 | obj-$(CONFIG_USB_GSPCA_SUNPLUS) += gspca_sunplus.o |
29 | obj-$(CONFIG_USB_GSPCA_STK014) += gspca_stk014.o | 30 | obj-$(CONFIG_USB_GSPCA_STK014) += gspca_stk014.o |
30 | obj-$(CONFIG_USB_GSPCA_STV0680) += gspca_stv0680.o | 31 | obj-$(CONFIG_USB_GSPCA_STV0680) += gspca_stv0680.o |
@@ -60,6 +61,7 @@ gspca_spca508-objs := spca508.o | |||
60 | gspca_spca561-objs := spca561.o | 61 | gspca_spca561-objs := spca561.o |
61 | gspca_sq905-objs := sq905.o | 62 | gspca_sq905-objs := sq905.o |
62 | gspca_sq905c-objs := sq905c.o | 63 | gspca_sq905c-objs := sq905c.o |
64 | gspca_sq930x-objs := sq930x.o | ||
63 | gspca_stk014-objs := stk014.o | 65 | gspca_stk014-objs := stk014.o |
64 | gspca_stv0680-objs := stv0680.o | 66 | gspca_stv0680-objs := stv0680.o |
65 | gspca_sunplus-objs := sunplus.o | 67 | gspca_sunplus-objs := sunplus.o |
diff --git a/drivers/media/video/gspca/sq930x.c b/drivers/media/video/gspca/sq930x.c new file mode 100644 index 000000000000..7e4381bbaf28 --- /dev/null +++ b/drivers/media/video/gspca/sq930x.c | |||
@@ -0,0 +1,1140 @@ | |||
1 | /* | ||
2 | * SQ930x subdriver | ||
3 | * | ||
4 | * Copyright (C) 2010 Jean-François Moine <http://moinejf.free.fr> | ||
5 | * Copyright (C) 2006 -2008 Gerard Klaver <gerard at gkall dot hobby dot nl> | ||
6 | * Copyright (C) 2007 Sam Revitch <samr7@cs.washington.edu> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | */ | ||
22 | |||
23 | #define MODULE_NAME "sq930x" | ||
24 | |||
25 | #include "gspca.h" | ||
26 | #include "jpeg.h" | ||
27 | |||
28 | MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>\n" | ||
29 | "Gerard Klaver <gerard at gkall dot hobby dot nl\n" | ||
30 | "Sam Revitch <samr7@cs.washington.edu>"); | ||
31 | MODULE_DESCRIPTION("GSPCA/SQ930x USB Camera Driver"); | ||
32 | MODULE_LICENSE("GPL"); | ||
33 | |||
34 | #define BULK_TRANSFER_LEN 5128 | ||
35 | |||
36 | /* Structure to hold all of our device specific stuff */ | ||
37 | struct sd { | ||
38 | struct gspca_dev gspca_dev; /* !! must be the first item */ | ||
39 | |||
40 | u16 expo; | ||
41 | u8 gain; | ||
42 | |||
43 | u8 quality; /* webcam quality 0..3 */ | ||
44 | #define QUALITY_DEF 1 | ||
45 | |||
46 | u8 gpio[2]; | ||
47 | |||
48 | u8 eof_len; | ||
49 | u8 do_ctrl; | ||
50 | |||
51 | u8 sensor; | ||
52 | enum { | ||
53 | SENSOR_ICX098BQ, | ||
54 | SENSOR_MI0360, | ||
55 | SENSOR_LZ24BP, | ||
56 | } sensors; | ||
57 | u8 type; | ||
58 | #define Generic 0 | ||
59 | #define Creative_live_motion 1 | ||
60 | |||
61 | u8 jpeg_hdr[JPEG_HDR_SZ]; | ||
62 | }; | ||
63 | |||
64 | static int sd_setexpo(struct gspca_dev *gspca_dev, __s32 val); | ||
65 | static int sd_getexpo(struct gspca_dev *gspca_dev, __s32 *val); | ||
66 | static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val); | ||
67 | static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val); | ||
68 | |||
69 | static const struct ctrl sd_ctrls[] = { | ||
70 | { | ||
71 | { | ||
72 | .id = V4L2_CID_EXPOSURE, | ||
73 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
74 | .name = "Exposure", | ||
75 | .minimum = 0x0001, | ||
76 | .maximum = 0x0fff, | ||
77 | .step = 1, | ||
78 | #define EXPO_DEF 0x027d | ||
79 | .default_value = EXPO_DEF, | ||
80 | }, | ||
81 | .set = sd_setexpo, | ||
82 | .get = sd_getexpo, | ||
83 | }, | ||
84 | { | ||
85 | { | ||
86 | .id = V4L2_CID_GAIN, | ||
87 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
88 | .name = "Gain", | ||
89 | .minimum = 0x01, | ||
90 | .maximum = 0xff, | ||
91 | .step = 1, | ||
92 | #define GAIN_DEF 0x61 | ||
93 | .default_value = GAIN_DEF, | ||
94 | }, | ||
95 | .set = sd_setgain, | ||
96 | .get = sd_getgain, | ||
97 | }, | ||
98 | }; | ||
99 | |||
100 | static struct v4l2_pix_format vga_mode[] = { | ||
101 | {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, | ||
102 | .bytesperline = 160, | ||
103 | .sizeimage = 160 * 120 * 5 / 8 + 590, | ||
104 | .colorspace = V4L2_COLORSPACE_JPEG, | ||
105 | .priv = 0}, | ||
106 | {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, | ||
107 | .bytesperline = 320, | ||
108 | .sizeimage = 320 * 240 * 4 / 8 + 590, | ||
109 | .colorspace = V4L2_COLORSPACE_JPEG, | ||
110 | .priv = 1}, | ||
111 | {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, | ||
112 | .bytesperline = 640, | ||
113 | .sizeimage = 640 * 480 * 3 / 8 + 590, | ||
114 | .colorspace = V4L2_COLORSPACE_JPEG, | ||
115 | .priv = 2}, | ||
116 | }; | ||
117 | |||
118 | /* JPEG quality indexed by webcam quality */ | ||
119 | #define QUAL_0 90 | ||
120 | #define QUAL_1 85 | ||
121 | #define QUAL_2 75 | ||
122 | #define QUAL_3 70 | ||
123 | static const u8 quality_tb[4] = { QUAL_0, QUAL_1, QUAL_2, QUAL_3 }; | ||
124 | |||
125 | /* sq930x registers */ | ||
126 | #define SQ930_CTRL_UCBUS_IO 0x0001 | ||
127 | #define SQ930_CTRL_I2C_IO 0x0002 | ||
128 | #define SQ930_CTRL_GPIO 0x0005 | ||
129 | #define SQ930_CTRL_CAP_START 0x0010 | ||
130 | #define SQ930_CTRL_CAP_STOP 0x0011 | ||
131 | #define SQ930_CTRL_SET_EXPOSURE 0x001d | ||
132 | #define SQ930_CTRL_RESET 0x001e | ||
133 | #define SQ930_CTRL_GET_DEV_INFO 0x001f | ||
134 | |||
135 | /* gpio 1 (8..15) */ | ||
136 | #define SQ930_GPIO_DFL_I2C_SDA 0x0001 | ||
137 | #define SQ930_GPIO_DFL_I2C_SCL 0x0002 | ||
138 | #define SQ930_GPIO_RSTBAR 0x0004 | ||
139 | #define SQ930_GPIO_EXTRA1 0x0040 | ||
140 | #define SQ930_GPIO_EXTRA2 0x0080 | ||
141 | /* gpio 3 (24..31) */ | ||
142 | #define SQ930_GPIO_POWER 0x0200 | ||
143 | #define SQ930_GPIO_DFL_LED 0x1000 | ||
144 | |||
145 | struct ucbus_write_cmd { | ||
146 | u16 bw_addr; | ||
147 | u8 bw_data; | ||
148 | }; | ||
149 | struct i2c_write_cmd { | ||
150 | u8 reg; | ||
151 | u16 val; | ||
152 | }; | ||
153 | |||
154 | static const struct ucbus_write_cmd icx098bq_start_0[] = { | ||
155 | {0x0354, 0x00}, {0x03fa, 0x00}, {0xf800, 0x02}, {0xf801, 0xce}, | ||
156 | {0xf802, 0xc1}, {0xf804, 0x00}, {0xf808, 0x00}, {0xf809, 0x0e}, | ||
157 | {0xf80a, 0x01}, {0xf80b, 0xee}, {0xf807, 0x60}, {0xf80c, 0x02}, | ||
158 | {0xf80d, 0xf0}, {0xf80e, 0x03}, {0xf80f, 0x0a}, {0xf81c, 0x02}, | ||
159 | {0xf81d, 0xf0}, {0xf81e, 0x03}, {0xf81f, 0x0a}, {0xf83a, 0x00}, | ||
160 | {0xf83b, 0x10}, {0xf83c, 0x00}, {0xf83d, 0x4e}, {0xf810, 0x04}, | ||
161 | {0xf811, 0x00}, {0xf812, 0x02}, {0xf813, 0x10}, {0xf803, 0x00}, | ||
162 | {0xf814, 0x01}, {0xf815, 0x18}, {0xf816, 0x00}, {0xf817, 0x48}, | ||
163 | {0xf818, 0x00}, {0xf819, 0x25}, {0xf81a, 0x00}, {0xf81b, 0x3c}, | ||
164 | {0xf82f, 0x03}, {0xf820, 0xff}, {0xf821, 0x0d}, {0xf822, 0xff}, | ||
165 | {0xf823, 0x07}, {0xf824, 0xff}, {0xf825, 0x03}, {0xf826, 0xff}, | ||
166 | {0xf827, 0x06}, {0xf828, 0xff}, {0xf829, 0x03}, {0xf82a, 0xff}, | ||
167 | {0xf82b, 0x0c}, {0xf82c, 0xfd}, {0xf82d, 0x01}, {0xf82e, 0x00}, | ||
168 | {0xf830, 0x00}, {0xf831, 0x47}, {0xf832, 0x00}, {0xf833, 0x00}, | ||
169 | {0xf850, 0x00}, {0xf851, 0x00}, {0xf852, 0x00}, {0xf853, 0x24}, | ||
170 | {0xf854, 0x00}, {0xf855, 0x18}, {0xf856, 0x00}, {0xf857, 0x3c}, | ||
171 | {0xf858, 0x00}, {0xf859, 0x0c}, {0xf85a, 0x00}, {0xf85b, 0x30}, | ||
172 | {0xf85c, 0x00}, {0xf85d, 0x0c}, {0xf85e, 0x00}, {0xf85f, 0x30}, | ||
173 | {0xf860, 0x00}, {0xf861, 0x48}, {0xf862, 0x01}, {0xf863, 0xdc}, | ||
174 | {0xf864, 0xff}, {0xf865, 0x98}, {0xf866, 0xff}, {0xf867, 0xc0}, | ||
175 | {0xf868, 0xff}, {0xf869, 0x70}, {0xf86c, 0xff}, {0xf86d, 0x00}, | ||
176 | {0xf86a, 0xff}, {0xf86b, 0x48}, {0xf86e, 0xff}, {0xf86f, 0x00}, | ||
177 | {0xf870, 0x01}, {0xf871, 0xdb}, {0xf872, 0x01}, {0xf873, 0xfa}, | ||
178 | {0xf874, 0x01}, {0xf875, 0xdb}, {0xf876, 0x01}, {0xf877, 0xfa}, | ||
179 | {0xf878, 0x0f}, {0xf879, 0x0f}, {0xf87a, 0xff}, {0xf87b, 0xff}, | ||
180 | {0xf800, 0x03} | ||
181 | }; | ||
182 | static const struct ucbus_write_cmd icx098bq_start_1[] = { | ||
183 | {0xf5f0, 0x00}, {0xf5f1, 0xcd}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, | ||
184 | {0xf5f4, 0xc0}, | ||
185 | {0xf5f0, 0x49}, {0xf5f1, 0xcd}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, | ||
186 | {0xf5f4, 0xc0}, | ||
187 | {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00}, | ||
188 | {0xf5f9, 0x00} | ||
189 | }; | ||
190 | |||
191 | static const struct ucbus_write_cmd icx098bq_start_2[] = { | ||
192 | {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x82}, {0xf806, 0x00}, | ||
193 | {0xf807, 0x7f}, {0xf800, 0x03}, | ||
194 | {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x40}, {0xf806, 0x00}, | ||
195 | {0xf807, 0x7f}, {0xf800, 0x03}, | ||
196 | {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0xcf}, {0xf806, 0xd0}, | ||
197 | {0xf807, 0x7f}, {0xf800, 0x03}, | ||
198 | {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x00}, {0xf806, 0x00}, | ||
199 | {0xf807, 0x7f}, {0xf800, 0x03} | ||
200 | }; | ||
201 | |||
202 | static const struct ucbus_write_cmd lz24bp_start_0[] = { | ||
203 | {0x0354, 0x00}, {0x03fa, 0x00}, {0xf800, 0x02}, {0xf801, 0xbe}, | ||
204 | {0xf802, 0xc6}, {0xf804, 0x00}, {0xf808, 0x00}, {0xf809, 0x06}, | ||
205 | {0xf80a, 0x01}, {0xf80b, 0xfe}, {0xf807, 0x84}, {0xf80c, 0x02}, | ||
206 | {0xf80d, 0xf7}, {0xf80e, 0x03}, {0xf80f, 0x0b}, {0xf81c, 0x00}, | ||
207 | {0xf81d, 0x49}, {0xf81e, 0x03}, {0xf81f, 0x0b}, {0xf83a, 0x00}, | ||
208 | {0xf83b, 0x01}, {0xf83c, 0x00}, {0xf83d, 0x6b}, {0xf810, 0x03}, | ||
209 | {0xf811, 0x10}, {0xf812, 0x02}, {0xf813, 0x6f}, {0xf803, 0x00}, | ||
210 | {0xf814, 0x00}, {0xf815, 0x44}, {0xf816, 0x00}, {0xf817, 0x48}, | ||
211 | {0xf818, 0x00}, {0xf819, 0x25}, {0xf81a, 0x00}, {0xf81b, 0x3c}, | ||
212 | {0xf82f, 0x03}, {0xf820, 0xff}, {0xf821, 0x0d}, {0xf822, 0xff}, | ||
213 | {0xf823, 0x07}, {0xf824, 0xfd}, {0xf825, 0x07}, {0xf826, 0xf0}, | ||
214 | {0xf827, 0x0c}, {0xf828, 0xff}, {0xf829, 0x03}, {0xf82a, 0xff}, | ||
215 | {0xf82b, 0x0c}, {0xf82c, 0xfc}, {0xf82d, 0x01}, {0xf82e, 0x00}, | ||
216 | {0xf830, 0x00}, {0xf831, 0x47}, {0xf832, 0x00}, {0xf833, 0x00}, | ||
217 | {0xf850, 0x00}, {0xf851, 0x00}, {0xf852, 0x00}, {0xf853, 0x24}, | ||
218 | {0xf854, 0x00}, {0xf855, 0x0c}, {0xf856, 0x00}, {0xf857, 0x30}, | ||
219 | {0xf858, 0x00}, {0xf859, 0x18}, {0xf85a, 0x00}, {0xf85b, 0x3c}, | ||
220 | {0xf85c, 0x00}, {0xf85d, 0x18}, {0xf85e, 0x00}, {0xf85f, 0x3c}, | ||
221 | {0xf860, 0xff}, {0xf861, 0x37}, {0xf862, 0xff}, {0xf863, 0x1d}, | ||
222 | {0xf864, 0xff}, {0xf865, 0x98}, {0xf866, 0xff}, {0xf867, 0xc0}, | ||
223 | {0xf868, 0x00}, {0xf869, 0x37}, {0xf86c, 0x02}, {0xf86d, 0x1d}, | ||
224 | {0xf86a, 0x00}, {0xf86b, 0x37}, {0xf86e, 0x02}, {0xf86f, 0x1d}, | ||
225 | {0xf870, 0x01}, {0xf871, 0xc6}, {0xf872, 0x02}, {0xf873, 0x04}, | ||
226 | {0xf874, 0x01}, {0xf875, 0xc6}, {0xf876, 0x02}, {0xf877, 0x04}, | ||
227 | {0xf878, 0x0f}, {0xf879, 0x0f}, {0xf87a, 0xff}, {0xf87b, 0xff}, | ||
228 | {0xf800, 0x03} | ||
229 | }; | ||
230 | static const struct ucbus_write_cmd lz24bp_start_1_gen[] = { | ||
231 | {0xf5f0, 0x00}, {0xf5f1, 0xff}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, | ||
232 | {0xf5f4, 0xb3}, | ||
233 | {0xf5f0, 0x40}, {0xf5f1, 0xff}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, | ||
234 | {0xf5f4, 0xb3}, | ||
235 | {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00}, | ||
236 | {0xf5f9, 0x00} | ||
237 | }; | ||
238 | |||
239 | static const struct ucbus_write_cmd lz24bp_start_1_clm[] = { | ||
240 | {0xf5f0, 0x00}, {0xf5f1, 0xff}, {0xf5f2, 0x88}, {0xf5f3, 0x88}, | ||
241 | {0xf5f4, 0xc0}, | ||
242 | {0xf5f0, 0x40}, {0xf5f1, 0xff}, {0xf5f2, 0x88}, {0xf5f3, 0x88}, | ||
243 | {0xf5f4, 0xc0}, | ||
244 | {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00}, | ||
245 | {0xf5f9, 0x00} | ||
246 | }; | ||
247 | |||
248 | static const struct ucbus_write_cmd lz24bp_start_2[] = { | ||
249 | {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x80}, {0xf806, 0x00}, | ||
250 | {0xf807, 0x7f}, {0xf800, 0x03}, | ||
251 | {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x4e}, {0xf806, 0x00}, | ||
252 | {0xf807, 0x7f}, {0xf800, 0x03}, | ||
253 | {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0xc0}, {0xf806, 0x48}, | ||
254 | {0xf807, 0x7f}, {0xf800, 0x03}, | ||
255 | {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x00}, {0xf806, 0x00}, | ||
256 | {0xf807, 0x7f}, {0xf800, 0x03} | ||
257 | }; | ||
258 | |||
259 | static const struct ucbus_write_cmd mi0360_start_0[] = { | ||
260 | {0x0354, 0x00}, {0x03fa, 0x00}, {0xf332, 0xcc}, {0xf333, 0xcc}, | ||
261 | {0xf334, 0xcc}, {0xf335, 0xcc}, {0xf33f, 0x00} | ||
262 | }; | ||
263 | static const struct i2c_write_cmd mi0360_init_23[] = { | ||
264 | {0x30, 0x0040}, /* reserved - def 0x0005 */ | ||
265 | {0x31, 0x0000}, /* reserved - def 0x002a */ | ||
266 | {0x34, 0x0100}, /* reserved - def 0x0100 */ | ||
267 | {0x3d, 0x068f}, /* reserved - def 0x068f */ | ||
268 | }; | ||
269 | static const struct i2c_write_cmd mi0360_init_24[] = { | ||
270 | {0x03, 0x01e5}, /* window height */ | ||
271 | {0x04, 0x0285}, /* window width */ | ||
272 | }; | ||
273 | static const struct i2c_write_cmd mi0360_init_25[] = { | ||
274 | {0x35, 0x0020}, /* global gain */ | ||
275 | {0x2b, 0x0020}, /* green1 gain */ | ||
276 | {0x2c, 0x002a}, /* blue gain */ | ||
277 | {0x2d, 0x0028}, /* red gain */ | ||
278 | {0x2e, 0x0020}, /* green2 gain */ | ||
279 | }; | ||
280 | static const struct ucbus_write_cmd mi0360_start_1[] = { | ||
281 | {0xf5f0, 0x11}, {0xf5f1, 0x99}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, | ||
282 | {0xf5f4, 0xa6}, | ||
283 | {0xf5f0, 0x51}, {0xf5f1, 0x99}, {0xf5f2, 0x80}, {0xf5f3, 0x80}, | ||
284 | {0xf5f4, 0xa6}, | ||
285 | {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00}, | ||
286 | {0xf5f9, 0x00} | ||
287 | }; | ||
288 | static const struct i2c_write_cmd mi0360_start_2[] = { | ||
289 | {0x62, 0x041d}, /* reserved - def 0x0418 */ | ||
290 | }; | ||
291 | static const struct i2c_write_cmd mi0360_start_3[] = { | ||
292 | {0x05, 0x007b}, /* horiz blanking */ | ||
293 | }; | ||
294 | static const struct i2c_write_cmd mi0360_start_4[] = { | ||
295 | {0x05, 0x03f5}, /* horiz blanking */ | ||
296 | }; | ||
297 | |||
298 | static const struct cap_s { | ||
299 | u8 cc_sizeid; | ||
300 | u8 cc_bytes[32]; | ||
301 | } capconfig[3][3] = { | ||
302 | [SENSOR_ICX098BQ] = { | ||
303 | {0, /* JPEG, 160x120 */ | ||
304 | {0x01, 0x1f, 0x20, 0x0e, 0x00, 0x9f, 0x02, 0xee, | ||
305 | 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, | ||
306 | 0x02, 0x8b, 0x00, 0x8b, 0x00, 0x41, 0x01, 0x41, | ||
307 | 0x01, 0x41, 0x01, 0x05, 0x40, 0x01, 0xf0, 0x00} }, | ||
308 | {2, /* JPEG, 320x240 */ | ||
309 | {0x01, 0x1f, 0x20, 0x0e, 0x00, 0x9f, 0x02, 0xee, | ||
310 | 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, | ||
311 | 0x02, 0xdf, 0x01, 0x00, 0x00, 0x3f, 0x01, 0x3f, | ||
312 | 0x01, 0x00, 0x00, 0x05, 0x40, 0x01, 0xf0, 0x00} }, | ||
313 | {4, /* JPEG, 640x480 */ | ||
314 | {0x01, 0x22, 0x20, 0x0e, 0x00, 0xa2, 0x02, 0xf0, | ||
315 | 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, | ||
316 | 0x07, 0xe1, 0x01, 0xe1, 0x01, 0x3f, 0x01, 0x3f, | ||
317 | 0x01, 0x3f, 0x01, 0x05, 0x80, 0x02, 0xe0, 0x01} }, | ||
318 | }, | ||
319 | [SENSOR_LZ24BP] = { | ||
320 | {0, /* JPEG, 160x120 */ | ||
321 | {0x01, 0x1f, 0x20, 0x0e, 0x00, 0x9f, 0x02, 0xee, | ||
322 | 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, | ||
323 | 0x02, 0x8b, 0x00, 0x8b, 0x00, 0x41, 0x01, 0x41, | ||
324 | 0x01, 0x41, 0x01, 0x05, 0x40, 0x01, 0xf0, 0x00} }, | ||
325 | {2, /* JPEG, 320x240 */ | ||
326 | {0x01, 0x22, 0x20, 0x0e, 0x00, 0xa2, 0x02, 0xee, | ||
327 | 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, | ||
328 | 0x02, 0xdf, 0x01, 0x00, 0x00, 0x3f, 0x01, 0x3f, | ||
329 | 0x01, 0x00, 0x00, 0x05, 0x40, 0x01, 0xf0, 0x00} }, | ||
330 | {4, /* JPEG, 640x480 */ | ||
331 | {0x01, 0x22, 0x20, 0x0e, 0x00, 0xa2, 0x02, 0xf0, | ||
332 | 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, | ||
333 | 0x07, 0xe1, 0x01, 0xe1, 0x01, 0x3f, 0x01, 0x3f, | ||
334 | 0x01, 0x3f, 0x01, 0x05, 0x80, 0x02, 0xe0, 0x01} }, | ||
335 | }, | ||
336 | [SENSOR_MI0360] = { | ||
337 | {0, /* JPEG, 160x120 */ | ||
338 | {0x05, 0x3d, 0x20, 0x0b, 0x00, 0xbd, 0x02, 0x0b, | ||
339 | 0x02, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, | ||
340 | 0x02, 0x01, 0x01, 0x01, 0x01, 0x9f, 0x00, 0x9f, | ||
341 | 0x00, 0x9f, 0x01, 0x05, 0xa0, 0x00, 0x80, 0x00} }, | ||
342 | {2, /* JPEG, 320x240 */ | ||
343 | {0x01, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe1, | ||
344 | /*fixme 03 e3 */ | ||
345 | 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, | ||
346 | 0x02, 0xdf, 0x01, 0x00, 0x00, 0x3f, 0x01, 0x3f, | ||
347 | 0x01, 0x00, 0x00, 0x05, 0x40, 0x01, 0xf0, 0x00} }, | ||
348 | {4, /* JPEG, 640x480 */ | ||
349 | {0x01, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe3, | ||
350 | 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8, | ||
351 | 0x07, 0xe1, 0x01, 0xe1, 0x01, 0x3f, 0x01, 0x3f, | ||
352 | 0x01, 0x3f, 0x01, 0x05, 0x80, 0x02, 0xe0, 0x01} }, | ||
353 | }, | ||
354 | }; | ||
355 | |||
356 | static void reg_r(struct gspca_dev *gspca_dev, | ||
357 | u16 value, int len) | ||
358 | { | ||
359 | usb_control_msg(gspca_dev->dev, | ||
360 | usb_rcvctrlpipe(gspca_dev->dev, 0), | ||
361 | 0x0c, | ||
362 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
363 | value, 0, gspca_dev->usb_buf, len, | ||
364 | 500); | ||
365 | } | ||
366 | |||
367 | static void reg_w(struct gspca_dev *gspca_dev, u16 value, u16 index) | ||
368 | { | ||
369 | int ret; | ||
370 | |||
371 | if (gspca_dev->usb_err < 0) | ||
372 | return; | ||
373 | PDEBUG(D_USBO, "reg_w v: %04x i: %04x", value, index); | ||
374 | ret = usb_control_msg(gspca_dev->dev, | ||
375 | usb_sndctrlpipe(gspca_dev->dev, 0), | ||
376 | 0x0c, /* request */ | ||
377 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
378 | value, index, NULL, 0, | ||
379 | 500); | ||
380 | msleep(30); | ||
381 | if (ret < 0) { | ||
382 | PDEBUG(D_ERR, "reg_w %04x %04x failed %d", value, index, ret); | ||
383 | gspca_dev->usb_err = ret; | ||
384 | } | ||
385 | } | ||
386 | |||
387 | static void reg_wb(struct gspca_dev *gspca_dev, u16 value, u16 index, | ||
388 | const u8 *data, int len) | ||
389 | { | ||
390 | int ret; | ||
391 | |||
392 | if (gspca_dev->usb_err < 0) | ||
393 | return; | ||
394 | PDEBUG(D_USBO, "reg_wb v: %04x i: %04x %02x...%02x", | ||
395 | value, index, *data, data[len - 1]); | ||
396 | memcpy(gspca_dev->usb_buf, data, len); | ||
397 | ret = usb_control_msg(gspca_dev->dev, | ||
398 | usb_sndctrlpipe(gspca_dev->dev, 0), | ||
399 | 0x0c, /* request */ | ||
400 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
401 | value, index, gspca_dev->usb_buf, len, | ||
402 | 1000); | ||
403 | msleep(30); | ||
404 | if (ret < 0) { | ||
405 | PDEBUG(D_ERR, "reg_wb %04x %04x failed %d", value, index, ret); | ||
406 | gspca_dev->usb_err = ret; | ||
407 | } | ||
408 | } | ||
409 | |||
410 | static void i2c_write(struct gspca_dev *gspca_dev, | ||
411 | const struct i2c_write_cmd *cmd, | ||
412 | int ncmds) | ||
413 | { | ||
414 | u16 val, idx; | ||
415 | u8 *buf; | ||
416 | int ret; | ||
417 | |||
418 | if (gspca_dev->usb_err < 0) | ||
419 | return; | ||
420 | |||
421 | val = (0x5d << 8) | SQ930_CTRL_I2C_IO; /* 0x5d = mi0360 i2c addr */ | ||
422 | idx = (cmd->val & 0xff00) | cmd->reg; | ||
423 | |||
424 | buf = gspca_dev->usb_buf; | ||
425 | *buf++ = 0x80; | ||
426 | *buf++ = cmd->val; | ||
427 | |||
428 | while (--ncmds > 0) { | ||
429 | cmd++; | ||
430 | *buf++ = cmd->reg; | ||
431 | *buf++ = cmd->val >> 8; | ||
432 | *buf++ = 0x80; | ||
433 | *buf++ = cmd->val; | ||
434 | } | ||
435 | |||
436 | PDEBUG(D_USBO, "i2c_w v: %04x i: %04x %02x...%02x", | ||
437 | val, idx, gspca_dev->usb_buf[0], buf[-1]); | ||
438 | ret = usb_control_msg(gspca_dev->dev, | ||
439 | usb_sndctrlpipe(gspca_dev->dev, 0), | ||
440 | 0x0c, /* request */ | ||
441 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
442 | val, idx, | ||
443 | gspca_dev->usb_buf, buf - gspca_dev->usb_buf, | ||
444 | 500); | ||
445 | if (ret < 0) { | ||
446 | PDEBUG(D_ERR, "i2c_write failed %d", ret); | ||
447 | gspca_dev->usb_err = ret; | ||
448 | } | ||
449 | } | ||
450 | |||
451 | static void ucbus_write(struct gspca_dev *gspca_dev, | ||
452 | const struct ucbus_write_cmd *cmd, | ||
453 | int ncmds, | ||
454 | int batchsize) | ||
455 | { | ||
456 | u8 *buf; | ||
457 | u16 val, idx; | ||
458 | int len, ret; | ||
459 | |||
460 | if (gspca_dev->usb_err < 0) | ||
461 | return; | ||
462 | |||
463 | #ifdef GSPCA_DEBUG | ||
464 | if ((batchsize - 1) * 3 > USB_BUF_SZ) { | ||
465 | err("Bug: usb_buf overflow"); | ||
466 | gspca_dev->usb_err = -ENOMEM; | ||
467 | return; | ||
468 | } | ||
469 | #endif | ||
470 | |||
471 | for (;;) { | ||
472 | len = ncmds; | ||
473 | if (len > batchsize) | ||
474 | len = batchsize; | ||
475 | ncmds -= len; | ||
476 | |||
477 | val = (cmd->bw_addr << 8) | SQ930_CTRL_UCBUS_IO; | ||
478 | idx = (cmd->bw_data << 8) | (cmd->bw_addr >> 8); | ||
479 | |||
480 | buf = gspca_dev->usb_buf; | ||
481 | while (--len > 0) { | ||
482 | cmd++; | ||
483 | *buf++ = cmd->bw_addr; | ||
484 | *buf++ = cmd->bw_addr >> 8; | ||
485 | *buf++ = cmd->bw_data; | ||
486 | } | ||
487 | if (buf != gspca_dev->usb_buf) | ||
488 | PDEBUG(D_USBO, "ucbus v: %04x i: %04x %02x...%02x", | ||
489 | val, idx, | ||
490 | gspca_dev->usb_buf[0], buf[-1]); | ||
491 | else | ||
492 | PDEBUG(D_USBO, "ucbus v: %04x i: %04x", | ||
493 | val, idx); | ||
494 | ret = usb_control_msg(gspca_dev->dev, | ||
495 | usb_sndctrlpipe(gspca_dev->dev, 0), | ||
496 | 0x0c, /* request */ | ||
497 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
498 | val, idx, | ||
499 | gspca_dev->usb_buf, buf - gspca_dev->usb_buf, | ||
500 | 500); | ||
501 | if (ret < 0) { | ||
502 | PDEBUG(D_ERR, "ucbus_write failed %d", ret); | ||
503 | gspca_dev->usb_err = ret; | ||
504 | return; | ||
505 | } | ||
506 | msleep(30); | ||
507 | if (ncmds <= 0) | ||
508 | break; | ||
509 | cmd++; | ||
510 | } | ||
511 | } | ||
512 | |||
513 | static void gpio_set(struct sd *sd, u16 val, u16 mask) | ||
514 | { | ||
515 | struct gspca_dev *gspca_dev = &sd->gspca_dev; | ||
516 | |||
517 | if (mask & 0x00ff) { | ||
518 | sd->gpio[0] &= ~mask; | ||
519 | sd->gpio[0] |= val; | ||
520 | reg_w(gspca_dev, 0x0100 | SQ930_CTRL_GPIO, | ||
521 | ~sd->gpio[0] << 8); | ||
522 | } | ||
523 | mask >>= 8; | ||
524 | val >>= 8; | ||
525 | if (mask) { | ||
526 | sd->gpio[1] &= ~mask; | ||
527 | sd->gpio[1] |= val; | ||
528 | reg_w(gspca_dev, 0x0300 | SQ930_CTRL_GPIO, | ||
529 | ~sd->gpio[1] << 8); | ||
530 | } | ||
531 | } | ||
532 | |||
533 | static void global_init(struct sd *sd, int first_time) | ||
534 | { | ||
535 | static const struct ucbus_write_cmd clkfreq_cmd = { | ||
536 | 0xf031, 0 /* SQ930_CLKFREQ_60MHZ */ | ||
537 | }; | ||
538 | |||
539 | ucbus_write(&sd->gspca_dev, &clkfreq_cmd, 1, 1); | ||
540 | |||
541 | gpio_set(sd, SQ930_GPIO_POWER, 0xff00); | ||
542 | switch (sd->sensor) { | ||
543 | case SENSOR_ICX098BQ: | ||
544 | if (first_time) | ||
545 | ucbus_write(&sd->gspca_dev, | ||
546 | icx098bq_start_0, | ||
547 | 8, 8); | ||
548 | gpio_set(sd, 0, 0x00ff); | ||
549 | gpio_set(sd, SQ930_GPIO_DFL_I2C_SCL | SQ930_GPIO_DFL_I2C_SDA, | ||
550 | SQ930_GPIO_DFL_I2C_SCL | SQ930_GPIO_DFL_I2C_SDA); | ||
551 | gpio_set(sd, 0, SQ930_GPIO_DFL_I2C_SCL); | ||
552 | gpio_set(sd, 0, SQ930_GPIO_DFL_I2C_SDA); | ||
553 | gpio_set(sd, SQ930_GPIO_RSTBAR, | ||
554 | SQ930_GPIO_RSTBAR); | ||
555 | break; | ||
556 | case SENSOR_LZ24BP: | ||
557 | if (sd->type != Creative_live_motion) | ||
558 | gpio_set(sd, SQ930_GPIO_EXTRA1, 0x00ff); | ||
559 | else | ||
560 | gpio_set(sd, 0, 0x00ff); | ||
561 | msleep(50); | ||
562 | if (first_time) | ||
563 | ucbus_write(&sd->gspca_dev, | ||
564 | lz24bp_start_0, | ||
565 | 8, 8); | ||
566 | gpio_set(sd, 0, 0x0001); /* no change */ | ||
567 | gpio_set(sd, SQ930_GPIO_DFL_I2C_SCL | SQ930_GPIO_DFL_I2C_SDA, | ||
568 | SQ930_GPIO_DFL_I2C_SCL | SQ930_GPIO_DFL_I2C_SDA); | ||
569 | gpio_set(sd, 0, SQ930_GPIO_DFL_I2C_SCL); | ||
570 | gpio_set(sd, 0, SQ930_GPIO_DFL_I2C_SDA); | ||
571 | gpio_set(sd, SQ930_GPIO_RSTBAR, | ||
572 | SQ930_GPIO_RSTBAR); | ||
573 | break; | ||
574 | default: | ||
575 | /* case SENSOR_MI0360: */ | ||
576 | if (first_time) { | ||
577 | ucbus_write(&sd->gspca_dev, | ||
578 | mi0360_start_0, | ||
579 | ARRAY_SIZE(mi0360_start_0), | ||
580 | 8); | ||
581 | gpio_set(sd, SQ930_GPIO_RSTBAR, 0x00ff); | ||
582 | } else { | ||
583 | gpio_set(sd, SQ930_GPIO_EXTRA2 | SQ930_GPIO_RSTBAR, | ||
584 | 0x00ff); | ||
585 | } | ||
586 | gpio_set(sd, SQ930_GPIO_DFL_I2C_SCL | SQ930_GPIO_DFL_I2C_SDA, | ||
587 | SQ930_GPIO_RSTBAR | | ||
588 | SQ930_GPIO_DFL_I2C_SCL | SQ930_GPIO_DFL_I2C_SDA); | ||
589 | gpio_set(sd, 0, SQ930_GPIO_DFL_I2C_SCL); | ||
590 | gpio_set(sd, 0, SQ930_GPIO_DFL_I2C_SDA); | ||
591 | gpio_set(sd, 0, SQ930_GPIO_DFL_I2C_SDA); | ||
592 | gpio_set(sd, SQ930_GPIO_EXTRA2, SQ930_GPIO_EXTRA2); | ||
593 | break; | ||
594 | } | ||
595 | } | ||
596 | |||
597 | static void lz24bp_ppl(struct sd *sd, u16 ppl) | ||
598 | { | ||
599 | struct ucbus_write_cmd cmds[2] = { | ||
600 | {0xf810, ppl >> 8}, | ||
601 | {0xf811, ppl} | ||
602 | }; | ||
603 | |||
604 | ucbus_write(&sd->gspca_dev, cmds, ARRAY_SIZE(cmds), 2); | ||
605 | } | ||
606 | |||
607 | static void setexposure(struct gspca_dev *gspca_dev) | ||
608 | { | ||
609 | struct sd *sd = (struct sd *) gspca_dev; | ||
610 | int i, integclks, intstartclk, frameclks, min_frclk; | ||
611 | u16 cmd; | ||
612 | u8 buf[15]; | ||
613 | |||
614 | integclks = sd->expo; | ||
615 | i = 0; | ||
616 | cmd = SQ930_CTRL_SET_EXPOSURE; | ||
617 | if (sd->sensor == SENSOR_MI0360) { | ||
618 | cmd |= 0x0100; | ||
619 | buf[i++] = 0x5d; /* i2c_slave_addr */ | ||
620 | buf[i++] = 0x08; /* 2 * ni2c */ | ||
621 | buf[i++] = 0x09; /* reg = shutter width */ | ||
622 | buf[i++] = integclks >> 8; /* val H */ | ||
623 | buf[i++] = 0x80; | ||
624 | buf[i++] = integclks; /* val L */ | ||
625 | buf[i++] = 0x35; /* reg = global gain */ | ||
626 | buf[i++] = 0x00; /* val H */ | ||
627 | buf[i++] = 0x80; | ||
628 | buf[i++] = sd->gain; /* val L */ | ||
629 | buf[i++] = 0x00; | ||
630 | buf[i++] = 0x00; | ||
631 | buf[i++] = 0x00; | ||
632 | buf[i++] = 0x00; | ||
633 | buf[i++] = 0x83; | ||
634 | } else { | ||
635 | min_frclk = sd->sensor == SENSOR_ICX098BQ ? 0x210 : 0x26f; | ||
636 | if (integclks >= min_frclk) { | ||
637 | intstartclk = 0; | ||
638 | frameclks = integclks; | ||
639 | } else { | ||
640 | intstartclk = min_frclk - integclks; | ||
641 | frameclks = min_frclk; | ||
642 | } | ||
643 | buf[i++] = intstartclk >> 8; | ||
644 | buf[i++] = intstartclk; | ||
645 | buf[i++] = frameclks >> 8; | ||
646 | buf[i++] = frameclks; | ||
647 | buf[i++] = sd->gain; | ||
648 | } | ||
649 | reg_wb(gspca_dev, cmd, 0, buf, i); | ||
650 | } | ||
651 | |||
652 | /* This function is called at probe time just before sd_init */ | ||
653 | static int sd_config(struct gspca_dev *gspca_dev, | ||
654 | const struct usb_device_id *id) | ||
655 | { | ||
656 | struct sd *sd = (struct sd *) gspca_dev; | ||
657 | struct cam *cam = &gspca_dev->cam; | ||
658 | |||
659 | sd->sensor = id->driver_info >> 8; | ||
660 | sd->type = id->driver_info; | ||
661 | |||
662 | cam->cam_mode = vga_mode; | ||
663 | cam->nmodes = ARRAY_SIZE(vga_mode); | ||
664 | |||
665 | cam->bulk = 1; | ||
666 | cam->bulk_size = BULK_TRANSFER_LEN; | ||
667 | /* cam->bulk_nurbs = 2; fixme: if no setexpo sync */ | ||
668 | |||
669 | sd->quality = QUALITY_DEF; | ||
670 | sd->gain = GAIN_DEF; | ||
671 | sd->expo = EXPO_DEF; | ||
672 | |||
673 | return 0; | ||
674 | } | ||
675 | |||
676 | /* this function is called at probe and resume time */ | ||
677 | static int sd_init(struct gspca_dev *gspca_dev) | ||
678 | { | ||
679 | struct sd *sd = (struct sd *) gspca_dev; | ||
680 | |||
681 | sd->gpio[0] = sd->gpio[1] = 0xff; /* force gpio rewrite */ | ||
682 | |||
683 | if (sd->sensor != SENSOR_LZ24BP) | ||
684 | reg_w(gspca_dev, SQ930_CTRL_RESET, 0x0000); | ||
685 | |||
686 | reg_r(gspca_dev, SQ930_CTRL_GET_DEV_INFO, 8); | ||
687 | /* it returns: | ||
688 | * 03 00 12 93 0b f6 c9 00 live! ultra | ||
689 | * 03 00 07 93 0b f6 ca 00 live! ultra for notebook | ||
690 | * 03 00 12 93 0b fe c8 00 Trust WB-3500T | ||
691 | * 02 00 06 93 0b fe c8 00 Joy-IT 318S | ||
692 | * 03 00 12 93 0b f6 cf 00 icam tracer - sensor icx098bq | ||
693 | * 02 00 12 93 0b fe cf 00 ProQ Motion Webcam | ||
694 | * | ||
695 | * byte | ||
696 | * 0: 02 = usb 1.0 (12Mbit) / 03 = usb2.0 (480Mbit) | ||
697 | * 1: 00 | ||
698 | * 2: 06 / 07 / 12 = mode webcam? firmware?? | ||
699 | * 3: 93 chip = 930b (930b or 930c) | ||
700 | * 4: 0b | ||
701 | * 5: f6 = cdd (icx098bq, lz24bp) / fe = cmos (i2c) (mi0360, ov9630) | ||
702 | * 6: c8 / c9 / ca / cf = mode webcam?, sensor? webcam? | ||
703 | * 7: 00 | ||
704 | */ | ||
705 | PDEBUG(D_PROBE, "info: %02x %02x %02x %02x %02x %02x %02x %02x", | ||
706 | gspca_dev->usb_buf[0], | ||
707 | gspca_dev->usb_buf[1], | ||
708 | gspca_dev->usb_buf[2], | ||
709 | gspca_dev->usb_buf[3], | ||
710 | gspca_dev->usb_buf[4], | ||
711 | gspca_dev->usb_buf[5], | ||
712 | gspca_dev->usb_buf[6], | ||
713 | gspca_dev->usb_buf[7]); | ||
714 | |||
715 | /*fixme: no sensor probe - special case for icam tracer */ | ||
716 | if (gspca_dev->usb_buf[5] == 0xf6 | ||
717 | && sd->sensor == SENSOR_MI0360) { | ||
718 | sd->sensor = SENSOR_ICX098BQ; | ||
719 | gspca_dev->cam.cam_mode = &vga_mode[1]; /* only 320x240 */ | ||
720 | gspca_dev->cam.nmodes = 1; | ||
721 | } | ||
722 | |||
723 | global_init(sd, 1); | ||
724 | return gspca_dev->usb_err; | ||
725 | } | ||
726 | |||
727 | /* special function to create the quantization tables of the JPEG header */ | ||
728 | static void sd_jpeg_set_qual(u8 *jpeg_hdr, | ||
729 | int quality) | ||
730 | { | ||
731 | int i, sc1, sc2; | ||
732 | |||
733 | quality = quality_tb[quality]; /* convert to JPEG quality */ | ||
734 | /* | ||
735 | * approximative qualities for Y and U/V: | ||
736 | * quant = 0:94%/91% 1:91%/87% 2:82%/73% 3:69%/56% | ||
737 | * should have: | ||
738 | * quant = 0:94%/91% 1:91%/87.5% 2:81.5%/72% 3:69%/54.5% | ||
739 | */ | ||
740 | sc1 = 200 - quality * 2; | ||
741 | quality = quality * 7 / 5 - 40; /* UV quality */ | ||
742 | sc2 = 200 - quality * 2; | ||
743 | for (i = 0; i < 64; i++) { | ||
744 | jpeg_hdr[JPEG_QT0_OFFSET + i] = | ||
745 | (jpeg_head[JPEG_QT0_OFFSET + i] * sc1 + 50) / 100; | ||
746 | jpeg_hdr[JPEG_QT1_OFFSET + i] = | ||
747 | (jpeg_head[JPEG_QT1_OFFSET + i] * sc2 + 50) / 100; | ||
748 | } | ||
749 | } | ||
750 | |||
751 | /* send the start/stop commands to the webcam */ | ||
752 | static void send_start(struct gspca_dev *gspca_dev) | ||
753 | { | ||
754 | struct sd *sd = (struct sd *) gspca_dev; | ||
755 | const struct cap_s *cap; | ||
756 | int mode, quality; | ||
757 | |||
758 | mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; | ||
759 | cap = &capconfig[sd->sensor][mode]; | ||
760 | quality = sd->quality; | ||
761 | reg_wb(gspca_dev, (quality << 12) | ||
762 | | 0x0a00 /* 900 for Bayer */ | ||
763 | | SQ930_CTRL_CAP_START, | ||
764 | 0x0500 /* a00 for Bayer */ | ||
765 | | cap->cc_sizeid, | ||
766 | cap->cc_bytes, 32); | ||
767 | }; | ||
768 | static void send_stop(struct gspca_dev *gspca_dev) | ||
769 | { | ||
770 | reg_w(gspca_dev, SQ930_CTRL_CAP_STOP, 0); | ||
771 | }; | ||
772 | |||
773 | /* function called at start time before URB creation */ | ||
774 | static int sd_isoc_init(struct gspca_dev *gspca_dev) | ||
775 | { | ||
776 | struct sd *sd = (struct sd *) gspca_dev; | ||
777 | |||
778 | gspca_dev->cam.bulk_nurbs = 1; /* there must be one URB only */ | ||
779 | sd->do_ctrl = 0; | ||
780 | return 0; | ||
781 | } | ||
782 | |||
783 | /* start the capture */ | ||
784 | static int sd_start(struct gspca_dev *gspca_dev) | ||
785 | { | ||
786 | struct sd *sd = (struct sd *) gspca_dev; | ||
787 | int mode; | ||
788 | |||
789 | /* initialize the JPEG header */ | ||
790 | jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, | ||
791 | 0x21); /* JPEG 422 */ | ||
792 | sd_jpeg_set_qual(sd->jpeg_hdr, sd->quality); | ||
793 | |||
794 | global_init(sd, 0); | ||
795 | msleep(100); | ||
796 | |||
797 | switch (sd->sensor) { | ||
798 | case SENSOR_ICX098BQ: | ||
799 | ucbus_write(gspca_dev, icx098bq_start_0, | ||
800 | ARRAY_SIZE(icx098bq_start_0), | ||
801 | 8); | ||
802 | ucbus_write(gspca_dev, icx098bq_start_1, | ||
803 | ARRAY_SIZE(icx098bq_start_1), | ||
804 | 5); | ||
805 | ucbus_write(gspca_dev, icx098bq_start_2, | ||
806 | ARRAY_SIZE(icx098bq_start_2), | ||
807 | 6); | ||
808 | msleep(50); | ||
809 | |||
810 | /* 1st start */ | ||
811 | send_start(gspca_dev); | ||
812 | gpio_set(sd, SQ930_GPIO_EXTRA2 | SQ930_GPIO_RSTBAR, 0x00ff); | ||
813 | msleep(70); | ||
814 | reg_w(gspca_dev, SQ930_CTRL_CAP_STOP, 0x0000); | ||
815 | gpio_set(sd, 0x7f, 0x00ff); | ||
816 | |||
817 | /* 2nd start */ | ||
818 | send_start(gspca_dev); | ||
819 | gpio_set(sd, SQ930_GPIO_EXTRA2 | SQ930_GPIO_RSTBAR, 0x00ff); | ||
820 | goto out; | ||
821 | case SENSOR_LZ24BP: | ||
822 | ucbus_write(gspca_dev, lz24bp_start_0, | ||
823 | ARRAY_SIZE(lz24bp_start_0), | ||
824 | 8); | ||
825 | if (sd->type != Creative_live_motion) | ||
826 | ucbus_write(gspca_dev, lz24bp_start_1_gen, | ||
827 | ARRAY_SIZE(lz24bp_start_1_gen), | ||
828 | 5); | ||
829 | else | ||
830 | ucbus_write(gspca_dev, lz24bp_start_1_clm, | ||
831 | ARRAY_SIZE(lz24bp_start_1_clm), | ||
832 | 5); | ||
833 | ucbus_write(gspca_dev, lz24bp_start_2, | ||
834 | ARRAY_SIZE(lz24bp_start_2), | ||
835 | 6); | ||
836 | mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; | ||
837 | lz24bp_ppl(sd, mode == 2 ? 0x0564 : 0x0310); | ||
838 | msleep(10); | ||
839 | break; | ||
840 | default: | ||
841 | /* case SENSOR_MI0360: */ | ||
842 | ucbus_write(gspca_dev, mi0360_start_0, | ||
843 | ARRAY_SIZE(mi0360_start_0), | ||
844 | 8); | ||
845 | i2c_write(gspca_dev, mi0360_init_23, | ||
846 | ARRAY_SIZE(mi0360_init_23)); | ||
847 | i2c_write(gspca_dev, mi0360_init_24, | ||
848 | ARRAY_SIZE(mi0360_init_24)); | ||
849 | i2c_write(gspca_dev, mi0360_init_25, | ||
850 | ARRAY_SIZE(mi0360_init_25)); | ||
851 | ucbus_write(gspca_dev, mi0360_start_1, | ||
852 | ARRAY_SIZE(mi0360_start_1), | ||
853 | 5); | ||
854 | i2c_write(gspca_dev, mi0360_start_2, | ||
855 | ARRAY_SIZE(mi0360_start_2)); | ||
856 | i2c_write(gspca_dev, mi0360_start_3, | ||
857 | ARRAY_SIZE(mi0360_start_3)); | ||
858 | |||
859 | /* 1st start */ | ||
860 | send_start(gspca_dev); | ||
861 | msleep(60); | ||
862 | reg_w(gspca_dev, SQ930_CTRL_CAP_STOP, 0x0000); | ||
863 | |||
864 | i2c_write(gspca_dev, | ||
865 | mi0360_start_4, ARRAY_SIZE(mi0360_start_4)); | ||
866 | break; | ||
867 | } | ||
868 | |||
869 | send_start(gspca_dev); | ||
870 | out: | ||
871 | msleep(1000); | ||
872 | |||
873 | sd->eof_len = 0; /* init packet scan */ | ||
874 | |||
875 | sd->do_ctrl = 1; /* set the exposure */ | ||
876 | |||
877 | return gspca_dev->usb_err; | ||
878 | } | ||
879 | |||
880 | static void sd_stopN(struct gspca_dev *gspca_dev) | ||
881 | { | ||
882 | send_stop(gspca_dev); | ||
883 | } | ||
884 | |||
885 | /* function called when the application gets a new frame */ | ||
886 | /* It sets the exposure if required and restart the bulk transfer. */ | ||
887 | static void sd_dq_callback(struct gspca_dev *gspca_dev) | ||
888 | { | ||
889 | struct sd *sd = (struct sd *) gspca_dev; | ||
890 | int ret; | ||
891 | |||
892 | if (!sd->do_ctrl || gspca_dev->cam.bulk_nurbs != 0) | ||
893 | return; | ||
894 | sd->do_ctrl = 0; | ||
895 | |||
896 | setexposure(gspca_dev); | ||
897 | |||
898 | gspca_dev->cam.bulk_nurbs = 1; | ||
899 | ret = usb_submit_urb(gspca_dev->urb[0], GFP_ATOMIC); | ||
900 | if (ret < 0) | ||
901 | PDEBUG(D_ERR|D_PACK, "sd_dq_callback() err %d", ret); | ||
902 | |||
903 | /* wait a little time, otherwise the webcam crashes */ | ||
904 | msleep(100); | ||
905 | } | ||
906 | |||
907 | /* move a packet adding 0x00 after 0xff */ | ||
908 | static void add_packet(struct gspca_dev *gspca_dev, | ||
909 | u8 *data, | ||
910 | int len) | ||
911 | { | ||
912 | int i; | ||
913 | |||
914 | i = 0; | ||
915 | do { | ||
916 | if (data[i] == 0xff) { | ||
917 | gspca_frame_add(gspca_dev, INTER_PACKET, | ||
918 | data, i + 1); | ||
919 | len -= i; | ||
920 | data += i; | ||
921 | *data = 0x00; | ||
922 | i = 0; | ||
923 | } | ||
924 | } while (++i < len); | ||
925 | gspca_frame_add(gspca_dev, INTER_PACKET, data, len); | ||
926 | } | ||
927 | |||
928 | /* end a frame and start a new one */ | ||
929 | static void eof_sof(struct gspca_dev *gspca_dev) | ||
930 | { | ||
931 | struct sd *sd = (struct sd *) gspca_dev; | ||
932 | static const u8 ffd9[] = {0xff, 0xd9}; | ||
933 | |||
934 | /* if control set, stop bulk transfer */ | ||
935 | if (sd->do_ctrl | ||
936 | && gspca_dev->last_packet_type == INTER_PACKET) | ||
937 | gspca_dev->cam.bulk_nurbs = 0; | ||
938 | gspca_frame_add(gspca_dev, LAST_PACKET, | ||
939 | ffd9, 2); | ||
940 | gspca_frame_add(gspca_dev, FIRST_PACKET, | ||
941 | sd->jpeg_hdr, JPEG_HDR_SZ); | ||
942 | } | ||
943 | |||
944 | static void sd_pkt_scan(struct gspca_dev *gspca_dev, | ||
945 | u8 *data, /* isoc packet */ | ||
946 | int len) /* iso packet length */ | ||
947 | { | ||
948 | struct sd *sd = (struct sd *) gspca_dev; | ||
949 | u8 *p; | ||
950 | int l; | ||
951 | |||
952 | len -= 8; /* ignore last 8 bytes (00 00 55 aa 55 aa 00 00) */ | ||
953 | |||
954 | /* | ||
955 | * the end/start of frame is indicated by | ||
956 | * 0x00 * 16 - 0xab * 8 | ||
957 | * aligned on 8 bytes boundary | ||
958 | */ | ||
959 | if (sd->eof_len != 0) { /* if 'abababab' in previous pkt */ | ||
960 | if (*((u32 *) data) == 0xabababab) { | ||
961 | /*fixme: should remove previous 0000ababab*/ | ||
962 | eof_sof(gspca_dev); | ||
963 | data += 4; | ||
964 | len -= 4; | ||
965 | } | ||
966 | sd->eof_len = 0; | ||
967 | } | ||
968 | p = data; | ||
969 | l = len; | ||
970 | for (;;) { | ||
971 | if (*((u32 *) p) == 0xabababab) { | ||
972 | if (l < 8) { /* (may be 4 only) */ | ||
973 | sd->eof_len = 1; | ||
974 | break; | ||
975 | } | ||
976 | if (*((u32 *) p + 1) == 0xabababab) { | ||
977 | add_packet(gspca_dev, data, p - data - 16); | ||
978 | /* remove previous zeros */ | ||
979 | eof_sof(gspca_dev); | ||
980 | p += 8; | ||
981 | l -= 8; | ||
982 | if (l <= 0) | ||
983 | return; | ||
984 | len = l; | ||
985 | data = p; | ||
986 | continue; | ||
987 | } | ||
988 | } | ||
989 | p += 4; | ||
990 | l -= 4; | ||
991 | if (l <= 0) | ||
992 | break; | ||
993 | } | ||
994 | add_packet(gspca_dev, data, len); | ||
995 | } | ||
996 | |||
997 | static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) | ||
998 | { | ||
999 | struct sd *sd = (struct sd *) gspca_dev; | ||
1000 | |||
1001 | sd->gain = val; | ||
1002 | if (gspca_dev->streaming) | ||
1003 | sd->do_ctrl = 1; | ||
1004 | return 0; | ||
1005 | } | ||
1006 | |||
1007 | static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) | ||
1008 | { | ||
1009 | struct sd *sd = (struct sd *) gspca_dev; | ||
1010 | |||
1011 | *val = sd->gain; | ||
1012 | return 0; | ||
1013 | } | ||
1014 | static int sd_setexpo(struct gspca_dev *gspca_dev, __s32 val) | ||
1015 | { | ||
1016 | struct sd *sd = (struct sd *) gspca_dev; | ||
1017 | |||
1018 | sd->expo = val; | ||
1019 | if (gspca_dev->streaming) | ||
1020 | sd->do_ctrl = 1; | ||
1021 | return 0; | ||
1022 | } | ||
1023 | |||
1024 | static int sd_getexpo(struct gspca_dev *gspca_dev, __s32 *val) | ||
1025 | { | ||
1026 | struct sd *sd = (struct sd *) gspca_dev; | ||
1027 | |||
1028 | *val = sd->expo; | ||
1029 | return 0; | ||
1030 | } | ||
1031 | |||
1032 | static int sd_set_jcomp(struct gspca_dev *gspca_dev, | ||
1033 | struct v4l2_jpegcompression *jcomp) | ||
1034 | { | ||
1035 | struct sd *sd = (struct sd *) gspca_dev; | ||
1036 | int quality; | ||
1037 | |||
1038 | if (jcomp->quality >= (QUAL_0 + QUAL_1) / 2) | ||
1039 | quality = 0; | ||
1040 | else if (jcomp->quality >= (QUAL_1 + QUAL_2) / 2) | ||
1041 | quality = 1; | ||
1042 | else if (jcomp->quality >= (QUAL_2 + QUAL_3) / 2) | ||
1043 | quality = 2; | ||
1044 | else | ||
1045 | quality = 3; | ||
1046 | |||
1047 | if (quality != sd->quality) { | ||
1048 | sd->quality = quality; | ||
1049 | if (gspca_dev->streaming) { | ||
1050 | send_stop(gspca_dev); | ||
1051 | sd_jpeg_set_qual(sd->jpeg_hdr, sd->quality); | ||
1052 | msleep(70); | ||
1053 | send_start(gspca_dev); | ||
1054 | } | ||
1055 | } | ||
1056 | return gspca_dev->usb_err; | ||
1057 | } | ||
1058 | |||
1059 | static int sd_get_jcomp(struct gspca_dev *gspca_dev, | ||
1060 | struct v4l2_jpegcompression *jcomp) | ||
1061 | { | ||
1062 | struct sd *sd = (struct sd *) gspca_dev; | ||
1063 | |||
1064 | memset(jcomp, 0, sizeof *jcomp); | ||
1065 | jcomp->quality = quality_tb[sd->quality]; | ||
1066 | jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT | ||
1067 | | V4L2_JPEG_MARKER_DQT; | ||
1068 | return 0; | ||
1069 | } | ||
1070 | |||
1071 | /* sub-driver description */ | ||
1072 | static const struct sd_desc sd_desc = { | ||
1073 | .name = MODULE_NAME, | ||
1074 | .ctrls = sd_ctrls, | ||
1075 | .nctrls = ARRAY_SIZE(sd_ctrls), | ||
1076 | .config = sd_config, | ||
1077 | .init = sd_init, | ||
1078 | .isoc_init = sd_isoc_init, | ||
1079 | .start = sd_start, | ||
1080 | .stopN = sd_stopN, | ||
1081 | .pkt_scan = sd_pkt_scan, | ||
1082 | .dq_callback = sd_dq_callback, | ||
1083 | .get_jcomp = sd_get_jcomp, | ||
1084 | .set_jcomp = sd_set_jcomp, | ||
1085 | }; | ||
1086 | |||
1087 | /* Table of supported USB devices */ | ||
1088 | #define ST(sensor, type) \ | ||
1089 | .driver_info = (SENSOR_ ## sensor << 8) \ | ||
1090 | | (type) | ||
1091 | static const __devinitdata struct usb_device_id device_table[] = { | ||
1092 | {USB_DEVICE(0x041e, 0x4038), ST(MI0360, 0)}, | ||
1093 | {USB_DEVICE(0x041e, 0x403c), ST(LZ24BP, 0)}, | ||
1094 | {USB_DEVICE(0x041e, 0x403d), ST(LZ24BP, 0)}, | ||
1095 | {USB_DEVICE(0x041e, 0x4041), ST(LZ24BP, Creative_live_motion)}, | ||
1096 | {USB_DEVICE(0x2770, 0x930b), ST(MI0360, 0)}, /* or ICX098BQ */ | ||
1097 | {USB_DEVICE(0x2770, 0x930c), ST(MI0360, 0)}, | ||
1098 | {} | ||
1099 | }; | ||
1100 | MODULE_DEVICE_TABLE(usb, device_table); | ||
1101 | |||
1102 | |||
1103 | /* -- device connect -- */ | ||
1104 | static int sd_probe(struct usb_interface *intf, | ||
1105 | const struct usb_device_id *id) | ||
1106 | { | ||
1107 | return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), | ||
1108 | THIS_MODULE); | ||
1109 | } | ||
1110 | |||
1111 | static struct usb_driver sd_driver = { | ||
1112 | .name = MODULE_NAME, | ||
1113 | .id_table = device_table, | ||
1114 | .probe = sd_probe, | ||
1115 | .disconnect = gspca_disconnect, | ||
1116 | #ifdef CONFIG_PM | ||
1117 | .suspend = gspca_suspend, | ||
1118 | .resume = gspca_resume, | ||
1119 | #endif | ||
1120 | }; | ||
1121 | |||
1122 | /* -- module insert / remove -- */ | ||
1123 | static int __init sd_mod_init(void) | ||
1124 | { | ||
1125 | int ret; | ||
1126 | |||
1127 | ret = usb_register(&sd_driver); | ||
1128 | if (ret < 0) | ||
1129 | return ret; | ||
1130 | info("registered"); | ||
1131 | return 0; | ||
1132 | } | ||
1133 | static void __exit sd_mod_exit(void) | ||
1134 | { | ||
1135 | usb_deregister(&sd_driver); | ||
1136 | info("deregistered"); | ||
1137 | } | ||
1138 | |||
1139 | module_init(sd_mod_init); | ||
1140 | module_exit(sd_mod_exit); | ||