Path: blob/master/drivers/media/video/gspca/sn9c2028.c
17681 views
/*1* SN9C2028 library2*3* Copyright (C) 2009 Theodore Kilgore <[email protected]>4*5* This program is free software; you can redistribute it and/or modify6* it under the terms of the GNU General Public License as published by7* the Free Software Foundation; either version 2 of the License, or8* any later version.9*10* This program is distributed in the hope that it will be useful,11* but WITHOUT ANY WARRANTY; without even the implied warranty of12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13* GNU General Public License for more details.14*15* You should have received a copy of the GNU General Public License16* along with this program; if not, write to the Free Software17* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA18*/1920#define MODULE_NAME "sn9c2028"2122#include "gspca.h"2324MODULE_AUTHOR("Theodore Kilgore");25MODULE_DESCRIPTION("Sonix SN9C2028 USB Camera Driver");26MODULE_LICENSE("GPL");2728/* specific webcam descriptor */29struct sd {30struct gspca_dev gspca_dev; /* !! must be the first item */31u8 sof_read;32u16 model;33};3435struct init_command {36unsigned char instruction[6];37unsigned char to_read; /* length to read. 0 means no reply requested */38};3940/* V4L2 controls supported by the driver */41static const struct ctrl sd_ctrls[] = {42};4344/* How to change the resolution of any of the VGA cams is unknown */45static const struct v4l2_pix_format vga_mode[] = {46{640, 480, V4L2_PIX_FMT_SN9C2028, V4L2_FIELD_NONE,47.bytesperline = 640,48.sizeimage = 640 * 480 * 3 / 4,49.colorspace = V4L2_COLORSPACE_SRGB,50.priv = 0},51};5253/* No way to change the resolution of the CIF cams is known */54static const struct v4l2_pix_format cif_mode[] = {55{352, 288, V4L2_PIX_FMT_SN9C2028, V4L2_FIELD_NONE,56.bytesperline = 352,57.sizeimage = 352 * 288 * 3 / 4,58.colorspace = V4L2_COLORSPACE_SRGB,59.priv = 0},60};6162/* the bytes to write are in gspca_dev->usb_buf */63static int sn9c2028_command(struct gspca_dev *gspca_dev, u8 *command)64{65int rc;6667PDEBUG(D_USBO, "sending command %02x%02x%02x%02x%02x%02x", command[0],68command[1], command[2], command[3], command[4], command[5]);6970memcpy(gspca_dev->usb_buf, command, 6);71rc = usb_control_msg(gspca_dev->dev,72usb_sndctrlpipe(gspca_dev->dev, 0),73USB_REQ_GET_CONFIGURATION,74USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,752, 0, gspca_dev->usb_buf, 6, 500);76if (rc < 0) {77err("command write [%02x] error %d",78gspca_dev->usb_buf[0], rc);79return rc;80}8182return 0;83}8485static int sn9c2028_read1(struct gspca_dev *gspca_dev)86{87int rc;8889rc = usb_control_msg(gspca_dev->dev,90usb_rcvctrlpipe(gspca_dev->dev, 0),91USB_REQ_GET_STATUS,92USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,931, 0, gspca_dev->usb_buf, 1, 500);94if (rc != 1) {95err("read1 error %d", rc);96return (rc < 0) ? rc : -EIO;97}98PDEBUG(D_USBI, "read1 response %02x", gspca_dev->usb_buf[0]);99return gspca_dev->usb_buf[0];100}101102static int sn9c2028_read4(struct gspca_dev *gspca_dev, u8 *reading)103{104int rc;105rc = usb_control_msg(gspca_dev->dev,106usb_rcvctrlpipe(gspca_dev->dev, 0),107USB_REQ_GET_STATUS,108USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,1094, 0, gspca_dev->usb_buf, 4, 500);110if (rc != 4) {111err("read4 error %d", rc);112return (rc < 0) ? rc : -EIO;113}114memcpy(reading, gspca_dev->usb_buf, 4);115PDEBUG(D_USBI, "read4 response %02x%02x%02x%02x", reading[0],116reading[1], reading[2], reading[3]);117return rc;118}119120static int sn9c2028_long_command(struct gspca_dev *gspca_dev, u8 *command)121{122int i, status;123__u8 reading[4];124125status = sn9c2028_command(gspca_dev, command);126if (status < 0)127return status;128129status = -1;130for (i = 0; i < 256 && status < 2; i++)131status = sn9c2028_read1(gspca_dev);132if (status != 2) {133err("long command status read error %d", status);134return (status < 0) ? status : -EIO;135}136137memset(reading, 0, 4);138status = sn9c2028_read4(gspca_dev, reading);139if (status < 0)140return status;141142/* in general, the first byte of the response is the first byte of143* the command, or'ed with 8 */144status = sn9c2028_read1(gspca_dev);145if (status < 0)146return status;147148return 0;149}150151static int sn9c2028_short_command(struct gspca_dev *gspca_dev, u8 *command)152{153int err_code;154155err_code = sn9c2028_command(gspca_dev, command);156if (err_code < 0)157return err_code;158159err_code = sn9c2028_read1(gspca_dev);160if (err_code < 0)161return err_code;162163return 0;164}165166/* this function is called at probe time */167static int sd_config(struct gspca_dev *gspca_dev,168const struct usb_device_id *id)169{170struct sd *sd = (struct sd *) gspca_dev;171struct cam *cam = &gspca_dev->cam;172173PDEBUG(D_PROBE, "SN9C2028 camera detected (vid/pid 0x%04X:0x%04X)",174id->idVendor, id->idProduct);175176sd->model = id->idProduct;177178switch (sd->model) {179case 0x7005:180PDEBUG(D_PROBE, "Genius Smart 300 camera");181break;182case 0x8000:183PDEBUG(D_PROBE, "DC31VC");184break;185case 0x8001:186PDEBUG(D_PROBE, "Spy camera");187break;188case 0x8003:189PDEBUG(D_PROBE, "CIF camera");190break;191case 0x8008:192PDEBUG(D_PROBE, "Mini-Shotz ms-350 camera");193break;194case 0x800a:195PDEBUG(D_PROBE, "Vivitar 3350b type camera");196cam->input_flags = V4L2_IN_ST_VFLIP | V4L2_IN_ST_HFLIP;197break;198}199200switch (sd->model) {201case 0x8000:202case 0x8001:203case 0x8003:204cam->cam_mode = cif_mode;205cam->nmodes = ARRAY_SIZE(cif_mode);206break;207default:208cam->cam_mode = vga_mode;209cam->nmodes = ARRAY_SIZE(vga_mode);210}211return 0;212}213214/* this function is called at probe and resume time */215static int sd_init(struct gspca_dev *gspca_dev)216{217int status = -1;218219sn9c2028_read1(gspca_dev);220sn9c2028_read1(gspca_dev);221status = sn9c2028_read1(gspca_dev);222223return (status < 0) ? status : 0;224}225226static int run_start_commands(struct gspca_dev *gspca_dev,227struct init_command *cam_commands, int n)228{229int i, err_code = -1;230231for (i = 0; i < n; i++) {232switch (cam_commands[i].to_read) {233case 4:234err_code = sn9c2028_long_command(gspca_dev,235cam_commands[i].instruction);236break;237case 1:238err_code = sn9c2028_short_command(gspca_dev,239cam_commands[i].instruction);240break;241case 0:242err_code = sn9c2028_command(gspca_dev,243cam_commands[i].instruction);244break;245}246if (err_code < 0)247return err_code;248}249return 0;250}251252static int start_spy_cam(struct gspca_dev *gspca_dev)253{254struct init_command spy_start_commands[] = {255{{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},256{{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4},257{{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4},258{{0x13, 0x22, 0x01, 0x04, 0x00, 0x00}, 4},259{{0x13, 0x23, 0x01, 0x03, 0x00, 0x00}, 4},260{{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4},261{{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4}, /* width 352 */262{{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4}, /* height 288 */263/* {{0x13, 0x27, 0x01, 0x28, 0x00, 0x00}, 4}, */264{{0x13, 0x27, 0x01, 0x68, 0x00, 0x00}, 4},265{{0x13, 0x28, 0x01, 0x09, 0x00, 0x00}, 4}, /* red gain ?*/266/* {{0x13, 0x28, 0x01, 0x00, 0x00, 0x00}, 4}, */267{{0x13, 0x29, 0x01, 0x00, 0x00, 0x00}, 4},268/* {{0x13, 0x29, 0x01, 0x0c, 0x00, 0x00}, 4}, */269{{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4},270{{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4},271/* {{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4}, */272{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},273{{0x13, 0x2d, 0x01, 0x02, 0x00, 0x00}, 4},274/* {{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4}, */275{{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4},276{{0x13, 0x2f, 0x01, 0x07, 0x00, 0x00}, 4},277{{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4},278{{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4},279{{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4},280{{0x11, 0x02, 0x06, 0x00, 0x00, 0x00}, 4},281{{0x11, 0x03, 0x13, 0x00, 0x00, 0x00}, 4}, /*don't mess with*/282/*{{0x11, 0x04, 0x06, 0x00, 0x00, 0x00}, 4}, observed */283{{0x11, 0x04, 0x00, 0x00, 0x00, 0x00}, 4}, /* brighter */284/*{{0x11, 0x05, 0x65, 0x00, 0x00, 0x00}, 4}, observed */285{{0x11, 0x05, 0x00, 0x00, 0x00, 0x00}, 4}, /* brighter */286{{0x11, 0x06, 0xb1, 0x00, 0x00, 0x00}, 4}, /* observed */287{{0x11, 0x07, 0x00, 0x00, 0x00, 0x00}, 4},288/*{{0x11, 0x08, 0x06, 0x00, 0x00, 0x00}, 4}, observed */289{{0x11, 0x08, 0x0b, 0x00, 0x00, 0x00}, 4},290{{0x11, 0x09, 0x01, 0x00, 0x00, 0x00}, 4},291{{0x11, 0x0a, 0x01, 0x00, 0x00, 0x00}, 4},292{{0x11, 0x0b, 0x01, 0x00, 0x00, 0x00}, 4},293{{0x11, 0x0c, 0x01, 0x00, 0x00, 0x00}, 4},294{{0x11, 0x0d, 0x00, 0x00, 0x00, 0x00}, 4},295{{0x11, 0x0e, 0x04, 0x00, 0x00, 0x00}, 4},296/* {{0x11, 0x0f, 0x00, 0x00, 0x00, 0x00}, 4}, */297/* brightness or gain. 0 is default. 4 is good298* indoors at night with incandescent lighting */299{{0x11, 0x0f, 0x04, 0x00, 0x00, 0x00}, 4},300{{0x11, 0x10, 0x06, 0x00, 0x00, 0x00}, 4}, /*hstart or hoffs*/301{{0x11, 0x11, 0x06, 0x00, 0x00, 0x00}, 4},302{{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},303{{0x11, 0x14, 0x02, 0x00, 0x00, 0x00}, 4},304{{0x11, 0x13, 0x01, 0x00, 0x00, 0x00}, 4},305/* {{0x1b, 0x02, 0x06, 0x00, 0x00, 0x00}, 1}, observed */306{{0x1b, 0x02, 0x11, 0x00, 0x00, 0x00}, 1}, /* brighter */307/* {{0x1b, 0x13, 0x01, 0x00, 0x00, 0x00}, 1}, observed */308{{0x1b, 0x13, 0x11, 0x00, 0x00, 0x00}, 1},309{{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 1}, /* compresses */310/* Camera should start to capture now. */311};312313return run_start_commands(gspca_dev, spy_start_commands,314ARRAY_SIZE(spy_start_commands));315}316317static int start_cif_cam(struct gspca_dev *gspca_dev)318{319struct init_command cif_start_commands[] = {320{{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},321/* The entire sequence below seems redundant */322/* {{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4},323{{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4},324{{0x13, 0x22, 0x01, 0x06, 0x00, 0x00}, 4},325{{0x13, 0x23, 0x01, 0x02, 0x00, 0x00}, 4},326{{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4},327{{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4}, width?328{{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4}, height?329{{0x13, 0x27, 0x01, 0x68, 0x00, 0x00}, 4}, subsample?330{{0x13, 0x28, 0x01, 0x00, 0x00, 0x00}, 4},331{{0x13, 0x29, 0x01, 0x20, 0x00, 0x00}, 4},332{{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4},333{{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4},334{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},335{{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4},336{{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4},337{{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4},338{{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4},339{{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4},340{{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4},*/341{{0x1b, 0x21, 0x00, 0x00, 0x00, 0x00}, 1},342{{0x1b, 0x17, 0x00, 0x00, 0x00, 0x00}, 1},343{{0x1b, 0x19, 0x00, 0x00, 0x00, 0x00}, 1},344{{0x1b, 0x02, 0x06, 0x00, 0x00, 0x00}, 1},345{{0x1b, 0x03, 0x5a, 0x00, 0x00, 0x00}, 1},346{{0x1b, 0x04, 0x27, 0x00, 0x00, 0x00}, 1},347{{0x1b, 0x05, 0x01, 0x00, 0x00, 0x00}, 1},348{{0x1b, 0x12, 0x14, 0x00, 0x00, 0x00}, 1},349{{0x1b, 0x13, 0x00, 0x00, 0x00, 0x00}, 1},350{{0x1b, 0x14, 0x00, 0x00, 0x00, 0x00}, 1},351{{0x1b, 0x15, 0x00, 0x00, 0x00, 0x00}, 1},352{{0x1b, 0x16, 0x00, 0x00, 0x00, 0x00}, 1},353{{0x1b, 0x77, 0xa2, 0x00, 0x00, 0x00}, 1},354{{0x1b, 0x06, 0x0f, 0x00, 0x00, 0x00}, 1},355{{0x1b, 0x07, 0x14, 0x00, 0x00, 0x00}, 1},356{{0x1b, 0x08, 0x0f, 0x00, 0x00, 0x00}, 1},357{{0x1b, 0x09, 0x10, 0x00, 0x00, 0x00}, 1},358{{0x1b, 0x0e, 0x00, 0x00, 0x00, 0x00}, 1},359{{0x1b, 0x0f, 0x00, 0x00, 0x00, 0x00}, 1},360{{0x1b, 0x12, 0x07, 0x00, 0x00, 0x00}, 1},361{{0x1b, 0x10, 0x1f, 0x00, 0x00, 0x00}, 1},362{{0x1b, 0x11, 0x01, 0x00, 0x00, 0x00}, 1},363{{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 1}, /* width/8 */364{{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 1}, /* height/8 */365/* {{0x13, 0x27, 0x01, 0x68, 0x00, 0x00}, 4}, subsample?366* {{0x13, 0x28, 0x01, 0x1e, 0x00, 0x00}, 4}, does nothing367* {{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4}, */368/* {{0x13, 0x29, 0x01, 0x22, 0x00, 0x00}, 4},369* causes subsampling370* but not a change in the resolution setting! */371{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},372{{0x13, 0x2d, 0x01, 0x01, 0x00, 0x00}, 4},373{{0x13, 0x2e, 0x01, 0x08, 0x00, 0x00}, 4},374{{0x13, 0x2f, 0x01, 0x06, 0x00, 0x00}, 4},375{{0x13, 0x28, 0x01, 0x00, 0x00, 0x00}, 4},376{{0x1b, 0x04, 0x6d, 0x00, 0x00, 0x00}, 1},377{{0x1b, 0x05, 0x03, 0x00, 0x00, 0x00}, 1},378{{0x20, 0x36, 0x06, 0x00, 0x00, 0x00}, 1},379{{0x1b, 0x0e, 0x01, 0x00, 0x00, 0x00}, 1},380{{0x12, 0x27, 0x01, 0x00, 0x00, 0x00}, 4},381{{0x1b, 0x0f, 0x00, 0x00, 0x00, 0x00}, 1},382{{0x20, 0x36, 0x05, 0x00, 0x00, 0x00}, 1},383{{0x1b, 0x10, 0x0f, 0x00, 0x00, 0x00}, 1},384{{0x1b, 0x02, 0x06, 0x00, 0x00, 0x00}, 1},385{{0x1b, 0x11, 0x01, 0x00, 0x00, 0x00}, 1},386{{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 1},/* use compression */387/* Camera should start to capture now. */388};389390return run_start_commands(gspca_dev, cif_start_commands,391ARRAY_SIZE(cif_start_commands));392}393394static int start_ms350_cam(struct gspca_dev *gspca_dev)395{396struct init_command ms350_start_commands[] = {397{{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},398{{0x16, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},399{{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4},400{{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4},401{{0x13, 0x22, 0x01, 0x04, 0x00, 0x00}, 4},402{{0x13, 0x23, 0x01, 0x03, 0x00, 0x00}, 4},403{{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4},404{{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4},405{{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4},406{{0x13, 0x27, 0x01, 0x28, 0x00, 0x00}, 4},407{{0x13, 0x28, 0x01, 0x09, 0x00, 0x00}, 4},408{{0x13, 0x29, 0x01, 0x00, 0x00, 0x00}, 4},409{{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4},410{{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4},411{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},412{{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4},413{{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4},414{{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4},415{{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4},416{{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4},417{{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4},418{{0x11, 0x00, 0x01, 0x00, 0x00, 0x00}, 4},419{{0x11, 0x01, 0x70, 0x00, 0x00, 0x00}, 4},420{{0x11, 0x02, 0x05, 0x00, 0x00, 0x00}, 4},421{{0x11, 0x03, 0x5d, 0x00, 0x00, 0x00}, 4},422{{0x11, 0x04, 0x07, 0x00, 0x00, 0x00}, 4},423{{0x11, 0x05, 0x25, 0x00, 0x00, 0x00}, 4},424{{0x11, 0x06, 0x00, 0x00, 0x00, 0x00}, 4},425{{0x11, 0x07, 0x09, 0x00, 0x00, 0x00}, 4},426{{0x11, 0x08, 0x01, 0x00, 0x00, 0x00}, 4},427{{0x11, 0x09, 0x00, 0x00, 0x00, 0x00}, 4},428{{0x11, 0x0a, 0x00, 0x00, 0x00, 0x00}, 4},429{{0x11, 0x0b, 0x01, 0x00, 0x00, 0x00}, 4},430{{0x11, 0x0c, 0x00, 0x00, 0x00, 0x00}, 4},431{{0x11, 0x0d, 0x0c, 0x00, 0x00, 0x00}, 4},432{{0x11, 0x0e, 0x01, 0x00, 0x00, 0x00}, 4},433{{0x11, 0x0f, 0x00, 0x00, 0x00, 0x00}, 4},434{{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4},435{{0x11, 0x11, 0x00, 0x00, 0x00, 0x00}, 4},436{{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},437{{0x11, 0x13, 0x63, 0x00, 0x00, 0x00}, 4},438{{0x11, 0x15, 0x70, 0x00, 0x00, 0x00}, 4},439{{0x11, 0x18, 0x00, 0x00, 0x00, 0x00}, 4},440{{0x11, 0x11, 0x01, 0x00, 0x00, 0x00}, 4},441{{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4}, /* width */442{{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4}, /* height */443{{0x13, 0x28, 0x01, 0x09, 0x00, 0x00}, 4}, /* vstart? */444{{0x13, 0x27, 0x01, 0x28, 0x00, 0x00}, 4},445{{0x13, 0x29, 0x01, 0x40, 0x00, 0x00}, 4}, /* hstart? */446{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},447{{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4},448{{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4},449{{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4},450{{0x1b, 0x02, 0x05, 0x00, 0x00, 0x00}, 1},451{{0x1b, 0x11, 0x01, 0x00, 0x00, 0x00}, 1},452{{0x20, 0x18, 0x00, 0x00, 0x00, 0x00}, 1},453{{0x1b, 0x02, 0x0a, 0x00, 0x00, 0x00}, 1},454{{0x1b, 0x11, 0x01, 0x00, 0x00, 0x00}, 0},455/* Camera should start to capture now. */456};457458return run_start_commands(gspca_dev, ms350_start_commands,459ARRAY_SIZE(ms350_start_commands));460}461462static int start_genius_cam(struct gspca_dev *gspca_dev)463{464struct init_command genius_start_commands[] = {465{{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},466{{0x16, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},467{{0x10, 0x00, 0x00, 0x00, 0x00, 0x00}, 4},468{{0x13, 0x25, 0x01, 0x16, 0x00, 0x00}, 4},469{{0x13, 0x26, 0x01, 0x12, 0x00, 0x00}, 4},470/* "preliminary" width and height settings */471{{0x13, 0x28, 0x01, 0x0e, 0x00, 0x00}, 4},472{{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4},473{{0x13, 0x29, 0x01, 0x22, 0x00, 0x00}, 4},474{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},475{{0x13, 0x2d, 0x01, 0x02, 0x00, 0x00}, 4},476{{0x13, 0x2e, 0x01, 0x09, 0x00, 0x00}, 4},477{{0x13, 0x2f, 0x01, 0x07, 0x00, 0x00}, 4},478{{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4},479{{0x11, 0x21, 0x2d, 0x00, 0x00, 0x00}, 4},480{{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4},481{{0x11, 0x23, 0x03, 0x00, 0x00, 0x00}, 4},482{{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4},483{{0x11, 0x11, 0x64, 0x00, 0x00, 0x00}, 4},484{{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},485{{0x11, 0x13, 0x91, 0x00, 0x00, 0x00}, 4},486{{0x11, 0x14, 0x01, 0x00, 0x00, 0x00}, 4},487{{0x11, 0x15, 0x20, 0x00, 0x00, 0x00}, 4},488{{0x11, 0x16, 0x01, 0x00, 0x00, 0x00}, 4},489{{0x11, 0x17, 0x60, 0x00, 0x00, 0x00}, 4},490{{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4},491{{0x11, 0x21, 0x2d, 0x00, 0x00, 0x00}, 4},492{{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4},493{{0x11, 0x23, 0x03, 0x00, 0x00, 0x00}, 4},494{{0x11, 0x25, 0x00, 0x00, 0x00, 0x00}, 4},495{{0x11, 0x26, 0x02, 0x00, 0x00, 0x00}, 4},496{{0x11, 0x27, 0x88, 0x00, 0x00, 0x00}, 4},497{{0x11, 0x30, 0x38, 0x00, 0x00, 0x00}, 4},498{{0x11, 0x31, 0x2a, 0x00, 0x00, 0x00}, 4},499{{0x11, 0x32, 0x2a, 0x00, 0x00, 0x00}, 4},500{{0x11, 0x33, 0x2a, 0x00, 0x00, 0x00}, 4},501{{0x11, 0x34, 0x02, 0x00, 0x00, 0x00}, 4},502{{0x11, 0x5b, 0x0a, 0x00, 0x00, 0x00}, 4},503{{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4}, /* real width */504{{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4}, /* real height */505{{0x13, 0x28, 0x01, 0x0e, 0x00, 0x00}, 4},506{{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4},507{{0x13, 0x29, 0x01, 0x62, 0x00, 0x00}, 4},508{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},509{{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4},510{{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4},511{{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4},512{{0x11, 0x20, 0x00, 0x00, 0x00, 0x00}, 4},513{{0x11, 0x21, 0x2a, 0x00, 0x00, 0x00}, 4},514{{0x11, 0x22, 0x00, 0x00, 0x00, 0x00}, 4},515{{0x11, 0x23, 0x28, 0x00, 0x00, 0x00}, 4},516{{0x11, 0x10, 0x00, 0x00, 0x00, 0x00}, 4},517{{0x11, 0x11, 0x04, 0x00, 0x00, 0x00}, 4},518{{0x11, 0x12, 0x00, 0x00, 0x00, 0x00}, 4},519{{0x11, 0x13, 0x03, 0x00, 0x00, 0x00}, 4},520{{0x11, 0x14, 0x01, 0x00, 0x00, 0x00}, 4},521{{0x11, 0x15, 0xe0, 0x00, 0x00, 0x00}, 4},522{{0x11, 0x16, 0x02, 0x00, 0x00, 0x00}, 4},523{{0x11, 0x17, 0x80, 0x00, 0x00, 0x00}, 4},524{{0x1c, 0x20, 0x00, 0x2a, 0x00, 0x00}, 1},525{{0x1c, 0x20, 0x00, 0x2a, 0x00, 0x00}, 1},526{{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 0}527/* Camera should start to capture now. */528};529530return run_start_commands(gspca_dev, genius_start_commands,531ARRAY_SIZE(genius_start_commands));532}533534static int start_vivitar_cam(struct gspca_dev *gspca_dev)535{536struct init_command vivitar_start_commands[] = {537{{0x0c, 0x01, 0x00, 0x00, 0x00, 0x00}, 4},538{{0x13, 0x20, 0x01, 0x00, 0x00, 0x00}, 4},539{{0x13, 0x21, 0x01, 0x00, 0x00, 0x00}, 4},540{{0x13, 0x22, 0x01, 0x01, 0x00, 0x00}, 4},541{{0x13, 0x23, 0x01, 0x01, 0x00, 0x00}, 4},542{{0x13, 0x24, 0x01, 0x00, 0x00, 0x00}, 4},543{{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4},544{{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4},545{{0x13, 0x27, 0x01, 0x20, 0x00, 0x00}, 4},546{{0x13, 0x28, 0x01, 0x0a, 0x00, 0x00}, 4},547/*548* Above is changed from OEM 0x0b. Fixes Bayer tiling.549* Presumably gives a vertical shift of one row.550*/551{{0x13, 0x29, 0x01, 0x20, 0x00, 0x00}, 4},552/* Above seems to do horizontal shift. */553{{0x13, 0x2a, 0x01, 0x00, 0x00, 0x00}, 4},554{{0x13, 0x2b, 0x01, 0x00, 0x00, 0x00}, 4},555{{0x13, 0x2c, 0x01, 0x02, 0x00, 0x00}, 4},556{{0x13, 0x2d, 0x01, 0x03, 0x00, 0x00}, 4},557{{0x13, 0x2e, 0x01, 0x0f, 0x00, 0x00}, 4},558{{0x13, 0x2f, 0x01, 0x0c, 0x00, 0x00}, 4},559/* Above three commands seem to relate to brightness. */560{{0x12, 0x34, 0x01, 0x00, 0x00, 0x00}, 4},561{{0x13, 0x34, 0x01, 0xa1, 0x00, 0x00}, 4},562{{0x13, 0x35, 0x01, 0x00, 0x00, 0x00}, 4},563{{0x1b, 0x12, 0x80, 0x00, 0x00, 0x00}, 1},564{{0x1b, 0x01, 0x77, 0x00, 0x00, 0x00}, 1},565{{0x1b, 0x02, 0x3a, 0x00, 0x00, 0x00}, 1},566{{0x1b, 0x12, 0x78, 0x00, 0x00, 0x00}, 1},567{{0x1b, 0x13, 0x00, 0x00, 0x00, 0x00}, 1},568{{0x1b, 0x14, 0x80, 0x00, 0x00, 0x00}, 1},569{{0x1b, 0x15, 0x34, 0x00, 0x00, 0x00}, 1},570{{0x1b, 0x1b, 0x04, 0x00, 0x00, 0x00}, 1},571{{0x1b, 0x20, 0x44, 0x00, 0x00, 0x00}, 1},572{{0x1b, 0x23, 0xee, 0x00, 0x00, 0x00}, 1},573{{0x1b, 0x26, 0xa0, 0x00, 0x00, 0x00}, 1},574{{0x1b, 0x27, 0x9a, 0x00, 0x00, 0x00}, 1},575{{0x1b, 0x28, 0xa0, 0x00, 0x00, 0x00}, 1},576{{0x1b, 0x29, 0x30, 0x00, 0x00, 0x00}, 1},577{{0x1b, 0x2a, 0x80, 0x00, 0x00, 0x00}, 1},578{{0x1b, 0x2b, 0x00, 0x00, 0x00, 0x00}, 1},579{{0x1b, 0x2f, 0x3d, 0x00, 0x00, 0x00}, 1},580{{0x1b, 0x30, 0x24, 0x00, 0x00, 0x00}, 1},581{{0x1b, 0x32, 0x86, 0x00, 0x00, 0x00}, 1},582{{0x1b, 0x60, 0xa9, 0x00, 0x00, 0x00}, 1},583{{0x1b, 0x61, 0x42, 0x00, 0x00, 0x00}, 1},584{{0x1b, 0x65, 0x00, 0x00, 0x00, 0x00}, 1},585{{0x1b, 0x69, 0x38, 0x00, 0x00, 0x00}, 1},586{{0x1b, 0x6f, 0x88, 0x00, 0x00, 0x00}, 1},587{{0x1b, 0x70, 0x0b, 0x00, 0x00, 0x00}, 1},588{{0x1b, 0x71, 0x00, 0x00, 0x00, 0x00}, 1},589{{0x1b, 0x74, 0x21, 0x00, 0x00, 0x00}, 1},590{{0x1b, 0x75, 0x86, 0x00, 0x00, 0x00}, 1},591{{0x1b, 0x76, 0x00, 0x00, 0x00, 0x00}, 1},592{{0x1b, 0x7d, 0xf3, 0x00, 0x00, 0x00}, 1},593{{0x1b, 0x17, 0x1c, 0x00, 0x00, 0x00}, 1},594{{0x1b, 0x18, 0xc0, 0x00, 0x00, 0x00}, 1},595{{0x1b, 0x19, 0x05, 0x00, 0x00, 0x00}, 1},596{{0x1b, 0x1a, 0xf6, 0x00, 0x00, 0x00}, 1},597/* {{0x13, 0x25, 0x01, 0x28, 0x00, 0x00}, 4},598{{0x13, 0x26, 0x01, 0x1e, 0x00, 0x00}, 4},599{{0x13, 0x28, 0x01, 0x0b, 0x00, 0x00}, 4}, */600{{0x20, 0x36, 0x06, 0x00, 0x00, 0x00}, 1},601{{0x1b, 0x10, 0x26, 0x00, 0x00, 0x00}, 1},602{{0x12, 0x27, 0x01, 0x00, 0x00, 0x00}, 4},603{{0x1b, 0x76, 0x03, 0x00, 0x00, 0x00}, 1},604{{0x20, 0x36, 0x05, 0x00, 0x00, 0x00}, 1},605{{0x1b, 0x00, 0x3f, 0x00, 0x00, 0x00}, 1},606/* Above is brightness; OEM driver setting is 0x10 */607{{0x12, 0x27, 0x01, 0x00, 0x00, 0x00}, 4},608{{0x20, 0x29, 0x30, 0x00, 0x00, 0x00}, 1},609{{0x20, 0x34, 0xa1, 0x00, 0x00, 0x00}, 1}610};611612return run_start_commands(gspca_dev, vivitar_start_commands,613ARRAY_SIZE(vivitar_start_commands));614}615616static int sd_start(struct gspca_dev *gspca_dev)617{618struct sd *sd = (struct sd *) gspca_dev;619int err_code;620621sd->sof_read = 0;622623switch (sd->model) {624case 0x7005:625err_code = start_genius_cam(gspca_dev);626break;627case 0x8001:628err_code = start_spy_cam(gspca_dev);629break;630case 0x8003:631err_code = start_cif_cam(gspca_dev);632break;633case 0x8008:634err_code = start_ms350_cam(gspca_dev);635break;636case 0x800a:637err_code = start_vivitar_cam(gspca_dev);638break;639default:640err("Starting unknown camera, please report this");641return -ENXIO;642}643644return err_code;645}646647static void sd_stopN(struct gspca_dev *gspca_dev)648{649int result;650__u8 data[6];651652result = sn9c2028_read1(gspca_dev);653if (result < 0)654PDEBUG(D_ERR, "Camera Stop read failed");655656memset(data, 0, 6);657data[0] = 0x14;658result = sn9c2028_command(gspca_dev, data);659if (result < 0)660PDEBUG(D_ERR, "Camera Stop command failed");661}662663/* Include sn9c2028 sof detection functions */664#include "sn9c2028.h"665666static void sd_pkt_scan(struct gspca_dev *gspca_dev,667__u8 *data, /* isoc packet */668int len) /* iso packet length */669{670unsigned char *sof;671672sof = sn9c2028_find_sof(gspca_dev, data, len);673if (sof) {674int n;675676/* finish decoding current frame */677n = sof - data;678if (n > sizeof sn9c2028_sof_marker)679n -= sizeof sn9c2028_sof_marker;680else681n = 0;682gspca_frame_add(gspca_dev, LAST_PACKET, data, n);683/* Start next frame. */684gspca_frame_add(gspca_dev, FIRST_PACKET,685sn9c2028_sof_marker, sizeof sn9c2028_sof_marker);686len -= sof - data;687data = sof;688}689gspca_frame_add(gspca_dev, INTER_PACKET, data, len);690}691692/* sub-driver description */693static const struct sd_desc sd_desc = {694.name = MODULE_NAME,695.ctrls = sd_ctrls,696.nctrls = ARRAY_SIZE(sd_ctrls),697.config = sd_config,698.init = sd_init,699.start = sd_start,700.stopN = sd_stopN,701.pkt_scan = sd_pkt_scan,702};703704/* -- module initialisation -- */705static const struct usb_device_id device_table[] = {706{USB_DEVICE(0x0458, 0x7005)}, /* Genius Smart 300, version 2 */707/* The Genius Smart is untested. I can't find an owner ! */708/* {USB_DEVICE(0x0c45, 0x8000)}, DC31VC, Don't know this camera */709{USB_DEVICE(0x0c45, 0x8001)}, /* Wild Planet digital spy cam */710{USB_DEVICE(0x0c45, 0x8003)}, /* Several small CIF cameras */711/* {USB_DEVICE(0x0c45, 0x8006)}, Unknown VGA camera */712{USB_DEVICE(0x0c45, 0x8008)}, /* Mini-Shotz ms-350 */713{USB_DEVICE(0x0c45, 0x800a)}, /* Vivicam 3350B */714{}715};716MODULE_DEVICE_TABLE(usb, device_table);717718/* -- device connect -- */719static int sd_probe(struct usb_interface *intf,720const struct usb_device_id *id)721{722return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),723THIS_MODULE);724}725726static struct usb_driver sd_driver = {727.name = MODULE_NAME,728.id_table = device_table,729.probe = sd_probe,730.disconnect = gspca_disconnect,731#ifdef CONFIG_PM732.suspend = gspca_suspend,733.resume = gspca_resume,734#endif735};736737/* -- module insert / remove -- */738static int __init sd_mod_init(void)739{740return usb_register(&sd_driver);741}742743static void __exit sd_mod_exit(void)744{745usb_deregister(&sd_driver);746}747748module_init(sd_mod_init);749module_exit(sd_mod_exit);750751752