V4L/DVB (13265): gspca_mr97310a: Partly back off red gain change for Sakar Digital...
[safe/jmp/linux-2.6] / drivers / media / video / gspca / stk014.c
index d676cd1..4762896 100644 (file)
@@ -23,9 +23,6 @@
 #include "gspca.h"
 #include "jpeg.h"
 
-#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(2, 1, 5)
-static const char version[] = "2.1.5";
-
 MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
 MODULE_DESCRIPTION("Syntek DV4000 (STK014) USB Camera Driver");
 MODULE_LICENSE("GPL");
@@ -38,10 +35,13 @@ struct sd {
        unsigned char contrast;
        unsigned char colors;
        unsigned char lightfreq;
-};
+       u8 quality;
+#define QUALITY_MIN 60
+#define QUALITY_MAX 95
+#define QUALITY_DEF 80
 
-/* global parameters */
-static int sd_quant = 7;               /* <= 4 KO - 7: good (enough!) */
+       u8 *jpeg_hdr;
+};
 
 /* V4L2 controls supported by the driver */
 static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
@@ -112,7 +112,7 @@ static struct ctrl sd_ctrls[] = {
        },
 };
 
-static struct v4l2_pix_format vga_mode[] = {
+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,
@@ -127,7 +127,7 @@ static struct v4l2_pix_format vga_mode[] = {
 
 /* -- read a register -- */
 static int reg_r(struct gspca_dev *gspca_dev,
-                       __u16 index, __u8 *buf)
+                       __u16 index)
 {
        struct usb_device *dev = gspca_dev->dev;
        int ret;
@@ -137,11 +137,13 @@ static int reg_r(struct gspca_dev *gspca_dev,
                        USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                        0x00,
                        index,
-                       buf, 1,
+                       gspca_dev->usb_buf, 1,
                        500);
-       if (ret < 0)
+       if (ret < 0) {
                PDEBUG(D_ERR, "reg_r err %d", ret);
-       return ret;
+               return ret;
+       }
+       return gspca_dev->usb_buf[0];
 }
 
 /* -- write a register -- */
@@ -164,58 +166,55 @@ static int reg_w(struct gspca_dev *gspca_dev,
        return ret;
 }
 
-/* -- get a value -- */
+/* -- get a bulk value (4 bytes) -- */
 static int rcv_val(struct gspca_dev *gspca_dev,
-                       int ads,
-                       int len)
+                       int ads)
 {
        struct usb_device *dev = gspca_dev->dev;
        int alen, ret;
-       unsigned char bulk_buf[4];
 
        reg_w(gspca_dev, 0x634, (ads >> 16) & 0xff);
        reg_w(gspca_dev, 0x635, (ads >> 8) & 0xff);
        reg_w(gspca_dev, 0x636, ads & 0xff);
        reg_w(gspca_dev, 0x637, 0);
-       reg_w(gspca_dev, 0x638, len & 0xff);
-       reg_w(gspca_dev, 0x639, len >> 8);
+       reg_w(gspca_dev, 0x638, 4);     /* len & 0xff */
+       reg_w(gspca_dev, 0x639, 0);     /* len >> 8 */
        reg_w(gspca_dev, 0x63a, 0);
        reg_w(gspca_dev, 0x63b, 0);
        reg_w(gspca_dev, 0x630, 5);
-       if (len > sizeof bulk_buf)
-               return -1;
        ret = usb_bulk_msg(dev,
-                       usb_rcvbulkpipe(dev, 5),
-                       bulk_buf,
-                       len,
+                       usb_rcvbulkpipe(dev, 0x05),
+                       gspca_dev->usb_buf,
+                       4,              /* length */
                        &alen,
-                       500);   /* timeout in milliseconds */
+                       500);           /* timeout in milliseconds */
        return ret;
 }
 
