162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Sunplus spca504(abc) spca533 spca536 library 462306a36Sopenharmony_ci * Copyright (C) 2005 Michel Xhaard mxhaard@magic.fr 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * V4L2 by Jean-Francois Moine <http://moinejf.free.fr> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#define MODULE_NAME "sunplus" 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include "gspca.h" 1462306a36Sopenharmony_ci#include "jpeg.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ciMODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>"); 1762306a36Sopenharmony_ciMODULE_DESCRIPTION("GSPCA/SPCA5xx USB Camera Driver"); 1862306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define QUALITY 85 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci/* specific webcam descriptor */ 2362306a36Sopenharmony_cistruct sd { 2462306a36Sopenharmony_ci struct gspca_dev gspca_dev; /* !! must be the first item */ 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci bool autogain; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci u8 bridge; 2962306a36Sopenharmony_ci#define BRIDGE_SPCA504 0 3062306a36Sopenharmony_ci#define BRIDGE_SPCA504B 1 3162306a36Sopenharmony_ci#define BRIDGE_SPCA504C 2 3262306a36Sopenharmony_ci#define BRIDGE_SPCA533 3 3362306a36Sopenharmony_ci#define BRIDGE_SPCA536 4 3462306a36Sopenharmony_ci u8 subtype; 3562306a36Sopenharmony_ci#define AiptekMiniPenCam13 1 3662306a36Sopenharmony_ci#define LogitechClickSmart420 2 3762306a36Sopenharmony_ci#define LogitechClickSmart820 3 3862306a36Sopenharmony_ci#define MegapixV4 4 3962306a36Sopenharmony_ci#define MegaImageVI 5 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci u8 jpeg_hdr[JPEG_HDR_SZ]; 4262306a36Sopenharmony_ci}; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistatic const struct v4l2_pix_format vga_mode[] = { 4562306a36Sopenharmony_ci {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, 4662306a36Sopenharmony_ci .bytesperline = 320, 4762306a36Sopenharmony_ci .sizeimage = 320 * 240 * 3 / 8 + 590, 4862306a36Sopenharmony_ci .colorspace = V4L2_COLORSPACE_JPEG, 4962306a36Sopenharmony_ci .priv = 2}, 5062306a36Sopenharmony_ci {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, 5162306a36Sopenharmony_ci .bytesperline = 640, 5262306a36Sopenharmony_ci .sizeimage = 640 * 480 * 3 / 8 + 590, 5362306a36Sopenharmony_ci .colorspace = V4L2_COLORSPACE_JPEG, 5462306a36Sopenharmony_ci .priv = 1}, 5562306a36Sopenharmony_ci}; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistatic const struct v4l2_pix_format custom_mode[] = { 5862306a36Sopenharmony_ci {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, 5962306a36Sopenharmony_ci .bytesperline = 320, 6062306a36Sopenharmony_ci .sizeimage = 320 * 240 * 3 / 8 + 590, 6162306a36Sopenharmony_ci .colorspace = V4L2_COLORSPACE_JPEG, 6262306a36Sopenharmony_ci .priv = 2}, 6362306a36Sopenharmony_ci {464, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, 6462306a36Sopenharmony_ci .bytesperline = 464, 6562306a36Sopenharmony_ci .sizeimage = 464 * 480 * 3 / 8 + 590, 6662306a36Sopenharmony_ci .colorspace = V4L2_COLORSPACE_JPEG, 6762306a36Sopenharmony_ci .priv = 1}, 6862306a36Sopenharmony_ci}; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic const struct v4l2_pix_format vga_mode2[] = { 7162306a36Sopenharmony_ci {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, 7262306a36Sopenharmony_ci .bytesperline = 176, 7362306a36Sopenharmony_ci .sizeimage = 176 * 144 * 3 / 8 + 590, 7462306a36Sopenharmony_ci .colorspace = V4L2_COLORSPACE_JPEG, 7562306a36Sopenharmony_ci .priv = 4}, 7662306a36Sopenharmony_ci {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, 7762306a36Sopenharmony_ci .bytesperline = 320, 7862306a36Sopenharmony_ci .sizeimage = 320 * 240 * 3 / 8 + 590, 7962306a36Sopenharmony_ci .colorspace = V4L2_COLORSPACE_JPEG, 8062306a36Sopenharmony_ci .priv = 3}, 8162306a36Sopenharmony_ci {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, 8262306a36Sopenharmony_ci .bytesperline = 352, 8362306a36Sopenharmony_ci .sizeimage = 352 * 288 * 3 / 8 + 590, 8462306a36Sopenharmony_ci .colorspace = V4L2_COLORSPACE_JPEG, 8562306a36Sopenharmony_ci .priv = 2}, 8662306a36Sopenharmony_ci {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, 8762306a36Sopenharmony_ci .bytesperline = 640, 8862306a36Sopenharmony_ci .sizeimage = 640 * 480 * 3 / 8 + 590, 8962306a36Sopenharmony_ci .colorspace = V4L2_COLORSPACE_JPEG, 9062306a36Sopenharmony_ci .priv = 1}, 9162306a36Sopenharmony_ci}; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci#define SPCA50X_OFFSET_DATA 10 9462306a36Sopenharmony_ci#define SPCA504_PCCAM600_OFFSET_SNAPSHOT 3 9562306a36Sopenharmony_ci#define SPCA504_PCCAM600_OFFSET_COMPRESS 4 9662306a36Sopenharmony_ci#define SPCA504_PCCAM600_OFFSET_MODE 5 9762306a36Sopenharmony_ci#define SPCA504_PCCAM600_OFFSET_DATA 14 9862306a36Sopenharmony_ci /* Frame packet header offsets for the spca533 */ 9962306a36Sopenharmony_ci#define SPCA533_OFFSET_DATA 16 10062306a36Sopenharmony_ci#define SPCA533_OFFSET_FRAMSEQ 15 10162306a36Sopenharmony_ci/* Frame packet header offsets for the spca536 */ 10262306a36Sopenharmony_ci#define SPCA536_OFFSET_DATA 4 10362306a36Sopenharmony_ci#define SPCA536_OFFSET_FRAMSEQ 1 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistruct cmd { 10662306a36Sopenharmony_ci u8 req; 10762306a36Sopenharmony_ci u16 val; 10862306a36Sopenharmony_ci u16 idx; 10962306a36Sopenharmony_ci}; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci/* Initialisation data for the Creative PC-CAM 600 */ 11262306a36Sopenharmony_cistatic const struct cmd spca504_pccam600_init_data[] = { 11362306a36Sopenharmony_ci/* {0xa0, 0x0000, 0x0503}, * capture mode */ 11462306a36Sopenharmony_ci {0x00, 0x0000, 0x2000}, 11562306a36Sopenharmony_ci {0x00, 0x0013, 0x2301}, 11662306a36Sopenharmony_ci {0x00, 0x0003, 0x2000}, 11762306a36Sopenharmony_ci {0x00, 0x0001, 0x21ac}, 11862306a36Sopenharmony_ci {0x00, 0x0001, 0x21a6}, 11962306a36Sopenharmony_ci {0x00, 0x0000, 0x21a7}, /* brightness */ 12062306a36Sopenharmony_ci {0x00, 0x0020, 0x21a8}, /* contrast */ 12162306a36Sopenharmony_ci {0x00, 0x0001, 0x21ac}, /* sat/hue */ 12262306a36Sopenharmony_ci {0x00, 0x0000, 0x21ad}, /* hue */ 12362306a36Sopenharmony_ci {0x00, 0x001a, 0x21ae}, /* saturation */ 12462306a36Sopenharmony_ci {0x00, 0x0002, 0x21a3}, /* gamma */ 12562306a36Sopenharmony_ci {0x30, 0x0154, 0x0008}, 12662306a36Sopenharmony_ci {0x30, 0x0004, 0x0006}, 12762306a36Sopenharmony_ci {0x30, 0x0258, 0x0009}, 12862306a36Sopenharmony_ci {0x30, 0x0004, 0x0000}, 12962306a36Sopenharmony_ci {0x30, 0x0093, 0x0004}, 13062306a36Sopenharmony_ci {0x30, 0x0066, 0x0005}, 13162306a36Sopenharmony_ci {0x00, 0x0000, 0x2000}, 13262306a36Sopenharmony_ci {0x00, 0x0013, 0x2301}, 13362306a36Sopenharmony_ci {0x00, 0x0003, 0x2000}, 13462306a36Sopenharmony_ci {0x00, 0x0013, 0x2301}, 13562306a36Sopenharmony_ci {0x00, 0x0003, 0x2000}, 13662306a36Sopenharmony_ci}; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci/* Creative PC-CAM 600 specific open data, sent before using the 13962306a36Sopenharmony_ci * generic initialisation data from spca504_open_data. 14062306a36Sopenharmony_ci */ 14162306a36Sopenharmony_cistatic const struct cmd spca504_pccam600_open_data[] = { 14262306a36Sopenharmony_ci {0x00, 0x0001, 0x2501}, 14362306a36Sopenharmony_ci {0x20, 0x0500, 0x0001}, /* snapshot mode */ 14462306a36Sopenharmony_ci {0x00, 0x0003, 0x2880}, 14562306a36Sopenharmony_ci {0x00, 0x0001, 0x2881}, 14662306a36Sopenharmony_ci}; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci/* Initialisation data for the logitech clicksmart 420 */ 14962306a36Sopenharmony_cistatic const struct cmd spca504A_clicksmart420_init_data[] = { 15062306a36Sopenharmony_ci/* {0xa0, 0x0000, 0x0503}, * capture mode */ 15162306a36Sopenharmony_ci {0x00, 0x0000, 0x2000}, 15262306a36Sopenharmony_ci {0x00, 0x0013, 0x2301}, 15362306a36Sopenharmony_ci {0x00, 0x0003, 0x2000}, 15462306a36Sopenharmony_ci {0x00, 0x0001, 0x21ac}, 15562306a36Sopenharmony_ci {0x00, 0x0001, 0x21a6}, 15662306a36Sopenharmony_ci {0x00, 0x0000, 0x21a7}, /* brightness */ 15762306a36Sopenharmony_ci {0x00, 0x0020, 0x21a8}, /* contrast */ 15862306a36Sopenharmony_ci {0x00, 0x0001, 0x21ac}, /* sat/hue */ 15962306a36Sopenharmony_ci {0x00, 0x0000, 0x21ad}, /* hue */ 16062306a36Sopenharmony_ci {0x00, 0x001a, 0x21ae}, /* saturation */ 16162306a36Sopenharmony_ci {0x00, 0x0002, 0x21a3}, /* gamma */ 16262306a36Sopenharmony_ci {0x30, 0x0004, 0x000a}, 16362306a36Sopenharmony_ci {0xb0, 0x0001, 0x0000}, 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci {0xa1, 0x0080, 0x0001}, 16662306a36Sopenharmony_ci {0x30, 0x0049, 0x0000}, 16762306a36Sopenharmony_ci {0x30, 0x0060, 0x0005}, 16862306a36Sopenharmony_ci {0x0c, 0x0004, 0x0000}, 16962306a36Sopenharmony_ci {0x00, 0x0000, 0x0000}, 17062306a36Sopenharmony_ci {0x00, 0x0000, 0x2000}, 17162306a36Sopenharmony_ci {0x00, 0x0013, 0x2301}, 17262306a36Sopenharmony_ci {0x00, 0x0003, 0x2000}, 17362306a36Sopenharmony_ci}; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci/* clicksmart 420 open data ? */ 17662306a36Sopenharmony_cistatic const struct cmd spca504A_clicksmart420_open_data[] = { 17762306a36Sopenharmony_ci {0x00, 0x0001, 0x2501}, 17862306a36Sopenharmony_ci {0x20, 0x0502, 0x0000}, 17962306a36Sopenharmony_ci {0x06, 0x0000, 0x0000}, 18062306a36Sopenharmony_ci {0x00, 0x0004, 0x2880}, 18162306a36Sopenharmony_ci {0x00, 0x0001, 0x2881}, 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci {0xa0, 0x0000, 0x0503}, 18462306a36Sopenharmony_ci}; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_cistatic const u8 qtable_creative_pccam[2][64] = { 18762306a36Sopenharmony_ci { /* Q-table Y-components */ 18862306a36Sopenharmony_ci 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12, 18962306a36Sopenharmony_ci 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11, 19062306a36Sopenharmony_ci 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11, 19162306a36Sopenharmony_ci 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13, 19262306a36Sopenharmony_ci 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17, 19362306a36Sopenharmony_ci 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c, 19462306a36Sopenharmony_ci 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e, 19562306a36Sopenharmony_ci 0x16, 0x1c, 0x1d, 0x1d, 0x22, 0x1e, 0x1f, 0x1e}, 19662306a36Sopenharmony_ci { /* Q-table C-components */ 19762306a36Sopenharmony_ci 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e, 19862306a36Sopenharmony_ci 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 19962306a36Sopenharmony_ci 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 20062306a36Sopenharmony_ci 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 20162306a36Sopenharmony_ci 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 20262306a36Sopenharmony_ci 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 20362306a36Sopenharmony_ci 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 20462306a36Sopenharmony_ci 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e} 20562306a36Sopenharmony_ci}; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci/* FIXME: This Q-table is identical to the Creative PC-CAM one, 20862306a36Sopenharmony_ci * except for one byte. Possibly a typo? 20962306a36Sopenharmony_ci * NWG: 18/05/2003. 21062306a36Sopenharmony_ci */ 21162306a36Sopenharmony_cistatic const u8 qtable_spca504_default[2][64] = { 21262306a36Sopenharmony_ci { /* Q-table Y-components */ 21362306a36Sopenharmony_ci 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12, 21462306a36Sopenharmony_ci 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11, 21562306a36Sopenharmony_ci 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11, 21662306a36Sopenharmony_ci 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13, 21762306a36Sopenharmony_ci 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17, 21862306a36Sopenharmony_ci 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c, 21962306a36Sopenharmony_ci 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e, 22062306a36Sopenharmony_ci 0x16, 0x1c, 0x1d, 0x1d, 0x1d /* 0x22 */ , 0x1e, 0x1f, 0x1e, 22162306a36Sopenharmony_ci }, 22262306a36Sopenharmony_ci { /* Q-table C-components */ 22362306a36Sopenharmony_ci 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e, 22462306a36Sopenharmony_ci 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 22562306a36Sopenharmony_ci 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 22662306a36Sopenharmony_ci 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 22762306a36Sopenharmony_ci 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 22862306a36Sopenharmony_ci 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 22962306a36Sopenharmony_ci 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 23062306a36Sopenharmony_ci 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e} 23162306a36Sopenharmony_ci}; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci/* read <len> bytes to gspca_dev->usb_buf */ 23462306a36Sopenharmony_cistatic void reg_r(struct gspca_dev *gspca_dev, 23562306a36Sopenharmony_ci u8 req, 23662306a36Sopenharmony_ci u16 index, 23762306a36Sopenharmony_ci u16 len) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci int ret; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci if (len > USB_BUF_SZ) { 24262306a36Sopenharmony_ci gspca_err(gspca_dev, "reg_r: buffer overflow\n"); 24362306a36Sopenharmony_ci return; 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci if (len == 0) { 24662306a36Sopenharmony_ci gspca_err(gspca_dev, "reg_r: zero-length read\n"); 24762306a36Sopenharmony_ci return; 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci if (gspca_dev->usb_err < 0) 25062306a36Sopenharmony_ci return; 25162306a36Sopenharmony_ci ret = usb_control_msg(gspca_dev->dev, 25262306a36Sopenharmony_ci usb_rcvctrlpipe(gspca_dev->dev, 0), 25362306a36Sopenharmony_ci req, 25462306a36Sopenharmony_ci USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 25562306a36Sopenharmony_ci 0, /* value */ 25662306a36Sopenharmony_ci index, 25762306a36Sopenharmony_ci gspca_dev->usb_buf, len, 25862306a36Sopenharmony_ci 500); 25962306a36Sopenharmony_ci if (ret < 0) { 26062306a36Sopenharmony_ci pr_err("reg_r err %d\n", ret); 26162306a36Sopenharmony_ci gspca_dev->usb_err = ret; 26262306a36Sopenharmony_ci /* 26362306a36Sopenharmony_ci * Make sure the buffer is zeroed to avoid uninitialized 26462306a36Sopenharmony_ci * values. 26562306a36Sopenharmony_ci */ 26662306a36Sopenharmony_ci memset(gspca_dev->usb_buf, 0, USB_BUF_SZ); 26762306a36Sopenharmony_ci } 26862306a36Sopenharmony_ci} 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci/* write one byte */ 27162306a36Sopenharmony_cistatic void reg_w_1(struct gspca_dev *gspca_dev, 27262306a36Sopenharmony_ci u8 req, 27362306a36Sopenharmony_ci u16 value, 27462306a36Sopenharmony_ci u16 index, 27562306a36Sopenharmony_ci u16 byte) 27662306a36Sopenharmony_ci{ 27762306a36Sopenharmony_ci int ret; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci if (gspca_dev->usb_err < 0) 28062306a36Sopenharmony_ci return; 28162306a36Sopenharmony_ci gspca_dev->usb_buf[0] = byte; 28262306a36Sopenharmony_ci ret = usb_control_msg(gspca_dev->dev, 28362306a36Sopenharmony_ci usb_sndctrlpipe(gspca_dev->dev, 0), 28462306a36Sopenharmony_ci req, 28562306a36Sopenharmony_ci USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 28662306a36Sopenharmony_ci value, index, 28762306a36Sopenharmony_ci gspca_dev->usb_buf, 1, 28862306a36Sopenharmony_ci 500); 28962306a36Sopenharmony_ci if (ret < 0) { 29062306a36Sopenharmony_ci pr_err("reg_w_1 err %d\n", ret); 29162306a36Sopenharmony_ci gspca_dev->usb_err = ret; 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci} 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci/* write req / index / value */ 29662306a36Sopenharmony_cistatic void reg_w_riv(struct gspca_dev *gspca_dev, 29762306a36Sopenharmony_ci u8 req, u16 index, u16 value) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci struct usb_device *dev = gspca_dev->dev; 30062306a36Sopenharmony_ci int ret; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci if (gspca_dev->usb_err < 0) 30362306a36Sopenharmony_ci return; 30462306a36Sopenharmony_ci ret = usb_control_msg(dev, 30562306a36Sopenharmony_ci usb_sndctrlpipe(dev, 0), 30662306a36Sopenharmony_ci req, 30762306a36Sopenharmony_ci USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 30862306a36Sopenharmony_ci value, index, NULL, 0, 500); 30962306a36Sopenharmony_ci if (ret < 0) { 31062306a36Sopenharmony_ci pr_err("reg_w_riv err %d\n", ret); 31162306a36Sopenharmony_ci gspca_dev->usb_err = ret; 31262306a36Sopenharmony_ci return; 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_USBO, "reg_w_riv: 0x%02x,0x%04x:0x%04x\n", 31562306a36Sopenharmony_ci req, index, value); 31662306a36Sopenharmony_ci} 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_cistatic void write_vector(struct gspca_dev *gspca_dev, 31962306a36Sopenharmony_ci const struct cmd *data, int ncmds) 32062306a36Sopenharmony_ci{ 32162306a36Sopenharmony_ci while (--ncmds >= 0) { 32262306a36Sopenharmony_ci reg_w_riv(gspca_dev, data->req, data->idx, data->val); 32362306a36Sopenharmony_ci data++; 32462306a36Sopenharmony_ci } 32562306a36Sopenharmony_ci} 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_cistatic void setup_qtable(struct gspca_dev *gspca_dev, 32862306a36Sopenharmony_ci const u8 qtable[2][64]) 32962306a36Sopenharmony_ci{ 33062306a36Sopenharmony_ci int i; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci /* loop over y components */ 33362306a36Sopenharmony_ci for (i = 0; i < 64; i++) 33462306a36Sopenharmony_ci reg_w_riv(gspca_dev, 0x00, 0x2800 + i, qtable[0][i]); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci /* loop over c components */ 33762306a36Sopenharmony_ci for (i = 0; i < 64; i++) 33862306a36Sopenharmony_ci reg_w_riv(gspca_dev, 0x00, 0x2840 + i, qtable[1][i]); 33962306a36Sopenharmony_ci} 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_cistatic void spca504_acknowledged_command(struct gspca_dev *gspca_dev, 34262306a36Sopenharmony_ci u8 req, u16 idx, u16 val) 34362306a36Sopenharmony_ci{ 34462306a36Sopenharmony_ci reg_w_riv(gspca_dev, req, idx, val); 34562306a36Sopenharmony_ci reg_r(gspca_dev, 0x01, 0x0001, 1); 34662306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_FRAM, "before wait 0x%04x\n", 34762306a36Sopenharmony_ci gspca_dev->usb_buf[0]); 34862306a36Sopenharmony_ci reg_w_riv(gspca_dev, req, idx, val); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci msleep(200); 35162306a36Sopenharmony_ci reg_r(gspca_dev, 0x01, 0x0001, 1); 35262306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_FRAM, "after wait 0x%04x\n", 35362306a36Sopenharmony_ci gspca_dev->usb_buf[0]); 35462306a36Sopenharmony_ci} 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_cistatic void spca504_read_info(struct gspca_dev *gspca_dev) 35762306a36Sopenharmony_ci{ 35862306a36Sopenharmony_ci int i; 35962306a36Sopenharmony_ci u8 info[6]; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci if (gspca_debug < D_STREAM) 36262306a36Sopenharmony_ci return; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci for (i = 0; i < 6; i++) { 36562306a36Sopenharmony_ci reg_r(gspca_dev, 0, i, 1); 36662306a36Sopenharmony_ci info[i] = gspca_dev->usb_buf[0]; 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_STREAM, 36962306a36Sopenharmony_ci "Read info: %d %d %d %d %d %d. Should be 1,0,2,2,0,0\n", 37062306a36Sopenharmony_ci info[0], info[1], info[2], 37162306a36Sopenharmony_ci info[3], info[4], info[5]); 37262306a36Sopenharmony_ci} 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_cistatic void spca504A_acknowledged_command(struct gspca_dev *gspca_dev, 37562306a36Sopenharmony_ci u8 req, 37662306a36Sopenharmony_ci u16 idx, u16 val, u8 endcode, u8 count) 37762306a36Sopenharmony_ci{ 37862306a36Sopenharmony_ci u16 status; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci reg_w_riv(gspca_dev, req, idx, val); 38162306a36Sopenharmony_ci reg_r(gspca_dev, 0x01, 0x0001, 1); 38262306a36Sopenharmony_ci if (gspca_dev->usb_err < 0) 38362306a36Sopenharmony_ci return; 38462306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_FRAM, "Status 0x%02x Need 0x%02x\n", 38562306a36Sopenharmony_ci gspca_dev->usb_buf[0], endcode); 38662306a36Sopenharmony_ci if (!count) 38762306a36Sopenharmony_ci return; 38862306a36Sopenharmony_ci count = 200; 38962306a36Sopenharmony_ci while (--count > 0) { 39062306a36Sopenharmony_ci msleep(10); 39162306a36Sopenharmony_ci /* gsmart mini2 write a each wait setting 1 ms is enough */ 39262306a36Sopenharmony_ci/* reg_w_riv(gspca_dev, req, idx, val); */ 39362306a36Sopenharmony_ci reg_r(gspca_dev, 0x01, 0x0001, 1); 39462306a36Sopenharmony_ci status = gspca_dev->usb_buf[0]; 39562306a36Sopenharmony_ci if (status == endcode) { 39662306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_FRAM, "status 0x%04x after wait %d\n", 39762306a36Sopenharmony_ci status, 200 - count); 39862306a36Sopenharmony_ci break; 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci } 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_cistatic void spca504B_PollingDataReady(struct gspca_dev *gspca_dev) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci int count = 10; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci while (--count > 0) { 40862306a36Sopenharmony_ci reg_r(gspca_dev, 0x21, 0, 1); 40962306a36Sopenharmony_ci if ((gspca_dev->usb_buf[0] & 0x01) == 0) 41062306a36Sopenharmony_ci break; 41162306a36Sopenharmony_ci msleep(10); 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_cistatic void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev) 41662306a36Sopenharmony_ci{ 41762306a36Sopenharmony_ci int count = 50; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci while (--count > 0) { 42062306a36Sopenharmony_ci reg_r(gspca_dev, 0x21, 1, 1); 42162306a36Sopenharmony_ci if (gspca_dev->usb_buf[0] != 0) { 42262306a36Sopenharmony_ci reg_w_1(gspca_dev, 0x21, 0, 1, 0); 42362306a36Sopenharmony_ci reg_r(gspca_dev, 0x21, 1, 1); 42462306a36Sopenharmony_ci spca504B_PollingDataReady(gspca_dev); 42562306a36Sopenharmony_ci break; 42662306a36Sopenharmony_ci } 42762306a36Sopenharmony_ci msleep(10); 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci} 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_cistatic void spca50x_GetFirmware(struct gspca_dev *gspca_dev) 43262306a36Sopenharmony_ci{ 43362306a36Sopenharmony_ci u8 *data; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci if (gspca_debug < D_STREAM) 43662306a36Sopenharmony_ci return; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci data = gspca_dev->usb_buf; 43962306a36Sopenharmony_ci reg_r(gspca_dev, 0x20, 0, 5); 44062306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_STREAM, "FirmWare: %d %d %d %d %d\n", 44162306a36Sopenharmony_ci data[0], data[1], data[2], data[3], data[4]); 44262306a36Sopenharmony_ci reg_r(gspca_dev, 0x23, 0, 64); 44362306a36Sopenharmony_ci reg_r(gspca_dev, 0x23, 1, 64); 44462306a36Sopenharmony_ci} 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_cistatic void spca504B_SetSizeType(struct gspca_dev *gspca_dev) 44762306a36Sopenharmony_ci{ 44862306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 44962306a36Sopenharmony_ci u8 Size; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci Size = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; 45262306a36Sopenharmony_ci switch (sd->bridge) { 45362306a36Sopenharmony_ci case BRIDGE_SPCA533: 45462306a36Sopenharmony_ci reg_w_riv(gspca_dev, 0x31, 0, 0); 45562306a36Sopenharmony_ci spca504B_WaitCmdStatus(gspca_dev); 45662306a36Sopenharmony_ci spca504B_PollingDataReady(gspca_dev); 45762306a36Sopenharmony_ci spca50x_GetFirmware(gspca_dev); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci reg_w_1(gspca_dev, 0x24, 0, 8, 2); /* type */ 46062306a36Sopenharmony_ci reg_r(gspca_dev, 0x24, 8, 1); 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci reg_w_1(gspca_dev, 0x25, 0, 4, Size); 46362306a36Sopenharmony_ci reg_r(gspca_dev, 0x25, 4, 1); /* size */ 46462306a36Sopenharmony_ci spca504B_PollingDataReady(gspca_dev); 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci /* Init the cam width height with some values get on init ? */ 46762306a36Sopenharmony_ci reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00); 46862306a36Sopenharmony_ci spca504B_WaitCmdStatus(gspca_dev); 46962306a36Sopenharmony_ci spca504B_PollingDataReady(gspca_dev); 47062306a36Sopenharmony_ci break; 47162306a36Sopenharmony_ci default: 47262306a36Sopenharmony_ci/* case BRIDGE_SPCA504B: */ 47362306a36Sopenharmony_ci/* case BRIDGE_SPCA536: */ 47462306a36Sopenharmony_ci reg_w_1(gspca_dev, 0x25, 0, 4, Size); 47562306a36Sopenharmony_ci reg_r(gspca_dev, 0x25, 4, 1); /* size */ 47662306a36Sopenharmony_ci reg_w_1(gspca_dev, 0x27, 0, 0, 6); 47762306a36Sopenharmony_ci reg_r(gspca_dev, 0x27, 0, 1); /* type */ 47862306a36Sopenharmony_ci spca504B_PollingDataReady(gspca_dev); 47962306a36Sopenharmony_ci break; 48062306a36Sopenharmony_ci case BRIDGE_SPCA504: 48162306a36Sopenharmony_ci Size += 3; 48262306a36Sopenharmony_ci if (sd->subtype == AiptekMiniPenCam13) { 48362306a36Sopenharmony_ci /* spca504a aiptek */ 48462306a36Sopenharmony_ci spca504A_acknowledged_command(gspca_dev, 48562306a36Sopenharmony_ci 0x08, Size, 0, 48662306a36Sopenharmony_ci 0x80 | (Size & 0x0f), 1); 48762306a36Sopenharmony_ci spca504A_acknowledged_command(gspca_dev, 48862306a36Sopenharmony_ci 1, 3, 0, 0x9f, 0); 48962306a36Sopenharmony_ci } else { 49062306a36Sopenharmony_ci spca504_acknowledged_command(gspca_dev, 0x08, Size, 0); 49162306a36Sopenharmony_ci } 49262306a36Sopenharmony_ci break; 49362306a36Sopenharmony_ci case BRIDGE_SPCA504C: 49462306a36Sopenharmony_ci /* capture mode */ 49562306a36Sopenharmony_ci reg_w_riv(gspca_dev, 0xa0, (0x0500 | (Size & 0x0f)), 0x00); 49662306a36Sopenharmony_ci reg_w_riv(gspca_dev, 0x20, 0x01, 0x0500 | (Size & 0x0f)); 49762306a36Sopenharmony_ci break; 49862306a36Sopenharmony_ci } 49962306a36Sopenharmony_ci} 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_cistatic void spca504_wait_status(struct gspca_dev *gspca_dev) 50262306a36Sopenharmony_ci{ 50362306a36Sopenharmony_ci int cnt; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci cnt = 256; 50662306a36Sopenharmony_ci while (--cnt > 0) { 50762306a36Sopenharmony_ci /* With this we get the status, when return 0 it's all ok */ 50862306a36Sopenharmony_ci reg_r(gspca_dev, 0x06, 0x00, 1); 50962306a36Sopenharmony_ci if (gspca_dev->usb_buf[0] == 0) 51062306a36Sopenharmony_ci return; 51162306a36Sopenharmony_ci msleep(10); 51262306a36Sopenharmony_ci } 51362306a36Sopenharmony_ci} 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_cistatic void spca504B_setQtable(struct gspca_dev *gspca_dev) 51662306a36Sopenharmony_ci{ 51762306a36Sopenharmony_ci reg_w_1(gspca_dev, 0x26, 0, 0, 3); 51862306a36Sopenharmony_ci reg_r(gspca_dev, 0x26, 0, 1); 51962306a36Sopenharmony_ci spca504B_PollingDataReady(gspca_dev); 52062306a36Sopenharmony_ci} 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_cistatic void setbrightness(struct gspca_dev *gspca_dev, s32 val) 52362306a36Sopenharmony_ci{ 52462306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 52562306a36Sopenharmony_ci u16 reg; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f0 : 0x21a7; 52862306a36Sopenharmony_ci reg_w_riv(gspca_dev, 0x00, reg, val); 52962306a36Sopenharmony_ci} 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_cistatic void setcontrast(struct gspca_dev *gspca_dev, s32 val) 53262306a36Sopenharmony_ci{ 53362306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 53462306a36Sopenharmony_ci u16 reg; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f1 : 0x21a8; 53762306a36Sopenharmony_ci reg_w_riv(gspca_dev, 0x00, reg, val); 53862306a36Sopenharmony_ci} 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_cistatic void setcolors(struct gspca_dev *gspca_dev, s32 val) 54162306a36Sopenharmony_ci{ 54262306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 54362306a36Sopenharmony_ci u16 reg; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f6 : 0x21ae; 54662306a36Sopenharmony_ci reg_w_riv(gspca_dev, 0x00, reg, val); 54762306a36Sopenharmony_ci} 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_cistatic void init_ctl_reg(struct gspca_dev *gspca_dev) 55062306a36Sopenharmony_ci{ 55162306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 55262306a36Sopenharmony_ci int pollreg = 1; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci switch (sd->bridge) { 55562306a36Sopenharmony_ci case BRIDGE_SPCA504: 55662306a36Sopenharmony_ci case BRIDGE_SPCA504C: 55762306a36Sopenharmony_ci pollreg = 0; 55862306a36Sopenharmony_ci fallthrough; 55962306a36Sopenharmony_ci default: 56062306a36Sopenharmony_ci/* case BRIDGE_SPCA533: */ 56162306a36Sopenharmony_ci/* case BRIDGE_SPCA504B: */ 56262306a36Sopenharmony_ci reg_w_riv(gspca_dev, 0, 0x21ad, 0x00); /* hue */ 56362306a36Sopenharmony_ci reg_w_riv(gspca_dev, 0, 0x21ac, 0x01); /* sat/hue */ 56462306a36Sopenharmony_ci reg_w_riv(gspca_dev, 0, 0x21a3, 0x00); /* gamma */ 56562306a36Sopenharmony_ci break; 56662306a36Sopenharmony_ci case BRIDGE_SPCA536: 56762306a36Sopenharmony_ci reg_w_riv(gspca_dev, 0, 0x20f5, 0x40); 56862306a36Sopenharmony_ci reg_w_riv(gspca_dev, 0, 0x20f4, 0x01); 56962306a36Sopenharmony_ci reg_w_riv(gspca_dev, 0, 0x2089, 0x00); 57062306a36Sopenharmony_ci break; 57162306a36Sopenharmony_ci } 57262306a36Sopenharmony_ci if (pollreg) 57362306a36Sopenharmony_ci spca504B_PollingDataReady(gspca_dev); 57462306a36Sopenharmony_ci} 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci/* this function is called at probe time */ 57762306a36Sopenharmony_cistatic int sd_config(struct gspca_dev *gspca_dev, 57862306a36Sopenharmony_ci const struct usb_device_id *id) 57962306a36Sopenharmony_ci{ 58062306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 58162306a36Sopenharmony_ci struct cam *cam; 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci cam = &gspca_dev->cam; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci sd->bridge = id->driver_info >> 8; 58662306a36Sopenharmony_ci sd->subtype = id->driver_info; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci if (sd->subtype == AiptekMiniPenCam13) { 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci /* try to get the firmware as some cam answer 2.0.1.2.2 59162306a36Sopenharmony_ci * and should be a spca504b then overwrite that setting */ 59262306a36Sopenharmony_ci reg_r(gspca_dev, 0x20, 0, 1); 59362306a36Sopenharmony_ci switch (gspca_dev->usb_buf[0]) { 59462306a36Sopenharmony_ci case 1: 59562306a36Sopenharmony_ci break; /* (right bridge/subtype) */ 59662306a36Sopenharmony_ci case 2: 59762306a36Sopenharmony_ci sd->bridge = BRIDGE_SPCA504B; 59862306a36Sopenharmony_ci sd->subtype = 0; 59962306a36Sopenharmony_ci break; 60062306a36Sopenharmony_ci default: 60162306a36Sopenharmony_ci return -ENODEV; 60262306a36Sopenharmony_ci } 60362306a36Sopenharmony_ci } 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci switch (sd->bridge) { 60662306a36Sopenharmony_ci default: 60762306a36Sopenharmony_ci/* case BRIDGE_SPCA504B: */ 60862306a36Sopenharmony_ci/* case BRIDGE_SPCA504: */ 60962306a36Sopenharmony_ci/* case BRIDGE_SPCA536: */ 61062306a36Sopenharmony_ci cam->cam_mode = vga_mode; 61162306a36Sopenharmony_ci cam->nmodes = ARRAY_SIZE(vga_mode); 61262306a36Sopenharmony_ci break; 61362306a36Sopenharmony_ci case BRIDGE_SPCA533: 61462306a36Sopenharmony_ci cam->cam_mode = custom_mode; 61562306a36Sopenharmony_ci if (sd->subtype == MegaImageVI) /* 320x240 only */ 61662306a36Sopenharmony_ci cam->nmodes = ARRAY_SIZE(custom_mode) - 1; 61762306a36Sopenharmony_ci else 61862306a36Sopenharmony_ci cam->nmodes = ARRAY_SIZE(custom_mode); 61962306a36Sopenharmony_ci break; 62062306a36Sopenharmony_ci case BRIDGE_SPCA504C: 62162306a36Sopenharmony_ci cam->cam_mode = vga_mode2; 62262306a36Sopenharmony_ci cam->nmodes = ARRAY_SIZE(vga_mode2); 62362306a36Sopenharmony_ci break; 62462306a36Sopenharmony_ci } 62562306a36Sopenharmony_ci return 0; 62662306a36Sopenharmony_ci} 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci/* this function is called at probe and resume time */ 62962306a36Sopenharmony_cistatic int sd_init(struct gspca_dev *gspca_dev) 63062306a36Sopenharmony_ci{ 63162306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci switch (sd->bridge) { 63462306a36Sopenharmony_ci case BRIDGE_SPCA504B: 63562306a36Sopenharmony_ci reg_w_riv(gspca_dev, 0x1d, 0x00, 0); 63662306a36Sopenharmony_ci reg_w_riv(gspca_dev, 0x00, 0x2306, 0x01); 63762306a36Sopenharmony_ci reg_w_riv(gspca_dev, 0x00, 0x0d04, 0x00); 63862306a36Sopenharmony_ci reg_w_riv(gspca_dev, 0x00, 0x2000, 0x00); 63962306a36Sopenharmony_ci reg_w_riv(gspca_dev, 0x00, 0x2301, 0x13); 64062306a36Sopenharmony_ci reg_w_riv(gspca_dev, 0x00, 0x2306, 0x00); 64162306a36Sopenharmony_ci fallthrough; 64262306a36Sopenharmony_ci case BRIDGE_SPCA533: 64362306a36Sopenharmony_ci spca504B_PollingDataReady(gspca_dev); 64462306a36Sopenharmony_ci spca50x_GetFirmware(gspca_dev); 64562306a36Sopenharmony_ci break; 64662306a36Sopenharmony_ci case BRIDGE_SPCA536: 64762306a36Sopenharmony_ci spca50x_GetFirmware(gspca_dev); 64862306a36Sopenharmony_ci reg_r(gspca_dev, 0x00, 0x5002, 1); 64962306a36Sopenharmony_ci reg_w_1(gspca_dev, 0x24, 0, 0, 0); 65062306a36Sopenharmony_ci reg_r(gspca_dev, 0x24, 0, 1); 65162306a36Sopenharmony_ci spca504B_PollingDataReady(gspca_dev); 65262306a36Sopenharmony_ci reg_w_riv(gspca_dev, 0x34, 0, 0); 65362306a36Sopenharmony_ci spca504B_WaitCmdStatus(gspca_dev); 65462306a36Sopenharmony_ci break; 65562306a36Sopenharmony_ci case BRIDGE_SPCA504C: /* pccam600 */ 65662306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_STREAM, "Opening SPCA504 (PC-CAM 600)\n"); 65762306a36Sopenharmony_ci reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0000); 65862306a36Sopenharmony_ci reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0001); /* reset */ 65962306a36Sopenharmony_ci spca504_wait_status(gspca_dev); 66062306a36Sopenharmony_ci if (sd->subtype == LogitechClickSmart420) 66162306a36Sopenharmony_ci write_vector(gspca_dev, 66262306a36Sopenharmony_ci spca504A_clicksmart420_open_data, 66362306a36Sopenharmony_ci ARRAY_SIZE(spca504A_clicksmart420_open_data)); 66462306a36Sopenharmony_ci else 66562306a36Sopenharmony_ci write_vector(gspca_dev, spca504_pccam600_open_data, 66662306a36Sopenharmony_ci ARRAY_SIZE(spca504_pccam600_open_data)); 66762306a36Sopenharmony_ci setup_qtable(gspca_dev, qtable_creative_pccam); 66862306a36Sopenharmony_ci break; 66962306a36Sopenharmony_ci default: 67062306a36Sopenharmony_ci/* case BRIDGE_SPCA504: */ 67162306a36Sopenharmony_ci gspca_dbg(gspca_dev, D_STREAM, "Opening SPCA504\n"); 67262306a36Sopenharmony_ci if (sd->subtype == AiptekMiniPenCam13) { 67362306a36Sopenharmony_ci spca504_read_info(gspca_dev); 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */ 67662306a36Sopenharmony_ci spca504A_acknowledged_command(gspca_dev, 0x24, 67762306a36Sopenharmony_ci 8, 3, 0x9e, 1); 67862306a36Sopenharmony_ci /* Twice sequential need status 0xff->0x9e->0x9d */ 67962306a36Sopenharmony_ci spca504A_acknowledged_command(gspca_dev, 0x24, 68062306a36Sopenharmony_ci 8, 3, 0x9e, 0); 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci spca504A_acknowledged_command(gspca_dev, 0x24, 68362306a36Sopenharmony_ci 0, 0, 0x9d, 1); 68462306a36Sopenharmony_ci /******************************/ 68562306a36Sopenharmony_ci /* spca504a aiptek */ 68662306a36Sopenharmony_ci spca504A_acknowledged_command(gspca_dev, 0x08, 68762306a36Sopenharmony_ci 6, 0, 0x86, 1); 68862306a36Sopenharmony_ci/* reg_write (dev, 0, 0x2000, 0); */ 68962306a36Sopenharmony_ci/* reg_write (dev, 0, 0x2883, 1); */ 69062306a36Sopenharmony_ci/* spca504A_acknowledged_command (gspca_dev, 0x08, 69162306a36Sopenharmony_ci 6, 0, 0x86, 1); */ 69262306a36Sopenharmony_ci/* spca504A_acknowledged_command (gspca_dev, 0x24, 69362306a36Sopenharmony_ci 0, 0, 0x9D, 1); */ 69462306a36Sopenharmony_ci reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05); 69562306a36Sopenharmony_ci /* L92 sno1t.txt */ 69662306a36Sopenharmony_ci reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05); 69762306a36Sopenharmony_ci spca504A_acknowledged_command(gspca_dev, 0x01, 69862306a36Sopenharmony_ci 0x0f, 0, 0xff, 0); 69962306a36Sopenharmony_ci } 70062306a36Sopenharmony_ci /* setup qtable */ 70162306a36Sopenharmony_ci reg_w_riv(gspca_dev, 0, 0x2000, 0); 70262306a36Sopenharmony_ci reg_w_riv(gspca_dev, 0, 0x2883, 1); 70362306a36Sopenharmony_ci setup_qtable(gspca_dev, qtable_spca504_default); 70462306a36Sopenharmony_ci break; 70562306a36Sopenharmony_ci } 70662306a36Sopenharmony_ci return gspca_dev->usb_err; 70762306a36Sopenharmony_ci} 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_cistatic int sd_start(struct gspca_dev *gspca_dev) 71062306a36Sopenharmony_ci{ 71162306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 71262306a36Sopenharmony_ci int enable; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci /* create the JPEG header */ 71562306a36Sopenharmony_ci jpeg_define(sd->jpeg_hdr, gspca_dev->pixfmt.height, 71662306a36Sopenharmony_ci gspca_dev->pixfmt.width, 71762306a36Sopenharmony_ci 0x22); /* JPEG 411 */ 71862306a36Sopenharmony_ci jpeg_set_qual(sd->jpeg_hdr, QUALITY); 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci if (sd->bridge == BRIDGE_SPCA504B) 72162306a36Sopenharmony_ci spca504B_setQtable(gspca_dev); 72262306a36Sopenharmony_ci spca504B_SetSizeType(gspca_dev); 72362306a36Sopenharmony_ci switch (sd->bridge) { 72462306a36Sopenharmony_ci default: 72562306a36Sopenharmony_ci/* case BRIDGE_SPCA504B: */ 72662306a36Sopenharmony_ci/* case BRIDGE_SPCA533: */ 72762306a36Sopenharmony_ci/* case BRIDGE_SPCA536: */ 72862306a36Sopenharmony_ci switch (sd->subtype) { 72962306a36Sopenharmony_ci case MegapixV4: 73062306a36Sopenharmony_ci case LogitechClickSmart820: 73162306a36Sopenharmony_ci case MegaImageVI: 73262306a36Sopenharmony_ci reg_w_riv(gspca_dev, 0xf0, 0, 0); 73362306a36Sopenharmony_ci spca504B_WaitCmdStatus(gspca_dev); 73462306a36Sopenharmony_ci reg_w_riv(gspca_dev, 0xf0, 4, 0); 73562306a36Sopenharmony_ci spca504B_WaitCmdStatus(gspca_dev); 73662306a36Sopenharmony_ci break; 73762306a36Sopenharmony_ci default: 73862306a36Sopenharmony_ci reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00); 73962306a36Sopenharmony_ci spca504B_WaitCmdStatus(gspca_dev); 74062306a36Sopenharmony_ci spca504B_PollingDataReady(gspca_dev); 74162306a36Sopenharmony_ci break; 74262306a36Sopenharmony_ci } 74362306a36Sopenharmony_ci break; 74462306a36Sopenharmony_ci case BRIDGE_SPCA504: 74562306a36Sopenharmony_ci if (sd->subtype == AiptekMiniPenCam13) { 74662306a36Sopenharmony_ci spca504_read_info(gspca_dev); 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */ 74962306a36Sopenharmony_ci spca504A_acknowledged_command(gspca_dev, 0x24, 75062306a36Sopenharmony_ci 8, 3, 0x9e, 1); 75162306a36Sopenharmony_ci /* Twice sequential need status 0xff->0x9e->0x9d */ 75262306a36Sopenharmony_ci spca504A_acknowledged_command(gspca_dev, 0x24, 75362306a36Sopenharmony_ci 8, 3, 0x9e, 0); 75462306a36Sopenharmony_ci spca504A_acknowledged_command(gspca_dev, 0x24, 75562306a36Sopenharmony_ci 0, 0, 0x9d, 1); 75662306a36Sopenharmony_ci } else { 75762306a36Sopenharmony_ci spca504_acknowledged_command(gspca_dev, 0x24, 8, 3); 75862306a36Sopenharmony_ci spca504_read_info(gspca_dev); 75962306a36Sopenharmony_ci spca504_acknowledged_command(gspca_dev, 0x24, 8, 3); 76062306a36Sopenharmony_ci spca504_acknowledged_command(gspca_dev, 0x24, 0, 0); 76162306a36Sopenharmony_ci } 76262306a36Sopenharmony_ci spca504B_SetSizeType(gspca_dev); 76362306a36Sopenharmony_ci reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05); 76462306a36Sopenharmony_ci /* L92 sno1t.txt */ 76562306a36Sopenharmony_ci reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05); 76662306a36Sopenharmony_ci break; 76762306a36Sopenharmony_ci case BRIDGE_SPCA504C: 76862306a36Sopenharmony_ci if (sd->subtype == LogitechClickSmart420) { 76962306a36Sopenharmony_ci write_vector(gspca_dev, 77062306a36Sopenharmony_ci spca504A_clicksmart420_init_data, 77162306a36Sopenharmony_ci ARRAY_SIZE(spca504A_clicksmart420_init_data)); 77262306a36Sopenharmony_ci } else { 77362306a36Sopenharmony_ci write_vector(gspca_dev, spca504_pccam600_init_data, 77462306a36Sopenharmony_ci ARRAY_SIZE(spca504_pccam600_init_data)); 77562306a36Sopenharmony_ci } 77662306a36Sopenharmony_ci enable = (sd->autogain ? 0x04 : 0x01); 77762306a36Sopenharmony_ci reg_w_riv(gspca_dev, 0x0c, 0x0000, enable); 77862306a36Sopenharmony_ci /* auto exposure */ 77962306a36Sopenharmony_ci reg_w_riv(gspca_dev, 0xb0, 0x0000, enable); 78062306a36Sopenharmony_ci /* auto whiteness */ 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci /* set default exposure compensation and whiteness balance */ 78362306a36Sopenharmony_ci reg_w_riv(gspca_dev, 0x30, 0x0001, 800); /* ~ 20 fps */ 78462306a36Sopenharmony_ci reg_w_riv(gspca_dev, 0x30, 0x0002, 1600); 78562306a36Sopenharmony_ci spca504B_SetSizeType(gspca_dev); 78662306a36Sopenharmony_ci break; 78762306a36Sopenharmony_ci } 78862306a36Sopenharmony_ci init_ctl_reg(gspca_dev); 78962306a36Sopenharmony_ci return gspca_dev->usb_err; 79062306a36Sopenharmony_ci} 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_cistatic void sd_stopN(struct gspca_dev *gspca_dev) 79362306a36Sopenharmony_ci{ 79462306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci switch (sd->bridge) { 79762306a36Sopenharmony_ci default: 79862306a36Sopenharmony_ci/* case BRIDGE_SPCA533: */ 79962306a36Sopenharmony_ci/* case BRIDGE_SPCA536: */ 80062306a36Sopenharmony_ci/* case BRIDGE_SPCA504B: */ 80162306a36Sopenharmony_ci reg_w_riv(gspca_dev, 0x31, 0, 0); 80262306a36Sopenharmony_ci spca504B_WaitCmdStatus(gspca_dev); 80362306a36Sopenharmony_ci spca504B_PollingDataReady(gspca_dev); 80462306a36Sopenharmony_ci break; 80562306a36Sopenharmony_ci case BRIDGE_SPCA504: 80662306a36Sopenharmony_ci case BRIDGE_SPCA504C: 80762306a36Sopenharmony_ci reg_w_riv(gspca_dev, 0x00, 0x2000, 0x0000); 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci if (sd->subtype == AiptekMiniPenCam13) { 81062306a36Sopenharmony_ci /* spca504a aiptek */ 81162306a36Sopenharmony_ci/* spca504A_acknowledged_command(gspca_dev, 0x08, 81262306a36Sopenharmony_ci 6, 0, 0x86, 1); */ 81362306a36Sopenharmony_ci spca504A_acknowledged_command(gspca_dev, 0x24, 81462306a36Sopenharmony_ci 0x00, 0x00, 0x9d, 1); 81562306a36Sopenharmony_ci spca504A_acknowledged_command(gspca_dev, 0x01, 81662306a36Sopenharmony_ci 0x0f, 0x00, 0xff, 1); 81762306a36Sopenharmony_ci } else { 81862306a36Sopenharmony_ci spca504_acknowledged_command(gspca_dev, 0x24, 0, 0); 81962306a36Sopenharmony_ci reg_w_riv(gspca_dev, 0x01, 0x000f, 0x0000); 82062306a36Sopenharmony_ci } 82162306a36Sopenharmony_ci break; 82262306a36Sopenharmony_ci } 82362306a36Sopenharmony_ci} 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_cistatic void sd_pkt_scan(struct gspca_dev *gspca_dev, 82662306a36Sopenharmony_ci u8 *data, /* isoc packet */ 82762306a36Sopenharmony_ci int len) /* iso packet length */ 82862306a36Sopenharmony_ci{ 82962306a36Sopenharmony_ci struct sd *sd = (struct sd *) gspca_dev; 83062306a36Sopenharmony_ci int i, sof = 0; 83162306a36Sopenharmony_ci static u8 ffd9[] = {0xff, 0xd9}; 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci/* frames are jpeg 4.1.1 without 0xff escape */ 83462306a36Sopenharmony_ci switch (sd->bridge) { 83562306a36Sopenharmony_ci case BRIDGE_SPCA533: 83662306a36Sopenharmony_ci if (data[0] == 0xff) { 83762306a36Sopenharmony_ci if (data[1] != 0x01) { /* drop packet */ 83862306a36Sopenharmony_ci/* gspca_dev->last_packet_type = DISCARD_PACKET; */ 83962306a36Sopenharmony_ci return; 84062306a36Sopenharmony_ci } 84162306a36Sopenharmony_ci sof = 1; 84262306a36Sopenharmony_ci data += SPCA533_OFFSET_DATA; 84362306a36Sopenharmony_ci len -= SPCA533_OFFSET_DATA; 84462306a36Sopenharmony_ci } else { 84562306a36Sopenharmony_ci data += 1; 84662306a36Sopenharmony_ci len -= 1; 84762306a36Sopenharmony_ci } 84862306a36Sopenharmony_ci break; 84962306a36Sopenharmony_ci case BRIDGE_SPCA536: 85062306a36Sopenharmony_ci if (data[0] == 0xff) { 85162306a36Sopenharmony_ci sof = 1; 85262306a36Sopenharmony_ci data += SPCA536_OFFSET_DATA; 85362306a36Sopenharmony_ci len -= SPCA536_OFFSET_DATA; 85462306a36Sopenharmony_ci } else { 85562306a36Sopenharmony_ci data += 2; 85662306a36Sopenharmony_ci len -= 2; 85762306a36Sopenharmony_ci } 85862306a36Sopenharmony_ci break; 85962306a36Sopenharmony_ci default: 86062306a36Sopenharmony_ci/* case BRIDGE_SPCA504: */ 86162306a36Sopenharmony_ci/* case BRIDGE_SPCA504B: */ 86262306a36Sopenharmony_ci switch (data[0]) { 86362306a36Sopenharmony_ci case 0xfe: /* start of frame */ 86462306a36Sopenharmony_ci sof = 1; 86562306a36Sopenharmony_ci data += SPCA50X_OFFSET_DATA; 86662306a36Sopenharmony_ci len -= SPCA50X_OFFSET_DATA; 86762306a36Sopenharmony_ci break; 86862306a36Sopenharmony_ci case 0xff: /* drop packet */ 86962306a36Sopenharmony_ci/* gspca_dev->last_packet_type = DISCARD_PACKET; */ 87062306a36Sopenharmony_ci return; 87162306a36Sopenharmony_ci default: 87262306a36Sopenharmony_ci data += 1; 87362306a36Sopenharmony_ci len -= 1; 87462306a36Sopenharmony_ci break; 87562306a36Sopenharmony_ci } 87662306a36Sopenharmony_ci break; 87762306a36Sopenharmony_ci case BRIDGE_SPCA504C: 87862306a36Sopenharmony_ci switch (data[0]) { 87962306a36Sopenharmony_ci case 0xfe: /* start of frame */ 88062306a36Sopenharmony_ci sof = 1; 88162306a36Sopenharmony_ci data += SPCA504_PCCAM600_OFFSET_DATA; 88262306a36Sopenharmony_ci len -= SPCA504_PCCAM600_OFFSET_DATA; 88362306a36Sopenharmony_ci break; 88462306a36Sopenharmony_ci case 0xff: /* drop packet */ 88562306a36Sopenharmony_ci/* gspca_dev->last_packet_type = DISCARD_PACKET; */ 88662306a36Sopenharmony_ci return; 88762306a36Sopenharmony_ci default: 88862306a36Sopenharmony_ci data += 1; 88962306a36Sopenharmony_ci len -= 1; 89062306a36Sopenharmony_ci break; 89162306a36Sopenharmony_ci } 89262306a36Sopenharmony_ci break; 89362306a36Sopenharmony_ci } 89462306a36Sopenharmony_ci if (sof) { /* start of frame */ 89562306a36Sopenharmony_ci gspca_frame_add(gspca_dev, LAST_PACKET, 89662306a36Sopenharmony_ci ffd9, 2); 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci /* put the JPEG header in the new frame */ 89962306a36Sopenharmony_ci gspca_frame_add(gspca_dev, FIRST_PACKET, 90062306a36Sopenharmony_ci sd->jpeg_hdr, JPEG_HDR_SZ); 90162306a36Sopenharmony_ci } 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci /* add 0x00 after 0xff */ 90462306a36Sopenharmony_ci i = 0; 90562306a36Sopenharmony_ci do { 90662306a36Sopenharmony_ci if (data[i] == 0xff) { 90762306a36Sopenharmony_ci gspca_frame_add(gspca_dev, INTER_PACKET, 90862306a36Sopenharmony_ci data, i + 1); 90962306a36Sopenharmony_ci len -= i; 91062306a36Sopenharmony_ci data += i; 91162306a36Sopenharmony_ci *data = 0x00; 91262306a36Sopenharmony_ci i = 0; 91362306a36Sopenharmony_ci } 91462306a36Sopenharmony_ci i++; 91562306a36Sopenharmony_ci } while (i < len); 91662306a36Sopenharmony_ci gspca_frame_add(gspca_dev, INTER_PACKET, data, len); 91762306a36Sopenharmony_ci} 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_cistatic int sd_s_ctrl(struct v4l2_ctrl *ctrl) 92062306a36Sopenharmony_ci{ 92162306a36Sopenharmony_ci struct gspca_dev *gspca_dev = 92262306a36Sopenharmony_ci container_of(ctrl->handler, struct gspca_dev, ctrl_handler); 92362306a36Sopenharmony_ci struct sd *sd = (struct sd *)gspca_dev; 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci gspca_dev->usb_err = 0; 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci if (!gspca_dev->streaming) 92862306a36Sopenharmony_ci return 0; 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci switch (ctrl->id) { 93162306a36Sopenharmony_ci case V4L2_CID_BRIGHTNESS: 93262306a36Sopenharmony_ci setbrightness(gspca_dev, ctrl->val); 93362306a36Sopenharmony_ci break; 93462306a36Sopenharmony_ci case V4L2_CID_CONTRAST: 93562306a36Sopenharmony_ci setcontrast(gspca_dev, ctrl->val); 93662306a36Sopenharmony_ci break; 93762306a36Sopenharmony_ci case V4L2_CID_SATURATION: 93862306a36Sopenharmony_ci setcolors(gspca_dev, ctrl->val); 93962306a36Sopenharmony_ci break; 94062306a36Sopenharmony_ci case V4L2_CID_AUTOGAIN: 94162306a36Sopenharmony_ci sd->autogain = ctrl->val; 94262306a36Sopenharmony_ci break; 94362306a36Sopenharmony_ci } 94462306a36Sopenharmony_ci return gspca_dev->usb_err; 94562306a36Sopenharmony_ci} 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_cistatic const struct v4l2_ctrl_ops sd_ctrl_ops = { 94862306a36Sopenharmony_ci .s_ctrl = sd_s_ctrl, 94962306a36Sopenharmony_ci}; 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_cistatic int sd_init_controls(struct gspca_dev *gspca_dev) 95262306a36Sopenharmony_ci{ 95362306a36Sopenharmony_ci struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci gspca_dev->vdev.ctrl_handler = hdl; 95662306a36Sopenharmony_ci v4l2_ctrl_handler_init(hdl, 4); 95762306a36Sopenharmony_ci v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, 95862306a36Sopenharmony_ci V4L2_CID_BRIGHTNESS, -128, 127, 1, 0); 95962306a36Sopenharmony_ci v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, 96062306a36Sopenharmony_ci V4L2_CID_CONTRAST, 0, 255, 1, 0x20); 96162306a36Sopenharmony_ci v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, 96262306a36Sopenharmony_ci V4L2_CID_SATURATION, 0, 255, 1, 0x1a); 96362306a36Sopenharmony_ci v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, 96462306a36Sopenharmony_ci V4L2_CID_AUTOGAIN, 0, 1, 1, 1); 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci if (hdl->error) { 96762306a36Sopenharmony_ci pr_err("Could not initialize controls\n"); 96862306a36Sopenharmony_ci return hdl->error; 96962306a36Sopenharmony_ci } 97062306a36Sopenharmony_ci return 0; 97162306a36Sopenharmony_ci} 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci/* sub-driver description */ 97462306a36Sopenharmony_cistatic const struct sd_desc sd_desc = { 97562306a36Sopenharmony_ci .name = MODULE_NAME, 97662306a36Sopenharmony_ci .config = sd_config, 97762306a36Sopenharmony_ci .init = sd_init, 97862306a36Sopenharmony_ci .init_controls = sd_init_controls, 97962306a36Sopenharmony_ci .start = sd_start, 98062306a36Sopenharmony_ci .stopN = sd_stopN, 98162306a36Sopenharmony_ci .pkt_scan = sd_pkt_scan, 98262306a36Sopenharmony_ci}; 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci/* -- module initialisation -- */ 98562306a36Sopenharmony_ci#define BS(bridge, subtype) \ 98662306a36Sopenharmony_ci .driver_info = (BRIDGE_ ## bridge << 8) \ 98762306a36Sopenharmony_ci | (subtype) 98862306a36Sopenharmony_cistatic const struct usb_device_id device_table[] = { 98962306a36Sopenharmony_ci {USB_DEVICE(0x041e, 0x400b), BS(SPCA504C, 0)}, 99062306a36Sopenharmony_ci {USB_DEVICE(0x041e, 0x4012), BS(SPCA504C, 0)}, 99162306a36Sopenharmony_ci {USB_DEVICE(0x041e, 0x4013), BS(SPCA504C, 0)}, 99262306a36Sopenharmony_ci {USB_DEVICE(0x0458, 0x7006), BS(SPCA504B, 0)}, 99362306a36Sopenharmony_ci {USB_DEVICE(0x0461, 0x0821), BS(SPCA533, 0)}, 99462306a36Sopenharmony_ci {USB_DEVICE(0x046d, 0x0905), BS(SPCA533, LogitechClickSmart820)}, 99562306a36Sopenharmony_ci {USB_DEVICE(0x046d, 0x0960), BS(SPCA504C, LogitechClickSmart420)}, 99662306a36Sopenharmony_ci {USB_DEVICE(0x0471, 0x0322), BS(SPCA504B, 0)}, 99762306a36Sopenharmony_ci {USB_DEVICE(0x04a5, 0x3003), BS(SPCA504B, 0)}, 99862306a36Sopenharmony_ci {USB_DEVICE(0x04a5, 0x3008), BS(SPCA533, 0)}, 99962306a36Sopenharmony_ci {USB_DEVICE(0x04a5, 0x300a), BS(SPCA533, 0)}, 100062306a36Sopenharmony_ci {USB_DEVICE(0x04f1, 0x1001), BS(SPCA504B, 0)}, 100162306a36Sopenharmony_ci {USB_DEVICE(0x04fc, 0x500c), BS(SPCA504B, 0)}, 100262306a36Sopenharmony_ci {USB_DEVICE(0x04fc, 0x504a), BS(SPCA504, AiptekMiniPenCam13)}, 100362306a36Sopenharmony_ci {USB_DEVICE(0x04fc, 0x504b), BS(SPCA504B, 0)}, 100462306a36Sopenharmony_ci {USB_DEVICE(0x04fc, 0x5330), BS(SPCA533, 0)}, 100562306a36Sopenharmony_ci {USB_DEVICE(0x04fc, 0x5360), BS(SPCA536, 0)}, 100662306a36Sopenharmony_ci {USB_DEVICE(0x04fc, 0xffff), BS(SPCA504B, 0)}, 100762306a36Sopenharmony_ci {USB_DEVICE(0x052b, 0x1507), BS(SPCA533, MegapixV4)}, 100862306a36Sopenharmony_ci {USB_DEVICE(0x052b, 0x1513), BS(SPCA533, MegapixV4)}, 100962306a36Sopenharmony_ci {USB_DEVICE(0x052b, 0x1803), BS(SPCA533, MegaImageVI)}, 101062306a36Sopenharmony_ci {USB_DEVICE(0x0546, 0x3155), BS(SPCA533, 0)}, 101162306a36Sopenharmony_ci {USB_DEVICE(0x0546, 0x3191), BS(SPCA504B, 0)}, 101262306a36Sopenharmony_ci {USB_DEVICE(0x0546, 0x3273), BS(SPCA504B, 0)}, 101362306a36Sopenharmony_ci {USB_DEVICE(0x055f, 0xc211), BS(SPCA536, 0)}, 101462306a36Sopenharmony_ci {USB_DEVICE(0x055f, 0xc230), BS(SPCA533, 0)}, 101562306a36Sopenharmony_ci {USB_DEVICE(0x055f, 0xc232), BS(SPCA533, 0)}, 101662306a36Sopenharmony_ci {USB_DEVICE(0x055f, 0xc360), BS(SPCA536, 0)}, 101762306a36Sopenharmony_ci {USB_DEVICE(0x055f, 0xc420), BS(SPCA504, 0)}, 101862306a36Sopenharmony_ci {USB_DEVICE(0x055f, 0xc430), BS(SPCA533, 0)}, 101962306a36Sopenharmony_ci {USB_DEVICE(0x055f, 0xc440), BS(SPCA533, 0)}, 102062306a36Sopenharmony_ci {USB_DEVICE(0x055f, 0xc520), BS(SPCA504, 0)}, 102162306a36Sopenharmony_ci {USB_DEVICE(0x055f, 0xc530), BS(SPCA533, 0)}, 102262306a36Sopenharmony_ci {USB_DEVICE(0x055f, 0xc540), BS(SPCA533, 0)}, 102362306a36Sopenharmony_ci {USB_DEVICE(0x055f, 0xc630), BS(SPCA533, 0)}, 102462306a36Sopenharmony_ci {USB_DEVICE(0x055f, 0xc650), BS(SPCA533, 0)}, 102562306a36Sopenharmony_ci {USB_DEVICE(0x05da, 0x1018), BS(SPCA504B, 0)}, 102662306a36Sopenharmony_ci {USB_DEVICE(0x06d6, 0x0031), BS(SPCA533, 0)}, 102762306a36Sopenharmony_ci {USB_DEVICE(0x06d6, 0x0041), BS(SPCA504B, 0)}, 102862306a36Sopenharmony_ci {USB_DEVICE(0x0733, 0x1311), BS(SPCA533, 0)}, 102962306a36Sopenharmony_ci {USB_DEVICE(0x0733, 0x1314), BS(SPCA533, 0)}, 103062306a36Sopenharmony_ci {USB_DEVICE(0x0733, 0x2211), BS(SPCA533, 0)}, 103162306a36Sopenharmony_ci {USB_DEVICE(0x0733, 0x2221), BS(SPCA533, 0)}, 103262306a36Sopenharmony_ci {USB_DEVICE(0x0733, 0x3261), BS(SPCA536, 0)}, 103362306a36Sopenharmony_ci {USB_DEVICE(0x0733, 0x3281), BS(SPCA536, 0)}, 103462306a36Sopenharmony_ci {USB_DEVICE(0x08ca, 0x0104), BS(SPCA533, 0)}, 103562306a36Sopenharmony_ci {USB_DEVICE(0x08ca, 0x0106), BS(SPCA533, 0)}, 103662306a36Sopenharmony_ci {USB_DEVICE(0x08ca, 0x2008), BS(SPCA504B, 0)}, 103762306a36Sopenharmony_ci {USB_DEVICE(0x08ca, 0x2010), BS(SPCA533, 0)}, 103862306a36Sopenharmony_ci {USB_DEVICE(0x08ca, 0x2016), BS(SPCA504B, 0)}, 103962306a36Sopenharmony_ci {USB_DEVICE(0x08ca, 0x2018), BS(SPCA504B, 0)}, 104062306a36Sopenharmony_ci {USB_DEVICE(0x08ca, 0x2020), BS(SPCA533, 0)}, 104162306a36Sopenharmony_ci {USB_DEVICE(0x08ca, 0x2022), BS(SPCA533, 0)}, 104262306a36Sopenharmony_ci {USB_DEVICE(0x08ca, 0x2024), BS(SPCA536, 0)}, 104362306a36Sopenharmony_ci {USB_DEVICE(0x08ca, 0x2028), BS(SPCA533, 0)}, 104462306a36Sopenharmony_ci {USB_DEVICE(0x08ca, 0x2040), BS(SPCA536, 0)}, 104562306a36Sopenharmony_ci {USB_DEVICE(0x08ca, 0x2042), BS(SPCA536, 0)}, 104662306a36Sopenharmony_ci {USB_DEVICE(0x08ca, 0x2050), BS(SPCA536, 0)}, 104762306a36Sopenharmony_ci {USB_DEVICE(0x08ca, 0x2060), BS(SPCA536, 0)}, 104862306a36Sopenharmony_ci {USB_DEVICE(0x0d64, 0x0303), BS(SPCA536, 0)}, 104962306a36Sopenharmony_ci {} 105062306a36Sopenharmony_ci}; 105162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, device_table); 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci/* -- device connect -- */ 105462306a36Sopenharmony_cistatic int sd_probe(struct usb_interface *intf, 105562306a36Sopenharmony_ci const struct usb_device_id *id) 105662306a36Sopenharmony_ci{ 105762306a36Sopenharmony_ci return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), 105862306a36Sopenharmony_ci THIS_MODULE); 105962306a36Sopenharmony_ci} 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_cistatic struct usb_driver sd_driver = { 106262306a36Sopenharmony_ci .name = MODULE_NAME, 106362306a36Sopenharmony_ci .id_table = device_table, 106462306a36Sopenharmony_ci .probe = sd_probe, 106562306a36Sopenharmony_ci .disconnect = gspca_disconnect, 106662306a36Sopenharmony_ci#ifdef CONFIG_PM 106762306a36Sopenharmony_ci .suspend = gspca_suspend, 106862306a36Sopenharmony_ci .resume = gspca_resume, 106962306a36Sopenharmony_ci .reset_resume = gspca_resume, 107062306a36Sopenharmony_ci#endif 107162306a36Sopenharmony_ci}; 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_cimodule_usb_driver(sd_driver); 1074