194 lines
6.2 KiB
C
194 lines
6.2 KiB
C
|
|
//<?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;
|
|
}//?>
|