964 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * SN9C2028 library4 *5 * Copyright (C) 2009 Theodore Kilgore <kilgota@auburn.edu>6 */7 8#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt9 10#define MODULE_NAME "sn9c2028"11 12#include "gspca.h"13 14MODULE_AUTHOR("Theodore Kilgore");15MODULE_DESCRIPTION("Sonix SN9C2028 USB Camera Driver");16MODULE_LICENSE("GPL");17 18/* specific webcam descriptor */19struct sd {20 struct gspca_dev gspca_dev; /* !! must be the first item */21 u8 sof_read;22 u16 model;23 24#define MIN_AVG_LUM 850025#define MAX_AVG_LUM 1000026 int avg_lum;27 u8 avg_lum_l;28 29 struct { /* autogain and gain control cluster */30 struct v4l2_ctrl *autogain;31 struct v4l2_ctrl *gain;32 };33};34 35struct init_command {36 unsigned char instruction[6];37 unsigned char to_read; /* length to read. 0 means no reply requested */38};39 40/* How to change the resolution of any of the VGA cams is unknown */41static const struct v4l2_pix_format vga_mode[] = {42 {640, 480, V4L2_PIX_FMT_SN9C2028, V4L2_FIELD_NONE,43 .bytesperline = 640,44 .sizeimage = 640 * 480 * 3 / 4,45 .colorspace = V4L2_COLORSPACE_SRGB,46 .priv = 0},47};48 49/* No way to change the resolution of the CIF cams is known */50static const struct v4l2_pix_format cif_mode[] = {51 {352, 288, V4L2_PIX_FMT_SN9C2028, V4L2_FIELD_NONE,52 .bytesperline = 352,53 .sizeimage = 352 * 288 * 3 / 4,54 .colorspace = V4L2_COLORSPACE_SRGB,55 .priv = 0},56};57 58/* the bytes to write are in gspca_dev->usb_buf */59static int sn9c2028_command(struct gspca_dev *gspca_dev, u8 *command)60{61 int rc;62 63 gspca_dbg(gspca_dev, D_USBO, "sending command %02x%02x%02x%02x%02x%02x\n",64 command[0], command[1], command[2],65 command[3], command[4], command[5]);66 67 memcpy(gspca_dev->usb_buf, command, 6);68 rc = usb_control_msg(gspca_dev->dev,69 usb_sndctrlpipe(gspca_dev->dev, 0),70 USB_REQ_GET_CONFIGURATION,71 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,72 2, 0, gspca_dev->usb_buf, 6, 500);73 if (rc < 0) {74 pr_err("command write [%02x] error %d\n",75 gspca_dev->usb_buf[0], rc);76 return rc;77 }78 79 return 0;80}81 82static int sn9c2028_read1(struct gspca_dev *gspca_dev)83{84 int rc;85 86 rc = usb_control_msg(gspca_dev->dev,87 usb_rcvctrlpipe(gspca_dev->dev, 0),88 USB_REQ_GET_STATUS,89 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,90 1, 0, gspca_dev->usb_buf, 1, 500);91 if (rc != 1) {92 pr_err("read1 error %d\n", rc);93 return (rc < 0) ? rc : -EIO;94 }95 gspca_dbg(gspca_dev, D_USBI, "read1 response %02x\n",96 gspca_dev->usb_buf[0]);97 return gspca_dev->usb_buf[0];98}99 100static int sn9c2028_read4(struct gspca_dev *gspca_dev, u8 *reading)101{102 int rc;103 rc = usb_control_msg(gspca_dev->dev,104 usb_rcvctrlpipe(gspca_dev->dev, 0),105 USB_REQ_GET_STATUS,106 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,107 4, 0, gspca_dev->usb_buf, 4, 500);108 if (rc != 4) {109 pr_err("read4 error %d\n", rc);110 return (rc < 0) ? rc : -EIO;111 }112 memcpy(reading, gspca_dev->usb_buf, 4);113 gspca_dbg(gspca_dev, D_USBI, "read4 response %02x%02x%02x%02x\n",114 reading[0], reading[1], reading[2], reading[3]);115 return rc;116}117 118static int sn9c2028_long_command(struct gspca_dev *gspca_dev, u8 *command)119{120 int i, status;121 __u8 reading[4];122 123 status = sn9c2028_command(gspca_dev, command);124 if (status < 0)125 return status;126 127 status = -1;128 for (i = 0; i < 256 && status < 2; i++)129 status = sn9c2028_read1(gspca_dev);130 if (status < 0) {131 pr_err("long command status read error %d\n", status);132 return status;133 }134 135 memset(reading, 0, 4);136 status = sn9c2028_read4(gspca_dev, reading);137 if (status < 0)138 return status;139 140 /* in general, the first byte of the response is the first byte of141 * the command, or'ed with 8 */142 status = sn9c2028_read1(gspca_dev);143 if (status < 0)144 return status;145 146 return 0;147}148 149static int sn9c2028_short_command(struct gspca_dev *gspca_dev, u8 *command)150{151 int err_code;152 153 err_code = sn9c2028_command(gspca_dev, command);154 if (err_code < 0)155 return err_code;156 157 err_code = sn9c2028_read1(gspca_dev);158 if (err_code < 0)159 return err_code;160 161 return 0;162}163 164/* this function is called at probe time */165static int sd_config(struct gspca_dev *gspca_dev,166 const struct usb_device_id *id)167{168 struct sd *sd = (struct sd *) gspca_dev;169 struct cam *cam = &gspca_dev->cam;170 171 gspca_dbg(gspca_dev, D_PROBE, "SN9C2028 camera detected (vid/pid 0x%04X:0x%04X)\n",172 id->idVendor, id->idProduct);173 174 sd->model = id->idProduct;175 176 switch (sd->model) {177 case 0x7005:178 gspca_dbg(gspca_dev, D_PROBE, "Genius Smart 300 camera\n");179 break;180 case 0x7003:181 gspca_dbg(gspca_dev, D_PROBE, "Genius Videocam Live v2\n");182 break;183 case 0x8000:184 gspca_dbg(gspca_dev, D_PROBE, "DC31VC\n");185 break;186 case 0x8001:187 gspca_dbg(gspca_dev, D_PROBE, "Spy camera\n");188 break;189 case 0x8003:190 gspca_dbg(gspca_dev, D_PROBE, "CIF camera\n");191 break;192 case 0x8008:193 gspca_dbg(gspca_dev, D_PROBE, "Mini-Shotz ms-350 camera\n");194 break;195 case 0x800a:196 gspca_dbg(gspca_dev, D_PROBE, "Vivitar 3350b type camera\n");197 cam->input_flags = V4L2_IN_ST_VFLIP | V4L2_IN_ST_HFLIP;198 break;199 }200 201 switch (sd->model) {202 case 0x8000:203 case 0x8001:204 case 0x8003:205 cam->cam_mode = cif_mode;206 cam->nmodes = ARRAY_SIZE(cif_mode);207 break;208 default:209 cam->cam_mode = vga_mode;210 cam->nmodes = ARRAY_SIZE(vga_mode);211 }212 return 0;213}214 215/* this function is called at probe and resume time */216static int sd_init(struct gspca_dev *gspca_dev)217{218 int status;219 220 sn9c2028_read1(gspca_dev);221 sn9c2028_read1(gspca_dev);222 status = sn9c2028_read1(gspca_dev);223 224 return (status < 0) ? status : 0;225}226 227static int run_start_commands(struct gspca_dev *gspca_dev,228 struct init_command *cam_commands, int n)229{230 int i, err_code = -1;231 232 for (i = 0; i < n; i++) {233 switch (cam_commands[i].to_read) {234 case 4:235 err_code = sn9c2028_long_command(gspca_dev,236 cam_commands[i].instruction);237 break;238 case 1:239 err_code = sn9c2028_short_command(gspca_dev,240 cam_commands[i].instruction);241 break;242 case 0:243 err_code = sn9c2028_command(gspca_dev,244 cam_commands[i].instruction);245 break;246 }247 if (err_code < 0)248 return err_code;249 }250 return 0;251}252 253static void set_gain(struct gspca_dev *gspca_dev, s32 g)254{255 struct sd *sd = (struct sd *) gspca_dev;256 257 struct init_command genius_vcam_live_gain_cmds[] = {258 {{0x1d, 0x25, 0x10 /* This byte is gain */,259 0x20, 0xab, 0x00}, 0},260 };261 if (!gspca_dev->streaming)262 return;263 264 switch (sd->model) {265 case 0x7003:266 genius_vcam_live_gain_cmds[0].instruction[2] = g;267 run_start_commands(gspca_dev, genius_vcam_live_gain_cmds,268 ARRAY_SIZE(genius_vcam_live_gain_cmds));269 break;270 default:271 break;272 }273}274 275static int sd_s_ctrl(struct v4l2_ctrl *ctrl)276{277 struct gspca_dev *gspca_dev =278 container_of(ctrl->handler, struct gspca_dev, ctrl_handler);279 struct sd *sd = (struct sd *)gspca_dev;280 281 gspca_dev->usb_err = 0;282 283 if (!gspca_dev->streaming)284 return 0;285 286 switch (ctrl->id) {287 /* standalone gain control */288 case V4L2_CID_GAIN:289 set_gain(gspca_dev, ctrl->val);290 break;291 /* autogain */292 case V4L2_CID_AUTOGAIN:293 set_gain(gspca_dev, sd->gain->val);294 break;295 }296 return gspca_dev->usb_err;297}298 299static const struct v4l2_ctrl_ops sd_ctrl_ops = {300 .s_ctrl = sd_s_ctrl,301};302 303 304static int sd_init_controls(struct gspca_dev *gspca_dev)305{306 struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;307 struct sd *sd = (struct sd *)gspca_dev;308 309 gspca_dev->vdev.ctrl_handler = hdl;310 v4l2_ctrl_handler_init(hdl, 2);311 312 switch (sd->model) {313 case 0x7003:314 sd->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,315 V4L2_CID_GAIN, 0, 20, 1, 0);316 sd->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,317 V4L2_CID_AUTOGAIN, 0, 1, 1, 1);318 break;319 default:320 break;321 }322 323 return 0;324}325static int start_spy_cam(struct gspca_dev *gspca_dev)326{327 struct init_command spy_start_commands[] = {328 {{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},329 {{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4},330 {{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4},331 {{0x13, 0x22, 0x01, 0x04, 0x00, 0x00}, 4},332 {{0x13, 0x23, 0x01, 0x03, 0x00, 0x00}, 4},333 {{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4},334 {{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4}, /* width 352 */335 {{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4}, /* height 288 */336 /* {{0x13, 0x27, 0x01, 0x28, 0x00, 0x00}, 4}, */337 {{0x13, 0x27, 0x01, 0x68, 0x00, 0x00}, 4},338 {{0x13, 0x28, 0x01, 0x09, 0x00, 0x00}, 4}, /* red gain ?*/339 /* {{0x13, 0x28, 0x01, 0x00, 0x00, 0x00}, 4}, */340 {{0x13, 0x29, 0x01, 0x00, 0x00, 0x00}, 4},341 /* {{0x13, 0x29, 0x01, 0x0c, 0x00, 0x00}, 4}, */342 {{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4},343 {{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4},344 /* {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4}, */345 {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},346 {{0x13, 0x2d, 0x01, 0x02, 0x00, 0x00}, 4},347 /* {{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4}, */348 {{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4},349 {{0x13, 0x2f, 0x01, 0x07, 0x00, 0x00}, 4},350 {{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4},351 {{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4},352 {{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4},353 {{0x11, 0x02, 0x06, 0x00, 0x00, 0x00}, 4},354 {{0x11, 0x03, 0x13, 0x00, 0x00, 0x00}, 4}, /*don't mess with*/355 /*{{0x11, 0x04, 0x06, 0x00, 0x00, 0x00}, 4}, observed */356 {{0x11, 0x04, 0x00, 0x00, 0x00, 0x00}, 4}, /* brighter */357 /*{{0x11, 0x05, 0x65, 0x00, 0x00, 0x00}, 4}, observed */358 {{0x11, 0x05, 0x00, 0x00, 0x00, 0x00}, 4}, /* brighter */359 {{0x11, 0x06, 0xb1, 0x00, 0x00, 0x00}, 4}, /* observed */360 {{0x11, 0x07, 0x00, 0x00, 0x00, 0x00}, 4},361 /*{{0x11, 0x08, 0x06, 0x00, 0x00, 0x00}, 4}, observed */362 {{0x11, 0x08, 0x0b, 0x00, 0x00, 0x00}, 4},363 {{0x11, 0x09, 0x01, 0x00, 0x00, 0x00}, 4},364 {{0x11, 0x0a, 0x01, 0x00, 0x00, 0x00}, 4},365 {{0x11, 0x0b, 0x01, 0x00, 0x00, 0x00}, 4},366 {{0x11, 0x0c, 0x01, 0x00, 0x00, 0x00}, 4},367 {{0x11, 0x0d, 0x00, 0x00, 0x00, 0x00}, 4},368 {{0x11, 0x0e, 0x04, 0x00, 0x00, 0x00}, 4},369 /* {{0x11, 0x0f, 0x00, 0x00, 0x00, 0x00}, 4}, */370 /* brightness or gain. 0 is default. 4 is good371 * indoors at night with incandescent lighting */372 {{0x11, 0x0f, 0x04, 0x00, 0x00, 0x00}, 4},373 {{0x11, 0x10, 0x06, 0x00, 0x00, 0x00}, 4}, /*hstart or hoffs*/374 {{0x11, 0x11, 0x06, 0x00, 0x00, 0x00}, 4},375 {{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},376 {{0x11, 0x14, 0x02, 0x00, 0x00, 0x00}, 4},377 {{0x11, 0x13, 0x01, 0x00, 0x00, 0x00}, 4},378 /* {{0x1b, 0x02, 0x06, 0x00, 0x00, 0x00}, 1}, observed */379 {{0x1b, 0x02, 0x11, 0x00, 0x00, 0x00}, 1}, /* brighter */380 /* {{0x1b, 0x13, 0x01, 0x00, 0x00, 0x00}, 1}, observed */381 {{0x1b, 0x13, 0x11, 0x00, 0x00, 0x00}, 1},382 {{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 1}, /* compresses */383 /* Camera should start to capture now. */384 };385 386 return run_start_commands(gspca_dev, spy_start_commands,387 ARRAY_SIZE(spy_start_commands));388}389 390static int start_cif_cam(struct gspca_dev *gspca_dev)391{392 struct init_command cif_start_commands[] = {393 {{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},394 /* The entire sequence below seems redundant */395 /* {{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4},396 {{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4},397 {{0x13, 0x22, 0x01, 0x06, 0x00, 0x00}, 4},398 {{0x13, 0x23, 0x01, 0x02, 0x00, 0x00}, 4},399 {{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4},400 {{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4}, width?401 {{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4}, height?402 {{0x13, 0x27, 0x01, 0x68, 0x00, 0x00}, 4}, subsample?403 {{0x13, 0x28, 0x01, 0x00, 0x00, 0x00}, 4},404 {{0x13, 0x29, 0x01, 0x20, 0x00, 0x00}, 4},405 {{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4},406 {{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4},407 {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},408 {{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4},409 {{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4},410 {{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4},411 {{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4},412 {{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4},413 {{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4},*/414 {{0x1b, 0x21, 0x00, 0x00, 0x00, 0x00}, 1},415 {{0x1b, 0x17, 0x00, 0x00, 0x00, 0x00}, 1},416 {{0x1b, 0x19, 0x00, 0x00, 0x00, 0x00}, 1},417 {{0x1b, 0x02, 0x06, 0x00, 0x00, 0x00}, 1},418 {{0x1b, 0x03, 0x5a, 0x00, 0x00, 0x00}, 1},419 {{0x1b, 0x04, 0x27, 0x00, 0x00, 0x00}, 1},420 {{0x1b, 0x05, 0x01, 0x00, 0x00, 0x00}, 1},421 {{0x1b, 0x12, 0x14, 0x00, 0x00, 0x00}, 1},422 {{0x1b, 0x13, 0x00, 0x00, 0x00, 0x00}, 1},423 {{0x1b, 0x14, 0x00, 0x00, 0x00, 0x00}, 1},424 {{0x1b, 0x15, 0x00, 0x00, 0x00, 0x00}, 1},425 {{0x1b, 0x16, 0x00, 0x00, 0x00, 0x00}, 1},426 {{0x1b, 0x77, 0xa2, 0x00, 0x00, 0x00}, 1},427 {{0x1b, 0x06, 0x0f, 0x00, 0x00, 0x00}, 1},428 {{0x1b, 0x07, 0x14, 0x00, 0x00, 0x00}, 1},429 {{0x1b, 0x08, 0x0f, 0x00, 0x00, 0x00}, 1},430 {{0x1b, 0x09, 0x10, 0x00, 0x00, 0x00}, 1},431 {{0x1b, 0x0e, 0x00, 0x00, 0x00, 0x00}, 1},432 {{0x1b, 0x0f, 0x00, 0x00, 0x00, 0x00}, 1},433 {{0x1b, 0x12, 0x07, 0x00, 0x00, 0x00}, 1},434 {{0x1b, 0x10, 0x1f, 0x00, 0x00, 0x00}, 1},435 {{0x1b, 0x11, 0x01, 0x00, 0x00, 0x00}, 1},436 {{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 1}, /* width/8 */437 {{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 1}, /* height/8 */438 /* {{0x13, 0x27, 0x01, 0x68, 0x00, 0x00}, 4}, subsample?439 * {{0x13, 0x28, 0x01, 0x1e, 0x00, 0x00}, 4}, does nothing440 * {{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4}, */441 /* {{0x13, 0x29, 0x01, 0x22, 0x00, 0x00}, 4},442 * causes subsampling443 * but not a change in the resolution setting! */444 {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},445 {{0x13, 0x2d, 0x01, 0x01, 0x00, 0x00}, 4},446 {{0x13, 0x2e, 0x01, 0x08, 0x00, 0x00}, 4},447 {{0x13, 0x2f, 0x01, 0x06, 0x00, 0x00}, 4},448 {{0x13, 0x28, 0x01, 0x00, 0x00, 0x00}, 4},449 {{0x1b, 0x04, 0x6d, 0x00, 0x00, 0x00}, 1},450 {{0x1b, 0x05, 0x03, 0x00, 0x00, 0x00}, 1},451 {{0x20, 0x36, 0x06, 0x00, 0x00, 0x00}, 1},452 {{0x1b, 0x0e, 0x01, 0x00, 0x00, 0x00}, 1},453 {{0x12, 0x27, 0x01, 0x00, 0x00, 0x00}, 4},454 {{0x1b, 0x0f, 0x00, 0x00, 0x00, 0x00}, 1},455 {{0x20, 0x36, 0x05, 0x00, 0x00, 0x00}, 1},456 {{0x1b, 0x10, 0x0f, 0x00, 0x00, 0x00}, 1},457 {{0x1b, 0x02, 0x06, 0x00, 0x00, 0x00}, 1},458 {{0x1b, 0x11, 0x01, 0x00, 0x00, 0x00}, 1},459 {{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 1},/* use compression */460 /* Camera should start to capture now. */461 };462 463 return run_start_commands(gspca_dev, cif_start_commands,464 ARRAY_SIZE(cif_start_commands));465}466 467static int start_ms350_cam(struct gspca_dev *gspca_dev)468{469 struct init_command ms350_start_commands[] = {470 {{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},471 {{0x16, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},472 {{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4},473 {{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4},474 {{0x13, 0x22, 0x01, 0x04, 0x00, 0x00}, 4},475 {{0x13, 0x23, 0x01, 0x03, 0x00, 0x00}, 4},476 {{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4},477 {{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4},478 {{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4},479 {{0x13, 0x27, 0x01, 0x28, 0x00, 0x00}, 4},480 {{0x13, 0x28, 0x01, 0x09, 0x00, 0x00}, 4},481 {{0x13, 0x29, 0x01, 0x00, 0x00, 0x00}, 4},482 {{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4},483 {{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4},484 {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},485 {{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4},486 {{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4},487 {{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4},488 {{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4},489 {{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4},490 {{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4},491 {{0x11, 0x00, 0x01, 0x00, 0x00, 0x00}, 4},492 {{0x11, 0x01, 0x70, 0x00, 0x00, 0x00}, 4},493 {{0x11, 0x02, 0x05, 0x00, 0x00, 0x00}, 4},494 {{0x11, 0x03, 0x5d, 0x00, 0x00, 0x00}, 4},495 {{0x11, 0x04, 0x07, 0x00, 0x00, 0x00}, 4},496 {{0x11, 0x05, 0x25, 0x00, 0x00, 0x00}, 4},497 {{0x11, 0x06, 0x00, 0x00, 0x00, 0x00}, 4},498 {{0x11, 0x07, 0x09, 0x00, 0x00, 0x00}, 4},499 {{0x11, 0x08, 0x01, 0x00, 0x00, 0x00}, 4},500 {{0x11, 0x09, 0x00, 0x00, 0x00, 0x00}, 4},501 {{0x11, 0x0a, 0x00, 0x00, 0x00, 0x00}, 4},502 {{0x11, 0x0b, 0x01, 0x00, 0x00, 0x00}, 4},503 {{0x11, 0x0c, 0x00, 0x00, 0x00, 0x00}, 4},504 {{0x11, 0x0d, 0x0c, 0x00, 0x00, 0x00}, 4},505 {{0x11, 0x0e, 0x01, 0x00, 0x00, 0x00}, 4},506 {{0x11, 0x0f, 0x00, 0x00, 0x00, 0x00}, 4},507 {{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4},508 {{0x11, 0x11, 0x00, 0x00, 0x00, 0x00}, 4},509 {{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},510 {{0x11, 0x13, 0x63, 0x00, 0x00, 0x00}, 4},511 {{0x11, 0x15, 0x70, 0x00, 0x00, 0x00}, 4},512 {{0x11, 0x18, 0x00, 0x00, 0x00, 0x00}, 4},513 {{0x11, 0x11, 0x01, 0x00, 0x00, 0x00}, 4},514 {{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4}, /* width */515 {{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4}, /* height */516 {{0x13, 0x28, 0x01, 0x09, 0x00, 0x00}, 4}, /* vstart? */517 {{0x13, 0x27, 0x01, 0x28, 0x00, 0x00}, 4},518 {{0x13, 0x29, 0x01, 0x40, 0x00, 0x00}, 4}, /* hstart? */519 {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},520 {{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4},521 {{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4},522 {{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4},523 {{0x1b, 0x02, 0x05, 0x00, 0x00, 0x00}, 1},524 {{0x1b, 0x11, 0x01, 0x00, 0x00, 0x00}, 1},525 {{0x20, 0x18, 0x00, 0x00, 0x00, 0x00}, 1},526 {{0x1b, 0x02, 0x0a, 0x00, 0x00, 0x00}, 1},527 {{0x1b, 0x11, 0x01, 0x00, 0x00, 0x00}, 0},528 /* Camera should start to capture now. */529 };530 531 return run_start_commands(gspca_dev, ms350_start_commands,532 ARRAY_SIZE(ms350_start_commands));533}534 535static int start_genius_cam(struct gspca_dev *gspca_dev)536{537 struct init_command genius_start_commands[] = {538 {{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},539 {{0x16, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},540 {{0x10, 0x00, 0x00, 0x00, 0x00, 0x00}, 4},541 {{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4},542 {{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4},543 /* "preliminary" width and height settings */544 {{0x13, 0x28, 0x01, 0x0e, 0x00, 0x00}, 4},545 {{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4},546 {{0x13, 0x29, 0x01, 0x22, 0x00, 0x00}, 4},547 {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},548 {{0x13, 0x2d, 0x01, 0x02, 0x00, 0x00}, 4},549 {{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4},550 {{0x13, 0x2f, 0x01, 0x07, 0x00, 0x00}, 4},551 {{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4},552 {{0x11, 0x21, 0x2d, 0x00, 0x00, 0x00}, 4},553 {{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4},554 {{0x11, 0x23, 0x03, 0x00, 0x00, 0x00}, 4},555 {{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4},556 {{0x11, 0x11, 0x64, 0x00, 0x00, 0x00}, 4},557 {{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},558 {{0x11, 0x13, 0x91, 0x00, 0x00, 0x00}, 4},559 {{0x11, 0x14, 0x01, 0x00, 0x00, 0x00}, 4},560 {{0x11, 0x15, 0x20, 0x00, 0x00, 0x00}, 4},561 {{0x11, 0x16, 0x01, 0x00, 0x00, 0x00}, 4},562 {{0x11, 0x17, 0x60, 0x00, 0x00, 0x00}, 4},563 {{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4},564 {{0x11, 0x21, 0x2d, 0x00, 0x00, 0x00}, 4},565 {{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4},566 {{0x11, 0x23, 0x03, 0x00, 0x00, 0x00}, 4},567 {{0x11, 0x25, 0x00, 0x00, 0x00, 0x00}, 4},568 {{0x11, 0x26, 0x02, 0x00, 0x00, 0x00}, 4},569 {{0x11, 0x27, 0x88, 0x00, 0x00, 0x00}, 4},570 {{0x11, 0x30, 0x38, 0x00, 0x00, 0x00}, 4},571 {{0x11, 0x31, 0x2a, 0x00, 0x00, 0x00}, 4},572 {{0x11, 0x32, 0x2a, 0x00, 0x00, 0x00}, 4},573 {{0x11, 0x33, 0x2a, 0x00, 0x00, 0x00}, 4},574 {{0x11, 0x34, 0x02, 0x00, 0x00, 0x00}, 4},575 {{0x11, 0x5b, 0x0a, 0x00, 0x00, 0x00}, 4},576 {{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4}, /* real width */577 {{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4}, /* real height */578 {{0x13, 0x28, 0x01, 0x0e, 0x00, 0x00}, 4},579 {{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4},580 {{0x13, 0x29, 0x01, 0x62, 0x00, 0x00}, 4},581 {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},582 {{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4},583 {{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4},584 {{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4},585 {{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4},586 {{0x11, 0x21, 0x2a, 0x00, 0x00, 0x00}, 4},587 {{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4},588 {{0x11, 0x23, 0x28, 0x00, 0x00, 0x00}, 4},589 {{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4},590 {{0x11, 0x11, 0x04, 0x00, 0x00, 0x00}, 4},591 {{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},592 {{0x11, 0x13, 0x03, 0x00, 0x00, 0x00}, 4},593 {{0x11, 0x14, 0x01, 0x00, 0x00, 0x00}, 4},594 {{0x11, 0x15, 0xe0, 0x00, 0x00, 0x00}, 4},595 {{0x11, 0x16, 0x02, 0x00, 0x00, 0x00}, 4},596 {{0x11, 0x17, 0x80, 0x00, 0x00, 0x00}, 4},597 {{0x1c, 0x20, 0x00, 0x2a, 0x00, 0x00}, 1},598 {{0x1c, 0x20, 0x00, 0x2a, 0x00, 0x00}, 1},599 {{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 0}600 /* Camera should start to capture now. */601 };602 603 return run_start_commands(gspca_dev, genius_start_commands,604 ARRAY_SIZE(genius_start_commands));605}606 607static int start_genius_videocam_live(struct gspca_dev *gspca_dev)608{609 int r;610 struct sd *sd = (struct sd *) gspca_dev;611 struct init_command genius_vcam_live_start_commands[] = {612 {{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 0},613 {{0x16, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},614 {{0x10, 0x00, 0x00, 0x00, 0x00, 0x00}, 4},615 {{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4},616 {{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4},617 618 {{0x13, 0x28, 0x01, 0x0e, 0x00, 0x00}, 4},619 {{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4},620 {{0x13, 0x29, 0x01, 0x22, 0x00, 0x00}, 4},621 {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},622 {{0x13, 0x2d, 0x01, 0x02, 0x00, 0x00}, 4},623 {{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4},624 {{0x13, 0x2f, 0x01, 0x07, 0x00, 0x00}, 4},625 {{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4},626 {{0x11, 0x21, 0x2d, 0x00, 0x00, 0x00}, 4},627 {{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4},628 {{0x11, 0x23, 0x03, 0x00, 0x00, 0x00}, 4},629 {{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4},630 {{0x11, 0x11, 0x64, 0x00, 0x00, 0x00}, 4},631 {{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},632 {{0x11, 0x13, 0x91, 0x00, 0x00, 0x00}, 4},633 {{0x11, 0x14, 0x01, 0x00, 0x00, 0x00}, 4},634 {{0x11, 0x15, 0x20, 0x00, 0x00, 0x00}, 4},635 {{0x11, 0x16, 0x01, 0x00, 0x00, 0x00}, 4},636 {{0x11, 0x17, 0x60, 0x00, 0x00, 0x00}, 4},637 {{0x1c, 0x20, 0x00, 0x2d, 0x00, 0x00}, 4},638 {{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4},639 {{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4},640 {{0x13, 0x22, 0x01, 0x00, 0x00, 0x00}, 4},641 {{0x13, 0x23, 0x01, 0x01, 0x00, 0x00}, 4},642 {{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4},643 {{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4},644 {{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4},645 {{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4},646 {{0x13, 0x28, 0x01, 0x0e, 0x00, 0x00}, 4},647 {{0x13, 0x29, 0x01, 0x22, 0x00, 0x00}, 4},648 {{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4},649 {{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4},650 {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},651 {{0x13, 0x2d, 0x01, 0x02, 0x00, 0x00}, 4},652 {{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4},653 {{0x13, 0x2f, 0x01, 0x07, 0x00, 0x00}, 4},654 {{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4},655 {{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4},656 {{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4},657 {{0x11, 0x01, 0x04, 0x00, 0x00, 0x00}, 4},658 {{0x11, 0x02, 0x92, 0x00, 0x00, 0x00}, 4},659 {{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4},660 {{0x11, 0x11, 0x64, 0x00, 0x00, 0x00}, 4},661 {{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},662 {{0x11, 0x13, 0x91, 0x00, 0x00, 0x00}, 4},663 {{0x11, 0x14, 0x01, 0x00, 0x00, 0x00}, 4},664 {{0x11, 0x15, 0x20, 0x00, 0x00, 0x00}, 4},665 {{0x11, 0x16, 0x01, 0x00, 0x00, 0x00}, 4},666 {{0x11, 0x17, 0x60, 0x00, 0x00, 0x00}, 4},667 {{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4},668 {{0x11, 0x21, 0x2d, 0x00, 0x00, 0x00}, 4},669 {{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4},670 {{0x11, 0x23, 0x03, 0x00, 0x00, 0x00}, 4},671 {{0x11, 0x25, 0x00, 0x00, 0x00, 0x00}, 4},672 {{0x11, 0x26, 0x02, 0x00, 0x00, 0x00}, 4},673 {{0x11, 0x27, 0x88, 0x00, 0x00, 0x00}, 4},674 {{0x11, 0x30, 0x38, 0x00, 0x00, 0x00}, 4},675 {{0x11, 0x31, 0x2a, 0x00, 0x00, 0x00}, 4},676 {{0x11, 0x32, 0x2a, 0x00, 0x00, 0x00}, 4},677 {{0x11, 0x33, 0x2a, 0x00, 0x00, 0x00}, 4},678 {{0x11, 0x34, 0x02, 0x00, 0x00, 0x00}, 4},679 {{0x11, 0x5b, 0x0a, 0x00, 0x00, 0x00}, 4},680 {{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4},681 {{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4},682 {{0x13, 0x28, 0x01, 0x0e, 0x00, 0x00}, 4},683 {{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4},684 {{0x13, 0x29, 0x01, 0x62, 0x00, 0x00}, 4},685 {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},686 {{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4},687 {{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4},688 {{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4},689 {{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4},690 {{0x11, 0x21, 0x2a, 0x00, 0x00, 0x00}, 4},691 {{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4},692 {{0x11, 0x23, 0x28, 0x00, 0x00, 0x00}, 4},693 {{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4},694 {{0x11, 0x11, 0x04, 0x00, 0x00, 0x00}, 4},695 {{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},696 {{0x11, 0x13, 0x03, 0x00, 0x00, 0x00}, 4},697 {{0x11, 0x14, 0x01, 0x00, 0x00, 0x00}, 4},698 {{0x11, 0x15, 0xe0, 0x00, 0x00, 0x00}, 4},699 {{0x11, 0x16, 0x02, 0x00, 0x00, 0x00}, 4},700 {{0x11, 0x17, 0x80, 0x00, 0x00, 0x00}, 4},701 {{0x1c, 0x20, 0x00, 0x2a, 0x00, 0x00}, 1},702 {{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 0},703 /* Camera should start to capture now. */704 {{0x12, 0x27, 0x01, 0x00, 0x00, 0x00}, 0},705 {{0x1b, 0x32, 0x26, 0x00, 0x00, 0x00}, 0},706 {{0x1d, 0x25, 0x10, 0x20, 0xab, 0x00}, 0},707 };708 709 r = run_start_commands(gspca_dev, genius_vcam_live_start_commands,710 ARRAY_SIZE(genius_vcam_live_start_commands));711 if (r < 0)712 return r;713 714 if (sd->gain)715 set_gain(gspca_dev, v4l2_ctrl_g_ctrl(sd->gain));716 717 return r;718}719 720static int start_vivitar_cam(struct gspca_dev *gspca_dev)721{722 struct init_command vivitar_start_commands[] = {723 {{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},724 {{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4},725 {{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4},726 {{0x13, 0x22, 0x01, 0x01, 0x00, 0x00}, 4},727 {{0x13, 0x23, 0x01, 0x01, 0x00, 0x00}, 4},728 {{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4},729 {{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4},730 {{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4},731 {{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4},732 {{0x13, 0x28, 0x01, 0x0a, 0x00, 0x00}, 4},733 /*734 * Above is changed from OEM 0x0b. Fixes Bayer tiling.735 * Presumably gives a vertical shift of one row.736 */737 {{0x13, 0x29, 0x01, 0x20, 0x00, 0x00}, 4},738 /* Above seems to do horizontal shift. */739 {{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4},740 {{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4},741 {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},742 {{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4},743 {{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4},744 {{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4},745 /* Above three commands seem to relate to brightness. */746 {{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4},747 {{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4},748 {{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4},749 {{0x1b, 0x12, 0x80, 0x00, 0x00, 0x00}, 1},750 {{0x1b, 0x01, 0x77, 0x00, 0x00, 0x00}, 1},751 {{0x1b, 0x02, 0x3a, 0x00, 0x00, 0x00}, 1},752 {{0x1b, 0x12, 0x78, 0x00, 0x00, 0x00}, 1},753 {{0x1b, 0x13, 0x00, 0x00, 0x00, 0x00}, 1},754 {{0x1b, 0x14, 0x80, 0x00, 0x00, 0x00}, 1},755 {{0x1b, 0x15, 0x34, 0x00, 0x00, 0x00}, 1},756 {{0x1b, 0x1b, 0x04, 0x00, 0x00, 0x00}, 1},757 {{0x1b, 0x20, 0x44, 0x00, 0x00, 0x00}, 1},758 {{0x1b, 0x23, 0xee, 0x00, 0x00, 0x00}, 1},759 {{0x1b, 0x26, 0xa0, 0x00, 0x00, 0x00}, 1},760 {{0x1b, 0x27, 0x9a, 0x00, 0x00, 0x00}, 1},761 {{0x1b, 0x28, 0xa0, 0x00, 0x00, 0x00}, 1},762 {{0x1b, 0x29, 0x30, 0x00, 0x00, 0x00}, 1},763 {{0x1b, 0x2a, 0x80, 0x00, 0x00, 0x00}, 1},764 {{0x1b, 0x2b, 0x00, 0x00, 0x00, 0x00}, 1},765 {{0x1b, 0x2f, 0x3d, 0x00, 0x00, 0x00}, 1},766 {{0x1b, 0x30, 0x24, 0x00, 0x00, 0x00}, 1},767 {{0x1b, 0x32, 0x86, 0x00, 0x00, 0x00}, 1},768 {{0x1b, 0x60, 0xa9, 0x00, 0x00, 0x00}, 1},769 {{0x1b, 0x61, 0x42, 0x00, 0x00, 0x00}, 1},770 {{0x1b, 0x65, 0x00, 0x00, 0x00, 0x00}, 1},771 {{0x1b, 0x69, 0x38, 0x00, 0x00, 0x00}, 1},772 {{0x1b, 0x6f, 0x88, 0x00, 0x00, 0x00}, 1},773 {{0x1b, 0x70, 0x0b, 0x00, 0x00, 0x00}, 1},774 {{0x1b, 0x71, 0x00, 0x00, 0x00, 0x00}, 1},775 {{0x1b, 0x74, 0x21, 0x00, 0x00, 0x00}, 1},776 {{0x1b, 0x75, 0x86, 0x00, 0x00, 0x00}, 1},777 {{0x1b, 0x76, 0x00, 0x00, 0x00, 0x00}, 1},778 {{0x1b, 0x7d, 0xf3, 0x00, 0x00, 0x00}, 1},779 {{0x1b, 0x17, 0x1c, 0x00, 0x00, 0x00}, 1},780 {{0x1b, 0x18, 0xc0, 0x00, 0x00, 0x00}, 1},781 {{0x1b, 0x19, 0x05, 0x00, 0x00, 0x00}, 1},782 {{0x1b, 0x1a, 0xf6, 0x00, 0x00, 0x00}, 1},783 /* {{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4},784 {{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4},785 {{0x13, 0x28, 0x01, 0x0b, 0x00, 0x00}, 4}, */786 {{0x20, 0x36, 0x06, 0x00, 0x00, 0x00}, 1},787 {{0x1b, 0x10, 0x26, 0x00, 0x00, 0x00}, 1},788 {{0x12, 0x27, 0x01, 0x00, 0x00, 0x00}, 4},789 {{0x1b, 0x76, 0x03, 0x00, 0x00, 0x00}, 1},790 {{0x20, 0x36, 0x05, 0x00, 0x00, 0x00}, 1},791 {{0x1b, 0x00, 0x3f, 0x00, 0x00, 0x00}, 1},792 /* Above is brightness; OEM driver setting is 0x10 */793 {{0x12, 0x27, 0x01, 0x00, 0x00, 0x00}, 4},794 {{0x20, 0x29, 0x30, 0x00, 0x00, 0x00}, 1},795 {{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 1}796 };797 798 return run_start_commands(gspca_dev, vivitar_start_commands,799 ARRAY_SIZE(vivitar_start_commands));800}801 802static int sd_start(struct gspca_dev *gspca_dev)803{804 struct sd *sd = (struct sd *) gspca_dev;805 int err_code;806 807 sd->sof_read = 0;808 809 switch (sd->model) {810 case 0x7005:811 err_code = start_genius_cam(gspca_dev);812 break;813 case 0x7003:814 err_code = start_genius_videocam_live(gspca_dev);815 break;816 case 0x8001:817 err_code = start_spy_cam(gspca_dev);818 break;819 case 0x8003:820 err_code = start_cif_cam(gspca_dev);821 break;822 case 0x8008:823 err_code = start_ms350_cam(gspca_dev);824 break;825 case 0x800a:826 err_code = start_vivitar_cam(gspca_dev);827 break;828 default:829 pr_err("Starting unknown camera, please report this\n");830 return -ENXIO;831 }832 833 sd->avg_lum = -1;834 835 return err_code;836}837 838static void sd_stopN(struct gspca_dev *gspca_dev)839{840 int result;841 __u8 data[6];842 843 result = sn9c2028_read1(gspca_dev);844 if (result < 0)845 gspca_err(gspca_dev, "Camera Stop read failed\n");846 847 memset(data, 0, 6);848 data[0] = 0x14;849 result = sn9c2028_command(gspca_dev, data);850 if (result < 0)851 gspca_err(gspca_dev, "Camera Stop command failed\n");852}853 854static void do_autogain(struct gspca_dev *gspca_dev, int avg_lum)855{856 struct sd *sd = (struct sd *) gspca_dev;857 s32 cur_gain = v4l2_ctrl_g_ctrl(sd->gain);858 859 if (avg_lum == -1)860 return;861 862 if (avg_lum < MIN_AVG_LUM) {863 if (cur_gain == sd->gain->maximum)864 return;865 cur_gain++;866 v4l2_ctrl_s_ctrl(sd->gain, cur_gain);867 }868 if (avg_lum > MAX_AVG_LUM) {869 if (cur_gain == sd->gain->minimum)870 return;871 cur_gain--;872 v4l2_ctrl_s_ctrl(sd->gain, cur_gain);873 }874 875}876 877static void sd_dqcallback(struct gspca_dev *gspca_dev)878{879 struct sd *sd = (struct sd *) gspca_dev;880 881 if (sd->autogain == NULL || !v4l2_ctrl_g_ctrl(sd->autogain))882 return;883 884 do_autogain(gspca_dev, sd->avg_lum);885}886 887/* Include sn9c2028 sof detection functions */888#include "sn9c2028.h"889 890static void sd_pkt_scan(struct gspca_dev *gspca_dev,891 __u8 *data, /* isoc packet */892 int len) /* iso packet length */893{894 unsigned char *sof;895 896 sof = sn9c2028_find_sof(gspca_dev, data, len);897 if (sof) {898 int n;899 900 /* finish decoding current frame */901 n = sof - data;902 if (n > sizeof sn9c2028_sof_marker)903 n -= sizeof sn9c2028_sof_marker;904 else905 n = 0;906 gspca_frame_add(gspca_dev, LAST_PACKET, data, n);907 /* Start next frame. */908 gspca_frame_add(gspca_dev, FIRST_PACKET,909 sn9c2028_sof_marker, sizeof sn9c2028_sof_marker);910 len -= sof - data;911 data = sof;912 }913 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);914}915 916/* sub-driver description */917static const struct sd_desc sd_desc = {918 .name = MODULE_NAME,919 .config = sd_config,920 .init = sd_init,921 .init_controls = sd_init_controls,922 .start = sd_start,923 .stopN = sd_stopN,924 .dq_callback = sd_dqcallback,925 .pkt_scan = sd_pkt_scan,926};927 928/* -- module initialisation -- */929static const struct usb_device_id device_table[] = {930 {USB_DEVICE(0x0458, 0x7005)}, /* Genius Smart 300, version 2 */931 {USB_DEVICE(0x0458, 0x7003)}, /* Genius Videocam Live v2 */932 /* The Genius Smart is untested. I can't find an owner ! */933 /* {USB_DEVICE(0x0c45, 0x8000)}, DC31VC, Don't know this camera */934 {USB_DEVICE(0x0c45, 0x8001)}, /* Wild Planet digital spy cam */935 {USB_DEVICE(0x0c45, 0x8003)}, /* Several small CIF cameras */936 /* {USB_DEVICE(0x0c45, 0x8006)}, Unknown VGA camera */937 {USB_DEVICE(0x0c45, 0x8008)}, /* Mini-Shotz ms-350 */938 {USB_DEVICE(0x0c45, 0x800a)}, /* Vivicam 3350B */939 {}940};941MODULE_DEVICE_TABLE(usb, device_table);942 943/* -- device connect -- */944static int sd_probe(struct usb_interface *intf,945 const struct usb_device_id *id)946{947 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),948 THIS_MODULE);949}950 951static struct usb_driver sd_driver = {952 .name = MODULE_NAME,953 .id_table = device_table,954 .probe = sd_probe,955 .disconnect = gspca_disconnect,956#ifdef CONFIG_PM957 .suspend = gspca_suspend,958 .resume = gspca_resume,959 .reset_resume = gspca_resume,960#endif961};962 963module_usb_driver(sd_driver);964