linux/drivers/media/usb/gspca/mars.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 *              Mars-Semi MR97311A library
   4 *              Copyright (C) 2005 <bradlch@hotmail.com>
   5 *
   6 * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
   7 */
   8
   9#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  10
  11#define MODULE_NAME "mars"
  12
  13#include "gspca.h"
  14#include "jpeg.h"
  15
  16MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
  17MODULE_DESCRIPTION("GSPCA/Mars USB Camera Driver");
  18MODULE_LICENSE("GPL");
  19
  20#define QUALITY 50
  21
  22/* specific webcam descriptor */
  23struct sd {
  24        struct gspca_dev gspca_dev;     /* !! must be the first item */
  25
  26        struct v4l2_ctrl *brightness;
  27        struct v4l2_ctrl *saturation;
  28        struct v4l2_ctrl *sharpness;
  29        struct v4l2_ctrl *gamma;
  30        struct { /* illuminator control cluster */
  31                struct v4l2_ctrl *illum_top;
  32                struct v4l2_ctrl *illum_bottom;
  33        };
  34        u8 jpeg_hdr[JPEG_HDR_SZ];
  35};
  36
  37/* V4L2 controls supported by the driver */
  38static void setbrightness(struct gspca_dev *gspca_dev, s32 val);
  39static void setcolors(struct gspca_dev *gspca_dev, s32 val);
  40static void setgamma(struct gspca_dev *gspca_dev, s32 val);
  41static void setsharpness(struct gspca_dev *gspca_dev, s32 val);
  42
  43static const struct v4l2_pix_format vga_mode[] = {
  44        {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
  45                .bytesperline = 320,
  46                .sizeimage = 320 * 240 * 3 / 8 + 590,
  47                .colorspace = V4L2_COLORSPACE_JPEG,
  48                .priv = 2},
  49        {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
  50                .bytesperline = 640,
  51                .sizeimage = 640 * 480 * 3 / 8 + 590,
  52                .colorspace = V4L2_COLORSPACE_JPEG,
  53                .priv = 1},
  54};
  55
  56static const __u8 mi_data[0x20] = {
  57/*       01    02   03     04    05    06    07    08 */
  58        0x48, 0x22, 0x01, 0x47, 0x10, 0x00, 0x00, 0x00,
  59/*       09    0a   0b     0c    0d    0e    0f    10 */
  60        0x00, 0x01, 0x30, 0x01, 0x30, 0x01, 0x30, 0x01,
  61/*       11    12   13     14    15    16    17    18 */
  62        0x30, 0x00, 0x04, 0x00, 0x06, 0x01, 0xe2, 0x02,
  63/*       19    1a   1b     1c    1d    1e    1f    20 */
  64        0x82, 0x00, 0x20, 0x17, 0x80, 0x08, 0x0c, 0x00
  65};
  66
  67/* write <len> bytes from gspca_dev->usb_buf */
  68static void reg_w(struct gspca_dev *gspca_dev,
  69                 int len)
  70{
  71        int alen, ret;
  72
  73        if (gspca_dev->usb_err < 0)
  74                return;
  75
  76        ret = usb_bulk_msg(gspca_dev->dev,
  77                        usb_sndbulkpipe(gspca_dev->dev, 4),
  78                        gspca_dev->usb_buf,
  79                        len,
  80                        &alen,
  81                        500);   /* timeout in milliseconds */
  82        if (ret < 0) {
  83                pr_err("reg write [%02x] error %d\n",
  84                       gspca_dev->usb_buf[0], ret);
  85                gspca_dev->usb_err = ret;
  86        }
  87}
  88
  89static void mi_w(struct gspca_dev *gspca_dev,
  90                 u8 addr,
  91                 u8 value)
  92{
  93        gspca_dev->usb_buf[0] = 0x1f;
  94        gspca_dev->usb_buf[1] = 0;                      /* control byte */
  95        gspca_dev->usb_buf[2] = addr;
  96        gspca_dev->usb_buf[3] = value;
  97
  98        reg_w(gspca_dev, 4);
  99}
 100
 101static void setbrightness(struct gspca_dev *gspca_dev, s32 val)
 102{
 103        gspca_dev->usb_buf[0] = 0x61;
 104        gspca_dev->usb_buf[1] = val;
 105        reg_w(gspca_dev, 2);
 106}
 107
 108static void setcolors(struct gspca_dev *gspca_dev, s32 val)
 109{
 110        gspca_dev->usb_buf[0] = 0x5f;
 111        gspca_dev->usb_buf[1] = val << 3;
 112        gspca_dev->usb_buf[2] = ((val >> 2) & 0xf8) | 0x04;
 113        reg_w(gspca_dev, 3);
 114}
 115
 116static void setgamma(struct gspca_dev *gspca_dev, s32 val)
 117{
 118        gspca_dev->usb_buf[0] = 0x06;
 119        gspca_dev->usb_buf[1] = val * 0x40;
 120        reg_w(gspca_dev, 2);
 121}
 122
 123static void setsharpness(struct gspca_dev *gspca_dev, s32 val)
 124{
 125        gspca_dev->usb_buf[0] = 0x67;
 126        gspca_dev->usb_buf[1] = val * 4 + 3;
 127        reg_w(gspca_dev, 2);
 128}
 129
 130static void setilluminators(struct gspca_dev *gspca_dev, bool top, bool bottom)
 131{
 132        /* both are off if not streaming */
 133        gspca_dev->usb_buf[0] = 0x22;
 134        if (top)
 135                gspca_dev->usb_buf[1] = 0x76;
 136        else if (bottom)
 137                gspca_dev->usb_buf[1] = 0x7a;
 138        else
 139                gspca_dev->usb_buf[1] = 0x7e;
 140        reg_w(gspca_dev, 2);
 141}
 142
 143static int mars_s_ctrl(struct v4l2_ctrl *ctrl)
 144{
 145        struct gspca_dev *gspca_dev =
 146                container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
 147        struct sd *sd = (struct sd *)gspca_dev;
 148
 149        gspca_dev->usb_err = 0;
 150
 151        if (ctrl->id == V4L2_CID_ILLUMINATORS_1) {
 152                /* only one can be on at a time */
 153                if (ctrl->is_new && ctrl->val)
 154                        sd->illum_bottom->val = 0;
 155                if (sd->illum_bottom->is_new && sd->illum_bottom->val)
 156                        sd->illum_top->val = 0;
 157        }
 158
 159        if (!gspca_dev->streaming)
 160                return 0;
 161
 162        switch (ctrl->id) {
 163        case V4L2_CID_BRIGHTNESS:
 164                setbrightness(gspca_dev, ctrl->val);
 165                break;
 166        case V4L2_CID_SATURATION:
 167                setcolors(gspca_dev, ctrl->val);
 168                break;
 169        case V4L2_CID_GAMMA:
 170                setgamma(gspca_dev, ctrl->val);
 171                break;
 172        case V4L2_CID_ILLUMINATORS_1:
 173                setilluminators(gspca_dev, sd->illum_top->val,
 174                                           sd->illum_bottom->val);
 175                break;
 176        case V4L2_CID_SHARPNESS:
 177                setsharpness(gspca_dev, ctrl->val);
 178                break;
 179        default:
 180                return -EINVAL;
 181        }
 182        return gspca_dev->usb_err;
 183}
 184
 185static const struct v4l2_ctrl_ops mars_ctrl_ops = {
 186        .s_ctrl = mars_s_ctrl,
 187};
 188
 189/* this function is called at probe time */
 190static int sd_init_controls(struct gspca_dev *gspca_dev)
 191{
 192        struct sd *sd = (struct sd *) gspca_dev;
 193        struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
 194
 195        gspca_dev->vdev.ctrl_handler = hdl;
 196        v4l2_ctrl_handler_init(hdl, 6);
 197        sd->brightness = v4l2_ctrl_new_std(hdl, &mars_ctrl_ops,
 198                        V4L2_CID_BRIGHTNESS, 0, 30, 1, 15);
 199        sd->saturation = v4l2_ctrl_new_std(hdl, &mars_ctrl_ops,
 200                        V4L2_CID_SATURATION, 0, 255, 1, 200);
 201        sd->gamma = v4l2_ctrl_new_std(hdl, &mars_ctrl_ops,
 202                        V4L2_CID_GAMMA, 0, 3, 1, 1);
 203        sd->sharpness = v4l2_ctrl_new_std(hdl, &mars_ctrl_ops,
 204                        V4L2_CID_SHARPNESS, 0, 2, 1, 1);
 205        sd->illum_top = v4l2_ctrl_new_std(hdl, &mars_ctrl_ops,
 206                        V4L2_CID_ILLUMINATORS_1, 0, 1, 1, 0);
 207        sd->illum_top->flags |= V4L2_CTRL_FLAG_UPDATE;
 208        sd->illum_bottom = v4l2_ctrl_new_std(hdl, &mars_ctrl_ops,
 209                        V4L2_CID_ILLUMINATORS_2, 0, 1, 1, 0);
 210        sd->illum_bottom->flags |= V4L2_CTRL_FLAG_UPDATE;
 211        if (hdl->error) {
 212                pr_err("Could not initialize controls\n");
 213                return hdl->error;
 214        }
 215        v4l2_ctrl_cluster(2, &sd->illum_top);
 216        return 0;
 217}
 218
 219/* this function is called at probe time */
 220static int sd_config(struct gspca_dev *gspca_dev,
 221                        const struct usb_device_id *id)
 222{
 223        struct cam *cam;
 224
 225        cam = &gspca_dev->cam;
 226        cam->cam_mode = vga_mode;
 227        cam->nmodes = ARRAY_SIZE(vga_mode);
 228        return 0;
 229}
 230
 231/* this function is called at probe and resume time */
 232static int sd_init(struct gspca_dev *gspca_dev)
 233{
 234        return 0;
 235}
 236
 237static int sd_start(struct gspca_dev *gspca_dev)
 238{
 239        struct sd *sd = (struct sd *) gspca_dev;
 240        u8 *data;
 241        int i;
 242
 243        /* create the JPEG header */
 244        jpeg_define(sd->jpeg_hdr, gspca_dev->pixfmt.height,
 245                        gspca_dev->pixfmt.width,
 246                        0x21);          /* JPEG 422 */
 247        jpeg_set_qual(sd->jpeg_hdr, QUALITY);
 248
 249        data = gspca_dev->usb_buf;
 250
 251        data[0] = 0x01;         /* address */
 252        data[1] = 0x01;
 253        reg_w(gspca_dev, 2);
 254
 255        /*
 256           Initialize the MR97113 chip register
 257         */
 258        data[0] = 0x00;         /* address */
 259        data[1] = 0x0c | 0x01;  /* reg 0 */
 260        data[2] = 0x01;         /* reg 1 */
 261        data[3] = gspca_dev->pixfmt.width / 8;  /* h_size , reg 2 */
 262        data[4] = gspca_dev->pixfmt.height / 8; /* v_size , reg 3 */
 263        data[5] = 0x30;         /* reg 4, MI, PAS5101 :
 264                                 *      0x30 for 24mhz , 0x28 for 12mhz */
 265        data[6] = 0x02;         /* reg 5, H start - was 0x04 */
 266        data[7] = v4l2_ctrl_g_ctrl(sd->gamma) * 0x40;   /* reg 0x06: gamma */
 267        data[8] = 0x01;         /* reg 7, V start - was 0x03 */
 268/*      if (h_size == 320 ) */
 269/*              data[9]= 0x56;   * reg 8, 24MHz, 2:1 scale down */
 270/*      else */
 271        data[9] = 0x52;         /* reg 8, 24MHz, no scale down */
 272/*jfm: from win trace*/
 273        data[10] = 0x18;
 274
 275        reg_w(gspca_dev, 11);
 276
 277        data[0] = 0x23;         /* address */
 278        data[1] = 0x09;         /* reg 35, append frame header */
 279
 280        reg_w(gspca_dev, 2);
 281
 282        data[0] = 0x3c;         /* address */
 283/*      if (gspca_dev->width == 1280) */
 284/*              data[1] = 200;   * reg 60, pc-cam frame size
 285                                 *      (unit: 4KB) 800KB */
 286/*      else */
 287        data[1] = 50;           /* 50 reg 60, pc-cam frame size
 288                                 *      (unit: 4KB) 200KB */
 289        reg_w(gspca_dev, 2);
 290
 291        /* auto dark-gain */
 292        data[0] = 0x5e;         /* address */
 293        data[1] = 0;            /* reg 94, Y Gain (auto) */
 294/*jfm: from win trace*/
 295                                /* reg 0x5f/0x60 (LE) = saturation */
 296                                /* h (60): xxxx x100
 297                                 * l (5f): xxxx x000 */
 298        data[2] = v4l2_ctrl_g_ctrl(sd->saturation) << 3;
 299        data[3] = ((v4l2_ctrl_g_ctrl(sd->saturation) >> 2) & 0xf8) | 0x04;
 300        data[4] = v4l2_ctrl_g_ctrl(sd->brightness); /* reg 0x61 = brightness */
 301        data[5] = 0x00;
 302
 303        reg_w(gspca_dev, 6);
 304
 305        data[0] = 0x67;
 306/*jfm: from win trace*/
 307        data[1] = v4l2_ctrl_g_ctrl(sd->sharpness) * 4 + 3;
 308        data[2] = 0x14;
 309        reg_w(gspca_dev, 3);
 310
 311        data[0] = 0x69;
 312        data[1] = 0x2f;
 313        data[2] = 0x28;
 314        data[3] = 0x42;
 315        reg_w(gspca_dev, 4);
 316
 317        data[0] = 0x63;
 318        data[1] = 0x07;
 319        reg_w(gspca_dev, 2);
 320/*jfm: win trace - many writes here to reg 0x64*/
 321
 322        /* initialize the MI sensor */
 323        for (i = 0; i < sizeof mi_data; i++)
 324                mi_w(gspca_dev, i + 1, mi_data[i]);
 325
 326        data[0] = 0x00;
 327        data[1] = 0x4d;         /* ISOC transferring enable... */
 328        reg_w(gspca_dev, 2);
 329
 330        setilluminators(gspca_dev, v4l2_ctrl_g_ctrl(sd->illum_top),
 331                                   v4l2_ctrl_g_ctrl(sd->illum_bottom));
 332
 333        return gspca_dev->usb_err;
 334}
 335
 336static void sd_stopN(struct gspca_dev *gspca_dev)
 337{
 338        struct sd *sd = (struct sd *) gspca_dev;
 339
 340        if (v4l2_ctrl_g_ctrl(sd->illum_top) ||
 341            v4l2_ctrl_g_ctrl(sd->illum_bottom)) {
 342                setilluminators(gspca_dev, false, false);
 343                msleep(20);
 344        }
 345
 346        gspca_dev->usb_buf[0] = 1;
 347        gspca_dev->usb_buf[1] = 0;
 348        reg_w(gspca_dev, 2);
 349}
 350
 351static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 352                        u8 *data,                       /* isoc packet */
 353                        int len)                        /* iso packet length */
 354{
 355        struct sd *sd = (struct sd *) gspca_dev;
 356        int p;
 357
 358        if (len < 6) {
 359/*              gspca_dev->last_packet_type = DISCARD_PACKET; */
 360                return;
 361        }
 362        for (p = 0; p < len - 6; p++) {
 363                if (data[0 + p] == 0xff
 364                    && data[1 + p] == 0xff
 365                    && data[2 + p] == 0x00
 366                    && data[3 + p] == 0xff
 367                    && data[4 + p] == 0x96) {
 368                        if (data[5 + p] == 0x64
 369                            || data[5 + p] == 0x65
 370                            || data[5 + p] == 0x66
 371                            || data[5 + p] == 0x67) {
 372                                gspca_dbg(gspca_dev, D_PACK, "sof offset: %d len: %d\n",
 373                                          p, len);
 374                                gspca_frame_add(gspca_dev, LAST_PACKET,
 375                                                data, p);
 376
 377                                /* put the JPEG header */
 378                                gspca_frame_add(gspca_dev, FIRST_PACKET,
 379                                        sd->jpeg_hdr, JPEG_HDR_SZ);
 380                                data += p + 16;
 381                                len -= p + 16;
 382                                break;
 383                        }
 384                }
 385        }
 386        gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 387}
 388
 389/* sub-driver description */
 390static const struct sd_desc sd_desc = {
 391        .name = MODULE_NAME,
 392        .config = sd_config,
 393        .init = sd_init,
 394        .init_controls = sd_init_controls,
 395        .start = sd_start,
 396        .stopN = sd_stopN,
 397        .pkt_scan = sd_pkt_scan,
 398};
 399
 400/* -- module initialisation -- */
 401static const struct usb_device_id device_table[] = {
 402        {USB_DEVICE(0x093a, 0x050f)},
 403        {}
 404};
 405MODULE_DEVICE_TABLE(usb, device_table);
 406
 407/* -- device connect -- */
 408static int sd_probe(struct usb_interface *intf,
 409                        const struct usb_device_id *id)
 410{
 411        return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
 412                                THIS_MODULE);
 413}
 414
 415static struct usb_driver sd_driver = {
 416        .name = MODULE_NAME,
 417        .id_table = device_table,
 418        .probe = sd_probe,
 419        .disconnect = gspca_disconnect,
 420#ifdef CONFIG_PM
 421        .suspend = gspca_suspend,
 422        .resume = gspca_resume,
 423        .reset_resume = gspca_resume,
 424#endif
 425};
 426
 427module_usb_driver(sd_driver);
 428