V4L/DVB (13422): gspca - ov534: ov772x changes from Richard Kaswy.
[safe/jmp/linux-2.6] / drivers / media / video / gspca / mars.c
index c70ccc8..de769ca 100644 (file)
@@ -24,9 +24,6 @@
 #include "gspca.h"
 #include "jpeg.h"
 
-#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(2, 1, 4)
-static const char version[] = "2.1.4";
-
 MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
 MODULE_DESCRIPTION("GSPCA/Mars USB Camera Driver");
 MODULE_LICENSE("GPL");
@@ -35,79 +32,139 @@ MODULE_LICENSE("GPL");
 struct sd {
        struct gspca_dev gspca_dev;     /* !! must be the first item */
 
-       char qindex;
+       u8 brightness;
+       u8 colors;
+       u8 gamma;
+       u8 sharpness;
+       u8 quality;
+#define QUALITY_MIN 40
+#define QUALITY_MAX 70
+#define QUALITY_DEF 50
+
+       u8 *jpeg_hdr;
 };
 
 /* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
+
 static struct ctrl sd_ctrls[] = {
+       {
+           {
+               .id      = V4L2_CID_BRIGHTNESS,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Brightness",
+               .minimum = 0,
+               .maximum = 30,
+               .step    = 1,
+#define BRIGHTNESS_DEF 15
+               .default_value = BRIGHTNESS_DEF,
+           },
+           .set = sd_setbrightness,
+           .get = sd_getbrightness,
+       },
+       {
+           {
+               .id      = V4L2_CID_SATURATION,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Color",
+               .minimum = 1,
+               .maximum = 255,
+               .step    = 1,
+#define COLOR_DEF 200
+               .default_value = COLOR_DEF,
+           },
+           .set = sd_setcolors,
+           .get = sd_getcolors,
+       },
+       {
+           {
+               .id      = V4L2_CID_GAMMA,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Gamma",
+               .minimum = 0,
+               .maximum = 3,
+               .step    = 1,
+#define GAMMA_DEF 1
+               .default_value = GAMMA_DEF,
+           },
+           .set = sd_setgamma,
+           .get = sd_getgamma,
+       },
+       {
+           {
+               .id      = V4L2_CID_SHARPNESS,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Sharpness",
+               .minimum = 0,
+               .maximum = 2,
+               .step    = 1,
+#define SHARPNESS_DEF 1
+               .default_value = SHARPNESS_DEF,
+           },
+           .set = sd_setsharpness,
+           .get = sd_getsharpness,
+       },
 };
 
-static struct cam_mode vga_mode[] = {
-       {V4L2_PIX_FMT_JPEG, 320, 240, 2},
-       {V4L2_PIX_FMT_JPEG, 640, 480, 1},
+static const struct v4l2_pix_format vga_mode[] = {
+       {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+               .bytesperline = 320,
+               .sizeimage = 320 * 240 * 3 / 8 + 590,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+               .priv = 2},
+       {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+               .bytesperline = 640,
+               .sizeimage = 640 * 480 * 3 / 8 + 590,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+               .priv = 1},
 };
 
-/* MI Register table //elvis */
-enum {
-       REG_HW_MI_0,
-       REG_HW_MI_1,
-       REG_HW_MI_2,
-       REG_HW_MI_3,
-       REG_HW_MI_4,
-       REG_HW_MI_5,
-       REG_HW_MI_6,
-       REG_HW_MI_7,
-       REG_HW_MI_9 = 0x09,
-       REG_HW_MI_B = 0x0B,
-       REG_HW_MI_C,
-       REG_HW_MI_D,
-       REG_HW_MI_1E = 0x1E,
-       REG_HW_MI_20 = 0x20,
-       REG_HW_MI_2B = 0x2B,
-       REG_HW_MI_2C,
-       REG_HW_MI_2D,
-       REG_HW_MI_2E,
-       REG_HW_MI_35 = 0x35,
-       REG_HW_MI_5F = 0x5f,
-       REG_HW_MI_60,
-       REG_HW_MI_61,
-       REG_HW_MI_62,
-       REG_HW_MI_63,
-       REG_HW_MI_64,
-       REG_HW_MI_F1 = 0xf1,
-       ATTR_TOTAL_MI_REG = 242
+static const __u8 mi_data[0x20] = {
+/*      01    02   03     04    05    06    07    08 */
+       0x48, 0x22, 0x01, 0x47, 0x10, 0x00, 0x00, 0x00,
+/*      09    0a   0b     0c    0d    0e    0f    10 */
+       0x00, 0x01, 0x30, 0x01, 0x30, 0x01, 0x30, 0x01,
+/*      11    12   13     14    15    16    17    18 */
+       0x30, 0x00, 0x04, 0x00, 0x06, 0x01, 0xe2, 0x02,
+/*      19    1a   1b     1c    1d    1e    1f    20 */
+       0x82, 0x00, 0x20, 0x17, 0x80, 0x08, 0x0c, 0x00
 };
 
-static int pcam_reg_write(struct usb_device *dev,
-                         __u16 index, __u8 *value, int len)
+/* write <len> bytes from gspca_dev->usb_buf */
+static int reg_w(struct gspca_dev *gspca_dev,
+                int len)
 {
-       int rc;
-
-       rc = usb_control_msg(dev,
-                        usb_sndbulkpipe(dev, 4),
-                        0x12,
-/*             ?? 0xc8 = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_??? !? */
-                        0xc8,
-                        0,             /* value */
-                        index, value, len, 500);
-       if (rc < 0)
-               PDEBUG(D_ERR, "reg write [%02x] error %d", index, rc);
-       return rc;
+       int alen, ret;
+
+       ret = usb_bulk_msg(gspca_dev->dev,
+                       usb_sndbulkpipe(gspca_dev->dev, 4),
+                       gspca_dev->usb_buf,
+                       len,
+                       &alen,
+                       500);   /* timeout in milliseconds */
+       if (ret < 0)
+               PDEBUG(D_ERR, "reg write [%02x] error %d",
+                       gspca_dev->usb_buf[0], ret);
+       return ret;
 }
 
-static void MISensor_BulkWrite(struct usb_device *dev,
-                               unsigned short *pch,
-                               char Address)
+static void mi_w(struct gspca_dev *gspca_dev,
+                u8 addr,
+                u8 value)
 {
-       __u8 data[6];
-
-       data[0] = 0x1f;
-       data[1] = 0;                    /* control byte */
-       data[2] = Address;
-       data[3] = *pch >> 8;            /* high byte */
-       data[4] = *pch;                 /* low byte */
+       gspca_dev->usb_buf[0] = 0x1f;
+       gspca_dev->usb_buf[1] = 0;                      /* control byte */
+       gspca_dev->usb_buf[2] = addr;
+       gspca_dev->usb_buf[3] = value;
 
-       pcam_reg_write(dev, Address, data, 5);
+       reg_w(gspca_dev, 4);
 }
 
 /* this function is called at probe time */
@@ -118,45 +175,45 @@ static int sd_config(struct gspca_dev *gspca_dev,
        struct cam *cam;
 
        cam = &gspca_dev->cam;
-       cam->dev_name = (char *) id->driver_info;
-       cam->epaddr = 0x01;
        cam->cam_mode = vga_mode;
-       cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
-       sd->qindex = 1;                 /* set the quantization table */
+       cam->nmodes = ARRAY_SIZE(vga_mode);
+       sd->brightness = BRIGHTNESS_DEF;
+       sd->colors = COLOR_DEF;
+       sd->gamma = GAMMA_DEF;
+       sd->sharpness = SHARPNESS_DEF;
+       sd->quality = QUALITY_DEF;
+       gspca_dev->nbalt = 9;           /* use the altsetting 08 */
        return 0;
 }
 
-/* this function is called at open time */
-static int sd_open(struct gspca_dev *gspca_dev)
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
 {
        return 0;
 }
 
-static void sd_start(struct gspca_dev *gspca_dev)
+static int sd_start(struct gspca_dev *gspca_dev)
 {
-       struct usb_device *dev = gspca_dev->dev;
+       struct sd *sd = (struct sd *) gspca_dev;
        int err_code;
-       __u8 data[12];
-       __u16 MI_buf[242];
-       int h_size, v_size;
-       int intpipe;
-/*     struct usb_device *dev = pcam->dev; */
-
-       memset(data, 0, sizeof data);
-       memset(MI_buf, 0, sizeof MI_buf);
-
-       PDEBUG(D_STREAM, "camera start, iface %d, alt 8", gspca_dev->iface);
-       if (usb_set_interface(dev, gspca_dev->iface, 8) < 0) {
-               PDEBUG(D_ERR|D_STREAM, "Set packet size: set interface error");
-               return;
-       }
+       u8 *data;
+       int i;
+
+       /* create the JPEG header */
+       sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
+       if (!sd->jpeg_hdr)
+               return -ENOMEM;
+       jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+                       0x21);          /* JPEG 422 */
+       jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+
+       data = gspca_dev->usb_buf;
 
        data[0] = 0x01;         /* address */
        data[1] = 0x01;
-
-       err_code = pcam_reg_write(dev, data[0], data, 2);
+       err_code = reg_w(gspca_dev, 2);
        if (err_code < 0)
-               return;
+               return err_code;
 
        /*
           Initialize the MR97113 chip register
@@ -164,190 +221,107 @@ static void sd_start(struct gspca_dev *gspca_dev)
        data[0] = 0x00;         /* address */
        data[1] = 0x0c | 0x01;  /* reg 0 */
        data[2] = 0x01;         /* reg 1 */
-       h_size = gspca_dev->width;
-       v_size = gspca_dev->height;
-       data[3] = h_size / 8;   /* h_size , reg 2 */
-       data[4] = v_size / 8;   /* v_size , reg 3 */
+       data[3] = gspca_dev->width / 8;         /* h_size , reg 2 */
+       data[4] = gspca_dev->height / 8;        /* v_size , reg 3 */
        data[5] = 0x30;         /* reg 4, MI, PAS5101 :
                                 *      0x30 for 24mhz , 0x28 for 12mhz */
-       data[6] = 4;            /* reg 5, H start */
-       data[7] = 0xc0;         /* reg 6, gamma 1.5 */
-       data[8] = 3;            /* reg 7, V start */
-/*     if(h_size == 320 ) */
+       data[6] = 0x02;         /* reg 5, H start - was 0x04 */
+       data[7] = sd->gamma * 0x40;     /* reg 0x06: gamma */
+       data[8] = 0x01;         /* reg 7, V start - was 0x03 */
+/*     if (h_size == 320 ) */
 /*             data[9]= 0x56;   * reg 8, 24MHz, 2:1 scale down */
 /*     else */
        data[9] = 0x52;         /* reg 8, 24MHz, no scale down */
-       data[10] = 0x5d;        /* reg 9, I2C device address
-                                *      [for PAS5101 (0x40)] [for MI (0x5d)] */
+/*jfm: from win trace*/
+       data[10] = 0x18;
 
-       err_code = pcam_reg_write(dev, data[0], data, 11);
+       err_code = reg_w(gspca_dev, 11);
        if (err_code < 0)
-               return;
+               return err_code;
 
        data[0] = 0x23;         /* address */
        data[1] = 0x09;         /* reg 35, append frame header */
 
-       err_code = pcam_reg_write(dev, data[0], data, 2);
-       if (err_code < 0) {
-               PDEBUG(D_ERR, "Register write failed");
-               return;
-       }
+       err_code = reg_w(gspca_dev, 2);
+       if (err_code < 0)
+               return err_code;
 
-       data[0] = 0x3C;         /* address */
-/*     if (pcam->width == 1280) */
+       data[0] = 0x3c;         /* address */
+/*     if (gspca_dev->width == 1280) */
 /*             data[1] = 200;   * reg 60, pc-cam frame size
                                 *      (unit: 4KB) 800KB */
 /*     else */
        data[1] = 50;           /* 50 reg 60, pc-cam frame size
                                 *      (unit: 4KB) 200KB */
-       err_code = pcam_reg_write(dev, data[0], data, 2);
+       err_code = reg_w(gspca_dev, 2);
        if (err_code < 0)
-               return;
+               return err_code;
 
-       if (0) {                        /* fixed dark-gain */
-               data[1] = 0;            /* reg 94, Y Gain (1.75) */
-               data[2] = 0;            /* reg 95, UV Gain (1.75) */
-               data[3] = 0x3f;         /* reg 96, Y Gain/UV Gain/disable
-                                        *      auto dark-gain */
-               data[4] = 0;            /* reg 97, set fixed dark level */
-               data[5] = 0;            /* reg 98, don't care */
-       } else {                        /* auto dark-gain */
-               data[1] = 0;            /* reg 94, Y Gain (auto) */
-               data[2] = 0;            /* reg 95, UV Gain (1.75) */
-               data[3] = 0x78;         /* reg 96, Y Gain/UV Gain/disable
-                                        *      auto dark-gain */
-               switch (gspca_dev->width) {
-/*             case 1280: */
-/*                     data[4] = 154;
-                                * reg 97, %3 shadow point (unit: 256 pixel) */
-/*                     data[5] = 51;
-                                * reg 98, %1 highlight point
-                                *      (uint: 256 pixel) */
-/*                     break; */
-               default:
-/*             case 640: */
-                       data[4] = 36;   /* reg 97, %3 shadow point
-                                        *      (unit: 256 pixel) */
-                       data[5] = 12;   /* reg 98, %1 highlight point
-                                        *      (uint: 256 pixel) */
-                       break;
-               case 320:
-                       data[4] = 9;    /* reg 97, %3 shadow point
-                                        *      (unit: 256 pixel) */
-                       data[5] = 3;    /* reg 98, %1 highlight point
-                                        *      (uint: 256 pixel) */
-                       break;
-               }
-       }
        /* auto dark-gain */
        data[0] = 0x5e;         /* address */
-
-       err_code = pcam_reg_write(dev, data[0], data, 6);
+       data[1] = 0;            /* reg 94, Y Gain (auto) */
+/*jfm: from win trace*/
+                               /* reg 0x5f/0x60 (LE) = saturation */
+                               /* h (60): xxxx x100
+                                * l (5f): xxxx x000 */
+       data[2] = sd->colors << 3;
+       data[3] = ((sd->colors >> 2) & 0xf8) | 0x04;
+       data[4] = sd->brightness; /* reg 0x61 = brightness */
+       data[5] = 0x00;
+
+       err_code = reg_w(gspca_dev, 6);
        if (err_code < 0)
-               return;
+               return err_code;
 
        data[0] = 0x67;
-       data[1] = 0x13;         /* reg 103, first pixel B, disable sharpness */
-       err_code = pcam_reg_write(dev, data[0], data, 2);
+/*jfm: from win trace*/
+       data[1] = sd->sharpness * 4 + 3;
+       data[2] = 0x14;
+       err_code = reg_w(gspca_dev, 3);
        if (err_code < 0)
-               return;
+               return err_code;
 
-       /*
-        * initialize the value of MI sensor...
-        */
-       MI_buf[REG_HW_MI_1] = 0x000a;
-       MI_buf[REG_HW_MI_2] = 0x000c;
-       MI_buf[REG_HW_MI_3] = 0x0405;
-       MI_buf[REG_HW_MI_4] = 0x0507;
-       /* mi_Attr_Reg_[REG_HW_MI_5]     = 0x01ff;//13 */
-       MI_buf[REG_HW_MI_5] = 0x0013;   /* 13 */
-       MI_buf[REG_HW_MI_6] = 0x001f;   /* vertical blanking */
-       /* mi_Attr_Reg_[REG_HW_MI_6]     = 0x0400;  // vertical blanking */
-       MI_buf[REG_HW_MI_7] = 0x0002;
-       /* mi_Attr_Reg_[REG_HW_MI_9]     = 0x015f; */
-       /* mi_Attr_Reg_[REG_HW_MI_9]     = 0x030f; */
-       MI_buf[REG_HW_MI_9] = 0x0374;
-       MI_buf[REG_HW_MI_B] = 0x0000;
-       MI_buf[REG_HW_MI_C] = 0x0000;
-       MI_buf[REG_HW_MI_D] = 0x0000;
-       MI_buf[REG_HW_MI_1E] = 0x8000;
-/* mi_Attr_Reg_[REG_HW_MI_20]    = 0x1104; */
-       MI_buf[REG_HW_MI_20] = 0x1104;  /* 0x111c; */
-       MI_buf[REG_HW_MI_2B] = 0x0008;
-/* mi_Attr_Reg_[REG_HW_MI_2C]    = 0x000f; */
-       MI_buf[REG_HW_MI_2C] = 0x001f;  /* lita suggest */
-       MI_buf[REG_HW_MI_2D] = 0x0008;
-       MI_buf[REG_HW_MI_2E] = 0x0008;
-       MI_buf[REG_HW_MI_35] = 0x0051;
-       MI_buf[REG_HW_MI_5F] = 0x0904;  /* fail to write */
-       MI_buf[REG_HW_MI_60] = 0x0000;
-       MI_buf[REG_HW_MI_61] = 0x0000;
-       MI_buf[REG_HW_MI_62] = 0x0498;
-       MI_buf[REG_HW_MI_63] = 0x0000;
-       MI_buf[REG_HW_MI_64] = 0x0000;
-       MI_buf[REG_HW_MI_F1] = 0x0001;
-       /* changing while setting up the different value of dx/dy */
-
-       if (gspca_dev->width != 1280) {
-               MI_buf[0x01] = 0x010a;
-               MI_buf[0x02] = 0x014c;
-               MI_buf[0x03] = 0x01e5;
-               MI_buf[0x04] = 0x0287;
-       }
-       MI_buf[0x20] = 0x1104;
-
-       MISensor_BulkWrite(dev, MI_buf + 1, 1);
-       MISensor_BulkWrite(dev, MI_buf + 2, 2);
-       MISensor_BulkWrite(dev, MI_buf + 3, 3);
-       MISensor_BulkWrite(dev, MI_buf + 4, 4);
-       MISensor_BulkWrite(dev, MI_buf + 5, 5);
-       MISensor_BulkWrite(dev, MI_buf + 6, 6);
-       MISensor_BulkWrite(dev, MI_buf + 7, 7);
-       MISensor_BulkWrite(dev, MI_buf + 9, 9);
-       MISensor_BulkWrite(dev, MI_buf + 0x0b, 0x0b);
-       MISensor_BulkWrite(dev, MI_buf + 0x0c, 0x0c);
-       MISensor_BulkWrite(dev, MI_buf + 0x0d, 0x0d);
-       MISensor_BulkWrite(dev, MI_buf + 0x1e, 0x1e);
-       MISensor_BulkWrite(dev, MI_buf + 0x20, 0x20);
-       MISensor_BulkWrite(dev, MI_buf + 0x2b, 0x2b);
-       MISensor_BulkWrite(dev, MI_buf + 0x2c, 0x2c);
-       MISensor_BulkWrite(dev, MI_buf + 0x2d, 0x2d);
-       MISensor_BulkWrite(dev, MI_buf + 0x2e, 0x2e);
-       MISensor_BulkWrite(dev, MI_buf + 0x35, 0x35);
-       MISensor_BulkWrite(dev, MI_buf + 0x5f, 0x5f);
-       MISensor_BulkWrite(dev, MI_buf + 0x60, 0x60);
-       MISensor_BulkWrite(dev, MI_buf + 0x61, 0x61);
-       MISensor_BulkWrite(dev, MI_buf + 0x62, 0x62);
-       MISensor_BulkWrite(dev, MI_buf + 0x63, 0x63);
-       MISensor_BulkWrite(dev, MI_buf + 0x64, 0x64);
-       MISensor_BulkWrite(dev, MI_buf + 0xf1, 0xf1);
-
-       intpipe = usb_sndintpipe(dev, 0);
-       err_code = usb_clear_halt(dev, intpipe);
+       data[0] = 0x69;
+       data[1] = 0x2f;
+       data[2] = 0x28;
+       data[3] = 0x42;
+       err_code = reg_w(gspca_dev, 4);
+       if (err_code < 0)
+               return err_code;
+
+       data[0] = 0x63;
+       data[1] = 0x07;
+       err_code = reg_w(gspca_dev, 2);
+/*jfm: win trace - many writes here to reg 0x64*/
+       if (err_code < 0)
+               return err_code;
+
+       /* initialize the MI sensor */
+       for (i = 0; i < sizeof mi_data; i++)
+               mi_w(gspca_dev, i + 1, mi_data[i]);
 
        data[0] = 0x00;
        data[1] = 0x4d;         /* ISOC transfering enable... */
-       pcam_reg_write(dev, data[0], data, 2);
+       reg_w(gspca_dev, 2);
+       return 0;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
 {
        int result;
-       __u8 data[2];
 
-       data[0] = 1;
-       data[1] = 0;
-       result = pcam_reg_write(gspca_dev->dev, data[0], data, 2);
+       gspca_dev->usb_buf[0] = 1;
+       gspca_dev->usb_buf[1] = 0;
+       result = reg_w(gspca_dev, 2);
        if (result < 0)
                PDEBUG(D_ERR, "Camera Stop failed");
 }
 
 static void sd_stop0(struct gspca_dev *gspca_dev)
 {
-}
+       struct sd *sd = (struct sd *) gspca_dev;
 
-static void sd_close(struct gspca_dev *gspca_dev)
-{
+       kfree(sd->jpeg_hdr);
 }
 
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
@@ -372,16 +346,16 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                            || data[5 + p] == 0x65
                            || data[5 + p] == 0x66
                            || data[5 + p] == 0x67) {
-                               PDEBUG(D_PACK, "sof offset: %d leng: %d",
+                               PDEBUG(D_PACK, "sof offset: %d len: %d",
                                        p, len);
                                frame = gspca_frame_add(gspca_dev, LAST_PACKET,
-                                                       frame, data, 0);
+                                                       frame, data, p);
 
                                /* put the JPEG header */
-                               jpeg_put_header(gspca_dev, frame,
-                                               sd->qindex, 0x21);
-                               data += 16;
-                               len -= 16;
+                               gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+                                       sd->jpeg_hdr, JPEG_HDR_SZ);
+                               data += p + 16;
+                               len -= p + 16;
                                break;
                        }
                }
