]>
Commit | Line | Data |
---|---|---|
618a864e JFM |
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); |