mirror of
https://github.com/patjak/facetimehd.git
synced 2026-04-09 19:10:01 +02:00
first version that actually streams ;-)
This commit is contained in:
2
Makefile
2
Makefile
@@ -1,4 +1,4 @@
|
||||
bcwc_pcie-objs := bcwc_ddr.o bcwc_hw.o bcwc_drv.o bcwc_ringbuf.o bcwc_isp.o bcwc_v4l2.o
|
||||
bcwc_pcie-objs := bcwc_ddr.o bcwc_hw.o bcwc_drv.o bcwc_ringbuf.o bcwc_isp.o bcwc_v4l2.o bcwc_buffer.o
|
||||
obj-m := bcwc_pcie.o
|
||||
|
||||
KVERSION := $(shell uname -r)
|
||||
|
||||
297
bcwc_drv.c
297
bcwc_drv.c
@@ -24,12 +24,15 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include "bcwc_drv.h"
|
||||
#include "bcwc_hw.h"
|
||||
#include "bcwc_isp.h"
|
||||
#include "bcwc_ringbuf.h"
|
||||
#include "bcwc_buffer.h"
|
||||
#include "bcwc_v4l2.h"
|
||||
|
||||
static int bcwc_pci_reserve_mem(struct bcwc_private *dev_priv)
|
||||
@@ -91,54 +94,112 @@ static int bcwc_pci_reserve_mem(struct bcwc_private *dev_priv)
|
||||
|
||||
static void bcwc_irq_disable(struct bcwc_private *dev_priv)
|
||||
{
|
||||
//bcwc_hw_irq_disable(dev_priv);
|
||||
free_irq(dev_priv->pdev->irq, dev_priv);
|
||||
}
|
||||
|
||||
static void sharedmalloc_handler(struct bcwc_private *dev_priv,
|
||||
struct fw_channel *chan,
|
||||
struct bcwc_ringbuf_entry *entry)
|
||||
{
|
||||
u32 request_size, response_size, address;
|
||||
struct isp_mem_obj *obj, **p;
|
||||
|
||||
request_size = entry->request_size;
|
||||
response_size = entry->response_size;
|
||||
address = entry->address_flags & ~ 3;
|
||||
|
||||
if (address) {
|
||||
pr_debug("Firmware wants to free memory at %08x\n", address);
|
||||
p = dev_priv->s2_mem + address - 64;
|
||||
isp_mem_destroy(*p);
|
||||
|
||||
bcwc_channel_ringbuf_mark_entry_available(dev_priv, chan);
|
||||
bcwc_channel_ringbuf_send(dev_priv, chan, 0, 0, 0);
|
||||
} else {
|
||||
if (!request_size)
|
||||
return;
|
||||
obj = isp_mem_create(dev_priv, FTHD_MEM_SHAREDMALLOC, request_size + 64);
|
||||
if (!obj)
|
||||
return;
|
||||
|
||||
pr_debug("Firmware allocated %d bytes at %08lx (tag %c%c%c%c)\n", request_size, obj->offset,
|
||||
response_size >> 24,response_size >> 16,
|
||||
response_size >> 8, response_size);
|
||||
p = dev_priv->s2_mem + obj->offset;
|
||||
*p = obj;
|
||||
bcwc_channel_ringbuf_send(dev_priv, chan, obj->offset + 64, 0, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void terminal_handler(struct bcwc_private *dev_priv,
|
||||
struct fw_channel *chan,
|
||||
struct bcwc_ringbuf_entry *entry)
|
||||
{
|
||||
u32 request_size, response_size, address;
|
||||
|
||||
request_size = entry->request_size;
|
||||
response_size = entry->response_size;
|
||||
address = entry->address_flags & ~ 3;
|
||||
|
||||
if (!address || !request_size)
|
||||
return;
|
||||
|
||||
pr_info("FWMSG: %.*s", request_size, (char *)(dev_priv->s2_mem + address));
|
||||
|
||||
}
|
||||
|
||||
static void buf_t2h_handler(struct bcwc_private *dev_priv,
|
||||
struct fw_channel *chan,
|
||||
struct bcwc_ringbuf_entry *entry)
|
||||
{
|
||||
u32 request_size, response_size, address;
|
||||
|
||||
request_size = entry->request_size;
|
||||
response_size = entry->response_size;
|
||||
address = entry->address_flags & ~ 3;
|
||||
|
||||
if (entry->address_flags & 1)
|
||||
return;
|
||||
|
||||
bcwc_buffer_return_handler(dev_priv, dev_priv->s2_mem + address, request_size);
|
||||
bcwc_channel_ringbuf_send(dev_priv, chan, (response_size & 0x10000000) ? address : 0,
|
||||
0, 0x80000000);
|
||||
}
|
||||
|
||||
static void io_t2h_handler(struct bcwc_private *dev_priv,
|
||||
struct fw_channel *chan,
|
||||
struct bcwc_ringbuf_entry *entry)
|
||||
{
|
||||
bcwc_channel_ringbuf_send(dev_priv, chan, 0, 0, 0);
|
||||
}
|
||||
|
||||
static void bcwc_handle_irq(struct bcwc_private *dev_priv, struct fw_channel *chan)
|
||||
{
|
||||
struct isp_mem_obj *obj;
|
||||
struct bcwc_ringbuf_entry *entry;
|
||||
int request_size;
|
||||
u32 address;
|
||||
int i = 0;
|
||||
// pr_debug("Interrupt from channel source %d, type %d [%s]\n", chan->source, chan->type, chan->name);
|
||||
|
||||
pr_debug("Interrupt from channel source %d, type %d [%s]\n", chan->source, chan->type, chan->name);
|
||||
bcwc_channel_ringbuf_dump(dev_priv, chan);
|
||||
if (chan == dev_priv->channel_io) {
|
||||
pr_debug("command ready\n");
|
||||
wake_up_interruptible(&dev_priv->wq);
|
||||
}
|
||||
// if (strcmp(chan->name, "TERMINAL"))
|
||||
// bcwc_channel_ringbuf_dump(dev_priv, chan);
|
||||
|
||||
while(bcwc_channel_ringbuf_entry_available(dev_priv, chan)) {
|
||||
while(bcwc_channel_ringbuf_entry_available(dev_priv, chan) && i++ < 500) {
|
||||
entry = bcwc_channel_ringbuf_get_entry(dev_priv, chan);
|
||||
if (!entry)
|
||||
goto next;
|
||||
|
||||
request_size = entry->request_size;
|
||||
address = entry->address_flags & ~ 3;
|
||||
|
||||
if (chan == dev_priv->channel_shared_malloc) {
|
||||
if (address) {
|
||||
pr_debug("Firmware wants to free memory at %08x\n", address);
|
||||
} else {
|
||||
if (!request_size)
|
||||
goto next;
|
||||
obj = isp_mem_create(dev_priv, FTHD_MEM_SHAREDMALLOC, request_size);
|
||||
if (!obj)
|
||||
goto next; /* FIXME */
|
||||
pr_debug("Firmware allocated %d bytes at %08lx\n", request_size, obj->offset);
|
||||
bcwc_channel_ringbuf_send(dev_priv, chan, obj->offset, 0, 0);
|
||||
}
|
||||
sharedmalloc_handler(dev_priv, chan, entry);
|
||||
} else if (chan == dev_priv->channel_terminal) {
|
||||
if (!address) {
|
||||
dev_err(&dev_priv->pdev->dev, "%s: no address\n", __FUNCTION__);
|
||||
goto next;
|
||||
}
|
||||
if (!request_size)
|
||||
goto next;
|
||||
pr_debug("FWMSG: %.*s", request_size, (char *)(dev_priv->s2_mem + address));
|
||||
}
|
||||
next:
|
||||
terminal_handler(dev_priv, chan, entry);
|
||||
bcwc_channel_ringbuf_mark_entry_available(dev_priv, chan);
|
||||
} else if (chan == dev_priv->channel_buf_t2h) {
|
||||
buf_t2h_handler(dev_priv, chan, entry);
|
||||
} else if (chan == dev_priv->channel_io) {
|
||||
wake_up_interruptible(&dev_priv->wq);
|
||||
} else if (chan == dev_priv->channel_io_t2h) {
|
||||
io_t2h_handler(dev_priv, chan, entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,19 +211,20 @@ static void bcwc_irq_work(struct work_struct *work)
|
||||
u32 pending;
|
||||
int i = 0;
|
||||
|
||||
|
||||
while(i++ < 500) {
|
||||
spin_lock_irq(&dev_priv->io_lock);
|
||||
pending = BCWC_ISP_REG_READ(ISP_REG_41000);
|
||||
pr_debug("interrupt: %08x\n", pending);
|
||||
spin_unlock_irq(&dev_priv->io_lock);
|
||||
|
||||
if (!(pending & 0xf0))
|
||||
break;
|
||||
|
||||
pci_write_config_dword(dev_priv->pdev, 0x94, 0);
|
||||
spin_lock_irq(&dev_priv->io_lock);
|
||||
BCWC_ISP_REG_WRITE(pending, ISP_REG_41024);
|
||||
spin_unlock_irq(&dev_priv->io_lock);
|
||||
pci_write_config_dword(dev_priv->pdev, 0x90, 0x200);
|
||||
|
||||
/* FIXME: locking */
|
||||
for(i = 0; i < dev_priv->num_channels; i++) {
|
||||
chan = dev_priv->channels[i];
|
||||
|
||||
@@ -176,11 +238,8 @@ static void bcwc_irq_work(struct work_struct *work)
|
||||
|
||||
if (i >= 500) {
|
||||
dev_err(&dev_priv->pdev->dev, "irq stuck, disabling\n");
|
||||
// bcwc_hw_irq_disable(dev_priv);
|
||||
bcwc_irq_disable(dev_priv);
|
||||
return;
|
||||
}
|
||||
|
||||
pci_write_config_dword(dev_priv->pdev, 0x94, 0x200);
|
||||
}
|
||||
|
||||
@@ -189,11 +248,11 @@ static irqreturn_t bcwc_irq_handler(int irq, void *arg)
|
||||
struct bcwc_private *dev_priv = arg;
|
||||
u32 pending;
|
||||
unsigned long flags;
|
||||
|
||||
|
||||
spin_lock_irqsave(&dev_priv->io_lock, flags);
|
||||
pending = BCWC_ISP_REG_READ(ISP_REG_41000);
|
||||
spin_unlock_irqrestore(&dev_priv->io_lock, flags);
|
||||
|
||||
|
||||
if (!(pending & 0xf0))
|
||||
return IRQ_NONE;
|
||||
|
||||
@@ -221,7 +280,7 @@ static int bcwc_pci_set_dma_mask(struct bcwc_private *dev_priv,
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = pci_set_dma_mask(dev_priv->pdev, DMA_BIT_MASK(mask));
|
||||
ret = dma_set_mask_and_coherent(&dev_priv->pdev->dev, DMA_BIT_MASK(mask));
|
||||
if (ret) {
|
||||
dev_err(&dev_priv->pdev->dev, "Failed to set %u pci dma mask\n",
|
||||
mask);
|
||||
@@ -233,6 +292,39 @@ static int bcwc_pci_set_dma_mask(struct bcwc_private *dev_priv,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bcwc_pci_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct bcwc_private *dev_priv;
|
||||
|
||||
dev_priv = pci_get_drvdata(pdev);
|
||||
if (!dev_priv)
|
||||
goto out;
|
||||
|
||||
bcwc_v4l2_unregister(dev_priv);
|
||||
bcwc_isp_cmd_stop(dev_priv);
|
||||
isp_powerdown(dev_priv);
|
||||
bcwc_irq_disable(dev_priv);
|
||||
cancel_work_sync(&dev_priv->irq_work);
|
||||
isp_uninit(dev_priv);
|
||||
bcwc_hw_deinit(dev_priv);
|
||||
bcwc_buffer_exit(dev_priv);
|
||||
pci_disable_msi(pdev);
|
||||
|
||||
if (dev_priv->s2_io)
|
||||
iounmap(dev_priv->s2_io);
|
||||
if (dev_priv->s2_mem)
|
||||
iounmap(dev_priv->s2_mem);
|
||||
if (dev_priv->isp_io)
|
||||
iounmap(dev_priv->isp_io);
|
||||
|
||||
pci_release_region(pdev, BCWC_PCI_S2_IO);
|
||||
pci_release_region(pdev, BCWC_PCI_S2_MEM);
|
||||
pci_release_region(pdev, BCWC_PCI_ISP_IO);
|
||||
out:
|
||||
pci_disable_device(pdev);
|
||||
}
|
||||
|
||||
|
||||
static int bcwc_pci_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *entry)
|
||||
{
|
||||
@@ -248,6 +340,14 @@ static int bcwc_pci_probe(struct pci_dev *pdev,
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
spin_lock_init(&dev_priv->io_lock);
|
||||
spin_lock_init(&dev_priv->rb_lock);
|
||||
mutex_init(&dev_priv->vb2_queue_lock);
|
||||
|
||||
mutex_init(&dev_priv->ioctl_lock);
|
||||
init_waitqueue_head(&dev_priv->wq);
|
||||
INIT_LIST_HEAD(&dev_priv->buffer_queue);
|
||||
|
||||
dev_priv->pdev = pdev;
|
||||
|
||||
ret = pci_enable_device(pdev);
|
||||
@@ -263,7 +363,7 @@ static int bcwc_pci_probe(struct pci_dev *pdev,
|
||||
ret = pci_enable_msi(pdev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to enable MSI\n");
|
||||
goto fail_enable;
|
||||
goto fail_reserve;
|
||||
}
|
||||
|
||||
INIT_WORK(&dev_priv->irq_work, bcwc_irq_work);
|
||||
@@ -288,78 +388,67 @@ static int bcwc_pci_probe(struct pci_dev *pdev,
|
||||
dev_priv->ddr_model = 4;
|
||||
dev_priv->ddr_speed = 450;
|
||||
|
||||
if (!(ret = bcwc_hw_init(dev_priv))) {
|
||||
mdelay(100);
|
||||
bcwc_isp_cmd_start(dev_priv);
|
||||
bcwc_isp_cmd_print_enable(dev_priv, 1);
|
||||
bcwc_isp_cmd_set_loadfile(dev_priv);
|
||||
bcwc_isp_cmd_channel_info(dev_priv);
|
||||
bcwc_isp_cmd_channel_camera_config(dev_priv);
|
||||
bcwc_isp_cmd_channel_camera_config_select(dev_priv, 0, 0);
|
||||
bcwc_isp_cmd_channel_crop_set(dev_priv, 0, 0, 0, 1280, 720);
|
||||
bcwc_isp_cmd_channel_output_config_set(dev_priv, 0, 1280, 720);
|
||||
bcwc_isp_cmd_channel_recycle_mode(dev_priv, 0, 1);
|
||||
bcwc_isp_cmd_channel_recycle_start(dev_priv, 0);
|
||||
bcwc_isp_cmd_channel_drc_start(dev_priv, 0);
|
||||
bcwc_isp_cmd_channel_tone_curve_adaptation_start(dev_priv, 0);
|
||||
bcwc_isp_cmd_channel_sif_pixel_format(dev_priv, 0, 1, 1);
|
||||
bcwc_isp_cmd_channel_error_handling_config(dev_priv, 0, 2, 1);
|
||||
bcwc_isp_cmd_channel_streaming_mode(dev_priv, 0, 0);
|
||||
bcwc_isp_cmd_channel_frame_rate_max(dev_priv, 0, 7672);
|
||||
bcwc_isp_cmd_channel_frame_rate_min(dev_priv, 0, 3072);
|
||||
bcwc_isp_cmd_channel_start(dev_priv);
|
||||
return 0;
|
||||
}
|
||||
ret = bcwc_buffer_init(dev_priv);
|
||||
if (ret)
|
||||
goto fail_irq;
|
||||
|
||||
bcwc_hw_deinit(dev_priv);
|
||||
isp_mem_destroy(dev_priv->firmware);
|
||||
pci_release_region(pdev, BCWC_PCI_S2_IO);
|
||||
pci_release_region(pdev, BCWC_PCI_S2_MEM);
|
||||
pci_release_region(pdev, BCWC_PCI_ISP_IO);
|
||||
ret = bcwc_hw_init(dev_priv);
|
||||
if (ret)
|
||||
goto fail_irq;
|
||||
|
||||
mdelay(1000); /* XXX: should not be needed */
|
||||
bcwc_isp_cmd_start(dev_priv);
|
||||
bcwc_isp_cmd_print_enable(dev_priv, 1);
|
||||
bcwc_isp_cmd_set_loadfile(dev_priv);
|
||||
bcwc_isp_cmd_camera_config(dev_priv);
|
||||
bcwc_isp_cmd_channel_info(dev_priv);
|
||||
bcwc_isp_cmd_channel_camera_config(dev_priv);
|
||||
bcwc_isp_cmd_channel_camera_config_select(dev_priv, 0, 0);
|
||||
bcwc_isp_cmd_channel_crop_set(dev_priv, 0, 0, 0, 1024, 768);
|
||||
bcwc_isp_cmd_channel_output_config_set(dev_priv, 0, 1024, 768, 1);
|
||||
bcwc_isp_cmd_channel_recycle_mode(dev_priv, 0, 1);
|
||||
bcwc_isp_cmd_channel_recycle_start(dev_priv, 0);
|
||||
bcwc_isp_cmd_channel_ae_metering_mode_set(dev_priv, 0, 3);
|
||||
bcwc_isp_cmd_channel_drc_start(dev_priv, 0);
|
||||
bcwc_isp_cmd_channel_tone_curve_adaptation_start(dev_priv, 0);
|
||||
bcwc_isp_cmd_channel_ae_speed_set(dev_priv, 0, 60);
|
||||
bcwc_isp_cmd_channel_ae_stability_set(dev_priv, 0, 75);
|
||||
bcwc_isp_cmd_channel_ae_stability_to_stable_set(dev_priv, 0, 8);
|
||||
bcwc_isp_cmd_channel_sif_pixel_format(dev_priv, 0, 1, 1);
|
||||
bcwc_isp_cmd_channel_error_handling_config(dev_priv, 0, 2, 1);
|
||||
bcwc_isp_cmd_channel_face_detection_enable(dev_priv, 0);
|
||||
bcwc_isp_cmd_channel_face_detection_start(dev_priv, 0);
|
||||
bcwc_isp_cmd_channel_frame_rate_max(dev_priv, 0, 7672);
|
||||
bcwc_isp_cmd_channel_frame_rate_min(dev_priv, 0, 3072);
|
||||
bcwc_isp_cmd_channel_temporal_filter_start(dev_priv, 0);
|
||||
bcwc_isp_cmd_channel_motion_history_start(dev_priv, 0);
|
||||
bcwc_isp_cmd_channel_temporal_filter_enable(dev_priv, 0);
|
||||
bcwc_isp_cmd_channel_streaming_mode(dev_priv, 0, 0);
|
||||
bcwc_isp_cmd_channel_brightness_set(dev_priv, 0, 0x80);
|
||||
bcwc_isp_cmd_channel_contrast_set(dev_priv, 0, 0x80);
|
||||
|
||||
ret = bcwc_v4l2_register(dev_priv);
|
||||
if (ret)
|
||||
goto fail_v4l2;
|
||||
|
||||
return 0;
|
||||
fail_v4l2:
|
||||
bcwc_pci_remove(pdev);
|
||||
fail_irq:
|
||||
bcwc_irq_disable(dev_priv);
|
||||
fail_msi:
|
||||
pci_disable_msi(pdev);
|
||||
fail_enable:
|
||||
pci_disable_device(pdev);
|
||||
fail_reserve:
|
||||
pci_release_region(pdev, BCWC_PCI_S2_IO);
|
||||
pci_release_region(pdev, BCWC_PCI_S2_MEM);
|
||||
pci_release_region(pdev, BCWC_PCI_ISP_IO);
|
||||
fail_free:
|
||||
kfree(dev_priv);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void bcwc_pci_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct bcwc_private *dev_priv;
|
||||
|
||||
dev_priv = pci_get_drvdata(pdev);
|
||||
if (dev_priv) {
|
||||
bcwc_isp_cmd_stop(dev_priv);
|
||||
isp_powerdown(dev_priv);
|
||||
bcwc_irq_disable(dev_priv);
|
||||
cancel_work_sync(&dev_priv->irq_work);
|
||||
isp_uninit(dev_priv);
|
||||
bcwc_hw_deinit(dev_priv);
|
||||
|
||||
isp_mem_destroy(dev_priv->firmware);
|
||||
bcwc_buffer_exit(dev_priv);
|
||||
pci_disable_msi(pdev);
|
||||
|
||||
if (dev_priv->s2_io)
|
||||
iounmap(dev_priv->s2_io);
|
||||
if (dev_priv->s2_mem)
|
||||
iounmap(dev_priv->s2_mem);
|
||||
if (dev_priv->isp_io)
|
||||
iounmap(dev_priv->isp_io);
|
||||
|
||||
pci_release_region(pdev, BCWC_PCI_S2_IO);
|
||||
pci_release_region(pdev, BCWC_PCI_S2_MEM);
|
||||
pci_release_region(pdev, BCWC_PCI_ISP_IO);
|
||||
}
|
||||
|
||||
pci_disable_device(pdev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int bcwc_pci_suspend(struct pci_dev *pdev, pm_message_t state)
|
||||
{
|
||||
|
||||
32
bcwc_drv.h
32
bcwc_drv.h
@@ -21,10 +21,15 @@
|
||||
#define _PCWC_PCIE_H
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/wait.h>
|
||||
|
||||
#include <linux/mutex.h>
|
||||
#include <media/videobuf2-dma-sg.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include "bcwc_reg.h"
|
||||
#include "bcwc_ringbuf.h"
|
||||
#include "bcwc_buffer.h"
|
||||
#include "bcwc_v4l2.h"
|
||||
|
||||
#define BCWC_PCI_S2_IO 0
|
||||
#define BCWC_PCI_S2_MEM 2
|
||||
@@ -32,6 +37,8 @@
|
||||
|
||||
#define MAX(a, b) ((a)>(b)?(a):(b))
|
||||
|
||||
#define BCWC_BUFFERS 4
|
||||
|
||||
struct bcwc_reg {
|
||||
u32 offset;
|
||||
u32 value;
|
||||
@@ -50,9 +57,18 @@ struct bcwc_private {
|
||||
struct pci_dev *pdev;
|
||||
unsigned int dma_mask;
|
||||
|
||||
struct v4l2_device v4l2_dev;
|
||||
struct video_device *videodev;
|
||||
struct mutex ioctl_lock;
|
||||
int users;
|
||||
/* lock for synchronizing with irq/workqueue */
|
||||
spinlock_t io_lock;
|
||||
/* lock for ringbuffer synchronization */
|
||||
spinlock_t rb_lock;
|
||||
|
||||
/* waitqueue for signaling command completion */
|
||||
wait_queue_head_t wq;
|
||||
|
||||
|
||||
/* Mapped PCI resources */
|
||||
void *s2_io;
|
||||
u32 s2_io_len;
|
||||
@@ -77,7 +93,8 @@ struct bcwc_private {
|
||||
|
||||
/* Root resource for memory management */
|
||||
struct resource *mem;
|
||||
|
||||
/* Resource for managing IO mmu slots */
|
||||
struct resource *iommu;
|
||||
/* ISP memory objects */
|
||||
struct isp_mem_obj *firmware;
|
||||
struct isp_mem_obj *set_file;
|
||||
@@ -97,6 +114,15 @@ struct bcwc_private {
|
||||
|
||||
/* camera config */
|
||||
int sensor_count;
|
||||
|
||||
const struct bcwc_fmt *fmt;
|
||||
|
||||
struct vb2_queue vb2_queue;
|
||||
struct mutex vb2_queue_lock;
|
||||
struct list_head buffer_queue;
|
||||
struct vb2_alloc_ctx *alloc_ctx;
|
||||
struct h2t_buf_ctx h2t_bufs[BCWC_BUFFERS];
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -43,11 +43,6 @@ static u32 ddr_phy_reg_map[] = {
|
||||
0x038c, 0x0390, 0x0394, 0x03a0, 0x03a4, 0x03a8, 0x03ac,
|
||||
};
|
||||
|
||||
static int bcwc_hw_set_core_clk(struct bcwc_private *dev_priv)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcwc_hw_s2_pll_reset(struct bcwc_private *dev_priv)
|
||||
{
|
||||
BCWC_S2_REG_WRITE(0x40, S2_PLL_CTRL_2C);
|
||||
|
||||
240
bcwc_isp.c
240
bcwc_isp.c
@@ -158,6 +158,7 @@ static int isp_load_firmware(struct bcwc_private *dev_priv)
|
||||
"Misaligned firmware memory object (offset: %lu)\n",
|
||||
dev_priv->firmware->offset);
|
||||
isp_mem_destroy(dev_priv->firmware);
|
||||
dev_priv->firmware = NULL;
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
@@ -287,7 +288,7 @@ int bcwc_isp_cmd(struct bcwc_private *dev_priv, enum bcwc_isp_cmds command, void
|
||||
|
||||
if (request_len)
|
||||
memcpy((char *)cmd + sizeof(struct isp_cmd_hdr), buf, request_len);
|
||||
print_hex_dump_bytes("TXCMD ", DUMP_PREFIX_OFFSET, cmd, len);
|
||||
|
||||
entry = bcwc_channel_ringbuf_send(dev_priv, dev_priv->channel_io,
|
||||
request->offset, request_len + 8, (response_len ? *response_len : 0) + 8);
|
||||
|
||||
@@ -297,7 +298,7 @@ int bcwc_isp_cmd(struct bcwc_private *dev_priv, enum bcwc_isp_cmds command, void
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!wait_event_interruptible_timeout(dev_priv->wq, (entry->address_flags & 1), 5 * HZ)) {
|
||||
if (!wait_event_interruptible_timeout(dev_priv->wq, (entry->address_flags & 1), HZ)) {
|
||||
dev_err(&dev_priv->pdev->dev, "timeout wait for command %d\n", cmd->opcode);
|
||||
bcwc_channel_ringbuf_dump(dev_priv, dev_priv->channel_io);
|
||||
if (response_len)
|
||||
@@ -310,7 +311,7 @@ int bcwc_isp_cmd(struct bcwc_private *dev_priv, enum bcwc_isp_cmds command, void
|
||||
if (response_len && *response_len)
|
||||
memcpy(buf, (entry->address_flags & ~3) + dev_priv->s2_mem + sizeof(struct isp_cmd_hdr), *response_len);
|
||||
|
||||
pr_debug("status %04x, request_len %d response len %d address_flags %x", cmd->status,
|
||||
pr_debug("status %04x, request_len %d response len %d address_flags %x\n", cmd->status,
|
||||
entry->request_size, entry->response_size, entry->address_flags);
|
||||
|
||||
ret = 0;
|
||||
@@ -329,10 +330,21 @@ int bcwc_isp_cmd_start(struct bcwc_private *dev_priv)
|
||||
|
||||
int bcwc_isp_cmd_channel_start(struct bcwc_private *dev_priv)
|
||||
{
|
||||
struct isp_cmd_channel_start cmd;
|
||||
pr_debug("sending channel start cmd to firmware\n");
|
||||
return bcwc_isp_cmd(dev_priv, CISP_CMD_CH_START, NULL, 0, NULL);
|
||||
|
||||
cmd.channel = 0;
|
||||
return bcwc_isp_cmd(dev_priv, CISP_CMD_CH_START, &cmd, sizeof(cmd), NULL);
|
||||
}
|
||||
|
||||
int bcwc_isp_cmd_channel_stop(struct bcwc_private *dev_priv)
|
||||
{
|
||||
struct isp_cmd_channel_stop cmd;
|
||||
|
||||
cmd.channel = 0;
|
||||
pr_debug("sending channel stop cmd to firmware\n");
|
||||
return bcwc_isp_cmd(dev_priv, CISP_CMD_CH_STOP, &cmd, sizeof(cmd), NULL);
|
||||
}
|
||||
|
||||
int bcwc_isp_cmd_stop(struct bcwc_private *dev_priv)
|
||||
{
|
||||
@@ -357,14 +369,14 @@ int isp_powerdown(struct bcwc_private *dev_priv)
|
||||
BCWC_ISP_REG_WRITE(0xf7fbdff9, 0xc3000);
|
||||
bcwc_isp_cmd_powerdown(dev_priv);
|
||||
|
||||
for (retries = 0; retries < 1000; retries++) {
|
||||
for (retries = 0; retries < 100; retries++) {
|
||||
reg = BCWC_ISP_REG_READ(0xc3000);
|
||||
if (reg == 0x8042006)
|
||||
break;
|
||||
mdelay(10);
|
||||
}
|
||||
|
||||
if (retries >= 1000) {
|
||||
if (retries >= 100) {
|
||||
dev_info(&dev_priv->pdev->dev, "deinit failed!\n");
|
||||
return -EIO;
|
||||
}
|
||||
@@ -399,6 +411,7 @@ int isp_uninit(struct bcwc_private *dev_priv)
|
||||
BCWC_ISP_REG_WRITE(0xffffffff, 0x41024);
|
||||
isp_free_channel_info(dev_priv);
|
||||
isp_free_set_file(dev_priv);
|
||||
isp_mem_destroy(dev_priv->firmware);
|
||||
kfree(dev_priv->mem);
|
||||
return 0;
|
||||
}
|
||||
@@ -465,11 +478,27 @@ int bcwc_isp_cmd_channel_info(struct bcwc_private *dev_priv)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int bcwc_isp_cmd_camera_config(struct bcwc_private *dev_priv)
|
||||
{
|
||||
struct isp_cmd_config cmd;
|
||||
int ret, len;
|
||||
|
||||
pr_debug("sending camera config\n");
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
|
||||
len = sizeof(cmd);
|
||||
ret = bcwc_isp_cmd(dev_priv, CISP_CMD_CONFIG_GET, &cmd, sizeof(cmd), &len);
|
||||
if (!ret)
|
||||
print_hex_dump_bytes("CAMINFO ", DUMP_PREFIX_OFFSET, &cmd, sizeof(cmd));
|
||||
return ret;
|
||||
}
|
||||
|
||||
int bcwc_isp_cmd_channel_camera_config(struct bcwc_private *dev_priv)
|
||||
{
|
||||
struct isp_cmd_channel_camera_config cmd;
|
||||
int ret, len, i;
|
||||
|
||||
char prefix[16];
|
||||
pr_debug("sending ch camera config\n");
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
@@ -480,7 +509,8 @@ int bcwc_isp_cmd_channel_camera_config(struct bcwc_private *dev_priv)
|
||||
ret = bcwc_isp_cmd(dev_priv, CISP_CMD_CH_CAMERA_CONFIG_GET, &cmd, sizeof(cmd), &len);
|
||||
if (ret)
|
||||
break;
|
||||
print_hex_dump_bytes("CHINFO ", DUMP_PREFIX_OFFSET, &cmd, sizeof(cmd));
|
||||
snprintf(prefix, sizeof(prefix)-1, "CAMCONF%d ", i);
|
||||
print_hex_dump_bytes(prefix, DUMP_PREFIX_OFFSET, &cmd, sizeof(cmd));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -517,7 +547,7 @@ int bcwc_isp_cmd_channel_crop_set(struct bcwc_private *dev_priv, int channel,
|
||||
return bcwc_isp_cmd(dev_priv, CISP_CMD_CH_CROP_SET, &cmd, sizeof(cmd), &len);
|
||||
}
|
||||
|
||||
int bcwc_isp_cmd_channel_output_config_set(struct bcwc_private *dev_priv, int channel, int x, int y)
|
||||
int bcwc_isp_cmd_channel_output_config_set(struct bcwc_private *dev_priv, int channel, int x, int y, int pixelformat)
|
||||
{
|
||||
struct isp_cmd_channel_output_config cmd;
|
||||
int len;
|
||||
@@ -525,11 +555,19 @@ int bcwc_isp_cmd_channel_output_config_set(struct bcwc_private *dev_priv, int ch
|
||||
pr_debug("output config: [%d, %d]\n", x, y);
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
// cmd.channel = channel;
|
||||
cmd.x1 = x;
|
||||
cmd.x2 = x;
|
||||
cmd.channel = channel;
|
||||
cmd.x1 = x; /* Y size */
|
||||
cmd.x2 = x * 2; /* Chroma size? */
|
||||
cmd.x3 = x;
|
||||
cmd.y1 = y;
|
||||
|
||||
/* pixel formats:
|
||||
* 0 - plane 0 Y plane 1 UV
|
||||
1 - YUYV
|
||||
2 - YVYU
|
||||
*/
|
||||
cmd.pixelformat = pixelformat;
|
||||
cmd.unknown3 = 0;
|
||||
cmd.unknown5 = 0x7ff;
|
||||
len = sizeof(cmd);
|
||||
return bcwc_isp_cmd(dev_priv, CISP_CMD_CH_OUTPUT_CONFIG_SET, &cmd, sizeof(cmd), &len);
|
||||
@@ -549,12 +587,25 @@ int bcwc_isp_cmd_channel_recycle_mode(struct bcwc_private *dev_priv, int channel
|
||||
return bcwc_isp_cmd(dev_priv, CISP_CMD_CH_BUFFER_RECYCLE_MODE_SET, &cmd, sizeof(cmd), &len);
|
||||
}
|
||||
|
||||
int bcwc_isp_cmd_channel_buffer_return(struct bcwc_private *dev_priv, int channel)
|
||||
{
|
||||
struct isp_cmd_channel_buffer_return cmd;
|
||||
int len;
|
||||
|
||||
pr_debug("buffer return\n");
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.channel = channel;
|
||||
len = sizeof(cmd);
|
||||
return bcwc_isp_cmd(dev_priv, CISP_CMD_CH_BUFFER_RETURN, &cmd, sizeof(cmd), &len);
|
||||
}
|
||||
|
||||
int bcwc_isp_cmd_channel_recycle_start(struct bcwc_private *dev_priv, int channel)
|
||||
{
|
||||
struct isp_cmd_channel_recycle_mode cmd;
|
||||
int len;
|
||||
|
||||
pr_debug("start recycle");
|
||||
pr_debug("start recycle\n");
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.channel = channel;
|
||||
@@ -567,7 +618,7 @@ int bcwc_isp_cmd_channel_drc_start(struct bcwc_private *dev_priv, int channel)
|
||||
struct isp_cmd_channel_drc_start cmd;
|
||||
int len;
|
||||
|
||||
pr_debug("start drc");
|
||||
pr_debug("start drc\n");
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.channel = channel;
|
||||
@@ -580,7 +631,7 @@ int bcwc_isp_cmd_channel_tone_curve_adaptation_start(struct bcwc_private *dev_pr
|
||||
struct isp_cmd_channel_tone_curve_adaptation_start cmd;
|
||||
int len;
|
||||
|
||||
pr_debug("start drc");
|
||||
pr_debug("tone curve adaptation start\n");
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.channel = channel;
|
||||
@@ -593,7 +644,7 @@ int bcwc_isp_cmd_channel_sif_pixel_format(struct bcwc_private *dev_priv, int cha
|
||||
struct isp_cmd_channel_sif_format_set cmd;
|
||||
int len;
|
||||
|
||||
pr_debug("set pixel format %d, %d", param1, param2);
|
||||
pr_debug("set pixel format %d, %d\n", param1, param2);
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.channel = channel;
|
||||
@@ -608,7 +659,7 @@ int bcwc_isp_cmd_channel_error_handling_config(struct bcwc_private *dev_priv, in
|
||||
struct isp_cmd_channel_camera_err_handle_config cmd;
|
||||
int len;
|
||||
|
||||
pr_debug("set error handling config %d, %d", param1, param2);
|
||||
pr_debug("set error handling config %d, %d\n", param1, param2);
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.channel = channel;
|
||||
@@ -623,7 +674,7 @@ int bcwc_isp_cmd_channel_streaming_mode(struct bcwc_private *dev_priv, int chann
|
||||
struct isp_cmd_channel_streaming_mode cmd;
|
||||
int len;
|
||||
|
||||
pr_debug("set streaming mode %d", mode);
|
||||
pr_debug("set streaming mode %d\n", mode);
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.channel = channel;
|
||||
@@ -637,7 +688,7 @@ int bcwc_isp_cmd_channel_frame_rate_min(struct bcwc_private *dev_priv, int chann
|
||||
struct isp_cmd_channel_frame_rate_set cmd;
|
||||
int len;
|
||||
|
||||
pr_debug("set ae frame rate min %d", rate);
|
||||
pr_debug("set ae frame rate min %d\n", rate);
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.channel = channel;
|
||||
@@ -651,7 +702,7 @@ int bcwc_isp_cmd_channel_frame_rate_max(struct bcwc_private *dev_priv, int chann
|
||||
struct isp_cmd_channel_frame_rate_set cmd;
|
||||
int len;
|
||||
|
||||
pr_debug("set ae frame rate max %d", rate);
|
||||
pr_debug("set ae frame rate max %d\n", rate);
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.channel = channel;
|
||||
@@ -660,6 +711,155 @@ int bcwc_isp_cmd_channel_frame_rate_max(struct bcwc_private *dev_priv, int chann
|
||||
return bcwc_isp_cmd(dev_priv, CISP_CMD_CH_AE_FRAME_RATE_MAX_SET, &cmd, sizeof(cmd), &len);
|
||||
}
|
||||
|
||||
int bcwc_isp_cmd_channel_ae_speed_set(struct bcwc_private *dev_priv, int channel, int speed)
|
||||
{
|
||||
struct isp_cmd_channel_ae_speed_set cmd;
|
||||
int len;
|
||||
|
||||
pr_debug("set ae speed %d\n", speed);
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.channel = channel;
|
||||
cmd.speed = speed;
|
||||
len = sizeof(cmd);
|
||||
return bcwc_isp_cmd(dev_priv, CISP_CMD_CH_AE_SPEED_SET, &cmd, sizeof(cmd), &len);
|
||||
}
|
||||
|
||||
int bcwc_isp_cmd_channel_ae_stability_set(struct bcwc_private *dev_priv, int channel, int stability)
|
||||
{
|
||||
struct isp_cmd_channel_ae_stability_set cmd;
|
||||
int len;
|
||||
|
||||
pr_debug("set ae stability %d\n", stability);
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.channel = channel;
|
||||
cmd.stability = stability;
|
||||
len = sizeof(cmd);
|
||||
return bcwc_isp_cmd(dev_priv, CISP_CMD_CH_AE_STABILITY_SET, &cmd, sizeof(cmd), &len);
|
||||
}
|
||||
|
||||
int bcwc_isp_cmd_channel_ae_stability_to_stable_set(struct bcwc_private *dev_priv, int channel, int value)
|
||||
{
|
||||
struct isp_cmd_channel_ae_stability_to_stable_set cmd;
|
||||
int len;
|
||||
|
||||
pr_debug("set ae stability to stable %d\n", value);
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.channel = channel;
|
||||
cmd.value = value;
|
||||
len = sizeof(cmd);
|
||||
return bcwc_isp_cmd(dev_priv, CISP_CMD_CH_AE_STABILITY_TO_STABLE_SET, &cmd, sizeof(cmd), &len);
|
||||
}
|
||||
|
||||
int bcwc_isp_cmd_channel_face_detection_start(struct bcwc_private *dev_priv, int channel)
|
||||
{
|
||||
struct isp_cmd_channel_face_detection_start cmd;
|
||||
int len;
|
||||
|
||||
pr_debug("face detection start\n");
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.channel = channel;
|
||||
len = sizeof(cmd);
|
||||
return bcwc_isp_cmd(dev_priv, CISP_CMD_CH_FACE_DETECTION_START, &cmd, sizeof(cmd), &len);
|
||||
}
|
||||
|
||||
int bcwc_isp_cmd_channel_face_detection_enable(struct bcwc_private *dev_priv, int channel)
|
||||
{
|
||||
struct isp_cmd_channel_face_detection_enable cmd;
|
||||
int len;
|
||||
|
||||
pr_debug("face detection enable\n");
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.channel = channel;
|
||||
len = sizeof(cmd);
|
||||
return bcwc_isp_cmd(dev_priv, CISP_CMD_CH_FACE_DETECTION_ENABLE, &cmd, sizeof(cmd), &len);
|
||||
}
|
||||
|
||||
int bcwc_isp_cmd_channel_temporal_filter_start(struct bcwc_private *dev_priv, int channel)
|
||||
{
|
||||
struct isp_cmd_channel_temporal_filter_start cmd;
|
||||
int len;
|
||||
|
||||
pr_debug("temporal filter start\n");
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.channel = channel;
|
||||
len = sizeof(cmd);
|
||||
return bcwc_isp_cmd(dev_priv, CISP_CMD_APPLE_CH_TEMPORAL_FILTER_START, &cmd, sizeof(cmd), &len);
|
||||
}
|
||||
|
||||
int bcwc_isp_cmd_channel_temporal_filter_enable(struct bcwc_private *dev_priv, int channel)
|
||||
{
|
||||
struct isp_cmd_channel_temporal_filter_enable cmd;
|
||||
int len;
|
||||
|
||||
pr_debug("temporal filter enable\n");
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.channel = channel;
|
||||
len = sizeof(cmd);
|
||||
return bcwc_isp_cmd(dev_priv, CISP_CMD_APPLE_CH_TEMPORAL_FILTER_ENABLE, &cmd, sizeof(cmd), &len);
|
||||
}
|
||||
|
||||
int bcwc_isp_cmd_channel_motion_history_start(struct bcwc_private *dev_priv, int channel)
|
||||
{
|
||||
struct isp_cmd_channel_motion_history_start cmd;
|
||||
int len;
|
||||
|
||||
pr_debug("motion history start\n");
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.channel = channel;
|
||||
len = sizeof(cmd);
|
||||
return bcwc_isp_cmd(dev_priv, CISP_CMD_APPLE_CH_MOTION_HISTORY_START, &cmd, sizeof(cmd), &len);
|
||||
}
|
||||
|
||||
int bcwc_isp_cmd_channel_ae_metering_mode_set(struct bcwc_private *dev_priv, int channel, int mode)
|
||||
{
|
||||
struct isp_cmd_channel_ae_metering_mode_set cmd;
|
||||
int len;
|
||||
|
||||
pr_debug("ae metering mode %d\n", mode);
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.channel = channel;
|
||||
cmd.mode = mode;
|
||||
len = sizeof(cmd);
|
||||
return bcwc_isp_cmd(dev_priv, CISP_CMD_APPLE_CH_AE_METERING_MODE_SET, &cmd, sizeof(cmd), &len);
|
||||
}
|
||||
|
||||
int bcwc_isp_cmd_channel_brightness_set(struct bcwc_private *dev_priv, int channel, int brightness)
|
||||
{
|
||||
struct isp_cmd_channel_brightness_set cmd;
|
||||
int len;
|
||||
|
||||
pr_debug("set brightness %d\n", brightness);
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.channel = channel;
|
||||
cmd.brightness = brightness;
|
||||
len = sizeof(cmd);
|
||||
return bcwc_isp_cmd(dev_priv, CISP_CMD_CH_SCALER_BRIGHTNESS_SET, &cmd, sizeof(cmd), &len);
|
||||
}
|
||||
|
||||
int bcwc_isp_cmd_channel_contrast_set(struct bcwc_private *dev_priv, int channel, int contrast)
|
||||
{
|
||||
struct isp_cmd_channel_contrast_set cmd;
|
||||
int len;
|
||||
|
||||
pr_debug("set contrast %d\n", contrast);
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.channel = channel;
|
||||
cmd.contrast = contrast;
|
||||
len = sizeof(cmd);
|
||||
return bcwc_isp_cmd(dev_priv, CISP_CMD_CH_SCALER_CONTRAST_SET, &cmd, sizeof(cmd), &len);
|
||||
}
|
||||
|
||||
int isp_init(struct bcwc_private *dev_priv)
|
||||
{
|
||||
struct isp_mem_obj *ipc_queue, *heap, *fw_args;
|
||||
|
||||
94
bcwc_isp.h
94
bcwc_isp.h
@@ -28,6 +28,7 @@
|
||||
#define FTHD_MEM_CMD 5
|
||||
#define FTHD_MEM_SHAREDMALLOC 6
|
||||
#define FTHD_MEM_SET_FILE 7
|
||||
#define FTHD_MEM_BUFFER 8
|
||||
|
||||
#define FTHD_MEM_SIZE 0x8000000 /* 128mb */
|
||||
#define FTHD_MEM_FW_SIZE 0x800000 /* 8mb */
|
||||
@@ -478,6 +479,17 @@ struct isp_cmd_print_enable {
|
||||
u32 enable;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct isp_cmd_config {
|
||||
u32 field0;
|
||||
u32 field4;
|
||||
u32 field8;
|
||||
u32 fieldc;
|
||||
u32 field10;
|
||||
u32 field14;
|
||||
u32 field18;
|
||||
u32 field1c;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct isp_cmd_set_loadfile {
|
||||
u32 unknown;
|
||||
u32 addr;
|
||||
@@ -507,11 +519,11 @@ struct isp_cmd_channel_set_crop {
|
||||
};
|
||||
|
||||
struct isp_cmd_channel_output_config {
|
||||
u32 unknown0;
|
||||
u32 channel;
|
||||
u32 x1;
|
||||
u32 y1;
|
||||
u32 unknown3;
|
||||
u32 unknown4;
|
||||
u32 pixelformat;
|
||||
u32 x2;
|
||||
u32 x3;
|
||||
u32 unknown5;
|
||||
@@ -560,6 +572,68 @@ struct isp_cmd_channel_frame_rate_set {
|
||||
u16 rate;
|
||||
};
|
||||
|
||||
struct isp_cmd_channel_ae_speed_set {
|
||||
u32 channel;
|
||||
u16 speed;
|
||||
};
|
||||
|
||||
struct isp_cmd_channel_ae_stability_set {
|
||||
u32 channel;
|
||||
u16 stability;
|
||||
};
|
||||
|
||||
struct isp_cmd_channel_ae_stability_to_stable_set {
|
||||
u32 channel;
|
||||
u16 value;
|
||||
};
|
||||
|
||||
struct isp_cmd_channel_face_detection_start {
|
||||
u32 channel;
|
||||
};
|
||||
|
||||
struct isp_cmd_channel_face_detection_enable {
|
||||
u32 channel;
|
||||
};
|
||||
|
||||
struct isp_cmd_channel_temporal_filter_start {
|
||||
u32 channel;
|
||||
};
|
||||
|
||||
struct isp_cmd_channel_temporal_filter_enable {
|
||||
u32 channel;
|
||||
};
|
||||
|
||||
struct isp_cmd_channel_motion_history_start {
|
||||
u32 channel;
|
||||
};
|
||||
|
||||
struct isp_cmd_channel_ae_metering_mode_set {
|
||||
u32 channel;
|
||||
u32 mode;
|
||||
};
|
||||
|
||||
struct isp_cmd_channel_start {
|
||||
u32 channel;
|
||||
};
|
||||
|
||||
struct isp_cmd_channel_stop {
|
||||
u32 channel;
|
||||
};
|
||||
|
||||
struct isp_cmd_channel_brightness_set {
|
||||
u32 channel;
|
||||
u32 brightness;
|
||||
};
|
||||
|
||||
struct isp_cmd_channel_contrast_set {
|
||||
u32 channel;
|
||||
u32 contrast;
|
||||
};
|
||||
|
||||
struct isp_cmd_channel_buffer_return {
|
||||
u32 channel;
|
||||
};
|
||||
|
||||
#define to_isp_mem_obj(x) container_of((x), struct isp_mem_obj, base)
|
||||
|
||||
extern int isp_init(struct bcwc_private *dev_priv);
|
||||
@@ -577,10 +651,11 @@ extern int bcwc_isp_cmd_print_enable(struct bcwc_private *dev_priv, int enable);
|
||||
extern int bcwc_isp_cmd_set_loadfile(struct bcwc_private *dev_priv);
|
||||
extern int bcwc_isp_cmd_channel_info(struct bcwc_private *dev_priv);
|
||||
extern int bcwc_isp_cmd_channel_start(struct bcwc_private *dev_priv);
|
||||
extern int bcwc_isp_cmd_channel_stop(struct bcwc_private *dev_priv);
|
||||
extern int bcwc_isp_cmd_channel_camera_config(struct bcwc_private *dev_priv);
|
||||
extern int bcwc_isp_cmd_channel_crop_set(struct bcwc_private *dev_priv, int channel,
|
||||
int x1, int y1, int x2, int y2);
|
||||
extern int bcwc_isp_cmd_channel_output_config_set(struct bcwc_private *dev_priv, int channel, int x, int y);
|
||||
extern int bcwc_isp_cmd_channel_output_config_set(struct bcwc_private *dev_priv, int channel, int x, int y, int pixelformat);
|
||||
extern int bcwc_isp_cmd_channel_recycle_mode(struct bcwc_private *dev_priv, int channel, int mode);
|
||||
extern int bcwc_isp_cmd_channel_recycle_start(struct bcwc_private *dev_priv, int channel);
|
||||
extern int bcwc_isp_cmd_channel_camera_config_select(struct bcwc_private *dev_priv, int channel, int config);
|
||||
@@ -591,4 +666,17 @@ extern int bcwc_isp_cmd_channel_error_handling_config(struct bcwc_private *dev_p
|
||||
extern int bcwc_isp_cmd_channel_streaming_mode(struct bcwc_private *dev_priv, int channel, int mode);
|
||||
extern int bcwc_isp_cmd_channel_frame_rate_min(struct bcwc_private *dev_priv, int channel, int rate);
|
||||
extern int bcwc_isp_cmd_channel_frame_rate_max(struct bcwc_private *dev_priv, int channel, int rate);
|
||||
extern int bcwc_isp_cmd_camera_config(struct bcwc_private *dev_priv);
|
||||
extern int bcwc_isp_cmd_channel_ae_speed_set(struct bcwc_private *dev_priv, int channel, int speed);
|
||||
extern int bcwc_isp_cmd_channel_ae_stability_set(struct bcwc_private *dev_priv, int channel, int stability);
|
||||
extern int bcwc_isp_cmd_channel_ae_stability_to_stable_set(struct bcwc_private *dev_priv, int channel, int value);
|
||||
extern int bcwc_isp_cmd_channel_face_detection_enable(struct bcwc_private *dev_priv, int channel);
|
||||
extern int bcwc_isp_cmd_channel_face_detection_start(struct bcwc_private *dev_priv, int channel);
|
||||
extern int bcwc_isp_cmd_channel_temporal_filter_start(struct bcwc_private *dev_priv, int channel);
|
||||
extern int bcwc_isp_cmd_channel_temporal_filter_enable(struct bcwc_private *dev_priv, int channel);
|
||||
extern int bcwc_isp_cmd_channel_motion_history_start(struct bcwc_private *dev_priv, int channel);
|
||||
extern int bcwc_isp_cmd_channel_ae_metering_mode_set(struct bcwc_private *dev_priv, int channel, int mode);
|
||||
extern int bcwc_isp_cmd_channel_brightness_set(struct bcwc_private *dev_priv, int channel, int brightness);
|
||||
extern int bcwc_isp_cmd_channel_contrast_set(struct bcwc_private *dev_priv, int channel, int contrast);
|
||||
extern int bcwc_isp_cmd_channel_buffer_return(struct bcwc_private *dev_priv, int channel);
|
||||
#endif
|
||||
|
||||
@@ -40,19 +40,14 @@ void bcwc_channel_ringbuf_dump(struct bcwc_private *dev_priv, struct fw_channel
|
||||
char pos;
|
||||
int i;
|
||||
|
||||
pr_debug("dumping %d [%s]\n", chan->type, chan->name);
|
||||
for( i = 0; i < chan->size; i++) {
|
||||
if (chan->ringbuf.send_idx == i && chan->ringbuf.recv_idx == i)
|
||||
if (chan->ringbuf.idx == i)
|
||||
pos = '*';
|
||||
else if (chan->ringbuf.send_idx == i)
|
||||
pos = 'S';
|
||||
else if (chan->ringbuf.recv_idx == i)
|
||||
pos = 'R';
|
||||
else
|
||||
pos = ' ';
|
||||
entry = dev_priv->s2_mem + chan->offset + i * sizeof(struct bcwc_ringbuf_entry);
|
||||
pr_debug("%c%3.3d: ADDRESS %08x REQUEST_SIZE %08x RESPONSE_SIZE %08x\n", pos, i, entry->address_flags,
|
||||
entry->request_size, entry->response_size);
|
||||
pr_debug("%s: %c%3.3d: ADDRESS %08x REQUEST_SIZE %08x RESPONSE_SIZE %08x\n", chan->name,
|
||||
pos, i, entry->address_flags, entry->request_size, entry->response_size);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -62,22 +57,22 @@ void bcwc_channel_ringbuf_init(struct bcwc_private *dev_priv, struct fw_channel
|
||||
struct bcwc_ringbuf_entry *entry;
|
||||
int i;
|
||||
|
||||
chan->ringbuf.recv_idx = 0;
|
||||
chan->ringbuf.send_idx = 0;
|
||||
chan->ringbuf.sent_cnt = 0;
|
||||
chan->ringbuf.recv_cnt = 0;
|
||||
chan->ringbuf.idx = 0;
|
||||
chan->ringbuf.phys_offset = chan->offset;
|
||||
chan->ringbuf.virt_addr = dev_priv->s2_mem + chan->offset;
|
||||
|
||||
if (chan->type == RINGBUF_TYPE_H2T) {
|
||||
entry = (struct bcwc_ringbuf_entry *)chan->ringbuf.virt_addr;
|
||||
pr_debug("clearing ringbuf %s at %p (size %d)\n", chan->name, entry, chan->size);
|
||||
|
||||
spin_lock_irq(&dev_priv->rb_lock);
|
||||
for(i = 0; i < chan->size; i++) {
|
||||
entry->address_flags = 1;
|
||||
entry->request_size = 0;
|
||||
entry->response_size = 0;
|
||||
entry++;
|
||||
}
|
||||
spin_unlock_irq(&dev_priv->rb_lock);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,19 +80,27 @@ struct bcwc_ringbuf_entry *bcwc_channel_ringbuf_send(struct bcwc_private *dev_pr
|
||||
u32 data_offset, u32 request_size, u32 response_size)
|
||||
{
|
||||
struct bcwc_ringbuf_entry *entry;
|
||||
pr_debug("%s: TX pos %d\n", chan->name, chan->ringbuf.send_idx);
|
||||
entry = get_entry_addr(dev_priv, chan, chan->ringbuf.send_idx++);
|
||||
if (chan->ringbuf.send_idx >= chan->size) {
|
||||
chan->ringbuf.send_idx = 0;
|
||||
pr_debug("send entry %p offset %08x\n", entry, data_offset);
|
||||
int pos = chan->ringbuf.idx;
|
||||
|
||||
entry = get_entry_addr(dev_priv, chan, chan->ringbuf.idx++);
|
||||
if (chan->ringbuf.idx >= chan->size) {
|
||||
pr_debug("%s: reset tx pointer\n", chan->name);
|
||||
chan->ringbuf.idx = 0;
|
||||
}
|
||||
pr_debug("%s: send entry %p offset %08x pos %d\n", chan->name, entry, data_offset, pos);
|
||||
|
||||
spin_lock_irq(&dev_priv->rb_lock);
|
||||
entry->request_size = request_size;
|
||||
entry->response_size = response_size;
|
||||
entry->address_flags = data_offset | (chan->type == 0 ? 0 : 1);
|
||||
spin_unlock_irq(&dev_priv->rb_lock);
|
||||
|
||||
pr_debug("address_flags %x, request size %x response size %x\n",
|
||||
entry->address_flags, entry->request_size, entry->response_size);
|
||||
// pr_debug("address_flags %x, request size %x response size %x\n",
|
||||
// entry->address_flags, entry->request_size, entry->response_size);
|
||||
wmb();
|
||||
spin_lock_irq(&dev_priv->io_lock);
|
||||
BCWC_ISP_REG_WRITE(0x10 << chan->source, ISP_REG_41020);
|
||||
spin_unlock_irq(&dev_priv->io_lock);
|
||||
return entry;
|
||||
}
|
||||
|
||||
@@ -106,9 +109,11 @@ struct bcwc_ringbuf_entry *bcwc_channel_ringbuf_get_entry(struct bcwc_private *d
|
||||
{
|
||||
struct bcwc_ringbuf_entry *entry;
|
||||
|
||||
entry = get_entry_addr(dev_priv, chan, chan->ringbuf.recv_idx);
|
||||
if (chan->ringbuf.recv_idx > chan->size)
|
||||
chan->ringbuf.recv_idx = 0;
|
||||
spin_lock_irq(&dev_priv->rb_lock);
|
||||
entry = get_entry_addr(dev_priv, chan, chan->ringbuf.idx);
|
||||
if (chan->ringbuf.idx > chan->size)
|
||||
chan->ringbuf.idx = 0;
|
||||
spin_unlock_irq(&dev_priv->rb_lock);
|
||||
return entry;
|
||||
}
|
||||
|
||||
@@ -117,18 +122,23 @@ void bcwc_channel_ringbuf_mark_entry_available(struct bcwc_private *dev_priv,
|
||||
{
|
||||
struct bcwc_ringbuf_entry *entry;
|
||||
|
||||
entry = get_entry_addr(dev_priv, chan, chan->ringbuf.recv_idx++);
|
||||
spin_lock_irq(&dev_priv->rb_lock);
|
||||
entry = get_entry_addr(dev_priv, chan, chan->ringbuf.idx++);
|
||||
entry->address_flags = 1;
|
||||
entry->request_size = 0;
|
||||
entry->response_size = 0;
|
||||
spin_unlock_irq(&dev_priv->rb_lock);
|
||||
}
|
||||
|
||||
int bcwc_channel_ringbuf_entry_available(struct bcwc_private *dev_priv,
|
||||
struct fw_channel *chan)
|
||||
{
|
||||
struct bcwc_ringbuf_entry *entry;
|
||||
int ret;
|
||||
|
||||
entry = get_entry_addr(dev_priv, chan, chan->ringbuf.recv_idx);
|
||||
return (!(entry->address_flags & 1));
|
||||
spin_lock_irq(&dev_priv->rb_lock);
|
||||
entry = get_entry_addr(dev_priv, chan, chan->ringbuf.idx);
|
||||
ret = !(entry->address_flags & 1) ^ (chan->type == 0);
|
||||
spin_unlock_irq(&dev_priv->rb_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,10 +29,7 @@ enum ringbuf_type_t {
|
||||
struct bcwc_ringbuf {
|
||||
void *doorbell;
|
||||
u32 phys_offset;
|
||||
int recv_idx;
|
||||
int send_idx;
|
||||
int recv_cnt;
|
||||
int sent_cnt;
|
||||
int idx;
|
||||
u8 *virt_addr;
|
||||
};
|
||||
|
||||
|
||||
589
bcwc_v4l2.c
589
bcwc_v4l2.c
@@ -1,4 +1,3 @@
|
||||
|
||||
/*
|
||||
* Broadcom PCIe 1570 webcam driver
|
||||
*
|
||||
@@ -22,139 +21,294 @@
|
||||
#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/videobuf-dma-sg.h>
|
||||
#include <media/videobuf2-dma-sg.h>
|
||||
#include "bcwc_drv.h"
|
||||
#include "bcwc_hw.h"
|
||||
#include "bcwc_isp.h"
|
||||
#include "bcwc_ringbuf.h"
|
||||
#include "bcwc_buffer.h"
|
||||
|
||||
static int bcwc_vb_buf_setup(struct videobuf_queue *q,
|
||||
unsigned int *count, unsigned int *size)
|
||||
{
|
||||
struct bcwc_private *priv = q->priv_data;
|
||||
pr_debug("%s: %d\n", __FUNCTION__, priv->user_format.sizeimage);
|
||||
*size = priv->user_format.sizeimage;
|
||||
if (*count == 0 || *count > 6)
|
||||
*count = 6;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcwc_vb_buf_prepare(struct videobuf_queue *q,
|
||||
struct videobuf_buffer *vb, enum v4l2_field field)
|
||||
{
|
||||
struct bcwc_private *priv = q->priv_data;
|
||||
int ret;
|
||||
|
||||
pr_debug("%s\n", __FUNCTION__);
|
||||
|
||||
vb->size = priv->user_format.sizeimage;
|
||||
vb->width = priv->user_format.width;
|
||||
vb->height = priv->user_format.height;
|
||||
vb->field = field;
|
||||
|
||||
if (vb->state == VIDEOBUF_NEEDS_INIT) {
|
||||
ret = videobuf_iolock(q, vb, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
#define BCWC_FMT(_desc, _x, _y, _sizeimage, _planes, _pixfmt, _range, _x1, _y1, _x2, _y2) \
|
||||
{ \
|
||||
.fmt.width = (_x), \
|
||||
.fmt.height = (_y), \
|
||||
.fmt.sizeimage = (_sizeimage), \
|
||||
.fmt.pixelformat = (_pixfmt), \
|
||||
.planes = (_planes), \
|
||||
.desc = (_desc), \
|
||||
.range = (_range), \
|
||||
.x1 = (_x1), \
|
||||
.y1 = (_y1), \
|
||||
.x2 = (_x2), \
|
||||
.y2 = (_y2) \
|
||||
}
|
||||
vb->state = VIDEOBUF_PREPARED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bcwc_vb_buf_queue(struct videobuf_queue *q,
|
||||
struct videobuf_buffer *vb)
|
||||
{
|
||||
struct bcwc_private *priv = q->priv_data;
|
||||
pr_debug("%s\n", __FUNCTION__);
|
||||
vb->state = VIDEOBUF_QUEUED;
|
||||
list_add_tail(&vb->queue, &priv->buffer_queue);
|
||||
}
|
||||
|
||||
static void bcwc_vb_buf_release(struct videobuf_queue *q,
|
||||
struct videobuf_buffer *vb)
|
||||
{
|
||||
struct bcwc_private *priv = q->priv_data;
|
||||
pr_debug("%s\n", __FUNCTION__);
|
||||
videobuf_dma_unmap(&priv->pdev->dev, videobuf_to_dma(vb));
|
||||
videobuf_dma_free(videobuf_to_dma(vb));
|
||||
vb->state = VIDEOBUF_NEEDS_INIT;
|
||||
}
|
||||
|
||||
static const struct videobuf_queue_ops bcwc_vb_ops = {
|
||||
.buf_setup = bcwc_vb_buf_setup,
|
||||
.buf_prepare = bcwc_vb_buf_prepare,
|
||||
.buf_queue = bcwc_vb_buf_queue,
|
||||
.buf_release = bcwc_vb_buf_release,
|
||||
struct bcwc_fmt bcwc_formats[] = {
|
||||
BCWC_FMT("1280x720 YUYV (4:2:2)", 1280, 720, 1280 * 720 * 2, 1, V4L2_PIX_FMT_YUYV, 0, 0, 0, 1280, 720),
|
||||
BCWC_FMT("1280x720 YVYU (4:2:2)", 1280, 720, 1280 * 720 * 2, 1, V4L2_PIX_FMT_YVYU, 0, 0, 0, 1280, 720),
|
||||
BCWC_FMT("1280x720 NV16", 1280, 720, 1280 * 720, 2, V4L2_PIX_FMT_NV16, 0, 0, 0, 1280, 720),
|
||||
BCWC_FMT("640x480 YUYV (4:2:2)", 640, 480, 640 * 480 * 2, 1, V4L2_PIX_FMT_YUYV, 0, 160, 0, 960, 720),
|
||||
BCWC_FMT("640x480 YVYU (4:2:2)", 640, 480, 640 * 480 * 2, 1, V4L2_PIX_FMT_YVYU, 0, 160, 0, 960, 720),
|
||||
BCWC_FMT("640x480 NV16", 640, 480, 640 * 480, 2, V4L2_PIX_FMT_NV16, 0, 160, 0, 960, 720),
|
||||
BCWC_FMT("320x240 YUYV (4:2:2)", 320, 240, 320 * 240 * 2, 1, V4L2_PIX_FMT_YUYV, 0, 160, 0, 960, 720),
|
||||
BCWC_FMT("320x240 YVYU (4:2:2)", 320, 240, 320 * 240 * 2, 1, V4L2_PIX_FMT_YVYU, 0, 160, 0, 960, 720),
|
||||
BCWC_FMT("320x240 NV16", 320, 240, 320 * 240, 2, V4L2_PIX_FMT_NV16, 0, 160, 0, 960, 720),
|
||||
};
|
||||
|
||||
static int bcwc_v4l2_open(struct file *filp)
|
||||
static int bcwc_buffer_queue_setup(struct vb2_queue *vq,
|
||||
const struct v4l2_format *fmt,
|
||||
unsigned int *nbuffers, unsigned int *nplanes,
|
||||
unsigned int sizes[], void *alloc_ctxs[])
|
||||
{
|
||||
struct bcwc_private *priv = video_drvdata(filp);
|
||||
pr_info("%s: %p\n", __FUNCTION__, priv);
|
||||
struct bcwc_private *dev_priv = vb2_get_drv_priv(vq);
|
||||
int i;
|
||||
pr_debug("%s: nbuffers %d, nplanes %d, sizes[0]: %d\n", __FUNCTION__,
|
||||
*nbuffers, *nplanes, sizes[0]);
|
||||
|
||||
mutex_lock(&priv->ioctl_lock);
|
||||
videobuf_queue_sg_init(&priv->vb_queue, &bcwc_vb_ops,
|
||||
&priv->pdev->dev, &priv->vb_queue_lock,
|
||||
V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
|
||||
sizeof(struct videobuf_buffer), priv, NULL);
|
||||
if (!dev_priv->fmt)
|
||||
return -EINVAL;
|
||||
|
||||
if (!priv->users++) {
|
||||
bcwc_isp_cmd_channel_start(priv);
|
||||
*nplanes = dev_priv->fmt->planes;
|
||||
for(i = 0; i < *nplanes; i++) {
|
||||
sizes[i] = dev_priv->fmt->fmt.sizeimage;
|
||||
alloc_ctxs[i] = dev_priv->alloc_ctx;
|
||||
}
|
||||
|
||||
mutex_unlock(&priv->ioctl_lock);
|
||||
*nbuffers = BCWC_BUFFERS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcwc_v4l2_release(struct file *filp)
|
||||
static void bcwc_buffer_cleanup(struct vb2_buffer *vb)
|
||||
{
|
||||
struct bcwc_private *priv = video_drvdata(filp);
|
||||
pr_info("%s\n", __FUNCTION__);
|
||||
mutex_lock(&priv->ioctl_lock);
|
||||
if (!--priv->users) {
|
||||
bcwc_isp_cmd_channel_stop(priv);
|
||||
struct bcwc_private *dev_priv = vb2_get_drv_priv(vb->vb2_queue);
|
||||
struct h2t_buf_ctx *ctx = NULL;
|
||||
int i;
|
||||
|
||||
pr_debug("%s: vb %p\n", __FUNCTION__, vb);
|
||||
for(i = 0; i < BCWC_BUFFERS; i++) {
|
||||
if (dev_priv->h2t_bufs[i].vb == vb) {
|
||||
ctx = dev_priv->h2t_bufs + i;
|
||||
break;
|
||||
};
|
||||
}
|
||||
if (!ctx) {
|
||||
pr_err("buffer not found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
videobuf_stop(&priv->vb_queue);
|
||||
videobuf_mmap_free(&priv->vb_queue);
|
||||
mutex_unlock(&priv->ioctl_lock);
|
||||
if (ctx->state == BUF_FREE)
|
||||
return;
|
||||
|
||||
ctx->state = BUF_FREE;
|
||||
ctx->vb = NULL;
|
||||
isp_mem_destroy(ctx->dma_desc_obj);
|
||||
for(i = 0; i < dev_priv->fmt->planes; i++) {
|
||||
iommu_free(dev_priv, ctx->plane[i]);
|
||||
ctx->plane[i] = NULL;
|
||||
}
|
||||
ctx->dma_desc_obj = NULL;
|
||||
}
|
||||
|
||||
static void bcwc_buffer_queue(struct vb2_buffer *vb)
|
||||
{
|
||||
struct bcwc_private *dev_priv = vb2_get_drv_priv(vb->vb2_queue);
|
||||
struct dma_descriptor_list *list;
|
||||
struct h2t_buf_ctx *ctx = NULL;
|
||||
|
||||
int i;
|
||||
|
||||
pr_debug("%s: vb %p\n", __FUNCTION__, vb);
|
||||
for(i = 0; i < BCWC_BUFFERS; i++) {
|
||||
if (dev_priv->h2t_bufs[i].vb == vb) {
|
||||
ctx = dev_priv->h2t_bufs + i;
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
if (!ctx) {
|
||||
pr_err("buffer not found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx->state != BUF_ALLOC) {
|
||||
pr_err("buffer busy\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!vb->vb2_queue->streaming) {
|
||||
pr_debug("not streaming\n");
|
||||
ctx->state = BUF_DRV_QUEUED;
|
||||
} else {
|
||||
list = ctx->dma_desc_list;
|
||||
list->field0 = 1;
|
||||
ctx->state = BUF_HW_QUEUED;
|
||||
wmb();
|
||||
pr_debug("%d: field0: %d, count %d, pool %d, addr0 0x%08x, addr1 0x%08x tag 0x%08llx vb = %p\n", i, list->field0,
|
||||
list->desc[i].count, list->desc[i].pool, list->desc[i].addr0, list->desc[i].addr1, list->desc[i].tag, ctx->vb);
|
||||
|
||||
bcwc_channel_ringbuf_send(dev_priv, dev_priv->channel_buf_h2t,
|
||||
ctx->dma_desc_obj->offset, 0x180, 0x30000000);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int bcwc_buffer_prepare(struct vb2_buffer *vb)
|
||||
{
|
||||
struct bcwc_private *dev_priv = vb2_get_drv_priv(vb->vb2_queue);
|
||||
struct sg_table *sgtable;
|
||||
struct h2t_buf_ctx *ctx = NULL;
|
||||
struct dma_descriptor_list *dma_list;
|
||||
int i;
|
||||
|
||||
pr_debug("vb = %p\n", vb);
|
||||
|
||||
for(i = 0; i < BCWC_BUFFERS; i++) {
|
||||
if (dev_priv->h2t_bufs[i].state == BUF_FREE ||
|
||||
(dev_priv->h2t_bufs[i].state == BUF_ALLOC && dev_priv->h2t_bufs[i].vb == vb)) {
|
||||
ctx = dev_priv->h2t_bufs + i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ctx)
|
||||
return -ENOBUFS;
|
||||
|
||||
if (ctx->state == BUF_FREE) {
|
||||
pr_debug("allocating new entry\n");
|
||||
ctx->dma_desc_obj = isp_mem_create(dev_priv, FTHD_MEM_BUFFER, 0x180);
|
||||
if (!ctx->dma_desc_obj)
|
||||
return -ENOMEM;
|
||||
|
||||
ctx->dma_desc_list = dev_priv->s2_mem + ctx->dma_desc_obj->offset;
|
||||
ctx->vb = vb;
|
||||
ctx->state = BUF_ALLOC;
|
||||
|
||||
for(i = 0; i < dev_priv->fmt->planes; i++) {
|
||||
sgtable = vb2_dma_sg_plane_desc(vb, i);
|
||||
ctx->plane[i] = iommu_allocate_sgtable(dev_priv, sgtable);
|
||||
}
|
||||
}
|
||||
|
||||
vb2_set_plane_payload(vb, 0, dev_priv->fmt->fmt.sizeimage);
|
||||
|
||||
dma_list = ctx->dma_desc_list;
|
||||
memset(dma_list, 0, 0x180);
|
||||
|
||||
dma_list->field0 = 1;
|
||||
dma_list->count = 1;
|
||||
dma_list->desc[0].count = 1;
|
||||
dma_list->desc[0].pool = 0x02;
|
||||
dma_list->desc[0].addr0 = (ctx->plane[0]->offset << 12) | 0xc0000000;
|
||||
|
||||
if (dev_priv->fmt->planes >= 2)
|
||||
dma_list->desc[0].addr1 = (ctx->plane[1]->offset << 12) | 0xc0000000;
|
||||
if (dev_priv->fmt->planes >= 3)
|
||||
dma_list->desc[0].addr2 = (ctx->plane[2]->offset << 12) | 0xc0000000;
|
||||
|
||||
dma_list->desc[0].tag = (u64)ctx;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t bcwc_v4l2_read(struct file *filp, char __user *buffer,
|
||||
size_t len, loff_t *pos)
|
||||
void bcwc_buffer_return_handler(struct bcwc_private *dev_priv, struct dma_descriptor_list *list, int size)
|
||||
{
|
||||
struct bcwc_private *priv = video_drvdata(filp);
|
||||
pr_info("%s: buf %p, size %d, pos %p\n", __FUNCTION__, buffer, (int)len, pos);
|
||||
return videobuf_read_stream(&priv->vb_queue, buffer, len, pos, 0,
|
||||
filp->f_flags & O_NONBLOCK);
|
||||
struct h2t_buf_ctx *ctx;
|
||||
int i;
|
||||
|
||||
for(i = 0; i < list->count; i++) {
|
||||
ctx = (struct h2t_buf_ctx *)list->desc[i].tag;
|
||||
pr_debug("%d: field0: %d, count %d, pool %d, addr0 0x%08x, addr1 0x%08x tag 0x%08llx vb = %p\n", i, list->field0,
|
||||
list->desc[i].count, list->desc[i].pool, list->desc[i].addr0, list->desc[i].addr1, list->desc[i].tag, ctx->vb);
|
||||
|
||||
if (ctx->state == BUF_HW_QUEUED || ctx->state == BUF_DRV_QUEUED) {
|
||||
ctx->state = BUF_ALLOC;
|
||||
vb2_buffer_done(ctx->vb, VB2_BUF_STATE_DONE);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int bcwc_v4l2_poll(struct file *filp, struct poll_table_struct *pt)
|
||||
static int bcwc_start_streaming(struct vb2_queue *vq, unsigned int count)
|
||||
{
|
||||
struct bcwc_private *priv = video_drvdata(filp);
|
||||
pr_debug("%s\n", __FUNCTION__);
|
||||
return videobuf_poll_stream(filp, &priv->vb_queue, pt);
|
||||
struct bcwc_private *dev_priv = vb2_get_drv_priv(vq);
|
||||
struct h2t_buf_ctx *ctx;
|
||||
int i, pixelformat;
|
||||
|
||||
pr_debug("%s: %d\n", __FUNCTION__, count);
|
||||
|
||||
bcwc_isp_cmd_channel_crop_set(dev_priv, 0,
|
||||
dev_priv->fmt->x1,
|
||||
dev_priv->fmt->y1,
|
||||
dev_priv->fmt->x2,
|
||||
dev_priv->fmt->y2);
|
||||
|
||||
switch(dev_priv->fmt->fmt.pixelformat) {
|
||||
case V4L2_PIX_FMT_YUYV:
|
||||
pixelformat = 1;
|
||||
break;
|
||||
case V4L2_PIX_FMT_YVYU:
|
||||
pixelformat = 2;
|
||||
break;
|
||||
case V4L2_PIX_FMT_NV16:
|
||||
pixelformat = 0;
|
||||
break;
|
||||
default:
|
||||
pixelformat = 1;
|
||||
WARN_ON(1);
|
||||
}
|
||||
bcwc_isp_cmd_channel_output_config_set(dev_priv, 0,
|
||||
dev_priv->fmt->fmt.width,
|
||||
dev_priv->fmt->fmt.height,
|
||||
pixelformat);
|
||||
|
||||
bcwc_isp_cmd_channel_start(dev_priv);
|
||||
mdelay(1000); /* Needed to settle AE */
|
||||
for(i = 0; i < BCWC_BUFFERS && count; i++, count--) {
|
||||
ctx = dev_priv->h2t_bufs + i;
|
||||
if (ctx->state != BUF_DRV_QUEUED)
|
||||
continue;
|
||||
|
||||
ctx->state = BUF_HW_QUEUED;
|
||||
bcwc_channel_ringbuf_send(dev_priv, dev_priv->channel_buf_h2t,
|
||||
ctx->dma_desc_obj->offset, 0x180, 0x30000000);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcwc_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
|
||||
static void bcwc_stop_streaming(struct vb2_queue *vq)
|
||||
{
|
||||
struct bcwc_private *priv = video_drvdata(filp);
|
||||
struct bcwc_private *dev_priv = vb2_get_drv_priv(vq);
|
||||
|
||||
pr_debug("%s\n", __FUNCTION__);
|
||||
return videobuf_mmap_mapper(&priv->vb_queue, vma);
|
||||
|
||||
bcwc_isp_cmd_channel_buffer_return(dev_priv, 0);
|
||||
pr_debug("waiting for buffers...\n");
|
||||
vb2_wait_for_all_buffers(vq);
|
||||
pr_debug("done\n");
|
||||
bcwc_isp_cmd_channel_stop(dev_priv);
|
||||
}
|
||||
|
||||
static struct vb2_ops vb2_queue_ops = {
|
||||
.queue_setup = bcwc_buffer_queue_setup,
|
||||
.buf_prepare = bcwc_buffer_prepare,
|
||||
.buf_cleanup = bcwc_buffer_cleanup,
|
||||
.start_streaming = bcwc_start_streaming,
|
||||
.stop_streaming = bcwc_stop_streaming,
|
||||
.buf_queue = bcwc_buffer_queue,
|
||||
.wait_prepare = vb2_ops_wait_prepare,
|
||||
.wait_finish = vb2_ops_wait_finish,
|
||||
};
|
||||
|
||||
static struct v4l2_file_operations bcwc_vdev_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = bcwc_v4l2_open,
|
||||
.release = bcwc_v4l2_release,
|
||||
.read = bcwc_v4l2_read,
|
||||
.poll = bcwc_v4l2_poll,
|
||||
.mmap = bcwc_v4l2_mmap,
|
||||
.open = v4l2_fh_open,
|
||||
|
||||
.release = vb2_fop_release,
|
||||
.poll = vb2_fop_poll,
|
||||
.mmap = vb2_fop_mmap,
|
||||
.unlocked_ioctl = video_ioctl2
|
||||
};
|
||||
|
||||
@@ -205,42 +359,6 @@ static int bcwc_v4l2_ioctl_querycap(struct file *filp, void *priv,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct bcwc_format {
|
||||
__u8 *desc;
|
||||
__u32 pixelformat;
|
||||
int bpp; /* Bytes per pixel */
|
||||
u32 mbus_code;
|
||||
} bcwc_formats[] = {
|
||||
{
|
||||
.desc = "YUYV 4:2:2",
|
||||
.pixelformat = V4L2_PIX_FMT_YUYV,
|
||||
.mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
|
||||
.bpp = 2,
|
||||
},
|
||||
};
|
||||
#if 0
|
||||
static struct bcwc_format *bcwc_find_format(u32 pixelformat)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(bcwc_formats); i++)
|
||||
if (bcwc_formats[i].pixelformat == pixelformat)
|
||||
return bcwc_formats + i;
|
||||
/* Not found? Then return the first format. */
|
||||
return bcwc_formats;
|
||||
}
|
||||
#endif
|
||||
static const struct v4l2_pix_format bcwc_def_pix_format = {
|
||||
.width = 1280,
|
||||
.height = 720,
|
||||
.pixelformat = V4L2_PIX_FMT_YUYV,
|
||||
.field = V4L2_FIELD_NONE,
|
||||
.bytesperline = 1280 * 2,
|
||||
.sizeimage = 1280 * 720 * 2,
|
||||
};
|
||||
|
||||
static const u32 bcwc_def_mbus_code = MEDIA_BUS_FMT_YUYV8_2X8;
|
||||
|
||||
static int bcwc_v4l2_ioctl_enum_fmt_vid_cap(struct file *filp, void *priv,
|
||||
struct v4l2_fmtdesc *fmt)
|
||||
{
|
||||
@@ -248,83 +366,118 @@ static int bcwc_v4l2_ioctl_enum_fmt_vid_cap(struct file *filp, void *priv,
|
||||
return -EINVAL;
|
||||
strlcpy(fmt->description, bcwc_formats[fmt->index].desc,
|
||||
sizeof(fmt->description));
|
||||
fmt->pixelformat = bcwc_formats[fmt->index].pixelformat;
|
||||
fmt->pixelformat = bcwc_formats[fmt->index].fmt.pixelformat;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcwc_v4l2_ioctl_try_fmt_vid_cap(struct file *filp, void *_priv,
|
||||
struct v4l2_format *fmt)
|
||||
{
|
||||
struct bcwc_private *priv = video_drvdata(filp);
|
||||
struct bcwc_private *dev_priv = video_drvdata(filp);
|
||||
const struct bcwc_fmt *p, *p1;
|
||||
int i, width, height, wanted_width, wanted_height, dist, maxdist;
|
||||
|
||||
pr_info("%s: %dx%d\n", __FUNCTION__, fmt->fmt.pix.width, fmt->fmt.pix.height);
|
||||
|
||||
if (fmt->fmt.pix.height != 720 ||
|
||||
fmt->fmt.pix.width != 1280 ||
|
||||
fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV)
|
||||
return -EINVAL;
|
||||
for(i = 0; i < ARRAY_SIZE(bcwc_formats); i++) {
|
||||
p = bcwc_formats + i;
|
||||
if (p->fmt.height == fmt->fmt.pix.height &&
|
||||
p->fmt.width == fmt->fmt.pix.width &&
|
||||
p->fmt.pixelformat == fmt->fmt.pix.pixelformat) {
|
||||
dev_priv->fmt = p;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
priv->user_format.height = fmt->fmt.pix.height;
|
||||
priv->user_format.width = fmt->fmt.pix.width;
|
||||
priv->user_format.sizeimage = priv->user_format.height * priv->user_format.width * 2;
|
||||
wanted_width = fmt->fmt.pix.width;
|
||||
wanted_height = fmt->fmt.pix.height;
|
||||
maxdist = 0x7fffffff;
|
||||
p1 = NULL;
|
||||
for (i = 0; i < ARRAY_SIZE(bcwc_formats); i++) {
|
||||
p = bcwc_formats + i;
|
||||
|
||||
if (p->fmt.pixelformat != fmt->fmt.pix.pixelformat)
|
||||
continue;
|
||||
|
||||
width = p->fmt.width;
|
||||
height = p->fmt.height;
|
||||
|
||||
dist = min(width, wanted_width) * min(height, wanted_height);
|
||||
dist = width * height + wanted_width * wanted_height - 2 * dist;
|
||||
|
||||
pr_debug("%dx%d, dist %d\n", width, height, dist);
|
||||
|
||||
if (dist < maxdist) {
|
||||
maxdist = dist;
|
||||
p1 = p;
|
||||
pr_debug("assign\n");
|
||||
}
|
||||
|
||||
if (maxdist == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!p1) {
|
||||
pr_debug("no assign\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fmt->fmt.pix.width = p1->fmt.width;
|
||||
fmt->fmt.pix.height = p1->fmt.height;
|
||||
fmt->fmt.pix.field = V4L2_FIELD_NONE;
|
||||
|
||||
switch(p1->fmt.pixelformat) {
|
||||
case V4L2_PIX_FMT_YUYV:
|
||||
case V4L2_PIX_FMT_YVYU:
|
||||
fmt->fmt.pix.bytesperline = p1->fmt.width * 2;
|
||||
break;
|
||||
case V4L2_PIX_FMT_NV16:
|
||||
fmt->fmt.pix.bytesperline = p1->fmt.width;
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcwc_v4l2_ioctl_g_fmt_vid_cap(struct file *filp, void *priv,
|
||||
struct v4l2_format *fmt)
|
||||
{
|
||||
fmt->fmt.pix.height = 720;
|
||||
fmt->fmt.pix.width = 1280;
|
||||
fmt->fmt.pix.sizeimage = 1280 * 720;
|
||||
fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
|
||||
struct bcwc_private *dev_priv = video_drvdata(filp);
|
||||
fmt->fmt.pix = dev_priv->fmt->fmt;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcwc_v4l2_ioctl_s_fmt_vid_cap(struct file *filp, void *priv,
|
||||
struct v4l2_format *fmt)
|
||||
{
|
||||
pr_info("%s: %dx%d\n", __FUNCTION__, fmt->fmt.pix.width, fmt->fmt.pix.height);
|
||||
struct bcwc_private *dev_priv = video_drvdata(filp);
|
||||
struct bcwc_fmt *p = NULL;
|
||||
int i;
|
||||
|
||||
pr_info("%s: %dx%d %c%c%c%c\n", __FUNCTION__,
|
||||
fmt->fmt.pix.width, fmt->fmt.pix.height,
|
||||
fmt->fmt.pix.pixelformat,
|
||||
fmt->fmt.pix.pixelformat >> 8,
|
||||
fmt->fmt.pix.pixelformat >> 16,
|
||||
fmt->fmt.pix.pixelformat >> 24);
|
||||
|
||||
for(i = 0; i < ARRAY_SIZE(bcwc_formats); i++) {
|
||||
p = bcwc_formats + i;
|
||||
if (p->fmt.width == fmt->fmt.pix.width &&
|
||||
p->fmt.height == fmt->fmt.pix.height &&
|
||||
p->fmt.pixelformat == fmt->fmt.pix.pixelformat) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == ARRAY_SIZE(bcwc_formats))
|
||||
return -EINVAL;
|
||||
|
||||
dev_priv->fmt = p;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcwc_v4l2_ioctl_reqbufs(struct file *filp, void *_priv,
|
||||
struct v4l2_requestbuffers *rb)
|
||||
{
|
||||
struct bcwc_private *priv = video_drvdata(filp);
|
||||
return videobuf_reqbufs(&priv->vb_queue, rb);
|
||||
}
|
||||
|
||||
static int bcwc_v4l2_ioctl_querybuf(struct file *filp, void *_priv,
|
||||
struct v4l2_buffer *buf)
|
||||
{
|
||||
struct bcwc_private *priv = video_drvdata(filp);
|
||||
return videobuf_querybuf(&priv->vb_queue, buf);
|
||||
}
|
||||
|
||||
static int bcwc_v4l2_ioctl_qbuf(struct file *filp, void *_priv,
|
||||
struct v4l2_buffer *buf)
|
||||
{
|
||||
struct bcwc_private *priv = video_drvdata(filp);
|
||||
return videobuf_qbuf(&priv->vb_queue, buf);
|
||||
}
|
||||
|
||||
static int bcwc_v4l2_ioctl_dqbuf(struct file *filp, void *_priv,
|
||||
struct v4l2_buffer *buf)
|
||||
{
|
||||
struct bcwc_private *priv = video_drvdata(filp);
|
||||
return videobuf_dqbuf(&priv->vb_queue, buf, filp->f_flags & O_NONBLOCK);
|
||||
}
|
||||
|
||||
static int bcwc_v4l2_ioctl_streamon(struct file *filp, void *priv, enum v4l2_buf_type t)
|
||||
{
|
||||
pr_debug("%s\n", __FUNCTION__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static int bcwc_v4l2_ioctl_streamoff(struct file *filp, void *priv, enum v4l2_buf_type t)
|
||||
{
|
||||
pr_debug("%s\n", __FUNCTION__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static int bcwc_v4l2_ioctl_g_parm(struct file *filp, void *priv,
|
||||
struct v4l2_streamparm *parm)
|
||||
@@ -343,8 +496,32 @@ static int bcwc_v4l2_ioctl_s_parm(struct file *filp, void *priv,
|
||||
static int bcwc_v4l2_ioctl_enum_framesizes(struct file *filp, void *priv,
|
||||
struct v4l2_frmsizeenum *sizes)
|
||||
{
|
||||
pr_debug("%s\n", __FUNCTION__);
|
||||
return -ENODEV;
|
||||
struct bcwc_fmt *p = NULL;
|
||||
int i, j;
|
||||
pr_debug("format %c%c%c%c, index %d\n",
|
||||
sizes->pixel_format >> 24,
|
||||
sizes->pixel_format >> 16,
|
||||
sizes->pixel_format >> 8,
|
||||
sizes->pixel_format,
|
||||
sizes->index);
|
||||
|
||||
for(i = 0, j = 0; i < ARRAY_SIZE(bcwc_formats); i++) {
|
||||
if (bcwc_formats[i].fmt.pixelformat == sizes->pixel_format) {
|
||||
if (j++ == sizes->index) {
|
||||
p = bcwc_formats + i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!p)
|
||||
return -EINVAL;
|
||||
|
||||
sizes->type = V4L2_FRMSIZE_TYPE_DISCRETE;
|
||||
sizes->discrete.width = p->fmt.width;
|
||||
sizes->discrete.height = p->fmt.height;
|
||||
pr_debug("%dx%d\n", sizes->discrete.width, sizes->discrete.height);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcwc_v4l2_ioctl_enum_frameintervals(struct file *filp, void *priv,
|
||||
@@ -366,14 +543,17 @@ static struct v4l2_ioctl_ops bcwc_ioctl_ops = {
|
||||
.vidioc_g_fmt_vid_cap = bcwc_v4l2_ioctl_g_fmt_vid_cap,
|
||||
.vidioc_s_fmt_vid_cap = bcwc_v4l2_ioctl_s_fmt_vid_cap,
|
||||
.vidioc_querycap = bcwc_v4l2_ioctl_querycap,
|
||||
.vidioc_reqbufs = bcwc_v4l2_ioctl_reqbufs,
|
||||
|
||||
.vidioc_querybuf = bcwc_v4l2_ioctl_querybuf,
|
||||
.vidioc_qbuf = bcwc_v4l2_ioctl_qbuf,
|
||||
.vidioc_dqbuf = bcwc_v4l2_ioctl_dqbuf,
|
||||
|
||||
.vidioc_streamon = bcwc_v4l2_ioctl_streamon,
|
||||
.vidioc_streamoff = bcwc_v4l2_ioctl_streamoff,
|
||||
.vidioc_reqbufs = vb2_ioctl_reqbufs,
|
||||
.vidioc_create_bufs = vb2_ioctl_create_bufs,
|
||||
.vidioc_querybuf = vb2_ioctl_querybuf,
|
||||
.vidioc_qbuf = vb2_ioctl_qbuf,
|
||||
.vidioc_dqbuf = vb2_ioctl_dqbuf,
|
||||
.vidioc_expbuf = vb2_ioctl_expbuf,
|
||||
.vidioc_streamon = vb2_ioctl_streamon,
|
||||
.vidioc_streamoff = vb2_ioctl_streamoff,
|
||||
|
||||
.vidioc_g_parm = bcwc_v4l2_ioctl_g_parm,
|
||||
.vidioc_s_parm = bcwc_v4l2_ioctl_s_parm,
|
||||
.vidioc_enum_framesizes = bcwc_v4l2_ioctl_enum_framesizes,
|
||||
@@ -384,6 +564,7 @@ int bcwc_v4l2_register(struct bcwc_private *dev_priv)
|
||||
{
|
||||
struct v4l2_device *v4l2_dev = &dev_priv->v4l2_dev;
|
||||
struct video_device *vdev;
|
||||
struct vb2_queue *q;
|
||||
int ret;
|
||||
|
||||
ret = v4l2_device_register(&dev_priv->pdev->dev, v4l2_dev);
|
||||
@@ -399,13 +580,31 @@ int bcwc_v4l2_register(struct bcwc_private *dev_priv)
|
||||
}
|
||||
dev_priv->videodev = vdev;
|
||||
|
||||
q = &dev_priv->vb2_queue;
|
||||
q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
|
||||
q->drv_priv = dev_priv;
|
||||
q->ops = &vb2_queue_ops;
|
||||
q->mem_ops = &vb2_dma_sg_memops;
|
||||
q->buf_struct_size = 0;//sizeof(struct vpif_cap_buffer);
|
||||
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
|
||||
q->min_buffers_needed = 1;
|
||||
q->lock = &dev_priv->vb2_queue_lock;
|
||||
|
||||
ret = vb2_queue_init(q);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
dev_priv->alloc_ctx = vb2_dma_sg_init_ctx(&dev_priv->pdev->dev);
|
||||
dev_priv->fmt = bcwc_formats;
|
||||
vdev->v4l2_dev = v4l2_dev;
|
||||
strcpy(vdev->name, "Apple Facetime HD"); // XXX: Length?
|
||||
vdev->vfl_dir = VFL_DIR_RX;
|
||||
vdev->fops = &bcwc_vdev_fops;
|
||||
vdev->ioctl_ops = &bcwc_ioctl_ops;
|
||||
vdev->queue = q;
|
||||
vdev->release = video_device_release;
|
||||
pr_info("%s: dev_priv %p\n", __FUNCTION__, dev_priv);
|
||||
|
||||
video_set_drvdata(vdev, dev_priv);
|
||||
ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
|
||||
if (ret) {
|
||||
@@ -420,6 +619,8 @@ fail:
|
||||
|
||||
void bcwc_v4l2_unregister(struct bcwc_private *dev_priv)
|
||||
{
|
||||
|
||||
vb2_dma_sg_cleanup_ctx(dev_priv->alloc_ctx);
|
||||
video_unregister_device(dev_priv->videodev);
|
||||
v4l2_device_unregister(&dev_priv->v4l2_dev);
|
||||
}
|
||||
|
||||
15
bcwc_v4l2.h
15
bcwc_v4l2.h
@@ -17,8 +17,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _BCWC_PCIE_H
|
||||
#define _PCWC_PCIE_H
|
||||
#ifndef _BCWC_V4L2_H
|
||||
#define _BCWC_V4L2_H
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/spinlock.h>
|
||||
@@ -27,6 +27,17 @@
|
||||
#include <media/videobuf-dma-sg.h>
|
||||
#include <media/v4l2-device.h>
|
||||
|
||||
struct bcwc_fmt {
|
||||
struct v4l2_pix_format fmt;
|
||||
const char *desc;
|
||||
int range; /* CISP_COMMAND_CH_OUTPUT_CONFIG_SET */
|
||||
int planes;
|
||||
int x1; /* for CISP_CMD_CH_CROP_SET */
|
||||
int y1;
|
||||
int x2;
|
||||
int y2;
|
||||
};
|
||||
|
||||
struct bcwc_private;
|
||||
extern int bcwc_v4l2_register(struct bcwc_private *dev_priv);
|
||||
extern void bcwc_v4l2_unregister(struct bcwc_private *dev_priv);
|
||||
|
||||
Reference in New Issue
Block a user