
//<?php cc flipped_webcam.c && ./a.out
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct v4lcontrol_flags_info {
    unsigned short vendor_id;
    unsigned short product_id;
    unsigned short product_mask;
    /*const */char *dmi_board_vendor;
    /*const */char *dmi_board_name;
    /* We could also use the USB manufacturer and product strings some devices have
       const char *manufacturer;
       const char *product; */
    int flags;
    int default_gamma;
    /* Some seldom used dmi strings (for notebooks with bogus info in the board
       entries, but usefull info elsewhere). We keep this at the end as to not
       polute the initalizers for the normal case. */
    /* System (product) vendor / name */
    const char *dmi_system_vendor;
    const char *dmi_system_name;
    /* Board and System versions */
    const char *dmi_board_version;
    const char *dmi_system_version;
};

/* Controls */
enum {
    V4LCONTROL_WHITEBALANCE,
    V4LCONTROL_HFLIP,
    V4LCONTROL_VFLIP,
    V4LCONTROL_GAMMA,
    /* All fake controls above here are auto enabled when not present in hw */
    V4LCONTROL_AUTO_ENABLE_COUNT,
    V4LCONTROL_AUTOGAIN,
    V4LCONTROL_AUTOGAIN_TARGET,
    V4LCONTROL_COUNT
};


struct v4lcontrol_data {
    int fd;                   /* Device fd */
    int flags;                /* Flags for this device */
    int priv_flags;           /* Internal use only flags */
    int controls;             /* Which controls to use for this device */
    unsigned int *shm_values; /* shared memory control value store */
    unsigned int old_values[V4LCONTROL_COUNT]; /* for controls_changed() */
    /*const */struct v4lcontrol_flags_info/* **/flags_info;
};

static void v4lcontrol_get_dmi_string(const char *string, char *buf, int size)
{
    FILE *f;
    char *s, sysfs_name[512];

    snprintf(sysfs_name, sizeof(sysfs_name),
            "/sys/class/dmi/id/%s", string);
    f = fopen(sysfs_name, "r");
    if (!f) {
        /* Try again with a different sysfs path, not sure if this is needed
           but we used to look under /sys/devices/virtual/dmi/id in older
           libv4l versions, but this did not work with some kernels */
        snprintf(sysfs_name, sizeof(sysfs_name),
                "/sys/devices/virtual/dmi/id/%s", string);
        f = fopen(sysfs_name, "r");
        if (!f) {
            buf[0] = 0;
            return;
        }
    }

    s = fgets(buf, size, f);
    if (s)
        s[strlen(s) - 1] = 0;
    fclose(f);
}

static int v4lcontrol_get_usb_ids(struct v4lcontrol_data *data,
        unsigned short *vendor_id, unsigned short *product_id)
{
    FILE *f;
    int i, minor;
    struct stat st;
    char sysfs_name[512];
    char c, *s, buf[32];

    if (fstat(data->fd, &st) || !S_ISCHR(st.st_mode))
        return 0; /* Should never happen */

    /* <Sigh> find ourselve in sysfs */
    for (i = 0; i < 256; i++) {
        snprintf(sysfs_name, sizeof(sysfs_name),
                "/sys/class/video4linux/video%d/dev", i);
        f = fopen(sysfs_name, "r");
        if (!f)
            continue;

        s = fgets(buf, sizeof(buf), f);
        fclose(f);

        if (s && sscanf(buf, "%*d:%d%c", &minor, &c) == 2 && c == '\n'/* &&
                minor == minor(st.st_rdev)*/)
            break;
    }
    if (i == 256)
        return 0; /* Not found, sysfs not mounted? */

    /* Get vendor and product ID */
    snprintf(sysfs_name, sizeof(sysfs_name),
            "/sys/class/video4linux/video%d/device/modalias", i);
    f = fopen(sysfs_name, "r");
    if (f) {
        s = fgets(buf, sizeof(buf), f);
        fclose(f);

        if (!s || sscanf(s, "usb:v%4hxp%4hx%c", vendor_id, product_id, &c) != 3 ||
                c != 'd')
            return 0; /* Not an USB device */
    } else {
        /* Try again assuming the device link points to the usb
           device instead of the usb interface (bug in older versions
           of gspca) */

        /* Get product ID */
        snprintf(sysfs_name, sizeof(sysfs_name),
                "/sys/class/video4linux/video%d/device/idVendor", i);
        f = fopen(sysfs_name, "r");
        if (!f)
            return 0; /* Not an USB device (or no sysfs) */

        s = fgets(buf, sizeof(buf), f);
        fclose(f);

        if (!s || sscanf(s, "%04hx%c", vendor_id, &c) != 2 || c != '\n')
            return 0; /* Should never happen */

        /* Get product ID */
        snprintf(sysfs_name, sizeof(sysfs_name),
                "/sys/class/video4linux/video%d/device/idProduct", i);
        f = fopen(sysfs_name, "r");
        if (!f)
            return 0; /* Should never happen */

        s = fgets(buf, sizeof(buf), f);
        fclose(f);

        if (!s || sscanf(s, "%04hx%c", product_id, &c) != 2 || c != '\n')
            return 0; /* Should never happen */
    }

    return 1;
}

int main(int argc, char *argv[])
{
    char dmi_board_vendor[512], dmi_board_name[512];

    unsigned short vendor_id = 0;
    unsigned short product_id = 0;
    struct v4lcontrol_data *data = calloc(1, sizeof(struct v4lcontrol_data));

    /* Get DMI board and system strings */
    v4lcontrol_get_dmi_string("board_vendor", dmi_board_vendor,
            sizeof(dmi_board_vendor));
    v4lcontrol_get_dmi_string("board_name", dmi_board_name,
            sizeof(dmi_board_name));

    data->flags_info.dmi_board_name = dmi_board_vendor;
    data->flags_info.dmi_board_name = dmi_board_name;

    /* Get Bus and Device ids */
    int got_usb_ids = v4lcontrol_get_usb_ids(data, &vendor_id, &product_id);

    if (!got_usb_ids) {
        fprintf(stderr, "Sorry, webcamera device not recognised :(");
        exit(-1);
    }

    puts("If Your PC is a Laptop add this two strings to mediat-tv/v4l-utils/lib/libv4lconvert/control/libv4lcontrol.c:");
    printf("        { 0x%4.4x, 0x%4.4x, 0, \"%s\", \"%s\",\n", vendor_id, product_id, dmi_board_vendor, dmi_board_name);
    puts("                V4LCONTROL_HFLIPPED | V4LCONTROL_VFLIPPED },");
    puts("\n");
    puts("Otherwise if Your PC is a Desktop string lines should look like this:");
    printf("        { 0x%4.4x, 0x%4.4x, 0, NULL, NULL,\n", vendor_id, product_id);
    puts("                V4LCONTROL_HFLIPPED | V4LCONTROL_VFLIPPED },");
    puts("\n");
    puts("Rebuild the package and send to v4l maintainers Your camera info.");

    return EXIT_SUCCESS;
}//?>
