linux/drivers/media/video/gspca/mars.c
<<
>>
Prefs
   1/*
   2 *              Mars-Semi MR97311A library
   3 *              Copyright (C) 2005 <bradlch@hotmail.com>
   4 *
   5 * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License as published by
   9 * the Free Software Foundation; either version 2 of the License, or
  10 * any later version.
  11 *
  12 * This program is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15 * GNU General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU General Public License
  18 * along with this program; if not, write to the Free Software
  19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  20 */
  21
  22#define MODULE_NAME "mars"
  23
  24#include "gspca.h"
  25#include "jpeg.h"
  26
  27MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
  28MODULE_DESCRIPTION("GSPCA/Mars USB Camera Driver");
  29MODULE_LICENSE("GPL");
  30
  31/* controls */
  32enum e_ctrl {
  33        BRIGHTNESS,
  34        COLORS,
  35        GAMMA,
  36        SHARPNESS,
  37        ILLUM_TOP,
  38        ILLUM_BOT,
  39        NCTRLS          /* number of controls */
  40};
  41
  42/* specific webcam descriptor */
  43struct sd {
  44        struct gspca_dev gspca_dev;     /* !! must be the first item */
  45
  46        struct gspca_ctrl ctrls[NCTRLS];
  47
  48        u8 quality;
  49#define QUALITY_MIN 40
  50#define QUALITY_MAX 70
  51#define QUALITY_DEF 50
  52
  53        u8 jpeg_hdr[JPEG_HDR_SZ];
  54};
  55
  56/* V4L2 controls supported by the driver */
  57static void setbrightness(struct gspca_dev *gspca_dev);
  58static void setcolors(struct gspca_dev *gspca_dev);
  59static void setgamma(struct gspca_dev *gspca_dev);
  60static void setsharpness(struct gspca_dev *gspca_dev);
  61static int sd_setilluminator1(struct gspca_dev *gspca_dev, __s32 val);
  62static int sd_setilluminator2(struct gspca_dev *gspca_dev, __s32 val);
  63
  64static const struct ctrl sd_ctrls[NCTRLS] = {
  65[BRIGHTNESS] = {
  66            {
  67                .id      = V4L2_CID_BRIGHTNESS,
  68                .type    = V4L2_CTRL_TYPE_INTEGER,
  69                .name    = "Brightness",
  70                .minimum = 0,
  71                .maximum = 30,
  72                .step    = 1,
  73                .default_value = 15,
  74            },
  75            .set_control = setbrightness
  76        },
  77[COLORS] = {
  78            {
  79                .id      = V4L2_CID_SATURATION,
  80                .type    = V4L2_CTRL_TYPE_INTEGER,
  81                .name    = "Color",
  82                .minimum = 1,
  83                .maximum = 255,
  84                .step    = 1,
  85                .default_value = 200,
  86            },
  87            .set_control = setcolors
  88        },
  89[GAMMA] = {
  90            {
  91                .id      = V4L2_CID_GAMMA,
  92                .type    = V4L2_CTRL_TYPE_INTEGER,
  93                .name    = "Gamma",
  94                .minimum = 0,
  95                .maximum = 3,
  96                .step    = 1,
  97                .default_value = 1,
  98            },
  99            .set_control = setgamma
 100        },
 101[SHARPNESS] = {
 102            {
 103                .id      = V4L2_CID_SHARPNESS,
 104                .type    = V4L2_CTRL_TYPE_INTEGER,
 105                .name    = "Sharpness",
 106                .minimum = 0,
 107                .maximum = 2,
 108                .step    = 1,
 109                .default_value = 1,
 110            },
 111            .set_control = setsharpness
 112        },
 113[ILLUM_TOP] = {
 114            {
 115                .id      = V4L2_CID_ILLUMINATORS_1,
 116                .type    = V4L2_CTRL_TYPE_BOOLEAN,
 117                .name    = "Top illuminator",
 118                .minimum = 0,
 119                .maximum = 1,
 120                .step    = 1,
 121                .default_value = 0,
 122                .flags = V4L2_CTRL_FLAG_UPDATE,
 123            },
 124            .set = sd_setilluminator1
 125        },
 126[ILLUM_BOT] = {
 127            {
 128                .id      = V4L2_CID_ILLUMINATORS_2,
 129                .type    = V4L2_CTRL_TYPE_BOOLEAN,
 130                .name    = "Bottom illuminator",
 131                .minimum = 0,
 132                .maximum = 1,
 133                .step    = 1,
 134                .default_value = 0,
 135                .flags = V4L2_CTRL_FLAG_UPDATE,
 136            },
 137            .set = sd_setilluminator2
 138        },
 139};
 140
 141static const struct v4l2_pix_format vga_mode[] = {
 142        {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
 143                .bytesperline = 320,
 144                .sizeimage = 320 * 240 * 3 / 8 + 590,
 145                .colorspace = V4L2_COLORSPACE_JPEG,
 146                .priv = 2},
 147        {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
 148                .bytesperline = 640,
 149                .sizeimage = 640 * 480 * 3 / 8 + 590,
 150                .colorspace = V4L2_COLORSPACE_JPEG,
 151                .priv = 1},
 152};
 153
 154static const __u8 mi_data[0x20] = {
 155/*       01    02   03     04    05    06    07    08 */
 156        0x48, 0x22, 0x01, 0x47, 0x10, 0x00, 0x00, 0x00,
 157/*       09    0a   0b     0c    0d    0e    0f    10 */
 158        0x00, 0x01, 0x30, 0x01, 0x30, 0x01, 0x30, 0x01,
 159/*       11    12   13     14    15    16    17    18 */
 160        0x30, 0x00, 0x04, 0x00, 0x06, 0x01, 0xe2, 0x02,
 161/*       19    1a   1b     1c    1d    1e    1f    20 */
 162        0x82, 0x00, 0x20, 0x17, 0x80, 0x08, 0x0c, 0x00
 163};
 164
 165/* write <len> bytes from gspca_dev->usb_buf */
 166static void reg_w(struct gspca_dev *gspca_dev,
 167                 int len)
 168{
 169        int alen, ret;
 170
 171        if (gspca_dev->usb_err < 0)
 172                return;
 173
 174        ret = usb_bulk_msg(gspca_dev->dev,
 175                        usb_sndbulkpipe(gspca_dev->dev, 4),
 176                        gspca_dev->usb_buf,
 177                        len,
 178                        &alen,
 179                        500);   /* timeout in milliseconds */
 180        if (ret < 0) {
 181                err("reg write [%02x] error %d",
 182                        gspca_dev->usb_buf[0], ret);
 183                gspca_dev->usb_err = ret;
 184        }
 185}
 186
 187static void mi_w(struct gspca_dev *gspca_dev,
 188                 u8 addr,
 189                 u8 value)
 190{
 191        gspca_dev->usb_buf[0] = 0x1f;
 192        gspca_dev->usb_buf[1] = 0;                      /* control byte */
 193        gspca_dev->usb_buf[2] = addr;
 194        gspca_dev->usb_buf[3] = value;
 195
 196        reg_w(gspca_dev, 4);
 197}
 198
 199static void setbrightness(struct gspca_dev *gspca_dev)
 200{
 201        struct sd *sd = (struct sd *) gspca_dev;
 202
 203        gspca_dev->usb_buf[0] = 0x61;
 204        gspca_dev->usb_buf[1] = sd->ctrls[BRIGHTNESS].val;
 205        reg_w(gspca_dev, 2);
 206}
 207
 208static void setcolors(struct gspca_dev *gspca_dev)
 209{
 210        struct sd *sd = (struct sd *) gspca_dev;
 211        s16 val;
 212
 213        val = sd->ctrls[COLORS].val;
 214        gspca_dev->usb_buf[0] = 0x5f;
 215        gspca_dev->usb_buf[1] = val << 3;
 216        gspca_dev->usb_buf[2] = ((val >> 2) & 0xf8) | 0x04;
 217        reg_w(gspca_dev, 3);
 218}
 219
 220static void setgamma(struct gspca_dev *gspca_dev)
 221{
 222        struct sd *sd = (struct sd *) gspca_dev;
 223
 224        gspca_dev->usb_buf[0] = 0x06;
 225        gspca_dev->usb_buf[1] = sd->ctrls[GAMMA].val * 0x40;
 226        reg_w(gspca_dev, 2);
 227}
 228
 229static void setsharpness(struct gspca_dev *gspca_dev)
 230{
 231        struct sd *sd = (struct sd *) gspca_dev;
 232
 233        gspca_dev->usb_buf[0] = 0x67;
 234        gspca_dev->usb_buf[1] = sd->ctrls[SHARPNESS].val * 4 + 3;
 235        reg_w(gspca_dev, 2);
 236}
 237
 238static void setilluminators(struct gspca_dev *gspca_dev)
 239{
 240        struct sd *sd = (struct sd *) gspca_dev;
 241
 242        gspca_dev->usb_buf[0] = 0x22;
 243        if (sd->ctrls[ILLUM_TOP].val)
 244                gspca_dev->usb_buf[1] = 0x76;
 245        else if (sd->ctrls[ILLUM_BOT].val)
 246                gspca_dev->usb_buf[1] = 0x7a;
 247        else
 248                gspca_dev->usb_buf[1] = 0x7e;
 249        reg_w(gspca_dev, 2);
 250}
 251
 252/* this function is called at probe time */
 253static int sd_config(struct gspca_dev *gspca_dev,
 254                        const struct usb_device_id *id)
 255{
 256        struct sd *sd = (struct sd *) gspca_dev;
 257        struct cam *cam;
 258
 259        cam = &gspca_dev->cam;
 260        cam->cam_mode = vga_mode;
 261        cam->nmodes = ARRAY_SIZE(vga_mode);
 262        cam->ctrls = sd->ctrls;
 263        sd->quality = QUALITY_DEF;
 264        gspca_dev->nbalt = 9;           /* use the altsetting 08 */
 265        return 0;
 266}
 267
 268/* this function is called at probe and resume time */
 269static int sd_init(struct gspca_dev *gspca_dev)
 270{
 271        gspca_dev->ctrl_inac = (1 << ILLUM_TOP) | (1 << ILLUM_BOT);
 272        return 0;
 273}
 274
 275static int sd_start(struct gspca_dev *gspca_dev)
 276{
 277        struct sd *sd = (struct sd *) gspca_dev;
 278        u8 *data;
 279        int i;
 280
 281        /* create the JPEG header */
 282        jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
 283                        0x21);          /* JPEG 422 */
 284        jpeg_set_qual(sd->jpeg_hdr, sd->quality);
 285
 286        data = gspca_dev->usb_buf;
 287
 288        data[0] = 0x01;         /* address */
 289        data[1] = 0x01;
 290        reg_w(gspca_dev, 2);
 291
 292        /*
 293           Initialize the MR97113 chip register
 294         */
 295        data[0] = 0x00;         /* address */
 296        data[1] = 0x0c | 0x01;  /* reg 0 */
 297        data[2] = 0x01;         /* reg 1 */
 298        data[3] = gspca_dev->width / 8;         /* h_size , reg 2 */
 299        data[4] = gspca_dev->height / 8;        /* v_size , reg 3 */
 300        data[5] = 0x30;         /* reg 4, MI, PAS5101 :
 301                                 *      0x30 for 24mhz , 0x28 for 12mhz */
 302        data[6] = 0x02;         /* reg 5, H start - was 0x04 */
 303        data[7] = sd->ctrls[GAMMA].val * 0x40;  /* reg 0x06: gamma */
 304        data[8] = 0x01;         /* reg 7, V start - was 0x03 */
 305/*      if (h_size == 320 ) */
 306/*              data[9]= 0x56;   * reg 8, 24MHz, 2:1 scale down */
 307/*      else */
 308        data[9] = 0x52;         /* reg 8, 24MHz, no scale down */
 309/*jfm: from win trace*/
 310        data[10] = 0x18;
 311
 312        reg_w(gspca_dev, 11);
 313
 314        data[0] = 0x23;         /* address */
 315        data[1] = 0x09;         /* reg 35, append frame header */
 316
 317        reg_w(gspca_dev, 2);
 318
 319        data[0] = 0x3c;         /* address */
 320/*      if (gspca_dev->width == 1280) */
 321/*              data[1] = 200;   * reg 60, pc-cam frame size
 322                                 *      (unit: 4KB) 800KB */
 323/*      else */
 324        data[1] = 50;           /* 50 reg 60, pc-cam frame size
 325                                 *      (unit: 4KB) 200KB */
 326        reg_w(gspca_dev, 2);
 327
 328        /* auto dark-gain */
 329        data[0] = 0x5e;         /* address */
 330        data[1] = 0;            /* reg 94, Y Gain (auto) */
 331/*jfm: from win trace*/
 332                                /* reg 0x5f/0x60 (LE) = saturation */
 333                                /* h (60): xxxx x100
 334                                 * l (5f): xxxx x000 */
 335        data[2] = sd->ctrls[COLORS].val << 3;
 336        data[3] = ((sd->ctrls[COLORS].val >> 2) & 0xf8) | 0x04;
 337        data[4] = sd->ctrls[BRIGHTNESS].val; /* reg 0x61 = brightness */
 338        data[5] = 0x00;
 339
 340        reg_w(gspca_dev, 6);
 341
 342        data[0] = 0x67;
 343/*jfm: from win trace*/
 344        data[1] = sd->ctrls[SHARPNESS].val * 4 + 3;
 345        data[2] = 0x14;
 346        reg_w(gspca_dev, 3);
 347
 348        data[0] = 0x69;
 349        data[1] = 0x2f;
 350        data[2] = 0x28;
 351        data[3] = 0x42;
 352        reg_w(gspca_dev, 4);
 353
 354        data[0] = 0x63;
 355        data[1] = 0x07;
 356        reg_w(gspca_dev, 2);
 357/*jfm: win trace - many writes here to reg 0x64*/
 358
 359        /* initialize the MI sensor */
 360        for (i = 0; i < sizeof mi_data; i++)
 361                mi_w(gspca_dev, i + 1, mi_data[i]);
 362
 363        data[0] = 0x00;
 364        data[1] = 0x4d;         /* ISOC transfering enable... */
 365        reg_w(gspca_dev, 2);
 366
 367        gspca_dev->ctrl_inac = 0; /* activate the illuminator controls */
 368        return gspca_dev->usb_err;
 369}
 370
 371static void sd_stopN(struct gspca_dev *gspca_dev)
 372{
 373        struct sd *sd = (struct sd *) gspca_dev;
 374
 375        gspca_dev->ctrl_inac = (1 << ILLUM_TOP) | (1 << ILLUM_BOT);
 376        if (sd->ctrls[ILLUM_TOP].val || sd->ctrls[ILLUM_BOT].val) {
 377                sd->ctrls[ILLUM_TOP].val = 0;
 378                sd->ctrls[ILLUM_BOT].val = 0;
 379                setilluminators(gspca_dev);
 380                msleep(20);
 381        }
 382
 383        gspca_dev->usb_buf[0] = 1;
 384        gspca_dev->usb_buf[1] = 0;
 385        reg_w(gspca_dev, 2);
 386}
 387
 388static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 389                        u8 *data,                       /* isoc packet */
 390                        int len)                        /* iso packet length */
 391{
 392        struct sd *sd = (struct sd *) gspca_dev;
 393        int p;
 394
 395        if (len < 6) {
 396/*              gspca_dev->last_packet_type = DISCARD_PACKET; */
 397                return;
 398        }
 399        for (p = 0; p < len - 6; p++) {
 400                if (data[0 + p] == 0xff
 401                    && data[1 + p] == 0xff
 402                    && data[2 + p] == 0x00
 403                    && data[3 + p] == 0xff
 404                    && data[4 + p] == 0x96) {
 405                        if (data[5 + p] == 0x64
 406                            || data[5 + p] == 0x65
 407                            || data[5 + p] == 0x66
 408                            || data[5 + p] == 0x67) {
 409                                PDEBUG(D_PACK, "sof offset: %d len: %d",
 410                                        p, len);
 411                                gspca_frame_add(gspca_dev, LAST_PACKET,
 412                                                data, p);
 413
 414                                /* put the JPEG header */
 415                                gspca_frame_add(gspca_dev, FIRST_PACKET,
 416                                        sd->jpeg_hdr, JPEG_HDR_SZ);
 417                                data += p + 16;
 418                                len -= p + 16;
 419                                break;
 420                        }
 421                }
 422        }
 423        gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 424}
 425
 426static int sd_setilluminator1(struct gspca_dev *gspca_dev, __s32 val)
 427{
 428        struct sd *sd = (struct sd *) gspca_dev;
 429
 430        /* only one illuminator may be on */
 431        sd->ctrls[ILLUM_TOP].val = val;
 432        if (val)
 433                sd->ctrls[ILLUM_BOT].val = 0;
 434        setilluminators(gspca_dev);
 435        return gspca_dev->usb_err;
 436}
 437
 438static int sd_setilluminator2(struct gspca_dev *gspca_dev, __s32 val)
 439{
 440        struct sd *sd = (struct sd *) gspca_dev;
 441
 442        /* only one illuminator may be on */
 443        sd->ctrls[ILLUM_BOT].val = val;
 444        if (val)
 445                sd->ctrls[ILLUM_TOP].val = 0;
 446        setilluminators(gspca_dev);
 447        return gspca_dev->usb_err;
 448}
 449
 450static int sd_set_jcomp(struct gspca_dev *gspca_dev,
 451                        struct v4l2_jpegcompression *jcomp)
 452{
 453        struct sd *sd = (struct sd *) gspca_dev;
 454
 455        if (jcomp->quality < QUALITY_MIN)
 456                sd->quality = QUALITY_MIN;
 457        else if (jcomp->quality > QUALITY_MAX)
 458                sd->quality = QUALITY_MAX;
 459        else
 460                sd->quality = jcomp->quality;
 461        if (gspca_dev->streaming)
 462                jpeg_set_qual(sd->jpeg_hdr, sd->quality);
 463        return 0;
 464}
 465
 466static int sd_get_jcomp(struct gspca_dev *gspca_dev,
 467                        struct v4l2_jpegcompression *jcomp)
 468{
 469        struct sd *sd = (struct sd *) gspca_dev;
 470
 471        memset(jcomp, 0, sizeof *jcomp);
 472        jcomp->quality = sd->quality;
 473        jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
 474                        | V4L2_JPEG_MARKER_DQT;
 475        return 0;
 476}
 477
 478/* sub-driver description */
 479static const struct sd_desc sd_desc = {
 480        .name = MODULE_NAME,
 481        .ctrls = sd_ctrls,
 482        .nctrls = NCTRLS,
 483        .config = sd_config,
 484        .init = sd_init,
 485        .start = sd_start,
 486        .stopN = sd_stopN,
 487        .pkt_scan = sd_pkt_scan,
 488        .get_jcomp = sd_get_jcomp,
 489        .set_jcomp = sd_set_jcomp,
 490};
 491
 492/* -- module initialisation -- */
 493static const struct usb_device_id device_table[] = {
 494        {USB_DEVICE(0x093a, 0x050f)},
 495        {}
 496};
 497MODULE_DEVICE_TABLE(usb, device_table);
 498
 499/* -- device connect -- */
 500static int sd_probe(struct usb_interface *intf,
 501                        const struct usb_device_id *id)
 502{
 503        return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
 504                                THIS_MODULE);
 505}
 506
 507static struct usb_driver sd_driver = {
 508        .name = MODULE_NAME,
 509        .id_table = device_table,
 510        .probe = sd_probe,
 511        .disconnect = gspca_disconnect,
 512#ifdef CONFIG_PM
 513        .suspend = gspca_suspend,
 514        .resume = gspca_resume,
 515#endif
 516};
 517
 518/* -- module insert / remove -- */
 519static int __init sd_mod_init(void)
 520{
 521        return usb_register(&sd_driver);
 522}
 523static void __exit sd_mod_exit(void)
 524{
 525        usb_deregister(&sd_driver);
 526}
 527
 528module_init(sd_mod_init);
 529module_exit(sd_mod_exit);
 530