Path: blob/master/drivers/media/video/gspca/stv0680.c
17633 views
/*1* STV0680 USB Camera Driver2*3* Copyright (C) 2009 Hans de Goede <[email protected]>4*5* This module is adapted from the in kernel v4l1 stv680 driver:6*7* STV0680 USB Camera Driver, by Kevin Sisson ([email protected])8*9* Thanks to STMicroelectronics for information on the usb commands, and10* to Steve Miller at STM for his help and encouragement while I was11* writing this driver.12*13* This program is free software; you can redistribute it and/or modify14* it under the terms of the GNU General Public License as published by15* the Free Software Foundation; either version 2 of the License, or16* (at your option) any later version.17*18* This program is distributed in the hope that it will be useful,19* but WITHOUT ANY WARRANTY; without even the implied warranty of20* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the21* GNU General Public License for more details.22*23* You should have received a copy of the GNU General Public License24* along with this program; if not, write to the Free Software25* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA26*27*/2829#define MODULE_NAME "stv0680"3031#include "gspca.h"3233MODULE_AUTHOR("Hans de Goede <[email protected]>");34MODULE_DESCRIPTION("STV0680 USB Camera Driver");35MODULE_LICENSE("GPL");3637/* specific webcam descriptor */38struct sd {39struct gspca_dev gspca_dev; /* !! must be the first item */40struct v4l2_pix_format mode;41u8 orig_mode;42u8 video_mode;43u8 current_mode;44};4546/* V4L2 controls supported by the driver */47static const struct ctrl sd_ctrls[] = {48};4950static int stv_sndctrl(struct gspca_dev *gspca_dev, int set, u8 req, u16 val,51int size)52{53int ret = -1;54u8 req_type = 0;55unsigned int pipe = 0;5657switch (set) {58case 0: /* 0xc1 */59req_type = USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT;60pipe = usb_rcvctrlpipe(gspca_dev->dev, 0);61break;62case 1: /* 0x41 */63req_type = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT;64pipe = usb_sndctrlpipe(gspca_dev->dev, 0);65break;66case 2: /* 0x80 */67req_type = USB_DIR_IN | USB_RECIP_DEVICE;68pipe = usb_rcvctrlpipe(gspca_dev->dev, 0);69break;70case 3: /* 0x40 */71req_type = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE;72pipe = usb_sndctrlpipe(gspca_dev->dev, 0);73break;74}7576ret = usb_control_msg(gspca_dev->dev, pipe,77req, req_type,78val, 0, gspca_dev->usb_buf, size, 500);7980if ((ret < 0) && (req != 0x0a))81err("usb_control_msg error %i, request = 0x%x, error = %i",82set, req, ret);8384return ret;85}8687static int stv0680_handle_error(struct gspca_dev *gspca_dev, int ret)88{89stv_sndctrl(gspca_dev, 0, 0x80, 0, 0x02); /* Get Last Error */90PDEBUG(D_ERR, "last error: %i, command = 0x%x",91gspca_dev->usb_buf[0], gspca_dev->usb_buf[1]);92return ret;93}9495static int stv0680_get_video_mode(struct gspca_dev *gspca_dev)96{97/* Note not sure if this init of usb_buf is really necessary */98memset(gspca_dev->usb_buf, 0, 8);99gspca_dev->usb_buf[0] = 0x0f;100101if (stv_sndctrl(gspca_dev, 0, 0x87, 0, 0x08) != 0x08) {102PDEBUG(D_ERR, "Get_Camera_Mode failed");103return stv0680_handle_error(gspca_dev, -EIO);104}105106return gspca_dev->usb_buf[0]; /* 01 = VGA, 03 = QVGA, 00 = CIF */107}108109static int stv0680_set_video_mode(struct gspca_dev *gspca_dev, u8 mode)110{111struct sd *sd = (struct sd *) gspca_dev;112113if (sd->current_mode == mode)114return 0;115116memset(gspca_dev->usb_buf, 0, 8);117gspca_dev->usb_buf[0] = mode;118119if (stv_sndctrl(gspca_dev, 3, 0x07, 0x0100, 0x08) != 0x08) {120PDEBUG(D_ERR, "Set_Camera_Mode failed");121return stv0680_handle_error(gspca_dev, -EIO);122}123124/* Verify we got what we've asked for */125if (stv0680_get_video_mode(gspca_dev) != mode) {126PDEBUG(D_ERR, "Error setting camera video mode!");127return -EIO;128}129130sd->current_mode = mode;131132return 0;133}134135/* this function is called at probe time */136static int sd_config(struct gspca_dev *gspca_dev,137const struct usb_device_id *id)138{139int ret;140struct sd *sd = (struct sd *) gspca_dev;141struct cam *cam = &gspca_dev->cam;142143/* Give the camera some time to settle, otherwise initalization will144fail on hotplug, and yes it really needs a full second. */145msleep(1000);146147/* ping camera to be sure STV0680 is present */148if (stv_sndctrl(gspca_dev, 0, 0x88, 0x5678, 0x02) != 0x02 ||149gspca_dev->usb_buf[0] != 0x56 || gspca_dev->usb_buf[1] != 0x78) {150PDEBUG(D_ERR, "STV(e): camera ping failed!!");151return stv0680_handle_error(gspca_dev, -ENODEV);152}153154/* get camera descriptor */155if (stv_sndctrl(gspca_dev, 2, 0x06, 0x0200, 0x09) != 0x09)156return stv0680_handle_error(gspca_dev, -ENODEV);157158if (stv_sndctrl(gspca_dev, 2, 0x06, 0x0200, 0x22) != 0x22 ||159gspca_dev->usb_buf[7] != 0xa0 || gspca_dev->usb_buf[8] != 0x23) {160PDEBUG(D_ERR, "Could not get descriptor 0200.");161return stv0680_handle_error(gspca_dev, -ENODEV);162}163if (stv_sndctrl(gspca_dev, 0, 0x8a, 0, 0x02) != 0x02)164return stv0680_handle_error(gspca_dev, -ENODEV);165if (stv_sndctrl(gspca_dev, 0, 0x8b, 0, 0x24) != 0x24)166return stv0680_handle_error(gspca_dev, -ENODEV);167if (stv_sndctrl(gspca_dev, 0, 0x85, 0, 0x10) != 0x10)168return stv0680_handle_error(gspca_dev, -ENODEV);169170if (!(gspca_dev->usb_buf[7] & 0x09)) {171PDEBUG(D_ERR, "Camera supports neither CIF nor QVGA mode");172return -ENODEV;173}174if (gspca_dev->usb_buf[7] & 0x01)175PDEBUG(D_PROBE, "Camera supports CIF mode");176if (gspca_dev->usb_buf[7] & 0x02)177PDEBUG(D_PROBE, "Camera supports VGA mode");178if (gspca_dev->usb_buf[7] & 0x04)179PDEBUG(D_PROBE, "Camera supports QCIF mode");180if (gspca_dev->usb_buf[7] & 0x08)181PDEBUG(D_PROBE, "Camera supports QVGA mode");182183if (gspca_dev->usb_buf[7] & 0x01)184sd->video_mode = 0x00; /* CIF */185else186sd->video_mode = 0x03; /* QVGA */187188/* FW rev, ASIC rev, sensor ID */189PDEBUG(D_PROBE, "Firmware rev is %i.%i",190gspca_dev->usb_buf[0], gspca_dev->usb_buf[1]);191PDEBUG(D_PROBE, "ASIC rev is %i.%i",192gspca_dev->usb_buf[2], gspca_dev->usb_buf[3]);193PDEBUG(D_PROBE, "Sensor ID is %i",194(gspca_dev->usb_buf[4]*16) + (gspca_dev->usb_buf[5]>>4));195196197ret = stv0680_get_video_mode(gspca_dev);198if (ret < 0)199return ret;200sd->current_mode = sd->orig_mode = ret;201202ret = stv0680_set_video_mode(gspca_dev, sd->video_mode);203if (ret < 0)204return ret;205206/* Get mode details */207if (stv_sndctrl(gspca_dev, 0, 0x8f, 0, 0x10) != 0x10)208return stv0680_handle_error(gspca_dev, -EIO);209210cam->bulk = 1;211cam->bulk_nurbs = 1; /* The cam cannot handle more */212cam->bulk_size = (gspca_dev->usb_buf[0] << 24) |213(gspca_dev->usb_buf[1] << 16) |214(gspca_dev->usb_buf[2] << 8) |215(gspca_dev->usb_buf[3]);216sd->mode.width = (gspca_dev->usb_buf[4] << 8) |217(gspca_dev->usb_buf[5]); /* 322, 356, 644 */218sd->mode.height = (gspca_dev->usb_buf[6] << 8) |219(gspca_dev->usb_buf[7]); /* 242, 292, 484 */220sd->mode.pixelformat = V4L2_PIX_FMT_STV0680;221sd->mode.field = V4L2_FIELD_NONE;222sd->mode.bytesperline = sd->mode.width;223sd->mode.sizeimage = cam->bulk_size;224sd->mode.colorspace = V4L2_COLORSPACE_SRGB;225226/* origGain = gspca_dev->usb_buf[12]; */227228cam->cam_mode = &sd->mode;229cam->nmodes = 1;230231232ret = stv0680_set_video_mode(gspca_dev, sd->orig_mode);233if (ret < 0)234return ret;235236if (stv_sndctrl(gspca_dev, 2, 0x06, 0x0100, 0x12) != 0x12 ||237gspca_dev->usb_buf[8] != 0x53 || gspca_dev->usb_buf[9] != 0x05) {238err("Could not get descriptor 0100.");239return stv0680_handle_error(gspca_dev, -EIO);240}241242return 0;243}244245/* this function is called at probe and resume time */246static int sd_init(struct gspca_dev *gspca_dev)247{248return 0;249}250251/* -- start the camera -- */252static int sd_start(struct gspca_dev *gspca_dev)253{254int ret;255struct sd *sd = (struct sd *) gspca_dev;256257ret = stv0680_set_video_mode(gspca_dev, sd->video_mode);258if (ret < 0)259return ret;260261if (stv_sndctrl(gspca_dev, 0, 0x85, 0, 0x10) != 0x10)262return stv0680_handle_error(gspca_dev, -EIO);263264/* Start stream at:2650x0000 = CIF (352x288)2660x0100 = VGA (640x480)2670x0300 = QVGA (320x240) */268if (stv_sndctrl(gspca_dev, 1, 0x09, sd->video_mode << 8, 0x0) != 0x0)269return stv0680_handle_error(gspca_dev, -EIO);270271return 0;272}273274static void sd_stopN(struct gspca_dev *gspca_dev)275{276/* This is a high priority command; it stops all lower order cmds */277if (stv_sndctrl(gspca_dev, 1, 0x04, 0x0000, 0x0) != 0x0)278stv0680_handle_error(gspca_dev, -EIO);279}280281static void sd_stop0(struct gspca_dev *gspca_dev)282{283struct sd *sd = (struct sd *) gspca_dev;284285if (!sd->gspca_dev.present)286return;287288stv0680_set_video_mode(gspca_dev, sd->orig_mode);289}290291static void sd_pkt_scan(struct gspca_dev *gspca_dev,292u8 *data,293int len)294{295struct sd *sd = (struct sd *) gspca_dev;296297/* Every now and then the camera sends a 16 byte packet, no idea298what it contains, but it is not image data, when this299happens the frame received before this packet is corrupt,300so discard it. */301if (len != sd->mode.sizeimage) {302gspca_dev->last_packet_type = DISCARD_PACKET;303return;304}305306/* Finish the previous frame, we do this upon reception of the next307packet, even though it is already complete so that the strange 16308byte packets send after a corrupt frame can discard it. */309gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);310311/* Store the just received frame */312gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);313}314315/* sub-driver description */316static const struct sd_desc sd_desc = {317.name = MODULE_NAME,318.ctrls = sd_ctrls,319.nctrls = ARRAY_SIZE(sd_ctrls),320.config = sd_config,321.init = sd_init,322.start = sd_start,323.stopN = sd_stopN,324.stop0 = sd_stop0,325.pkt_scan = sd_pkt_scan,326};327328/* -- module initialisation -- */329static const struct usb_device_id device_table[] = {330{USB_DEVICE(0x0553, 0x0202)},331{USB_DEVICE(0x041e, 0x4007)},332{}333};334MODULE_DEVICE_TABLE(usb, device_table);335336/* -- device connect -- */337static int sd_probe(struct usb_interface *intf,338const struct usb_device_id *id)339{340return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),341THIS_MODULE);342}343344static struct usb_driver sd_driver = {345.name = MODULE_NAME,346.id_table = device_table,347.probe = sd_probe,348.disconnect = gspca_disconnect,349#ifdef CONFIG_PM350.suspend = gspca_suspend,351.resume = gspca_resume,352#endif353};354355/* -- module insert / remove -- */356static int __init sd_mod_init(void)357{358return usb_register(&sd_driver);359}360static void __exit sd_mod_exit(void)361{362usb_deregister(&sd_driver);363}364365module_init(sd_mod_init);366module_exit(sd_mod_exit);367368369