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