1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * spca1528 subdriver
4 *
5 * Copyright (C) 2010-2011 Jean-Francois Moine (http://moinejf.free.fr)
6 */
7
8#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
9
10#define MODULE_NAME "spca1528"
11
12#include "gspca.h"
13#include "jpeg.h"
14
15MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
16MODULE_DESCRIPTION("SPCA1528 USB Camera Driver");
17MODULE_LICENSE("GPL");
18
19/* specific webcam descriptor */
20struct sd {
21 struct gspca_dev gspca_dev; /* !! must be the first item */
22
23 u8 pkt_seq;
24
25 u8 jpeg_hdr[JPEG_HDR_SZ];
26};
27
28static const struct v4l2_pix_format vga_mode[] = {
29/* (does not work correctly)
30 {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
31 .bytesperline = 176,
32 .sizeimage = 176 * 144 * 5 / 8 + 590,
33 .colorspace = V4L2_COLORSPACE_JPEG,
34 .priv = 3},
35*/
36 {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
37 .bytesperline = 320,
38 .sizeimage = 320 * 240 * 4 / 8 + 590,
39 .colorspace = V4L2_COLORSPACE_JPEG,
40 .priv = 2},
41 {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
42 .bytesperline = 640,
43 .sizeimage = 640 * 480 * 3 / 8 + 590,
44 .colorspace = V4L2_COLORSPACE_JPEG,
45 .priv = 1},
46};
47
48/* read <len> bytes to gspca usb_buf */
49static void reg_r(struct gspca_dev *gspca_dev,
50 u8 req,
51 u16 index,
52 int len)
53{
54#if USB_BUF_SZ < 64
55#error "USB buffer too small"
56#endif
57 struct usb_device *dev = gspca_dev->dev;
58 int ret;
59
60 if (gspca_dev->usb_err < 0)
61 return;
62 ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
63 request: req,
64 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
65 value: 0x0000, /* value */
66 index,
67 data: gspca_dev->usb_buf, size: len,
68 timeout: 500);
69 gspca_dbg(gspca_dev, D_USBI, "GET %02x 0000 %04x %02x\n", req, index,
70 gspca_dev->usb_buf[0]);
71 if (ret < 0) {
72 pr_err("reg_r err %d\n", ret);
73 gspca_dev->usb_err = ret;
74 /*
75 * Make sure the buffer is zeroed to avoid uninitialized
76 * values.
77 */
78 memset(gspca_dev->usb_buf, 0, USB_BUF_SZ);
79 }
80}
81
82static void reg_w(struct gspca_dev *gspca_dev,
83 u8 req,
84 u16 value,
85 u16 index)
86{
87 struct usb_device *dev = gspca_dev->dev;
88 int ret;
89
90 if (gspca_dev->usb_err < 0)
91 return;
92 gspca_dbg(gspca_dev, D_USBO, "SET %02x %04x %04x\n", req, value, index);
93 ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
94 request: req,
95 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
96 value, index,
97 NULL, size: 0, timeout: 500);
98 if (ret < 0) {
99 pr_err("reg_w err %d\n", ret);
100 gspca_dev->usb_err = ret;
101 }
102}
103
104static void reg_wb(struct gspca_dev *gspca_dev,
105 u8 req,
106 u16 value,
107 u16 index,
108 u8 byte)
109{
110 struct usb_device *dev = gspca_dev->dev;
111 int ret;
112
113 if (gspca_dev->usb_err < 0)
114 return;
115 gspca_dbg(gspca_dev, D_USBO, "SET %02x %04x %04x %02x\n",
116 req, value, index, byte);
117 gspca_dev->usb_buf[0] = byte;
118 ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
119 request: req,
120 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
121 value, index,
122 data: gspca_dev->usb_buf, size: 1, timeout: 500);
123 if (ret < 0) {
124 pr_err("reg_w err %d\n", ret);
125 gspca_dev->usb_err = ret;
126 }
127}
128
129static void wait_status_0(struct gspca_dev *gspca_dev)
130{
131 int i, w;
132
133 i = 16;
134 w = 0;
135 do {
136 reg_r(gspca_dev, req: 0x21, index: 0x0000, len: 1);
137 if (gspca_dev->usb_buf[0] == 0)
138 return;
139 w += 15;
140 msleep(msecs: w);
141 } while (--i > 0);
142 gspca_err(gspca_dev, "wait_status_0 timeout\n");
143 gspca_dev->usb_err = -ETIME;
144}
145
146static void wait_status_1(struct gspca_dev *gspca_dev)
147{
148 int i;
149
150 i = 10;
151 do {
152 reg_r(gspca_dev, req: 0x21, index: 0x0001, len: 1);
153 msleep(msecs: 10);
154 if (gspca_dev->usb_buf[0] == 1) {
155 reg_wb(gspca_dev, req: 0x21, value: 0x0000, index: 0x0001, byte: 0x00);
156 reg_r(gspca_dev, req: 0x21, index: 0x0001, len: 1);
157 return;
158 }
159 } while (--i > 0);
160 gspca_err(gspca_dev, "wait_status_1 timeout\n");
161 gspca_dev->usb_err = -ETIME;
162}
163
164static void setbrightness(struct gspca_dev *gspca_dev, s32 val)
165{
166 reg_wb(gspca_dev, req: 0xc0, value: 0x0000, index: 0x00c0, byte: val);
167}
168
169static void setcontrast(struct gspca_dev *gspca_dev, s32 val)
170{
171 reg_wb(gspca_dev, req: 0xc1, value: 0x0000, index: 0x00c1, byte: val);
172}
173
174static void sethue(struct gspca_dev *gspca_dev, s32 val)
175{
176 reg_wb(gspca_dev, req: 0xc2, value: 0x0000, index: 0x0000, byte: val);
177}
178
179static void setcolor(struct gspca_dev *gspca_dev, s32 val)
180{
181 reg_wb(gspca_dev, req: 0xc3, value: 0x0000, index: 0x00c3, byte: val);
182}
183
184static void setsharpness(struct gspca_dev *gspca_dev, s32 val)
185{
186 reg_wb(gspca_dev, req: 0xc4, value: 0x0000, index: 0x00c4, byte: val);
187}
188
189/* this function is called at probe time */
190static int sd_config(struct gspca_dev *gspca_dev,
191 const struct usb_device_id *id)
192{
193 gspca_dev->cam.cam_mode = vga_mode;
194 gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode);
195 gspca_dev->cam.npkt = 128; /* number of packets per ISOC message */
196 /*fixme: 256 in ms-win traces*/
197
198 return 0;
199}
200
201/* this function is called at probe and resume time */
202static int sd_init(struct gspca_dev *gspca_dev)
203{
204 reg_w(gspca_dev, req: 0x00, value: 0x0001, index: 0x2067);
205 reg_w(gspca_dev, req: 0x00, value: 0x00d0, index: 0x206b);
206 reg_w(gspca_dev, req: 0x00, value: 0x0000, index: 0x206c);
207 reg_w(gspca_dev, req: 0x00, value: 0x0001, index: 0x2069);
208 msleep(msecs: 8);
209 reg_w(gspca_dev, req: 0x00, value: 0x00c0, index: 0x206b);
210 reg_w(gspca_dev, req: 0x00, value: 0x0000, index: 0x206c);
211 reg_w(gspca_dev, req: 0x00, value: 0x0001, index: 0x2069);
212
213 reg_r(gspca_dev, req: 0x20, index: 0x0000, len: 1);
214 reg_r(gspca_dev, req: 0x20, index: 0x0000, len: 5);
215 reg_r(gspca_dev, req: 0x23, index: 0x0000, len: 64);
216 gspca_dbg(gspca_dev, D_PROBE, "%s%s\n", &gspca_dev->usb_buf[0x1c],
217 &gspca_dev->usb_buf[0x30]);
218 reg_r(gspca_dev, req: 0x23, index: 0x0001, len: 64);
219 return gspca_dev->usb_err;
220}
221
222/* function called at start time before URB creation */
223static int sd_isoc_init(struct gspca_dev *gspca_dev)
224{
225 u8 mode;
226
227 reg_r(gspca_dev, req: 0x00, index: 0x2520, len: 1);
228 wait_status_0(gspca_dev);
229 reg_w(gspca_dev, req: 0xc5, value: 0x0003, index: 0x0000);
230 wait_status_1(gspca_dev);
231
232 wait_status_0(gspca_dev);
233 mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
234 reg_wb(gspca_dev, req: 0x25, value: 0x0000, index: 0x0004, byte: mode);
235 reg_r(gspca_dev, req: 0x25, index: 0x0004, len: 1);
236 reg_wb(gspca_dev, req: 0x27, value: 0x0000, index: 0x0000, byte: 0x06); /* 420 */
237 reg_r(gspca_dev, req: 0x27, index: 0x0000, len: 1);
238
239/* not useful..
240 gspca_dev->alt = 4; * use alternate setting 3 */
241
242 return gspca_dev->usb_err;
243}
244
245/* -- start the camera -- */
246static int sd_start(struct gspca_dev *gspca_dev)
247{
248 struct sd *sd = (struct sd *) gspca_dev;
249
250 /* initialize the JPEG header */
251 jpeg_define(jpeg_hdr: sd->jpeg_hdr, height: gspca_dev->pixfmt.height,
252 width: gspca_dev->pixfmt.width,
253 samplesY: 0x22); /* JPEG 411 */
254
255 /* the JPEG quality shall be 85% */
256 jpeg_set_qual(jpeg_hdr: sd->jpeg_hdr, quality: 85);
257
258 reg_r(gspca_dev, req: 0x00, index: 0x2520, len: 1);
259 msleep(msecs: 8);
260
261 /* start the capture */
262 wait_status_0(gspca_dev);
263 reg_w(gspca_dev, req: 0x31, value: 0x0000, index: 0x0004); /* start request */
264 wait_status_1(gspca_dev);
265 wait_status_0(gspca_dev);
266 msleep(msecs: 200);
267
268 sd->pkt_seq = 0;
269 return gspca_dev->usb_err;
270}
271
272static void sd_stopN(struct gspca_dev *gspca_dev)
273{
274 /* stop the capture */
275 wait_status_0(gspca_dev);
276 reg_w(gspca_dev, req: 0x31, value: 0x0000, index: 0x0000); /* stop request */
277 wait_status_1(gspca_dev);
278 wait_status_0(gspca_dev);
279}
280
281/* move a packet adding 0x00 after 0xff */
282static void add_packet(struct gspca_dev *gspca_dev,
283 u8 *data,
284 int len)
285{
286 int i;
287
288 i = 0;
289 do {
290 if (data[i] == 0xff) {
291 gspca_frame_add(gspca_dev, packet_type: INTER_PACKET,
292 data, len: i + 1);
293 len -= i;
294 data += i;
295 *data = 0x00;
296 i = 0;
297 }
298 } while (++i < len);
299 gspca_frame_add(gspca_dev, packet_type: INTER_PACKET, data, len);
300}
301
302static void sd_pkt_scan(struct gspca_dev *gspca_dev,
303 u8 *data, /* isoc packet */
304 int len) /* iso packet length */
305{
306 struct sd *sd = (struct sd *) gspca_dev;
307 static const u8 ffd9[] = {0xff, 0xd9};
308
309 /* image packets start with:
310 * 02 8n
311 * with <n> bit:
312 * 0x01: even (0) / odd (1) image
313 * 0x02: end of image when set
314 */
315 if (len < 3)
316 return; /* empty packet */
317 if (*data == 0x02) {
318 if (data[1] & 0x02) {
319 sd->pkt_seq = !(data[1] & 1);
320 add_packet(gspca_dev, data: data + 2, len: len - 2);
321 gspca_frame_add(gspca_dev, packet_type: LAST_PACKET,
322 data: ffd9, len: 2);
323 return;
324 }
325 if ((data[1] & 1) != sd->pkt_seq)
326 goto err;
327 if (gspca_dev->last_packet_type == LAST_PACKET)
328 gspca_frame_add(gspca_dev, packet_type: FIRST_PACKET,
329 data: sd->jpeg_hdr, JPEG_HDR_SZ);
330 add_packet(gspca_dev, data: data + 2, len: len - 2);
331 return;
332 }
333err:
334 gspca_dev->last_packet_type = DISCARD_PACKET;
335}
336
337static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
338{
339 struct gspca_dev *gspca_dev =
340 container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
341
342 gspca_dev->usb_err = 0;
343
344 if (!gspca_dev->streaming)
345 return 0;
346
347 switch (ctrl->id) {
348 case V4L2_CID_BRIGHTNESS:
349 setbrightness(gspca_dev, val: ctrl->val);
350 break;
351 case V4L2_CID_CONTRAST:
352 setcontrast(gspca_dev, val: ctrl->val);
353 break;
354 case V4L2_CID_HUE:
355 sethue(gspca_dev, val: ctrl->val);
356 break;
357 case V4L2_CID_SATURATION:
358 setcolor(gspca_dev, val: ctrl->val);
359 break;
360 case V4L2_CID_SHARPNESS:
361 setsharpness(gspca_dev, val: ctrl->val);
362 break;
363 }
364 return gspca_dev->usb_err;
365}
366
367static const struct v4l2_ctrl_ops sd_ctrl_ops = {
368 .s_ctrl = sd_s_ctrl,
369};
370
371static int sd_init_controls(struct gspca_dev *gspca_dev)
372{
373 struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
374
375 gspca_dev->vdev.ctrl_handler = hdl;
376 v4l2_ctrl_handler_init(hdl, 5);
377 v4l2_ctrl_new_std(hdl, ops: &sd_ctrl_ops,
378 V4L2_CID_BRIGHTNESS, min: 0, max: 255, step: 1, def: 128);
379 v4l2_ctrl_new_std(hdl, ops: &sd_ctrl_ops,
380 V4L2_CID_CONTRAST, min: 0, max: 8, step: 1, def: 1);
381 v4l2_ctrl_new_std(hdl, ops: &sd_ctrl_ops,
382 V4L2_CID_HUE, min: 0, max: 255, step: 1, def: 0);
383 v4l2_ctrl_new_std(hdl, ops: &sd_ctrl_ops,
384 V4L2_CID_SATURATION, min: 0, max: 8, step: 1, def: 1);
385 v4l2_ctrl_new_std(hdl, ops: &sd_ctrl_ops,
386 V4L2_CID_SHARPNESS, min: 0, max: 255, step: 1, def: 0);
387
388 if (hdl->error) {
389 pr_err("Could not initialize controls\n");
390 return hdl->error;
391 }
392 return 0;
393}
394
395/* sub-driver description */
396static const struct sd_desc sd_desc = {
397 .name = MODULE_NAME,
398 .config = sd_config,
399 .init = sd_init,
400 .init_controls = sd_init_controls,
401 .isoc_init = sd_isoc_init,
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(0x04fc, 0x1528)},
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 /* the video interface for isochronous transfer is 1 */
419 if (intf->cur_altsetting->desc.bInterfaceNumber != 1)
420 return -ENODEV;
421
422 return gspca_dev_probe2(intf, id, sd_desc: &sd_desc, dev_size: sizeof(struct sd),
423 THIS_MODULE);
424}
425
426static struct usb_driver sd_driver = {
427 .name = MODULE_NAME,
428 .id_table = device_table,
429 .probe = sd_probe,
430 .disconnect = gspca_disconnect,
431#ifdef CONFIG_PM
432 .suspend = gspca_suspend,
433 .resume = gspca_resume,
434 .reset_resume = gspca_resume,
435#endif
436};
437
438module_usb_driver(sd_driver);
439

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