mirror of
https://github.com/patjak/facetimehd.git
synced 2026-04-09 19:10:01 +02:00
Merge branch 'my_fixes' of git://github.com/sschnelle/facetimehd
This commit is contained in:
2
Makefile
2
Makefile
@@ -1,4 +1,4 @@
|
||||
facetimehd-objs := fthd_ddr.o fthd_hw.o fthd_drv.o fthd_ringbuf.o fthd_isp.o fthd_v4l2.o fthd_buffer.o
|
||||
facetimehd-objs := fthd_ddr.o fthd_hw.o fthd_drv.o fthd_ringbuf.o fthd_isp.o fthd_v4l2.o fthd_buffer.o fthd_sysfs.o
|
||||
obj-m := facetimehd.o
|
||||
|
||||
KVERSION := $(shell uname -r)
|
||||
|
||||
13
fthd_drv.c
13
fthd_drv.c
@@ -34,6 +34,7 @@
|
||||
#include "fthd_ringbuf.h"
|
||||
#include "fthd_buffer.h"
|
||||
#include "fthd_v4l2.h"
|
||||
#include "fthd_sysfs.h"
|
||||
|
||||
static int fthd_pci_reserve_mem(struct fthd_private *dev_priv)
|
||||
{
|
||||
@@ -207,8 +208,11 @@ static void fthd_handle_irq(struct fthd_private *dev_priv, struct fw_channel *ch
|
||||
return;
|
||||
}
|
||||
|
||||
if (chan == dev_priv->channel_debug)
|
||||
if (chan == dev_priv->channel_debug) {
|
||||
pr_debug("DEBUG channel ready\n");
|
||||
wake_up_interruptible(&chan->wq);
|
||||
return;
|
||||
}
|
||||
|
||||
while((entry = fthd_channel_ringbuf_receive(dev_priv, chan)) != (u32)-1) {
|
||||
pr_debug("channel %s: message available, address %08x\n", chan->name, FTHD_S2_MEM_READ(entry + FTHD_RINGBUF_ADDRESS_FLAGS));
|
||||
@@ -330,6 +334,8 @@ static void fthd_pci_remove(struct pci_dev *pdev)
|
||||
if (!dev_priv)
|
||||
goto out;
|
||||
|
||||
fthd_sysfs_exit(dev_priv);
|
||||
|
||||
fthd_v4l2_unregister(dev_priv);
|
||||
|
||||
fthd_stop_firmware(dev_priv);
|
||||
@@ -485,7 +491,12 @@ static int fthd_pci_probe(struct pci_dev *pdev,
|
||||
if (ret)
|
||||
goto fail_firmware;
|
||||
|
||||
ret = fthd_sysfs_init(dev_priv);
|
||||
if (ret)
|
||||
goto fail_v4l2;
|
||||
return 0;
|
||||
fail_v4l2:
|
||||
fthd_v4l2_unregister(dev_priv);
|
||||
fail_firmware:
|
||||
fthd_stop_firmware(dev_priv);
|
||||
fail_hw:
|
||||
|
||||
69
fthd_isp.c
69
fthd_isp.c
@@ -332,6 +332,75 @@ static int fthd_isp_cmd(struct fthd_private *dev_priv, enum fthd_isp_cmds comman
|
||||
pr_debug("status %04x, request_len %d response len %d address_flags %x\n", cmd.status,
|
||||
request_size, response_size, address);
|
||||
|
||||
ret = cmd.status ? -EIO : 0;
|
||||
out:
|
||||
isp_mem_destroy(request);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int fthd_isp_debug_cmd(struct fthd_private *dev_priv, enum fthd_isp_cmds command, void *buf,
|
||||
int request_len, int *response_len)
|
||||
{
|
||||
struct isp_mem_obj *request;
|
||||
struct isp_cmd_hdr cmd;
|
||||
u32 address, request_size, response_size;
|
||||
u32 entry;
|
||||
int len, ret;
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
|
||||
if (response_len) {
|
||||
len = max(request_len, *response_len);
|
||||
} else {
|
||||
len = request_len;
|
||||
}
|
||||
len += sizeof(struct isp_cmd_hdr);
|
||||
|
||||
pr_debug("sending debug cmd %d to firmware\n", command);
|
||||
|
||||
request = isp_mem_create(dev_priv, FTHD_MEM_CMD, len);
|
||||
if (!request) {
|
||||
dev_err(&dev_priv->pdev->dev, "failed to allocate cmd memory object\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
cmd.opcode = command;
|
||||
|
||||
FTHD_S2_MEMCPY_TOIO(request->offset, &cmd, sizeof(struct isp_cmd_hdr));
|
||||
if (request_len)
|
||||
FTHD_S2_MEMCPY_TOIO(request->offset + sizeof(struct isp_cmd_hdr), buf, request_len);
|
||||
|
||||
ret = fthd_channel_ringbuf_send(dev_priv, dev_priv->channel_debug,
|
||||
request->offset, request_len + 8, (response_len ? *response_len : 0) + 8, &entry);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (entry == (u32)-1) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = fthd_channel_wait_ready(dev_priv, dev_priv->channel_debug, entry, 20000);
|
||||
if (ret) {
|
||||
if (response_len)
|
||||
*response_len = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
FTHD_S2_MEMCPY_FROMIO(&cmd, request->offset, sizeof(struct isp_cmd_hdr));
|
||||
address = FTHD_S2_MEM_READ(entry + FTHD_RINGBUF_ADDRESS_FLAGS);
|
||||
request_size = FTHD_S2_MEM_READ(entry + FTHD_RINGBUF_REQUEST_SIZE);
|
||||
response_size = FTHD_S2_MEM_READ(entry + FTHD_RINGBUF_RESPONSE_SIZE);
|
||||
|
||||
/* XXX: response size in the ringbuf is zero after command completion, how is buffer size
|
||||
verification done? */
|
||||
if (response_len && *response_len)
|
||||
FTHD_S2_MEMCPY_FROMIO(buf, (address & ~3) + sizeof(struct isp_cmd_hdr),
|
||||
*response_len);
|
||||
|
||||
pr_info("status %04x, request_len %d response len %d address_flags %x\n", cmd.status,
|
||||
request_size, response_size, address);
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
isp_mem_destroy(request);
|
||||
|
||||
39
fthd_isp.h
39
fthd_isp.h
@@ -447,6 +447,37 @@ enum fthd_isp_cmds {
|
||||
CISP_CMD_APPLE_CH_DPC_STATIC_DEFECTS_TABLE_SET = 0xc50c,
|
||||
};
|
||||
|
||||
enum isp_debug_cmds {
|
||||
CISP_CMD_DEBUG_BANNER=0,
|
||||
CISP_CMD_DEBUG_NOP1,
|
||||
CISP_CMD_DEBUG_NOP2,
|
||||
CISP_CMD_DEBUG_PS,
|
||||
CISP_CMD_DEBUG_GET_ROOT_HANDLE,
|
||||
CISP_CMD_DEBUG_GET_OBJECT_BY_NAME,
|
||||
CISP_CMD_DEBUG_GET_NUMBER_OF_CHILDREN,
|
||||
CISP_CMD_DEBUG_GET_CHILDREN_BY_INDEX,
|
||||
CISP_CMD_DEBUG_SHOW_OBJECT_GRAPH,
|
||||
CISP_CMD_DEBUG_DUMP_OBJECT,
|
||||
CISP_CMD_DEBUG_DUMP_ALL_OBJECTS,
|
||||
CISP_CMD_DEBUG_GET_DEBUG_LEVEL,
|
||||
CISP_CMD_DEBUG_SET_DEBUG_LEVEL,
|
||||
CISP_CMD_DEBUG_SET_DEBUG_LEVEL_RECURSIVE,
|
||||
CISP_CMD_DEBUG_GET_FSM_COUNT,
|
||||
CISP_CMD_DEBUG_GET_FSM_BY_INDEX,
|
||||
CISP_CMD_DEBUG_GET_FSM_BY_NAME,
|
||||
CISP_CMD_DEBUG_GET_FSM_DEBUG_LEVEL,
|
||||
CISP_CMD_DEBUG_SET_FSM_DEBUG_LEVEL,
|
||||
CISP_CMD_DEBUG_FSM_UNKNOWN, /* XXX: don't know what this cmd is doing yet */
|
||||
CISP_CMD_DEBUG_HEAP_STATISTICS,
|
||||
CISP_CMD_DEBUG_IRQ_STATISTICS,
|
||||
CISP_CMD_DEBUG_SHOW_SEMAPHORE_STATUS,
|
||||
CISP_CMD_DEBUG_START_CPU_PERFORMANCE_COUNTER,
|
||||
CISP_CMD_DEBUG_STOP_CPU_PERFORMANCE_COUNTER,
|
||||
CISP_CMD_DEBUG_SHOW_WIRING_OPERATIONS,
|
||||
CISP_CMD_DEBUG_SHOW_UNIT_TEST_STATUS,
|
||||
CISP_CMD_DEBUG_GET_ENVIRONMENT,
|
||||
};
|
||||
|
||||
struct isp_mem_obj {
|
||||
struct resource base;
|
||||
unsigned int type;
|
||||
@@ -675,6 +706,11 @@ struct isp_cmd_channel_buffer_return {
|
||||
u32 channel;
|
||||
};
|
||||
|
||||
struct fthd_isp_debug_cmd {
|
||||
u32 show_errors;
|
||||
u32 arg[64];
|
||||
};
|
||||
|
||||
#define to_isp_mem_obj(x) container_of((x), struct isp_mem_obj, base)
|
||||
|
||||
extern int isp_init(struct fthd_private *dev_priv);
|
||||
@@ -729,4 +765,7 @@ extern int fthd_isp_cmd_channel_hue_set(struct fthd_private *dev_priv, int chann
|
||||
extern int fthd_isp_cmd_channel_buffer_return(struct fthd_private *dev_priv, int channel);
|
||||
extern int fthd_start_channel(struct fthd_private *dev_priv, int channel);
|
||||
extern int fthd_stop_channel(struct fthd_private *dev_priv, int channel);
|
||||
extern int fthd_isp_debug_cmd(struct fthd_private *dev_priv, enum fthd_isp_cmds command, void *buf,
|
||||
int request_len, int *response_len);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#include "fthd_ringbuf.h"
|
||||
#include "fthd_isp.h"
|
||||
|
||||
static u32 get_entry_addr(struct fthd_private *dev_priv,
|
||||
u32 get_entry_addr(struct fthd_private *dev_priv,
|
||||
struct fw_channel *chan, int num)
|
||||
{
|
||||
return chan->offset + num * FTHD_RINGBUF_ENTRY_SIZE;
|
||||
|
||||
@@ -49,4 +49,6 @@ extern u32 fthd_channel_ringbuf_receive(struct fthd_private *dev_priv,
|
||||
struct fw_channel *chan);
|
||||
|
||||
extern int fthd_channel_wait_ready(struct fthd_private *dev_priv, struct fw_channel *chan, u32 entry, int timeout);
|
||||
extern u32 get_entry_addr(struct fthd_private *dev_priv,
|
||||
struct fw_channel *chan, int num);
|
||||
#endif
|
||||
|
||||
215
fthd_sysfs.c
Normal file
215
fthd_sysfs.c
Normal file
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* FacetimeHD camera driver
|
||||
*
|
||||
* Copyright (C) 2015 Sven Schnelle <svens@stackframe.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <media/v4l2-dev.h>
|
||||
#include <media/v4l2-ioctl.h>
|
||||
#include <media/v4l2-ctrls.h>
|
||||
#include <media/videobuf2-dma-sg.h>
|
||||
#include "fthd_drv.h"
|
||||
#include "fthd_sysfs.h"
|
||||
#include "fthd_isp.h"
|
||||
#include "fthd_ringbuf.h"
|
||||
#include "fthd_hw.h"
|
||||
|
||||
static ssize_t fthd_store_debug(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct fthd_isp_debug_cmd cmd;
|
||||
struct fthd_private *dev_priv = dev_get_drvdata(dev);
|
||||
int ret, opcode;
|
||||
|
||||
if (count == 0)
|
||||
return 0;
|
||||
|
||||
if (count > 64)
|
||||
return -EINVAL;
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
|
||||
if (!strcmp(buf, "ps"))
|
||||
opcode = CISP_CMD_DEBUG_PS;
|
||||
else if (!strcmp(buf, "banner"))
|
||||
opcode = CISP_CMD_DEBUG_BANNER;
|
||||
else if (!strcmp(buf, "get_root"))
|
||||
opcode = CISP_CMD_DEBUG_GET_ROOT_HANDLE;
|
||||
else if (!strcmp(buf, "heap"))
|
||||
opcode = CISP_CMD_DEBUG_HEAP_STATISTICS;
|
||||
else if (!strcmp(buf, "irq"))
|
||||
opcode = CISP_CMD_DEBUG_IRQ_STATISTICS;
|
||||
else if (!strcmp(buf, "semaphore"))
|
||||
opcode = CISP_CMD_DEBUG_SHOW_SEMAPHORE_STATUS;
|
||||
else if (!strcmp(buf, "wiring"))
|
||||
opcode = CISP_CMD_DEBUG_SHOW_WIRING_OPERATIONS;
|
||||
else if (sscanf(buf, "get_object_by_name %s", (char *)&cmd.arg) == 1)
|
||||
opcode = CISP_CMD_DEBUG_GET_OBJECT_BY_NAME;
|
||||
else if (sscanf(buf, "dump_object %x", &cmd.arg[0]) == 1)
|
||||
opcode = CISP_CMD_DEBUG_DUMP_OBJECT;
|
||||
else if (!strcmp(buf, "dump_objects"))
|
||||
opcode = CISP_CMD_DEBUG_DUMP_ALL_OBJECTS;
|
||||
else if (!strcmp(buf, "show_objects"))
|
||||
opcode = CISP_CMD_DEBUG_SHOW_OBJECT_GRAPH;
|
||||
else if (sscanf(buf, "get_debug_level %i", &cmd.arg[0]) == 1)
|
||||
opcode = CISP_CMD_DEBUG_GET_DEBUG_LEVEL;
|
||||
else if (sscanf(buf, "set_debug_level %x %i", &cmd.arg[0], &cmd.arg[1]) == 2)
|
||||
opcode = CISP_CMD_DEBUG_SET_DEBUG_LEVEL;
|
||||
else if (sscanf(buf, "set_debug_level_rec %x %i", &cmd.arg[0], &cmd.arg[1]) == 2)
|
||||
opcode = CISP_CMD_DEBUG_SET_DEBUG_LEVEL_RECURSIVE;
|
||||
else if (!strcmp(buf, "get_fsm_count"))
|
||||
opcode = CISP_CMD_DEBUG_GET_FSM_COUNT;
|
||||
else if (sscanf(buf, "get_fsm_by_name %s", (char *)&cmd.arg[0]) == 1)
|
||||
opcode = CISP_CMD_DEBUG_GET_FSM_BY_NAME;
|
||||
else if (sscanf(buf, "get_fsm_by_index %i", &cmd.arg[0]) == 1)
|
||||
opcode = CISP_CMD_DEBUG_GET_FSM_BY_INDEX;
|
||||
else if (sscanf(buf, "get_fsm_debug_level %x", &cmd.arg[0]) == 1)
|
||||
opcode = CISP_CMD_DEBUG_GET_FSM_DEBUG_LEVEL;
|
||||
else if (sscanf(buf, "set_fsm_debug_level %x", &cmd.arg[0]) == 2)
|
||||
opcode = CISP_CMD_DEBUG_SET_FSM_DEBUG_LEVEL;
|
||||
|
||||
else if (sscanf(buf, "%i %i\n", &opcode, &cmd.arg[0]) != 2)
|
||||
return -EINVAL;
|
||||
cmd.show_errors = 1;
|
||||
|
||||
ret = fthd_isp_debug_cmd(dev_priv, opcode, &cmd, sizeof(cmd), NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
static ssize_t fthd_dump_channel(struct device *dev, struct fw_channel *chan,
|
||||
char *buf)
|
||||
{
|
||||
struct fthd_private *dev_priv = dev_get_drvdata(dev);
|
||||
int i;
|
||||
char pos;
|
||||
u32 entry;
|
||||
ssize_t ret = 0, len;
|
||||
spin_lock_irq(&chan->lock);
|
||||
for( i = 0; i < chan->size; i++) {
|
||||
if (chan->ringbuf.idx == i)
|
||||
pos = '*';
|
||||
else
|
||||
pos = ' ';
|
||||
entry = get_entry_addr(dev_priv, chan, i);
|
||||
len = sprintf(buf+ret, "%c%3.3d: ADDRESS %08x REQUEST_SIZE %08x RESPONSE_SIZE %08x\n",
|
||||
pos, i,
|
||||
FTHD_S2_MEM_READ(entry + FTHD_RINGBUF_ADDRESS_FLAGS),
|
||||
FTHD_S2_MEM_READ(entry + FTHD_RINGBUF_REQUEST_SIZE),
|
||||
FTHD_S2_MEM_READ(entry + FTHD_RINGBUF_RESPONSE_SIZE));
|
||||
if (len < 0) {
|
||||
ret = len;
|
||||
break;
|
||||
} else {
|
||||
ret += len;
|
||||
}
|
||||
}
|
||||
spin_unlock_irq(&chan->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t channel_terminal_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct fthd_private *dev_priv = dev_get_drvdata(dev);
|
||||
return fthd_dump_channel(dev, dev_priv->channel_io, buf);
|
||||
}
|
||||
|
||||
static ssize_t channel_sharedmalloc_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct fthd_private *dev_priv = dev_get_drvdata(dev);
|
||||
return fthd_dump_channel(dev, dev_priv->channel_shared_malloc, buf);
|
||||
}
|
||||
|
||||
static ssize_t channel_io_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct fthd_private *dev_priv = dev_get_drvdata(dev);
|
||||
return fthd_dump_channel(dev, dev_priv->channel_io, buf);
|
||||
}
|
||||
|
||||
static ssize_t channel_debug_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct fthd_private *dev_priv = dev_get_drvdata(dev);
|
||||
return fthd_dump_channel(dev, dev_priv->channel_debug, buf);
|
||||
}
|
||||
|
||||
static ssize_t channel_buf_h2t_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct fthd_private *dev_priv = dev_get_drvdata(dev);
|
||||
return fthd_dump_channel(dev, dev_priv->channel_buf_h2t, buf);
|
||||
}
|
||||
|
||||
static ssize_t channel_buf_t2h_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct fthd_private *dev_priv = dev_get_drvdata(dev);
|
||||
return fthd_dump_channel(dev, dev_priv->channel_buf_t2h, buf);
|
||||
}
|
||||
|
||||
static ssize_t channel_io_t2h_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct fthd_private *dev_priv = dev_get_drvdata(dev);
|
||||
return fthd_dump_channel(dev, dev_priv->channel_io_t2h, buf);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(debug, S_IWUSR | S_IRUGO, NULL, fthd_store_debug);
|
||||
static DEVICE_ATTR_RO(channel_terminal);
|
||||
static DEVICE_ATTR_RO(channel_sharedmalloc);
|
||||
static DEVICE_ATTR_RO(channel_io);
|
||||
static DEVICE_ATTR_RO(channel_debug);
|
||||
static DEVICE_ATTR_RO(channel_buf_h2t);
|
||||
static DEVICE_ATTR_RO(channel_buf_t2h);
|
||||
static DEVICE_ATTR_RO(channel_io_t2h);
|
||||
|
||||
static struct attribute *fthd_attributes[] = {
|
||||
&dev_attr_debug.attr,
|
||||
&dev_attr_channel_terminal.attr,
|
||||
&dev_attr_channel_sharedmalloc.attr,
|
||||
&dev_attr_channel_io.attr,
|
||||
&dev_attr_channel_debug.attr,
|
||||
&dev_attr_channel_buf_h2t.attr,
|
||||
&dev_attr_channel_buf_t2h.attr,
|
||||
&dev_attr_channel_io_t2h.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group fthd_attribute_group = {
|
||||
.attrs = fthd_attributes,
|
||||
};
|
||||
|
||||
int fthd_sysfs_init(struct fthd_private *dev_priv)
|
||||
{
|
||||
return sysfs_create_group(&dev_priv->pdev->dev.kobj, &fthd_attribute_group);
|
||||
}
|
||||
|
||||
void fthd_sysfs_exit(struct fthd_private *dev_priv)
|
||||
{
|
||||
sysfs_remove_group(&dev_priv->pdev->dev.kobj, &fthd_attribute_group);
|
||||
}
|
||||
27
fthd_sysfs.h
Normal file
27
fthd_sysfs.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Broadcom PCIe 1570 webcam driver
|
||||
*
|
||||
* Copyright (C) 2015 Sven Schnelle <svens@stackframe.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _FTHD_SYSFS_H
|
||||
#define _FTHD_SYSFS_H
|
||||
|
||||
struct fthd_private;
|
||||
|
||||
int fthd_sysfs_init(struct fthd_private *priv);
|
||||
void fthd_sysfs_exit(struct fthd_private *priv);
|
||||
#endif
|
||||
@@ -305,9 +305,11 @@ static int fthd_v4l2_ioctl_enum_input(struct file *filp, void *priv,
|
||||
if (input->index != 0)
|
||||
return -EINVAL;
|
||||
|
||||
memset(input, 0, sizeof(*input));
|
||||
strcpy(input->name, "Camera");
|
||||
input->type = V4L2_INPUT_TYPE_CAMERA;
|
||||
input->std = 0;
|
||||
strcpy(input->name, "Apple Facetime HD");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user