summaryrefslogtreecommitdiff
path: root/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c
diff options
context:
space:
mode:
Diffstat (limited to 'v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c')
-rw-r--r--v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c252
1 files changed, 214 insertions, 38 deletions
diff --git a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c
index 4e600351b..243f35dae 100644
--- a/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c
+++ b/v4l2-apps/libv4l/libv4lconvert/control/libv4lcontrol.c
@@ -3,6 +3,7 @@
# (C) 2008-2009 Sjoerd Piepenbrink <need4weed@gmail.com>
# (C) 2008-2009 Radjnies Bhansingh <radjnies@gmail.com>
# (C) 2008-2009 Hans de Goede <hdegoede@redhat.com>
+# (C) 2009 Paul Sladen <ubuntu@paul.sladen.org>
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
@@ -28,6 +29,7 @@
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
+#include <pwd.h>
#include "libv4lcontrol.h"
#include "libv4lcontrol-priv.h"
#include "../libv4lsyscall-priv.h"
@@ -57,9 +59,111 @@ static const struct v4lcontrol_flags_info v4lcontrol_flags[] = {
/* Genius E-M 112 (also want whitebalance by default) */
{ 0x093a, 0x2476, 0, NULL, NULL,
V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED|V4LCONTROL_WANTS_WB, 1500 },
- /* Asus N50Vn laptop */
+ /* Laptops */
+ { 0x04f2, 0xb012, 0, "ASUSTeK Computer Inc. ", "F7L ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb012, 0, "ASUSTeK Computer Inc. ", "W7Sg ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb012, 0, "ASUSTeK Computer Inc. ", "F7SR ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb012, 0, "ASUSTeK Computer Inc. ", "G50VT ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb012, 0, "ASUSTeK Computer Inc. ", "W7S ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb012, 0, "ASUSTeK Computer Inc. ", "X55SR ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb012, 0, "ASUSTeK Computer Inc. ", "X55SV ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ /* note different white space: http://launchpad.net/bugs/413752 */
+ { 0x04f2, 0xb012, 0, "ASUSTeK Computer Inc. ", "X71SL ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ /* These 3 PACKARD BELL's seem to be Asus notebook in disguise */
+ { 0x04f2, 0xb012, 0, "Packard Bell BV", "T32A ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb012, 0, "PACKARD BELL BV ", "EasyNote_BG45",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb012, 0, "PACKARD BELL BV ", "EasyNote_BG46",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb036, 0, "ASUSTeK Computer Inc. ", "U6S ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb036, 0, "ASUSTeK Computer Inc. ", "U6V ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb071, 0, "ASUSTeK Computer Inc. ", "K40IJ ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb071, 0, "ASUSTeK Computer Inc. ", "K50IJ ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb071, 0, "ASUSTeK Computer Inc. ", "K50IN ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb071, 0, "ASUSTeK Computer Inc. ", "K70AB ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb071, 0, "ASUSTeK Computer Inc. ", "K70IO ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb071, 0, "ASUSTeK Computer Inc. ", "N10J ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb071, 0, "ASUSTeK Computer Inc. ", "N20A ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ /* Note no whitespace padding for these 2 models, this is not a typo */
+ { 0x04f2, 0xb071, 0, "ASUSTeK Computer INC.", "K50AB",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb071, 0, "ASUSTeK Computer INC.", "N5051Tp",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb106, 0, "ASUSTeK Computer Inc. ", "N50Vc ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
{ 0x04f2, 0xb106, 0, "ASUSTeK Computer Inc. ", "N50Vn ",
V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb106, 0, "ASUSTeK Computer Inc. ", "N51Vf ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb106, 0, "ASUSTeK Computer Inc. ", "N51Vg ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb106, 0, "ASUSTeK Computer Inc. ", "N51Vn ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x04f2, 0xb16b, 0, "ASUSTeK Computer Inc. ", "U80A ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ /* Note no whitespace padding for board vendor, this is not a typo */
+ { 0x064e, 0xa111, 0, "ASUSTeK Computer Inc.", "F5RL ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ /* Another Asus laptop in disguise */
+ { 0x064e, 0xa111, 0, "PEGATRON CORPORATION ", "F5SR ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x064e, 0xa116, 0, "ASUSTeK Computer Inc. ", "N10Jb ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x064e, 0xa116, 0, "ASUSTeK Computer Inc. ", "N10Jc ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x064e, 0xa116, 0, "ASUSTeK Computer Inc. ", "N20A ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x064e, 0xa116, 0, "ASUSTeK Computer Inc. ", "X58LE ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x090c, 0xe370, 0, "ASUSTeK Computer Inc. ", "U6S ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x174f, 0x5a35, 0, "ASUSTeK Computer Inc. ", "F3Ke ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x174f, 0x5a35, 0, "ASUSTeK Computer Inc. ", "F3Q ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x174f, 0x5a35, 0, "ASUSTeK Computer Inc. ", "F3Sa ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x174f, 0x5a35, 0, "ASUSTeK Computer Inc. ", "F3Sg ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x174f, 0x5a35, 0, "ASUSTeK Computer Inc. ", "F3Sr ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x174f, 0x5a35, 0, "ASUSTeK Computer Inc. ", "F5N ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x174f, 0x5a35, 0, "ASUSTeK Computer Inc. ", "F5SL ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x174f, 0x5a35, 0, "ASUSTeK Computer Inc. ", "G1S ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x174f, 0x5a35, 0, "ASUSTeK Computer Inc. ", "G1Sn ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x174f, 0x5a35, 0, "ASUSTeK Computer Inc. ", "G2S ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x174f, 0xa311, 0, "ASUSTeK Computer Inc. ", "A3F ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED },
+ { 0x5986, 0x0200, 0, "LENOVO", "SPEEDY ",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED, 0, NULL, NULL, NULL,
+ "Lenovo IdeaPad Y510" },
+ { 0x5986, 0x0205, 0, "LENOVO", "Base Board Product Name",
+ V4LCONTROL_HFLIPPED|V4LCONTROL_VFLIPPED, 0, NULL, NULL, NULL,
+ "Lenovo IdeaPad U330" },
+
/* Second: devices which should use some software processing by default */
/* Pac207 based devices */
{ 0x041e, 0x4028, 0, NULL, NULL, V4LCONTROL_WANTS_WB, 1500 },
@@ -69,6 +173,8 @@ static const struct v4lcontrol_flags_info v4lcontrol_flags[] = {
/* Pac7302 based devices */
{ 0x093a, 0x2620, 0x0f, NULL, NULL,
V4LCONTROL_ROTATED_90_JPEG|V4LCONTROL_WANTS_WB },
+ { 0x06f8, 0x3009, 0, NULL, NULL,
+ V4LCONTROL_ROTATED_90_JPEG|V4LCONTROL_WANTS_WB },
/* Pac7311 based devices */
{ 0x093a, 0x2600, 0x0f, NULL, NULL, V4LCONTROL_WANTS_WB },
/* sq905 devices */
@@ -87,6 +193,33 @@ static const struct v4lcontrol_flags_info v4lcontrol_flags[] = {
static const struct v4l2_queryctrl fake_controls[];
+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 void v4lcontrol_init_flags(struct v4lcontrol_data *data)
{
struct stat st;
@@ -94,8 +227,8 @@ static void v4lcontrol_init_flags(struct v4lcontrol_data *data)
char sysfs_name[512];
unsigned short vendor_id = 0;
unsigned short product_id = 0;
- char dmi_board_vendor[512] = "";
- char dmi_board_name[512]= "";
+ char dmi_system_vendor[512], dmi_system_name[512], dmi_system_version[512];
+ char dmi_board_vendor[512], dmi_board_name[512], dmi_board_version[512];
int i, minor;
char c, *s, buf[32];
struct v4l2_input input;
@@ -174,31 +307,39 @@ static void v4lcontrol_init_flags(struct v4lcontrol_data *data)
return; /* Should never happen */
}
- /* Get DMI board vendor and name */
- f = fopen("/sys/devices/virtual/dmi/id/board_vendor", "r");
- if (f) {
- s = fgets(dmi_board_vendor, sizeof(dmi_board_vendor), f);
- if (s)
- s[strlen(s) - 1] = 0;
- fclose(f);
- }
-
- f = fopen("/sys/devices/virtual/dmi/id/board_name", "r");
- if (f) {
- s = fgets(dmi_board_name, sizeof(dmi_board_name), f);
- if (s)
- s[strlen(s) - 1] = 0;
- fclose(f);
- }
+ /* Get DMI board and system strings */
+ v4lcontrol_get_dmi_string("sys_vendor", dmi_system_vendor,
+ sizeof(dmi_system_vendor));
+ v4lcontrol_get_dmi_string("product_name", dmi_system_name,
+ sizeof(dmi_system_name));
+ v4lcontrol_get_dmi_string("product_version", dmi_system_version,
+ sizeof(dmi_system_version));
+
+ 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));
+ v4lcontrol_get_dmi_string("board_version", dmi_board_version,
+ sizeof(dmi_board_version));
for (i = 0; i < ARRAY_SIZE(v4lcontrol_flags); i++)
if (v4lcontrol_flags[i].vendor_id == vendor_id &&
v4lcontrol_flags[i].product_id ==
(product_id & ~v4lcontrol_flags[i].product_mask) &&
+
+ (v4lcontrol_flags[i].dmi_system_vendor == NULL ||
+ !strcmp(v4lcontrol_flags[i].dmi_system_vendor, dmi_system_vendor)) &&
+ (v4lcontrol_flags[i].dmi_system_name == NULL ||
+ !strcmp(v4lcontrol_flags[i].dmi_system_name, dmi_system_name)) &&
+ (v4lcontrol_flags[i].dmi_system_version == NULL ||
+ !strcmp(v4lcontrol_flags[i].dmi_system_version, dmi_system_version)) &&
+
(v4lcontrol_flags[i].dmi_board_vendor == NULL ||
!strcmp(v4lcontrol_flags[i].dmi_board_vendor, dmi_board_vendor)) &&
(v4lcontrol_flags[i].dmi_board_name == NULL ||
- !strcmp(v4lcontrol_flags[i].dmi_board_name, dmi_board_name))) {
+ !strcmp(v4lcontrol_flags[i].dmi_board_name, dmi_board_name)) &&
+ (v4lcontrol_flags[i].dmi_board_version == NULL ||
+ !strcmp(v4lcontrol_flags[i].dmi_board_version, dmi_board_version))) {
data->flags |= v4lcontrol_flags[i].flags;
data->flags_info = &v4lcontrol_flags[i];
break;
@@ -209,14 +350,17 @@ struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion)
{
int shm_fd;
int i, rc, init = 0;
- char *s, shm_name[256];
+ char *s, shm_name[256], pwd_buf[1024];
struct v4l2_capability cap;
struct v4l2_queryctrl ctrl;
+ struct passwd pwd, *pwd_p;
struct v4lcontrol_data *data = calloc(1, sizeof(struct v4lcontrol_data));
- if (!data)
+ if (!data) {
+ fprintf(stderr, "libv4lcontrol: error: out of memory!\n");
return NULL;
+ }
data->fd = fd;
@@ -252,8 +396,19 @@ struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion)
if (data->controls == 0)
return data; /* No need to create a shared memory segment */
- SYS_IOCTL(fd, VIDIOC_QUERYCAP, &cap);
- snprintf(shm_name, 256, "/%s:%s", cap.bus_info, cap.card);
+ if (SYS_IOCTL(fd, VIDIOC_QUERYCAP, &cap)) {
+ perror("libv4lcontrol: error querying device capabilities");
+ goto error;
+ }
+
+ if (getpwuid_r(geteuid(), &pwd, pwd_buf, sizeof(pwd_buf), &pwd_p) == 0) {
+ snprintf(shm_name, 256, "/libv4l-%s:%s:%s", pwd.pw_name,
+ cap.bus_info, cap.card);
+ } else {
+ perror("libv4lcontrol: error getting username using uid instead");
+ snprintf(shm_name, 256, "/libv4l-%lu:%s:%s", (unsigned long)geteuid(),
+ cap.bus_info, cap.card);
+ }
/* / is not allowed inside shm names */
for (i = 1; shm_name[i]; i++)
@@ -264,23 +419,41 @@ struct v4lcontrol_data *v4lcontrol_create(int fd, int always_needs_conversion)
if ((shm_fd = shm_open(shm_name, (O_CREAT | O_EXCL | O_RDWR),
(S_IREAD | S_IWRITE))) >= 0)
init = 1;
- else if ((shm_fd = shm_open(shm_name, O_RDWR, (S_IREAD | S_IWRITE))) < 0)
- goto error;
+ else
+ shm_fd = shm_open(shm_name, O_RDWR, (S_IREAD | S_IWRITE));
- /* Set the shared memory size */
- ftruncate(shm_fd, V4LCONTROL_SHM_SIZE);
+ if (shm_fd >= 0) {
+ /* Set the shared memory size */
+ ftruncate(shm_fd, V4LCONTROL_SHM_SIZE);
- /* Retreive a pointer to the shm object */
- data->shm_values = mmap(NULL, V4LCONTROL_SHM_SIZE, (PROT_READ | PROT_WRITE),
- MAP_SHARED, shm_fd, 0);
- close(shm_fd);
+ /* Retreive a pointer to the shm object */
+ data->shm_values = mmap(NULL, V4LCONTROL_SHM_SIZE, (PROT_READ | PROT_WRITE),
+ MAP_SHARED, shm_fd, 0);
+ close(shm_fd);
- if (data->shm_values == MAP_FAILED)
- goto error;
+ if (data->shm_values == MAP_FAILED) {
+ perror("libv4lcontrol: error shm mmap failed");
+ data->shm_values = NULL;
+ }
+ } else
+ perror("libv4lcontrol: error creating shm segment failed");
+
+ /* Fall back to malloc */
+ if (data->shm_values == NULL) {
+ fprintf(stderr,
+ "libv4lcontrol: falling back to malloc-ed memory for controls\n");
+ data->shm_values = malloc(V4LCONTROL_SHM_SIZE);
+ if (!data->shm_values) {
+ fprintf(stderr, "libv4lcontrol: error: out of memory!\n");
+ goto error;
+ }
+ init = 1;
+ data->priv_flags |= V4LCONTROL_MEMORY_IS_MALLOCED;
+ }
if (init) {
/* Initialize the new shm object we created */
- memset(data->shm_values, 0, sizeof(V4LCONTROL_SHM_SIZE));
+ memset(data->shm_values, 0, V4LCONTROL_SHM_SIZE);
for (i = 0; i < V4LCONTROL_COUNT; i++)
data->shm_values[i] = fake_controls[i].default_value;
@@ -301,12 +474,15 @@ error:
void v4lcontrol_destroy(struct v4lcontrol_data *data)
{
- if (data->controls)
- munmap(data->shm_values, V4LCONTROL_SHM_SIZE);
+ if (data->controls) {
+ if (data->priv_flags & V4LCONTROL_MEMORY_IS_MALLOCED)
+ free(data->shm_values);
+ else
+ munmap(data->shm_values, V4LCONTROL_SHM_SIZE);
+ }
free(data);
}
-/* FIXME get better CID's for normalize */
static const struct v4l2_queryctrl fake_controls[V4LCONTROL_COUNT] = {
{
.id = V4L2_CID_AUTO_WHITE_BALANCE,