Path: blob/master/drivers/media/video/gspca/spca500.c
17602 views
/*1* SPCA500 chip based cameras initialization data2*3* V4L2 by Jean-Francois Moine <http://moinejf.free.fr>4*5* This program is free software; you can redistribute it and/or modify6* it under the terms of the GNU General Public License as published by7* the Free Software Foundation; either version 2 of the License, or8* any later version.9*10* This program is distributed in the hope that it will be useful,11* but WITHOUT ANY WARRANTY; without even the implied warranty of12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13* GNU General Public License for more details.14*15* You should have received a copy of the GNU General Public License16* along with this program; if not, write to the Free Software17* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA18*19*/2021#define MODULE_NAME "spca500"2223#include "gspca.h"24#include "jpeg.h"2526MODULE_AUTHOR("Michel Xhaard <[email protected]>");27MODULE_DESCRIPTION("GSPCA/SPCA500 USB Camera Driver");28MODULE_LICENSE("GPL");2930/* specific webcam descriptor */31struct sd {32struct gspca_dev gspca_dev; /* !! must be the first item */3334unsigned char brightness;35unsigned char contrast;36unsigned char colors;37u8 quality;38#define QUALITY_MIN 7039#define QUALITY_MAX 9540#define QUALITY_DEF 854142char subtype;43#define AgfaCl20 044#define AiptekPocketDV 145#define BenqDC1016 246#define CreativePCCam300 347#define DLinkDSC350 448#define Gsmartmini 549#define IntelPocketPCCamera 650#define KodakEZ200 751#define LogitechClickSmart310 852#define LogitechClickSmart510 953#define LogitechTraveler 1054#define MustekGsmart300 1155#define Optimedia 1256#define PalmPixDC85 1357#define ToptroIndus 145859u8 jpeg_hdr[JPEG_HDR_SZ];60};6162/* V4L2 controls supported by the driver */63static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);64static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);65static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);66static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);67static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);68static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);6970static const struct ctrl sd_ctrls[] = {71{72{73.id = V4L2_CID_BRIGHTNESS,74.type = V4L2_CTRL_TYPE_INTEGER,75.name = "Brightness",76.minimum = 0,77.maximum = 255,78.step = 1,79#define BRIGHTNESS_DEF 12780.default_value = BRIGHTNESS_DEF,81},82.set = sd_setbrightness,83.get = sd_getbrightness,84},85{86{87.id = V4L2_CID_CONTRAST,88.type = V4L2_CTRL_TYPE_INTEGER,89.name = "Contrast",90.minimum = 0,91.maximum = 63,92.step = 1,93#define CONTRAST_DEF 3194.default_value = CONTRAST_DEF,95},96.set = sd_setcontrast,97.get = sd_getcontrast,98},99{100{101.id = V4L2_CID_SATURATION,102.type = V4L2_CTRL_TYPE_INTEGER,103.name = "Color",104.minimum = 0,105.maximum = 63,106.step = 1,107#define COLOR_DEF 31108.default_value = COLOR_DEF,109},110.set = sd_setcolors,111.get = sd_getcolors,112},113};114115static const struct v4l2_pix_format vga_mode[] = {116{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,117.bytesperline = 320,118.sizeimage = 320 * 240 * 3 / 8 + 590,119.colorspace = V4L2_COLORSPACE_JPEG,120.priv = 1},121{640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,122.bytesperline = 640,123.sizeimage = 640 * 480 * 3 / 8 + 590,124.colorspace = V4L2_COLORSPACE_JPEG,125.priv = 0},126};127128static const struct v4l2_pix_format sif_mode[] = {129{176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,130.bytesperline = 176,131.sizeimage = 176 * 144 * 3 / 8 + 590,132.colorspace = V4L2_COLORSPACE_JPEG,133.priv = 1},134{352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,135.bytesperline = 352,136.sizeimage = 352 * 288 * 3 / 8 + 590,137.colorspace = V4L2_COLORSPACE_JPEG,138.priv = 0},139};140141/* Frame packet header offsets for the spca500 */142#define SPCA500_OFFSET_PADDINGLB 2143#define SPCA500_OFFSET_PADDINGHB 3144#define SPCA500_OFFSET_MODE 4145#define SPCA500_OFFSET_IMGWIDTH 5146#define SPCA500_OFFSET_IMGHEIGHT 6147#define SPCA500_OFFSET_IMGMODE 7148#define SPCA500_OFFSET_QTBLINDEX 8149#define SPCA500_OFFSET_FRAMSEQ 9150#define SPCA500_OFFSET_CDSPINFO 10151#define SPCA500_OFFSET_GPIO 11152#define SPCA500_OFFSET_AUGPIO 12153#define SPCA500_OFFSET_DATA 16154155156static const __u16 spca500_visual_defaults[][3] = {157{0x00, 0x0003, 0x816b}, /* SSI not active sync with vsync,158* hue (H byte) = 0,159* saturation/hue enable,160* brightness/contrast enable.161*/162{0x00, 0x0000, 0x8167}, /* brightness = 0 */163{0x00, 0x0020, 0x8168}, /* contrast = 0 */164{0x00, 0x0003, 0x816b}, /* SSI not active sync with vsync,165* hue (H byte) = 0, saturation/hue enable,166* brightness/contrast enable.167* was 0x0003, now 0x0000.168*/169{0x00, 0x0000, 0x816a}, /* hue (L byte) = 0 */170{0x00, 0x0020, 0x8169}, /* saturation = 0x20 */171{0x00, 0x0050, 0x8157}, /* edge gain high threshold */172{0x00, 0x0030, 0x8158}, /* edge gain low threshold */173{0x00, 0x0028, 0x8159}, /* edge bandwidth high threshold */174{0x00, 0x000a, 0x815a}, /* edge bandwidth low threshold */175{0x00, 0x0001, 0x8202}, /* clock rate compensation = 1/25 sec/frame */176{0x0c, 0x0004, 0x0000},177/* set interface */178{}179};180static const __u16 Clicksmart510_defaults[][3] = {181{0x00, 0x00, 0x8211},182{0x00, 0x01, 0x82c0},183{0x00, 0x10, 0x82cb},184{0x00, 0x0f, 0x800d},185{0x00, 0x82, 0x8225},186{0x00, 0x21, 0x8228},187{0x00, 0x00, 0x8203},188{0x00, 0x00, 0x8204},189{0x00, 0x08, 0x8205},190{0x00, 0xf8, 0x8206},191{0x00, 0x28, 0x8207},192{0x00, 0xa0, 0x8208},193{0x00, 0x08, 0x824a},194{0x00, 0x08, 0x8214},195{0x00, 0x80, 0x82c1},196{0x00, 0x00, 0x82c2},197{0x00, 0x00, 0x82ca},198{0x00, 0x80, 0x82c1},199{0x00, 0x04, 0x82c2},200{0x00, 0x00, 0x82ca},201{0x00, 0xfc, 0x8100},202{0x00, 0xfc, 0x8105},203{0x00, 0x30, 0x8101},204{0x00, 0x00, 0x8102},205{0x00, 0x00, 0x8103},206{0x00, 0x66, 0x8107},207{0x00, 0x00, 0x816b},208{0x00, 0x00, 0x8155},209{0x00, 0x01, 0x8156},210{0x00, 0x60, 0x8157},211{0x00, 0x40, 0x8158},212{0x00, 0x0a, 0x8159},213{0x00, 0x06, 0x815a},214{0x00, 0x00, 0x813f},215{0x00, 0x00, 0x8200},216{0x00, 0x19, 0x8201},217{0x00, 0x00, 0x82c1},218{0x00, 0xa0, 0x82c2},219{0x00, 0x00, 0x82ca},220{0x00, 0x00, 0x8117},221{0x00, 0x00, 0x8118},222{0x00, 0x65, 0x8119},223{0x00, 0x00, 0x811a},224{0x00, 0x00, 0x811b},225{0x00, 0x55, 0x811c},226{0x00, 0x65, 0x811d},227{0x00, 0x55, 0x811e},228{0x00, 0x16, 0x811f},229{0x00, 0x19, 0x8120},230{0x00, 0x80, 0x8103},231{0x00, 0x83, 0x816b},232{0x00, 0x25, 0x8168},233{0x00, 0x01, 0x820f},234{0x00, 0xff, 0x8115},235{0x00, 0x48, 0x8116},236{0x00, 0x50, 0x8151},237{0x00, 0x40, 0x8152},238{0x00, 0x78, 0x8153},239{0x00, 0x40, 0x8154},240{0x00, 0x00, 0x8167},241{0x00, 0x20, 0x8168},242{0x00, 0x00, 0x816a},243{0x00, 0x03, 0x816b},244{0x00, 0x20, 0x8169},245{0x00, 0x60, 0x8157},246{0x00, 0x00, 0x8190},247{0x00, 0x00, 0x81a1},248{0x00, 0x00, 0x81b2},249{0x00, 0x27, 0x8191},250{0x00, 0x27, 0x81a2},251{0x00, 0x27, 0x81b3},252{0x00, 0x4b, 0x8192},253{0x00, 0x4b, 0x81a3},254{0x00, 0x4b, 0x81b4},255{0x00, 0x66, 0x8193},256{0x00, 0x66, 0x81a4},257{0x00, 0x66, 0x81b5},258{0x00, 0x79, 0x8194},259{0x00, 0x79, 0x81a5},260{0x00, 0x79, 0x81b6},261{0x00, 0x8a, 0x8195},262{0x00, 0x8a, 0x81a6},263{0x00, 0x8a, 0x81b7},264{0x00, 0x9b, 0x8196},265{0x00, 0x9b, 0x81a7},266{0x00, 0x9b, 0x81b8},267{0x00, 0xa6, 0x8197},268{0x00, 0xa6, 0x81a8},269{0x00, 0xa6, 0x81b9},270{0x00, 0xb2, 0x8198},271{0x00, 0xb2, 0x81a9},272{0x00, 0xb2, 0x81ba},273{0x00, 0xbe, 0x8199},274{0x00, 0xbe, 0x81aa},275{0x00, 0xbe, 0x81bb},276{0x00, 0xc8, 0x819a},277{0x00, 0xc8, 0x81ab},278{0x00, 0xc8, 0x81bc},279{0x00, 0xd2, 0x819b},280{0x00, 0xd2, 0x81ac},281{0x00, 0xd2, 0x81bd},282{0x00, 0xdb, 0x819c},283{0x00, 0xdb, 0x81ad},284{0x00, 0xdb, 0x81be},285{0x00, 0xe4, 0x819d},286{0x00, 0xe4, 0x81ae},287{0x00, 0xe4, 0x81bf},288{0x00, 0xed, 0x819e},289{0x00, 0xed, 0x81af},290{0x00, 0xed, 0x81c0},291{0x00, 0xf7, 0x819f},292{0x00, 0xf7, 0x81b0},293{0x00, 0xf7, 0x81c1},294{0x00, 0xff, 0x81a0},295{0x00, 0xff, 0x81b1},296{0x00, 0xff, 0x81c2},297{0x00, 0x03, 0x8156},298{0x00, 0x00, 0x8211},299{0x00, 0x20, 0x8168},300{0x00, 0x01, 0x8202},301{0x00, 0x30, 0x8101},302{0x00, 0x00, 0x8111},303{0x00, 0x00, 0x8112},304{0x00, 0x00, 0x8113},305{0x00, 0x00, 0x8114},306{}307};308309static const __u8 qtable_creative_pccam[2][64] = {310{ /* Q-table Y-components */3110x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,3120x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,3130x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,3140x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,3150x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,3160x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,3170x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,3180x16, 0x1c, 0x1d, 0x1d, 0x22, 0x1e, 0x1f, 0x1e},319{ /* Q-table C-components */3200x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,3210x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,3220x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,3230x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,3240x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,3250x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,3260x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,3270x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}328};329330static const __u8 qtable_kodak_ez200[2][64] = {331{ /* Q-table Y-components */3320x02, 0x01, 0x01, 0x02, 0x02, 0x04, 0x05, 0x06,3330x01, 0x01, 0x01, 0x02, 0x03, 0x06, 0x06, 0x06,3340x01, 0x01, 0x02, 0x02, 0x04, 0x06, 0x07, 0x06,3350x01, 0x02, 0x02, 0x03, 0x05, 0x09, 0x08, 0x06,3360x02, 0x02, 0x04, 0x06, 0x07, 0x0b, 0x0a, 0x08,3370x02, 0x04, 0x06, 0x06, 0x08, 0x0a, 0x0b, 0x09,3380x05, 0x06, 0x08, 0x09, 0x0a, 0x0c, 0x0c, 0x0a,3390x07, 0x09, 0x0a, 0x0a, 0x0b, 0x0a, 0x0a, 0x0a},340{ /* Q-table C-components */3410x02, 0x02, 0x02, 0x05, 0x0a, 0x0a, 0x0a, 0x0a,3420x02, 0x02, 0x03, 0x07, 0x0a, 0x0a, 0x0a, 0x0a,3430x02, 0x03, 0x06, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,3440x05, 0x07, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,3450x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,3460x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,3470x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,3480x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a}349};350351static const __u8 qtable_pocketdv[2][64] = {352{ /* Q-table Y-components start registers 0x8800 */3530x06, 0x04, 0x04, 0x06, 0x0a, 0x10, 0x14, 0x18,3540x05, 0x05, 0x06, 0x08, 0x0a, 0x17, 0x18, 0x16,3550x06, 0x05, 0x06, 0x0a, 0x10, 0x17, 0x1c, 0x16,3560x06, 0x07, 0x09, 0x0c, 0x14, 0x23, 0x20, 0x19,3570x07, 0x09, 0x0f, 0x16, 0x1b, 0x2c, 0x29, 0x1f,3580x0a, 0x0e, 0x16, 0x1a, 0x20, 0x2a, 0x2d, 0x25,3590x14, 0x1a, 0x1f, 0x23, 0x29, 0x30, 0x30, 0x28,3600x1d, 0x25, 0x26, 0x27, 0x2d, 0x28, 0x29, 0x28,361},362{ /* Q-table C-components start registers 0x8840 */3630x07, 0x07, 0x0a, 0x13, 0x28, 0x28, 0x28, 0x28,3640x07, 0x08, 0x0a, 0x1a, 0x28, 0x28, 0x28, 0x28,3650x0a, 0x0a, 0x16, 0x28, 0x28, 0x28, 0x28, 0x28,3660x13, 0x1a, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,3670x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,3680x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,3690x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,3700x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28}371};372373/* read 'len' bytes to gspca_dev->usb_buf */374static void reg_r(struct gspca_dev *gspca_dev,375__u16 index,376__u16 length)377{378usb_control_msg(gspca_dev->dev,379usb_rcvctrlpipe(gspca_dev->dev, 0),3800,381USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,3820, /* value */383index, gspca_dev->usb_buf, length, 500);384}385386static int reg_w(struct gspca_dev *gspca_dev,387__u16 req, __u16 index, __u16 value)388{389int ret;390391PDEBUG(D_USBO, "reg write: [0x%02x] = 0x%02x", index, value);392ret = usb_control_msg(gspca_dev->dev,393usb_sndctrlpipe(gspca_dev->dev, 0),394req,395USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,396value, index, NULL, 0, 500);397if (ret < 0)398err("reg write: error %d", ret);399return ret;400}401402/* returns: negative is error, pos or zero is data */403static int reg_r_12(struct gspca_dev *gspca_dev,404__u16 req, /* bRequest */405__u16 index, /* wIndex */406__u16 length) /* wLength (1 or 2 only) */407{408int ret;409410gspca_dev->usb_buf[1] = 0;411ret = usb_control_msg(gspca_dev->dev,412usb_rcvctrlpipe(gspca_dev->dev, 0),413req,414USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,4150, /* value */416index,417gspca_dev->usb_buf, length,418500); /* timeout */419if (ret < 0) {420err("reg_r_12 err %d", ret);421return ret;422}423return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0];424}425426/*427* Simple function to wait for a given 8-bit value to be returned from428* a reg_read call.429* Returns: negative is error or timeout, zero is success.430*/431static int reg_r_wait(struct gspca_dev *gspca_dev,432__u16 reg, __u16 index, __u16 value)433{434int ret, cnt = 20;435436while (--cnt > 0) {437ret = reg_r_12(gspca_dev, reg, index, 1);438if (ret == value)439return 0;440msleep(50);441}442return -EIO;443}444445static int write_vector(struct gspca_dev *gspca_dev,446const __u16 data[][3])447{448int ret, i = 0;449450while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) {451ret = reg_w(gspca_dev, data[i][0], data[i][2], data[i][1]);452if (ret < 0)453return ret;454i++;455}456return 0;457}458459static int spca50x_setup_qtable(struct gspca_dev *gspca_dev,460unsigned int request,461unsigned int ybase,462unsigned int cbase,463const __u8 qtable[2][64])464{465int i, err;466467/* loop over y components */468for (i = 0; i < 64; i++) {469err = reg_w(gspca_dev, request, ybase + i, qtable[0][i]);470if (err < 0)471return err;472}473474/* loop over c components */475for (i = 0; i < 64; i++) {476err = reg_w(gspca_dev, request, cbase + i, qtable[1][i]);477if (err < 0)478return err;479}480return 0;481}482483static void spca500_ping310(struct gspca_dev *gspca_dev)484{485reg_r(gspca_dev, 0x0d04, 2);486PDEBUG(D_STREAM, "ClickSmart310 ping 0x0d04 0x%02x 0x%02x",487gspca_dev->usb_buf[0], gspca_dev->usb_buf[1]);488}489490static void spca500_clksmart310_init(struct gspca_dev *gspca_dev)491{492reg_r(gspca_dev, 0x0d05, 2);493PDEBUG(D_STREAM, "ClickSmart310 init 0x0d05 0x%02x 0x%02x",494gspca_dev->usb_buf[0], gspca_dev->usb_buf[1]);495reg_w(gspca_dev, 0x00, 0x8167, 0x5a);496spca500_ping310(gspca_dev);497498reg_w(gspca_dev, 0x00, 0x8168, 0x22);499reg_w(gspca_dev, 0x00, 0x816a, 0xc0);500reg_w(gspca_dev, 0x00, 0x816b, 0x0b);501reg_w(gspca_dev, 0x00, 0x8169, 0x25);502reg_w(gspca_dev, 0x00, 0x8157, 0x5b);503reg_w(gspca_dev, 0x00, 0x8158, 0x5b);504reg_w(gspca_dev, 0x00, 0x813f, 0x03);505reg_w(gspca_dev, 0x00, 0x8151, 0x4a);506reg_w(gspca_dev, 0x00, 0x8153, 0x78);507reg_w(gspca_dev, 0x00, 0x0d01, 0x04);508/* 00 for adjust shutter */509reg_w(gspca_dev, 0x00, 0x0d02, 0x01);510reg_w(gspca_dev, 0x00, 0x8169, 0x25);511reg_w(gspca_dev, 0x00, 0x0d01, 0x02);512}513514static void spca500_setmode(struct gspca_dev *gspca_dev,515__u8 xmult, __u8 ymult)516{517int mode;518519/* set x multiplier */520reg_w(gspca_dev, 0, 0x8001, xmult);521522/* set y multiplier */523reg_w(gspca_dev, 0, 0x8002, ymult);524525/* use compressed mode, VGA, with mode specific subsample */526mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;527reg_w(gspca_dev, 0, 0x8003, mode << 4);528}529530static int spca500_full_reset(struct gspca_dev *gspca_dev)531{532int err;533534/* send the reset command */535err = reg_w(gspca_dev, 0xe0, 0x0001, 0x0000);536if (err < 0)537return err;538539/* wait for the reset to complete */540err = reg_r_wait(gspca_dev, 0x06, 0x0000, 0x0000);541if (err < 0)542return err;543err = reg_w(gspca_dev, 0xe0, 0x0000, 0x0000);544if (err < 0)545return err;546err = reg_r_wait(gspca_dev, 0x06, 0, 0);547if (err < 0) {548PDEBUG(D_ERR, "reg_r_wait() failed");549return err;550}551/* all ok */552return 0;553}554555/* Synchro the Bridge with sensor */556/* Maybe that will work on all spca500 chip */557/* because i only own a clicksmart310 try for that chip */558/* using spca50x_set_packet_size() cause an Ooops here */559/* usb_set_interface from kernel 2.6.x clear all the urb stuff */560/* up-port the same feature as in 2.4.x kernel */561static int spca500_synch310(struct gspca_dev *gspca_dev)562{563if (usb_set_interface(gspca_dev->dev, gspca_dev->iface, 0) < 0) {564PDEBUG(D_ERR, "Set packet size: set interface error");565goto error;566}567spca500_ping310(gspca_dev);568569reg_r(gspca_dev, 0x0d00, 1);570571/* need alt setting here */572PDEBUG(D_PACK, "ClickSmart310 sync alt: %d", gspca_dev->alt);573574/* Windoze use pipe with altsetting 6 why 7 here */575if (usb_set_interface(gspca_dev->dev,576gspca_dev->iface,577gspca_dev->alt) < 0) {578PDEBUG(D_ERR, "Set packet size: set interface error");579goto error;580}581return 0;582error:583return -EBUSY;584}585586static void spca500_reinit(struct gspca_dev *gspca_dev)587{588int err;589__u8 Data;590591/* some unknown command from Aiptek pocket dv and family300 */592593reg_w(gspca_dev, 0x00, 0x0d01, 0x01);594reg_w(gspca_dev, 0x00, 0x0d03, 0x00);595reg_w(gspca_dev, 0x00, 0x0d02, 0x01);596597/* enable drop packet */598reg_w(gspca_dev, 0x00, 0x850a, 0x0001);599600err = spca50x_setup_qtable(gspca_dev, 0x00, 0x8800, 0x8840,601qtable_pocketdv);602if (err < 0)603PDEBUG(D_ERR|D_STREAM, "spca50x_setup_qtable failed on init");604605/* set qtable index */606reg_w(gspca_dev, 0x00, 0x8880, 2);607/* family cam Quicksmart stuff */608reg_w(gspca_dev, 0x00, 0x800a, 0x00);609/* Set agc transfer: synced between frames */610reg_w(gspca_dev, 0x00, 0x820f, 0x01);611/* Init SDRAM - needed for SDRAM access */612reg_w(gspca_dev, 0x00, 0x870a, 0x04);613/*Start init sequence or stream */614reg_w(gspca_dev, 0, 0x8003, 0x00);615/* switch to video camera mode */616reg_w(gspca_dev, 0x00, 0x8000, 0x0004);617msleep(2000);618if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0) {619reg_r(gspca_dev, 0x816b, 1);620Data = gspca_dev->usb_buf[0];621reg_w(gspca_dev, 0x00, 0x816b, Data);622}623}624625/* this function is called at probe time */626static int sd_config(struct gspca_dev *gspca_dev,627const struct usb_device_id *id)628{629struct sd *sd = (struct sd *) gspca_dev;630struct cam *cam;631632cam = &gspca_dev->cam;633sd->subtype = id->driver_info;634if (sd->subtype != LogitechClickSmart310) {635cam->cam_mode = vga_mode;636cam->nmodes = ARRAY_SIZE(vga_mode);637} else {638cam->cam_mode = sif_mode;639cam->nmodes = ARRAY_SIZE(sif_mode);640}641sd->brightness = BRIGHTNESS_DEF;642sd->contrast = CONTRAST_DEF;643sd->colors = COLOR_DEF;644sd->quality = QUALITY_DEF;645return 0;646}647648/* this function is called at probe and resume time */649static int sd_init(struct gspca_dev *gspca_dev)650{651struct sd *sd = (struct sd *) gspca_dev;652653/* initialisation of spca500 based cameras is deferred */654PDEBUG(D_STREAM, "SPCA500 init");655if (sd->subtype == LogitechClickSmart310)656spca500_clksmart310_init(gspca_dev);657/* else658spca500_initialise(gspca_dev); */659PDEBUG(D_STREAM, "SPCA500 init done");660return 0;661}662663static int sd_start(struct gspca_dev *gspca_dev)664{665struct sd *sd = (struct sd *) gspca_dev;666int err;667__u8 Data;668__u8 xmult, ymult;669670/* create the JPEG header */671jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,6720x22); /* JPEG 411 */673jpeg_set_qual(sd->jpeg_hdr, sd->quality);674675if (sd->subtype == LogitechClickSmart310) {676xmult = 0x16;677ymult = 0x12;678} else {679xmult = 0x28;680ymult = 0x1e;681}682683/* is there a sensor here ? */684reg_r(gspca_dev, 0x8a04, 1);685PDEBUG(D_STREAM, "Spca500 Sensor Address 0x%02x",686gspca_dev->usb_buf[0]);687PDEBUG(D_STREAM, "Spca500 curr_mode: %d Xmult: 0x%02x, Ymult: 0x%02x",688gspca_dev->curr_mode, xmult, ymult);689690/* setup qtable */691switch (sd->subtype) {692case LogitechClickSmart310:693spca500_setmode(gspca_dev, xmult, ymult);694695/* enable drop packet */696reg_w(gspca_dev, 0x00, 0x850a, 0x0001);697reg_w(gspca_dev, 0x00, 0x8880, 3);698err = spca50x_setup_qtable(gspca_dev,6990x00, 0x8800, 0x8840,700qtable_creative_pccam);701if (err < 0)702PDEBUG(D_ERR, "spca50x_setup_qtable failed");703/* Init SDRAM - needed for SDRAM access */704reg_w(gspca_dev, 0x00, 0x870a, 0x04);705706/* switch to video camera mode */707reg_w(gspca_dev, 0x00, 0x8000, 0x0004);708msleep(500);709if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0)710PDEBUG(D_ERR, "reg_r_wait() failed");711712reg_r(gspca_dev, 0x816b, 1);713Data = gspca_dev->usb_buf[0];714reg_w(gspca_dev, 0x00, 0x816b, Data);715716spca500_synch310(gspca_dev);717718write_vector(gspca_dev, spca500_visual_defaults);719spca500_setmode(gspca_dev, xmult, ymult);720/* enable drop packet */721err = reg_w(gspca_dev, 0x00, 0x850a, 0x0001);722if (err < 0)723PDEBUG(D_ERR, "failed to enable drop packet");724reg_w(gspca_dev, 0x00, 0x8880, 3);725err = spca50x_setup_qtable(gspca_dev,7260x00, 0x8800, 0x8840,727qtable_creative_pccam);728if (err < 0)729PDEBUG(D_ERR, "spca50x_setup_qtable failed");730731/* Init SDRAM - needed for SDRAM access */732reg_w(gspca_dev, 0x00, 0x870a, 0x04);733734/* switch to video camera mode */735reg_w(gspca_dev, 0x00, 0x8000, 0x0004);736737if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0)738PDEBUG(D_ERR, "reg_r_wait() failed");739740reg_r(gspca_dev, 0x816b, 1);741Data = gspca_dev->usb_buf[0];742reg_w(gspca_dev, 0x00, 0x816b, Data);743break;744case CreativePCCam300: /* Creative PC-CAM 300 640x480 CCD */745case IntelPocketPCCamera: /* FIXME: Temporary fix for746* Intel Pocket PC Camera747* - NWG (Sat 29th March 2003) */748749/* do a full reset */750err = spca500_full_reset(gspca_dev);751if (err < 0)752PDEBUG(D_ERR, "spca500_full_reset failed");753754/* enable drop packet */755err = reg_w(gspca_dev, 0x00, 0x850a, 0x0001);756if (err < 0)757PDEBUG(D_ERR, "failed to enable drop packet");758reg_w(gspca_dev, 0x00, 0x8880, 3);759err = spca50x_setup_qtable(gspca_dev,7600x00, 0x8800, 0x8840,761qtable_creative_pccam);762if (err < 0)763PDEBUG(D_ERR, "spca50x_setup_qtable failed");764765spca500_setmode(gspca_dev, xmult, ymult);766reg_w(gspca_dev, 0x20, 0x0001, 0x0004);767768/* switch to video camera mode */769reg_w(gspca_dev, 0x00, 0x8000, 0x0004);770771if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0)772PDEBUG(D_ERR, "reg_r_wait() failed");773774reg_r(gspca_dev, 0x816b, 1);775Data = gspca_dev->usb_buf[0];776reg_w(gspca_dev, 0x00, 0x816b, Data);777778/* write_vector(gspca_dev, spca500_visual_defaults); */779break;780case KodakEZ200: /* Kodak EZ200 */781782/* do a full reset */783err = spca500_full_reset(gspca_dev);784if (err < 0)785PDEBUG(D_ERR, "spca500_full_reset failed");786/* enable drop packet */787reg_w(gspca_dev, 0x00, 0x850a, 0x0001);788reg_w(gspca_dev, 0x00, 0x8880, 0);789err = spca50x_setup_qtable(gspca_dev,7900x00, 0x8800, 0x8840,791qtable_kodak_ez200);792if (err < 0)793PDEBUG(D_ERR, "spca50x_setup_qtable failed");794spca500_setmode(gspca_dev, xmult, ymult);795796reg_w(gspca_dev, 0x20, 0x0001, 0x0004);797798/* switch to video camera mode */799reg_w(gspca_dev, 0x00, 0x8000, 0x0004);800801if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0)802PDEBUG(D_ERR, "reg_r_wait() failed");803804reg_r(gspca_dev, 0x816b, 1);805Data = gspca_dev->usb_buf[0];806reg_w(gspca_dev, 0x00, 0x816b, Data);807808/* write_vector(gspca_dev, spca500_visual_defaults); */809break;810811case BenqDC1016:812case DLinkDSC350: /* FamilyCam 300 */813case AiptekPocketDV: /* Aiptek PocketDV */814case Gsmartmini: /*Mustek Gsmart Mini */815case MustekGsmart300: /* Mustek Gsmart 300 */816case PalmPixDC85:817case Optimedia:818case ToptroIndus:819case AgfaCl20:820spca500_reinit(gspca_dev);821reg_w(gspca_dev, 0x00, 0x0d01, 0x01);822/* enable drop packet */823reg_w(gspca_dev, 0x00, 0x850a, 0x0001);824825err = spca50x_setup_qtable(gspca_dev,8260x00, 0x8800, 0x8840, qtable_pocketdv);827if (err < 0)828PDEBUG(D_ERR, "spca50x_setup_qtable failed");829reg_w(gspca_dev, 0x00, 0x8880, 2);830831/* familycam Quicksmart pocketDV stuff */832reg_w(gspca_dev, 0x00, 0x800a, 0x00);833/* Set agc transfer: synced between frames */834reg_w(gspca_dev, 0x00, 0x820f, 0x01);835/* Init SDRAM - needed for SDRAM access */836reg_w(gspca_dev, 0x00, 0x870a, 0x04);837838spca500_setmode(gspca_dev, xmult, ymult);839/* switch to video camera mode */840reg_w(gspca_dev, 0x00, 0x8000, 0x0004);841842reg_r_wait(gspca_dev, 0, 0x8000, 0x44);843844reg_r(gspca_dev, 0x816b, 1);845Data = gspca_dev->usb_buf[0];846reg_w(gspca_dev, 0x00, 0x816b, Data);847break;848case LogitechTraveler:849case LogitechClickSmart510:850reg_w(gspca_dev, 0x02, 0x00, 0x00);851/* enable drop packet */852reg_w(gspca_dev, 0x00, 0x850a, 0x0001);853854err = spca50x_setup_qtable(gspca_dev,8550x00, 0x8800,8560x8840, qtable_creative_pccam);857if (err < 0)858PDEBUG(D_ERR, "spca50x_setup_qtable failed");859reg_w(gspca_dev, 0x00, 0x8880, 3);860reg_w(gspca_dev, 0x00, 0x800a, 0x00);861/* Init SDRAM - needed for SDRAM access */862reg_w(gspca_dev, 0x00, 0x870a, 0x04);863864spca500_setmode(gspca_dev, xmult, ymult);865866/* switch to video camera mode */867reg_w(gspca_dev, 0x00, 0x8000, 0x0004);868reg_r_wait(gspca_dev, 0, 0x8000, 0x44);869870reg_r(gspca_dev, 0x816b, 1);871Data = gspca_dev->usb_buf[0];872reg_w(gspca_dev, 0x00, 0x816b, Data);873write_vector(gspca_dev, Clicksmart510_defaults);874break;875}876return 0;877}878879static void sd_stopN(struct gspca_dev *gspca_dev)880{881reg_w(gspca_dev, 0, 0x8003, 0x00);882883/* switch to video camera mode */884reg_w(gspca_dev, 0x00, 0x8000, 0x0004);885reg_r(gspca_dev, 0x8000, 1);886PDEBUG(D_STREAM, "stop SPCA500 done reg8000: 0x%2x",887gspca_dev->usb_buf[0]);888}889890static void sd_pkt_scan(struct gspca_dev *gspca_dev,891u8 *data, /* isoc packet */892int len) /* iso packet length */893{894struct sd *sd = (struct sd *) gspca_dev;895int i;896static __u8 ffd9[] = {0xff, 0xd9};897898/* frames are jpeg 4.1.1 without 0xff escape */899if (data[0] == 0xff) {900if (data[1] != 0x01) { /* drop packet */901/* gspca_dev->last_packet_type = DISCARD_PACKET; */902return;903}904gspca_frame_add(gspca_dev, LAST_PACKET,905ffd9, 2);906907/* put the JPEG header in the new frame */908gspca_frame_add(gspca_dev, FIRST_PACKET,909sd->jpeg_hdr, JPEG_HDR_SZ);910911data += SPCA500_OFFSET_DATA;912len -= SPCA500_OFFSET_DATA;913} else {914data += 1;915len -= 1;916}917918/* add 0x00 after 0xff */919i = 0;920do {921if (data[i] == 0xff) {922gspca_frame_add(gspca_dev, INTER_PACKET,923data, i + 1);924len -= i;925data += i;926*data = 0x00;927i = 0;928}929i++;930} while (i < len);931gspca_frame_add(gspca_dev, INTER_PACKET, data, len);932}933934static void setbrightness(struct gspca_dev *gspca_dev)935{936struct sd *sd = (struct sd *) gspca_dev;937938reg_w(gspca_dev, 0x00, 0x8167,939(__u8) (sd->brightness - 128));940}941942static void setcontrast(struct gspca_dev *gspca_dev)943{944struct sd *sd = (struct sd *) gspca_dev;945946reg_w(gspca_dev, 0x00, 0x8168, sd->contrast);947}948949static void setcolors(struct gspca_dev *gspca_dev)950{951struct sd *sd = (struct sd *) gspca_dev;952953reg_w(gspca_dev, 0x00, 0x8169, sd->colors);954}955956static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)957{958struct sd *sd = (struct sd *) gspca_dev;959960sd->brightness = val;961if (gspca_dev->streaming)962setbrightness(gspca_dev);963return 0;964}965966static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)967{968struct sd *sd = (struct sd *) gspca_dev;969970*val = sd->brightness;971return 0;972}973974static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)975{976struct sd *sd = (struct sd *) gspca_dev;977978sd->contrast = val;979if (gspca_dev->streaming)980setcontrast(gspca_dev);981return 0;982}983984static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)985{986struct sd *sd = (struct sd *) gspca_dev;987988*val = sd->contrast;989return 0;990}991992static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)993{994struct sd *sd = (struct sd *) gspca_dev;995996sd->colors = val;997if (gspca_dev->streaming)998setcolors(gspca_dev);999return 0;1000}10011002static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)1003{1004struct sd *sd = (struct sd *) gspca_dev;10051006*val = sd->colors;1007return 0;1008}10091010static int sd_set_jcomp(struct gspca_dev *gspca_dev,1011struct v4l2_jpegcompression *jcomp)1012{1013struct sd *sd = (struct sd *) gspca_dev;10141015if (jcomp->quality < QUALITY_MIN)1016sd->quality = QUALITY_MIN;1017else if (jcomp->quality > QUALITY_MAX)1018sd->quality = QUALITY_MAX;1019else1020sd->quality = jcomp->quality;1021if (gspca_dev->streaming)1022jpeg_set_qual(sd->jpeg_hdr, sd->quality);1023return 0;1024}10251026static int sd_get_jcomp(struct gspca_dev *gspca_dev,1027struct v4l2_jpegcompression *jcomp)1028{1029struct sd *sd = (struct sd *) gspca_dev;10301031memset(jcomp, 0, sizeof *jcomp);1032jcomp->quality = sd->quality;1033jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT1034| V4L2_JPEG_MARKER_DQT;1035return 0;1036}10371038/* sub-driver description */1039static const struct sd_desc sd_desc = {1040.name = MODULE_NAME,1041.ctrls = sd_ctrls,1042.nctrls = ARRAY_SIZE(sd_ctrls),1043.config = sd_config,1044.init = sd_init,1045.start = sd_start,1046.stopN = sd_stopN,1047.pkt_scan = sd_pkt_scan,1048.get_jcomp = sd_get_jcomp,1049.set_jcomp = sd_set_jcomp,1050};10511052/* -- module initialisation -- */1053static const struct usb_device_id device_table[] = {1054{USB_DEVICE(0x040a, 0x0300), .driver_info = KodakEZ200},1055{USB_DEVICE(0x041e, 0x400a), .driver_info = CreativePCCam300},1056{USB_DEVICE(0x046d, 0x0890), .driver_info = LogitechTraveler},1057{USB_DEVICE(0x046d, 0x0900), .driver_info = LogitechClickSmart310},1058{USB_DEVICE(0x046d, 0x0901), .driver_info = LogitechClickSmart510},1059{USB_DEVICE(0x04a5, 0x300c), .driver_info = BenqDC1016},1060{USB_DEVICE(0x04fc, 0x7333), .driver_info = PalmPixDC85},1061{USB_DEVICE(0x055f, 0xc200), .driver_info = MustekGsmart300},1062{USB_DEVICE(0x055f, 0xc220), .driver_info = Gsmartmini},1063{USB_DEVICE(0x06bd, 0x0404), .driver_info = AgfaCl20},1064{USB_DEVICE(0x06be, 0x0800), .driver_info = Optimedia},1065{USB_DEVICE(0x084d, 0x0003), .driver_info = DLinkDSC350},1066{USB_DEVICE(0x08ca, 0x0103), .driver_info = AiptekPocketDV},1067{USB_DEVICE(0x2899, 0x012c), .driver_info = ToptroIndus},1068{USB_DEVICE(0x8086, 0x0630), .driver_info = IntelPocketPCCamera},1069{}1070};1071MODULE_DEVICE_TABLE(usb, device_table);10721073/* -- device connect -- */1074static int sd_probe(struct usb_interface *intf,1075const struct usb_device_id *id)1076{1077return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),1078THIS_MODULE);1079}10801081static struct usb_driver sd_driver = {1082.name = MODULE_NAME,1083.id_table = device_table,1084.probe = sd_probe,1085.disconnect = gspca_disconnect,1086#ifdef CONFIG_PM1087.suspend = gspca_suspend,1088.resume = gspca_resume,1089#endif1090};10911092/* -- module insert / remove -- */1093static int __init sd_mod_init(void)1094{1095return usb_register(&sd_driver);1096}1097static void __exit sd_mod_exit(void)1098{1099usb_deregister(&sd_driver);1100}11011102module_init(sd_mod_init);1103module_exit(sd_mod_exit);110411051106