1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Jeilinj subdriver
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Supports some Jeilin dual-mode cameras which use bulk transport and
6*4882a593Smuzhiyun * download raw JPEG data.
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * Copyright (C) 2009 Theodore Kilgore
9*4882a593Smuzhiyun *
10*4882a593Smuzhiyun * Sportscam DV15 support and control settings are
11*4882a593Smuzhiyun * Copyright (C) 2011 Patrice Chotard
12*4882a593Smuzhiyun */
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun #define MODULE_NAME "jeilinj"
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun #include <linux/slab.h>
19*4882a593Smuzhiyun #include "gspca.h"
20*4882a593Smuzhiyun #include "jpeg.h"
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun MODULE_AUTHOR("Theodore Kilgore <kilgota@auburn.edu>");
23*4882a593Smuzhiyun MODULE_DESCRIPTION("GSPCA/JEILINJ USB Camera Driver");
24*4882a593Smuzhiyun MODULE_LICENSE("GPL");
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun /* Default timeouts, in ms */
27*4882a593Smuzhiyun #define JEILINJ_CMD_TIMEOUT 500
28*4882a593Smuzhiyun #define JEILINJ_CMD_DELAY 160
29*4882a593Smuzhiyun #define JEILINJ_DATA_TIMEOUT 1000
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun /* Maximum transfer size to use. */
32*4882a593Smuzhiyun #define JEILINJ_MAX_TRANSFER 0x200
33*4882a593Smuzhiyun #define FRAME_HEADER_LEN 0x10
34*4882a593Smuzhiyun #define FRAME_START 0xFFFFFFFF
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun enum {
37*4882a593Smuzhiyun SAKAR_57379,
38*4882a593Smuzhiyun SPORTSCAM_DV15,
39*4882a593Smuzhiyun };
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun #define CAMQUALITY_MIN 0 /* highest cam quality */
42*4882a593Smuzhiyun #define CAMQUALITY_MAX 97 /* lowest cam quality */
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun /* Structure to hold all of our device specific stuff */
45*4882a593Smuzhiyun struct sd {
46*4882a593Smuzhiyun struct gspca_dev gspca_dev; /* !! must be the first item */
47*4882a593Smuzhiyun int blocks_left;
48*4882a593Smuzhiyun const struct v4l2_pix_format *cap_mode;
49*4882a593Smuzhiyun struct v4l2_ctrl *freq;
50*4882a593Smuzhiyun struct v4l2_ctrl *jpegqual;
51*4882a593Smuzhiyun /* Driver stuff */
52*4882a593Smuzhiyun u8 type;
53*4882a593Smuzhiyun u8 quality; /* image quality */
54*4882a593Smuzhiyun #define QUALITY_MIN 35
55*4882a593Smuzhiyun #define QUALITY_MAX 85
56*4882a593Smuzhiyun #define QUALITY_DEF 85
57*4882a593Smuzhiyun u8 jpeg_hdr[JPEG_HDR_SZ];
58*4882a593Smuzhiyun };
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun struct jlj_command {
61*4882a593Smuzhiyun unsigned char instruction[2];
62*4882a593Smuzhiyun unsigned char ack_wanted;
63*4882a593Smuzhiyun unsigned char delay;
64*4882a593Smuzhiyun };
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun /* AFAICT these cameras will only do 320x240. */
67*4882a593Smuzhiyun static struct v4l2_pix_format jlj_mode[] = {
68*4882a593Smuzhiyun { 320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
69*4882a593Smuzhiyun .bytesperline = 320,
70*4882a593Smuzhiyun .sizeimage = 320 * 240,
71*4882a593Smuzhiyun .colorspace = V4L2_COLORSPACE_JPEG,
72*4882a593Smuzhiyun .priv = 0},
73*4882a593Smuzhiyun { 640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
74*4882a593Smuzhiyun .bytesperline = 640,
75*4882a593Smuzhiyun .sizeimage = 640 * 480,
76*4882a593Smuzhiyun .colorspace = V4L2_COLORSPACE_JPEG,
77*4882a593Smuzhiyun .priv = 0}
78*4882a593Smuzhiyun };
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun /*
81*4882a593Smuzhiyun * cam uses endpoint 0x03 to send commands, 0x84 for read commands,
82*4882a593Smuzhiyun * and 0x82 for bulk transfer.
83*4882a593Smuzhiyun */
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun /* All commands are two bytes only */
jlj_write2(struct gspca_dev * gspca_dev,unsigned char * command)86*4882a593Smuzhiyun static void jlj_write2(struct gspca_dev *gspca_dev, unsigned char *command)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun int retval;
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun if (gspca_dev->usb_err < 0)
91*4882a593Smuzhiyun return;
92*4882a593Smuzhiyun memcpy(gspca_dev->usb_buf, command, 2);
93*4882a593Smuzhiyun retval = usb_bulk_msg(gspca_dev->dev,
94*4882a593Smuzhiyun usb_sndbulkpipe(gspca_dev->dev, 3),
95*4882a593Smuzhiyun gspca_dev->usb_buf, 2, NULL, 500);
96*4882a593Smuzhiyun if (retval < 0) {
97*4882a593Smuzhiyun pr_err("command write [%02x] error %d\n",
98*4882a593Smuzhiyun gspca_dev->usb_buf[0], retval);
99*4882a593Smuzhiyun gspca_dev->usb_err = retval;
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun /* Responses are one byte only */
jlj_read1(struct gspca_dev * gspca_dev,unsigned char * response)104*4882a593Smuzhiyun static void jlj_read1(struct gspca_dev *gspca_dev, unsigned char *response)
105*4882a593Smuzhiyun {
106*4882a593Smuzhiyun int retval;
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun if (gspca_dev->usb_err < 0)
109*4882a593Smuzhiyun return;
110*4882a593Smuzhiyun retval = usb_bulk_msg(gspca_dev->dev,
111*4882a593Smuzhiyun usb_rcvbulkpipe(gspca_dev->dev, 0x84),
112*4882a593Smuzhiyun gspca_dev->usb_buf, 1, NULL, 500);
113*4882a593Smuzhiyun *response = gspca_dev->usb_buf[0];
114*4882a593Smuzhiyun if (retval < 0) {
115*4882a593Smuzhiyun pr_err("read command [%02x] error %d\n",
116*4882a593Smuzhiyun gspca_dev->usb_buf[0], retval);
117*4882a593Smuzhiyun gspca_dev->usb_err = retval;
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun
setfreq(struct gspca_dev * gspca_dev,s32 val)121*4882a593Smuzhiyun static void setfreq(struct gspca_dev *gspca_dev, s32 val)
122*4882a593Smuzhiyun {
123*4882a593Smuzhiyun u8 freq_commands[][2] = {
124*4882a593Smuzhiyun {0x71, 0x80},
125*4882a593Smuzhiyun {0x70, 0x07}
126*4882a593Smuzhiyun };
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun freq_commands[0][1] |= val >> 1;
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun jlj_write2(gspca_dev, freq_commands[0]);
131*4882a593Smuzhiyun jlj_write2(gspca_dev, freq_commands[1]);
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun
setcamquality(struct gspca_dev * gspca_dev,s32 val)134*4882a593Smuzhiyun static void setcamquality(struct gspca_dev *gspca_dev, s32 val)
135*4882a593Smuzhiyun {
136*4882a593Smuzhiyun u8 quality_commands[][2] = {
137*4882a593Smuzhiyun {0x71, 0x1E},
138*4882a593Smuzhiyun {0x70, 0x06}
139*4882a593Smuzhiyun };
140*4882a593Smuzhiyun u8 camquality;
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun /* adapt camera quality from jpeg quality */
143*4882a593Smuzhiyun camquality = ((QUALITY_MAX - val) * CAMQUALITY_MAX)
144*4882a593Smuzhiyun / (QUALITY_MAX - QUALITY_MIN);
145*4882a593Smuzhiyun quality_commands[0][1] += camquality;
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun jlj_write2(gspca_dev, quality_commands[0]);
148*4882a593Smuzhiyun jlj_write2(gspca_dev, quality_commands[1]);
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun
setautogain(struct gspca_dev * gspca_dev,s32 val)151*4882a593Smuzhiyun static void setautogain(struct gspca_dev *gspca_dev, s32 val)
152*4882a593Smuzhiyun {
153*4882a593Smuzhiyun u8 autogain_commands[][2] = {
154*4882a593Smuzhiyun {0x94, 0x02},
155*4882a593Smuzhiyun {0xcf, 0x00}
156*4882a593Smuzhiyun };
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun autogain_commands[1][1] = val << 4;
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun jlj_write2(gspca_dev, autogain_commands[0]);
161*4882a593Smuzhiyun jlj_write2(gspca_dev, autogain_commands[1]);
162*4882a593Smuzhiyun }
163*4882a593Smuzhiyun
setred(struct gspca_dev * gspca_dev,s32 val)164*4882a593Smuzhiyun static void setred(struct gspca_dev *gspca_dev, s32 val)
165*4882a593Smuzhiyun {
166*4882a593Smuzhiyun u8 setred_commands[][2] = {
167*4882a593Smuzhiyun {0x94, 0x02},
168*4882a593Smuzhiyun {0xe6, 0x00}
169*4882a593Smuzhiyun };
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun setred_commands[1][1] = val;
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun jlj_write2(gspca_dev, setred_commands[0]);
174*4882a593Smuzhiyun jlj_write2(gspca_dev, setred_commands[1]);
175*4882a593Smuzhiyun }
176*4882a593Smuzhiyun
setgreen(struct gspca_dev * gspca_dev,s32 val)177*4882a593Smuzhiyun static void setgreen(struct gspca_dev *gspca_dev, s32 val)
178*4882a593Smuzhiyun {
179*4882a593Smuzhiyun u8 setgreen_commands[][2] = {
180*4882a593Smuzhiyun {0x94, 0x02},
181*4882a593Smuzhiyun {0xe7, 0x00}
182*4882a593Smuzhiyun };
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun setgreen_commands[1][1] = val;
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun jlj_write2(gspca_dev, setgreen_commands[0]);
187*4882a593Smuzhiyun jlj_write2(gspca_dev, setgreen_commands[1]);
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun
setblue(struct gspca_dev * gspca_dev,s32 val)190*4882a593Smuzhiyun static void setblue(struct gspca_dev *gspca_dev, s32 val)
191*4882a593Smuzhiyun {
192*4882a593Smuzhiyun u8 setblue_commands[][2] = {
193*4882a593Smuzhiyun {0x94, 0x02},
194*4882a593Smuzhiyun {0xe9, 0x00}
195*4882a593Smuzhiyun };
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun setblue_commands[1][1] = val;
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun jlj_write2(gspca_dev, setblue_commands[0]);
200*4882a593Smuzhiyun jlj_write2(gspca_dev, setblue_commands[1]);
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun
jlj_start(struct gspca_dev * gspca_dev)203*4882a593Smuzhiyun static int jlj_start(struct gspca_dev *gspca_dev)
204*4882a593Smuzhiyun {
205*4882a593Smuzhiyun int i;
206*4882a593Smuzhiyun int start_commands_size;
207*4882a593Smuzhiyun u8 response = 0xff;
208*4882a593Smuzhiyun struct sd *sd = (struct sd *) gspca_dev;
209*4882a593Smuzhiyun struct jlj_command start_commands[] = {
210*4882a593Smuzhiyun {{0x71, 0x81}, 0, 0},
211*4882a593Smuzhiyun {{0x70, 0x05}, 0, JEILINJ_CMD_DELAY},
212*4882a593Smuzhiyun {{0x95, 0x70}, 1, 0},
213*4882a593Smuzhiyun {{0x71, 0x81 - gspca_dev->curr_mode}, 0, 0},
214*4882a593Smuzhiyun {{0x70, 0x04}, 0, JEILINJ_CMD_DELAY},
215*4882a593Smuzhiyun {{0x95, 0x70}, 1, 0},
216*4882a593Smuzhiyun {{0x71, 0x00}, 0, 0}, /* start streaming ??*/
217*4882a593Smuzhiyun {{0x70, 0x08}, 0, JEILINJ_CMD_DELAY},
218*4882a593Smuzhiyun {{0x95, 0x70}, 1, 0},
219*4882a593Smuzhiyun #define SPORTSCAM_DV15_CMD_SIZE 9
220*4882a593Smuzhiyun {{0x94, 0x02}, 0, 0},
221*4882a593Smuzhiyun {{0xde, 0x24}, 0, 0},
222*4882a593Smuzhiyun {{0x94, 0x02}, 0, 0},
223*4882a593Smuzhiyun {{0xdd, 0xf0}, 0, 0},
224*4882a593Smuzhiyun {{0x94, 0x02}, 0, 0},
225*4882a593Smuzhiyun {{0xe3, 0x2c}, 0, 0},
226*4882a593Smuzhiyun {{0x94, 0x02}, 0, 0},
227*4882a593Smuzhiyun {{0xe4, 0x00}, 0, 0},
228*4882a593Smuzhiyun {{0x94, 0x02}, 0, 0},
229*4882a593Smuzhiyun {{0xe5, 0x00}, 0, 0},
230*4882a593Smuzhiyun {{0x94, 0x02}, 0, 0},
231*4882a593Smuzhiyun {{0xe6, 0x2c}, 0, 0},
232*4882a593Smuzhiyun {{0x94, 0x03}, 0, 0},
233*4882a593Smuzhiyun {{0xaa, 0x00}, 0, 0}
234*4882a593Smuzhiyun };
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun sd->blocks_left = 0;
237*4882a593Smuzhiyun /* Under Windows, USB spy shows that only the 9 first start
238*4882a593Smuzhiyun * commands are used for SPORTSCAM_DV15 webcam
239*4882a593Smuzhiyun */
240*4882a593Smuzhiyun if (sd->type == SPORTSCAM_DV15)
241*4882a593Smuzhiyun start_commands_size = SPORTSCAM_DV15_CMD_SIZE;
242*4882a593Smuzhiyun else
243*4882a593Smuzhiyun start_commands_size = ARRAY_SIZE(start_commands);
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun for (i = 0; i < start_commands_size; i++) {
246*4882a593Smuzhiyun jlj_write2(gspca_dev, start_commands[i].instruction);
247*4882a593Smuzhiyun if (start_commands[i].delay)
248*4882a593Smuzhiyun msleep(start_commands[i].delay);
249*4882a593Smuzhiyun if (start_commands[i].ack_wanted)
250*4882a593Smuzhiyun jlj_read1(gspca_dev, &response);
251*4882a593Smuzhiyun }
252*4882a593Smuzhiyun setcamquality(gspca_dev, v4l2_ctrl_g_ctrl(sd->jpegqual));
253*4882a593Smuzhiyun msleep(2);
254*4882a593Smuzhiyun setfreq(gspca_dev, v4l2_ctrl_g_ctrl(sd->freq));
255*4882a593Smuzhiyun if (gspca_dev->usb_err < 0)
256*4882a593Smuzhiyun gspca_err(gspca_dev, "Start streaming command failed\n");
257*4882a593Smuzhiyun return gspca_dev->usb_err;
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun
sd_pkt_scan(struct gspca_dev * gspca_dev,u8 * data,int len)260*4882a593Smuzhiyun static void sd_pkt_scan(struct gspca_dev *gspca_dev,
261*4882a593Smuzhiyun u8 *data, int len)
262*4882a593Smuzhiyun {
263*4882a593Smuzhiyun struct sd *sd = (struct sd *) gspca_dev;
264*4882a593Smuzhiyun int packet_type;
265*4882a593Smuzhiyun u32 header_marker;
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun gspca_dbg(gspca_dev, D_STREAM, "Got %d bytes out of %d for Block 0\n",
268*4882a593Smuzhiyun len, JEILINJ_MAX_TRANSFER);
269*4882a593Smuzhiyun if (len != JEILINJ_MAX_TRANSFER) {
270*4882a593Smuzhiyun gspca_dbg(gspca_dev, D_PACK, "bad length\n");
271*4882a593Smuzhiyun goto discard;
272*4882a593Smuzhiyun }
273*4882a593Smuzhiyun /* check if it's start of frame */
274*4882a593Smuzhiyun header_marker = ((u32 *)data)[0];
275*4882a593Smuzhiyun if (header_marker == FRAME_START) {
276*4882a593Smuzhiyun sd->blocks_left = data[0x0a] - 1;
277*4882a593Smuzhiyun gspca_dbg(gspca_dev, D_STREAM, "blocks_left = 0x%x\n",
278*4882a593Smuzhiyun sd->blocks_left);
279*4882a593Smuzhiyun /* Start a new frame, and add the JPEG header, first thing */
280*4882a593Smuzhiyun gspca_frame_add(gspca_dev, FIRST_PACKET,
281*4882a593Smuzhiyun sd->jpeg_hdr, JPEG_HDR_SZ);
282*4882a593Smuzhiyun /* Toss line 0 of data block 0, keep the rest. */
283*4882a593Smuzhiyun gspca_frame_add(gspca_dev, INTER_PACKET,
284*4882a593Smuzhiyun data + FRAME_HEADER_LEN,
285*4882a593Smuzhiyun JEILINJ_MAX_TRANSFER - FRAME_HEADER_LEN);
286*4882a593Smuzhiyun } else if (sd->blocks_left > 0) {
287*4882a593Smuzhiyun gspca_dbg(gspca_dev, D_STREAM, "%d blocks remaining for frame\n",
288*4882a593Smuzhiyun sd->blocks_left);
289*4882a593Smuzhiyun sd->blocks_left -= 1;
290*4882a593Smuzhiyun if (sd->blocks_left == 0)
291*4882a593Smuzhiyun packet_type = LAST_PACKET;
292*4882a593Smuzhiyun else
293*4882a593Smuzhiyun packet_type = INTER_PACKET;
294*4882a593Smuzhiyun gspca_frame_add(gspca_dev, packet_type,
295*4882a593Smuzhiyun data, JEILINJ_MAX_TRANSFER);
296*4882a593Smuzhiyun } else
297*4882a593Smuzhiyun goto discard;
298*4882a593Smuzhiyun return;
299*4882a593Smuzhiyun discard:
300*4882a593Smuzhiyun /* Discard data until a new frame starts. */
301*4882a593Smuzhiyun gspca_dev->last_packet_type = DISCARD_PACKET;
302*4882a593Smuzhiyun }
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun /* This function is called at probe time just before sd_init */
sd_config(struct gspca_dev * gspca_dev,const struct usb_device_id * id)305*4882a593Smuzhiyun static int sd_config(struct gspca_dev *gspca_dev,
306*4882a593Smuzhiyun const struct usb_device_id *id)
307*4882a593Smuzhiyun {
308*4882a593Smuzhiyun struct cam *cam = &gspca_dev->cam;
309*4882a593Smuzhiyun struct sd *dev = (struct sd *) gspca_dev;
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun dev->type = id->driver_info;
312*4882a593Smuzhiyun dev->quality = QUALITY_DEF;
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun cam->cam_mode = jlj_mode;
315*4882a593Smuzhiyun cam->nmodes = ARRAY_SIZE(jlj_mode);
316*4882a593Smuzhiyun cam->bulk = 1;
317*4882a593Smuzhiyun cam->bulk_nurbs = 1;
318*4882a593Smuzhiyun cam->bulk_size = JEILINJ_MAX_TRANSFER;
319*4882a593Smuzhiyun return 0;
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun
sd_stopN(struct gspca_dev * gspca_dev)322*4882a593Smuzhiyun static void sd_stopN(struct gspca_dev *gspca_dev)
323*4882a593Smuzhiyun {
324*4882a593Smuzhiyun int i;
325*4882a593Smuzhiyun u8 *buf;
326*4882a593Smuzhiyun static u8 stop_commands[][2] = {
327*4882a593Smuzhiyun {0x71, 0x00},
328*4882a593Smuzhiyun {0x70, 0x09},
329*4882a593Smuzhiyun {0x71, 0x80},
330*4882a593Smuzhiyun {0x70, 0x05}
331*4882a593Smuzhiyun };
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun for (;;) {
334*4882a593Smuzhiyun /* get the image remaining blocks */
335*4882a593Smuzhiyun usb_bulk_msg(gspca_dev->dev,
336*4882a593Smuzhiyun gspca_dev->urb[0]->pipe,
337*4882a593Smuzhiyun gspca_dev->urb[0]->transfer_buffer,
338*4882a593Smuzhiyun JEILINJ_MAX_TRANSFER, NULL,
339*4882a593Smuzhiyun JEILINJ_DATA_TIMEOUT);
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun /* search for 0xff 0xd9 (EOF for JPEG) */
342*4882a593Smuzhiyun i = 0;
343*4882a593Smuzhiyun buf = gspca_dev->urb[0]->transfer_buffer;
344*4882a593Smuzhiyun while ((i < (JEILINJ_MAX_TRANSFER - 1)) &&
345*4882a593Smuzhiyun ((buf[i] != 0xff) || (buf[i+1] != 0xd9)))
346*4882a593Smuzhiyun i++;
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun if (i != (JEILINJ_MAX_TRANSFER - 1))
349*4882a593Smuzhiyun /* last remaining block found */
350*4882a593Smuzhiyun break;
351*4882a593Smuzhiyun }
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(stop_commands); i++)
354*4882a593Smuzhiyun jlj_write2(gspca_dev, stop_commands[i]);
355*4882a593Smuzhiyun }
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun /* this function is called at probe and resume time */
sd_init(struct gspca_dev * gspca_dev)358*4882a593Smuzhiyun static int sd_init(struct gspca_dev *gspca_dev)
359*4882a593Smuzhiyun {
360*4882a593Smuzhiyun return gspca_dev->usb_err;
361*4882a593Smuzhiyun }
362*4882a593Smuzhiyun
363*4882a593Smuzhiyun /* Set up for getting frames. */
sd_start(struct gspca_dev * gspca_dev)364*4882a593Smuzhiyun static int sd_start(struct gspca_dev *gspca_dev)
365*4882a593Smuzhiyun {
366*4882a593Smuzhiyun struct sd *dev = (struct sd *) gspca_dev;
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun /* create the JPEG header */
369*4882a593Smuzhiyun jpeg_define(dev->jpeg_hdr, gspca_dev->pixfmt.height,
370*4882a593Smuzhiyun gspca_dev->pixfmt.width,
371*4882a593Smuzhiyun 0x21); /* JPEG 422 */
372*4882a593Smuzhiyun jpeg_set_qual(dev->jpeg_hdr, dev->quality);
373*4882a593Smuzhiyun gspca_dbg(gspca_dev, D_STREAM, "Start streaming at %dx%d\n",
374*4882a593Smuzhiyun gspca_dev->pixfmt.height, gspca_dev->pixfmt.width);
375*4882a593Smuzhiyun jlj_start(gspca_dev);
376*4882a593Smuzhiyun return gspca_dev->usb_err;
377*4882a593Smuzhiyun }
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun /* Table of supported USB devices */
380*4882a593Smuzhiyun static const struct usb_device_id device_table[] = {
381*4882a593Smuzhiyun {USB_DEVICE(0x0979, 0x0280), .driver_info = SAKAR_57379},
382*4882a593Smuzhiyun {USB_DEVICE(0x0979, 0x0270), .driver_info = SPORTSCAM_DV15},
383*4882a593Smuzhiyun {}
384*4882a593Smuzhiyun };
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun MODULE_DEVICE_TABLE(usb, device_table);
387*4882a593Smuzhiyun
sd_s_ctrl(struct v4l2_ctrl * ctrl)388*4882a593Smuzhiyun static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
389*4882a593Smuzhiyun {
390*4882a593Smuzhiyun struct gspca_dev *gspca_dev =
391*4882a593Smuzhiyun container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
392*4882a593Smuzhiyun struct sd *sd = (struct sd *)gspca_dev;
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun gspca_dev->usb_err = 0;
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun if (!gspca_dev->streaming)
397*4882a593Smuzhiyun return 0;
398*4882a593Smuzhiyun
399*4882a593Smuzhiyun switch (ctrl->id) {
400*4882a593Smuzhiyun case V4L2_CID_POWER_LINE_FREQUENCY:
401*4882a593Smuzhiyun setfreq(gspca_dev, ctrl->val);
402*4882a593Smuzhiyun break;
403*4882a593Smuzhiyun case V4L2_CID_RED_BALANCE:
404*4882a593Smuzhiyun setred(gspca_dev, ctrl->val);
405*4882a593Smuzhiyun break;
406*4882a593Smuzhiyun case V4L2_CID_GAIN:
407*4882a593Smuzhiyun setgreen(gspca_dev, ctrl->val);
408*4882a593Smuzhiyun break;
409*4882a593Smuzhiyun case V4L2_CID_BLUE_BALANCE:
410*4882a593Smuzhiyun setblue(gspca_dev, ctrl->val);
411*4882a593Smuzhiyun break;
412*4882a593Smuzhiyun case V4L2_CID_AUTOGAIN:
413*4882a593Smuzhiyun setautogain(gspca_dev, ctrl->val);
414*4882a593Smuzhiyun break;
415*4882a593Smuzhiyun case V4L2_CID_JPEG_COMPRESSION_QUALITY:
416*4882a593Smuzhiyun jpeg_set_qual(sd->jpeg_hdr, ctrl->val);
417*4882a593Smuzhiyun setcamquality(gspca_dev, ctrl->val);
418*4882a593Smuzhiyun break;
419*4882a593Smuzhiyun }
420*4882a593Smuzhiyun return gspca_dev->usb_err;
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun static const struct v4l2_ctrl_ops sd_ctrl_ops = {
424*4882a593Smuzhiyun .s_ctrl = sd_s_ctrl,
425*4882a593Smuzhiyun };
426*4882a593Smuzhiyun
sd_init_controls(struct gspca_dev * gspca_dev)427*4882a593Smuzhiyun static int sd_init_controls(struct gspca_dev *gspca_dev)
428*4882a593Smuzhiyun {
429*4882a593Smuzhiyun struct sd *sd = (struct sd *)gspca_dev;
430*4882a593Smuzhiyun struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
431*4882a593Smuzhiyun static const struct v4l2_ctrl_config custom_autogain = {
432*4882a593Smuzhiyun .ops = &sd_ctrl_ops,
433*4882a593Smuzhiyun .id = V4L2_CID_AUTOGAIN,
434*4882a593Smuzhiyun .type = V4L2_CTRL_TYPE_INTEGER,
435*4882a593Smuzhiyun .name = "Automatic Gain (and Exposure)",
436*4882a593Smuzhiyun .max = 3,
437*4882a593Smuzhiyun .step = 1,
438*4882a593Smuzhiyun .def = 0,
439*4882a593Smuzhiyun };
440*4882a593Smuzhiyun
441*4882a593Smuzhiyun gspca_dev->vdev.ctrl_handler = hdl;
442*4882a593Smuzhiyun v4l2_ctrl_handler_init(hdl, 6);
443*4882a593Smuzhiyun sd->freq = v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops,
444*4882a593Smuzhiyun V4L2_CID_POWER_LINE_FREQUENCY,
445*4882a593Smuzhiyun V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 1,
446*4882a593Smuzhiyun V4L2_CID_POWER_LINE_FREQUENCY_60HZ);
447*4882a593Smuzhiyun v4l2_ctrl_new_custom(hdl, &custom_autogain, NULL);
448*4882a593Smuzhiyun v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
449*4882a593Smuzhiyun V4L2_CID_RED_BALANCE, 0, 3, 1, 2);
450*4882a593Smuzhiyun v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
451*4882a593Smuzhiyun V4L2_CID_GAIN, 0, 3, 1, 2);
452*4882a593Smuzhiyun v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
453*4882a593Smuzhiyun V4L2_CID_BLUE_BALANCE, 0, 3, 1, 2);
454*4882a593Smuzhiyun sd->jpegqual = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
455*4882a593Smuzhiyun V4L2_CID_JPEG_COMPRESSION_QUALITY,
456*4882a593Smuzhiyun QUALITY_MIN, QUALITY_MAX, 1, QUALITY_DEF);
457*4882a593Smuzhiyun
458*4882a593Smuzhiyun if (hdl->error) {
459*4882a593Smuzhiyun pr_err("Could not initialize controls\n");
460*4882a593Smuzhiyun return hdl->error;
461*4882a593Smuzhiyun }
462*4882a593Smuzhiyun return 0;
463*4882a593Smuzhiyun }
464*4882a593Smuzhiyun
sd_set_jcomp(struct gspca_dev * gspca_dev,const struct v4l2_jpegcompression * jcomp)465*4882a593Smuzhiyun static int sd_set_jcomp(struct gspca_dev *gspca_dev,
466*4882a593Smuzhiyun const struct v4l2_jpegcompression *jcomp)
467*4882a593Smuzhiyun {
468*4882a593Smuzhiyun struct sd *sd = (struct sd *) gspca_dev;
469*4882a593Smuzhiyun
470*4882a593Smuzhiyun v4l2_ctrl_s_ctrl(sd->jpegqual, jcomp->quality);
471*4882a593Smuzhiyun return 0;
472*4882a593Smuzhiyun }
473*4882a593Smuzhiyun
sd_get_jcomp(struct gspca_dev * gspca_dev,struct v4l2_jpegcompression * jcomp)474*4882a593Smuzhiyun static int sd_get_jcomp(struct gspca_dev *gspca_dev,
475*4882a593Smuzhiyun struct v4l2_jpegcompression *jcomp)
476*4882a593Smuzhiyun {
477*4882a593Smuzhiyun struct sd *sd = (struct sd *) gspca_dev;
478*4882a593Smuzhiyun
479*4882a593Smuzhiyun memset(jcomp, 0, sizeof *jcomp);
480*4882a593Smuzhiyun jcomp->quality = v4l2_ctrl_g_ctrl(sd->jpegqual);
481*4882a593Smuzhiyun jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
482*4882a593Smuzhiyun | V4L2_JPEG_MARKER_DQT;
483*4882a593Smuzhiyun return 0;
484*4882a593Smuzhiyun }
485*4882a593Smuzhiyun
486*4882a593Smuzhiyun
487*4882a593Smuzhiyun /* sub-driver description */
488*4882a593Smuzhiyun static const struct sd_desc sd_desc_sakar_57379 = {
489*4882a593Smuzhiyun .name = MODULE_NAME,
490*4882a593Smuzhiyun .config = sd_config,
491*4882a593Smuzhiyun .init = sd_init,
492*4882a593Smuzhiyun .start = sd_start,
493*4882a593Smuzhiyun .stopN = sd_stopN,
494*4882a593Smuzhiyun .pkt_scan = sd_pkt_scan,
495*4882a593Smuzhiyun };
496*4882a593Smuzhiyun
497*4882a593Smuzhiyun /* sub-driver description */
498*4882a593Smuzhiyun static const struct sd_desc sd_desc_sportscam_dv15 = {
499*4882a593Smuzhiyun .name = MODULE_NAME,
500*4882a593Smuzhiyun .config = sd_config,
501*4882a593Smuzhiyun .init = sd_init,
502*4882a593Smuzhiyun .init_controls = sd_init_controls,
503*4882a593Smuzhiyun .start = sd_start,
504*4882a593Smuzhiyun .stopN = sd_stopN,
505*4882a593Smuzhiyun .pkt_scan = sd_pkt_scan,
506*4882a593Smuzhiyun .get_jcomp = sd_get_jcomp,
507*4882a593Smuzhiyun .set_jcomp = sd_set_jcomp,
508*4882a593Smuzhiyun };
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun static const struct sd_desc *sd_desc[2] = {
511*4882a593Smuzhiyun &sd_desc_sakar_57379,
512*4882a593Smuzhiyun &sd_desc_sportscam_dv15
513*4882a593Smuzhiyun };
514*4882a593Smuzhiyun
515*4882a593Smuzhiyun /* -- device connect -- */
sd_probe(struct usb_interface * intf,const struct usb_device_id * id)516*4882a593Smuzhiyun static int sd_probe(struct usb_interface *intf,
517*4882a593Smuzhiyun const struct usb_device_id *id)
518*4882a593Smuzhiyun {
519*4882a593Smuzhiyun return gspca_dev_probe(intf, id,
520*4882a593Smuzhiyun sd_desc[id->driver_info],
521*4882a593Smuzhiyun sizeof(struct sd),
522*4882a593Smuzhiyun THIS_MODULE);
523*4882a593Smuzhiyun }
524*4882a593Smuzhiyun
525*4882a593Smuzhiyun static struct usb_driver sd_driver = {
526*4882a593Smuzhiyun .name = MODULE_NAME,
527*4882a593Smuzhiyun .id_table = device_table,
528*4882a593Smuzhiyun .probe = sd_probe,
529*4882a593Smuzhiyun .disconnect = gspca_disconnect,
530*4882a593Smuzhiyun #ifdef CONFIG_PM
531*4882a593Smuzhiyun .suspend = gspca_suspend,
532*4882a593Smuzhiyun .resume = gspca_resume,
533*4882a593Smuzhiyun .reset_resume = gspca_resume,
534*4882a593Smuzhiyun #endif
535*4882a593Smuzhiyun };
536*4882a593Smuzhiyun
537*4882a593Smuzhiyun module_usb_driver(sd_driver);
538