-/* -- send a value -- */
+/* -- send a bulk value -- */
 static int snd_val(struct gspca_dev *gspca_dev,
                        int ads,
                        unsigned int val)
 {
        struct usb_device *dev = gspca_dev->dev;
        int alen, ret;
-       __u8 value, seq;
-       unsigned char bulk_buf[4];
+       __u8 seq = 0;
 
        if (ads == 0x003f08) {
-               ret = reg_r(gspca_dev, 0x0704, &value);
+               ret = reg_r(gspca_dev, 0x0704);
                if (ret < 0)
                        goto ko;
-               ret = reg_r(gspca_dev, 0x0705, &seq);
+               ret = reg_r(gspca_dev, 0x0705);
                if (ret < 0)
                        goto ko;
-               ret = reg_r(gspca_dev, 0x0650, &value);
+               seq = ret;              /* keep the sequence number */
+               ret = reg_r(gspca_dev, 0x0650);
                if (ret < 0)
                        goto ko;
                reg_w(gspca_dev, 0x654, seq);
-       } else
+       } else {
                reg_w(gspca_dev, 0x654, (ads >> 16) & 0xff);
+       }
        reg_w(gspca_dev, 0x655, (ads >> 8) & 0xff);
        reg_w(gspca_dev, 0x656, ads & 0xff);
        reg_w(gspca_dev, 0x657, 0);
@@ -224,13 +223,13 @@ static int snd_val(struct gspca_dev *gspca_dev,
        reg_w(gspca_dev, 0x65a, 0);
        reg_w(gspca_dev, 0x65b, 0);
        reg_w(gspca_dev, 0x650, 5);
-       bulk_buf[0] = (val >> 24) & 0xff;
-       bulk_buf[1] = (val >> 16) & 0xff;
-       bulk_buf[2] = (val >> 8) & 0xff;
-       bulk_buf[3] = val & 0xff;
+       gspca_dev->usb_buf[0] = val >> 24;
+       gspca_dev->usb_buf[1] = val >> 16;
+       gspca_dev->usb_buf[2] = val >> 8;
+       gspca_dev->usb_buf[3] = val;
        ret = usb_bulk_msg(dev,
                        usb_sndbulkpipe(dev, 6),
-                       bulk_buf,
+                       gspca_dev->usb_buf,
                        4,
                        &alen,
                        500);   /* timeout in milliseconds */
@@ -298,43 +297,48 @@ static int sd_config(struct gspca_dev *gspca_dev,
                        const struct usb_device_id *id)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       struct cam *cam = &gspca_dev->cam;
 
-       cam->dev_name = (char *) id->driver_info;
-       cam->epaddr = 0x02;
        gspca_dev->cam.cam_mode = vga_mode;
-       gspca_dev->cam.nmodes = sizeof vga_mode / sizeof vga_mode[0];
+       gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode);
        sd->brightness = BRIGHTNESS_DEF;
        sd->contrast = CONTRAST_DEF;
        sd->colors = COLOR_DEF;
        sd->lightfreq = FREQ_DEF;
+       sd->quality = QUALITY_DEF;
        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)
 {
-       __u8 value;
        int ret;
 
        /* check if the device responds */
        usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1);
-       ret = reg_r(gspca_dev, 0x0740, &value);
+       ret = reg_r(gspca_dev, 0x0740);
        if (ret < 0)
                return ret;
-       if (value != 0xff) {
-               PDEBUG(D_ERR|D_STREAM, "init reg: 0x%02x", value);
+       if (ret != 0xff) {
+               PDEBUG(D_ERR|D_STREAM, "init reg: 0x%02x", ret);
                return -1;
        }
        return 0;
 }
 
 /* -- start the camera -- */
-static void sd_start(struct gspca_dev *gspca_dev)
+static int sd_start(struct gspca_dev *gspca_dev)
 {
-       __u8 dum;
+       struct sd *sd = (struct sd *) gspca_dev;
        int ret, value;
 
+       /* 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,
+                       0x22);          /* JPEG 411 */
+       jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+
        /* work on alternate 1 */
        usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1);
 
@@ -355,11 +359,11 @@ static void sd_start(struct gspca_dev *gspca_dev)
                        gspca_dev->iface, gspca_dev->alt);
                goto out;
        }
-       ret = reg_r(gspca_dev, 0x0630, &dum);
+       ret = reg_r(gspca_dev, 0x0630);
        if (ret < 0)
                goto out;
