2005-04-17 02:20:36 +04:00
/*
* av7110_hw . c : av7110 low level hardware access and firmware interface
*
* Copyright ( C ) 1999 - 2002 Ralph Metzler
* & Marcus Metzler for convergence integrated media GmbH
*
* originally based on code by :
* Copyright ( C ) 1998 , 1999 Christian Theiss < mistert @ rz . fh - augsburg . de >
*
* 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 .
* Or , point your browser to http : //www.gnu.org/copyleft/gpl.html
*
* the project ' s page is at http : //www.linuxtv.org/dvb/
*/
/* for debugging ARM communication: */
//#define COM_DEBUG
# include <stdarg.h>
# include <linux/types.h>
# include <linux/kernel.h>
# include <linux/string.h>
# include <linux/delay.h>
# include <linux/fs.h>
# include "av7110.h"
# include "av7110_hw.h"
2005-09-10 00:03:10 +04:00
# define _NOHANDSHAKE
2005-04-17 02:20:36 +04:00
/****************************************************************************
* DEBI functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* This DEBI code is based on the Stradis driver
by Nathan Laredo < laredo @ gnu . org > */
int av7110_debiwrite ( struct av7110 * av7110 , u32 config ,
int addr , u32 val , int count )
{
struct saa7146_dev * dev = av7110 - > dev ;
if ( count < = 0 | | count > 32764 ) {
printk ( " %s: invalid count %d \n " , __FUNCTION__ , count ) ;
return - 1 ;
}
if ( saa7146_wait_for_debi_done ( av7110 - > dev , 0 ) < 0 ) {
printk ( " %s: wait_for_debi_done failed \n " , __FUNCTION__ ) ;
return - 1 ;
}
saa7146_write ( dev , DEBI_CONFIG , config ) ;
if ( count < = 4 ) /* immediate transfer */
saa7146_write ( dev , DEBI_AD , val ) ;
else /* block transfer */
saa7146_write ( dev , DEBI_AD , av7110 - > debi_bus ) ;
saa7146_write ( dev , DEBI_COMMAND , ( count < < 17 ) | ( addr & 0xffff ) ) ;
saa7146_write ( dev , MC2 , ( 2 < < 16 ) | 2 ) ;
return 0 ;
}
u32 av7110_debiread ( struct av7110 * av7110 , u32 config , int addr , int count )
{
struct saa7146_dev * dev = av7110 - > dev ;
u32 result = 0 ;
if ( count > 32764 | | count < = 0 ) {
printk ( " %s: invalid count %d \n " , __FUNCTION__ , count ) ;
return 0 ;
}
if ( saa7146_wait_for_debi_done ( av7110 - > dev , 0 ) < 0 ) {
printk ( " %s: wait_for_debi_done #1 failed \n " , __FUNCTION__ ) ;
return 0 ;
}
saa7146_write ( dev , DEBI_AD , av7110 - > debi_bus ) ;
saa7146_write ( dev , DEBI_COMMAND , ( count < < 17 ) | 0x10000 | ( addr & 0xffff ) ) ;
saa7146_write ( dev , DEBI_CONFIG , config ) ;
saa7146_write ( dev , MC2 , ( 2 < < 16 ) | 2 ) ;
if ( count > 4 )
return count ;
if ( saa7146_wait_for_debi_done ( av7110 - > dev , 0 ) < 0 ) {
printk ( " %s: wait_for_debi_done #2 failed \n " , __FUNCTION__ ) ;
return 0 ;
}
result = saa7146_read ( dev , DEBI_AD ) ;
result & = ( 0xffffffffUL > > ( ( 4 - count ) * 8 ) ) ;
return result ;
}
/* av7110 ARM core boot stuff */
2005-05-17 08:54:38 +04:00
#if 0
2005-04-17 02:20:36 +04:00
void av7110_reset_arm ( struct av7110 * av7110 )
{
saa7146_setgpio ( av7110 - > dev , RESET_LINE , SAA7146_GPIO_OUTLO ) ;
/* Disable DEBI and GPIO irq */
SAA7146_IER_DISABLE ( av7110 - > dev , MASK_19 | MASK_03 ) ;
SAA7146_ISR_CLEAR ( av7110 - > dev , MASK_19 | MASK_03 ) ;
saa7146_setgpio ( av7110 - > dev , RESET_LINE , SAA7146_GPIO_OUTHI ) ;
msleep ( 30 ) ; /* the firmware needs some time to initialize */
ARM_ResetMailBox ( av7110 ) ;
SAA7146_ISR_CLEAR ( av7110 - > dev , MASK_19 | MASK_03 ) ;
SAA7146_IER_ENABLE ( av7110 - > dev , MASK_03 ) ;
av7110 - > arm_ready = 1 ;
dprintk ( 1 , " reset ARM \n " ) ;
}
2005-05-17 08:54:38 +04:00
# endif /* 0 */
2005-04-17 02:20:36 +04:00
static int waitdebi ( struct av7110 * av7110 , int adr , int state )
{
int k ;
dprintk ( 4 , " %p \n " , av7110 ) ;
for ( k = 0 ; k < 100 ; k + + ) {
if ( irdebi ( av7110 , DEBINOSWAP , adr , 0 , 2 ) = = state )
return 0 ;
udelay ( 5 ) ;
}
2005-07-08 04:57:55 +04:00
return - ETIMEDOUT ;
2005-04-17 02:20:36 +04:00
}
static int load_dram ( struct av7110 * av7110 , u32 * data , int len )
{
int i ;
int blocks , rest ;
2006-01-15 13:12:14 +03:00
u32 base , bootblock = AV7110_BOOT_BLOCK ;
2005-04-17 02:20:36 +04:00
dprintk ( 4 , " %p \n " , av7110 ) ;
2006-01-15 13:12:14 +03:00
blocks = len / AV7110_BOOT_MAX_SIZE ;
rest = len % AV7110_BOOT_MAX_SIZE ;
2005-04-17 02:20:36 +04:00
base = DRAM_START_CODE ;
for ( i = 0 ; i < blocks ; i + + ) {
2006-01-15 13:12:14 +03:00
if ( waitdebi ( av7110 , AV7110_BOOT_STATE , BOOTSTATE_BUFFER_EMPTY ) < 0 ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " dvb-ttpci: load_dram(): timeout at block %d \n " , i ) ;
2005-07-08 04:57:55 +04:00
return - ETIMEDOUT ;
2005-04-17 02:20:36 +04:00
}
dprintk ( 4 , " writing DRAM block %d \n " , i ) ;
mwdebi ( av7110 , DEBISWAB , bootblock ,
2007-07-13 03:37:50 +04:00
( ( u8 * ) data ) + i * AV7110_BOOT_MAX_SIZE , AV7110_BOOT_MAX_SIZE ) ;
2005-04-17 02:20:36 +04:00
bootblock ^ = 0x1400 ;
2006-01-15 13:12:14 +03:00
iwdebi ( av7110 , DEBISWAB , AV7110_BOOT_BASE , swab32 ( base ) , 4 ) ;
iwdebi ( av7110 , DEBINOSWAP , AV7110_BOOT_SIZE , AV7110_BOOT_MAX_SIZE , 2 ) ;
iwdebi ( av7110 , DEBINOSWAP , AV7110_BOOT_STATE , BOOTSTATE_BUFFER_FULL , 2 ) ;
base + = AV7110_BOOT_MAX_SIZE ;
2005-04-17 02:20:36 +04:00
}
if ( rest > 0 ) {
2006-01-15 13:12:14 +03:00
if ( waitdebi ( av7110 , AV7110_BOOT_STATE , BOOTSTATE_BUFFER_EMPTY ) < 0 ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " dvb-ttpci: load_dram(): timeout at last block \n " ) ;
2005-07-08 04:57:55 +04:00
return - ETIMEDOUT ;
2005-04-17 02:20:36 +04:00
}
if ( rest > 4 )
mwdebi ( av7110 , DEBISWAB , bootblock ,
2007-07-13 03:37:50 +04:00
( ( u8 * ) data ) + i * AV7110_BOOT_MAX_SIZE , rest ) ;
2005-04-17 02:20:36 +04:00
else
mwdebi ( av7110 , DEBISWAB , bootblock ,
2007-07-13 03:37:50 +04:00
( ( u8 * ) data ) + i * AV7110_BOOT_MAX_SIZE - 4 , rest + 4 ) ;
2005-04-17 02:20:36 +04:00
2006-01-15 13:12:14 +03:00
iwdebi ( av7110 , DEBISWAB , AV7110_BOOT_BASE , swab32 ( base ) , 4 ) ;
iwdebi ( av7110 , DEBINOSWAP , AV7110_BOOT_SIZE , rest , 2 ) ;
iwdebi ( av7110 , DEBINOSWAP , AV7110_BOOT_STATE , BOOTSTATE_BUFFER_FULL , 2 ) ;
2005-04-17 02:20:36 +04:00
}
2006-01-15 13:12:14 +03:00
if ( waitdebi ( av7110 , AV7110_BOOT_STATE , BOOTSTATE_BUFFER_EMPTY ) < 0 ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " dvb-ttpci: load_dram(): timeout after last block \n " ) ;
2005-07-08 04:57:55 +04:00
return - ETIMEDOUT ;
2005-04-17 02:20:36 +04:00
}
2006-01-15 13:12:14 +03:00
iwdebi ( av7110 , DEBINOSWAP , AV7110_BOOT_SIZE , 0 , 2 ) ;
iwdebi ( av7110 , DEBINOSWAP , AV7110_BOOT_STATE , BOOTSTATE_BUFFER_FULL , 2 ) ;
if ( waitdebi ( av7110 , AV7110_BOOT_STATE , BOOTSTATE_AV7110_BOOT_COMPLETE ) < 0 ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " dvb-ttpci: load_dram(): final handshake timeout \n " ) ;
2005-07-08 04:57:55 +04:00
return - ETIMEDOUT ;
2005-04-17 02:20:36 +04:00
}
return 0 ;
}
/* we cannot write av7110 DRAM directly, so load a bootloader into
* the DPRAM which implements a simple boot protocol */
static u8 bootcode [ ] = {
0xea , 0x00 , 0x00 , 0x0e , 0xe1 , 0xb0 , 0xf0 , 0x0e , 0xe2 , 0x5e , 0xf0 , 0x04 ,
0xe2 , 0x5e , 0xf0 , 0x04 , 0xe2 , 0x5e , 0xf0 , 0x08 , 0xe2 , 0x5e , 0xf0 , 0x04 ,
0xe2 , 0x5e , 0xf0 , 0x04 , 0xe2 , 0x5e , 0xf0 , 0x04 , 0x2c , 0x00 , 0x00 , 0x24 ,
0x00 , 0x00 , 0x00 , 0x0c , 0x00 , 0x00 , 0x00 , 0x00 , 0x2c , 0x00 , 0x00 , 0x34 ,
0x00 , 0x00 , 0x00 , 0x00 , 0xa5 , 0xa5 , 0x5a , 0x5a , 0x00 , 0x1f , 0x15 , 0x55 ,
0x00 , 0x00 , 0x00 , 0x09 , 0xe5 , 0x9f , 0xd0 , 0x7c , 0xe5 , 0x9f , 0x40 , 0x74 ,
0xe3 , 0xa0 , 0x00 , 0x00 , 0xe5 , 0x84 , 0x00 , 0x00 , 0xe5 , 0x84 , 0x00 , 0x04 ,
0xe5 , 0x9f , 0x10 , 0x70 , 0xe5 , 0x9f , 0x20 , 0x70 , 0xe5 , 0x9f , 0x30 , 0x64 ,
0xe8 , 0xb1 , 0x1f , 0xe0 , 0xe8 , 0xa3 , 0x1f , 0xe0 , 0xe1 , 0x51 , 0x00 , 0x02 ,
0xda , 0xff , 0xff , 0xfb , 0xe5 , 0x9f , 0xf0 , 0x50 , 0xe1 , 0xd4 , 0x10 , 0xb0 ,
0xe3 , 0x51 , 0x00 , 0x00 , 0x0a , 0xff , 0xff , 0xfc , 0xe1 , 0xa0 , 0x10 , 0x0d ,
0xe5 , 0x94 , 0x30 , 0x04 , 0xe1 , 0xd4 , 0x20 , 0xb2 , 0xe2 , 0x82 , 0x20 , 0x3f ,
0xe1 , 0xb0 , 0x23 , 0x22 , 0x03 , 0xa0 , 0x00 , 0x02 , 0xe1 , 0xc4 , 0x00 , 0xb0 ,
0x0a , 0xff , 0xff , 0xf4 , 0xe8 , 0xb1 , 0x1f , 0xe0 , 0xe8 , 0xa3 , 0x1f , 0xe0 ,
0xe8 , 0xb1 , 0x1f , 0xe0 , 0xe8 , 0xa3 , 0x1f , 0xe0 , 0xe2 , 0x52 , 0x20 , 0x01 ,
0x1a , 0xff , 0xff , 0xf9 , 0xe2 , 0x2d , 0xdb , 0x05 , 0xea , 0xff , 0xff , 0xec ,
0x2c , 0x00 , 0x03 , 0xf8 , 0x2c , 0x00 , 0x04 , 0x00 , 0x9e , 0x00 , 0x08 , 0x00 ,
0x2c , 0x00 , 0x00 , 0x74 , 0x2c , 0x00 , 0x00 , 0xc0
} ;
int av7110_bootarm ( struct av7110 * av7110 )
{
struct saa7146_dev * dev = av7110 - > dev ;
u32 ret ;
int i ;
dprintk ( 4 , " %p \n " , av7110 ) ;
2006-01-09 20:32:42 +03:00
av7110 - > arm_ready = 0 ;
2005-04-17 02:20:36 +04:00
saa7146_setgpio ( dev , RESET_LINE , SAA7146_GPIO_OUTLO ) ;
/* Disable DEBI and GPIO irq */
SAA7146_IER_DISABLE ( av7110 - > dev , MASK_03 | MASK_19 ) ;
SAA7146_ISR_CLEAR ( av7110 - > dev , MASK_19 | MASK_03 ) ;
/* enable DEBI */
saa7146_write ( av7110 - > dev , MC1 , 0x08800880 ) ;
saa7146_write ( av7110 - > dev , DD1_STREAM_B , 0x00000000 ) ;
saa7146_write ( av7110 - > dev , MC2 , ( MASK_09 | MASK_25 | MASK_10 | MASK_26 ) ) ;
/* test DEBI */
iwdebi ( av7110 , DEBISWAP , DPRAM_BASE , 0x76543210 , 4 ) ;
2006-02-25 00:53:00 +03:00
/* FIXME: Why does Nexus CA require 2x iwdebi for first init? */
iwdebi ( av7110 , DEBISWAP , DPRAM_BASE , 0x76543210 , 4 ) ;
2005-04-17 02:20:36 +04:00
if ( ( ret = irdebi ( av7110 , DEBINOSWAP , DPRAM_BASE , 0 , 4 ) ) ! = 0x10325476 ) {
printk ( KERN_ERR " dvb-ttpci: debi test in av7110_bootarm() failed: "
" %08x != %08x (check your BIOS 'Plug&Play OS' settings) \n " ,
ret , 0x10325476 ) ;
return - 1 ;
}
for ( i = 0 ; i < 8192 ; i + = 4 )
iwdebi ( av7110 , DEBISWAP , DPRAM_BASE + i , 0x00 , 4 ) ;
dprintk ( 2 , " debi test OK \n " ) ;
/* boot */
dprintk ( 1 , " load boot code \n " ) ;
saa7146_setgpio ( dev , ARM_IRQ_LINE , SAA7146_GPIO_IRQLO ) ;
//saa7146_setgpio(dev, DEBI_DONE_LINE, SAA7146_GPIO_INPUT);
//saa7146_setgpio(dev, 3, SAA7146_GPIO_INPUT);
mwdebi ( av7110 , DEBISWAB , DPRAM_BASE , bootcode , sizeof ( bootcode ) ) ;
2006-01-15 13:12:14 +03:00
iwdebi ( av7110 , DEBINOSWAP , AV7110_BOOT_STATE , BOOTSTATE_BUFFER_FULL , 2 ) ;
2005-04-17 02:20:36 +04:00
if ( saa7146_wait_for_debi_done ( av7110 - > dev , 1 ) ) {
printk ( KERN_ERR " dvb-ttpci: av7110_bootarm(): "
" saa7146_wait_for_debi_done() timed out \n " ) ;
2005-07-08 04:57:55 +04:00
return - ETIMEDOUT ;
2005-04-17 02:20:36 +04:00
}
saa7146_setgpio ( dev , RESET_LINE , SAA7146_GPIO_OUTHI ) ;
mdelay ( 1 ) ;
dprintk ( 1 , " load dram code \n " ) ;
if ( load_dram ( av7110 , ( u32 * ) av7110 - > bin_root , av7110 - > size_root ) < 0 ) {
printk ( KERN_ERR " dvb-ttpci: av7110_bootarm(): "
" load_dram() failed \n " ) ;
return - 1 ;
}
saa7146_setgpio ( dev , RESET_LINE , SAA7146_GPIO_OUTLO ) ;
mdelay ( 1 ) ;
dprintk ( 1 , " load dpram code \n " ) ;
mwdebi ( av7110 , DEBISWAB , DPRAM_BASE , av7110 - > bin_dpram , av7110 - > size_dpram ) ;
if ( saa7146_wait_for_debi_done ( av7110 - > dev , 1 ) ) {
printk ( KERN_ERR " dvb-ttpci: av7110_bootarm(): "
" saa7146_wait_for_debi_done() timed out after loading DRAM \n " ) ;
2005-07-08 04:57:55 +04:00
return - ETIMEDOUT ;
2005-04-17 02:20:36 +04:00
}
saa7146_setgpio ( dev , RESET_LINE , SAA7146_GPIO_OUTHI ) ;
msleep ( 30 ) ; /* the firmware needs some time to initialize */
//ARM_ClearIrq(av7110);
ARM_ResetMailBox ( av7110 ) ;
SAA7146_ISR_CLEAR ( av7110 - > dev , MASK_19 | MASK_03 ) ;
SAA7146_IER_ENABLE ( av7110 - > dev , MASK_03 ) ;
av7110 - > arm_errors = 0 ;
av7110 - > arm_ready = 1 ;
return 0 ;
}
/****************************************************************************
* DEBI command polling
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int av7110_wait_msgstate ( struct av7110 * av7110 , u16 flags )
{
unsigned long start ;
u32 stat ;
2005-07-08 04:58:28 +04:00
int err ;
2005-04-17 02:20:36 +04:00
if ( FW_VERSION ( av7110 - > arm_app ) < = 0x261c ) {
/* not supported by old firmware */
msleep ( 50 ) ;
return 0 ;
}
/* new firmware */
start = jiffies ;
for ( ; ; ) {
2005-07-08 04:58:28 +04:00
err = time_after ( jiffies , start + ARM_WAIT_FREE ) ;
2006-02-07 11:49:14 +03:00
if ( mutex_lock_interruptible ( & av7110 - > dcomlock ) )
2005-04-17 02:20:36 +04:00
return - ERESTARTSYS ;
stat = rdebi ( av7110 , DEBINOSWAP , MSGSTATE , 0 , 2 ) ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & av7110 - > dcomlock ) ;
2005-07-08 04:58:28 +04:00
if ( ( stat & flags ) = = 0 )
2005-04-17 02:20:36 +04:00
break ;
2005-07-08 04:58:28 +04:00
if ( err ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " %s: timeout waiting for MSGSTATE %04x \n " ,
__FUNCTION__ , stat & flags ) ;
2005-07-08 04:57:55 +04:00
return - ETIMEDOUT ;
2005-04-17 02:20:36 +04:00
}
msleep ( 1 ) ;
}
return 0 ;
}
2005-05-17 08:54:38 +04:00
static int __av7110_send_fw_cmd ( struct av7110 * av7110 , u16 * buf , int length )
2005-04-17 02:20:36 +04:00
{
int i ;
unsigned long start ;
char * type = NULL ;
u16 flags [ 2 ] = { 0 , 0 } ;
u32 stat ;
2005-07-08 04:58:28 +04:00
int err ;
2005-04-17 02:20:36 +04:00
// dprintk(4, "%p\n", av7110);
if ( ! av7110 - > arm_ready ) {
dprintk ( 1 , " arm not ready. \n " ) ;
return - ENXIO ;
}
start = jiffies ;
2005-07-08 04:58:28 +04:00
while ( 1 ) {
err = time_after ( jiffies , start + ARM_WAIT_FREE ) ;
if ( rdebi ( av7110 , DEBINOSWAP , COMMAND , 0 , 2 ) = = 0 )
break ;
if ( err ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " dvb-ttpci: %s(): timeout waiting for COMMAND idle \n " , __FUNCTION__ ) ;
2006-01-09 20:32:42 +03:00
av7110 - > arm_errors + + ;
2005-04-17 02:20:36 +04:00
return - ETIMEDOUT ;
}
2005-07-08 04:57:56 +04:00
msleep ( 1 ) ;
2005-04-17 02:20:36 +04:00
}
2005-09-10 00:03:11 +04:00
if ( FW_VERSION ( av7110 - > arm_app ) < = 0x261f )
wdebi ( av7110 , DEBINOSWAP , COM_IF_LOCK , 0xffff , 2 ) ;
2005-04-17 02:20:36 +04:00
# ifndef _NOHANDSHAKE
start = jiffies ;
2005-07-08 04:58:28 +04:00
while ( 1 ) {
err = time_after ( jiffies , start + ARM_WAIT_SHAKE ) ;
if ( rdebi ( av7110 , DEBINOSWAP , HANDSHAKE_REG , 0 , 2 ) = = 0 )
break ;
if ( err ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " dvb-ttpci: %s(): timeout waiting for HANDSHAKE_REG \n " , __FUNCTION__ ) ;
return - ETIMEDOUT ;
}
2005-07-08 04:57:56 +04:00
msleep ( 1 ) ;
2005-04-17 02:20:36 +04:00
}
# endif
switch ( ( buf [ 0 ] > > 8 ) & 0xff ) {
case COMTYPE_PIDFILTER :
case COMTYPE_ENCODER :
case COMTYPE_REC_PLAY :
case COMTYPE_MPEGDECODER :
type = " MSG " ;
flags [ 0 ] = GPMQOver ;
flags [ 1 ] = GPMQFull ;
break ;
case COMTYPE_OSD :
type = " OSD " ;
flags [ 0 ] = OSDQOver ;
flags [ 1 ] = OSDQFull ;
break ;
case COMTYPE_MISC :
if ( FW_VERSION ( av7110 - > arm_app ) > = 0x261d ) {
type = " MSG " ;
flags [ 0 ] = GPMQOver ;
flags [ 1 ] = GPMQBusy ;
}
break ;
default :
break ;
}
if ( type ! = NULL ) {
/* non-immediate COMMAND type */
start = jiffies ;
for ( ; ; ) {
2005-07-08 04:58:28 +04:00
err = time_after ( jiffies , start + ARM_WAIT_FREE ) ;
2005-04-17 02:20:36 +04:00
stat = rdebi ( av7110 , DEBINOSWAP , MSGSTATE , 0 , 2 ) ;
if ( stat & flags [ 0 ] ) {
printk ( KERN_ERR " %s: %s QUEUE overflow \n " ,
__FUNCTION__ , type ) ;
return - 1 ;
}
if ( ( stat & flags [ 1 ] ) = = 0 )
break ;
2005-07-08 04:58:28 +04:00
if ( err ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " %s: timeout waiting on busy %s QUEUE \n " ,
__FUNCTION__ , type ) ;
2005-07-08 04:57:55 +04:00
return - ETIMEDOUT ;
2005-04-17 02:20:36 +04:00
}
msleep ( 1 ) ;
}
}
for ( i = 2 ; i < length ; i + + )
wdebi ( av7110 , DEBINOSWAP , COMMAND + 2 * i , ( u32 ) buf [ i ] , 2 ) ;
if ( length )
wdebi ( av7110 , DEBINOSWAP , COMMAND + 2 , ( u32 ) buf [ 1 ] , 2 ) ;
else
wdebi ( av7110 , DEBINOSWAP , COMMAND + 2 , 0 , 2 ) ;
wdebi ( av7110 , DEBINOSWAP , COMMAND , ( u32 ) buf [ 0 ] , 2 ) ;
2005-09-10 00:03:11 +04:00
if ( FW_VERSION ( av7110 - > arm_app ) < = 0x261f )
wdebi ( av7110 , DEBINOSWAP , COM_IF_LOCK , 0x0000 , 2 ) ;
2005-04-17 02:20:36 +04:00
# ifdef COM_DEBUG
start = jiffies ;
2005-07-08 04:58:28 +04:00
while ( 1 ) {
err = time_after ( jiffies , start + ARM_WAIT_FREE ) ;
if ( rdebi ( av7110 , DEBINOSWAP , COMMAND , 0 , 2 ) = = 0 )
break ;
if ( err ) {
2005-07-08 04:57:55 +04:00
printk ( KERN_ERR " dvb-ttpci: %s(): timeout waiting for COMMAND %d to complete \n " ,
2005-07-08 04:58:28 +04:00
__FUNCTION__ , ( buf [ 0 ] > > 8 ) & 0xff ) ;
2005-04-17 02:20:36 +04:00
return - ETIMEDOUT ;
}
2005-07-08 04:57:56 +04:00
msleep ( 1 ) ;
2005-04-17 02:20:36 +04:00
}
stat = rdebi ( av7110 , DEBINOSWAP , MSGSTATE , 0 , 2 ) ;
if ( stat & GPMQOver ) {
printk ( KERN_ERR " dvb-ttpci: %s(): GPMQOver \n " , __FUNCTION__ ) ;
return - ENOSPC ;
}
else if ( stat & OSDQOver ) {
printk ( KERN_ERR " dvb-ttpci: %s(): OSDQOver \n " , __FUNCTION__ ) ;
return - ENOSPC ;
}
# endif
return 0 ;
}
2005-05-17 08:54:38 +04:00
static int av7110_send_fw_cmd ( struct av7110 * av7110 , u16 * buf , int length )
2005-04-17 02:20:36 +04:00
{
int ret ;
// dprintk(4, "%p\n", av7110);
if ( ! av7110 - > arm_ready ) {
dprintk ( 1 , " arm not ready. \n " ) ;
return - 1 ;
}
2006-02-07 11:49:14 +03:00
if ( mutex_lock_interruptible ( & av7110 - > dcomlock ) )
2005-04-17 02:20:36 +04:00
return - ERESTARTSYS ;
ret = __av7110_send_fw_cmd ( av7110 , buf , length ) ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & av7110 - > dcomlock ) ;
2005-07-08 04:57:55 +04:00
if ( ret & & ret ! = - ERESTARTSYS )
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " dvb-ttpci: %s(): av7110_send_fw_cmd error %d \n " ,
__FUNCTION__ , ret ) ;
return ret ;
}
int av7110_fw_cmd ( struct av7110 * av7110 , int type , int com , int num , . . . )
{
va_list args ;
u16 buf [ num + 2 ] ;
int i , ret ;
// dprintk(4, "%p\n", av7110);
buf [ 0 ] = ( ( type < < 8 ) | com ) ;
buf [ 1 ] = num ;
if ( num ) {
va_start ( args , num ) ;
for ( i = 0 ; i < num ; i + + )
buf [ i + 2 ] = va_arg ( args , u32 ) ;
va_end ( args ) ;
}
ret = av7110_send_fw_cmd ( av7110 , buf , num + 2 ) ;
2005-07-08 04:57:55 +04:00
if ( ret & & ret ! = - ERESTARTSYS )
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " dvb-ttpci: av7110_fw_cmd error %d \n " , ret ) ;
return ret ;
}
2005-05-17 08:54:38 +04:00
#if 0
2005-04-17 02:20:36 +04:00
int av7110_send_ci_cmd ( struct av7110 * av7110 , u8 subcom , u8 * buf , u8 len )
{
int i , ret ;
u16 cmd [ 18 ] = { ( ( COMTYPE_COMMON_IF < < 8 ) + subcom ) ,
16 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ;
dprintk ( 4 , " %p \n " , av7110 ) ;
for ( i = 0 ; i < len & & i < 32 ; i + + )
{
if ( i % 2 = = 0 )
cmd [ ( i / 2 ) + 2 ] = ( u16 ) ( buf [ i ] ) < < 8 ;
else
cmd [ ( i / 2 ) + 2 ] | = buf [ i ] ;
}
ret = av7110_send_fw_cmd ( av7110 , cmd , 18 ) ;
2005-07-08 04:57:55 +04:00
if ( ret & & ret ! = - ERESTARTSYS )
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " dvb-ttpci: av7110_send_ci_cmd error %d \n " , ret ) ;
return ret ;
}
2005-05-17 08:54:38 +04:00
# endif /* 0 */
2005-04-17 02:20:36 +04:00
int av7110_fw_request ( struct av7110 * av7110 , u16 * request_buf ,
int request_buf_len , u16 * reply_buf , int reply_buf_len )
{
int err ;
s16 i ;
unsigned long start ;
# ifdef COM_DEBUG
u32 stat ;
# endif
dprintk ( 4 , " %p \n " , av7110 ) ;
if ( ! av7110 - > arm_ready ) {
dprintk ( 1 , " arm not ready. \n " ) ;
return - 1 ;
}
2006-02-07 11:49:14 +03:00
if ( mutex_lock_interruptible ( & av7110 - > dcomlock ) )
2005-04-17 02:20:36 +04:00
return - ERESTARTSYS ;
if ( ( err = __av7110_send_fw_cmd ( av7110 , request_buf , request_buf_len ) ) < 0 ) {
2006-02-07 11:49:14 +03:00
mutex_unlock ( & av7110 - > dcomlock ) ;
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " dvb-ttpci: av7110_fw_request error %d \n " , err ) ;
return err ;
}
start = jiffies ;
2005-07-08 04:58:28 +04:00
while ( 1 ) {
err = time_after ( jiffies , start + ARM_WAIT_FREE ) ;
if ( rdebi ( av7110 , DEBINOSWAP , COMMAND , 0 , 2 ) = = 0 )
break ;
if ( err ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " %s: timeout waiting for COMMAND to complete \n " , __FUNCTION__ ) ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & av7110 - > dcomlock ) ;
2005-07-08 04:57:55 +04:00
return - ETIMEDOUT ;
2005-04-17 02:20:36 +04:00
}
2005-07-08 04:57:56 +04:00
# ifdef _NOHANDSHAKE
msleep ( 1 ) ;
# endif
2005-04-17 02:20:36 +04:00
}
# ifndef _NOHANDSHAKE
start = jiffies ;
2005-07-08 04:58:28 +04:00
while ( 1 ) {
err = time_after ( jiffies , start + ARM_WAIT_SHAKE ) ;
if ( rdebi ( av7110 , DEBINOSWAP , HANDSHAKE_REG , 0 , 2 ) = = 0 )
break ;
if ( err ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " %s: timeout waiting for HANDSHAKE_REG \n " , __FUNCTION__ ) ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & av7110 - > dcomlock ) ;
2005-07-08 04:57:55 +04:00
return - ETIMEDOUT ;
2005-04-17 02:20:36 +04:00
}
2005-07-08 04:57:56 +04:00
msleep ( 1 ) ;
2005-04-17 02:20:36 +04:00
}
# endif
# ifdef COM_DEBUG
stat = rdebi ( av7110 , DEBINOSWAP , MSGSTATE , 0 , 2 ) ;
if ( stat & GPMQOver ) {
printk ( KERN_ERR " %s: GPMQOver \n " , __FUNCTION__ ) ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & av7110 - > dcomlock ) ;
2005-04-17 02:20:36 +04:00
return - 1 ;
}
else if ( stat & OSDQOver ) {
printk ( KERN_ERR " %s: OSDQOver \n " , __FUNCTION__ ) ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & av7110 - > dcomlock ) ;
2005-04-17 02:20:36 +04:00
return - 1 ;
}
# endif
for ( i = 0 ; i < reply_buf_len ; i + + )
reply_buf [ i ] = rdebi ( av7110 , DEBINOSWAP , COM_BUFF + 2 * i , 0 , 2 ) ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & av7110 - > dcomlock ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2005-05-17 08:54:38 +04:00
static int av7110_fw_query ( struct av7110 * av7110 , u16 tag , u16 * buf , s16 length )
2005-04-17 02:20:36 +04:00
{
int ret ;
ret = av7110_fw_request ( av7110 , & tag , 0 , buf , length ) ;
if ( ret )
printk ( KERN_ERR " dvb-ttpci: av7110_fw_query error %d \n " , ret ) ;
return ret ;
}
/****************************************************************************
* Firmware commands
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* get version of the firmware ROM, RTSL, video ucode and ARM application */
int av7110_firmversion ( struct av7110 * av7110 )
{
u16 buf [ 20 ] ;
u16 tag = ( ( COMTYPE_REQUEST < < 8 ) + ReqVersion ) ;
dprintk ( 4 , " %p \n " , av7110 ) ;
if ( av7110_fw_query ( av7110 , tag , buf , 16 ) ) {
printk ( " dvb-ttpci: failed to boot firmware @ card %d \n " ,
2005-05-17 08:54:39 +04:00
av7110 - > dvb_adapter . num ) ;
2005-04-17 02:20:36 +04:00
return - EIO ;
}
av7110 - > arm_fw = ( buf [ 0 ] < < 16 ) + buf [ 1 ] ;
av7110 - > arm_rtsl = ( buf [ 2 ] < < 16 ) + buf [ 3 ] ;
av7110 - > arm_vid = ( buf [ 4 ] < < 16 ) + buf [ 5 ] ;
av7110 - > arm_app = ( buf [ 6 ] < < 16 ) + buf [ 7 ] ;
av7110 - > avtype = ( buf [ 8 ] < < 16 ) + buf [ 9 ] ;
printk ( " dvb-ttpci: info @ card %d: firm %08x, rtsl %08x, vid %08x, app %08x \n " ,
2005-05-17 08:54:39 +04:00
av7110 - > dvb_adapter . num , av7110 - > arm_fw ,
2005-04-17 02:20:36 +04:00
av7110 - > arm_rtsl , av7110 - > arm_vid , av7110 - > arm_app ) ;
/* print firmware capabilities */
if ( FW_CI_LL_SUPPORT ( av7110 - > arm_app ) )
printk ( " dvb-ttpci: firmware @ card %d supports CI link layer interface \n " ,
2005-05-17 08:54:39 +04:00
av7110 - > dvb_adapter . num ) ;
2005-04-17 02:20:36 +04:00
else
printk ( " dvb-ttpci: no firmware support for CI link layer interface @ card %d \n " ,
2005-05-17 08:54:39 +04:00
av7110 - > dvb_adapter . num ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
int av7110_diseqc_send ( struct av7110 * av7110 , int len , u8 * msg , unsigned long burst )
{
int i , ret ;
u16 buf [ 18 ] = { ( ( COMTYPE_AUDIODAC < < 8 ) + SendDiSEqC ) ,
16 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ;
dprintk ( 4 , " %p \n " , av7110 ) ;
if ( len > 10 )
len = 10 ;
buf [ 1 ] = len + 2 ;
buf [ 2 ] = len ;
if ( burst ! = - 1 )
buf [ 3 ] = burst ? 0x01 : 0x00 ;
else
buf [ 3 ] = 0xffff ;
for ( i = 0 ; i < len ; i + + )
buf [ i + 4 ] = msg [ i ] ;
2005-07-08 04:57:55 +04:00
ret = av7110_send_fw_cmd ( av7110 , buf , 18 ) ;
if ( ret & & ret ! = - ERESTARTSYS )
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " dvb-ttpci: av7110_diseqc_send error %d \n " , ret ) ;
2005-07-08 04:57:55 +04:00
return ret ;
2005-04-17 02:20:36 +04:00
}
# ifdef CONFIG_DVB_AV7110_OSD
static inline int SetColorBlend ( struct av7110 * av7110 , u8 windownr )
{
return av7110_fw_cmd ( av7110 , COMTYPE_OSD , SetCBlend , 1 , windownr ) ;
}
static inline int SetBlend_ ( struct av7110 * av7110 , u8 windownr ,
enum av7110_osd_palette_type colordepth , u16 index , u8 blending )
{
return av7110_fw_cmd ( av7110 , COMTYPE_OSD , SetBlend , 4 ,
windownr , colordepth , index , blending ) ;
}
static inline int SetColor_ ( struct av7110 * av7110 , u8 windownr ,
enum av7110_osd_palette_type colordepth , u16 index , u16 colorhi , u16 colorlo )
{
return av7110_fw_cmd ( av7110 , COMTYPE_OSD , SetColor , 5 ,
windownr , colordepth , index , colorhi , colorlo ) ;
}
static inline int SetFont ( struct av7110 * av7110 , u8 windownr , u8 fontsize ,
u16 colorfg , u16 colorbg )
{
return av7110_fw_cmd ( av7110 , COMTYPE_OSD , Set_Font , 4 ,
windownr , fontsize , colorfg , colorbg ) ;
}
static int FlushText ( struct av7110 * av7110 )
{
unsigned long start ;
2005-07-08 04:58:28 +04:00
int err ;
2005-04-17 02:20:36 +04:00
2006-02-07 11:49:14 +03:00
if ( mutex_lock_interruptible ( & av7110 - > dcomlock ) )
2005-04-17 02:20:36 +04:00
return - ERESTARTSYS ;
start = jiffies ;
2005-07-08 04:58:28 +04:00
while ( 1 ) {
err = time_after ( jiffies , start + ARM_WAIT_OSD ) ;
if ( rdebi ( av7110 , DEBINOSWAP , BUFF1_BASE , 0 , 2 ) = = 0 )
break ;
if ( err ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " dvb-ttpci: %s(): timeout waiting for BUFF1_BASE == 0 \n " ,
__FUNCTION__ ) ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & av7110 - > dcomlock ) ;
2005-07-08 04:57:55 +04:00
return - ETIMEDOUT ;
2005-04-17 02:20:36 +04:00
}
2005-07-08 04:57:56 +04:00
msleep ( 1 ) ;
2005-04-17 02:20:36 +04:00
}
2006-02-07 11:49:14 +03:00
mutex_unlock ( & av7110 - > dcomlock ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2007-07-13 03:37:50 +04:00
static int WriteText ( struct av7110 * av7110 , u8 win , u16 x , u16 y , char * buf )
2005-04-17 02:20:36 +04:00
{
int i , ret ;
unsigned long start ;
int length = strlen ( buf ) + 1 ;
u16 cbuf [ 5 ] = { ( COMTYPE_OSD < < 8 ) + DText , 3 , win , x , y } ;
2006-02-07 11:49:14 +03:00
if ( mutex_lock_interruptible ( & av7110 - > dcomlock ) )
2005-04-17 02:20:36 +04:00
return - ERESTARTSYS ;
start = jiffies ;
2005-07-08 04:58:28 +04:00
while ( 1 ) {
ret = time_after ( jiffies , start + ARM_WAIT_OSD ) ;
if ( rdebi ( av7110 , DEBINOSWAP , BUFF1_BASE , 0 , 2 ) = = 0 )
break ;
if ( ret ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " dvb-ttpci: %s: timeout waiting for BUFF1_BASE == 0 \n " ,
__FUNCTION__ ) ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & av7110 - > dcomlock ) ;
2005-07-08 04:57:55 +04:00
return - ETIMEDOUT ;
2005-04-17 02:20:36 +04:00
}
2005-07-08 04:57:56 +04:00
msleep ( 1 ) ;
2005-04-17 02:20:36 +04:00
}
# ifndef _NOHANDSHAKE
start = jiffies ;
2005-07-08 04:58:28 +04:00
while ( 1 ) {
ret = time_after ( jiffies , start + ARM_WAIT_SHAKE ) ;
if ( rdebi ( av7110 , DEBINOSWAP , HANDSHAKE_REG , 0 , 2 ) = = 0 )
break ;
if ( ret ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " dvb-ttpci: %s: timeout waiting for HANDSHAKE_REG \n " ,
__FUNCTION__ ) ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & av7110 - > dcomlock ) ;
2005-07-08 04:57:55 +04:00
return - ETIMEDOUT ;
2005-04-17 02:20:36 +04:00
}
2005-07-08 04:57:56 +04:00
msleep ( 1 ) ;
2005-04-17 02:20:36 +04:00
}
# endif
for ( i = 0 ; i < length / 2 ; i + + )
wdebi ( av7110 , DEBINOSWAP , BUFF1_BASE + i * 2 ,
swab16 ( * ( u16 * ) ( buf + 2 * i ) ) , 2 ) ;
if ( length & 1 )
wdebi ( av7110 , DEBINOSWAP , BUFF1_BASE + i * 2 , 0 , 2 ) ;
ret = __av7110_send_fw_cmd ( av7110 , cbuf , 5 ) ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & av7110 - > dcomlock ) ;
2005-07-08 04:57:55 +04:00
if ( ret & & ret ! = - ERESTARTSYS )
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " dvb-ttpci: WriteText error %d \n " , ret ) ;
return ret ;
}
static inline int DrawLine ( struct av7110 * av7110 , u8 windownr ,
u16 x , u16 y , u16 dx , u16 dy , u16 color )
{
return av7110_fw_cmd ( av7110 , COMTYPE_OSD , DLine , 6 ,
windownr , x , y , dx , dy , color ) ;
}
static inline int DrawBlock ( struct av7110 * av7110 , u8 windownr ,
u16 x , u16 y , u16 dx , u16 dy , u16 color )
{
return av7110_fw_cmd ( av7110 , COMTYPE_OSD , DBox , 6 ,
windownr , x , y , dx , dy , color ) ;
}
static inline int HideWindow ( struct av7110 * av7110 , u8 windownr )
{
return av7110_fw_cmd ( av7110 , COMTYPE_OSD , WHide , 1 , windownr ) ;
}
static inline int MoveWindowRel ( struct av7110 * av7110 , u8 windownr , u16 x , u16 y )
{
return av7110_fw_cmd ( av7110 , COMTYPE_OSD , WMoveD , 3 , windownr , x , y ) ;
}
static inline int MoveWindowAbs ( struct av7110 * av7110 , u8 windownr , u16 x , u16 y )
{
return av7110_fw_cmd ( av7110 , COMTYPE_OSD , WMoveA , 3 , windownr , x , y ) ;
}
static inline int DestroyOSDWindow ( struct av7110 * av7110 , u8 windownr )
{
return av7110_fw_cmd ( av7110 , COMTYPE_OSD , WDestroy , 1 , windownr ) ;
}
static inline int CreateOSDWindow ( struct av7110 * av7110 , u8 windownr ,
osd_raw_window_t disptype ,
u16 width , u16 height )
{
return av7110_fw_cmd ( av7110 , COMTYPE_OSD , WCreate , 4 ,
windownr , disptype , width , height ) ;
}
static enum av7110_osd_palette_type bpp2pal [ 8 ] = {
Pal1Bit , Pal2Bit , 0 , Pal4Bit , 0 , 0 , 0 , Pal8Bit
} ;
static osd_raw_window_t bpp2bit [ 8 ] = {
OSD_BITMAP1 , OSD_BITMAP2 , 0 , OSD_BITMAP4 , 0 , 0 , 0 , OSD_BITMAP8
} ;
2005-07-08 04:57:55 +04:00
static inline int WaitUntilBmpLoaded ( struct av7110 * av7110 )
{
int ret = wait_event_interruptible_timeout ( av7110 - > bmpq ,
av7110 - > bmp_state ! = BMP_LOADING , 10 * HZ ) ;
if ( ret = = - ERESTARTSYS )
return ret ;
if ( ret = = 0 ) {
printk ( " dvb-ttpci: warning: timeout waiting in LoadBitmap: %d, %d \n " ,
ret , av7110 - > bmp_state ) ;
av7110 - > bmp_state = BMP_NONE ;
return - ETIMEDOUT ;
}
return 0 ;
}
static inline int LoadBitmap ( struct av7110 * av7110 ,
2005-04-17 02:20:36 +04:00
u16 dx , u16 dy , int inc , u8 __user * data )
{
2005-07-08 04:57:55 +04:00
u16 format ;
2005-04-17 02:20:36 +04:00
int bpp ;
int i ;
int d , delta ;
u8 c ;
int ret ;
dprintk ( 4 , " %p \n " , av7110 ) ;
2005-07-08 04:57:55 +04:00
format = bpp2bit [ av7110 - > osdbpp [ av7110 - > osdwin ] ] ;
2005-04-17 02:20:36 +04:00
av7110 - > bmp_state = BMP_LOADING ;
if ( format = = OSD_BITMAP8 ) {
bpp = 8 ; delta = 1 ;
} else if ( format = = OSD_BITMAP4 ) {
bpp = 4 ; delta = 2 ;
} else if ( format = = OSD_BITMAP2 ) {
bpp = 2 ; delta = 4 ;
} else if ( format = = OSD_BITMAP1 ) {
bpp = 1 ; delta = 8 ;
} else {
av7110 - > bmp_state = BMP_NONE ;
2005-07-08 04:57:55 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
}
av7110 - > bmplen = ( ( dx * dy * bpp + 7 ) & ~ 7 ) / 8 ;
av7110 - > bmpp = 0 ;
if ( av7110 - > bmplen > 32768 ) {
av7110 - > bmp_state = BMP_NONE ;
2005-07-08 04:57:55 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
}
for ( i = 0 ; i < dy ; i + + ) {
if ( copy_from_user ( av7110 - > bmpbuf + 1024 + i * dx , data + i * inc , dx ) ) {
av7110 - > bmp_state = BMP_NONE ;
2005-07-08 04:57:55 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
}
}
if ( format ! = OSD_BITMAP8 ) {
for ( i = 0 ; i < dx * dy / delta ; i + + ) {
c = ( ( u8 * ) av7110 - > bmpbuf ) [ 1024 + i * delta + delta - 1 ] ;
for ( d = delta - 2 ; d > = 0 ; d - - ) {
c | = ( ( ( u8 * ) av7110 - > bmpbuf ) [ 1024 + i * delta + d ]
< < ( ( delta - d - 1 ) * bpp ) ) ;
( ( u8 * ) av7110 - > bmpbuf ) [ 1024 + i ] = c ;
}
}
}
av7110 - > bmplen + = 1024 ;
dprintk ( 4 , " av7110_fw_cmd: LoadBmp size %d \n " , av7110 - > bmplen ) ;
2005-07-08 04:57:55 +04:00
ret = av7110_fw_cmd ( av7110 , COMTYPE_OSD , LoadBmp , 3 , format , dx , dy ) ;
if ( ! ret )
ret = WaitUntilBmpLoaded ( av7110 ) ;
return ret ;
2005-04-17 02:20:36 +04:00
}
2005-07-08 04:57:55 +04:00
static int BlitBitmap ( struct av7110 * av7110 , u16 x , u16 y )
2005-04-17 02:20:36 +04:00
{
dprintk ( 4 , " %p \n " , av7110 ) ;
2005-07-08 04:57:55 +04:00
return av7110_fw_cmd ( av7110 , COMTYPE_OSD , BlitBmp , 4 , av7110 - > osdwin , x , y , 0 ) ;
2005-04-17 02:20:36 +04:00
}
static inline int ReleaseBitmap ( struct av7110 * av7110 )
{
dprintk ( 4 , " %p \n " , av7110 ) ;
2005-07-08 04:57:55 +04:00
if ( av7110 - > bmp_state ! = BMP_LOADED & & FW_VERSION ( av7110 - > arm_app ) < 0x261e )
2005-04-17 02:20:36 +04:00
return - 1 ;
2005-07-08 04:57:55 +04:00
if ( av7110 - > bmp_state = = BMP_LOADING )
dprintk ( 1 , " ReleaseBitmap called while BMP_LOADING \n " ) ;
2005-04-17 02:20:36 +04:00
av7110 - > bmp_state = BMP_NONE ;
return av7110_fw_cmd ( av7110 , COMTYPE_OSD , ReleaseBmp , 0 ) ;
}
static u32 RGB2YUV ( u16 R , u16 G , u16 B )
{
u16 y , u , v ;
u16 Y , Cr , Cb ;
y = R * 77 + G * 150 + B * 29 ; /* Luma=0.299R+0.587G+0.114B 0..65535 */
u = 2048 + B * 8 - ( y > > 5 ) ; /* Cr 0..4095 */
v = 2048 + R * 8 - ( y > > 5 ) ; /* Cb 0..4095 */
Y = y / 256 ;
Cb = u / 16 ;
Cr = v / 16 ;
return Cr | ( Cb < < 16 ) | ( Y < < 8 ) ;
}
2005-07-08 04:57:55 +04:00
static int OSDSetColor ( struct av7110 * av7110 , u8 color , u8 r , u8 g , u8 b , u8 blend )
2005-04-17 02:20:36 +04:00
{
2005-07-08 04:57:55 +04:00
int ret ;
2005-04-17 02:20:36 +04:00
u16 ch , cl ;
u32 yuv ;
yuv = blend ? RGB2YUV ( r , g , b ) : 0 ;
cl = ( yuv & 0xffff ) ;
ch = ( ( yuv > > 16 ) & 0xffff ) ;
2005-07-08 04:57:55 +04:00
ret = SetColor_ ( av7110 , av7110 - > osdwin , bpp2pal [ av7110 - > osdbpp [ av7110 - > osdwin ] ] ,
color , ch , cl ) ;
if ( ! ret )
ret = SetBlend_ ( av7110 , av7110 - > osdwin , bpp2pal [ av7110 - > osdbpp [ av7110 - > osdwin ] ] ,
color , ( ( blend > > 4 ) & 0x0f ) ) ;
return ret ;
2005-04-17 02:20:36 +04:00
}
static int OSDSetPalette ( struct av7110 * av7110 , u32 __user * colors , u8 first , u8 last )
{
int i ;
int length = last - first + 1 ;
if ( length * 4 > DATA_BUFF3_SIZE )
return - EINVAL ;
for ( i = 0 ; i < length ; i + + ) {
u32 color , blend , yuv ;
if ( get_user ( color , colors + i ) )
return - EFAULT ;
blend = ( color & 0xF0000000 ) > > 4 ;
yuv = blend ? RGB2YUV ( color & 0xFF , ( color > > 8 ) & 0xFF ,
( color > > 16 ) & 0xFF ) | blend : 0 ;
yuv = ( ( yuv & 0xFFFF0000 ) > > 16 ) | ( ( yuv & 0x0000FFFF ) < < 16 ) ;
wdebi ( av7110 , DEBINOSWAP , DATA_BUFF3_BASE + i * 4 , yuv , 4 ) ;
}
return av7110_fw_cmd ( av7110 , COMTYPE_OSD , Set_Palette , 4 ,
av7110 - > osdwin ,
bpp2pal [ av7110 - > osdbpp [ av7110 - > osdwin ] ] ,
first , last ) ;
}
static int OSDSetBlock ( struct av7110 * av7110 , int x0 , int y0 ,
int x1 , int y1 , int inc , u8 __user * data )
{
uint w , h , bpp , bpl , size , lpb , bnum , brest ;
int i ;
2005-07-08 04:57:55 +04:00
int rc , release_rc ;
2005-04-17 02:20:36 +04:00
w = x1 - x0 + 1 ;
h = y1 - y0 + 1 ;
if ( inc < = 0 )
inc = w ;
if ( w < = 0 | | w > 720 | | h < = 0 | | h > 576 )
2005-07-08 04:57:55 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
bpp = av7110 - > osdbpp [ av7110 - > osdwin ] + 1 ;
bpl = ( ( w * bpp + 7 ) & ~ 7 ) / 8 ;
size = h * bpl ;
lpb = ( 32 * 1024 ) / bpl ;
bnum = size / ( lpb * bpl ) ;
brest = size - bnum * lpb * bpl ;
2005-07-08 04:57:55 +04:00
if ( av7110 - > bmp_state = = BMP_LOADING ) {
/* possible if syscall is repeated by -ERESTARTSYS and if firmware cannot abort */
BUG_ON ( FW_VERSION ( av7110 - > arm_app ) > = 0x261e ) ;
rc = WaitUntilBmpLoaded ( av7110 ) ;
2005-04-17 02:20:36 +04:00
if ( rc )
return rc ;
2005-07-08 04:57:55 +04:00
/* just continue. This should work for all fw versions
* if bnum = = 1 & & ! brest & & LoadBitmap was successful
*/
2005-04-17 02:20:36 +04:00
}
2005-07-08 04:57:55 +04:00
rc = 0 ;
for ( i = 0 ; i < bnum ; i + + ) {
rc = LoadBitmap ( av7110 , w , lpb , inc , data ) ;
2005-04-17 02:20:36 +04:00
if ( rc )
2005-07-08 04:57:55 +04:00
break ;
rc = BlitBitmap ( av7110 , x0 , y0 + i * lpb ) ;
2005-04-17 02:20:36 +04:00
if ( rc )
2005-07-08 04:57:55 +04:00
break ;
data + = lpb * inc ;
2005-04-17 02:20:36 +04:00
}
2005-07-08 04:57:55 +04:00
if ( ! rc & & brest ) {
rc = LoadBitmap ( av7110 , w , brest / bpl , inc , data ) ;
if ( ! rc )
rc = BlitBitmap ( av7110 , x0 , y0 + bnum * lpb ) ;
}
release_rc = ReleaseBitmap ( av7110 ) ;
if ( ! rc )
rc = release_rc ;
if ( rc )
dprintk ( 1 , " returns %d \n " , rc ) ;
return rc ;
2005-04-17 02:20:36 +04:00
}
int av7110_osd_cmd ( struct av7110 * av7110 , osd_cmd_t * dc )
{
int ret ;
2006-02-07 11:49:14 +03:00
if ( mutex_lock_interruptible ( & av7110 - > osd_mutex ) )
2005-04-17 02:20:36 +04:00
return - ERESTARTSYS ;
switch ( dc - > cmd ) {
case OSD_Close :
2005-07-08 04:57:55 +04:00
ret = DestroyOSDWindow ( av7110 , av7110 - > osdwin ) ;
break ;
2005-04-17 02:20:36 +04:00
case OSD_Open :
av7110 - > osdbpp [ av7110 - > osdwin ] = ( dc - > color - 1 ) & 7 ;
2005-07-08 04:57:55 +04:00
ret = CreateOSDWindow ( av7110 , av7110 - > osdwin ,
2005-04-17 02:20:36 +04:00
bpp2bit [ av7110 - > osdbpp [ av7110 - > osdwin ] ] ,
dc - > x1 - dc - > x0 + 1 , dc - > y1 - dc - > y0 + 1 ) ;
2005-07-08 04:57:55 +04:00
if ( ret )
break ;
2005-04-17 02:20:36 +04:00
if ( ! dc - > data ) {
2005-07-08 04:57:55 +04:00
ret = MoveWindowAbs ( av7110 , av7110 - > osdwin , dc - > x0 , dc - > y0 ) ;
if ( ret )
break ;
ret = SetColorBlend ( av7110 , av7110 - > osdwin ) ;
2005-04-17 02:20:36 +04:00
}
2005-07-08 04:57:55 +04:00
break ;
2005-04-17 02:20:36 +04:00
case OSD_Show :
2005-07-08 04:57:55 +04:00
ret = MoveWindowRel ( av7110 , av7110 - > osdwin , 0 , 0 ) ;
break ;
2005-04-17 02:20:36 +04:00
case OSD_Hide :
2005-07-08 04:57:55 +04:00
ret = HideWindow ( av7110 , av7110 - > osdwin ) ;
break ;
2005-04-17 02:20:36 +04:00
case OSD_Clear :
2005-07-08 04:57:55 +04:00
ret = DrawBlock ( av7110 , av7110 - > osdwin , 0 , 0 , 720 , 576 , 0 ) ;
break ;
2005-04-17 02:20:36 +04:00
case OSD_Fill :
2005-07-08 04:57:55 +04:00
ret = DrawBlock ( av7110 , av7110 - > osdwin , 0 , 0 , 720 , 576 , dc - > color ) ;
break ;
2005-04-17 02:20:36 +04:00
case OSD_SetColor :
2005-07-08 04:57:55 +04:00
ret = OSDSetColor ( av7110 , dc - > color , dc - > x0 , dc - > y0 , dc - > x1 , dc - > y1 ) ;
break ;
2005-04-17 02:20:36 +04:00
case OSD_SetPalette :
2005-07-08 04:57:55 +04:00
if ( FW_VERSION ( av7110 - > arm_app ) > = 0x2618 )
2005-04-17 02:20:36 +04:00
ret = OSDSetPalette ( av7110 , dc - > data , dc - > color , dc - > x0 ) ;
2005-07-08 04:57:55 +04:00
else {
2005-04-17 02:20:36 +04:00
int i , len = dc - > x0 - dc - > color + 1 ;
u8 __user * colors = ( u8 __user * ) dc - > data ;
u8 r , g , b , blend ;
2005-07-08 04:57:55 +04:00
ret = 0 ;
2005-04-17 02:20:36 +04:00
for ( i = 0 ; i < len ; i + + ) {
if ( get_user ( r , colors + i * 4 ) | |
get_user ( g , colors + i * 4 + 1 ) | |
get_user ( b , colors + i * 4 + 2 ) | |
get_user ( blend , colors + i * 4 + 3 ) ) {
ret = - EFAULT ;
2005-07-08 04:57:55 +04:00
break ;
2005-04-17 02:20:36 +04:00
}
2005-07-08 04:57:55 +04:00
ret = OSDSetColor ( av7110 , dc - > color + i , r , g , b , blend ) ;
if ( ret )
break ;
2005-04-17 02:20:36 +04:00
}
}
2005-07-08 04:57:55 +04:00
break ;
2005-04-17 02:20:36 +04:00
case OSD_SetPixel :
2005-07-08 04:57:55 +04:00
ret = DrawLine ( av7110 , av7110 - > osdwin ,
2005-04-17 02:20:36 +04:00
dc - > x0 , dc - > y0 , 0 , 0 , dc - > color ) ;
2005-07-08 04:57:55 +04:00
break ;
2005-04-17 02:20:36 +04:00
case OSD_SetRow :
dc - > y1 = dc - > y0 ;
/* fall through */
case OSD_SetBlock :
ret = OSDSetBlock ( av7110 , dc - > x0 , dc - > y0 , dc - > x1 , dc - > y1 , dc - > color , dc - > data ) ;
2005-07-08 04:57:55 +04:00
break ;
2005-04-17 02:20:36 +04:00
case OSD_FillRow :
2005-07-08 04:57:55 +04:00
ret = DrawBlock ( av7110 , av7110 - > osdwin , dc - > x0 , dc - > y0 ,
2005-04-17 02:20:36 +04:00
dc - > x1 - dc - > x0 + 1 , dc - > y1 , dc - > color ) ;
2005-07-08 04:57:55 +04:00
break ;
2005-04-17 02:20:36 +04:00
case OSD_FillBlock :
2005-07-08 04:57:55 +04:00
ret = DrawBlock ( av7110 , av7110 - > osdwin , dc - > x0 , dc - > y0 ,
2005-04-17 02:20:36 +04:00
dc - > x1 - dc - > x0 + 1 , dc - > y1 - dc - > y0 + 1 , dc - > color ) ;
2005-07-08 04:57:55 +04:00
break ;
2005-04-17 02:20:36 +04:00
case OSD_Line :
2005-07-08 04:57:55 +04:00
ret = DrawLine ( av7110 , av7110 - > osdwin ,
2005-04-17 02:20:36 +04:00
dc - > x0 , dc - > y0 , dc - > x1 - dc - > x0 , dc - > y1 - dc - > y0 , dc - > color ) ;
2005-07-08 04:57:55 +04:00
break ;
2005-04-17 02:20:36 +04:00
case OSD_Text :
{
char textbuf [ 240 ] ;
if ( strncpy_from_user ( textbuf , dc - > data , 240 ) < 0 ) {
ret = - EFAULT ;
2005-07-08 04:57:55 +04:00
break ;
2005-04-17 02:20:36 +04:00
}
textbuf [ 239 ] = 0 ;
if ( dc - > x1 > 3 )
dc - > x1 = 3 ;
2005-07-08 04:57:55 +04:00
ret = SetFont ( av7110 , av7110 - > osdwin , dc - > x1 ,
2005-04-17 02:20:36 +04:00
( u16 ) ( dc - > color & 0xffff ) , ( u16 ) ( dc - > color > > 16 ) ) ;
2005-07-08 04:57:55 +04:00
if ( ! ret )
ret = FlushText ( av7110 ) ;
if ( ! ret )
ret = WriteText ( av7110 , av7110 - > osdwin , dc - > x0 , dc - > y0 , textbuf ) ;
break ;
2005-04-17 02:20:36 +04:00
}
case OSD_SetWindow :
2005-07-08 04:57:55 +04:00
if ( dc - > x0 < 1 | | dc - > x0 > 7 )
2005-04-17 02:20:36 +04:00
ret = - EINVAL ;
2005-07-08 04:57:55 +04:00
else {
av7110 - > osdwin = dc - > x0 ;
ret = 0 ;
2005-04-17 02:20:36 +04:00
}
2005-07-08 04:57:55 +04:00
break ;
2005-04-17 02:20:36 +04:00
case OSD_MoveWindow :
2005-07-08 04:57:55 +04:00
ret = MoveWindowAbs ( av7110 , av7110 - > osdwin , dc - > x0 , dc - > y0 ) ;
if ( ! ret )
ret = SetColorBlend ( av7110 , av7110 - > osdwin ) ;
break ;
2005-04-17 02:20:36 +04:00
case OSD_OpenRaw :
if ( dc - > color < OSD_BITMAP1 | | dc - > color > OSD_CURSOR ) {
ret = - EINVAL ;
2005-07-08 04:57:55 +04:00
break ;
2005-04-17 02:20:36 +04:00
}
2005-07-08 04:57:55 +04:00
if ( dc - > color > = OSD_BITMAP1 & & dc - > color < = OSD_BITMAP8HR )
2005-04-17 02:20:36 +04:00
av7110 - > osdbpp [ av7110 - > osdwin ] = ( 1 < < ( dc - > color & 3 ) ) - 1 ;
2005-07-08 04:57:55 +04:00
else
2005-04-17 02:20:36 +04:00
av7110 - > osdbpp [ av7110 - > osdwin ] = 0 ;
2005-07-08 04:57:55 +04:00
ret = CreateOSDWindow ( av7110 , av7110 - > osdwin , ( osd_raw_window_t ) dc - > color ,
2005-04-17 02:20:36 +04:00
dc - > x1 - dc - > x0 + 1 , dc - > y1 - dc - > y0 + 1 ) ;
2005-07-08 04:57:55 +04:00
if ( ret )
break ;
2005-04-17 02:20:36 +04:00
if ( ! dc - > data ) {
2005-07-08 04:57:55 +04:00
ret = MoveWindowAbs ( av7110 , av7110 - > osdwin , dc - > x0 , dc - > y0 ) ;
if ( ! ret )
ret = SetColorBlend ( av7110 , av7110 - > osdwin ) ;
2005-04-17 02:20:36 +04:00
}
2005-07-08 04:57:55 +04:00
break ;
2005-04-17 02:20:36 +04:00
default :
ret = - EINVAL ;
2005-07-08 04:57:55 +04:00
break ;
2005-04-17 02:20:36 +04:00
}
2006-02-07 11:49:14 +03:00
mutex_unlock ( & av7110 - > osd_mutex ) ;
2005-07-08 04:57:55 +04:00
if ( ret = = - ERESTARTSYS )
dprintk ( 1 , " av7110_osd_cmd(%d) returns with -ERESTARTSYS \n " , dc - > cmd ) ;
else if ( ret )
dprintk ( 1 , " av7110_osd_cmd(%d) returns with %d \n " , dc - > cmd , ret ) ;
2005-04-17 02:20:36 +04:00
return ret ;
}
int av7110_osd_capability ( struct av7110 * av7110 , osd_cap_t * cap )
{
2005-12-12 11:37:24 +03:00
switch ( cap - > cmd ) {
case OSD_CAP_MEMSIZE :
if ( FW_4M_SDRAM ( av7110 - > arm_app ) )
2006-01-09 20:25:34 +03:00
cap - > val = 1000000 ;
2005-12-12 11:37:24 +03:00
else
2006-01-09 20:25:34 +03:00
cap - > val = 92000 ;
2005-12-12 11:37:24 +03:00
return 0 ;
default :
return - EINVAL ;
}
2005-04-17 02:20:36 +04:00
}
# endif /* CONFIG_DVB_AV7110_OSD */