Commit | Line | Data |
---|---|---|
30ece903 RB |
1 | /* |
2 | * Subdriver for Scopium astro-camera (DTCS033, 0547:7303) | |
3 | * | |
4 | * Copyright (C) 2014 Robert Butora (robert.butora.fi@gmail.com) | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License as published by | |
8 | * the Free Software Foundation; either version 2 of the License, or | |
9 | * any later version. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | */ | |
16 | ||
17 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
18 | #define MODULE_NAME "dtcs033" | |
19 | #include "gspca.h" | |
20 | ||
21 | MODULE_AUTHOR("Robert Butora <robert.butora.fi@gmail.com>"); | |
22 | MODULE_DESCRIPTION("Scopium DTCS033 astro-cam USB Camera Driver"); | |
23 | MODULE_LICENSE("GPL"); | |
24 | ||
ac9687a2 RB |
25 | struct dtcs033_usb_requests { |
26 | u8 bRequestType; | |
27 | u8 bRequest; | |
28 | u16 wValue; | |
29 | u16 wIndex; | |
30 | u16 wLength; | |
31 | }; | |
30ece903 RB |
32 | |
33 | /* send a usb request */ | |
34 | static void reg_rw(struct gspca_dev *gspca_dev, | |
35 | u8 bRequestType, u8 bRequest, | |
36 | u16 wValue, u16 wIndex, u16 wLength) | |
37 | { | |
38 | struct usb_device *udev = gspca_dev->dev; | |
39 | int ret; | |
40 | ||
41 | if (gspca_dev->usb_err < 0) | |
42 | return; | |
43 | ||
44 | ret = usb_control_msg(udev, | |
45 | usb_rcvctrlpipe(udev, 0), | |
46 | bRequest, | |
47 | bRequestType, | |
48 | wValue, wIndex, | |
49 | gspca_dev->usb_buf, wLength, 500); | |
50 | ||
51 | if (ret < 0) { | |
52 | gspca_dev->usb_err = ret; | |
53 | pr_err("usb_control_msg error %d\n", ret); | |
54 | } | |
55 | ||
56 | return; | |
57 | } | |
58 | /* send several usb in/out requests */ | |
59 | static int reg_reqs(struct gspca_dev *gspca_dev, | |
ac9687a2 | 60 | const struct dtcs033_usb_requests *preqs, int n_reqs) |
30ece903 RB |
61 | { |
62 | int i = 0; | |
ac9687a2 | 63 | const struct dtcs033_usb_requests *preq; |
30ece903 RB |
64 | |
65 | while ((i < n_reqs) && (gspca_dev->usb_err >= 0)) { | |
66 | ||
67 | preq = &preqs[i]; | |
68 | ||
69 | reg_rw(gspca_dev, preq->bRequestType, preq->bRequest, | |
70 | preq->wValue, preq->wIndex, preq->wLength); | |
71 | ||
72 | if (gspca_dev->usb_err < 0) { | |
73 | ||
74 | PERR("usb error request no: %d / %d\n", | |
75 | i, n_reqs); | |
76 | } else if (preq->bRequestType & USB_DIR_IN) { | |
77 | ||
78 | PDEBUG(D_STREAM, | |
79 | "USB IN (%d) returned[%d] %02X %02X %02X %s", | |
80 | i, | |
81 | preq->wLength, | |
82 | gspca_dev->usb_buf[0], | |
83 | gspca_dev->usb_buf[1], | |
84 | gspca_dev->usb_buf[2], | |
85 | preq->wLength > 3 ? "...\n" : "\n"); | |
86 | } | |
87 | ||
88 | i++; | |
89 | } | |
90 | return gspca_dev->usb_err; | |
91 | } | |
92 | ||
93 | /* -- subdriver interface implementation -- */ | |
94 | ||
95 | #define DT_COLS (640) | |
96 | static const struct v4l2_pix_format dtcs033_mode[] = { | |
97 | /* raw Bayer patterned output */ | |
98 | {DT_COLS, 480, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE, | |
99 | .bytesperline = DT_COLS, | |
100 | .sizeimage = DT_COLS*480, | |
101 | .colorspace = V4L2_COLORSPACE_SRGB, | |
102 | }, | |
103 | /* this mode will demosaic the Bayer pattern */ | |
104 | {DT_COLS, 480, V4L2_PIX_FMT_SRGGB8, V4L2_FIELD_NONE, | |
105 | .bytesperline = DT_COLS, | |
106 | .sizeimage = DT_COLS*480, | |
107 | .colorspace = V4L2_COLORSPACE_SRGB, | |
108 | } | |
109 | }; | |
110 | ||
111 | /* config called at probe time */ | |
112 | static int sd_config(struct gspca_dev *gspca_dev, | |
113 | const struct usb_device_id *id) | |
114 | { | |
115 | gspca_dev->cam.cam_mode = dtcs033_mode; | |
116 | gspca_dev->cam.nmodes = ARRAY_SIZE(dtcs033_mode); | |
117 | ||
118 | gspca_dev->cam.bulk = 1; | |
119 | gspca_dev->cam.bulk_nurbs = 1; | |
120 | gspca_dev->cam.bulk_size = DT_COLS*512; | |
121 | ||
122 | return 0; | |
123 | } | |
124 | ||
125 | /* init called at probe and resume time */ | |
126 | static int sd_init(struct gspca_dev *gspca_dev) | |
127 | { | |
128 | return 0; | |
129 | } | |
130 | ||
131 | /* start stop the camera */ | |
132 | static int dtcs033_start(struct gspca_dev *gspca_dev); | |
133 | static void dtcs033_stopN(struct gspca_dev *gspca_dev); | |
134 | ||
135 | /* intercept camera image data */ | |
136 | static void dtcs033_pkt_scan(struct gspca_dev *gspca_dev, | |
137 | u8 *data, /* packet data */ | |
138 | int len) /* packet data length */ | |
139 | { | |
140 | /* drop incomplete frames */ | |
141 | if (len != DT_COLS*512) { | |
142 | gspca_dev->last_packet_type = DISCARD_PACKET; | |
143 | /* gspca.c: discard invalidates the whole frame. */ | |
144 | return; | |
145 | } | |
146 | ||
147 | /* forward complete frames */ | |
148 | gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0); | |
149 | gspca_frame_add(gspca_dev, INTER_PACKET, | |
150 | data + 16*DT_COLS, | |
151 | len - 32*DT_COLS); /* skip first & last 16 lines */ | |
152 | gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); | |
153 | ||
154 | return; | |
155 | } | |
156 | ||
157 | /* -- controls: exposure and gain -- */ | |
158 | ||
159 | static void dtcs033_setexposure(struct gspca_dev *gspca_dev, | |
160 | s32 expo, s32 gain) | |
161 | { | |
162 | /* gain [dB] encoding */ | |
163 | u16 sGain = (u16)gain; | |
164 | u16 gainVal = 224+(sGain-14)*(768-224)/(33-14); | |
165 | u16 wIndex = 0x0100|(0x00FF&gainVal); | |
166 | u16 wValue = (0xFF00&gainVal)>>8; | |
167 | ||
168 | /* exposure time [msec] encoding */ | |
169 | u16 sXTime = (u16)expo; | |
170 | u16 xtimeVal = (524*(150-(sXTime-1)))/150; | |
171 | ||
172 | const u8 bRequestType = | |
173 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE; | |
174 | const u8 bRequest = 0x18; | |
175 | ||
176 | reg_rw(gspca_dev, | |
177 | bRequestType, bRequest, wValue, wIndex, 0); | |
178 | if (gspca_dev->usb_err < 0) | |
179 | PERR("usb error in setexposure(gain) sequence.\n"); | |
180 | ||
181 | reg_rw(gspca_dev, | |
182 | bRequestType, bRequest, (xtimeVal<<4), 0x6300, 0); | |
183 | if (gspca_dev->usb_err < 0) | |
184 | PERR("usb error in setexposure(time) sequence.\n"); | |
185 | } | |
186 | ||
187 | /* specific webcam descriptor */ | |
188 | struct sd { | |
189 | struct gspca_dev gspca_dev;/* !! must be the first item */ | |
190 | ||
191 | /* exposure & gain controls */ | |
192 | struct { | |
193 | struct v4l2_ctrl *exposure; | |
194 | struct v4l2_ctrl *gain; | |
195 | }; | |
196 | }; | |
197 | ||
198 | static int sd_s_ctrl(struct v4l2_ctrl *ctrl) | |
199 | { | |
200 | struct gspca_dev *gspca_dev = | |
201 | container_of(ctrl->handler, | |
202 | struct gspca_dev, ctrl_handler); | |
203 | struct sd *sd = (struct sd *) gspca_dev; | |
204 | ||
205 | gspca_dev->usb_err = 0; | |
206 | ||
207 | if (!gspca_dev->streaming) | |
208 | return 0; | |
209 | ||
210 | switch (ctrl->id) { | |
211 | case V4L2_CID_EXPOSURE: | |
212 | dtcs033_setexposure(gspca_dev, | |
213 | ctrl->val, sd->gain->val); | |
214 | break; | |
215 | case V4L2_CID_GAIN: | |
216 | dtcs033_setexposure(gspca_dev, | |
217 | sd->exposure->val, ctrl->val); | |
218 | break; | |
219 | } | |
220 | return gspca_dev->usb_err; | |
221 | } | |
222 | ||
223 | static const struct v4l2_ctrl_ops sd_ctrl_ops = { | |
224 | .s_ctrl = sd_s_ctrl, | |
225 | }; | |
226 | ||
227 | static int dtcs033_init_controls(struct gspca_dev *gspca_dev) | |
228 | { | |
229 | struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; | |
230 | struct sd *sd = (struct sd *) gspca_dev; | |
231 | ||
232 | gspca_dev->vdev.ctrl_handler = hdl; | |
233 | v4l2_ctrl_handler_init(hdl, 2); | |
234 | /* min max step default */ | |
235 | sd->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, | |
236 | V4L2_CID_EXPOSURE, | |
237 | 1, 150, 1, 75);/* [msec] */ | |
238 | sd->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, | |
239 | V4L2_CID_GAIN, | |
240 | 14, 33, 1, 24);/* [dB] */ | |
241 | if (hdl->error) { | |
242 | PERR("Could not initialize controls: %d\n", | |
243 | hdl->error); | |
244 | return hdl->error; | |
245 | } | |
246 | ||
247 | v4l2_ctrl_cluster(2, &sd->exposure); | |
248 | return 0; | |
249 | } | |
250 | ||
251 | /* sub-driver description */ | |
252 | static const struct sd_desc sd_desc = { | |
253 | .name = MODULE_NAME, | |
254 | .config = sd_config, | |
255 | .init = sd_init, | |
256 | .start = dtcs033_start, | |
257 | .stopN = dtcs033_stopN, | |
258 | .pkt_scan = dtcs033_pkt_scan, | |
259 | .init_controls = dtcs033_init_controls, | |
260 | }; | |
261 | ||
262 | /* -- module initialisation -- */ | |
263 | ||
264 | static const struct usb_device_id device_table[] = { | |
265 | {USB_DEVICE(0x0547, 0x7303)}, | |
266 | {} | |
267 | }; | |
268 | MODULE_DEVICE_TABLE(usb, device_table); | |
269 | ||
270 | /* device connect */ | |
271 | static int sd_probe(struct usb_interface *intf, | |
272 | const struct usb_device_id *id) | |
273 | { | |
274 | return gspca_dev_probe(intf, id, | |
275 | &sd_desc, sizeof(struct sd), | |
276 | THIS_MODULE); | |
277 | } | |
278 | ||
279 | static struct usb_driver sd_driver = { | |
280 | .name = MODULE_NAME, | |
281 | .id_table = device_table, | |
282 | .probe = sd_probe, | |
283 | .disconnect = gspca_disconnect, | |
284 | #ifdef CONFIG_PM | |
285 | .suspend = gspca_suspend, | |
286 | .resume = gspca_resume, | |
287 | .reset_resume = gspca_resume, | |
288 | #endif | |
289 | }; | |
290 | module_usb_driver(sd_driver); | |
291 | ||
292 | ||
293 | /* --------------------------------------------------------- | |
294 | USB requests to start/stop the camera [USB 2.0 spec Ch.9]. | |
295 | ||
296 | bRequestType : | |
297 | 0x40 = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | |
298 | 0xC0 = USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | |
299 | */ | |
ac9687a2 | 300 | static const struct dtcs033_usb_requests dtcs033_start_reqs[] = { |
30ece903 RB |
301 | /* -- bRequest,wValue,wIndex,wLength */ |
302 | { 0x40, 0x01, 0x0001, 0x000F, 0x0000 }, | |
303 | { 0x40, 0x01, 0x0000, 0x000F, 0x0000 }, | |
304 | { 0x40, 0x01, 0x0001, 0x000F, 0x0000 }, | |
305 | { 0x40, 0x18, 0x0000, 0x7F00, 0x0000 }, | |
306 | { 0x40, 0x18, 0x0000, 0x1001, 0x0000 }, | |
307 | { 0x40, 0x18, 0x0000, 0x0004, 0x0000 }, | |
308 | { 0x40, 0x18, 0x0000, 0x7F01, 0x0000 }, | |
309 | { 0x40, 0x18, 0x30E0, 0x0009, 0x0000 }, | |
310 | { 0x40, 0x18, 0x0500, 0x012C, 0x0000 }, | |
311 | { 0x40, 0x18, 0x0380, 0x0200, 0x0000 }, | |
312 | { 0x40, 0x18, 0x0000, 0x035C, 0x0000 }, | |
313 | { 0x40, 0x18, 0x05C0, 0x0438, 0x0000 }, | |
314 | { 0x40, 0x18, 0x0440, 0x0500, 0x0000 }, | |
315 | { 0x40, 0x18, 0x0000, 0x0668, 0x0000 }, | |
316 | { 0x40, 0x18, 0x0000, 0x0700, 0x0000 }, | |
317 | { 0x40, 0x18, 0x0000, 0x0800, 0x0000 }, | |
318 | { 0x40, 0x18, 0x0000, 0x0900, 0x0000 }, | |
319 | { 0x40, 0x18, 0x0000, 0x0A00, 0x0000 }, | |
320 | { 0x40, 0x18, 0x0000, 0x0B00, 0x0000 }, | |
321 | { 0x40, 0x18, 0x30E0, 0x6009, 0x0000 }, | |
322 | { 0x40, 0x18, 0x0500, 0x612C, 0x0000 }, | |
323 | { 0x40, 0x18, 0x2090, 0x6274, 0x0000 }, | |
324 | { 0x40, 0x18, 0x05C0, 0x6338, 0x0000 }, | |
325 | { 0x40, 0x18, 0x0000, 0x6400, 0x0000 }, | |
326 | { 0x40, 0x18, 0x05C0, 0x6538, 0x0000 }, | |
327 | { 0x40, 0x18, 0x0000, 0x6600, 0x0000 }, | |
328 | { 0x40, 0x18, 0x0680, 0x6744, 0x0000 }, | |
329 | { 0x40, 0x18, 0x0000, 0x6800, 0x0000 }, | |
330 | { 0x40, 0x18, 0x0000, 0x6900, 0x0000 }, | |
331 | { 0x40, 0x18, 0x0000, 0x6A00, 0x0000 }, | |
332 | { 0x40, 0x18, 0x0000, 0x6B00, 0x0000 }, | |
333 | { 0x40, 0x18, 0x0000, 0x6C00, 0x0000 }, | |
334 | { 0x40, 0x18, 0x0000, 0x6D00, 0x0000 }, | |
335 | { 0x40, 0x18, 0x0000, 0x6E00, 0x0000 }, | |
336 | { 0x40, 0x18, 0x0000, 0x808C, 0x0000 }, | |
337 | { 0x40, 0x18, 0x0010, 0x8101, 0x0000 }, | |
338 | { 0x40, 0x18, 0x30E0, 0x8200, 0x0000 }, | |
339 | { 0x40, 0x18, 0x0810, 0x832C, 0x0000 }, | |
340 | { 0x40, 0x18, 0x0680, 0x842B, 0x0000 }, | |
341 | { 0x40, 0x18, 0x0000, 0x8500, 0x0000 }, | |
342 | { 0x40, 0x18, 0x0000, 0x8600, 0x0000 }, | |
343 | { 0x40, 0x18, 0x0280, 0x8715, 0x0000 }, | |
344 | { 0x40, 0x18, 0x0000, 0x880C, 0x0000 }, | |
345 | { 0x40, 0x18, 0x0010, 0x8901, 0x0000 }, | |
346 | { 0x40, 0x18, 0x30E0, 0x8A00, 0x0000 }, | |
347 | { 0x40, 0x18, 0x0810, 0x8B2C, 0x0000 }, | |
348 | { 0x40, 0x18, 0x0680, 0x8C2B, 0x0000 }, | |
349 | { 0x40, 0x18, 0x0000, 0x8D00, 0x0000 }, | |
350 | { 0x40, 0x18, 0x0000, 0x8E00, 0x0000 }, | |
351 | { 0x40, 0x18, 0x0280, 0x8F15, 0x0000 }, | |
352 | { 0x40, 0x18, 0x0010, 0xD040, 0x0000 }, | |
353 | { 0x40, 0x18, 0x0000, 0xD100, 0x0000 }, | |
354 | { 0x40, 0x18, 0x00B0, 0xD20A, 0x0000 }, | |
355 | { 0x40, 0x18, 0x0000, 0xD300, 0x0000 }, | |
356 | { 0x40, 0x18, 0x30E2, 0xD40D, 0x0000 }, | |
357 | { 0x40, 0x18, 0x0001, 0xD5C0, 0x0000 }, | |
358 | { 0x40, 0x18, 0x00A0, 0xD60A, 0x0000 }, | |
359 | { 0x40, 0x18, 0x0000, 0xD700, 0x0000 }, | |
360 | { 0x40, 0x18, 0x0000, 0x7F00, 0x0000 }, | |
361 | { 0x40, 0x18, 0x0000, 0x1501, 0x0000 }, | |
362 | { 0x40, 0x18, 0x0001, 0x01FF, 0x0000 }, | |
363 | { 0x40, 0x18, 0x0000, 0x0200, 0x0000 }, | |
364 | { 0x40, 0x18, 0x0000, 0x0304, 0x0000 }, | |
365 | { 0x40, 0x18, 0x0000, 0x1101, 0x0000 }, | |
366 | { 0x40, 0x18, 0x0000, 0x1201, 0x0000 }, | |
367 | { 0x40, 0x18, 0x0000, 0x1300, 0x0000 }, | |
368 | { 0x40, 0x18, 0x0000, 0x1400, 0x0000 }, | |
369 | { 0x40, 0x18, 0x0000, 0x1601, 0x0000 }, | |
370 | { 0x40, 0x18, 0x0000, 0x1800, 0x0000 }, | |
371 | { 0x40, 0x18, 0x0000, 0x1900, 0x0000 }, | |
372 | { 0x40, 0x18, 0x0000, 0x1A00, 0x0000 }, | |
373 | { 0x40, 0x18, 0x2000, 0x1B00, 0x0000 }, | |
374 | { 0x40, 0x18, 0x0000, 0x1C00, 0x0000 }, | |
375 | { 0x40, 0x18, 0x0000, 0x2100, 0x0000 }, | |
376 | { 0x40, 0x18, 0x00C0, 0x228E, 0x0000 }, | |
377 | { 0x40, 0x18, 0x0000, 0x3001, 0x0000 }, | |
378 | { 0x40, 0x18, 0x0010, 0x3101, 0x0000 }, | |
379 | { 0x40, 0x18, 0x0008, 0x3301, 0x0000 }, | |
380 | { 0x40, 0x18, 0x0000, 0x3400, 0x0000 }, | |
381 | { 0x40, 0x18, 0x0012, 0x3549, 0x0000 }, | |
382 | { 0x40, 0x18, 0x0000, 0x3620, 0x0000 }, | |
383 | { 0x40, 0x18, 0x0001, 0x3700, 0x0000 }, | |
384 | { 0x40, 0x18, 0x0000, 0x4000, 0x0000 }, | |
385 | { 0x40, 0x18, 0xFFFF, 0x41FF, 0x0000 }, | |
386 | { 0x40, 0x18, 0xFFFF, 0x42FF, 0x0000 }, | |
387 | { 0x40, 0x18, 0x0000, 0x500F, 0x0000 }, | |
388 | { 0x40, 0x18, 0x2272, 0x5108, 0x0000 }, | |
389 | { 0x40, 0x18, 0x2272, 0x5208, 0x0000 }, | |
390 | { 0x40, 0x18, 0xFFFF, 0x53FF, 0x0000 }, | |
391 | { 0x40, 0x18, 0xFFFF, 0x54FF, 0x0000 }, | |
392 | { 0x40, 0x18, 0x0000, 0x6000, 0x0000 }, | |
393 | { 0x40, 0x18, 0x0000, 0x6102, 0x0000 }, | |
394 | { 0x40, 0x18, 0x0010, 0x6214, 0x0000 }, | |
395 | { 0x40, 0x18, 0x0C80, 0x6300, 0x0000 }, | |
396 | { 0x40, 0x18, 0x0000, 0x6401, 0x0000 }, | |
397 | { 0x40, 0x18, 0x0680, 0x6551, 0x0000 }, | |
398 | { 0x40, 0x18, 0xFFFF, 0x66FF, 0x0000 }, | |
399 | { 0x40, 0x18, 0x0000, 0x6702, 0x0000 }, | |
400 | { 0x40, 0x18, 0x0010, 0x6800, 0x0000 }, | |
401 | { 0x40, 0x18, 0x0000, 0x6900, 0x0000 }, | |
402 | { 0x40, 0x18, 0x0000, 0x6A00, 0x0000 }, | |
403 | { 0x40, 0x18, 0x0000, 0x6B00, 0x0000 }, | |
404 | { 0x40, 0x18, 0x0000, 0x6C00, 0x0000 }, | |
405 | { 0x40, 0x18, 0x0000, 0x6D01, 0x0000 }, | |
406 | { 0x40, 0x18, 0x0000, 0x6E00, 0x0000 }, | |
407 | { 0x40, 0x18, 0x0000, 0x6F00, 0x0000 }, | |
408 | { 0x40, 0x18, 0x0000, 0x7000, 0x0000 }, | |
409 | { 0x40, 0x18, 0x0001, 0x7118, 0x0000 }, | |
410 | { 0x40, 0x18, 0x0000, 0x2001, 0x0000 }, | |
411 | { 0x40, 0x18, 0x0000, 0x1101, 0x0000 }, | |
412 | { 0x40, 0x18, 0x0000, 0x1301, 0x0000 }, | |
413 | { 0x40, 0x18, 0x0000, 0x1300, 0x0000 }, | |
414 | { 0x40, 0x18, 0x0000, 0x1501, 0x0000 }, | |
415 | { 0xC0, 0x11, 0x0000, 0x24C0, 0x0003 }, | |
416 | { 0x40, 0x18, 0x0000, 0x3000, 0x0000 }, | |
417 | { 0x40, 0x18, 0x0000, 0x3620, 0x0000 }, | |
418 | { 0x40, 0x18, 0x0000, 0x1501, 0x0000 }, | |
419 | { 0x40, 0x18, 0x0010, 0x6300, 0x0000 }, | |
420 | { 0x40, 0x18, 0x0002, 0x01F0, 0x0000 }, | |
421 | { 0x40, 0x01, 0x0003, 0x000F, 0x0000 } | |
422 | }; | |
423 | ||
ac9687a2 | 424 | static const struct dtcs033_usb_requests dtcs033_stop_reqs[] = { |
30ece903 RB |
425 | /* -- bRequest,wValue,wIndex,wLength */ |
426 | { 0x40, 0x01, 0x0001, 0x000F, 0x0000 }, | |
427 | { 0x40, 0x01, 0x0000, 0x000F, 0x0000 }, | |
428 | { 0x40, 0x18, 0x0000, 0x0003, 0x0000 } | |
429 | }; | |
430 | static int dtcs033_start(struct gspca_dev *gspca_dev) | |
431 | { | |
432 | return reg_reqs(gspca_dev, dtcs033_start_reqs, | |
433 | ARRAY_SIZE(dtcs033_start_reqs)); | |
434 | } | |
435 | ||
436 | static void dtcs033_stopN(struct gspca_dev *gspca_dev) | |
437 | { | |
438 | reg_reqs(gspca_dev, dtcs033_stop_reqs, | |
439 | ARRAY_SIZE(dtcs033_stop_reqs)); | |
440 | return; | |
441 | } |