aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn McMaster <johndmcmaster@gmail.com>2014-11-30 21:27:53 -0500
committerMauro Carvalho Chehab <mchehab@osg.samsung.com>2015-01-29 15:13:13 -0500
commit7cc42d9f75766246faab4a1436eb02b97041fb41 (patch)
treee36785d2e8e2423aacc073309abae7961c5be1d1
parentafad4dd50acbe6457413ec6a68708433d9824d37 (diff)
[media] gspca_touptek: Add support for ToupTek UCMOS series USB cameras
Adds support for AmScope MU800 / ToupTek UCMOS08000KPB USB microscope camera. Signed-off-by: John McMaster <johndmcmaster@gmail.com> Signed-off-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
-rw-r--r--drivers/media/usb/gspca/Kconfig10
-rw-r--r--drivers/media/usb/gspca/Makefile2
-rw-r--r--drivers/media/usb/gspca/touptek.c732
3 files changed, 744 insertions, 0 deletions
diff --git a/drivers/media/usb/gspca/Kconfig b/drivers/media/usb/gspca/Kconfig
index eed10d782535..60af3b167f3b 100644
--- a/drivers/media/usb/gspca/Kconfig
+++ b/drivers/media/usb/gspca/Kconfig
@@ -395,6 +395,16 @@ config USB_GSPCA_TOPRO
395 To compile this driver as a module, choose M here: the 395 To compile this driver as a module, choose M here: the
396 module will be called gspca_topro. 396 module will be called gspca_topro.
397 397
398config USB_GSPCA_TOUPTEK
399 tristate "Touptek USB Camera Driver"
400 depends on VIDEO_V4L2 && USB_GSPCA
401 help
402 Say Y here if you want support for cameras based on the ToupTek UCMOS
403 / AmScope MU series camera.
404
405 To compile this driver as a module, choose M here: the
406 module will be called gspca_touptek.
407
398config USB_GSPCA_TV8532 408config USB_GSPCA_TV8532
399 tristate "TV8532 USB Camera Driver" 409 tristate "TV8532 USB Camera Driver"
400 depends on VIDEO_V4L2 && USB_GSPCA 410 depends on VIDEO_V4L2 && USB_GSPCA
diff --git a/drivers/media/usb/gspca/Makefile b/drivers/media/usb/gspca/Makefile
index f46975e4c82d..9f5ccecb9c8a 100644
--- a/drivers/media/usb/gspca/Makefile
+++ b/drivers/media/usb/gspca/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_USB_GSPCA_STK1135) += gspca_stk1135.o
39obj-$(CONFIG_USB_GSPCA_STV0680) += gspca_stv0680.o 39obj-$(CONFIG_USB_GSPCA_STV0680) += gspca_stv0680.o
40obj-$(CONFIG_USB_GSPCA_T613) += gspca_t613.o 40obj-$(CONFIG_USB_GSPCA_T613) += gspca_t613.o
41obj-$(CONFIG_USB_GSPCA_TOPRO) += gspca_topro.o 41obj-$(CONFIG_USB_GSPCA_TOPRO) += gspca_topro.o
42obj-$(CONFIG_USB_GSPCA_TOUPTEK) += gspca_touptek.o
42obj-$(CONFIG_USB_GSPCA_TV8532) += gspca_tv8532.o 43obj-$(CONFIG_USB_GSPCA_TV8532) += gspca_tv8532.o
43obj-$(CONFIG_USB_GSPCA_VC032X) += gspca_vc032x.o 44obj-$(CONFIG_USB_GSPCA_VC032X) += gspca_vc032x.o
44obj-$(CONFIG_USB_GSPCA_VICAM) += gspca_vicam.o 45obj-$(CONFIG_USB_GSPCA_VICAM) += gspca_vicam.o
@@ -86,6 +87,7 @@ gspca_stv0680-objs := stv0680.o
86gspca_sunplus-objs := sunplus.o 87gspca_sunplus-objs := sunplus.o
87gspca_t613-objs := t613.o 88gspca_t613-objs := t613.o
88gspca_topro-objs := topro.o 89gspca_topro-objs := topro.o
90gspca_touptek-objs := touptek.o
89gspca_tv8532-objs := tv8532.o 91gspca_tv8532-objs := tv8532.o
90gspca_vc032x-objs := vc032x.o 92gspca_vc032x-objs := vc032x.o
91gspca_vicam-objs := vicam.o 93gspca_vicam-objs := vicam.o
diff --git a/drivers/media/usb/gspca/touptek.c b/drivers/media/usb/gspca/touptek.c
new file mode 100644
index 000000000000..8b7c01e4b772
--- /dev/null
+++ b/drivers/media/usb/gspca/touptek.c
@@ -0,0 +1,732 @@
1/*
2 * ToupTek UCMOS / AmScope MU series camera driver
3 * TODO: contrast with ScopeTek / AmScope MDC cameras
4 *
5 * Copyright (C) 2012-2014 John McMaster <JohnDMcMaster@gmail.com>
6 *
7 * Special thanks to Bushing for helping with the decrypt algorithm and
8 * Sean O'Sullivan / the Rensselaer Center for Open Source
9 * Software (RCOS) for helping me learn kernel development
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
26#include "gspca.h"
27
28#define MODULE_NAME "touptek"
29
30MODULE_AUTHOR("John McMaster");
31MODULE_DESCRIPTION("ToupTek UCMOS / Amscope MU microscope camera driver");
32MODULE_LICENSE("GPL");
33
34/*
35Exposure reg is linear with exposure time
36Exposure (sec), E (reg)
370.000400, 0x0002
380.001000, 0x0005
390.005000, 0x0019
400.020000, 0x0064
410.080000, 0x0190
420.400000, 0x07D0
431.000000, 0x1388
442.000000, 0x2710
45
46Three gain stages
470x1000: master channel enable bit
480x007F: low gain bits
490x0080: medium gain bit
500x0100: high gain bit
51gain = enable * (1 + regH) * (1 + regM) * z * regL
52
53Gain implementation
54Want to do something similar to mt9v011.c's set_balance
55
56Gain does not vary with resolution (checked 640x480 vs 1600x1200)
57
58Constant derivation:
59
60Raw data:
61Gain, GTOP, B, R, GBOT
621.00, 0x105C, 0x1068, 0x10C8, 0x105C
631.20, 0x106E, 0x107E, 0x10D6, 0x106E
641.40, 0x10C0, 0x10CA, 0x10E5, 0x10C0
651.60, 0x10C9, 0x10D4, 0x10F3, 0x10C9
661.80, 0x10D2, 0x10DE, 0x11C1, 0x10D2
672.00, 0x10DC, 0x10E9, 0x11C8, 0x10DC
682.20, 0x10E5, 0x10F3, 0x11CF, 0x10E5
692.40, 0x10EE, 0x10FE, 0x11D7, 0x10EE
702.60, 0x10F7, 0x11C4, 0x11DE, 0x10F7
712.80, 0x11C0, 0x11CA, 0x11E5, 0x11C0
723.00, 0x11C5, 0x11CF, 0x11ED, 0x11C5
73
74zR = 0.0069605943152454778
75 about 3/431 = 0.0069605568445475635
76zB = 0.0095695970695970703
77 about 6/627 = 0.0095693779904306216
78zG = 0.010889328063241107
79 about 6/551 = 0.010889292196007259
80about 10 bits for constant + 7 bits for value => at least 17 bit intermediate
81with 32 bit ints should be fine for overflow etc
82Essentially gains are in range 0-0x001FF
83
84However, V4L expects a main gain channel + R and B balance
85To keep things simple for now saturate the values of balance is too high/low
86This isn't really ideal but easy way to fit the Linux model
87
88Converted using gain model turns out to be quite linear:
89Gain, GTOP, B, R, GBOT
901.00, 92, 104, 144, 92
911.20, 110, 126, 172, 110
921.40, 128, 148, 202, 128
931.60, 146, 168, 230, 146
941.80, 164, 188, 260, 164
952.00, 184, 210, 288, 184
962.20, 202, 230, 316, 202
972.40, 220, 252, 348, 220
982.60, 238, 272, 376, 238
992.80, 256, 296, 404, 256
1003.00, 276, 316, 436, 276
101
102Maximum gain is 0x7FF * 2 * 2 => 0x1FFC (8188)
103or about 13 effective bits of gain
104The highest the commercial driver goes in my setup 436
105However, because could *maybe* damage circuits
106limit the gain until have a reason to go higher
107Solution: gain clipped and warning emitted
108*/
109#define GAIN_MAX 511
110
111/* Frame sync is a short read */
112#define BULK_SIZE 0x4000
113
114/* MT9E001 reg names to give a rough approximation */
115#define REG_COARSE_INTEGRATION_TIME_ 0x3012
116#define REG_GROUPED_PARAMETER_HOLD_ 0x3022
117#define REG_MODE_SELECT 0x0100
118#define REG_OP_SYS_CLK_DIV 0x030A
119#define REG_VT_SYS_CLK_DIV 0x0302
120#define REG_PRE_PLL_CLK_DIV 0x0304
121#define REG_VT_PIX_CLK_DIV 0x0300
122#define REG_OP_PIX_CLK_DIV 0x0308
123#define REG_PLL_MULTIPLIER 0x0306
124#define REG_COARSE_INTEGRATION_TIME_ 0x3012
125#define REG_FRAME_LENGTH_LINES 0x0340
126#define REG_FRAME_LENGTH_LINES_ 0x300A
127#define REG_GREEN1_GAIN 0x3056
128#define REG_GREEN2_GAIN 0x305C
129#define REG_GROUPED_PARAMETER_HOLD 0x0104
130#define REG_LINE_LENGTH_PCK_ 0x300C
131#define REG_MODE_SELECT 0x0100
132#define REG_PLL_MULTIPLIER 0x0306
133#define REG_READ_MODE 0x3040
134#define REG_BLUE_GAIN 0x3058
135#define REG_RED_GAIN 0x305A
136#define REG_RESET_REGISTER 0x301A
137#define REG_SCALE_M 0x0404
138#define REG_SCALING_MODE 0x0400
139#define REG_SOFTWARE_RESET 0x0103
140#define REG_X_ADDR_END 0x0348
141#define REG_X_ADDR_START 0x0344
142#define REG_X_ADDR_START 0x0344
143#define REG_X_OUTPUT_SIZE 0x034C
144#define REG_Y_ADDR_END 0x034A
145#define REG_Y_ADDR_START 0x0346
146#define REG_Y_OUTPUT_SIZE 0x034E
147
148
149/* specific webcam descriptor */
150struct sd {
151 struct gspca_dev gspca_dev; /* !! must be the first item */
152 /* How many bytes this frame */
153 unsigned int this_f;
154
155 /*
156 Device has separate gains for each Bayer quadrant
157 V4L supports master gain which is referenced to G1/G2 and supplies
158 individual balance controls for R/B
159 */
160 struct v4l2_ctrl *blue;
161 struct v4l2_ctrl *red;
162};
163
164/* Used to simplify reg write error handling */
165struct cmd {
166 u16 value;
167 u16 index;
168};
169
170static const struct v4l2_pix_format vga_mode[] = {
171 {800, 600,
172 V4L2_PIX_FMT_SGRBG8,
173 V4L2_FIELD_NONE,
174 .bytesperline = 800,
175 .sizeimage = 800 * 600,
176 .colorspace = V4L2_COLORSPACE_SRGB},
177 {1600, 1200,
178 V4L2_PIX_FMT_SGRBG8,
179 V4L2_FIELD_NONE,
180 .bytesperline = 1600,
181 .sizeimage = 1600 * 1200,
182 .colorspace = V4L2_COLORSPACE_SRGB},
183 {3264, 2448,
184 V4L2_PIX_FMT_SGRBG8,
185 V4L2_FIELD_NONE,
186 .bytesperline = 3264,
187 .sizeimage = 3264 * 2448,
188 .colorspace = V4L2_COLORSPACE_SRGB},
189};
190
191/*
192As theres no known frame sync, the only way to keep synced is to try hard
193to never miss any packets
194*/
195#if MAX_NURBS < 4
196#error "Not enough URBs in the gspca table"
197#endif
198
199static int val_reply(struct gspca_dev *gspca_dev, const char *reply, int rc)
200{
201 if (rc < 0) {
202 PERR("reply has error %d", rc);
203 return -EIO;
204 }
205 if (rc != 1) {
206 PERR("Bad reply size %d", rc);
207 return -EIO;
208 }
209 if (reply[0] != 0x08) {
210 PERR("Bad reply 0x%02X", reply[0]);
211 return -EIO;
212 }
213 return 0;
214}
215
216static void reg_w(struct gspca_dev *gspca_dev, u16 value, u16 index)
217{
218 char buff[1];
219 int rc;
220
221 PDEBUG(D_USBO, "reg_w bReq=0x0B, bReqT=0xC0, wVal=0x%04X, wInd=0x%04X\n",
222 value, index);
223 rc = usb_control_msg(gspca_dev->dev, usb_rcvctrlpipe(gspca_dev->dev, 0),
224 0x0B, 0xC0, value, index, buff, 1, 500);
225 PDEBUG(D_USBO, "rc=%d, ret={0x%02X}", rc, buff[0]);
226 if (rc < 0) {
227 PERR("Failed reg_w(0x0B, 0xC0, 0x%04X, 0x%04X) w/ rc %d\n",
228 value, index, rc);
229 gspca_dev->usb_err = rc;
230 return;
231 }
232 if (val_reply(gspca_dev, buff, rc)) {
233 PERR("Bad reply to reg_w(0x0B, 0xC0, 0x%04X, 0x%04X\n",
234 value, index);
235 gspca_dev->usb_err = -EIO;
236 }
237}
238
239static void reg_w_buf(struct gspca_dev *gspca_dev,
240 const struct cmd *p, int l)
241{
242 do {
243 reg_w(gspca_dev, p->value, p->index);
244 p++;
245 } while (--l > 0);
246}
247
248static void setexposure(struct gspca_dev *gspca_dev, s32 val)
249{
250 u16 value;
251 unsigned int w = gspca_dev->pixfmt.width;
252
253 if (w == 800)
254 value = val * 5;
255 else if (w == 1600)
256 value = val * 3;
257 else if (w == 3264)
258 value = val * 3 / 2;
259 else {
260 PERR("Invalid width %u\n", w);
261 gspca_dev->usb_err = -EINVAL;
262 return;
263 }
264 PDEBUG(D_STREAM, "exposure: 0x%04X ms\n", value);
265 /* Wonder if theres a good reason for sending it twice */
266 /* probably not but leave it in because...why not */
267 reg_w(gspca_dev, value, REG_COARSE_INTEGRATION_TIME_);
268 reg_w(gspca_dev, value, REG_COARSE_INTEGRATION_TIME_);
269}
270
271static int gainify(int in)
272{
273 /*
274 TODO: check if there are any issues with corner cases
275 0x000 (0):0x07F (127): regL
276 0x080 (128) - 0x0FF (255): regM, regL
277 0x100 (256) - max: regH, regM, regL
278 */
279 if (in <= 0x7F)
280 return 0x1000 | in;
281 else if (in <= 0xFF)
282 return 0x1080 | in / 2;
283 else
284 return 0x1180 | in / 4;
285}
286
287static void setggain(struct gspca_dev *gspca_dev, u16 global_gain)
288{
289 u16 normalized;
290
291 normalized = gainify(global_gain);
292 PDEBUG(D_STREAM, "gain G1/G2 (0x%04X): 0x%04X (src 0x%04X)\n",
293 REG_GREEN1_GAIN,
294 normalized, global_gain);
295
296 reg_w(gspca_dev, normalized, REG_GREEN1_GAIN);
297 reg_w(gspca_dev, normalized, REG_GREEN2_GAIN);
298}
299
300static void setbgain(struct gspca_dev *gspca_dev,
301 u16 gain, u16 global_gain)
302{
303 u16 normalized;
304
305 normalized = global_gain +
306 ((u32)global_gain) * gain / GAIN_MAX;
307 if (normalized > GAIN_MAX) {
308 PDEBUG(D_STREAM, "Truncating blue 0x%04X w/ value 0x%04X\n",
309 GAIN_MAX, normalized);
310 normalized = GAIN_MAX;
311 }
312 normalized = gainify(normalized);
313 PDEBUG(D_STREAM, "gain B (0x%04X): 0x%04X w/ source 0x%04X\n",
314 REG_BLUE_GAIN, normalized, gain);
315
316 reg_w(gspca_dev, normalized, REG_BLUE_GAIN);
317}
318
319static void setrgain(struct gspca_dev *gspca_dev,
320 u16 gain, u16 global_gain)
321{
322 u16 normalized;
323
324 normalized = global_gain +
325 ((u32)global_gain) * gain / GAIN_MAX;
326 if (normalized > GAIN_MAX) {
327 PDEBUG(D_STREAM, "Truncating gain 0x%04X w/ value 0x%04X\n",
328 GAIN_MAX, normalized);
329 normalized = GAIN_MAX;
330 }
331 normalized = gainify(normalized);
332 PDEBUG(D_STREAM, "gain R (0x%04X): 0x%04X w / source 0x%04X\n",
333 REG_RED_GAIN, normalized, gain);
334
335 reg_w(gspca_dev, normalized, REG_RED_GAIN);
336}
337
338static void configure_wh(struct gspca_dev *gspca_dev)
339{
340 unsigned int w = gspca_dev->pixfmt.width;
341
342 PDEBUG(D_STREAM, "configure_wh\n");
343
344 if (w == 800) {
345 static const struct cmd reg_init_res[] = {
346 {0x0060, REG_X_ADDR_START},
347 {0x0CD9, REG_X_ADDR_END},
348 {0x0036, REG_Y_ADDR_START},
349 {0x098F, REG_Y_ADDR_END},
350 {0x07C7, REG_READ_MODE},
351 };
352
353 reg_w_buf(gspca_dev,
354 reg_init_res, ARRAY_SIZE(reg_init_res));
355 } else if (w == 1600) {
356 static const struct cmd reg_init_res[] = {
357 {0x009C, REG_X_ADDR_START},
358 {0x0D19, REG_X_ADDR_END},
359 {0x0068, REG_Y_ADDR_START},
360 {0x09C5, REG_Y_ADDR_END},
361 {0x06C3, REG_READ_MODE},
362 };
363
364 reg_w_buf(gspca_dev,
365 reg_init_res, ARRAY_SIZE(reg_init_res));
366 } else if (w == 3264) {
367 static const struct cmd reg_init_res[] = {
368 {0x00E8, REG_X_ADDR_START},
369 {0x0DA7, REG_X_ADDR_END},
370 {0x009E, REG_Y_ADDR_START},
371 {0x0A2D, REG_Y_ADDR_END},
372 {0x0241, REG_READ_MODE},
373 };
374
375 reg_w_buf(gspca_dev,
376 reg_init_res, ARRAY_SIZE(reg_init_res));
377 } else {
378 PERR("bad width %u\n", w);
379 gspca_dev->usb_err = -EINVAL;
380 return;
381 }
382
383 reg_w(gspca_dev, 0x0000, REG_SCALING_MODE);
384 reg_w(gspca_dev, 0x0010, REG_SCALE_M);
385 reg_w(gspca_dev, w, REG_X_OUTPUT_SIZE);
386 reg_w(gspca_dev, gspca_dev->pixfmt.height, REG_Y_OUTPUT_SIZE);
387
388 if (w == 800) {
389 reg_w(gspca_dev, 0x0384, REG_FRAME_LENGTH_LINES_);
390 reg_w(gspca_dev, 0x0960, REG_LINE_LENGTH_PCK_);
391 } else if (w == 1600) {
392 reg_w(gspca_dev, 0x0640, REG_FRAME_LENGTH_LINES_);
393 reg_w(gspca_dev, 0x0FA0, REG_LINE_LENGTH_PCK_);
394 } else if (w == 3264) {
395 reg_w(gspca_dev, 0x0B4B, REG_FRAME_LENGTH_LINES_);
396 reg_w(gspca_dev, 0x1F40, REG_LINE_LENGTH_PCK_);
397 } else {
398 PERR("bad width %u\n", w);
399 gspca_dev->usb_err = -EINVAL;
400 return;
401 }
402}
403
404/* Packets that were encrypted, no idea if the grouping is significant */
405static void configure_encrypted(struct gspca_dev *gspca_dev)
406{
407 static const struct cmd reg_init_begin[] = {
408 {0x0100, REG_SOFTWARE_RESET},
409 {0x0000, REG_MODE_SELECT},
410 {0x0100, REG_GROUPED_PARAMETER_HOLD},
411 {0x0004, REG_VT_PIX_CLK_DIV},
412 {0x0001, REG_VT_SYS_CLK_DIV},
413 {0x0008, REG_OP_PIX_CLK_DIV},
414 {0x0001, REG_OP_SYS_CLK_DIV},
415 {0x0004, REG_PRE_PLL_CLK_DIV},
416 {0x0040, REG_PLL_MULTIPLIER},
417 {0x0000, REG_GROUPED_PARAMETER_HOLD},
418 {0x0100, REG_GROUPED_PARAMETER_HOLD},
419 };
420 static const struct cmd reg_init_end[] = {
421 {0x0000, REG_GROUPED_PARAMETER_HOLD},
422 {0x0301, 0x31AE},
423 {0x0805, 0x3064},
424 {0x0071, 0x3170},
425 {0x10DE, REG_RESET_REGISTER},
426 {0x0000, REG_MODE_SELECT},
427 {0x0010, REG_PLL_MULTIPLIER},
428 {0x0100, REG_MODE_SELECT},
429 };
430
431 PDEBUG(D_STREAM, "Encrypted begin, w = %u\n", gspca_dev->pixfmt.width);
432 reg_w_buf(gspca_dev, reg_init_begin, ARRAY_SIZE(reg_init_begin));
433 configure_wh(gspca_dev);
434 reg_w_buf(gspca_dev, reg_init_end, ARRAY_SIZE(reg_init_end));
435 reg_w(gspca_dev, 0x0100, REG_GROUPED_PARAMETER_HOLD);
436 reg_w(gspca_dev, 0x0000, REG_GROUPED_PARAMETER_HOLD);
437
438 PDEBUG(D_STREAM, "Encrypted end\n");
439}
440
441static int configure(struct gspca_dev *gspca_dev)
442{
443 int rc;
444 uint8_t buff[4];
445
446 PDEBUG(D_STREAM, "configure()\n");
447
448 /*
449 First driver sets a sort of encryption key
450 A number of futur requests of this type have wValue and wIndex encrypted
451 as follows:
452 -Compute key = this wValue rotate left by 4 bits
453 (decrypt.py rotates right because we are decrypting)
454 -Later packets encrypt packets by XOR'ing with key
455 XOR encrypt/decrypt is symmetrical
456 wValue, and wIndex are encrypted
457 bRequest is not and bRequestType is always 0xC0
458 This allows resyncing if key is unknown?
459 By setting 0 we XOR with 0 and the shifting and XOR drops out
460 */
461 rc = usb_control_msg(gspca_dev->dev, usb_rcvctrlpipe(gspca_dev->dev, 0),
462 0x16, 0xC0, 0x0000, 0x0000, buff, 2, 500);
463 if (val_reply(gspca_dev, buff, rc)) {
464 PERR("failed key req");
465 return -EIO;
466 }
467
468 /*
469 Next does some sort of 2 packet challenge / response
470 evidence suggests its an Atmel I2C crypto part but nobody cares to look
471 (to make sure its not cloned hardware?)
472 Ignore: I want to work with their hardware, not clone it
473 16 bytes out challenge, requestType: 0x40
474 16 bytes in response, requestType: 0xC0
475 */
476
477 rc = usb_control_msg(gspca_dev->dev, usb_sndctrlpipe(gspca_dev->dev, 0),
478 0x01, 0x40, 0x0001, 0x000F, NULL, 0, 500);
479 if (rc < 0) {
480 PERR("failed to replay packet 176 w/ rc %d\n", rc);
481 return rc;
482 }
483
484 rc = usb_control_msg(gspca_dev->dev, usb_sndctrlpipe(gspca_dev->dev, 0),
485 0x01, 0x40, 0x0000, 0x000F, NULL, 0, 500);
486 if (rc < 0) {
487 PERR("failed to replay packet 178 w/ rc %d\n", rc);
488 return rc;
489 }
490
491 rc = usb_control_msg(gspca_dev->dev, usb_sndctrlpipe(gspca_dev->dev, 0),
492 0x01, 0x40, 0x0001, 0x000F, NULL, 0, 500);
493 if (rc < 0) {
494 PERR("failed to replay packet 180 w/ rc %d\n", rc);
495 return rc;
496 }
497
498 /*
499 Serial number? Doesn't seem to be required
500 cam1: \xE6\x0D\x00\x00, cam2: \x70\x19\x00\x00
501 rc = usb_control_msg(gspca_dev->dev, usb_rcvctrlpipe(gspca_dev->dev, 0),
502 0x20, 0xC0, 0x0000, 0x0000, buff, 4, 500);
503 */
504
505 /* Large (EEPROM?) read, skip it since no idea what to do with it */
506 gspca_dev->usb_err = 0;
507 configure_encrypted(gspca_dev);
508 if (gspca_dev->usb_err)
509 return gspca_dev->usb_err;
510
511 /* Omitted this by accident, does not work without it */
512 rc = usb_control_msg(gspca_dev->dev, usb_sndctrlpipe(gspca_dev->dev, 0),
513 0x01, 0x40, 0x0003, 0x000F, NULL, 0, 500);
514 if (rc < 0) {
515 PERR("failed to replay final packet w/ rc %d\n", rc);
516 return rc;
517 }
518
519 PDEBUG(D_STREAM, "Configure complete\n");
520 return 0;
521}
522
523static int sd_config(struct gspca_dev *gspca_dev,
524 const struct usb_device_id *id)
525{
526 gspca_dev->cam.cam_mode = vga_mode;
527 gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode);
528
529 /* Yes we want URBs and we want them now! */
530 gspca_dev->cam.no_urb_create = 0;
531 gspca_dev->cam.bulk_nurbs = 4;
532 /* Largest size the windows driver uses */
533 gspca_dev->cam.bulk_size = BULK_SIZE;
534 /* Def need to use bulk transfers */
535 gspca_dev->cam.bulk = 1;
536
537 return 0;
538}
539
540static int sd_start(struct gspca_dev *gspca_dev)
541{
542 struct sd *sd = (struct sd *) gspca_dev;
543 int rc;
544
545 sd->this_f = 0;
546
547 rc = configure(gspca_dev);
548 if (rc < 0) {
549 PERR("Failed configure");
550 return rc;
551 }
552 /* First two frames have messed up gains
553 Drop them to avoid special cases in user apps? */
554 return 0;
555}
556
557static void sd_pkt_scan(struct gspca_dev *gspca_dev,
558 u8 *data, /* isoc packet */
559 int len) /* iso packet length */
560{
561 struct sd *sd = (struct sd *) gspca_dev;
562
563 if (len != BULK_SIZE) {
564 /* can we finish a frame? */
565 if (sd->this_f + len == gspca_dev->pixfmt.sizeimage) {
566 gspca_frame_add(gspca_dev, LAST_PACKET, data, len);
567 PDEBUG(D_FRAM, "finish frame sz %u/%u w/ len %u\n",
568 sd->this_f, gspca_dev->pixfmt.sizeimage, len);
569 /* lost some data, discard the frame */
570 } else {
571 gspca_frame_add(gspca_dev, DISCARD_PACKET, NULL, 0);
572 PDEBUG(D_FRAM, "abort frame sz %u/%u w/ len %u\n",
573 sd->this_f, gspca_dev->pixfmt.sizeimage, len);
574 }
575 sd->this_f = 0;
576 } else {
577 if (sd->this_f == 0)
578 gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
579 else
580 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
581 sd->this_f += len;
582 }
583}
584
585static int sd_init(struct gspca_dev *gspca_dev)
586{
587 return 0;
588}
589
590static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
591{
592 struct gspca_dev *gspca_dev =
593 container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
594 struct sd *sd = (struct sd *) gspca_dev;
595
596 gspca_dev->usb_err = 0;
597
598 if (!gspca_dev->streaming)
599 return 0;
600
601 switch (ctrl->id) {
602 case V4L2_CID_EXPOSURE:
603 setexposure(gspca_dev, ctrl->val);
604 break;
605 case V4L2_CID_GAIN:
606 /* gspca_dev->gain automatically updated */
607 setggain(gspca_dev, gspca_dev->gain->val);
608 break;
609 case V4L2_CID_BLUE_BALANCE:
610 sd->blue->val = ctrl->val;
611 setbgain(gspca_dev, sd->blue->val, gspca_dev->gain->val);
612 break;
613 case V4L2_CID_RED_BALANCE:
614 sd->red->val = ctrl->val;
615 setrgain(gspca_dev, sd->red->val, gspca_dev->gain->val);
616 break;
617 }
618 return gspca_dev->usb_err;
619}
620
621static const struct v4l2_ctrl_ops sd_ctrl_ops = {
622 .s_ctrl = sd_s_ctrl,
623};
624
625static int sd_init_controls(struct gspca_dev *gspca_dev)
626{
627 struct sd *sd = (struct sd *) gspca_dev;
628 struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
629
630 gspca_dev->vdev.ctrl_handler = hdl;
631 v4l2_ctrl_handler_init(hdl, 4);
632
633 gspca_dev->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
634 /* Mostly limited by URB timeouts */
635 /* XXX: make dynamic based on frame rate? */
636 V4L2_CID_EXPOSURE, 0, 800, 1, 350);
637 gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
638 V4L2_CID_GAIN, 0, 511, 1, 128);
639 sd->blue = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
640 V4L2_CID_BLUE_BALANCE, 0, 1023, 1, 80);
641 sd->red = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
642 V4L2_CID_RED_BALANCE, 0, 1023, 1, 295);
643
644 if (hdl->error) {
645 PERR("Could not initialize controls\n");
646 return hdl->error;
647 }
648 return 0;
649}
650
651/* sub-driver description */
652static const struct sd_desc sd_desc = {
653 .name = MODULE_NAME,
654 .config = sd_config,
655 .init = sd_init,
656 .init_controls = sd_init_controls,
657 .start = sd_start,
658 .pkt_scan = sd_pkt_scan,
659};
660
661/* Table of supported USB devices */
662static const struct usb_device_id device_table[] = {
663 /* Commented out devices should be related */
664 /* AS: AmScope, TT: ToupTek */
665 /* { USB_DEVICE(0x0547, 0x6035) }, TT UCMOS00350KPA */
666 /* { USB_DEVICE(0x0547, 0x6130) }, TT UCMOS01300KPA */
667 /* { USB_DEVICE(0x0547, 0x6200) }, TT UCMOS02000KPA */
668 /* { USB_DEVICE(0x0547, 0x6310) }, TT UCMOS03100KPA */
669 /* { USB_DEVICE(0x0547, 0x6510) }, TT UCMOS05100KPA */
670 /* { USB_DEVICE(0x0547, 0x6800) }, TT UCMOS08000KPA */
671 /* { USB_DEVICE(0x0547, 0x6801) }, TT UCMOS08000KPB */
672 { USB_DEVICE(0x0547, 0x6801) }, /* TT UCMOS08000KPB, AS MU800 */
673 /* { USB_DEVICE(0x0547, 0x6900) }, TT UCMOS09000KPA */
674 /* { USB_DEVICE(0x0547, 0x6901) }, TT UCMOS09000KPB */
675 /* { USB_DEVICE(0x0547, 0x6010) }, TT UCMOS10000KPA */
676 /* { USB_DEVICE(0x0547, 0x6014) }, TT UCMOS14000KPA */
677 /* { USB_DEVICE(0x0547, 0x6131) }, TT UCMOS01300KMA */
678 /* { USB_DEVICE(0x0547, 0x6511) }, TT UCMOS05100KMA */
679 /* { USB_DEVICE(0x0547, 0x8080) }, TT UHCCD00800KPA */
680 /* { USB_DEVICE(0x0547, 0x8140) }, TT UHCCD01400KPA */
681 /* { USB_DEVICE(0x0547, 0x8141) }, TT EXCCD01400KPA */
682 /* { USB_DEVICE(0x0547, 0x8200) }, TT UHCCD02000KPA */
683 /* { USB_DEVICE(0x0547, 0x8201) }, TT UHCCD02000KPB */
684 /* { USB_DEVICE(0x0547, 0x8310) }, TT UHCCD03100KPA */
685 /* { USB_DEVICE(0x0547, 0x8500) }, TT UHCCD05000KPA */
686 /* { USB_DEVICE(0x0547, 0x8510) }, TT UHCCD05100KPA */
687 /* { USB_DEVICE(0x0547, 0x8600) }, TT UHCCD06000KPA */
688 /* { USB_DEVICE(0x0547, 0x8800) }, TT UHCCD08000KPA */
689 /* { USB_DEVICE(0x0547, 0x8315) }, TT UHCCD03150KPA */
690 /* { USB_DEVICE(0x0547, 0x7800) }, TT UHCCD00800KMA */
691 /* { USB_DEVICE(0x0547, 0x7140) }, TT UHCCD01400KMA */
692 /* { USB_DEVICE(0x0547, 0x7141) }, TT UHCCD01400KMB */
693 /* { USB_DEVICE(0x0547, 0x7200) }, TT UHCCD02000KMA */
694 /* { USB_DEVICE(0x0547, 0x7315) }, TT UHCCD03150KMA */
695 { }
696};
697MODULE_DEVICE_TABLE(usb, device_table);
698
699static int sd_probe(struct usb_interface *intf,
700 const struct usb_device_id *id)
701{
702 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
703 THIS_MODULE);
704}
705
706static struct usb_driver sd_driver = {
707 .name = MODULE_NAME,
708 .id_table = device_table,
709 .probe = sd_probe,
710 .disconnect = gspca_disconnect,
711#ifdef CONFIG_PM
712 .suspend = gspca_suspend,
713 .resume = gspca_resume,
714#endif
715};
716
717static int __init sd_mod_init(void)
718{
719 int ret;
720
721 ret = usb_register(&sd_driver);
722 if (ret < 0)
723 return ret;
724 return 0;
725}
726static void __exit sd_mod_exit(void)
727{
728 usb_deregister(&sd_driver);
729}
730
731module_init(sd_mod_init);
732module_exit(sd_mod_exit);