-       rcv_val(gspca_dev, 0x000020, 4);        /* << (value ff ff ff ff) */
-       ret = reg_r(gspca_dev, 0x0650, &dum);
+       rcv_val(gspca_dev, 0x000020);   /* << (value ff ff ff ff) */
+       ret = reg_r(gspca_dev, 0x0650);
        if (ret < 0)
                goto out;
        snd_val(gspca_dev, 0x000020, 0xffffffff);
@@ -381,22 +385,22 @@ static void sd_start(struct gspca_dev *gspca_dev)
        set_par(gspca_dev, 0x01000000);
        set_par(gspca_dev, 0x01000000);
        PDEBUG(D_STREAM, "camera started alt: 0x%02x", gspca_dev->alt);
-       return;
+       return 0;
 out:
        PDEBUG(D_ERR|D_STREAM, "camera start err %d", ret);
+       return ret;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
 {
        struct usb_device *dev = gspca_dev->dev;
-       __u8 value;
 
        set_par(gspca_dev, 0x02000000);
        set_par(gspca_dev, 0x02000000);
        usb_set_interface(dev, gspca_dev->iface, 1);
-       reg_r(gspca_dev, 0x0630, &value);
-       rcv_val(gspca_dev, 0x000020, 4);        /* << (value ff ff ff ff) */
-       reg_r(gspca_dev, 0x0650, &value);
+       reg_r(gspca_dev, 0x0630);
+       rcv_val(gspca_dev, 0x000020);   /* << (value ff ff ff ff) */
+       reg_r(gspca_dev, 0x0650);
        snd_val(gspca_dev, 0x000020, 0xffffffff);
        reg_w(gspca_dev, 0x0620, 0);
        reg_w(gspca_dev, 0x0630, 0);
@@ -408,10 +412,9 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
 
 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,
@@ -419,6 +422,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        __u8 *data,                     /* isoc packet */
                        int len)                        /* iso packet length */
 {
+       struct sd *sd = (struct sd *) gspca_dev;
        static unsigned char ffd9[] = {0xff, 0xd9};
 
        /* a frame starts with:
@@ -435,14 +439,13 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                                        ffd9, 2);
 
                /* put the JPEG 411 header */
-               jpeg_put_header(gspca_dev, frame, sd_quant, 0x22);
+               gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+                       sd->jpeg_hdr, JPEG_HDR_SZ);
 
                /* beginning of the frame */
 #define STKHDRSZ 12
-               gspca_frame_add(gspca_dev, INTER_PACKET, frame,
-                               data + STKHDRSZ, len - STKHDRSZ);
-#undef STKHDRSZ
-               return;
+               data += STKHDRSZ;
+               len -= STKHDRSZ;
        }
        gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
 }
@@ -537,25 +540,53 @@ static int sd_querymenu(struct gspca_dev *gspca_dev,
        return -EINVAL;
 }
 
+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 struct sd_desc sd_desc = {
+static const struct sd_desc sd_desc = {
        .name = MODULE_NAME,
        .ctrls = sd_ctrls,
-       .nctrls = sizeof sd_ctrls / sizeof sd_ctrls[0],
+       .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,
        .querymenu = sd_querymenu,
+       .get_jcomp = sd_get_jcomp,
+       .set_jcomp = sd_set_jcomp,
 };
 
 /* -- module initialisation -- */
-#define DVNM(name) .driver_info = (kernel_ulong_t) name
-static __devinitdata struct usb_device_id device_table[] = {
-       {USB_DEVICE(0x05e1, 0x0893), DVNM("Syntek DV4000")},
+static const __devinitdata struct usb_device_id device_table[] = {
+       {USB_DEVICE(0x05e1, 0x0893)},
        {}
 };
 MODULE_DEVICE_TABLE(usb, device_table);
@@ -573,14 +604,20 @@ 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;
-       info("v%s registered", version);
+       int ret;
+       ret = usb_register(&sd_driver);
+       if (ret < 0)
+               return ret;
+       info("registered");
        return 0;
 }
 static void __exit sd_mod_exit(void)
@@ -591,6 +628,3 @@ static void __exit sd_mod_exit(void)
 
 module_init(sd_mod_init);
 module_exit(sd_mod_exit);
-
-module_param_named(quant, sd_quant, int, 0644);
-MODULE_PARM_DESC(quant, "Quantization index (0..8)");