linux/drivers/media/usb/gspca/pac207.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Pixart PAC207BCA library
   4 *
   5 * Copyright (C) 2008 Hans de Goede <hdegoede@redhat.com>
   6 * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li
   7 * Copyleft (C) 2005 Michel Xhaard mxhaard@magic.fr
   8 *
   9 * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
  10 */
  11
  12#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  13
  14#define MODULE_NAME "pac207"
  15
  16#include <linux/input.h>
  17#include "gspca.h"
  18/* Include pac common sof detection functions */
  19#include "pac_common.h"
  20
  21MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
  22MODULE_DESCRIPTION("Pixart PAC207");
  23MODULE_LICENSE("GPL");
  24
  25#define PAC207_CTRL_TIMEOUT             100  /* ms */
  26
  27#define PAC207_BRIGHTNESS_MIN           0
  28#define PAC207_BRIGHTNESS_MAX           255
  29#define PAC207_BRIGHTNESS_DEFAULT       46
  30#define PAC207_BRIGHTNESS_REG           0x08
  31
  32#define PAC207_EXPOSURE_MIN             3
  33#define PAC207_EXPOSURE_MAX             90 /* 1 sec expo time / 1 fps */
  34#define PAC207_EXPOSURE_DEFAULT         5 /* power on default: 3 */
  35#define PAC207_EXPOSURE_REG             0x02
  36
  37#define PAC207_GAIN_MIN                 0
  38#define PAC207_GAIN_MAX                 31
  39#define PAC207_GAIN_DEFAULT             7 /* power on default: 9 */
  40#define PAC207_GAIN_REG                 0x0e
  41
  42#define PAC207_AUTOGAIN_DEADZONE        30
  43
  44/* global parameters */
  45static int led_invert;
  46module_param(led_invert, int, 0644);
  47MODULE_PARM_DESC(led_invert, "Invert led");
  48
  49/* specific webcam descriptor */
  50struct sd {
  51        struct gspca_dev gspca_dev;             /* !! must be the first item */
  52
  53        struct v4l2_ctrl *brightness;
  54
  55        u8 mode;
  56        u8 sof_read;
  57        u8 header_read;
  58        u8 autogain_ignore_frames;
  59
  60        atomic_t avg_lum;
  61};
  62
  63static const struct v4l2_pix_format sif_mode[] = {
  64        {176, 144, V4L2_PIX_FMT_PAC207, V4L2_FIELD_NONE,
  65                .bytesperline = 176,
  66                .sizeimage = (176 + 2) * 144,
  67                        /* uncompressed, add 2 bytes / line for line header */
  68                .colorspace = V4L2_COLORSPACE_SRGB,
  69                .priv = 1},
  70        {352, 288, V4L2_PIX_FMT_PAC207, V4L2_FIELD_NONE,
  71                .bytesperline = 352,
  72                        /* compressed, but only when needed (not compressed
  73                           when the framerate is low) */
  74                .sizeimage = (352 + 2) * 288,
  75                .colorspace = V4L2_COLORSPACE_SRGB,
  76                .priv = 0},
  77};
  78
  79static const __u8 pac207_sensor_init[][8] = {
  80        {0x10, 0x12, 0x0d, 0x12, 0x0c, 0x01, 0x29, 0x84},
  81        {0x49, 0x64, 0x64, 0x64, 0x04, 0x10, 0xf0, 0x30},
  82        {0x00, 0x00, 0x00, 0x70, 0xa0, 0xf8, 0x00, 0x00},
  83        {0x32, 0x00, 0x96, 0x00, 0xa2, 0x02, 0xaf, 0x00},
  84};
  85
  86static void pac207_write_regs(struct gspca_dev *gspca_dev, u16 index,
  87        const u8 *buffer, u16 length)
  88{
  89        struct usb_device *udev = gspca_dev->dev;
  90        int err;
  91
  92        if (gspca_dev->usb_err < 0)
  93                return;
  94
  95        memcpy(gspca_dev->usb_buf, buffer, length);
  96
  97        err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x01,
  98                        USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
  99                        0x00, index,
 100                        gspca_dev->usb_buf, length, PAC207_CTRL_TIMEOUT);
 101        if (err < 0) {
 102                pr_err("Failed to write registers to index 0x%04X, error %d\n",
 103                       index, err);
 104                gspca_dev->usb_err = err;
 105        }
 106}
 107
 108static void pac207_write_reg(struct gspca_dev *gspca_dev, u16 index, u16 value)
 109{
 110        struct usb_device *udev = gspca_dev->dev;
 111        int err;
 112
 113        if (gspca_dev->usb_err < 0)
 114                return;
 115
 116        err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00,
 117                        USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
 118                        value, index, NULL, 0, PAC207_CTRL_TIMEOUT);
 119        if (err) {
 120                pr_err("Failed to write a register (index 0x%04X, value 0x%02X, error %d)\n",
 121                       index, value, err);
 122                gspca_dev->usb_err = err;
 123        }
 124}
 125
 126static int pac207_read_reg(struct gspca_dev *gspca_dev, u16 index)
 127{
 128        struct usb_device *udev = gspca_dev->dev;
 129        int res;
 130
 131        if (gspca_dev->usb_err < 0)
 132                return 0;
 133
 134        res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00,
 135                        USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
 136                        0x00, index,
 137                        gspca_dev->usb_buf, 1, PAC207_CTRL_TIMEOUT);
 138        if (res < 0) {
 139                pr_err("Failed to read a register (index 0x%04X, error %d)\n",
 140                       index, res);
 141                gspca_dev->usb_err = res;
 142                return 0;
 143        }
 144
 145        return gspca_dev->usb_buf[0];
 146}
 147
 148/* this function is called at probe time */
 149static int sd_config(struct gspca_dev *gspca_dev,
 150                        const struct usb_device_id *id)
 151{
 152        struct cam *cam;
 153        u8 idreg[2];
 154
 155        idreg[0] = pac207_read_reg(gspca_dev, 0x0000);
 156        idreg[1] = pac207_read_reg(gspca_dev, 0x0001);
 157        idreg[0] = ((idreg[0] & 0x0f) << 4) | ((idreg[1] & 0xf0) >> 4);
 158        idreg[1] = idreg[1] & 0x0f;
 159        gspca_dbg(gspca_dev, D_PROBE, "Pixart Sensor ID 0x%02X Chips ID 0x%02X\n",
 160                  idreg[0], idreg[1]);
 161
 162        if (idreg[0] != 0x27) {
 163                gspca_dbg(gspca_dev, D_PROBE, "Error invalid sensor ID!\n");
 164                return -ENODEV;
 165        }
 166
 167        gspca_dbg(gspca_dev, D_PROBE,
 168                  "Pixart PAC207BCA Image Processor and Control Chip detected (vid/pid 0x%04X:0x%04X)\n",
 169                  id->idVendor, id->idProduct);
 170
 171        cam = &gspca_dev->cam;
 172        cam->cam_mode = sif_mode;
 173        cam->nmodes = ARRAY_SIZE(sif_mode);
 174
 175        return 0;
 176}
 177
 178/* this function is called at probe and resume time */
 179static int sd_init(struct gspca_dev *gspca_dev)
 180{
 181        u8 mode;
 182
 183        /* mode: Image Format (Bit 0), LED (1), Compr. test mode (2) */
 184        if (led_invert)
 185                mode = 0x02;
 186        else
 187                mode = 0x00;
 188        pac207_write_reg(gspca_dev, 0x41, mode);
 189        pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
 190
 191        return gspca_dev->usb_err;
 192}
 193
 194static void setcontrol(struct gspca_dev *gspca_dev, u16 reg, u16 val)
 195{
 196        pac207_write_reg(gspca_dev, reg, val);
 197        pac207_write_reg(gspca_dev, 0x13, 0x01);        /* Bit 0, auto clear */
 198        pac207_write_reg(gspca_dev, 0x1c, 0x01);        /* not documented */
 199}
 200
 201static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
 202{
 203        struct gspca_dev *gspca_dev =
 204                container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
 205        struct sd *sd = (struct sd *)gspca_dev;
 206
 207        gspca_dev->usb_err = 0;
 208
 209        if (ctrl->id == V4L2_CID_AUTOGAIN && ctrl->is_new && ctrl->val) {
 210                /* when switching to autogain set defaults to make sure
 211                   we are on a valid point of the autogain gain /
 212                   exposure knee graph, and give this change time to
 213                   take effect before doing autogain. */
 214                gspca_dev->exposure->val    = PAC207_EXPOSURE_DEFAULT;
 215                gspca_dev->gain->val        = PAC207_GAIN_DEFAULT;
 216                sd->autogain_ignore_frames  = PAC_AUTOGAIN_IGNORE_FRAMES;
 217        }
 218
 219        if (!gspca_dev->streaming)
 220                return 0;
 221
 222        switch (ctrl->id) {
 223        case V4L2_CID_BRIGHTNESS:
 224                setcontrol(gspca_dev, PAC207_BRIGHTNESS_REG, ctrl->val);
 225                break;
 226        case V4L2_CID_AUTOGAIN:
 227                if (gspca_dev->exposure->is_new || (ctrl->is_new && ctrl->val))
 228                        setcontrol(gspca_dev, PAC207_EXPOSURE_REG,
 229                                   gspca_dev->exposure->val);
 230                if (gspca_dev->gain->is_new || (ctrl->is_new && ctrl->val))
 231                        setcontrol(gspca_dev, PAC207_GAIN_REG,
 232                                   gspca_dev->gain->val);
 233                break;
 234        default:
 235                return -EINVAL;
 236        }
 237        return gspca_dev->usb_err;
 238}
 239
 240static const struct v4l2_ctrl_ops sd_ctrl_ops = {
 241        .s_ctrl = sd_s_ctrl,
 242};
 243
 244/* this function is called at probe time */
 245static int sd_init_controls(struct gspca_dev *gspca_dev)
 246{
 247        struct sd *sd = (struct sd *) gspca_dev;
 248        struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
 249
 250        gspca_dev->vdev.ctrl_handler = hdl;
 251        v4l2_ctrl_handler_init(hdl, 4);
 252
 253        sd->brightness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
 254                                V4L2_CID_BRIGHTNESS,
 255                                PAC207_BRIGHTNESS_MIN, PAC207_BRIGHTNESS_MAX,
 256                                1, PAC207_BRIGHTNESS_DEFAULT);
 257        gspca_dev->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
 258                                V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
 259        gspca_dev->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
 260                                V4L2_CID_EXPOSURE,
 261                                PAC207_EXPOSURE_MIN, PAC207_EXPOSURE_MAX,
 262                                1, PAC207_EXPOSURE_DEFAULT);
 263        gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
 264                                V4L2_CID_GAIN,
 265                                PAC207_GAIN_MIN, PAC207_GAIN_MAX,
 266                                1, PAC207_GAIN_DEFAULT);
 267        if (hdl->error) {
 268                pr_err("Could not initialize controls\n");
 269                return hdl->error;
 270        }
 271        v4l2_ctrl_auto_cluster(3, &gspca_dev->autogain, 0, false);
 272        return 0;
 273}
 274
 275/* -- start the camera -- */
 276static int sd_start(struct gspca_dev *gspca_dev)
 277{
 278        struct sd *sd = (struct sd *) gspca_dev;
 279        __u8 mode;
 280
 281        pac207_write_reg(gspca_dev, 0x0f, 0x10); /* Power control (Bit 6-0) */
 282        pac207_write_regs(gspca_dev, 0x0002, pac207_sensor_init[0], 8);
 283        pac207_write_regs(gspca_dev, 0x000a, pac207_sensor_init[1], 8);
 284        pac207_write_regs(gspca_dev, 0x0012, pac207_sensor_init[2], 8);
 285        pac207_write_regs(gspca_dev, 0x0042, pac207_sensor_init[3], 8);
 286
 287        /* Compression Balance */
 288        if (gspca_dev->pixfmt.width == 176)
 289                pac207_write_reg(gspca_dev, 0x4a, 0xff);
 290        else
 291                pac207_write_reg(gspca_dev, 0x4a, 0x30);
 292        pac207_write_reg(gspca_dev, 0x4b, 0x00); /* Sram test value */
 293        pac207_write_reg(gspca_dev, 0x08, v4l2_ctrl_g_ctrl(sd->brightness));
 294
 295        /* PGA global gain (Bit 4-0) */
 296        pac207_write_reg(gspca_dev, 0x0e,
 297                v4l2_ctrl_g_ctrl(gspca_dev->gain));
 298        pac207_write_reg(gspca_dev, 0x02,
 299                v4l2_ctrl_g_ctrl(gspca_dev->exposure)); /* PXCK = 12MHz /n */
 300
 301        /* mode: Image Format (Bit 0), LED (1), Compr. test mode (2) */
 302        if (led_invert)
 303                mode = 0x00;
 304        else
 305                mode = 0x02;
 306        if (gspca_dev->pixfmt.width == 176) {   /* 176x144 */
 307                mode |= 0x01;
 308                gspca_dbg(gspca_dev, D_STREAM, "pac207_start mode 176x144\n");
 309        } else {                                /* 352x288 */
 310                gspca_dbg(gspca_dev, D_STREAM, "pac207_start mode 352x288\n");
 311        }
 312        pac207_write_reg(gspca_dev, 0x41, mode);
 313
 314        pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
 315        pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
 316        msleep(10);
 317        pac207_write_reg(gspca_dev, 0x40, 0x01); /* Start ISO pipe */
 318
 319        sd->sof_read = 0;
 320        sd->autogain_ignore_frames = 0;
 321        atomic_set(&sd->avg_lum, -1);
 322        return gspca_dev->usb_err;
 323}
 324
 325static void sd_stopN(struct gspca_dev *gspca_dev)
 326{
 327        u8 mode;
 328
 329        /* mode: Image Format (Bit 0), LED (1), Compr. test mode (2) */
 330        if (led_invert)
 331                mode = 0x02;
 332        else
 333                mode = 0x00;
 334        pac207_write_reg(gspca_dev, 0x40, 0x00); /* Stop ISO pipe */
 335        pac207_write_reg(gspca_dev, 0x41, mode); /* Turn off LED */
 336        pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
 337}
 338
 339
 340static void pac207_do_auto_gain(struct gspca_dev *gspca_dev)
 341{
 342        struct sd *sd = (struct sd *) gspca_dev;
 343        int avg_lum = atomic_read(&sd->avg_lum);
 344
 345        if (avg_lum == -1)
 346                return;
 347
 348        if (sd->autogain_ignore_frames > 0)
 349                sd->autogain_ignore_frames--;
 350        else if (gspca_coarse_grained_expo_autogain(gspca_dev, avg_lum,
 351                        90, PAC207_AUTOGAIN_DEADZONE))
 352                sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
 353}
 354
 355static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 356                        u8 *data,
 357                        int len)
 358{
 359        struct sd *sd = (struct sd *) gspca_dev;
 360        unsigned char *sof;
 361
 362        sof = pac_find_sof(gspca_dev, &sd->sof_read, data, len);
 363        if (sof) {
 364                int n;
 365
 366                /* finish decoding current frame */
 367                n = sof - data;
 368                if (n > sizeof pac_sof_marker)
 369                        n -= sizeof pac_sof_marker;
 370                else
 371                        n = 0;
 372                gspca_frame_add(gspca_dev, LAST_PACKET,
 373                                data, n);
 374                sd->header_read = 0;
 375                gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0);
 376                len -= sof - data;
 377                data = sof;
 378        }
 379        if (sd->header_read < 11) {
 380                int needed;
 381
 382                /* get average lumination from frame header (byte 5) */
 383                if (sd->header_read < 5) {
 384                        needed = 5 - sd->header_read;
 385                        if (len >= needed)
 386                                atomic_set(&sd->avg_lum, data[needed - 1]);
 387                }
 388                /* skip the rest of the header */
 389                needed = 11 - sd->header_read;
 390                if (len <= needed) {
 391                        sd->header_read += len;
 392                        return;
 393                }
 394                data += needed;
 395                len -= needed;
 396                sd->header_read = 11;
 397        }
 398
 399        gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
 400}
 401
 402#if IS_ENABLED(CONFIG_INPUT)
 403static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
 404                        u8 *data,               /* interrupt packet data */
 405                        int len)                /* interrupt packet length */
 406{
 407        int ret = -EINVAL;
 408
 409        if (len == 2 && data[0] == 0x5a && data[1] == 0x5a) {
 410                input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
 411                input_sync(gspca_dev->input_dev);
 412                input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
 413                input_sync(gspca_dev->input_dev);
 414                ret = 0;
 415        }
 416
 417        return ret;
 418}
 419#endif
 420
 421/* sub-driver description */
 422static const struct sd_desc sd_desc = {
 423        .name = MODULE_NAME,
 424        .config = sd_config,
 425        .init = sd_init,
 426        .init_controls = sd_init_controls,
 427        .start = sd_start,
 428        .stopN = sd_stopN,
 429        .dq_callback = pac207_do_auto_gain,
 430        .pkt_scan = sd_pkt_scan,
 431#if IS_ENABLED(CONFIG_INPUT)
 432        .int_pkt_scan = sd_int_pkt_scan,
 433#endif
 434};
 435
 436/* -- module initialisation -- */
 437static const struct usb_device_id device_table[] = {
 438        {USB_DEVICE(0x041e, 0x4028)},
 439        {USB_DEVICE(0x093a, 0x2460)},
 440        {USB_DEVICE(0x093a, 0x2461)},
 441        {USB_DEVICE(0x093a, 0x2463)},
 442        {USB_DEVICE(0x093a, 0x2464)},
 443        {USB_DEVICE(0x093a, 0x2468)},
 444        {USB_DEVICE(0x093a, 0x2470)},
 445        {USB_DEVICE(0x093a, 0x2471)},
 446        {USB_DEVICE(0x093a, 0x2472)},
 447        {USB_DEVICE(0x093a, 0x2474)},
 448        {USB_DEVICE(0x093a, 0x2476)},
 449        {USB_DEVICE(0x145f, 0x013a)},
 450        {USB_DEVICE(0x2001, 0xf115)},
 451        {}
 452};
 453MODULE_DEVICE_TABLE(usb, device_table);
 454
 455/* -- device connect -- */
 456static int sd_probe(struct usb_interface *intf,
 457                        const struct usb_device_id *id)
 458{
 459        return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
 460                                THIS_MODULE);
 461}
 462
 463static struct usb_driver sd_driver = {
 464        .name = MODULE_NAME,
 465        .id_table = device_table,
 466        .probe = sd_probe,
 467        .disconnect = gspca_disconnect,
 468#ifdef CONFIG_PM
 469        .suspend = gspca_suspend,
 470        .resume = gspca_resume,
 471        .reset_resume = gspca_resume,
 472#endif
 473};
 474
 475module_usb_driver(sd_driver);
 476