0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0015
0016 #define MODULE_NAME "jeilinj"
0017
0018 #include <linux/slab.h>
0019 #include "gspca.h"
0020 #include "jpeg.h"
0021
0022 MODULE_AUTHOR("Theodore Kilgore <kilgota@auburn.edu>");
0023 MODULE_DESCRIPTION("GSPCA/JEILINJ USB Camera Driver");
0024 MODULE_LICENSE("GPL");
0025
0026
0027 #define JEILINJ_CMD_TIMEOUT 500
0028 #define JEILINJ_CMD_DELAY 160
0029 #define JEILINJ_DATA_TIMEOUT 1000
0030
0031
0032 #define JEILINJ_MAX_TRANSFER 0x200
0033 #define FRAME_HEADER_LEN 0x10
0034 #define FRAME_START 0xFFFFFFFF
0035
0036 enum {
0037 SAKAR_57379,
0038 SPORTSCAM_DV15,
0039 };
0040
0041 #define CAMQUALITY_MIN 0
0042 #define CAMQUALITY_MAX 97
0043
0044
0045 struct sd {
0046 struct gspca_dev gspca_dev;
0047 int blocks_left;
0048 const struct v4l2_pix_format *cap_mode;
0049 struct v4l2_ctrl *freq;
0050 struct v4l2_ctrl *jpegqual;
0051
0052 u8 type;
0053 u8 quality;
0054 #define QUALITY_MIN 35
0055 #define QUALITY_MAX 85
0056 #define QUALITY_DEF 85
0057 u8 jpeg_hdr[JPEG_HDR_SZ];
0058 };
0059
0060 struct jlj_command {
0061 unsigned char instruction[2];
0062 unsigned char ack_wanted;
0063 unsigned char delay;
0064 };
0065
0066
0067 static struct v4l2_pix_format jlj_mode[] = {
0068 { 320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
0069 .bytesperline = 320,
0070 .sizeimage = 320 * 240,
0071 .colorspace = V4L2_COLORSPACE_JPEG,
0072 .priv = 0},
0073 { 640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
0074 .bytesperline = 640,
0075 .sizeimage = 640 * 480,
0076 .colorspace = V4L2_COLORSPACE_JPEG,
0077 .priv = 0}
0078 };
0079
0080
0081
0082
0083
0084
0085
0086 static void jlj_write2(struct gspca_dev *gspca_dev, unsigned char *command)
0087 {
0088 int retval;
0089
0090 if (gspca_dev->usb_err < 0)
0091 return;
0092 memcpy(gspca_dev->usb_buf, command, 2);
0093 retval = usb_bulk_msg(gspca_dev->dev,
0094 usb_sndbulkpipe(gspca_dev->dev, 3),
0095 gspca_dev->usb_buf, 2, NULL, 500);
0096 if (retval < 0) {
0097 pr_err("command write [%02x] error %d\n",
0098 gspca_dev->usb_buf[0], retval);
0099 gspca_dev->usb_err = retval;
0100 }
0101 }
0102
0103
0104 static void jlj_read1(struct gspca_dev *gspca_dev, unsigned char *response)
0105 {
0106 int retval;
0107
0108 if (gspca_dev->usb_err < 0)
0109 return;
0110 retval = usb_bulk_msg(gspca_dev->dev,
0111 usb_rcvbulkpipe(gspca_dev->dev, 0x84),
0112 gspca_dev->usb_buf, 1, NULL, 500);
0113 *response = gspca_dev->usb_buf[0];
0114 if (retval < 0) {
0115 pr_err("read command [%02x] error %d\n",
0116 gspca_dev->usb_buf[0], retval);
0117 gspca_dev->usb_err = retval;
0118 }
0119 }
0120
0121 static void setfreq(struct gspca_dev *gspca_dev, s32 val)
0122 {
0123 u8 freq_commands[][2] = {
0124 {0x71, 0x80},
0125 {0x70, 0x07}
0126 };
0127
0128 freq_commands[0][1] |= val >> 1;
0129
0130 jlj_write2(gspca_dev, freq_commands[0]);
0131 jlj_write2(gspca_dev, freq_commands[1]);
0132 }
0133
0134 static void setcamquality(struct gspca_dev *gspca_dev, s32 val)
0135 {
0136 u8 quality_commands[][2] = {
0137 {0x71, 0x1E},
0138 {0x70, 0x06}
0139 };
0140 u8 camquality;
0141
0142
0143 camquality = ((QUALITY_MAX - val) * CAMQUALITY_MAX)
0144 / (QUALITY_MAX - QUALITY_MIN);
0145 quality_commands[0][1] += camquality;
0146
0147 jlj_write2(gspca_dev, quality_commands[0]);
0148 jlj_write2(gspca_dev, quality_commands[1]);
0149 }
0150
0151 static void setautogain(struct gspca_dev *gspca_dev, s32 val)
0152 {
0153 u8 autogain_commands[][2] = {
0154 {0x94, 0x02},
0155 {0xcf, 0x00}
0156 };
0157
0158 autogain_commands[1][1] = val << 4;
0159
0160 jlj_write2(gspca_dev, autogain_commands[0]);
0161 jlj_write2(gspca_dev, autogain_commands[1]);
0162 }
0163
0164 static void setred(struct gspca_dev *gspca_dev, s32 val)
0165 {
0166 u8 setred_commands[][2] = {
0167 {0x94, 0x02},
0168 {0xe6, 0x00}
0169 };
0170
0171 setred_commands[1][1] = val;
0172
0173 jlj_write2(gspca_dev, setred_commands[0]);
0174 jlj_write2(gspca_dev, setred_commands[1]);
0175 }
0176
0177 static void setgreen(struct gspca_dev *gspca_dev, s32 val)
0178 {
0179 u8 setgreen_commands[][2] = {
0180 {0x94, 0x02},
0181 {0xe7, 0x00}
0182 };
0183
0184 setgreen_commands[1][1] = val;
0185
0186 jlj_write2(gspca_dev, setgreen_commands[0]);
0187 jlj_write2(gspca_dev, setgreen_commands[1]);
0188 }
0189
0190 static void setblue(struct gspca_dev *gspca_dev, s32 val)
0191 {
0192 u8 setblue_commands[][2] = {
0193 {0x94, 0x02},
0194 {0xe9, 0x00}
0195 };
0196
0197 setblue_commands[1][1] = val;
0198
0199 jlj_write2(gspca_dev, setblue_commands[0]);
0200 jlj_write2(gspca_dev, setblue_commands[1]);
0201 }
0202
0203 static int jlj_start(struct gspca_dev *gspca_dev)
0204 {
0205 int i;
0206 int start_commands_size;
0207 u8 response = 0xff;
0208 struct sd *sd = (struct sd *) gspca_dev;
0209 struct jlj_command start_commands[] = {
0210 {{0x71, 0x81}, 0, 0},
0211 {{0x70, 0x05}, 0, JEILINJ_CMD_DELAY},
0212 {{0x95, 0x70}, 1, 0},
0213 {{0x71, 0x81 - gspca_dev->curr_mode}, 0, 0},
0214 {{0x70, 0x04}, 0, JEILINJ_CMD_DELAY},
0215 {{0x95, 0x70}, 1, 0},
0216 {{0x71, 0x00}, 0, 0},
0217 {{0x70, 0x08}, 0, JEILINJ_CMD_DELAY},
0218 {{0x95, 0x70}, 1, 0},
0219 #define SPORTSCAM_DV15_CMD_SIZE 9
0220 {{0x94, 0x02}, 0, 0},
0221 {{0xde, 0x24}, 0, 0},
0222 {{0x94, 0x02}, 0, 0},
0223 {{0xdd, 0xf0}, 0, 0},
0224 {{0x94, 0x02}, 0, 0},
0225 {{0xe3, 0x2c}, 0, 0},
0226 {{0x94, 0x02}, 0, 0},
0227 {{0xe4, 0x00}, 0, 0},
0228 {{0x94, 0x02}, 0, 0},
0229 {{0xe5, 0x00}, 0, 0},
0230 {{0x94, 0x02}, 0, 0},
0231 {{0xe6, 0x2c}, 0, 0},
0232 {{0x94, 0x03}, 0, 0},
0233 {{0xaa, 0x00}, 0, 0}
0234 };
0235
0236 sd->blocks_left = 0;
0237
0238
0239
0240 if (sd->type == SPORTSCAM_DV15)
0241 start_commands_size = SPORTSCAM_DV15_CMD_SIZE;
0242 else
0243 start_commands_size = ARRAY_SIZE(start_commands);
0244
0245 for (i = 0; i < start_commands_size; i++) {
0246 jlj_write2(gspca_dev, start_commands[i].instruction);
0247 if (start_commands[i].delay)
0248 msleep(start_commands[i].delay);
0249 if (start_commands[i].ack_wanted)
0250 jlj_read1(gspca_dev, &response);
0251 }
0252 setcamquality(gspca_dev, v4l2_ctrl_g_ctrl(sd->jpegqual));
0253 msleep(2);
0254 setfreq(gspca_dev, v4l2_ctrl_g_ctrl(sd->freq));
0255 if (gspca_dev->usb_err < 0)
0256 gspca_err(gspca_dev, "Start streaming command failed\n");
0257 return gspca_dev->usb_err;
0258 }
0259
0260 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
0261 u8 *data, int len)
0262 {
0263 struct sd *sd = (struct sd *) gspca_dev;
0264 int packet_type;
0265 u32 header_marker;
0266
0267 gspca_dbg(gspca_dev, D_STREAM, "Got %d bytes out of %d for Block 0\n",
0268 len, JEILINJ_MAX_TRANSFER);
0269 if (len != JEILINJ_MAX_TRANSFER) {
0270 gspca_dbg(gspca_dev, D_PACK, "bad length\n");
0271 goto discard;
0272 }
0273
0274 header_marker = ((u32 *)data)[0];
0275 if (header_marker == FRAME_START) {
0276 sd->blocks_left = data[0x0a] - 1;
0277 gspca_dbg(gspca_dev, D_STREAM, "blocks_left = 0x%x\n",
0278 sd->blocks_left);
0279
0280 gspca_frame_add(gspca_dev, FIRST_PACKET,
0281 sd->jpeg_hdr, JPEG_HDR_SZ);
0282
0283 gspca_frame_add(gspca_dev, INTER_PACKET,
0284 data + FRAME_HEADER_LEN,
0285 JEILINJ_MAX_TRANSFER - FRAME_HEADER_LEN);
0286 } else if (sd->blocks_left > 0) {
0287 gspca_dbg(gspca_dev, D_STREAM, "%d blocks remaining for frame\n",
0288 sd->blocks_left);
0289 sd->blocks_left -= 1;
0290 if (sd->blocks_left == 0)
0291 packet_type = LAST_PACKET;
0292 else
0293 packet_type = INTER_PACKET;
0294 gspca_frame_add(gspca_dev, packet_type,
0295 data, JEILINJ_MAX_TRANSFER);
0296 } else
0297 goto discard;
0298 return;
0299 discard:
0300
0301 gspca_dev->last_packet_type = DISCARD_PACKET;
0302 }
0303
0304
0305 static int sd_config(struct gspca_dev *gspca_dev,
0306 const struct usb_device_id *id)
0307 {
0308 struct cam *cam = &gspca_dev->cam;
0309 struct sd *dev = (struct sd *) gspca_dev;
0310
0311 dev->type = id->driver_info;
0312 dev->quality = QUALITY_DEF;
0313
0314 cam->cam_mode = jlj_mode;
0315 cam->nmodes = ARRAY_SIZE(jlj_mode);
0316 cam->bulk = 1;
0317 cam->bulk_nurbs = 1;
0318 cam->bulk_size = JEILINJ_MAX_TRANSFER;
0319 return 0;
0320 }
0321
0322 static void sd_stopN(struct gspca_dev *gspca_dev)
0323 {
0324 int i;
0325 u8 *buf;
0326 static u8 stop_commands[][2] = {
0327 {0x71, 0x00},
0328 {0x70, 0x09},
0329 {0x71, 0x80},
0330 {0x70, 0x05}
0331 };
0332
0333 for (;;) {
0334
0335 usb_bulk_msg(gspca_dev->dev,
0336 gspca_dev->urb[0]->pipe,
0337 gspca_dev->urb[0]->transfer_buffer,
0338 JEILINJ_MAX_TRANSFER, NULL,
0339 JEILINJ_DATA_TIMEOUT);
0340
0341
0342 i = 0;
0343 buf = gspca_dev->urb[0]->transfer_buffer;
0344 while ((i < (JEILINJ_MAX_TRANSFER - 1)) &&
0345 ((buf[i] != 0xff) || (buf[i+1] != 0xd9)))
0346 i++;
0347
0348 if (i != (JEILINJ_MAX_TRANSFER - 1))
0349
0350 break;
0351 }
0352
0353 for (i = 0; i < ARRAY_SIZE(stop_commands); i++)
0354 jlj_write2(gspca_dev, stop_commands[i]);
0355 }
0356
0357
0358 static int sd_init(struct gspca_dev *gspca_dev)
0359 {
0360 return gspca_dev->usb_err;
0361 }
0362
0363
0364 static int sd_start(struct gspca_dev *gspca_dev)
0365 {
0366 struct sd *dev = (struct sd *) gspca_dev;
0367
0368
0369 jpeg_define(dev->jpeg_hdr, gspca_dev->pixfmt.height,
0370 gspca_dev->pixfmt.width,
0371 0x21);
0372 jpeg_set_qual(dev->jpeg_hdr, dev->quality);
0373 gspca_dbg(gspca_dev, D_STREAM, "Start streaming at %dx%d\n",
0374 gspca_dev->pixfmt.height, gspca_dev->pixfmt.width);
0375 jlj_start(gspca_dev);
0376 return gspca_dev->usb_err;
0377 }
0378
0379
0380 static const struct usb_device_id device_table[] = {
0381 {USB_DEVICE(0x0979, 0x0280), .driver_info = SAKAR_57379},
0382 {USB_DEVICE(0x0979, 0x0270), .driver_info = SPORTSCAM_DV15},
0383 {}
0384 };
0385
0386 MODULE_DEVICE_TABLE(usb, device_table);
0387
0388 static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
0389 {
0390 struct gspca_dev *gspca_dev =
0391 container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
0392 struct sd *sd = (struct sd *)gspca_dev;
0393
0394 gspca_dev->usb_err = 0;
0395
0396 if (!gspca_dev->streaming)
0397 return 0;
0398
0399 switch (ctrl->id) {
0400 case V4L2_CID_POWER_LINE_FREQUENCY:
0401 setfreq(gspca_dev, ctrl->val);
0402 break;
0403 case V4L2_CID_RED_BALANCE:
0404 setred(gspca_dev, ctrl->val);
0405 break;
0406 case V4L2_CID_GAIN:
0407 setgreen(gspca_dev, ctrl->val);
0408 break;
0409 case V4L2_CID_BLUE_BALANCE:
0410 setblue(gspca_dev, ctrl->val);
0411 break;
0412 case V4L2_CID_AUTOGAIN:
0413 setautogain(gspca_dev, ctrl->val);
0414 break;
0415 case V4L2_CID_JPEG_COMPRESSION_QUALITY:
0416 jpeg_set_qual(sd->jpeg_hdr, ctrl->val);
0417 setcamquality(gspca_dev, ctrl->val);
0418 break;
0419 }
0420 return gspca_dev->usb_err;
0421 }
0422
0423 static const struct v4l2_ctrl_ops sd_ctrl_ops = {
0424 .s_ctrl = sd_s_ctrl,
0425 };
0426
0427 static int sd_init_controls(struct gspca_dev *gspca_dev)
0428 {
0429 struct sd *sd = (struct sd *)gspca_dev;
0430 struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
0431 static const struct v4l2_ctrl_config custom_autogain = {
0432 .ops = &sd_ctrl_ops,
0433 .id = V4L2_CID_AUTOGAIN,
0434 .type = V4L2_CTRL_TYPE_INTEGER,
0435 .name = "Automatic Gain (and Exposure)",
0436 .max = 3,
0437 .step = 1,
0438 .def = 0,
0439 };
0440
0441 gspca_dev->vdev.ctrl_handler = hdl;
0442 v4l2_ctrl_handler_init(hdl, 6);
0443 sd->freq = v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops,
0444 V4L2_CID_POWER_LINE_FREQUENCY,
0445 V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 1,
0446 V4L2_CID_POWER_LINE_FREQUENCY_60HZ);
0447 v4l2_ctrl_new_custom(hdl, &custom_autogain, NULL);
0448 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
0449 V4L2_CID_RED_BALANCE, 0, 3, 1, 2);
0450 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
0451 V4L2_CID_GAIN, 0, 3, 1, 2);
0452 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
0453 V4L2_CID_BLUE_BALANCE, 0, 3, 1, 2);
0454 sd->jpegqual = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
0455 V4L2_CID_JPEG_COMPRESSION_QUALITY,
0456 QUALITY_MIN, QUALITY_MAX, 1, QUALITY_DEF);
0457
0458 if (hdl->error) {
0459 pr_err("Could not initialize controls\n");
0460 return hdl->error;
0461 }
0462 return 0;
0463 }
0464
0465 static int sd_set_jcomp(struct gspca_dev *gspca_dev,
0466 const struct v4l2_jpegcompression *jcomp)
0467 {
0468 struct sd *sd = (struct sd *) gspca_dev;
0469
0470 v4l2_ctrl_s_ctrl(sd->jpegqual, jcomp->quality);
0471 return 0;
0472 }
0473
0474 static int sd_get_jcomp(struct gspca_dev *gspca_dev,
0475 struct v4l2_jpegcompression *jcomp)
0476 {
0477 struct sd *sd = (struct sd *) gspca_dev;
0478
0479 memset(jcomp, 0, sizeof *jcomp);
0480 jcomp->quality = v4l2_ctrl_g_ctrl(sd->jpegqual);
0481 jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
0482 | V4L2_JPEG_MARKER_DQT;
0483 return 0;
0484 }
0485
0486
0487
0488 static const struct sd_desc sd_desc_sakar_57379 = {
0489 .name = MODULE_NAME,
0490 .config = sd_config,
0491 .init = sd_init,
0492 .start = sd_start,
0493 .stopN = sd_stopN,
0494 .pkt_scan = sd_pkt_scan,
0495 };
0496
0497
0498 static const struct sd_desc sd_desc_sportscam_dv15 = {
0499 .name = MODULE_NAME,
0500 .config = sd_config,
0501 .init = sd_init,
0502 .init_controls = sd_init_controls,
0503 .start = sd_start,
0504 .stopN = sd_stopN,
0505 .pkt_scan = sd_pkt_scan,
0506 .get_jcomp = sd_get_jcomp,
0507 .set_jcomp = sd_set_jcomp,
0508 };
0509
0510 static const struct sd_desc *sd_desc[2] = {
0511 &sd_desc_sakar_57379,
0512 &sd_desc_sportscam_dv15
0513 };
0514
0515
0516 static int sd_probe(struct usb_interface *intf,
0517 const struct usb_device_id *id)
0518 {
0519 return gspca_dev_probe(intf, id,
0520 sd_desc[id->driver_info],
0521 sizeof(struct sd),
0522 THIS_MODULE);
0523 }
0524
0525 static struct usb_driver sd_driver = {
0526 .name = MODULE_NAME,
0527 .id_table = device_table,
0528 .probe = sd_probe,
0529 .disconnect = gspca_disconnect,
0530 #ifdef CONFIG_PM
0531 .suspend = gspca_suspend,
0532 .resume = gspca_resume,
0533 .reset_resume = gspca_resume,
0534 #endif
0535 };
0536
0537 module_usb_driver(sd_driver);