/*
* Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
* Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kthread.h>
#include <linux/freezer.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-common.h>
#include <media/videobuf-dma-sg.h>
#include "solo6x10.h"
#include "tw28.h"
#define SOLO_HW_BPL 2048
#define SOLO_DISP_PIX_FIELD V4L2_FIELD_INTERLACED
/* Image size is two fields, SOLO_HW_BPL is one horizontal line */
#define solo_vlines(__solo) (__solo->video_vsize * 2)
#define solo_image_size(__solo) (solo_bytesperline(__solo) * \
solo_vlines(__solo))
#define solo_bytesperline(__solo) (__solo->video_hsize * 2)
#define MIN_VID_BUFFERS 4
/* Simple file handle */
struct solo_filehandle {
struct solo_dev *solo_dev;
struct videobuf_queue vidq;
struct task_struct *kthread;
spinlock_t slock;
int old_write;
struct list_head vidq_active;
struct p2m_desc desc[SOLO_NR_P2M_DESC];
int desc_idx;
};
unsigned video_nr = -1;
module_param(video_nr, uint, 0644);
MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect (default)");
static void erase_on(struct solo_dev *solo_dev)
{
solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, SOLO_VO_DISP_ERASE_ON);
solo_dev->erasing = 1;
solo_dev->frame_blank = 0;
}
static int erase_off(struct solo_dev *solo_dev)
{
if (!solo_dev->erasing)
return 0;
/* First time around, assert erase off */
if (!solo_dev->frame_blank)
solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, 0);
/* Keep the erasing flag on for 8 frames minimum */
if (solo_dev->frame_blank++ >= 8)
solo_dev->erasing = 0;
return 1;
}
void solo_video_in_isr(struct solo_dev *solo_dev)
{
solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_VIDEO_IN);
wake_up_interruptible(&solo_dev->disp_thread_wait);
}
static void solo_win_setup(struct solo_dev *solo_dev, u8 ch,
int sx, int sy, int ex, int ey, int scale)
{
if (ch >= solo_dev->nr_chans)
return;
/* Here, we just keep window/channel the same */
solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL0(ch),
SOLO_VI_WIN_CHANNEL(ch) |
SOLO_VI_WIN_SX(sx) |
SOLO_VI_WIN_EX(ex) |
SOLO_VI_WIN_SCALE(scale));
solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL1(ch),
SOLO_VI_WIN_SY(sy) |
SOLO_VI_WIN_EY(ey));
}
static int solo_v4l2_ch_ext_4up(struct solo_dev *solo_dev, u8 idx, int on)
{
u8 ch = idx * 4;
if (ch >= solo_dev->nr_chans)
return -EINVAL;
if (!on) {
u8 i;
for (i = ch; i < ch + 4; i++)
solo_win_setup(solo_dev, i, solo_dev->video_hsize,
solo_vlines(solo_dev),
solo_dev->video_hsize,
solo_vlines(solo_dev), 0);
return 0;
}
/* Row 1 */
solo_win_setup(solo_dev, ch, 0, 0, solo_dev->video_hsize / 2,
solo_vlines(solo_dev) / 2, 3);
solo_win_setup(solo_dev, ch + 1, solo_dev->video_hsize / 2, 0,
solo_dev->video_hsize, solo_vlines(solo_dev) / 2, 3);
/* Row 2 */
solo_win_setup(solo_dev, ch + 2, 0, solo_vlines(solo_dev) / 2,
solo_dev->video_hsize / 2, solo_vlines(solo_dev), 3);
solo_win_setup(solo_dev, ch + 3, solo_dev->video_hsize / 2,
solo_vlines(solo_dev) / 2, solo_dev->video_hsize,
solo_vlines(solo_dev), 3);
return 0;
}
static int solo_v4l2_ch_ext_16up(struct solo_dev *solo_dev, int on)
{
int sy, ysize, hsize, i;
if (!on) {
for (i = 0; i < 16; i++)
solo_win_setup(solo_dev, i, solo_dev->video_hsize,
solo_vlines(solo_dev),
solo_dev->video_hsize,
solo_vlines(solo_dev), 0);
return 0;
}
ysize = solo_vlines(solo_dev) / 4;
hsize = solo_dev->video_hsize / 4;
for (sy = 0, i = 0; i < 4; i++, sy