600 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * SPCA506 chip based cameras function4 * M Xhaard 15/04/2004 based on different work Mark Taylor and others5 * and my own snoopy file on a pv-321c donate by a german compagny6 * "Firma Frank Gmbh" from Saarbruecken7 *8 * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>9 */10 11#define MODULE_NAME "spca506"12 13#include "gspca.h"14 15MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");16MODULE_DESCRIPTION("GSPCA/SPCA506 USB Camera Driver");17MODULE_LICENSE("GPL");18 19/* specific webcam descriptor */20struct sd {21 struct gspca_dev gspca_dev; /* !! must be the first item */22 23 char norme;24 char channel;25};26 27static const struct v4l2_pix_format vga_mode[] = {28 {160, 120, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE,29 .bytesperline = 160,30 .sizeimage = 160 * 120 * 3 / 2,31 .colorspace = V4L2_COLORSPACE_SRGB,32 .priv = 5},33 {176, 144, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE,34 .bytesperline = 176,35 .sizeimage = 176 * 144 * 3 / 2,36 .colorspace = V4L2_COLORSPACE_SRGB,37 .priv = 4},38 {320, 240, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE,39 .bytesperline = 320,40 .sizeimage = 320 * 240 * 3 / 2,41 .colorspace = V4L2_COLORSPACE_SRGB,42 .priv = 2},43 {352, 288, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE,44 .bytesperline = 352,45 .sizeimage = 352 * 288 * 3 / 2,46 .colorspace = V4L2_COLORSPACE_SRGB,47 .priv = 1},48 {640, 480, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE,49 .bytesperline = 640,50 .sizeimage = 640 * 480 * 3 / 2,51 .colorspace = V4L2_COLORSPACE_SRGB,52 .priv = 0},53};54 55#define SPCA50X_OFFSET_DATA 1056 57#define SAA7113_bright 0x0a /* defaults 0x80 */58#define SAA7113_contrast 0x0b /* defaults 0x47 */59#define SAA7113_saturation 0x0c /* defaults 0x40 */60#define SAA7113_hue 0x0d /* defaults 0x00 */61#define SAA7113_I2C_BASE_WRITE 0x4a62 63/* read 'len' bytes to gspca_dev->usb_buf */64static void reg_r(struct gspca_dev *gspca_dev,65 __u16 req,66 __u16 index,67 __u16 length)68{69 usb_control_msg(gspca_dev->dev,70 usb_rcvctrlpipe(gspca_dev->dev, 0),71 req,72 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,73 0, /* value */74 index, gspca_dev->usb_buf, length,75 500);76}77 78static void reg_w(struct usb_device *dev,79 __u16 req,80 __u16 value,81 __u16 index)82{83 usb_control_msg(dev,84 usb_sndctrlpipe(dev, 0),85 req,86 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,87 value, index,88 NULL, 0, 500);89}90 91static void spca506_Initi2c(struct gspca_dev *gspca_dev)92{93 reg_w(gspca_dev->dev, 0x07, SAA7113_I2C_BASE_WRITE, 0x0004);94}95 96static void spca506_WriteI2c(struct gspca_dev *gspca_dev, __u16 valeur,97 __u16 reg)98{99 int retry = 60;100 101 reg_w(gspca_dev->dev, 0x07, reg, 0x0001);102 reg_w(gspca_dev->dev, 0x07, valeur, 0x0000);103 while (retry--) {104 reg_r(gspca_dev, 0x07, 0x0003, 2);105 if ((gspca_dev->usb_buf[0] | gspca_dev->usb_buf[1]) == 0x00)106 break;107 }108}109 110static void spca506_SetNormeInput(struct gspca_dev *gspca_dev,111 __u16 norme,112 __u16 channel)113{114 struct sd *sd = (struct sd *) gspca_dev;115/* fixme: check if channel == 0..3 and 6..9 (8 values) */116 __u8 setbit0 = 0x00;117 __u8 setbit1 = 0x00;118 __u8 videomask = 0x00;119 120 gspca_dbg(gspca_dev, D_STREAM, "** Open Set Norme **\n");121 spca506_Initi2c(gspca_dev);122 /* NTSC bit0 -> 1(525 l) PAL SECAM bit0 -> 0 (625 l) */123 /* Composite channel bit1 -> 1 S-video bit 1 -> 0 */124 /* and exclude SAA7113 reserved channel set default 0 otherwise */125 if (norme & V4L2_STD_NTSC)126 setbit0 = 0x01;127 if (channel == 4 || channel == 5 || channel > 9)128 channel = 0;129 if (channel < 4)130 setbit1 = 0x02;131 videomask = (0x48 | setbit0 | setbit1);132 reg_w(gspca_dev->dev, 0x08, videomask, 0x0000);133 spca506_WriteI2c(gspca_dev, (0xc0 | (channel & 0x0F)), 0x02);134 135 if (norme & V4L2_STD_NTSC)136 spca506_WriteI2c(gspca_dev, 0x33, 0x0e);137 /* Chrominance Control NTSC N */138 else if (norme & V4L2_STD_SECAM)139 spca506_WriteI2c(gspca_dev, 0x53, 0x0e);140 /* Chrominance Control SECAM */141 else142 spca506_WriteI2c(gspca_dev, 0x03, 0x0e);143 /* Chrominance Control PAL BGHIV */144 145 sd->norme = norme;146 sd->channel = channel;147 gspca_dbg(gspca_dev, D_STREAM, "Set Video Byte to 0x%2x\n", videomask);148 gspca_dbg(gspca_dev, D_STREAM, "Set Norme: %08x Channel %d",149 norme, channel);150}151 152static void spca506_GetNormeInput(struct gspca_dev *gspca_dev,153 __u16 *norme, __u16 *channel)154{155 struct sd *sd = (struct sd *) gspca_dev;156 157 /* Read the register is not so good value change so158 we use your own copy in spca50x struct */159 *norme = sd->norme;160 *channel = sd->channel;161 gspca_dbg(gspca_dev, D_STREAM, "Get Norme: %d Channel %d\n",162 *norme, *channel);163}164 165static void spca506_Setsize(struct gspca_dev *gspca_dev, __u16 code,166 __u16 xmult, __u16 ymult)167{168 struct usb_device *dev = gspca_dev->dev;169 170 gspca_dbg(gspca_dev, D_STREAM, "** SetSize **\n");171 reg_w(dev, 0x04, (0x18 | (code & 0x07)), 0x0000);172 /* Soft snap 0x40 Hard 0x41 */173 reg_w(dev, 0x04, 0x41, 0x0001);174 reg_w(dev, 0x04, 0x00, 0x0002);175 /* reserved */176 reg_w(dev, 0x04, 0x00, 0x0003);177 178 /* reserved */179 reg_w(dev, 0x04, 0x00, 0x0004);180 /* reserved */181 reg_w(dev, 0x04, 0x01, 0x0005);182 /* reserced */183 reg_w(dev, 0x04, xmult, 0x0006);184 /* reserved */185 reg_w(dev, 0x04, ymult, 0x0007);186 /* compression 1 */187 reg_w(dev, 0x04, 0x00, 0x0008);188 /* T=64 -> 2 */189 reg_w(dev, 0x04, 0x00, 0x0009);190 /* threshold2D */191 reg_w(dev, 0x04, 0x21, 0x000a);192 /* quantization */193 reg_w(dev, 0x04, 0x00, 0x000b);194}195 196/* this function is called at probe time */197static int sd_config(struct gspca_dev *gspca_dev,198 const struct usb_device_id *id)199{200 struct cam *cam;201 202 cam = &gspca_dev->cam;203 cam->cam_mode = vga_mode;204 cam->nmodes = ARRAY_SIZE(vga_mode);205 return 0;206}207 208/* this function is called at probe and resume time */209static int sd_init(struct gspca_dev *gspca_dev)210{211 struct usb_device *dev = gspca_dev->dev;212 213 reg_w(dev, 0x03, 0x00, 0x0004);214 reg_w(dev, 0x03, 0xFF, 0x0003);215 reg_w(dev, 0x03, 0x00, 0x0000);216 reg_w(dev, 0x03, 0x1c, 0x0001);217 reg_w(dev, 0x03, 0x18, 0x0001);218 /* Init on PAL and composite input0 */219 spca506_SetNormeInput(gspca_dev, 0, 0);220 reg_w(dev, 0x03, 0x1c, 0x0001);221 reg_w(dev, 0x03, 0x18, 0x0001);222 reg_w(dev, 0x05, 0x00, 0x0000);223 reg_w(dev, 0x05, 0xef, 0x0001);224 reg_w(dev, 0x05, 0x00, 0x00c1);225 reg_w(dev, 0x05, 0x00, 0x00c2);226 reg_w(dev, 0x06, 0x18, 0x0002);227 reg_w(dev, 0x06, 0xf5, 0x0011);228 reg_w(dev, 0x06, 0x02, 0x0012);229 reg_w(dev, 0x06, 0xfb, 0x0013);230 reg_w(dev, 0x06, 0x00, 0x0014);231 reg_w(dev, 0x06, 0xa4, 0x0051);232 reg_w(dev, 0x06, 0x40, 0x0052);233 reg_w(dev, 0x06, 0x71, 0x0053);234 reg_w(dev, 0x06, 0x40, 0x0054);235 /************************************************/236 reg_w(dev, 0x03, 0x00, 0x0004);237 reg_w(dev, 0x03, 0x00, 0x0003);238 reg_w(dev, 0x03, 0x00, 0x0004);239 reg_w(dev, 0x03, 0xFF, 0x0003);240 reg_w(dev, 0x02, 0x00, 0x0000);241 reg_w(dev, 0x03, 0x60, 0x0000);242 reg_w(dev, 0x03, 0x18, 0x0001);243 /* for a better reading mx :) */244 /*sdca506_WriteI2c(value,register) */245 spca506_Initi2c(gspca_dev);246 spca506_WriteI2c(gspca_dev, 0x08, 0x01);247 spca506_WriteI2c(gspca_dev, 0xc0, 0x02);248 /* input composite video */249 spca506_WriteI2c(gspca_dev, 0x33, 0x03);250 spca506_WriteI2c(gspca_dev, 0x00, 0x04);251 spca506_WriteI2c(gspca_dev, 0x00, 0x05);252 spca506_WriteI2c(gspca_dev, 0x0d, 0x06);253 spca506_WriteI2c(gspca_dev, 0xf0, 0x07);254 spca506_WriteI2c(gspca_dev, 0x98, 0x08);255 spca506_WriteI2c(gspca_dev, 0x03, 0x09);256 spca506_WriteI2c(gspca_dev, 0x80, 0x0a);257 spca506_WriteI2c(gspca_dev, 0x47, 0x0b);258 spca506_WriteI2c(gspca_dev, 0x48, 0x0c);259 spca506_WriteI2c(gspca_dev, 0x00, 0x0d);260 spca506_WriteI2c(gspca_dev, 0x03, 0x0e); /* Chroma Pal adjust */261 spca506_WriteI2c(gspca_dev, 0x2a, 0x0f);262 spca506_WriteI2c(gspca_dev, 0x00, 0x10);263 spca506_WriteI2c(gspca_dev, 0x0c, 0x11);264 spca506_WriteI2c(gspca_dev, 0xb8, 0x12);265 spca506_WriteI2c(gspca_dev, 0x01, 0x13);266 spca506_WriteI2c(gspca_dev, 0x00, 0x14);267 spca506_WriteI2c(gspca_dev, 0x00, 0x15);268 spca506_WriteI2c(gspca_dev, 0x00, 0x16);269 spca506_WriteI2c(gspca_dev, 0x00, 0x17);270 spca506_WriteI2c(gspca_dev, 0x00, 0x18);271 spca506_WriteI2c(gspca_dev, 0x00, 0x19);272 spca506_WriteI2c(gspca_dev, 0x00, 0x1a);273 spca506_WriteI2c(gspca_dev, 0x00, 0x1b);274 spca506_WriteI2c(gspca_dev, 0x00, 0x1c);275 spca506_WriteI2c(gspca_dev, 0x00, 0x1d);276 spca506_WriteI2c(gspca_dev, 0x00, 0x1e);277 spca506_WriteI2c(gspca_dev, 0xa1, 0x1f);278 spca506_WriteI2c(gspca_dev, 0x02, 0x40);279 spca506_WriteI2c(gspca_dev, 0xff, 0x41);280 spca506_WriteI2c(gspca_dev, 0xff, 0x42);281 spca506_WriteI2c(gspca_dev, 0xff, 0x43);282 spca506_WriteI2c(gspca_dev, 0xff, 0x44);283 spca506_WriteI2c(gspca_dev, 0xff, 0x45);284 spca506_WriteI2c(gspca_dev, 0xff, 0x46);285 spca506_WriteI2c(gspca_dev, 0xff, 0x47);286 spca506_WriteI2c(gspca_dev, 0xff, 0x48);287 spca506_WriteI2c(gspca_dev, 0xff, 0x49);288 spca506_WriteI2c(gspca_dev, 0xff, 0x4a);289 spca506_WriteI2c(gspca_dev, 0xff, 0x4b);290 spca506_WriteI2c(gspca_dev, 0xff, 0x4c);291 spca506_WriteI2c(gspca_dev, 0xff, 0x4d);292 spca506_WriteI2c(gspca_dev, 0xff, 0x4e);293 spca506_WriteI2c(gspca_dev, 0xff, 0x4f);294 spca506_WriteI2c(gspca_dev, 0xff, 0x50);295 spca506_WriteI2c(gspca_dev, 0xff, 0x51);296 spca506_WriteI2c(gspca_dev, 0xff, 0x52);297 spca506_WriteI2c(gspca_dev, 0xff, 0x53);298 spca506_WriteI2c(gspca_dev, 0xff, 0x54);299 spca506_WriteI2c(gspca_dev, 0xff, 0x55);300 spca506_WriteI2c(gspca_dev, 0xff, 0x56);301 spca506_WriteI2c(gspca_dev, 0xff, 0x57);302 spca506_WriteI2c(gspca_dev, 0x00, 0x58);303 spca506_WriteI2c(gspca_dev, 0x54, 0x59);304 spca506_WriteI2c(gspca_dev, 0x07, 0x5a);305 spca506_WriteI2c(gspca_dev, 0x83, 0x5b);306 spca506_WriteI2c(gspca_dev, 0x00, 0x5c);307 spca506_WriteI2c(gspca_dev, 0x00, 0x5d);308 spca506_WriteI2c(gspca_dev, 0x00, 0x5e);309 spca506_WriteI2c(gspca_dev, 0x00, 0x5f);310 spca506_WriteI2c(gspca_dev, 0x00, 0x60);311 spca506_WriteI2c(gspca_dev, 0x05, 0x61);312 spca506_WriteI2c(gspca_dev, 0x9f, 0x62);313 gspca_dbg(gspca_dev, D_STREAM, "** Close Init *\n");314 return 0;315}316 317static int sd_start(struct gspca_dev *gspca_dev)318{319 struct usb_device *dev = gspca_dev->dev;320 __u16 norme;321 __u16 channel;322 323 /**************************************/324 reg_w(dev, 0x03, 0x00, 0x0004);325 reg_w(dev, 0x03, 0x00, 0x0003);326 reg_w(dev, 0x03, 0x00, 0x0004);327 reg_w(dev, 0x03, 0xFF, 0x0003);328 reg_w(dev, 0x02, 0x00, 0x0000);329 reg_w(dev, 0x03, 0x60, 0x0000);330 reg_w(dev, 0x03, 0x18, 0x0001);331 332 /*sdca506_WriteI2c(value,register) */333 spca506_Initi2c(gspca_dev);334 spca506_WriteI2c(gspca_dev, 0x08, 0x01); /* Increment Delay */335/* spca506_WriteI2c(gspca_dev, 0xc0, 0x02); * Analog Input Control 1 */336 spca506_WriteI2c(gspca_dev, 0x33, 0x03);337 /* Analog Input Control 2 */338 spca506_WriteI2c(gspca_dev, 0x00, 0x04);339 /* Analog Input Control 3 */340 spca506_WriteI2c(gspca_dev, 0x00, 0x05);341 /* Analog Input Control 4 */342 spca506_WriteI2c(gspca_dev, 0x0d, 0x06);343 /* Horizontal Sync Start 0xe9-0x0d */344 spca506_WriteI2c(gspca_dev, 0xf0, 0x07);345 /* Horizontal Sync Stop 0x0d-0xf0 */346 347 spca506_WriteI2c(gspca_dev, 0x98, 0x08); /* Sync Control */348/* Defaults value */349 spca506_WriteI2c(gspca_dev, 0x03, 0x09); /* Luminance Control */350 spca506_WriteI2c(gspca_dev, 0x80, 0x0a);351 /* Luminance Brightness */352 spca506_WriteI2c(gspca_dev, 0x47, 0x0b); /* Luminance Contrast */353 spca506_WriteI2c(gspca_dev, 0x48, 0x0c);354 /* Chrominance Saturation */355 spca506_WriteI2c(gspca_dev, 0x00, 0x0d);356 /* Chrominance Hue Control */357 spca506_WriteI2c(gspca_dev, 0x2a, 0x0f);358 /* Chrominance Gain Control */359 /**************************************/360 spca506_WriteI2c(gspca_dev, 0x00, 0x10);361 /* Format/Delay Control */362 spca506_WriteI2c(gspca_dev, 0x0c, 0x11); /* Output Control 1 */363 spca506_WriteI2c(gspca_dev, 0xb8, 0x12); /* Output Control 2 */364 spca506_WriteI2c(gspca_dev, 0x01, 0x13); /* Output Control 3 */365 spca506_WriteI2c(gspca_dev, 0x00, 0x14); /* reserved */366 spca506_WriteI2c(gspca_dev, 0x00, 0x15); /* VGATE START */367 spca506_WriteI2c(gspca_dev, 0x00, 0x16); /* VGATE STOP */368 spca506_WriteI2c(gspca_dev, 0x00, 0x17); /* VGATE Control (MSB) */369 spca506_WriteI2c(gspca_dev, 0x00, 0x18);370 spca506_WriteI2c(gspca_dev, 0x00, 0x19);371 spca506_WriteI2c(gspca_dev, 0x00, 0x1a);372 spca506_WriteI2c(gspca_dev, 0x00, 0x1b);373 spca506_WriteI2c(gspca_dev, 0x00, 0x1c);374 spca506_WriteI2c(gspca_dev, 0x00, 0x1d);375 spca506_WriteI2c(gspca_dev, 0x00, 0x1e);376 spca506_WriteI2c(gspca_dev, 0xa1, 0x1f);377 spca506_WriteI2c(gspca_dev, 0x02, 0x40);378 spca506_WriteI2c(gspca_dev, 0xff, 0x41);379 spca506_WriteI2c(gspca_dev, 0xff, 0x42);380 spca506_WriteI2c(gspca_dev, 0xff, 0x43);381 spca506_WriteI2c(gspca_dev, 0xff, 0x44);382 spca506_WriteI2c(gspca_dev, 0xff, 0x45);383 spca506_WriteI2c(gspca_dev, 0xff, 0x46);384 spca506_WriteI2c(gspca_dev, 0xff, 0x47);385 spca506_WriteI2c(gspca_dev, 0xff, 0x48);386 spca506_WriteI2c(gspca_dev, 0xff, 0x49);387 spca506_WriteI2c(gspca_dev, 0xff, 0x4a);388 spca506_WriteI2c(gspca_dev, 0xff, 0x4b);389 spca506_WriteI2c(gspca_dev, 0xff, 0x4c);390 spca506_WriteI2c(gspca_dev, 0xff, 0x4d);391 spca506_WriteI2c(gspca_dev, 0xff, 0x4e);392 spca506_WriteI2c(gspca_dev, 0xff, 0x4f);393 spca506_WriteI2c(gspca_dev, 0xff, 0x50);394 spca506_WriteI2c(gspca_dev, 0xff, 0x51);395 spca506_WriteI2c(gspca_dev, 0xff, 0x52);396 spca506_WriteI2c(gspca_dev, 0xff, 0x53);397 spca506_WriteI2c(gspca_dev, 0xff, 0x54);398 spca506_WriteI2c(gspca_dev, 0xff, 0x55);399 spca506_WriteI2c(gspca_dev, 0xff, 0x56);400 spca506_WriteI2c(gspca_dev, 0xff, 0x57);401 spca506_WriteI2c(gspca_dev, 0x00, 0x58);402 spca506_WriteI2c(gspca_dev, 0x54, 0x59);403 spca506_WriteI2c(gspca_dev, 0x07, 0x5a);404 spca506_WriteI2c(gspca_dev, 0x83, 0x5b);405 spca506_WriteI2c(gspca_dev, 0x00, 0x5c);406 spca506_WriteI2c(gspca_dev, 0x00, 0x5d);407 spca506_WriteI2c(gspca_dev, 0x00, 0x5e);408 spca506_WriteI2c(gspca_dev, 0x00, 0x5f);409 spca506_WriteI2c(gspca_dev, 0x00, 0x60);410 spca506_WriteI2c(gspca_dev, 0x05, 0x61);411 spca506_WriteI2c(gspca_dev, 0x9f, 0x62);412 /**************************************/413 reg_w(dev, 0x05, 0x00, 0x0003);414 reg_w(dev, 0x05, 0x00, 0x0004);415 reg_w(dev, 0x03, 0x10, 0x0001);416 reg_w(dev, 0x03, 0x78, 0x0000);417 switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {418 case 0:419 spca506_Setsize(gspca_dev, 0, 0x10, 0x10);420 break;421 case 1:422 spca506_Setsize(gspca_dev, 1, 0x1a, 0x1a);423 break;424 case 2:425 spca506_Setsize(gspca_dev, 2, 0x1c, 0x1c);426 break;427 case 4:428 spca506_Setsize(gspca_dev, 4, 0x34, 0x34);429 break;430 default:431/* case 5: */432 spca506_Setsize(gspca_dev, 5, 0x40, 0x40);433 break;434 }435 436 /* compress setting and size */437 /* set i2c luma */438 reg_w(dev, 0x02, 0x01, 0x0000);439 reg_w(dev, 0x03, 0x12, 0x0000);440 reg_r(gspca_dev, 0x04, 0x0001, 2);441 gspca_dbg(gspca_dev, D_STREAM, "webcam started\n");442 spca506_GetNormeInput(gspca_dev, &norme, &channel);443 spca506_SetNormeInput(gspca_dev, norme, channel);444 return 0;445}446 447static void sd_stopN(struct gspca_dev *gspca_dev)448{449 struct usb_device *dev = gspca_dev->dev;450 451 reg_w(dev, 0x02, 0x00, 0x0000);452 reg_w(dev, 0x03, 0x00, 0x0004);453 reg_w(dev, 0x03, 0x00, 0x0003);454}455 456static void sd_pkt_scan(struct gspca_dev *gspca_dev,457 u8 *data, /* isoc packet */458 int len) /* iso packet length */459{460 switch (data[0]) {461 case 0: /* start of frame */462 gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);463 data += SPCA50X_OFFSET_DATA;464 len -= SPCA50X_OFFSET_DATA;465 gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);466 break;467 case 0xff: /* drop */468/* gspca_dev->last_packet_type = DISCARD_PACKET; */469 break;470 default:471 data += 1;472 len -= 1;473 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);474 break;475 }476}477 478static void setbrightness(struct gspca_dev *gspca_dev, s32 val)479{480 spca506_Initi2c(gspca_dev);481 spca506_WriteI2c(gspca_dev, val, SAA7113_bright);482 spca506_WriteI2c(gspca_dev, 0x01, 0x09);483}484 485static void setcontrast(struct gspca_dev *gspca_dev, s32 val)486{487 spca506_Initi2c(gspca_dev);488 spca506_WriteI2c(gspca_dev, val, SAA7113_contrast);489 spca506_WriteI2c(gspca_dev, 0x01, 0x09);490}491 492static void setcolors(struct gspca_dev *gspca_dev, s32 val)493{494 spca506_Initi2c(gspca_dev);495 spca506_WriteI2c(gspca_dev, val, SAA7113_saturation);496 spca506_WriteI2c(gspca_dev, 0x01, 0x09);497}498 499static void sethue(struct gspca_dev *gspca_dev, s32 val)500{501 spca506_Initi2c(gspca_dev);502 spca506_WriteI2c(gspca_dev, val, SAA7113_hue);503 spca506_WriteI2c(gspca_dev, 0x01, 0x09);504}505 506static int sd_s_ctrl(struct v4l2_ctrl *ctrl)507{508 struct gspca_dev *gspca_dev =509 container_of(ctrl->handler, struct gspca_dev, ctrl_handler);510 511 gspca_dev->usb_err = 0;512 513 if (!gspca_dev->streaming)514 return 0;515 516 switch (ctrl->id) {517 case V4L2_CID_BRIGHTNESS:518 setbrightness(gspca_dev, ctrl->val);519 break;520 case V4L2_CID_CONTRAST:521 setcontrast(gspca_dev, ctrl->val);522 break;523 case V4L2_CID_SATURATION:524 setcolors(gspca_dev, ctrl->val);525 break;526 case V4L2_CID_HUE:527 sethue(gspca_dev, ctrl->val);528 break;529 }530 return gspca_dev->usb_err;531}532 533static const struct v4l2_ctrl_ops sd_ctrl_ops = {534 .s_ctrl = sd_s_ctrl,535};536 537static int sd_init_controls(struct gspca_dev *gspca_dev)538{539 struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;540 541 gspca_dev->vdev.ctrl_handler = hdl;542 v4l2_ctrl_handler_init(hdl, 4);543 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,544 V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);545 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,546 V4L2_CID_CONTRAST, 0, 255, 1, 0x47);547 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,548 V4L2_CID_SATURATION, 0, 255, 1, 0x40);549 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,550 V4L2_CID_HUE, 0, 255, 1, 0);551 552 if (hdl->error) {553 pr_err("Could not initialize controls\n");554 return hdl->error;555 }556 return 0;557}558 559/* sub-driver description */560static const struct sd_desc sd_desc = {561 .name = MODULE_NAME,562 .config = sd_config,563 .init = sd_init,564 .init_controls = sd_init_controls,565 .start = sd_start,566 .stopN = sd_stopN,567 .pkt_scan = sd_pkt_scan,568};569 570/* -- module initialisation -- */571static const struct usb_device_id device_table[] = {572 {USB_DEVICE(0x06e1, 0xa190)},573/* {USB_DEVICE(0x0733, 0x0430)}, FIXME: may be IntelPCCameraPro BRIDGE_SPCA505 */574 {USB_DEVICE(0x0734, 0x043b)},575 {USB_DEVICE(0x99fa, 0x8988)},576 {}577};578MODULE_DEVICE_TABLE(usb, device_table);579 580/* -- device connect -- */581static int sd_probe(struct usb_interface *intf, const struct usb_device_id *id)582{583 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),584 THIS_MODULE);585}586 587static struct usb_driver sd_driver = {588 .name = MODULE_NAME,589 .id_table = device_table,590 .probe = sd_probe,591 .disconnect = gspca_disconnect,592#ifdef CONFIG_PM593 .suspend = gspca_suspend,594 .resume = gspca_resume,595 .reset_resume = gspca_resume,596#endif597};598 599module_usb_driver(sd_driver);600