/*
yuv support
Copyright (C) 2007 Ian Armstrong <ian@iarmst.demon.co.uk>
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 "ivtv-driver.h"
#include "ivtv-udma.h"
#include "ivtv-yuv.h"
/* YUV buffer offsets */
const u32 yuv_offset[IVTV_YUV_BUFFERS] = {
0x001a8600,
0x00240400,
0x002d8200,
0x00370000,
0x00029000,
0x000C0E00,
0x006B0400,
0x00748200
};
static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
struct ivtv_dma_frame *args)
{
struct ivtv_dma_page_info y_dma;
struct ivtv_dma_page_info uv_dma;
struct yuv_playback_info *yi = &itv->yuv_info;
u8 frame = yi->draw_frame;
struct yuv_frame_info *f = &yi->new_frame_info[frame];
int i;
int y_pages, uv_pages;
unsigned long y_buffer_offset, uv_buffer_offset;
int y_decode_height, uv_decode_height, y_size;
y_buffer_offset = IVTV_DECODER_OFFSET + yuv_offset[frame];
uv_buffer_offset = y_buffer_offset + IVTV_YUV_BUFFER_UV_OFFSET;
y_decode_height = uv_decode_height = f->src_h + f->src_y;
if (f->offset_y)
y_buffer_offset += 720 * 16;
if (y_decode_height & 15)
y_decode_height = (y_decode_height + 16) & ~15;
if (uv_decode_height & 31)
uv_decode_height = (uv_decode_height + 32) & ~31;
y_size = 720 * y_decode_height;
/* Still in USE */
if (dma->SG_length || dma->page_count) {
IVTV_DEBUG_WARN
("prep_user_dma: SG_length %d page_count %d still full?\n",
dma->SG_length, dma->page_count);
return -EBUSY;
}
ivtv_udma_get_page_info (&y_dma, (unsigned long)args->y_source, 720 * y_decode_height);
ivtv_udma_get_page_info (&uv_dma, (unsigned long)args->uv_source, 360 * uv_decode_height);
/* Get user pages for DMA Xfer */
down_read(¤t->mm->mmap_sem);
y_pages = get_user_pages(current, current->mm, y_dma.uaddr, y_dma.page_count, 0, 1, &dma->map[0], NULL);
uv_pages = get_user_pages(current, current->mm, uv_dma.