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