1/* 2 * SN9C2028 library 3 * 4 * Copyright (C) 2009 Theodore Kilgore <kilgota@auburn.edu> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 */ 20 21#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 22 23#define MODULE_NAME "sn9c2028" 24 25#include "gspca.h" 26 27MODULE_AUTHOR("Theodore Kilgore"); 28MODULE_DESCRIPTION("Sonix SN9C2028 USB Camera Driver"); 29MODULE_LICENSE("GPL"); 30 31/* specific webcam descriptor */ 32struct sd { 33 struct gspca_dev gspca_dev; /* !! must be the first item */ 34 u8 sof_read; 35 u16 model; 36}; 37 38struct init_command { 39 unsigned char instruction[6]; 40 unsigned char to_read; /* length to read. 0 means no reply requested */ 41}; 42 43/* How to change the resolution of any of the VGA cams is unknown */ 44static const struct v4l2_pix_format vga_mode[] = { 45 {640, 480, V4L2_PIX_FMT_SN9C2028, V4L2_FIELD_NONE, 46 .bytesperline = 640, 47 .sizeimage = 640 * 480 * 3 / 4, 48 .colorspace = V4L2_COLORSPACE_SRGB, 49 .priv = 0}, 50}; 51 52/* No way to change the resolution of the CIF cams is known */ 53static const struct v4l2_pix_format cif_mode[] = { 54 {352, 288, V4L2_PIX_FMT_SN9C2028, V4L2_FIELD_NONE, 55 .bytesperline = 352, 56 .sizeimage = 352 * 288 * 3 / 4, 57 .colorspace = V4L2_COLORSPACE_SRGB, 58 .priv = 0}, 59}; 60 61/* the bytes to write are in gspca_dev->usb_buf */ 62static int sn9c2028_command(struct gspca_dev *gspca_dev, u8 *command) 63{ 64 int rc; 65 66 PDEBUG(D_USBO, "sending command %02x%02x%02x%02x%02x%02x", command[0], 67 command[1], command[2], command[3], command[4], command[5]); 68 69 memcpy(gspca_dev->usb_buf, command, 6); 70 rc = usb_control_msg(gspca_dev->dev, 71 usb_sndctrlpipe(gspca_dev->dev, 0), 72 USB_REQ_GET_CONFIGURATION, 73 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, 74 2, 0, gspca_dev->usb_buf, 6, 500); 75 if (rc < 0) { 76 pr_err("command write [%02x] error %d\n", 77 gspca_dev->usb_buf[0], rc); 78 return rc; 79 } 80 81 return 0; 82} 83 84static int sn9c2028_read1(struct gspca_dev *gspca_dev) 85{ 86 int rc; 87 88 rc = usb_control_msg(gspca_dev->dev, 89 usb_rcvctrlpipe(gspca_dev->dev, 0), 90 USB_REQ_GET_STATUS, 91 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, 92 1, 0, gspca_dev->usb_buf, 1, 500); 93 if (rc != 1) { 94 pr_err("read1 error %d\n", rc); 95 return (rc < 0) ? rc : -EIO; 96 } 97 PDEBUG(D_USBI, "read1 response %02x", gspca_dev->usb_buf[0]); 98 return gspca_dev->usb_buf[0]; 99} 100 101static int sn9c2028_read4(struct gspca_dev *gspca_dev, u8 *reading) 102{ 103 int rc; 104 rc = usb_control_msg(gspca_dev->dev, 105 usb_rcvctrlpipe(gspca_dev->dev, 0), 106 USB_REQ_GET_STATUS, 107 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, 108 4, 0, gspca_dev->usb_buf, 4, 500); 109 if (rc != 4) { 110 pr_err("read4 error %d\n", rc); 111 return (rc < 0) ? rc : -EIO; 112 } 113 memcpy(reading, gspca_dev->usb_buf, 4); 114 PDEBUG(D_USBI, "read4 response %02x%02x%02x%02x", reading[0], 115 reading[1], reading[2], reading[3]); 116 return rc; 117} 118 119static int sn9c2028_long_command(struct gspca_dev *gspca_dev, u8 *command) 120{ 121 int i, status; 122 __u8 reading[4]; 123 124 status = sn9c2028_command(gspca_dev, command); 125 if (status < 0) 126 return status; 127 128 status = -1; 129 for (i = 0; i < 256 && status < 2; i++) 130 status = sn9c2028_read1(gspca_dev); 131 if (status != 2) { 132 pr_err("long command status read error %d\n", status); 133 return (status < 0) ? status : -EIO; 134 } 135 136 memset(reading, 0, 4); 137 status = sn9c2028_read4(gspca_dev, reading); 138 if (status < 0) 139 return status; 140 141 /* in general, the first byte of the response is the first byte of 142 * the command, or'ed with 8 */ 143 status = sn9c2028_read1(gspca_dev); 144 if (status < 0) 145 return status; 146 147 return 0; 148} 149 150static int sn9c2028_short_command(struct gspca_dev *gspca_dev, u8 *command) 151{ 152 int err_code; 153 154 err_code = sn9c2028_command(gspca_dev, command); 155 if (err_code < 0) 156 return err_code; 157 158 err_code = sn9c2028_read1(gspca_dev); 159 if (err_code < 0) 160 return err_code; 161 162 return 0; 163} 164 165/* this function is called at probe time */ 166static int sd_config(struct gspca_dev *gspca_dev, 167 const struct usb_device_id *id) 168{ 169 struct sd *sd = (struct sd *) gspca_dev; 170 struct cam *cam = &gspca_dev->cam; 171 172 PDEBUG(D_PROBE, "SN9C2028 camera detected (vid/pid 0x%04X:0x%04X)", 173 id->idVendor, id->idProduct); 174 175 sd->model = id->idProduct; 176 177 switch (sd->model) { 178 case 0x7005: 179 PDEBUG(D_PROBE, "Genius Smart 300 camera"); 180 break; 181 case 0x8000: 182 PDEBUG(D_PROBE, "DC31VC"); 183 break; 184 case 0x8001: 185 PDEBUG(D_PROBE, "Spy camera"); 186 break; 187 case 0x8003: 188 PDEBUG(D_PROBE, "CIF camera"); 189 break; 190 case 0x8008: 191 PDEBUG(D_PROBE, "Mini-Shotz ms-350 camera"); 192 break; 193 case 0x800a: 194 PDEBUG(D_PROBE, "Vivitar 3350b type camera"); 195 cam->input_flags = V4L2_IN_ST_VFLIP | V4L2_IN_ST_HFLIP; 196 break; 197 } 198 199 switch (sd->model) { 200 case 0x8000: 201 case 0x8001: 202 case 0x8003: 203 cam->cam_mode = cif_mode; 204 cam->nmodes = ARRAY_SIZE(cif_mode); 205 break; 206 default: 207 cam->cam_mode = vga_mode; 208 cam->nmodes = ARRAY_SIZE(vga_mode); 209 } 210 return 0; 211} 212 213/* this function is called at probe and resume time */ 214static int sd_init(struct gspca_dev *gspca_dev) 215{ 216 int status = -1; 217 218 sn9c2028_read1(gspca_dev); 219 sn9c2028_read1(gspca_dev); 220 status = sn9c2028_read1(gspca_dev); 221 222 return (status < 0) ? status : 0; 223} 224 225static int run_start_commands(struct gspca_dev *gspca_dev, 226 struct init_command *cam_commands, int n) 227{ 228 int i, err_code = -1; 229 230 for (i = 0; i < n; i++) { 231 switch (cam_commands[i].to_read) { 232 case 4: 233 err_code = sn9c2028_long_command(gspca_dev, 234 cam_commands[i].instruction); 235 break; 236 case 1: 237 err_code = sn9c2028_short_command(gspca_dev, 238 cam_commands[i].instruction); 239 break; 240 case 0: 241 err_code = sn9c2028_command(gspca_dev, 242 cam_commands[i].instruction); 243 break; 244 } 245 if (err_code < 0) 246 return err_code; 247 } 248 return 0; 249} 250 251static int start_spy_cam(struct gspca_dev *gspca_dev) 252{ 253 struct init_command spy_start_commands[] = { 254 {{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4}, 255 {{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4}, 256 {{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4}, 257 {{0x13, 0x22, 0x01, 0x04, 0x00, 0x00}, 4}, 258 {{0x13, 0x23, 0x01, 0x03, 0x00, 0x00}, 4}, 259 {{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4}, 260 {{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4}, /* width 352 */ 261 {{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4}, /* height 288 */ 262 /* {{0x13, 0x27, 0x01, 0x28, 0x00, 0x00}, 4}, */ 263 {{0x13, 0x27, 0x01, 0x68, 0x00, 0x00}, 4}, 264 {{0x13, 0x28, 0x01, 0x09, 0x00, 0x00}, 4}, /* red gain ?*/ 265 /* {{0x13, 0x28, 0x01, 0x00, 0x00, 0x00}, 4}, */ 266 {{0x13, 0x29, 0x01, 0x00, 0x00, 0x00}, 4}, 267 /* {{0x13, 0x29, 0x01, 0x0c, 0x00, 0x00}, 4}, */ 268 {{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4}, 269 {{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4}, 270 /* {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4}, */ 271 {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4}, 272 {{0x13, 0x2d, 0x01, 0x02, 0x00, 0x00}, 4}, 273 /* {{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4}, */ 274 {{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4}, 275 {{0x13, 0x2f, 0x01, 0x07, 0x00, 0x00}, 4}, 276 {{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4}, 277 {{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4}, 278 {{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4}, 279 {{0x11, 0x02, 0x06, 0x00, 0x00, 0x00}, 4}, 280 {{0x11, 0x03, 0x13, 0x00, 0x00, 0x00}, 4}, /*don't mess with*/ 281 /*{{0x11, 0x04, 0x06, 0x00, 0x00, 0x00}, 4}, observed */ 282 {{0x11, 0x04, 0x00, 0x00, 0x00, 0x00}, 4}, /* brighter */ 283 /*{{0x11, 0x05, 0x65, 0x00, 0x00, 0x00}, 4}, observed */ 284 {{0x11, 0x05, 0x00, 0x00, 0x00, 0x00}, 4}, /* brighter */ 285 {{0x11, 0x06, 0xb1, 0x00, 0x00, 0x00}, 4}, /* observed */ 286 {{0x11, 0x07, 0x00, 0x00, 0x00, 0x00}, 4}, 287 /*{{0x11, 0x08, 0x06, 0x00, 0x00, 0x00}, 4}, observed */ 288 {{0x11, 0x08, 0x0b, 0x00, 0x00, 0x00}, 4}, 289 {{0x11, 0x09, 0x01, 0x00, 0x00, 0x00}, 4}, 290 {{0x11, 0x0a, 0x01, 0x00, 0x00, 0x00}, 4}, 291 {{0x11, 0x0b, 0x01, 0x00, 0x00, 0x00}, 4}, 292 {{0x11, 0x0c, 0x01, 0x00, 0x00, 0x00}, 4}, 293 {{0x11, 0x0d, 0x00, 0x00, 0x00, 0x00}, 4}, 294 {{0x11, 0x0e, 0x04, 0x00, 0x00, 0x00}, 4}, 295 /* {{0x11, 0x0f, 0x00, 0x00, 0x00, 0x00}, 4}, */ 296 /* brightness or gain. 0 is default. 4 is good 297 * indoors at night with incandescent lighting */ 298 {{0x11, 0x0f, 0x04, 0x00, 0x00, 0x00}, 4}, 299 {{0x11, 0x10, 0x06, 0x00, 0x00, 0x00}, 4}, /*hstart or hoffs*/ 300 {{0x11, 0x11, 0x06, 0x00, 0x00, 0x00}, 4}, 301 {{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4}, 302 {{0x11, 0x14, 0x02, 0x00, 0x00, 0x00}, 4}, 303 {{0x11, 0x13, 0x01, 0x00, 0x00, 0x00}, 4}, 304 /* {{0x1b, 0x02, 0x06, 0x00, 0x00, 0x00}, 1}, observed */ 305 {{0x1b, 0x02, 0x11, 0x00, 0x00, 0x00}, 1}, /* brighter */ 306 /* {{0x1b, 0x13, 0x01, 0x00, 0x00, 0x00}, 1}, observed */ 307 {{0x1b, 0x13, 0x11, 0x00, 0x00, 0x00}, 1}, 308 {{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 1}, /* compresses */ 309 /* Camera should start to capture now. */ 310 }; 311 312 return run_start_commands(gspca_dev, spy_start_commands, 313 ARRAY_SIZE(spy_start_commands)); 314} 315 316static int start_cif_cam(struct gspca_dev *gspca_dev) 317{ 318 struct init_command cif_start_commands[] = { 319 {{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4}, 320 /* The entire sequence below seems redundant */ 321 /* {{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4}, 322 {{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4}, 323 {{0x13, 0x22, 0x01, 0x06, 0x00, 0x00}, 4}, 324 {{0x13, 0x23, 0x01, 0x02, 0x00, 0x00}, 4}, 325 {{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4}, 326 {{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4}, width? 327 {{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4}, height? 328 {{0x13, 0x27, 0x01, 0x68, 0x00, 0x00}, 4}, subsample? 329 {{0x13, 0x28, 0x01, 0x00, 0x00, 0x00}, 4}, 330 {{0x13, 0x29, 0x01, 0x20, 0x00, 0x00}, 4}, 331 {{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4}, 332 {{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4}, 333 {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4}, 334 {{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4}, 335 {{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4}, 336 {{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4}, 337 {{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4}, 338 {{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4}, 339 {{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4},*/ 340 {{0x1b, 0x21, 0x00, 0x00, 0x00, 0x00}, 1}, 341 {{0x1b, 0x17, 0x00, 0x00, 0x00, 0x00}, 1}, 342 {{0x1b, 0x19, 0x00, 0x00, 0x00, 0x00}, 1}, 343 {{0x1b, 0x02, 0x06, 0x00, 0x00, 0x00}, 1}, 344 {{0x1b, 0x03, 0x5a, 0x00, 0x00, 0x00}, 1}, 345 {{0x1b, 0x04, 0x27, 0x00, 0x00, 0x00}, 1}, 346 {{0x1b, 0x05, 0x01, 0x00, 0x00, 0x00}, 1}, 347 {{0x1b, 0x12, 0x14, 0x00, 0x00, 0x00}, 1}, 348 {{0x1b, 0x13, 0x00, 0x00, 0x00, 0x00}, 1}, 349 {{0x1b, 0x14, 0x00, 0x00, 0x00, 0x00}, 1}, 350 {{0x1b, 0x15, 0x00, 0x00, 0x00, 0x00}, 1}, 351 {{0x1b, 0x16, 0x00, 0x00, 0x00, 0x00}, 1}, 352 {{0x1b, 0x77, 0xa2, 0x00, 0x00, 0x00}, 1}, 353 {{0x1b, 0x06, 0x0f, 0x00, 0x00, 0x00}, 1}, 354 {{0x1b, 0x07, 0x14, 0x00, 0x00, 0x00}, 1}, 355 {{0x1b, 0x08, 0x0f, 0x00, 0x00, 0x00}, 1}, 356 {{0x1b, 0x09, 0x10, 0x00, 0x00, 0x00}, 1}, 357 {{0x1b, 0x0e, 0x00, 0x00, 0x00, 0x00}, 1}, 358 {{0x1b, 0x0f, 0x00, 0x00, 0x00, 0x00}, 1}, 359 {{0x1b, 0x12, 0x07, 0x00, 0x00, 0x00}, 1}, 360 {{0x1b, 0x10, 0x1f, 0x00, 0x00, 0x00}, 1}, 361 {{0x1b, 0x11, 0x01, 0x00, 0x00, 0x00}, 1}, 362 {{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 1}, /* width/8 */ 363 {{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 1}, /* height/8 */ 364 /* {{0x13, 0x27, 0x01, 0x68, 0x00, 0x00}, 4}, subsample? 365 * {{0x13, 0x28, 0x01, 0x1e, 0x00, 0x00}, 4}, does nothing 366 * {{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4}, */ 367 /* {{0x13, 0x29, 0x01, 0x22, 0x00, 0x00}, 4}, 368 * causes subsampling 369 * but not a change in the resolution setting! */ 370 {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4}, 371 {{0x13, 0x2d, 0x01, 0x01, 0x00, 0x00}, 4}, 372 {{0x13, 0x2e, 0x01, 0x08, 0x00, 0x00}, 4}, 373 {{0x13, 0x2f, 0x01, 0x06, 0x00, 0x00}, 4}, 374 {{0x13, 0x28, 0x01, 0x00, 0x00, 0x00}, 4}, 375 {{0x1b, 0x04, 0x6d, 0x00, 0x00, 0x00}, 1}, 376 {{0x1b, 0x05, 0x03, 0x00, 0x00, 0x00}, 1}, 377 {{0x20, 0x36, 0x06, 0x00, 0x00, 0x00}, 1}, 378 {{0x1b, 0x0e, 0x01, 0x00, 0x00, 0x00}, 1}, 379 {{0x12, 0x27, 0x01, 0x00, 0x00, 0x00}, 4}, 380 {{0x1b, 0x0f, 0x00, 0x00, 0x00, 0x00}, 1}, 381 {{0x20, 0x36, 0x05, 0x00, 0x00, 0x00}, 1}, 382 {{0x1b, 0x10, 0x0f, 0x00, 0x00, 0x00}, 1}, 383 {{0x1b, 0x02, 0x06, 0x00, 0x00, 0x00}, 1}, 384 {{0x1b, 0x11, 0x01, 0x00, 0x00, 0x00}, 1}, 385 {{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 1},/* use compression */ 386 /* Camera should start to capture now. */ 387 }; 388 389 return run_start_commands(gspca_dev, cif_start_commands, 390 ARRAY_SIZE(cif_start_commands)); 391} 392 393static int start_ms350_cam(struct gspca_dev *gspca_dev) 394{ 395 struct init_command ms350_start_commands[] = { 396 {{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4}, 397 {{0x16, 0x01, 0x00, 0x00, 0x00, 0x00}, 4}, 398 {{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4}, 399 {{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4}, 400 {{0x13, 0x22, 0x01, 0x04, 0x00, 0x00}, 4}, 401 {{0x13, 0x23, 0x01, 0x03, 0x00, 0x00}, 4}, 402 {{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4}, 403 {{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4}, 404 {{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4}, 405 {{0x13, 0x27, 0x01, 0x28, 0x00, 0x00}, 4}, 406 {{0x13, 0x28, 0x01, 0x09, 0x00, 0x00}, 4}, 407 {{0x13, 0x29, 0x01, 0x00, 0x00, 0x00}, 4}, 408 {{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4}, 409 {{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4}, 410 {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4}, 411 {{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4}, 412 {{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4}, 413 {{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4}, 414 {{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4}, 415 {{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4}, 416 {{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4}, 417 {{0x11, 0x00, 0x01, 0x00, 0x00, 0x00}, 4}, 418 {{0x11, 0x01, 0x70, 0x00, 0x00, 0x00}, 4}, 419 {{0x11, 0x02, 0x05, 0x00, 0x00, 0x00}, 4}, 420 {{0x11, 0x03, 0x5d, 0x00, 0x00, 0x00}, 4}, 421 {{0x11, 0x04, 0x07, 0x00, 0x00, 0x00}, 4}, 422 {{0x11, 0x05, 0x25, 0x00, 0x00, 0x00}, 4}, 423 {{0x11, 0x06, 0x00, 0x00, 0x00, 0x00}, 4}, 424 {{0x11, 0x07, 0x09, 0x00, 0x00, 0x00}, 4}, 425 {{0x11, 0x08, 0x01, 0x00, 0x00, 0x00}, 4}, 426 {{0x11, 0x09, 0x00, 0x00, 0x00, 0x00}, 4}, 427 {{0x11, 0x0a, 0x00, 0x00, 0x00, 0x00}, 4}, 428 {{0x11, 0x0b, 0x01, 0x00, 0x00, 0x00}, 4}, 429 {{0x11, 0x0c, 0x00, 0x00, 0x00, 0x00}, 4}, 430 {{0x11, 0x0d, 0x0c, 0x00, 0x00, 0x00}, 4}, 431 {{0x11, 0x0e, 0x01, 0x00, 0x00, 0x00}, 4}, 432 {{0x11, 0x0f, 0x00, 0x00, 0x00, 0x00}, 4}, 433 {{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4}, 434 {{0x11, 0x11, 0x00, 0x00, 0x00, 0x00}, 4}, 435 {{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4}, 436 {{0x11, 0x13, 0x63, 0x00, 0x00, 0x00}, 4}, 437 {{0x11, 0x15, 0x70, 0x00, 0x00, 0x00}, 4}, 438 {{0x11, 0x18, 0x00, 0x00, 0x00, 0x00}, 4}, 439 {{0x11, 0x11, 0x01, 0x00, 0x00, 0x00}, 4}, 440 {{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4}, /* width */ 441 {{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4}, /* height */ 442 {{0x13, 0x28, 0x01, 0x09, 0x00, 0x00}, 4}, /* vstart? */ 443 {{0x13, 0x27, 0x01, 0x28, 0x00, 0x00}, 4}, 444 {{0x13, 0x29, 0x01, 0x40, 0x00, 0x00}, 4}, /* hstart? */ 445 {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4}, 446 {{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4}, 447 {{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4}, 448 {{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4}, 449 {{0x1b, 0x02, 0x05, 0x00, 0x00, 0x00}, 1}, 450 {{0x1b, 0x11, 0x01, 0x00, 0x00, 0x00}, 1}, 451 {{0x20, 0x18, 0x00, 0x00, 0x00, 0x00}, 1}, 452 {{0x1b, 0x02, 0x0a, 0x00, 0x00, 0x00}, 1}, 453 {{0x1b, 0x11, 0x01, 0x00, 0x00, 0x00}, 0}, 454 /* Camera should start to capture now. */ 455 }; 456 457 return run_start_commands(gspca_dev, ms350_start_commands, 458 ARRAY_SIZE(ms350_start_commands)); 459} 460 461static int start_genius_cam(struct gspca_dev *gspca_dev) 462{ 463 struct init_command genius_start_commands[] = { 464 {{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4}, 465 {{0x16, 0x01, 0x00, 0x00, 0x00, 0x00}, 4}, 466 {{0x10, 0x00, 0x00, 0x00, 0x00, 0x00}, 4}, 467 {{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4}, 468 {{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4}, 469 /* "preliminary" width and height settings */ 470 {{0x13, 0x28, 0x01, 0x0e, 0x00, 0x00}, 4}, 471 {{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4}, 472 {{0x13, 0x29, 0x01, 0x22, 0x00, 0x00}, 4}, 473 {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4}, 474 {{0x13, 0x2d, 0x01, 0x02, 0x00, 0x00}, 4}, 475 {{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4}, 476 {{0x13, 0x2f, 0x01, 0x07, 0x00, 0x00}, 4}, 477 {{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4}, 478 {{0x11, 0x21, 0x2d, 0x00, 0x00, 0x00}, 4}, 479 {{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4}, 480 {{0x11, 0x23, 0x03, 0x00, 0x00, 0x00}, 4}, 481 {{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4}, 482 {{0x11, 0x11, 0x64, 0x00, 0x00, 0x00}, 4}, 483 {{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4}, 484 {{0x11, 0x13, 0x91, 0x00, 0x00, 0x00}, 4}, 485 {{0x11, 0x14, 0x01, 0x00, 0x00, 0x00}, 4}, 486 {{0x11, 0x15, 0x20, 0x00, 0x00, 0x00}, 4}, 487 {{0x11, 0x16, 0x01, 0x00, 0x00, 0x00}, 4}, 488 {{0x11, 0x17, 0x60, 0x00, 0x00, 0x00}, 4}, 489 {{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4}, 490 {{0x11, 0x21, 0x2d, 0x00, 0x00, 0x00}, 4}, 491 {{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4}, 492 {{0x11, 0x23, 0x03, 0x00, 0x00, 0x00}, 4}, 493 {{0x11, 0x25, 0x00, 0x00, 0x00, 0x00}, 4}, 494 {{0x11, 0x26, 0x02, 0x00, 0x00, 0x00}, 4}, 495 {{0x11, 0x27, 0x88, 0x00, 0x00, 0x00}, 4}, 496 {{0x11, 0x30, 0x38, 0x00, 0x00, 0x00}, 4}, 497 {{0x11, 0x31, 0x2a, 0x00, 0x00, 0x00}, 4}, 498 {{0x11, 0x32, 0x2a, 0x00, 0x00, 0x00}, 4}, 499 {{0x11, 0x33, 0x2a, 0x00, 0x00, 0x00}, 4}, 500 {{0x11, 0x34, 0x02, 0x00, 0x00, 0x00}, 4}, 501 {{0x11, 0x5b, 0x0a, 0x00, 0x00, 0x00}, 4}, 502 {{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4}, /* real width */ 503 {{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4}, /* real height */ 504 {{0x13, 0x28, 0x01, 0x0e, 0x00, 0x00}, 4}, 505 {{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4}, 506 {{0x13, 0x29, 0x01, 0x62, 0x00, 0x00}, 4}, 507 {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4}, 508 {{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4}, 509 {{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4}, 510 {{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4}, 511 {{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4}, 512 {{0x11, 0x21, 0x2a, 0x00, 0x00, 0x00}, 4}, 513 {{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4}, 514 {{0x11, 0x23, 0x28, 0x00, 0x00, 0x00}, 4}, 515 {{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4}, 516 {{0x11, 0x11, 0x04, 0x00, 0x00, 0x00}, 4}, 517 {{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4}, 518 {{0x11, 0x13, 0x03, 0x00, 0x00, 0x00}, 4}, 519 {{0x11, 0x14, 0x01, 0x00, 0x00, 0x00}, 4}, 520 {{0x11, 0x15, 0xe0, 0x00, 0x00, 0x00}, 4}, 521 {{0x11, 0x16, 0x02, 0x00, 0x00, 0x00}, 4}, 522 {{0x11, 0x17, 0x80, 0x00, 0x00, 0x00}, 4}, 523 {{0x1c, 0x20, 0x00, 0x2a, 0x00, 0x00}, 1}, 524 {{0x1c, 0x20, 0x00, 0x2a, 0x00, 0x00}, 1}, 525 {{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 0} 526 /* Camera should start to capture now. */ 527 }; 528 529 return run_start_commands(gspca_dev, genius_start_commands, 530 ARRAY_SIZE(genius_start_commands)); 531} 532 533static int start_vivitar_cam(struct gspca_dev *gspca_dev) 534{ 535 struct init_command vivitar_start_commands[] = { 536 {{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4}, 537 {{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4}, 538 {{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4}, 539 {{0x13, 0x22, 0x01, 0x01, 0x00, 0x00}, 4}, 540 {{0x13, 0x23, 0x01, 0x01, 0x00, 0x00}, 4}, 541 {{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4}, 542 {{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4}, 543 {{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4}, 544 {{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4}, 545 {{0x13, 0x28, 0x01, 0x0a, 0x00, 0x00}, 4}, 546 /* 547 * Above is changed from OEM 0x0b. Fixes Bayer tiling. 548 * Presumably gives a vertical shift of one row. 549 */ 550 {{0x13, 0x29, 0x01, 0x20, 0x00, 0x00}, 4}, 551 /* Above seems to do horizontal shift. */ 552 {{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4}, 553 {{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4}, 554 {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4}, 555 {{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4}, 556 {{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4}, 557 {{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4}, 558 /* Above three commands seem to relate to brightness. */ 559 {{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4}, 560 {{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4}, 561 {{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4}, 562 {{0x1b, 0x12, 0x80, 0x00, 0x00, 0x00}, 1}, 563 {{0x1b, 0x01, 0x77, 0x00, 0x00, 0x00}, 1}, 564 {{0x1b, 0x02, 0x3a, 0x00, 0x00, 0x00}, 1}, 565 {{0x1b, 0x12, 0x78, 0x00, 0x00, 0x00}, 1}, 566 {{0x1b, 0x13, 0x00, 0x00, 0x00, 0x00}, 1}, 567 {{0x1b, 0x14, 0x80, 0x00, 0x00, 0x00}, 1}, 568 {{0x1b, 0x15, 0x34, 0x00, 0x00, 0x00}, 1}, 569 {{0x1b, 0x1b, 0x04, 0x00, 0x00, 0x00}, 1}, 570 {{0x1b, 0x20, 0x44, 0x00, 0x00, 0x00}, 1}, 571 {{0x1b, 0x23, 0xee, 0x00, 0x00, 0x00}, 1}, 572 {{0x1b, 0x26, 0xa0, 0x00, 0x00, 0x00}, 1}, 573 {{0x1b, 0x27, 0x9a, 0x00, 0x00, 0x00}, 1}, 574 {{0x1b, 0x28, 0xa0, 0x00, 0x00, 0x00}, 1}, 575 {{0x1b, 0x29, 0x30, 0x00, 0x00, 0x00}, 1}, 576 {{0x1b, 0x2a, 0x80, 0x00, 0x00, 0x00}, 1}, 577 {{0x1b, 0x2b, 0x00, 0x00, 0x00, 0x00}, 1}, 578 {{0x1b, 0x2f, 0x3d, 0x00, 0x00, 0x00}, 1}, 579 {{0x1b, 0x30, 0x24, 0x00, 0x00, 0x00}, 1}, 580 {{0x1b, 0x32, 0x86, 0x00, 0x00, 0x00}, 1}, 581 {{0x1b, 0x60, 0xa9, 0x00, 0x00, 0x00}, 1}, 582 {{0x1b, 0x61, 0x42, 0x00, 0x00, 0x00}, 1}, 583 {{0x1b, 0x65, 0x00, 0x00, 0x00, 0x00}, 1}, 584 {{0x1b, 0x69, 0x38, 0x00, 0x00, 0x00}, 1}, 585 {{0x1b, 0x6f, 0x88, 0x00, 0x00, 0x00}, 1}, 586 {{0x1b, 0x70, 0x0b, 0x00, 0x00, 0x00}, 1}, 587 {{0x1b, 0x71, 0x00, 0x00, 0x00, 0x00}, 1}, 588 {{0x1b, 0x74, 0x21, 0x00, 0x00, 0x00}, 1}, 589 {{0x1b, 0x75, 0x86, 0x00, 0x00, 0x00}, 1}, 590 {{0x1b, 0x76, 0x00, 0x00, 0x00, 0x00}, 1}, 591 {{0x1b, 0x7d, 0xf3, 0x00, 0x00, 0x00}, 1}, 592 {{0x1b, 0x17, 0x1c, 0x00, 0x00, 0x00}, 1}, 593 {{0x1b, 0x18, 0xc0, 0x00, 0x00, 0x00}, 1}, 594 {{0x1b, 0x19, 0x05, 0x00, 0x00, 0x00}, 1}, 595 {{0x1b, 0x1a, 0xf6, 0x00, 0x00, 0x00}, 1}, 596 /* {{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4}, 597 {{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4}, 598 {{0x13, 0x28, 0x01, 0x0b, 0x00, 0x00}, 4}, */ 599 {{0x20, 0x36, 0x06, 0x00, 0x00, 0x00}, 1}, 600 {{0x1b, 0x10, 0x26, 0x00, 0x00, 0x00}, 1}, 601 {{0x12, 0x27, 0x01, 0x00, 0x00, 0x00}, 4}, 602 {{0x1b, 0x76, 0x03, 0x00, 0x00, 0x00}, 1}, 603 {{0x20, 0x36, 0x05, 0x00, 0x00, 0x00}, 1}, 604 {{0x1b, 0x00, 0x3f, 0x00, 0x00, 0x00}, 1}, 605 /* Above is brightness; OEM driver setting is 0x10 */ 606 {{0x12, 0x27, 0x01, 0x00, 0x00, 0x00}, 4}, 607 {{0x20, 0x29, 0x30, 0x00, 0x00, 0x00}, 1}, 608 {{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 1} 609 }; 610 611 return run_start_commands(gspca_dev, vivitar_start_commands, 612 ARRAY_SIZE(vivitar_start_commands)); 613} 614 615static int sd_start(struct gspca_dev *gspca_dev) 616{ 617 struct sd *sd = (struct sd *) gspca_dev; 618 int err_code; 619 620 sd->sof_read = 0; 621 622 switch (sd->model) { 623 case 0x7005: 624 err_code = start_genius_cam(gspca_dev); 625 break; 626 case 0x8001: 627 err_code = start_spy_cam(gspca_dev); 628 break; 629 case 0x8003: 630 err_code = start_cif_cam(gspca_dev); 631 break; 632 case 0x8008: 633 err_code = start_ms350_cam(gspca_dev); 634 break; 635 case 0x800a: 636 err_code = start_vivitar_cam(gspca_dev); 637 break; 638 default: 639 pr_err("Starting unknown camera, please report this\n"); 640 return -ENXIO; 641 } 642 643 return err_code; 644} 645 646static void sd_stopN(struct gspca_dev *gspca_dev) 647{ 648 int result; 649 __u8 data[6]; 650 651 result = sn9c2028_read1(gspca_dev); 652 if (result < 0) 653 PERR("Camera Stop read failed"); 654 655 memset(data, 0, 6); 656 data[0] = 0x14; 657 result = sn9c2028_command(gspca_dev, data); 658 if (result < 0) 659 PERR("Camera Stop command failed"); 660} 661 662/* Include sn9c2028 sof detection functions */ 663#include "sn9c2028.h" 664 665static void sd_pkt_scan(struct gspca_dev *gspca_dev, 666 __u8 *data, /* isoc packet */ 667 int len) /* iso packet length */ 668{ 669 unsigned char *sof; 670 671 sof = sn9c2028_find_sof(gspca_dev, data, len); 672 if (sof) { 673 int n; 674 675 /* finish decoding current frame */ 676 n = sof - data; 677 if (n > sizeof sn9c2028_sof_marker) 678 n -= sizeof sn9c2028_sof_marker; 679 else 680 n = 0; 681 gspca_frame_add(gspca_dev, LAST_PACKET, data, n); 682 /* Start next frame. */ 683 gspca_frame_add(gspca_dev, FIRST_PACKET, 684 sn9c2028_sof_marker, sizeof sn9c2028_sof_marker); 685 len -= sof - data; 686 data = sof; 687 } 688 gspca_frame_add(gspca_dev, INTER_PACKET, data, len); 689} 690 691/* sub-driver description */ 692static const struct sd_desc sd_desc = { 693 .name = MODULE_NAME, 694 .config = sd_config, 695 .init = sd_init, 696 .start = sd_start, 697 .stopN = sd_stopN, 698 .pkt_scan = sd_pkt_scan, 699}; 700 701/* -- module initialisation -- */ 702static const struct usb_device_id device_table[] = { 703 {USB_DEVICE(0x0458, 0x7005)}, /* Genius Smart 300, version 2 */ 704 /* The Genius Smart is untested. I can't find an owner ! */ 705 /* {USB_DEVICE(0x0c45, 0x8000)}, DC31VC, Don't know this camera */ 706 {USB_DEVICE(0x0c45, 0x8001)}, /* Wild Planet digital spy cam */ 707 {USB_DEVICE(0x0c45, 0x8003)}, /* Several small CIF cameras */ 708 /* {USB_DEVICE(0x0c45, 0x8006)}, Unknown VGA camera */ 709 {USB_DEVICE(0x0c45, 0x8008)}, /* Mini-Shotz ms-350 */ 710 {USB_DEVICE(0x0c45, 0x800a)}, /* Vivicam 3350B */ 711 {} 712}; 713MODULE_DEVICE_TABLE(usb, device_table); 714 715/* -- device connect -- */ 716static int sd_probe(struct usb_interface *intf, 717 const struct usb_device_id *id) 718{ 719 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), 720 THIS_MODULE); 721} 722 723static struct usb_driver sd_driver = { 724 .name = MODULE_NAME, 725 .id_table = device_table, 726 .probe = sd_probe, 727 .disconnect = gspca_disconnect, 728#ifdef CONFIG_PM 729 .suspend = gspca_suspend, 730 .resume = gspca_resume, 731 .reset_resume = gspca_resume, 732#endif 733}; 734 735module_usb_driver(sd_driver); 736