linux/drivers/media/usb/gspca/sn9c2028.c
<<
>>
Prefs
   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