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