@@ -389,24 +363,139 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
        gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
 }
 
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->brightness = val;
+       if (gspca_dev->streaming) {
+               gspca_dev->usb_buf[0] = 0x61;
+               gspca_dev->usb_buf[1] = val;
+               reg_w(gspca_dev, 2);
+       }
+       return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->brightness;
+       return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->colors = val;
+       if (gspca_dev->streaming) {
+
+               /* see sd_start */
+               gspca_dev->usb_buf[0] = 0x5f;
+               gspca_dev->usb_buf[1] = sd->colors << 3;
+               gspca_dev->usb_buf[2] = ((sd->colors >> 2) & 0xf8) | 0x04;
+               reg_w(gspca_dev, 3);
+       }
+       return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->colors;
+       return 0;
+}
+
+static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->gamma = val;
+       if (gspca_dev->streaming) {
+               gspca_dev->usb_buf[0] = 0x06;
+               gspca_dev->usb_buf[1] = val * 0x40;
+               reg_w(gspca_dev, 2);
+       }
+       return 0;
+}
+
+static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->gamma;
+       return 0;
+}
+
+static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->sharpness = val;
+       if (gspca_dev->streaming) {
+               gspca_dev->usb_buf[0] = 0x67;
+               gspca_dev->usb_buf[1] = val * 4 + 3;
+               reg_w(gspca_dev, 2);
+       }
+       return 0;
+}
+
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->sharpness;
+       return 0;
+}
+
+static int sd_set_jcomp(struct gspca_dev *gspca_dev,
+                       struct v4l2_jpegcompression *jcomp)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       if (jcomp->quality < QUALITY_MIN)
+               sd->quality = QUALITY_MIN;
+       else if (jcomp->quality > QUALITY_MAX)
+               sd->quality = QUALITY_MAX;
+       else
+               sd->quality = jcomp->quality;
+       if (gspca_dev->streaming)
+               jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+       return 0;
+}
+
+static int sd_get_jcomp(struct gspca_dev *gspca_dev,
+                       struct v4l2_jpegcompression *jcomp)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       memset(jcomp, 0, sizeof *jcomp);
+       jcomp->quality = sd->quality;
+       jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
+                       | V4L2_JPEG_MARKER_DQT;
+       return 0;
+}
+
 /* sub-driver description */
 static const struct sd_desc sd_desc = {
        .name = MODULE_NAME,
        .ctrls = sd_ctrls,
        .nctrls = ARRAY_SIZE(sd_ctrls),
        .config = sd_config,
-       .open = sd_open,
+       .init = sd_init,
        .start = sd_start,
        .stopN = sd_stopN,
        .stop0 = sd_stop0,
-       .close = sd_close,
        .pkt_scan = sd_pkt_scan,
+       .get_jcomp = sd_get_jcomp,
+       .set_jcomp = sd_set_jcomp,
 };
 
 /* -- module initialisation -- */
-#define DVNM(name) .driver_info = (kernel_ulong_t) name
 static const __devinitdata struct usb_device_id device_table[] = {
-       {USB_DEVICE(0x093a, 0x050f), DVNM("Mars-Semi Pc-Camera")},
+       {USB_DEVICE(0x093a, 0x050f)},
        {}
 };
 MODULE_DEVICE_TABLE(usb, device_table);
@@ -424,14 +513,21 @@ static struct usb_driver sd_driver = {
        .id_table = device_table,
        .probe = sd_probe,
        .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+       .suspend = gspca_suspend,
+       .resume = gspca_resume,
+#endif
 };
 
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       if (usb_register(&sd_driver) < 0)
-               return -1;
-       PDEBUG(D_PROBE, "v%s registered", version);
+       int ret;
+
+       ret = usb_register(&sd_driver);
+       if (ret < 0)
+               return ret;
+       PDEBUG(D_PROBE, "registered");
        return 0;
 }
 static void __exit sd_mod_exit(void)