V4L/DVB: gspca - sn9c20x: Add upside down detection
authorBrian Johnson <brijohn@gmail.com>
Tue, 16 Mar 2010 16:58:27 +0000 (13:58 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Tue, 18 May 2010 03:50:08 +0000 (00:50 -0300)
Add support for detecting webcams that are mounted
upside down in laptops. Currently the only two known
are two MSI modesl using the 0c45:624f.

Signed-off-by: Brian Johnson <brijohn@gmail.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/video/gspca/sn9c20x.c

index 825d5b8..06c75db 100644 (file)
@@ -27,6 +27,7 @@
 #include "jpeg.h"
 
 #include <media/v4l2-chip-ident.h>
+#include <linux/dmi.h>
 
 MODULE_AUTHOR("Brian Johnson <brijohn@gmail.com>, "
                "microdia project <microdia@googlegroups.com>");
@@ -55,6 +56,7 @@ MODULE_LICENSE("GPL");
 /* camera flags */
 #define HAS_BUTTON     0x1
 #define LED_REVERSE    0x2 /* some cameras unset gpio to turn on leds */
+#define FLIP_DETECT    0x4
 
 /* specific webcam descriptor */
 struct sd {
@@ -127,6 +129,25 @@ static int sd_getexposure(struct gspca_dev *gspca_dev, s32 *val);
 static int sd_setautoexposure(struct gspca_dev *gspca_dev, s32 val);
 static int sd_getautoexposure(struct gspca_dev *gspca_dev, s32 *val);
 
+static const struct dmi_system_id flip_dmi_table[] = {
+       {
+               .ident = "MSI MS-1034",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "MICRO-STAR INT'L CO.,LTD."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MS-1034"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "0341")
+               }
+       },
+       {
+               .ident = "MSI MS-1632",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "MSI"),
+                       DMI_MATCH(DMI_BOARD_NAME, "MS-1632")
+               }
+       },
+       {}
+};
+
 static const struct ctrl sd_ctrls[] = {
        {
 #define BRIGHTNESS_IDX 0
@@ -1496,17 +1517,26 @@ static int set_redblue(struct gspca_dev *gspca_dev)
 
 static int set_hvflip(struct gspca_dev *gspca_dev)
 {
-       u8 value, tslb;
+       u8 value, tslb, hflip, vflip;
        u16 value2;
        struct sd *sd = (struct sd *) gspca_dev;
+
+       if ((sd->flags & FLIP_DETECT) && dmi_check_system(flip_dmi_table)) {
+               hflip = !sd->hflip;
+               vflip = !sd->vflip;
+       } else {
+               hflip = sd->hflip;
+               vflip = sd->vflip;
+       }
+
        switch (sd->sensor) {
        case SENSOR_OV9650:
                i2c_r1(gspca_dev, 0x1e, &value);
                value &= ~0x30;
                tslb = 0x01;
-               if (sd->hflip)
+               if (hflip)
                        value |= 0x20;
-               if (sd->vflip) {
+               if (vflip) {
                        value |= 0x10;
                        tslb = 0x49;
                }
@@ -1517,9 +1547,9 @@ static int set_hvflip(struct gspca_dev *gspca_dev)
        case SENSOR_MT9V011:
                i2c_r2(gspca_dev, 0x20, &value2);
                value2 &= ~0xc0a0;
-               if (sd->hflip)
+               if (hflip)
                        value2 |= 0x8080;
-               if (sd->vflip)
+               if (vflip)
                        value2 |= 0x4020;
                i2c_w2(gspca_dev, 0x20, value2);
                break;
@@ -1527,18 +1557,18 @@ static int set_hvflip(struct gspca_dev *gspca_dev)
        case SENSOR_MT9V112:
                i2c_r2(gspca_dev, 0x20, &value2);
                value2 &= ~0x0003;
-               if (sd->hflip)
+               if (hflip)
                        value2 |= 0x0002;
-               if (sd->vflip)
+               if (vflip)
                        value2 |= 0x0001;
                i2c_w2(gspca_dev, 0x20, value2);
                break;
        case SENSOR_HV7131R:
                i2c_r1(gspca_dev, 0x01, &value);
                value &= ~0x03;
-               if (sd->vflip)
+               if (vflip)
                        value |= 0x01;
-               if (sd->hflip)
+               if (hflip)
                        value |= 0x02;
                i2c_w1(gspca_dev, 0x01, value);
                break;
@@ -2371,7 +2401,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
        {USB_DEVICE(0x0c45, 0x6248), SN9C20X(OV9655, 0x30, 0)},
        {USB_DEVICE(0x0c45, 0x624e), SN9C20X(SOI968, 0x30,
                                             (HAS_BUTTON | LED_REVERSE))},
-       {USB_DEVICE(0x0c45, 0x624f), SN9C20X(OV9650, 0x30, 0)},
+       {USB_DEVICE(0x0c45, 0x624f), SN9C20X(OV9650, 0x30, FLIP_DETECT)},
        {USB_DEVICE(0x0c45, 0x6251), SN9C20X(OV9650, 0x30, 0)},
        {USB_DEVICE(0x0c45, 0x6253), SN9C20X(OV9650, 0x30, 0)},
        {USB_DEVICE(0x0c45, 0x6260), SN9C20X(OV7670, 0x21, 0)},