Path: blob/master/drivers/media/video/gspca/stk014.c
17628 views
/*1* Syntek DV4000 (STK014) subdriver2*3* Copyright (C) 2008 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*/1920#define MODULE_NAME "stk014"2122#include "gspca.h"23#include "jpeg.h"2425MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");26MODULE_DESCRIPTION("Syntek DV4000 (STK014) USB Camera Driver");27MODULE_LICENSE("GPL");2829/* controls */30enum e_ctrl {31BRIGHTNESS,32CONTRAST,33COLORS,34LIGHTFREQ,35NCTRLS /* number of controls */36};3738/* specific webcam descriptor */39struct sd {40struct gspca_dev gspca_dev; /* !! must be the first item */4142struct gspca_ctrl ctrls[NCTRLS];4344u8 quality;45#define QUALITY_MIN 7046#define QUALITY_MAX 9547#define QUALITY_DEF 884849u8 jpeg_hdr[JPEG_HDR_SZ];50};5152/* V4L2 controls supported by the driver */53static void setbrightness(struct gspca_dev *gspca_dev);54static void setcontrast(struct gspca_dev *gspca_dev);55static void setcolors(struct gspca_dev *gspca_dev);56static void setlightfreq(struct gspca_dev *gspca_dev);5758static const struct ctrl sd_ctrls[NCTRLS] = {59[BRIGHTNESS] = {60{61.id = V4L2_CID_BRIGHTNESS,62.type = V4L2_CTRL_TYPE_INTEGER,63.name = "Brightness",64.minimum = 0,65.maximum = 255,66.step = 1,67.default_value = 127,68},69.set_control = setbrightness70},71[CONTRAST] = {72{73.id = V4L2_CID_CONTRAST,74.type = V4L2_CTRL_TYPE_INTEGER,75.name = "Contrast",76.minimum = 0,77.maximum = 255,78.step = 1,79.default_value = 127,80},81.set_control = setcontrast82},83[COLORS] = {84{85.id = V4L2_CID_SATURATION,86.type = V4L2_CTRL_TYPE_INTEGER,87.name = "Color",88.minimum = 0,89.maximum = 255,90.step = 1,91.default_value = 127,92},93.set_control = setcolors94},95[LIGHTFREQ] = {96{97.id = V4L2_CID_POWER_LINE_FREQUENCY,98.type = V4L2_CTRL_TYPE_MENU,99.name = "Light frequency filter",100.minimum = 1,101.maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */102.step = 1,103.default_value = 1,104},105.set_control = setlightfreq106},107};108109static const struct v4l2_pix_format vga_mode[] = {110{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,111.bytesperline = 320,112.sizeimage = 320 * 240 * 3 / 8 + 590,113.colorspace = V4L2_COLORSPACE_JPEG,114.priv = 1},115{640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,116.bytesperline = 640,117.sizeimage = 640 * 480 * 3 / 8 + 590,118.colorspace = V4L2_COLORSPACE_JPEG,119.priv = 0},120};121122/* -- read a register -- */123static u8 reg_r(struct gspca_dev *gspca_dev,124__u16 index)125{126struct usb_device *dev = gspca_dev->dev;127int ret;128129if (gspca_dev->usb_err < 0)130return 0;131ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),1320x00,133USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,1340x00,135index,136gspca_dev->usb_buf, 1,137500);138if (ret < 0) {139err("reg_r err %d", ret);140gspca_dev->usb_err = ret;141return 0;142}143return gspca_dev->usb_buf[0];144}145146/* -- write a register -- */147static void reg_w(struct gspca_dev *gspca_dev,148__u16 index, __u16 value)149{150struct usb_device *dev = gspca_dev->dev;151int ret;152153if (gspca_dev->usb_err < 0)154return;155ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),1560x01,157USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,158value,159index,160NULL,1610,162500);163if (ret < 0) {164err("reg_w err %d", ret);165gspca_dev->usb_err = ret;166}167}168169/* -- get a bulk value (4 bytes) -- */170static void rcv_val(struct gspca_dev *gspca_dev,171int ads)172{173struct usb_device *dev = gspca_dev->dev;174int alen, ret;175176reg_w(gspca_dev, 0x634, (ads >> 16) & 0xff);177reg_w(gspca_dev, 0x635, (ads >> 8) & 0xff);178reg_w(gspca_dev, 0x636, ads & 0xff);179reg_w(gspca_dev, 0x637, 0);180reg_w(gspca_dev, 0x638, 4); /* len & 0xff */181reg_w(gspca_dev, 0x639, 0); /* len >> 8 */182reg_w(gspca_dev, 0x63a, 0);183reg_w(gspca_dev, 0x63b, 0);184reg_w(gspca_dev, 0x630, 5);185if (gspca_dev->usb_err < 0)186return;187ret = usb_bulk_msg(dev,188usb_rcvbulkpipe(dev, 0x05),189gspca_dev->usb_buf,1904, /* length */191&alen,192500); /* timeout in milliseconds */193if (ret < 0) {194err("rcv_val err %d", ret);195gspca_dev->usb_err = ret;196}197}198199/* -- send a bulk value -- */200static void snd_val(struct gspca_dev *gspca_dev,201int ads,202unsigned int val)203{204struct usb_device *dev = gspca_dev->dev;205int alen, ret;206__u8 seq = 0;207208if (ads == 0x003f08) {209reg_r(gspca_dev, 0x0704);210seq = reg_r(gspca_dev, 0x0705);211reg_r(gspca_dev, 0x0650);212reg_w(gspca_dev, 0x654, seq);213} else {214reg_w(gspca_dev, 0x654, (ads >> 16) & 0xff);215}216reg_w(gspca_dev, 0x655, (ads >> 8) & 0xff);217reg_w(gspca_dev, 0x656, ads & 0xff);218reg_w(gspca_dev, 0x657, 0);219reg_w(gspca_dev, 0x658, 0x04); /* size */220reg_w(gspca_dev, 0x659, 0);221reg_w(gspca_dev, 0x65a, 0);222reg_w(gspca_dev, 0x65b, 0);223reg_w(gspca_dev, 0x650, 5);224if (gspca_dev->usb_err < 0)225return;226gspca_dev->usb_buf[0] = val >> 24;227gspca_dev->usb_buf[1] = val >> 16;228gspca_dev->usb_buf[2] = val >> 8;229gspca_dev->usb_buf[3] = val;230ret = usb_bulk_msg(dev,231usb_sndbulkpipe(dev, 6),232gspca_dev->usb_buf,2334,234&alen,235500); /* timeout in milliseconds */236if (ret < 0) {237err("snd_val err %d", ret);238gspca_dev->usb_err = ret;239} else {240if (ads == 0x003f08) {241seq += 4;242seq &= 0x3f;243reg_w(gspca_dev, 0x705, seq);244}245}246}247248/* set a camera parameter */249static void set_par(struct gspca_dev *gspca_dev,250int parval)251{252snd_val(gspca_dev, 0x003f08, parval);253}254255static void setbrightness(struct gspca_dev *gspca_dev)256{257struct sd *sd = (struct sd *) gspca_dev;258int parval;259260parval = 0x06000000 /* whiteness */261+ (sd->ctrls[BRIGHTNESS].val << 16);262set_par(gspca_dev, parval);263}264265static void setcontrast(struct gspca_dev *gspca_dev)266{267struct sd *sd = (struct sd *) gspca_dev;268int parval;269270parval = 0x07000000 /* contrast */271+ (sd->ctrls[CONTRAST].val << 16);272set_par(gspca_dev, parval);273}274275static void setcolors(struct gspca_dev *gspca_dev)276{277struct sd *sd = (struct sd *) gspca_dev;278int parval;279280parval = 0x08000000 /* saturation */281+ (sd->ctrls[COLORS].val << 16);282set_par(gspca_dev, parval);283}284285static void setlightfreq(struct gspca_dev *gspca_dev)286{287struct sd *sd = (struct sd *) gspca_dev;288289set_par(gspca_dev, sd->ctrls[LIGHTFREQ].val == 1290? 0x33640000 /* 50 Hz */291: 0x33780000); /* 60 Hz */292}293294/* this function is called at probe time */295static int sd_config(struct gspca_dev *gspca_dev,296const struct usb_device_id *id)297{298struct sd *sd = (struct sd *) gspca_dev;299300gspca_dev->cam.cam_mode = vga_mode;301gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode);302gspca_dev->cam.ctrls = sd->ctrls;303sd->quality = QUALITY_DEF;304return 0;305}306307/* this function is called at probe and resume time */308static int sd_init(struct gspca_dev *gspca_dev)309{310u8 ret;311312/* check if the device responds */313usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1);314ret = reg_r(gspca_dev, 0x0740);315if (gspca_dev->usb_err >= 0) {316if (ret != 0xff) {317err("init reg: 0x%02x", ret);318gspca_dev->usb_err = -EIO;319}320}321return gspca_dev->usb_err;322}323324/* -- start the camera -- */325static int sd_start(struct gspca_dev *gspca_dev)326{327struct sd *sd = (struct sd *) gspca_dev;328int ret, value;329330/* create the JPEG header */331jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,3320x22); /* JPEG 411 */333jpeg_set_qual(sd->jpeg_hdr, sd->quality);334335/* work on alternate 1 */336usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1);337338set_par(gspca_dev, 0x10000000);339set_par(gspca_dev, 0x00000000);340set_par(gspca_dev, 0x8002e001);341set_par(gspca_dev, 0x14000000);342if (gspca_dev->width > 320)343value = 0x8002e001; /* 640x480 */344else345value = 0x4001f000; /* 320x240 */346set_par(gspca_dev, value);347ret = usb_set_interface(gspca_dev->dev,348gspca_dev->iface,349gspca_dev->alt);350if (ret < 0) {351err("set intf %d %d failed",352gspca_dev->iface, gspca_dev->alt);353gspca_dev->usb_err = ret;354goto out;355}356reg_r(gspca_dev, 0x0630);357rcv_val(gspca_dev, 0x000020); /* << (value ff ff ff ff) */358reg_r(gspca_dev, 0x0650);359snd_val(gspca_dev, 0x000020, 0xffffffff);360reg_w(gspca_dev, 0x0620, 0);361reg_w(gspca_dev, 0x0630, 0);362reg_w(gspca_dev, 0x0640, 0);363reg_w(gspca_dev, 0x0650, 0);364reg_w(gspca_dev, 0x0660, 0);365setbrightness(gspca_dev); /* whiteness */366setcontrast(gspca_dev); /* contrast */367setcolors(gspca_dev); /* saturation */368set_par(gspca_dev, 0x09800000); /* Red ? */369set_par(gspca_dev, 0x0a800000); /* Green ? */370set_par(gspca_dev, 0x0b800000); /* Blue ? */371set_par(gspca_dev, 0x0d030000); /* Gamma ? */372setlightfreq(gspca_dev);373374/* start the video flow */375set_par(gspca_dev, 0x01000000);376set_par(gspca_dev, 0x01000000);377if (gspca_dev->usb_err >= 0)378PDEBUG(D_STREAM, "camera started alt: 0x%02x",379gspca_dev->alt);380out:381return gspca_dev->usb_err;382}383384static void sd_stopN(struct gspca_dev *gspca_dev)385{386struct usb_device *dev = gspca_dev->dev;387388set_par(gspca_dev, 0x02000000);389set_par(gspca_dev, 0x02000000);390usb_set_interface(dev, gspca_dev->iface, 1);391reg_r(gspca_dev, 0x0630);392rcv_val(gspca_dev, 0x000020); /* << (value ff ff ff ff) */393reg_r(gspca_dev, 0x0650);394snd_val(gspca_dev, 0x000020, 0xffffffff);395reg_w(gspca_dev, 0x0620, 0);396reg_w(gspca_dev, 0x0630, 0);397reg_w(gspca_dev, 0x0640, 0);398reg_w(gspca_dev, 0x0650, 0);399reg_w(gspca_dev, 0x0660, 0);400PDEBUG(D_STREAM, "camera stopped");401}402403static void sd_pkt_scan(struct gspca_dev *gspca_dev,404u8 *data, /* isoc packet */405int len) /* iso packet length */406{407struct sd *sd = (struct sd *) gspca_dev;408static unsigned char ffd9[] = {0xff, 0xd9};409410/* a frame starts with:411* - 0xff 0xfe412* - 0x08 0x00 - length (little endian ?!)413* - 4 bytes = size of whole frame (BE - including header)414* - 0x00 0x0c415* - 0xff 0xd8416* - .. JPEG image with escape sequences (ff 00)417* (without ending - ff d9)418*/419if (data[0] == 0xff && data[1] == 0xfe) {420gspca_frame_add(gspca_dev, LAST_PACKET,421ffd9, 2);422423/* put the JPEG 411 header */424gspca_frame_add(gspca_dev, FIRST_PACKET,425sd->jpeg_hdr, JPEG_HDR_SZ);426427/* beginning of the frame */428#define STKHDRSZ 12429data += STKHDRSZ;430len -= STKHDRSZ;431}432gspca_frame_add(gspca_dev, INTER_PACKET, data, len);433}434435static int sd_querymenu(struct gspca_dev *gspca_dev,436struct v4l2_querymenu *menu)437{438static const char *freq_nm[3] = {"NoFliker", "50 Hz", "60 Hz"};439440switch (menu->id) {441case V4L2_CID_POWER_LINE_FREQUENCY:442if ((unsigned) menu->index >= ARRAY_SIZE(freq_nm))443break;444strcpy((char *) menu->name, freq_nm[menu->index]);445return 0;446}447return -EINVAL;448}449450static int sd_set_jcomp(struct gspca_dev *gspca_dev,451struct v4l2_jpegcompression *jcomp)452{453struct sd *sd = (struct sd *) gspca_dev;454455if (jcomp->quality < QUALITY_MIN)456sd->quality = QUALITY_MIN;457else if (jcomp->quality > QUALITY_MAX)458sd->quality = QUALITY_MAX;459else460sd->quality = jcomp->quality;461if (gspca_dev->streaming)462jpeg_set_qual(sd->jpeg_hdr, sd->quality);463return gspca_dev->usb_err;464}465466static int sd_get_jcomp(struct gspca_dev *gspca_dev,467struct v4l2_jpegcompression *jcomp)468{469struct sd *sd = (struct sd *) gspca_dev;470471memset(jcomp, 0, sizeof *jcomp);472jcomp->quality = sd->quality;473jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT474| V4L2_JPEG_MARKER_DQT;475return 0;476}477478/* sub-driver description */479static const struct sd_desc sd_desc = {480.name = MODULE_NAME,481.ctrls = sd_ctrls,482.nctrls = NCTRLS,483.config = sd_config,484.init = sd_init,485.start = sd_start,486.stopN = sd_stopN,487.pkt_scan = sd_pkt_scan,488.querymenu = sd_querymenu,489.get_jcomp = sd_get_jcomp,490.set_jcomp = sd_set_jcomp,491};492493/* -- module initialisation -- */494static const struct usb_device_id device_table[] = {495{USB_DEVICE(0x05e1, 0x0893)},496{}497};498MODULE_DEVICE_TABLE(usb, device_table);499500/* -- device connect -- */501static int sd_probe(struct usb_interface *intf,502const struct usb_device_id *id)503{504return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),505THIS_MODULE);506}507508static struct usb_driver sd_driver = {509.name = MODULE_NAME,510.id_table = device_table,511.probe = sd_probe,512.disconnect = gspca_disconnect,513#ifdef CONFIG_PM514.suspend = gspca_suspend,515.resume = gspca_resume,516#endif517};518519/* -- module insert / remove -- */520static int __init sd_mod_init(void)521{522return usb_register(&sd_driver);523}524static void __exit sd_mod_exit(void)525{526usb_deregister(&sd_driver);527}528529module_init(sd_mod_init);530module_exit(sd_mod_exit);531532533