Path: blob/master/drivers/media/video/gspca/mars.c
17627 views
/*1* Mars-Semi MR97311A library2* Copyright (C) 2005 <[email protected]>3*4* V4L2 by Jean-Francois Moine <http://moinejf.free.fr>5*6* This program is free software; you can redistribute it and/or modify7* it under the terms of the GNU General Public License as published by8* the Free Software Foundation; either version 2 of the License, or9* any later version.10*11* This program is distributed in the hope that it will be useful,12* but WITHOUT ANY WARRANTY; without even the implied warranty of13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the14* GNU General Public License for more details.15*16* You should have received a copy of the GNU General Public License17* along with this program; if not, write to the Free Software18* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA19*/2021#define MODULE_NAME "mars"2223#include "gspca.h"24#include "jpeg.h"2526MODULE_AUTHOR("Michel Xhaard <[email protected]>");27MODULE_DESCRIPTION("GSPCA/Mars USB Camera Driver");28MODULE_LICENSE("GPL");2930/* controls */31enum e_ctrl {32BRIGHTNESS,33COLORS,34GAMMA,35SHARPNESS,36ILLUM_TOP,37ILLUM_BOT,38NCTRLS /* number of controls */39};4041/* specific webcam descriptor */42struct sd {43struct gspca_dev gspca_dev; /* !! must be the first item */4445struct gspca_ctrl ctrls[NCTRLS];4647u8 quality;48#define QUALITY_MIN 4049#define QUALITY_MAX 7050#define QUALITY_DEF 505152u8 jpeg_hdr[JPEG_HDR_SZ];53};5455/* V4L2 controls supported by the driver */56static void setbrightness(struct gspca_dev *gspca_dev);57static void setcolors(struct gspca_dev *gspca_dev);58static void setgamma(struct gspca_dev *gspca_dev);59static void setsharpness(struct gspca_dev *gspca_dev);60static int sd_setilluminator1(struct gspca_dev *gspca_dev, __s32 val);61static int sd_setilluminator2(struct gspca_dev *gspca_dev, __s32 val);6263static const struct ctrl sd_ctrls[NCTRLS] = {64[BRIGHTNESS] = {65{66.id = V4L2_CID_BRIGHTNESS,67.type = V4L2_CTRL_TYPE_INTEGER,68.name = "Brightness",69.minimum = 0,70.maximum = 30,71.step = 1,72.default_value = 15,73},74.set_control = setbrightness75},76[COLORS] = {77{78.id = V4L2_CID_SATURATION,79.type = V4L2_CTRL_TYPE_INTEGER,80.name = "Color",81.minimum = 1,82.maximum = 255,83.step = 1,84.default_value = 200,85},86.set_control = setcolors87},88[GAMMA] = {89{90.id = V4L2_CID_GAMMA,91.type = V4L2_CTRL_TYPE_INTEGER,92.name = "Gamma",93.minimum = 0,94.maximum = 3,95.step = 1,96.default_value = 1,97},98.set_control = setgamma99},100[SHARPNESS] = {101{102.id = V4L2_CID_SHARPNESS,103.type = V4L2_CTRL_TYPE_INTEGER,104.name = "Sharpness",105.minimum = 0,106.maximum = 2,107.step = 1,108.default_value = 1,109},110.set_control = setsharpness111},112[ILLUM_TOP] = {113{114.id = V4L2_CID_ILLUMINATORS_1,115.type = V4L2_CTRL_TYPE_BOOLEAN,116.name = "Top illuminator",117.minimum = 0,118.maximum = 1,119.step = 1,120.default_value = 0,121.flags = V4L2_CTRL_FLAG_UPDATE,122},123.set = sd_setilluminator1124},125[ILLUM_BOT] = {126{127.id = V4L2_CID_ILLUMINATORS_2,128.type = V4L2_CTRL_TYPE_BOOLEAN,129.name = "Bottom illuminator",130.minimum = 0,131.maximum = 1,132.step = 1,133.default_value = 0,134.flags = V4L2_CTRL_FLAG_UPDATE,135},136.set = sd_setilluminator2137},138};139140static const struct v4l2_pix_format vga_mode[] = {141{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,142.bytesperline = 320,143.sizeimage = 320 * 240 * 3 / 8 + 590,144.colorspace = V4L2_COLORSPACE_JPEG,145.priv = 2},146{640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,147.bytesperline = 640,148.sizeimage = 640 * 480 * 3 / 8 + 590,149.colorspace = V4L2_COLORSPACE_JPEG,150.priv = 1},151};152153static const __u8 mi_data[0x20] = {154/* 01 02 03 04 05 06 07 08 */1550x48, 0x22, 0x01, 0x47, 0x10, 0x00, 0x00, 0x00,156/* 09 0a 0b 0c 0d 0e 0f 10 */1570x00, 0x01, 0x30, 0x01, 0x30, 0x01, 0x30, 0x01,158/* 11 12 13 14 15 16 17 18 */1590x30, 0x00, 0x04, 0x00, 0x06, 0x01, 0xe2, 0x02,160/* 19 1a 1b 1c 1d 1e 1f 20 */1610x82, 0x00, 0x20, 0x17, 0x80, 0x08, 0x0c, 0x00162};163164/* write <len> bytes from gspca_dev->usb_buf */165static void reg_w(struct gspca_dev *gspca_dev,166int len)167{168int alen, ret;169170if (gspca_dev->usb_err < 0)171return;172173ret = usb_bulk_msg(gspca_dev->dev,174usb_sndbulkpipe(gspca_dev->dev, 4),175gspca_dev->usb_buf,176len,177&alen,178500); /* timeout in milliseconds */179if (ret < 0) {180err("reg write [%02x] error %d",181gspca_dev->usb_buf[0], ret);182gspca_dev->usb_err = ret;183}184}185186static void mi_w(struct gspca_dev *gspca_dev,187u8 addr,188u8 value)189{190gspca_dev->usb_buf[0] = 0x1f;191gspca_dev->usb_buf[1] = 0; /* control byte */192gspca_dev->usb_buf[2] = addr;193gspca_dev->usb_buf[3] = value;194195reg_w(gspca_dev, 4);196}197198static void setbrightness(struct gspca_dev *gspca_dev)199{200struct sd *sd = (struct sd *) gspca_dev;201202gspca_dev->usb_buf[0] = 0x61;203gspca_dev->usb_buf[1] = sd->ctrls[BRIGHTNESS].val;204reg_w(gspca_dev, 2);205}206207static void setcolors(struct gspca_dev *gspca_dev)208{209struct sd *sd = (struct sd *) gspca_dev;210s16 val;211212val = sd->ctrls[COLORS].val;213gspca_dev->usb_buf[0] = 0x5f;214gspca_dev->usb_buf[1] = val << 3;215gspca_dev->usb_buf[2] = ((val >> 2) & 0xf8) | 0x04;216reg_w(gspca_dev, 3);217}218219static void setgamma(struct gspca_dev *gspca_dev)220{221struct sd *sd = (struct sd *) gspca_dev;222223gspca_dev->usb_buf[0] = 0x06;224gspca_dev->usb_buf[1] = sd->ctrls[GAMMA].val * 0x40;225reg_w(gspca_dev, 2);226}227228static void setsharpness(struct gspca_dev *gspca_dev)229{230struct sd *sd = (struct sd *) gspca_dev;231232gspca_dev->usb_buf[0] = 0x67;233gspca_dev->usb_buf[1] = sd->ctrls[SHARPNESS].val * 4 + 3;234reg_w(gspca_dev, 2);235}236237static void setilluminators(struct gspca_dev *gspca_dev)238{239struct sd *sd = (struct sd *) gspca_dev;240241gspca_dev->usb_buf[0] = 0x22;242if (sd->ctrls[ILLUM_TOP].val)243gspca_dev->usb_buf[1] = 0x76;244else if (sd->ctrls[ILLUM_BOT].val)245gspca_dev->usb_buf[1] = 0x7a;246else247gspca_dev->usb_buf[1] = 0x7e;248reg_w(gspca_dev, 2);249}250251/* this function is called at probe time */252static int sd_config(struct gspca_dev *gspca_dev,253const struct usb_device_id *id)254{255struct sd *sd = (struct sd *) gspca_dev;256struct cam *cam;257258cam = &gspca_dev->cam;259cam->cam_mode = vga_mode;260cam->nmodes = ARRAY_SIZE(vga_mode);261cam->ctrls = sd->ctrls;262sd->quality = QUALITY_DEF;263gspca_dev->nbalt = 9; /* use the altsetting 08 */264return 0;265}266267/* this function is called at probe and resume time */268static int sd_init(struct gspca_dev *gspca_dev)269{270gspca_dev->ctrl_inac = (1 << ILLUM_TOP) | (1 << ILLUM_BOT);271return 0;272}273274static int sd_start(struct gspca_dev *gspca_dev)275{276struct sd *sd = (struct sd *) gspca_dev;277u8 *data;278int i;279280/* create the JPEG header */281jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,2820x21); /* JPEG 422 */283jpeg_set_qual(sd->jpeg_hdr, sd->quality);284285data = gspca_dev->usb_buf;286287data[0] = 0x01; /* address */288data[1] = 0x01;289reg_w(gspca_dev, 2);290291/*292Initialize the MR97113 chip register293*/294data[0] = 0x00; /* address */295data[1] = 0x0c | 0x01; /* reg 0 */296data[2] = 0x01; /* reg 1 */297data[3] = gspca_dev->width / 8; /* h_size , reg 2 */298data[4] = gspca_dev->height / 8; /* v_size , reg 3 */299data[5] = 0x30; /* reg 4, MI, PAS5101 :300* 0x30 for 24mhz , 0x28 for 12mhz */301data[6] = 0x02; /* reg 5, H start - was 0x04 */302data[7] = sd->ctrls[GAMMA].val * 0x40; /* reg 0x06: gamma */303data[8] = 0x01; /* reg 7, V start - was 0x03 */304/* if (h_size == 320 ) */305/* data[9]= 0x56; * reg 8, 24MHz, 2:1 scale down */306/* else */307data[9] = 0x52; /* reg 8, 24MHz, no scale down */308/*jfm: from win trace*/309data[10] = 0x18;310311reg_w(gspca_dev, 11);312313data[0] = 0x23; /* address */314data[1] = 0x09; /* reg 35, append frame header */315316reg_w(gspca_dev, 2);317318data[0] = 0x3c; /* address */319/* if (gspca_dev->width == 1280) */320/* data[1] = 200; * reg 60, pc-cam frame size321* (unit: 4KB) 800KB */322/* else */323data[1] = 50; /* 50 reg 60, pc-cam frame size324* (unit: 4KB) 200KB */325reg_w(gspca_dev, 2);326327/* auto dark-gain */328data[0] = 0x5e; /* address */329data[1] = 0; /* reg 94, Y Gain (auto) */330/*jfm: from win trace*/331/* reg 0x5f/0x60 (LE) = saturation */332/* h (60): xxxx x100333* l (5f): xxxx x000 */334data[2] = sd->ctrls[COLORS].val << 3;335data[3] = ((sd->ctrls[COLORS].val >> 2) & 0xf8) | 0x04;336data[4] = sd->ctrls[BRIGHTNESS].val; /* reg 0x61 = brightness */337data[5] = 0x00;338339reg_w(gspca_dev, 6);340341data[0] = 0x67;342/*jfm: from win trace*/343data[1] = sd->ctrls[SHARPNESS].val * 4 + 3;344data[2] = 0x14;345reg_w(gspca_dev, 3);346347data[0] = 0x69;348data[1] = 0x2f;349data[2] = 0x28;350data[3] = 0x42;351reg_w(gspca_dev, 4);352353data[0] = 0x63;354data[1] = 0x07;355reg_w(gspca_dev, 2);356/*jfm: win trace - many writes here to reg 0x64*/357358/* initialize the MI sensor */359for (i = 0; i < sizeof mi_data; i++)360mi_w(gspca_dev, i + 1, mi_data[i]);361362data[0] = 0x00;363data[1] = 0x4d; /* ISOC transferring enable... */364reg_w(gspca_dev, 2);365366gspca_dev->ctrl_inac = 0; /* activate the illuminator controls */367return gspca_dev->usb_err;368}369370static void sd_stopN(struct gspca_dev *gspca_dev)371{372struct sd *sd = (struct sd *) gspca_dev;373374gspca_dev->ctrl_inac = (1 << ILLUM_TOP) | (1 << ILLUM_BOT);375if (sd->ctrls[ILLUM_TOP].val || sd->ctrls[ILLUM_BOT].val) {376sd->ctrls[ILLUM_TOP].val = 0;377sd->ctrls[ILLUM_BOT].val = 0;378setilluminators(gspca_dev);379msleep(20);380}381382gspca_dev->usb_buf[0] = 1;383gspca_dev->usb_buf[1] = 0;384reg_w(gspca_dev, 2);385}386387static void sd_pkt_scan(struct gspca_dev *gspca_dev,388u8 *data, /* isoc packet */389int len) /* iso packet length */390{391struct sd *sd = (struct sd *) gspca_dev;392int p;393394if (len < 6) {395/* gspca_dev->last_packet_type = DISCARD_PACKET; */396return;397}398for (p = 0; p < len - 6; p++) {399if (data[0 + p] == 0xff400&& data[1 + p] == 0xff401&& data[2 + p] == 0x00402&& data[3 + p] == 0xff403&& data[4 + p] == 0x96) {404if (data[5 + p] == 0x64405|| data[5 + p] == 0x65406|| data[5 + p] == 0x66407|| data[5 + p] == 0x67) {408PDEBUG(D_PACK, "sof offset: %d len: %d",409p, len);410gspca_frame_add(gspca_dev, LAST_PACKET,411data, p);412413/* put the JPEG header */414gspca_frame_add(gspca_dev, FIRST_PACKET,415sd->jpeg_hdr, JPEG_HDR_SZ);416data += p + 16;417len -= p + 16;418break;419}420}421}422gspca_frame_add(gspca_dev, INTER_PACKET, data, len);423}424425static int sd_setilluminator1(struct gspca_dev *gspca_dev, __s32 val)426{427struct sd *sd = (struct sd *) gspca_dev;428429/* only one illuminator may be on */430sd->ctrls[ILLUM_TOP].val = val;431if (val)432sd->ctrls[ILLUM_BOT].val = 0;433setilluminators(gspca_dev);434return gspca_dev->usb_err;435}436437static int sd_setilluminator2(struct gspca_dev *gspca_dev, __s32 val)438{439struct sd *sd = (struct sd *) gspca_dev;440441/* only one illuminator may be on */442sd->ctrls[ILLUM_BOT].val = val;443if (val)444sd->ctrls[ILLUM_TOP].val = 0;445setilluminators(gspca_dev);446return gspca_dev->usb_err;447}448449static int sd_set_jcomp(struct gspca_dev *gspca_dev,450struct v4l2_jpegcompression *jcomp)451{452struct sd *sd = (struct sd *) gspca_dev;453454if (jcomp->quality < QUALITY_MIN)455sd->quality = QUALITY_MIN;456else if (jcomp->quality > QUALITY_MAX)457sd->quality = QUALITY_MAX;458else459sd->quality = jcomp->quality;460if (gspca_dev->streaming)461jpeg_set_qual(sd->jpeg_hdr, sd->quality);462return 0;463}464465static int sd_get_jcomp(struct gspca_dev *gspca_dev,466struct v4l2_jpegcompression *jcomp)467{468struct sd *sd = (struct sd *) gspca_dev;469470memset(jcomp, 0, sizeof *jcomp);471jcomp->quality = sd->quality;472jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT473| V4L2_JPEG_MARKER_DQT;474return 0;475}476477/* sub-driver description */478static const struct sd_desc sd_desc = {479.name = MODULE_NAME,480.ctrls = sd_ctrls,481.nctrls = NCTRLS,482.config = sd_config,483.init = sd_init,484.start = sd_start,485.stopN = sd_stopN,486.pkt_scan = sd_pkt_scan,487.get_jcomp = sd_get_jcomp,488.set_jcomp = sd_set_jcomp,489};490491/* -- module initialisation -- */492static const struct usb_device_id device_table[] = {493{USB_DEVICE(0x093a, 0x050f)},494{}495};496MODULE_DEVICE_TABLE(usb, device_table);497498/* -- device connect -- */499static int sd_probe(struct usb_interface *intf,500const struct usb_device_id *id)501{502return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),503THIS_MODULE);504}505506static struct usb_driver sd_driver = {507.name = MODULE_NAME,508.id_table = device_table,509.probe = sd_probe,510.disconnect = gspca_disconnect,511#ifdef CONFIG_PM512.suspend = gspca_suspend,513.resume = gspca_resume,514#endif515};516517/* -- module insert / remove -- */518static int __init sd_mod_init(void)519{520return usb_register(&sd_driver);521}522static void __exit sd_mod_exit(void)523{524usb_deregister(&sd_driver);525}526527module_init(sd_mod_init);528module_exit(sd_mod_exit);529530531