1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Syntek DV4000 (STK014) subdriver
4 *
5 * Copyright (C) 2008 Jean-Francois Moine (http://moinejf.free.fr)
6 */
7
8#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
9
10#define MODULE_NAME "stk014"
11
12#include "gspca.h"
13#include "jpeg.h"
14
15MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
16MODULE_DESCRIPTION("Syntek DV4000 (STK014) USB Camera Driver");
17MODULE_LICENSE("GPL");
18
19#define QUALITY 50
20
21/* specific webcam descriptor */
22struct sd {
23 struct gspca_dev gspca_dev; /* !! must be the first item */
24 u8 jpeg_hdr[JPEG_HDR_SZ];
25};
26
27static const struct v4l2_pix_format vga_mode[] = {
28 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
29 .bytesperline = 320,
30 .sizeimage = 320 * 240 * 3 / 8 + 590,
31 .colorspace = V4L2_COLORSPACE_JPEG,
32 .priv = 1},
33 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
34 .bytesperline = 640,
35 .sizeimage = 640 * 480 * 3 / 8 + 590,
36 .colorspace = V4L2_COLORSPACE_JPEG,
37 .priv = 0},
38};
39
40/* -- read a register -- */
41static u8 reg_r(struct gspca_dev *gspca_dev,
42 __u16 index)
43{
44 struct usb_device *dev = gspca_dev->dev;
45 int ret;
46
47 if (gspca_dev->usb_err < 0)
48 return 0;
49 ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
50 request: 0x00,
51 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
52 value: 0x00,
53 index,
54 data: gspca_dev->usb_buf, size: 1,
55 timeout: 500);
56 if (ret < 0) {
57 pr_err("reg_r err %d\n", ret);
58 gspca_dev->usb_err = ret;
59 return 0;
60 }
61 return gspca_dev->usb_buf[0];
62}
63
64/* -- write a register -- */
65static void reg_w(struct gspca_dev *gspca_dev,
66 __u16 index, __u16 value)
67{
68 struct usb_device *dev = gspca_dev->dev;
69 int ret;
70
71 if (gspca_dev->usb_err < 0)
72 return;
73 ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
74 request: 0x01,
75 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
76 value,
77 index,
78 NULL,
79 size: 0,
80 timeout: 500);
81 if (ret < 0) {
82 pr_err("reg_w err %d\n", ret);
83 gspca_dev->usb_err = ret;
84 }
85}
86
87/* -- get a bulk value (4 bytes) -- */
88static void rcv_val(struct gspca_dev *gspca_dev,
89 int ads)
90{
91 struct usb_device *dev = gspca_dev->dev;
92 int alen, ret;
93
94 reg_w(gspca_dev, index: 0x634, value: (ads >> 16) & 0xff);
95 reg_w(gspca_dev, index: 0x635, value: (ads >> 8) & 0xff);
96 reg_w(gspca_dev, index: 0x636, value: ads & 0xff);
97 reg_w(gspca_dev, index: 0x637, value: 0);
98 reg_w(gspca_dev, index: 0x638, value: 4); /* len & 0xff */
99 reg_w(gspca_dev, index: 0x639, value: 0); /* len >> 8 */
100 reg_w(gspca_dev, index: 0x63a, value: 0);
101 reg_w(gspca_dev, index: 0x63b, value: 0);
102 reg_w(gspca_dev, index: 0x630, value: 5);
103 if (gspca_dev->usb_err < 0)
104 return;
105 ret = usb_bulk_msg(usb_dev: dev,
106 usb_rcvbulkpipe(dev, 0x05),
107 data: gspca_dev->usb_buf,
108 len: 4, /* length */
109 actual_length: &alen,
110 timeout: 500); /* timeout in milliseconds */
111 if (ret < 0) {
112 pr_err("rcv_val err %d\n", ret);
113 gspca_dev->usb_err = ret;
114 }
115}
116
117/* -- send a bulk value -- */
118static void snd_val(struct gspca_dev *gspca_dev,
119 int ads,
120 unsigned int val)
121{
122 struct usb_device *dev = gspca_dev->dev;
123 int alen, ret;
124 __u8 seq = 0;
125
126 if (ads == 0x003f08) {
127 reg_r(gspca_dev, index: 0x0704);
128 seq = reg_r(gspca_dev, index: 0x0705);
129 reg_r(gspca_dev, index: 0x0650);
130 reg_w(gspca_dev, index: 0x654, value: seq);
131 } else {
132 reg_w(gspca_dev, index: 0x654, value: (ads >> 16) & 0xff);
133 }
134 reg_w(gspca_dev, index: 0x655, value: (ads >> 8) & 0xff);
135 reg_w(gspca_dev, index: 0x656, value: ads & 0xff);
136 reg_w(gspca_dev, index: 0x657, value: 0);
137 reg_w(gspca_dev, index: 0x658, value: 0x04); /* size */
138 reg_w(gspca_dev, index: 0x659, value: 0);
139 reg_w(gspca_dev, index: 0x65a, value: 0);
140 reg_w(gspca_dev, index: 0x65b, value: 0);
141 reg_w(gspca_dev, index: 0x650, value: 5);
142 if (gspca_dev->usb_err < 0)
143 return;
144 gspca_dev->usb_buf[0] = val >> 24;
145 gspca_dev->usb_buf[1] = val >> 16;
146 gspca_dev->usb_buf[2] = val >> 8;
147 gspca_dev->usb_buf[3] = val;
148 ret = usb_bulk_msg(usb_dev: dev,
149 usb_sndbulkpipe(dev, 6),
150 data: gspca_dev->usb_buf,
151 len: 4,
152 actual_length: &alen,
153 timeout: 500); /* timeout in milliseconds */
154 if (ret < 0) {
155 pr_err("snd_val err %d\n", ret);
156 gspca_dev->usb_err = ret;
157 } else {
158 if (ads == 0x003f08) {
159 seq += 4;
160 seq &= 0x3f;
161 reg_w(gspca_dev, index: 0x705, value: seq);
162 }
163 }
164}
165
166/* set a camera parameter */
167static void set_par(struct gspca_dev *gspca_dev,
168 int parval)
169{
170 snd_val(gspca_dev, ads: 0x003f08, val: parval);
171}
172
173static void setbrightness(struct gspca_dev *gspca_dev, s32 val)
174{
175 int parval;
176
177 parval = 0x06000000 /* whiteness */
178 + (val << 16);
179 set_par(gspca_dev, parval);
180}
181
182static void setcontrast(struct gspca_dev *gspca_dev, s32 val)
183{
184 int parval;
185
186 parval = 0x07000000 /* contrast */
187 + (val << 16);
188 set_par(gspca_dev, parval);
189}
190
191static void setcolors(struct gspca_dev *gspca_dev, s32 val)
192{
193 int parval;
194
195 parval = 0x08000000 /* saturation */
196 + (val << 16);
197 set_par(gspca_dev, parval);
198}
199
200static void setlightfreq(struct gspca_dev *gspca_dev, s32 val)
201{
202 set_par(gspca_dev, parval: val == 1
203 ? 0x33640000 /* 50 Hz */
204 : 0x33780000); /* 60 Hz */
205}
206
207/* this function is called at probe time */
208static int sd_config(struct gspca_dev *gspca_dev,
209 const struct usb_device_id *id)
210{
211 gspca_dev->cam.cam_mode = vga_mode;
212 gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode);
213 return 0;
214}
215
216/* this function is called at probe and resume time */
217static int sd_init(struct gspca_dev *gspca_dev)
218{
219 u8 ret;
220
221 /* check if the device responds */
222 usb_set_interface(dev: gspca_dev->dev, ifnum: gspca_dev->iface, alternate: 1);
223 ret = reg_r(gspca_dev, index: 0x0740);
224 if (gspca_dev->usb_err >= 0) {
225 if (ret != 0xff) {
226 pr_err("init reg: 0x%02x\n", ret);
227 gspca_dev->usb_err = -EIO;
228 }
229 }
230 return gspca_dev->usb_err;
231}
232
233/* -- start the camera -- */
234static int sd_start(struct gspca_dev *gspca_dev)
235{
236 struct sd *sd = (struct sd *) gspca_dev;
237 int ret, value;
238
239 /* create the JPEG header */
240 jpeg_define(jpeg_hdr: sd->jpeg_hdr, height: gspca_dev->pixfmt.height,
241 width: gspca_dev->pixfmt.width,
242 samplesY: 0x22); /* JPEG 411 */
243 jpeg_set_qual(jpeg_hdr: sd->jpeg_hdr, QUALITY);
244
245 /* work on alternate 1 */
246 usb_set_interface(dev: gspca_dev->dev, ifnum: gspca_dev->iface, alternate: 1);
247
248 set_par(gspca_dev, parval: 0x10000000);
249 set_par(gspca_dev, parval: 0x00000000);
250 set_par(gspca_dev, parval: 0x8002e001);
251 set_par(gspca_dev, parval: 0x14000000);
252 if (gspca_dev->pixfmt.width > 320)
253 value = 0x8002e001; /* 640x480 */
254 else
255 value = 0x4001f000; /* 320x240 */
256 set_par(gspca_dev, parval: value);
257 ret = usb_set_interface(dev: gspca_dev->dev,
258 ifnum: gspca_dev->iface,
259 alternate: gspca_dev->alt);
260 if (ret < 0) {
261 pr_err("set intf %d %d failed\n",
262 gspca_dev->iface, gspca_dev->alt);
263 gspca_dev->usb_err = ret;
264 goto out;
265 }
266 reg_r(gspca_dev, index: 0x0630);
267 rcv_val(gspca_dev, ads: 0x000020); /* << (value ff ff ff ff) */
268 reg_r(gspca_dev, index: 0x0650);
269 snd_val(gspca_dev, ads: 0x000020, val: 0xffffffff);
270 reg_w(gspca_dev, index: 0x0620, value: 0);
271 reg_w(gspca_dev, index: 0x0630, value: 0);
272 reg_w(gspca_dev, index: 0x0640, value: 0);
273 reg_w(gspca_dev, index: 0x0650, value: 0);
274 reg_w(gspca_dev, index: 0x0660, value: 0);
275 set_par(gspca_dev, parval: 0x09800000); /* Red ? */
276 set_par(gspca_dev, parval: 0x0a800000); /* Green ? */
277 set_par(gspca_dev, parval: 0x0b800000); /* Blue ? */
278 set_par(gspca_dev, parval: 0x0d030000); /* Gamma ? */
279
280 /* start the video flow */
281 set_par(gspca_dev, parval: 0x01000000);
282 set_par(gspca_dev, parval: 0x01000000);
283 if (gspca_dev->usb_err >= 0)
284 gspca_dbg(gspca_dev, D_STREAM, "camera started alt: 0x%02x\n",
285 gspca_dev->alt);
286out:
287 return gspca_dev->usb_err;
288}
289
290static void sd_stopN(struct gspca_dev *gspca_dev)
291{
292 struct usb_device *dev = gspca_dev->dev;
293
294 set_par(gspca_dev, parval: 0x02000000);
295 set_par(gspca_dev, parval: 0x02000000);
296 usb_set_interface(dev, ifnum: gspca_dev->iface, alternate: 1);
297 reg_r(gspca_dev, index: 0x0630);
298 rcv_val(gspca_dev, ads: 0x000020); /* << (value ff ff ff ff) */
299 reg_r(gspca_dev, index: 0x0650);
300 snd_val(gspca_dev, ads: 0x000020, val: 0xffffffff);
301 reg_w(gspca_dev, index: 0x0620, value: 0);
302 reg_w(gspca_dev, index: 0x0630, value: 0);
303 reg_w(gspca_dev, index: 0x0640, value: 0);
304 reg_w(gspca_dev, index: 0x0650, value: 0);
305 reg_w(gspca_dev, index: 0x0660, value: 0);
306 gspca_dbg(gspca_dev, D_STREAM, "camera stopped\n");
307}
308
309static void sd_pkt_scan(struct gspca_dev *gspca_dev,
310 u8 *data, /* isoc packet */
311 int len) /* iso packet length */
312{
313 struct sd *sd = (struct sd *) gspca_dev;
314 static unsigned char ffd9[] = {0xff, 0xd9};
315
316 /* a frame starts with:
317 * - 0xff 0xfe
318 * - 0x08 0x00 - length (little endian ?!)
319 * - 4 bytes = size of whole frame (BE - including header)
320 * - 0x00 0x0c
321 * - 0xff 0xd8
322 * - .. JPEG image with escape sequences (ff 00)
323 * (without ending - ff d9)
324 */
325 if (data[0] == 0xff && data[1] == 0xfe) {
326 gspca_frame_add(gspca_dev, packet_type: LAST_PACKET,
327 data: ffd9, len: 2);
328
329 /* put the JPEG 411 header */
330 gspca_frame_add(gspca_dev, packet_type: FIRST_PACKET,
331 data: sd->jpeg_hdr, JPEG_HDR_SZ);
332
333 /* beginning of the frame */
334#define STKHDRSZ 12
335 data += STKHDRSZ;
336 len -= STKHDRSZ;
337 }
338 gspca_frame_add(gspca_dev, packet_type: INTER_PACKET, data, len);
339}
340
341static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
342{
343 struct gspca_dev *gspca_dev =
344 container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
345
346 gspca_dev->usb_err = 0;
347
348 if (!gspca_dev->streaming)
349 return 0;
350
351 switch (ctrl->id) {
352 case V4L2_CID_BRIGHTNESS:
353 setbrightness(gspca_dev, val: ctrl->val);
354 break;
355 case V4L2_CID_CONTRAST:
356 setcontrast(gspca_dev, val: ctrl->val);
357 break;
358 case V4L2_CID_SATURATION:
359 setcolors(gspca_dev, val: ctrl->val);
360 break;
361 case V4L2_CID_POWER_LINE_FREQUENCY:
362 setlightfreq(gspca_dev, val: ctrl->val);
363 break;
364 }
365 return gspca_dev->usb_err;
366}
367
368static const struct v4l2_ctrl_ops sd_ctrl_ops = {
369 .s_ctrl = sd_s_ctrl,
370};
371
372static int sd_init_controls(struct gspca_dev *gspca_dev)
373{
374 struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
375
376 gspca_dev->vdev.ctrl_handler = hdl;
377 v4l2_ctrl_handler_init(hdl, 4);
378 v4l2_ctrl_new_std(hdl, ops: &sd_ctrl_ops,
379 V4L2_CID_BRIGHTNESS, min: 0, max: 255, step: 1, def: 127);
380 v4l2_ctrl_new_std(hdl, ops: &sd_ctrl_ops,
381 V4L2_CID_CONTRAST, min: 0, max: 255, step: 1, def: 127);
382 v4l2_ctrl_new_std(hdl, ops: &sd_ctrl_ops,
383 V4L2_CID_SATURATION, min: 0, max: 255, step: 1, def: 127);
384 v4l2_ctrl_new_std_menu(hdl, ops: &sd_ctrl_ops,
385 V4L2_CID_POWER_LINE_FREQUENCY,
386 max: V4L2_CID_POWER_LINE_FREQUENCY_60HZ, mask: 1,
387 def: V4L2_CID_POWER_LINE_FREQUENCY_50HZ);
388
389 if (hdl->error) {
390 pr_err("Could not initialize controls\n");
391 return hdl->error;
392 }
393 return 0;
394}
395
396/* sub-driver description */
397static const struct sd_desc sd_desc = {
398 .name = MODULE_NAME,
399 .config = sd_config,
400 .init = sd_init,
401 .init_controls = sd_init_controls,
402 .start = sd_start,
403 .stopN = sd_stopN,
404 .pkt_scan = sd_pkt_scan,
405};
406
407/* -- module initialisation -- */
408static const struct usb_device_id device_table[] = {
409 {USB_DEVICE(0x05e1, 0x0893)},
410 {}
411};
412MODULE_DEVICE_TABLE(usb, device_table);
413
414/* -- device connect -- */
415static int sd_probe(struct usb_interface *intf,
416 const struct usb_device_id *id)
417{
418 return gspca_dev_probe(intf, id, sd_desc: &sd_desc, dev_size: sizeof(struct sd),
419 THIS_MODULE);
420}
421
422static struct usb_driver sd_driver = {
423 .name = MODULE_NAME,
424 .id_table = device_table,
425 .probe = sd_probe,
426 .disconnect = gspca_disconnect,
427#ifdef CONFIG_PM
428 .suspend = gspca_suspend,
429 .resume = gspca_resume,
430 .reset_resume = gspca_resume,
431#endif
432};
433
434module_usb_driver(sd_driver);
435

source code of linux/drivers/media/usb/gspca/stk014.c