/*
cvdv.c
Copyright (C) Christian Wolff for convergence integrated media.
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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/////////////////////////////////////////////////////////////////////
// //
// Driver for the Convergence Digital Video decoder card (pci) //
// with L64017, L64021, PCM1723, and Bt864/Bt865 chipset //
// (c) Christian Wolff 19990209 for convergence integrated media //
// //
/////////////////////////////////////////////////////////////////////
// Convergence CV2300i
#define __NO_VERSION__
#include "cvdv.h"
#include "i2c.h"
//////////////////////
// global variables //
//////////////////////
// Our major device number
unsigned int major_device_number;
// my little random function for memory test
u16 rnd_seed;
u16 rnd(u16 range)
{ // returns random 0..(range-1) range<=872
u32 b = 75 * (rnd_seed + 1) - 1;
rnd_seed = (u16) (b & 0xFFFF);
return ((b * range) / 0xFFFF) - ((b / 0xFFFF) * range);
}
void rnd_omize(void)
{
rnd_seed = (u16) jiffies;
}
/////////////////////////////////////////////
// //
// Controlling the L64021 MPEG-2 Decoder //
// //
/////////////////////////////////////////////
int OSDTest(struct cvdv_cards *card)
{
int i, j, x, y, col, xpos, ypos, x0, y0, x1, y1, aspx, aspy, width,
height;
u8 row[130];
if (!card->OSD.open)
return -2;
//VideoSetBackground(card,2,83,90,249); // Red
//VideoSetBackground(card,2,155,53,53); // Green
//VideoSetBackground(card,2,35,212,114); // Blue
//VideoSetBackground(card,2,4,128,128); // Black
OSDQuery(card, &x0, &y0, &x1, &y1, &aspx);
aspy = 11;
width = 130;
height = width * aspy / aspx;
xpos = ((x1 - x0 + 1) - width) / 2;
ypos = ((y1 - y0 + 1) - height) / 2;
OSDShow(card);
OSDSetColor(card, 0, 0, 0, 0, 1, 0, 1); // transparent background
for (i = 0; i < 2; i++) {
for (j = 0; j < 8; j++) {
col = 1 + i * 8 + j;
OSDSetColor(card, col, (j & 2) ? 192 : 0,
(j & 4) ? 192 : 0, (j & 1) ? 192 : 0,
1, i, 0);
}
}
// for (x=1; x<=16; x++) {
// OSDFill(card,x);
// }
// OSDClear(card);
for (i = 0; i < 2; i++) {
for (j = 0; j < 8; j++) {
col = 1 + i * 8 + j;
for (x = 0; x < 16; x++)
row[1 + x + j * 16] = col;
}
for (y = 0; y < (height - 2) / 2; y++) {
OSDSetRow(card, xpos,
ypos + 1 + y + i * ((height - 2) / 2),
xpos + width - 1, row);
}
}
OSDFillRow(card, xpos, ypos, xpos + width - 1, 8);
OSDFillRow(card, xpos, ypos + height - 1, xpos + width - 1, 8);
for (y = ypos; y < ypos + height; y++) {
OSDSetPixel(card, xpos, y, 8);
OSDSetPixel(card, xpos + width - 1, y, 8);
}
for (x = 0; x < 130; x++) {
OSDSetPixel(card, x + xpos, x * aspy / aspx + ypos, 8);
OSDSetPixel(card, width - x + xpos, x * aspy / aspx + ypos,
8);
OSDSetPixel(card, x + xpos,
(x >> 3) + ypos + ((height / 2) - 8), 8);
}
OSDLine(card, x0, y0, x1, y0, 8);
OSDLine(card, x1, y0, x1, y1, 8);
OSDLine(card, x1, y1, x0, y1, 8);
OSDLine(card, x0, y1, x0, y0, 8);
OSDLine(card, x0, y0, x1, y1, 8);
OSDLine(card, x0, y1, x1, y0, 8);
// OSDShow(card);
return 0;
}
void SetVideoSystem(struct cvdv_cards *card)
{
// set the hsync and vsync generators in the L64017 according to the video standard
switch (card->videomode) {
case PAL: // 864*625*50Hz = 27MHz, 25fps
I2CWrite(card, card->i2c_addr, CS_CONTROL0, 0x41 | 0x0a);
I2CWrite(card, card->i2c_addr, CS_CONTROL1, 0x04);
I2CWrite(card, card->i2c_addr, CS_SC_AMP, 0x15);
I2CWrite(card, card->i2c_addr, CS_SC_SYNTH0, 0x96);
I2CWrite(card, card->i2c_addr, CS_SC_SYNTH1, 0x15);
I2CWrite(card, card->i2c_addr, CS_SC_SYNTH2, 0x13);
I2CWrite(card, card->i2c_addr, CS_SC_SYNTH3, 0x54);
write_indexed_register(card, IIO_VIDEO_CONTROL1, VMS_PAL);
break;
case PALN:
I2CWrite(card, card->i2c_addr, CS_CONTROL0, 0xa1 | 0x0a);
I2CWrite(card, card->i2c_addr, CS_CONTROL1, 0x04);
I2CWrite(card, card->i2c_addr, CS_SC_AMP, 0x15);
I2CWrite(card, card->i2c_addr, CS_SC_SYNTH0, 0x96);
I2CWrite(card, card->i2c_addr, CS_SC_SYNTH1, 0x15);
I2CWrite(card, card->i2c_addr, CS_SC_SYNTH2, 0x13);
I2CWrite(card, card->i2c_addr, CS_SC_SYNTH3, 0x54);
write_indexed_register(card, IIO_VIDEO_CONTROL1, VMS_PAL);
break;
case PALNc:
I2CWrite(card, card->i2c_addr, CS_CONTROL0, 0x81 | 0x0a);
I2CWrite(card, card->i2c_addr, CS_CONTROL1, 0x04);
I2CWrite(card, card->i2c_addr, CS_SC_AMP, 0x15);
I2CWrite(card, card->i2c_addr, CS_SC_SYNTH0, 0x8c);
I2CWrite(card, card->i2c_addr, CS_SC_SYNTH1, 0x28);
I2CWrite(card, card->i2c_addr, CS_SC_SYNTH2, 0xed);
I2CWrite(card, card->i2c_addr, CS_SC_SYNTH3, 0x43);
write_indexed_register(card, IIO_VIDEO_CONTROL1, VMS_PAL);
break;
case NTSC: // 858*525*59.94006Hz = 27MHz, 29.97fps
I2CWrite(card, card->i2c_addr, CS_CONTROL0, 0x01 | 0x0a);
I2CWrite(card, card->i2c_addr, CS_CONTROL1, 0x04);
I2CWrite(card, card->i2c_addr, CS_SC_AMP, 0x1c);
I2CWrite(card, card->i2c_addr, CS_SC_SYNTH0, 0x3e);
I2CWrite(card, card->i2c_addr, CS_SC_SYNTH1, 0xf8);
I2CWrite(card, card->i2c_addr, CS_SC_SYNTH2, 0xe0);
I2CWrite(card, card->i2c_addr, CS_SC_SYNTH3, 0x43);
write_indexed_register(card, IIO_VIDEO_CONTROL1, VMS_NTSC);
break;
case PALM:
I2CWrite(card, card->i2c_addr, CS_CONTROL0, 0x01 | 0x0a);
I2CWrite(card, card->i2c_addr, CS_CONTROL1, 0x04);
I2CWrite(card, card->i2c_addr, CS_SC_AMP, 0x15);
I2CWrite(card, card->i2c_addr, CS_SC_SYNTH0, 0x4e);
I2CWrite(card, card->i2c_addr, CS_SC_SYNTH1, 0x4a);
I2CWrite(card, card->i2c_addr, CS_SC_SYNTH2, 0xe1);
I2CWrite(card, card->i2c_addr, CS_SC_SYNTH3, 0x43);
write_indexed_register(card, IIO_VIDEO_CONTROL1, VMS_PAL);
break;
case NTSC60: // 857*525*60.010002Hz = 27MHz, 30fps
I2CWrite(card, card->i2c_addr, CS_CONTROL0, 0x21 | 0x0a);
I2CWrite(card, card->i2c_addr, CS_CONTROL1, 0x04);
I2CWrite(card, card->i2c_addr, CS_SC_AMP, 0x1c);
I2CWrite(card, card->i2c_addr, CS_SC_SYNTH0, 0x3e);
I2CWrite(card, card->i2c_addr, CS_SC_SYNTH1, 0xf8);
I2CWrite(card, card->i2c_addr, CS_SC_SYNTH2, 0xe0);
I2CWrite(card, card->i2c_addr, CS_SC_SYNTH3, 0x43);
write_indexed_register(card, IIO_VIDEO_CONTROL1, VMS_NTSC);
break;
case PALM60:
I2CWrite(card, card->i2c_addr, CS_CONTROL0, 0x61 | 0x0a);
I2CWrite(card, card->i2c_addr, CS_CONTROL1, 0x04);
I2CWrite(card, card->i2c_addr, CS_SC_AMP, 0x15);
I2CWrite(card, card->i2c_addr, CS_SC_SYNTH0, 0x4e);
I2CWrite(card, card->i2c_addr, CS_SC_SYNTH1, 0x4a);
I2CWrite(card, card->i2c_addr, CS_SC_SYNTH2, 0xe1);
I2CWrite(card, card->i2c_addr, CS_SC_SYNTH3, 0x43);
write_indexed_register(card, IIO_VIDEO_CONTROL1, VMS_PAL);
break;
case PAL60:
break;
}
// set the pixel generators according to the video standard
L64021Setup(card);
}
int SetVideoAttr(struct cvdv_cards *card, u16 vattr)
{
u8 video_compression_mode;
u8 tv_system;
u8 aspect_ratio;
u8 display_mode;
u8 line_21_switch_1;
u8 line_21_switch_2;
u8 source_picture_resolution;
u8 source_picture_letterboxed;
u8 reserved;
u8 film_camera_mode;
u16 hsize, vsize;
if (vattr != card->lastvattr) {
video_compression_mode = (vattr >> 14) & 0x03;
tv_system = (vattr >> 12) & 0x03;
aspect_ratio = (vattr >> 10) & 0x03;
display_mode = (vattr >> 8) & 0x03;
line_21_switch_1 = (vattr >> 7) & 0x01;
line_21_switch_2 = (vattr >> 6) & 0x01;
source_picture_resolution = (vattr >> 3) & 0x07;
source_picture_letterboxed = (vattr >> 2) & 0x01;
reserved = (vattr >> 1) & 0x01;
film_camera_mode = (vattr >> 0) & 0x01;
card->videomode =
((tv_system == 0) ? NTSC : ((tv_system == 1) ?
PAL : PAL));
SetVideoSystem(card);
hsize =
((source_picture_resolution == 0) ? 720
: ((source_picture_resolution == 1) ? 702 : 352));
vsize = ((source_picture_resolution == 3)
? ((tv_system == 0) ? 240 : 288)
: ((tv_system == 0) ? 480 : 576));
if (DecoderOpen
(card, hsize, vsize, ((aspect_ratio) ? 3 : 2),
((video_compression_mode) ? 0 : 1),
source_picture_letterboxed, tv_system)) {
printk(KERN_ERR LOGNAME
": Video Decoder Open failed: On-card memory insufficient for frame stores\n");
}
card->lastvattr = vattr;
} else {
printk(KERN_ERR LOGNAME
": Video attribute not set, equal to previous one.\n");
}
return 0;
}
int SetAudioAttr(struct cvdv_cards *card, u16 aattr)
{
u8 audio_coding_mode;
u8 multichannel_extension;
u8 audio_type;
u8 audio_application_mode;
u8 quantization_drc;
u8 fs;
u8 reserved;
u8 num_audio_ch;
if (aattr) {
if (aattr != card->lastaattr) {
audio_coding_mode = (aattr >> 13) & 0x07;
multichannel_extension = (aattr >> 12) & 0x01;
audio_type = (aattr >> 10) & 0x03;
audio_application_mode = (aattr >> 8) & 0x03;
quantization_drc = (aattr >> 6) & 0x03;
fs = (aattr >> 4) & 0x03;
reserved = (aattr >> 3) & 0x01;
num_audio_ch = (aattr >> 0) & 0x07;
switch (audio_coding_mode) {
case 0: // AC-3
card->setup.audioselect = audio_AC3;
break;
case 2: // MPEG Audio
card->setup.audioselect = audio_MPEG;
break;
case 3: // MPEG Audio with ext.
card->setup.audioselect = audio_MPEG_EXT;
break;
case 4: // Linear Pulse Code Modulation LPCM
card->setup.audioselect = audio_LPCM;
break;
case 6: // DTS
card->setup.audioselect = audio_DTS;
break;
case 7: // SDDS
card->setup.audioselect = audio_SDDS;
break;
}
DecoderPrepareAudio(card);
AudioInit(card, ((fs) ? 96 : 48),
((audio_application_mode == 2) ? 1 : 0));
} else {
printk(KERN_ERR LOGNAME
": Audio attribute not set, equal to previous one.\n");
}
} else {
card->setup.audioselect = audio_none;
DecoderPrepareAudio(card);
}
card->lastaattr = aattr;
return 0;
}
int Prepare(struct cvdv_cards *card)
{
int err, h;
struct StreamSetup *setup = &card->setup;
if (!card->ChannelBuffersAllocated) {
DecoderStreamReset(card);
if (setup->streamtype == stream_none) {
setup->streamtype = stream_PS;
}
if (setup->audioselect == audio_none) {
setup->audioselect = audio_MPEG;
}
DecoderPrepareAudio(card);
AudioMute(card, 1);
DecoderPrepareVideo(card);
VideoSetBackground(card, 1, 0, 0, 0); // black
switch (setup->streamtype) {
default:
case stream_none: // unknown stream!
printk(KERN_ERR LOGNAME
": Video Decoder Prepare failed: unknown stream type\n");
return -ENODEV; // not an MPEG stream!
case stream_ES: // Elementary Stream
err = DecoderPrepareES(card);
break;
case stream_PES: // Packetized Elementary Stream
err = DecoderPreparePES(card);
break;
case stream_PS: // MPEG-1 System Stream / MPEG-2 Program Stream
err = DecoderPreparePS(card, -1, 0, 0, 0, 0, 0);
break;
case stream_DVD: // DVD Stream
err = DecoderPreparePS(card, 0, 0, 0, 0, 3, 1);
break;
}
if (err) { // insufficient memory
printk(KERN_ERR LOGNAME
": Video Decoder Prepare failed: no kernel memory, please reboot if possible\n");
CloseCard(card);
return -ENODEV;
}
}
// Set up the Video Decoder as we have the stream information
if ((!card->FrameBuffersAllocated)
&& (card->ChannelBuffersAllocated) && (card->stream.sh.valid)) {
//printk(KERN_DEBUG LOGNAME ": Setup Decoder %d\n",channel);
// Automatic PAL/NTSC-switch according to MPEG-Source
h = card->stream.vsize;
if (h < 480)
h *= 2; // catch quarter sized images
printk(KERN_INFO LOGNAME ": Video mode: %s\n",
((h == 480) ? "NTSC" : "PAL"));
card->videomode = ((h == 480) ? NTSC : PAL);
SetVideoSystem(card);
// Open the Video Decoder with the parameters retreived from the stream
if (
(err =
DecoderOpen(card, card->stream.hsize,
card->stream.vsize,
card->stream.sh.aspectratio,
!card->stream.MPEG2, 0,
(card->videomode == PAL)))) { // TODO: include vbvbuffersize
printk(KERN_ERR LOGNAME
": Video Decoder Open failed: %s\n",
((err == 1) ?
"Picture size too big (>1440 pixel wide)" :
"On-card memory insufficient for frame stores"));
CloseCard(card);
return -ENODEV; // picture too big or insufficient memory
}
card->startingV = 1; // tell the card to start playing as soon as ES-buffers are sufficiently full
card->startingA = 1; // tell the card to start playing as soon as ES-buffers are sufficiently full
}
return 0;
}
int SetSCRstart(struct cvdv_cards *card, u32 SCR_base)
{
u32 SCR_compare;
u32 SCR_compareA;
u32 SCR_compareV;
if (card->startingV) {
printk(KERN_ERR LOGNAME ": SCR in DVD Pack: 0x%08X\n",
SCR_base);
card->startingV = 0;
card->startingA = 0;
DecoderMaskByte(card, 0x007, 0xD2, 0xD2); // Set 0x010, halt SCR counter
SCR_compare = SCR_base + 000;
if (SCR_base < 900)
SCR_base = 0;
else
SCR_base -= 900;
//DecoderWriteDWord(card,0x009,SCR_base); // Set SCR counter
DecoderWriteByte(card, 0x009, SCR_base & 0xFF); // Set SCR counter
DecoderWriteByte(card, 0x00A, (SCR_base >> 8) & 0xFF);
DecoderWriteByte(card, 0x00B, (SCR_base >> 16) & 0xFF);
DecoderWriteByte(card, 0x00C, (SCR_base >> 24) & 0xFF);
DecoderMaskByte(card, 0x011, 0x03, 0x02); // compare, not capture
printk(KERN_ERR LOGNAME ": SCR compare value: 0x%08X\n",
SCR_compare);
//DecoderWriteDWord(card,0x00D,SCR_compare); // Set Compare register
DecoderWriteByte(card, 0x00D, SCR_compare & 0xFF); // Set Compare register
DecoderWriteByte(card, 0x00E, (SCR_compare >> 8) & 0xFF);
DecoderWriteByte(card, 0x00F, (SCR_compare >> 16) & 0xFF);
DecoderWriteByte(card, 0x010, (SCR_compare >> 24) & 0xFF);
//DecoderWriteDWord(card,0x014,SCR_compare); // Set audio compare reg.
DecoderWriteByte(card, 0x014, SCR_compare & 0xFF); // Set audio compare reg.
DecoderWriteByte(card, 0x015, (SCR_compare >> 8) & 0xFF);
DecoderWriteByte(card, 0x016, (SCR_compare >> 16) & 0xFF);
DecoderWriteByte(card, 0x017, (SCR_compare >> 24) & 0xFF);
DecoderSetByte(card, 0x013, 0x03); // Video and Audio start on cmp.
//DecoderSetVideoPanic(card,0,DecoderGetVideoESSize(card)/4); // video panic at 25 percent
VideoSetBackground(card, 1, 0, 0, 0); // black
SCR_base = DecoderReadByte(card, 0x009);
SCR_base =
SCR_base | ((u32) DecoderReadByte(card, 0x00A) << 8);
SCR_base =
SCR_base | ((u32) DecoderReadByte(card, 0x00B) << 16);
SCR_base =
SCR_base | ((u32) DecoderReadByte(card, 0x00C) << 24);
SCR_compareA = DecoderReadByte(card, 0x014);
SCR_compareA =
SCR_compareA | ((u32) DecoderReadByte(card, 0x015) <<
8);
SCR_compareA =
SCR_compareA | ((u32) DecoderReadByte(card, 0x016) <<
16);
SCR_compareA =
SCR_compareA | ((u32) DecoderReadByte(card, 0x017) <<
24);
SCR_compareV = DecoderReadByte(card, 0x00D);
SCR_compareV =
SCR_compareV | ((u32) DecoderReadByte(card, 0x00E) <<
8);
SCR_compareV =
SCR_compareV | ((u32) DecoderReadByte(card, 0x00F) <<
16);
SCR_compareV =
SCR_compareV | ((u32) DecoderReadByte(card, 0x010) <<
24);
if (DecoderReadByte(card, 0x013) & 0x03)
printk(KERN_DEBUG LOGNAME
": SCR 0x%08X, videocmp=0x%08X, audiocmp=0x%08X %02X\n",
SCR_base, SCR_compareV, SCR_compareA,
DecoderReadByte(card, 0x013));
DecoderMaskByte(card, 0x007, 0xD2, 0xC2); // Del 0x010, SCR counter run
}
return 0;
}
int DecoderWriteBlock(struct cvdv_cards *card, u8 * data, int size,
int initial, int setSCR)
{
//int a,v,as,vs,ap,vp;
int res;
u32 SCR_base;
int co = 0;
// u32 SCR_compare;
res = 0;
//Prepare(card);
if (size > 0) {
if (!card->use_ring)
MargiSetBuffers(card, 16*65536);
if (card->startingDVDV || card->startingDVDA)
setSCR = 1;
if (initial) {
DecoderStreamReset(card);
DecoderSetupReset(card);
//TODO stop and start channel interface
setSCR = 1;
}
if (setSCR) {
SCR_base = ParseSCR(data);
SetSCR(card, SCR_base);
}
while (((res = MargiPush(card, size, data)) < size)
&& co < 100) {
data+=res;
size-=res;
co++;
// printk(KERN_DEBUG LOGNAME
// ": DecoderWriteBlock - buffers only filled with %d instead of %d bytes\n",
// res, size);
if (card->DMAABusy)
interruptible_sleep_on(&card->wqA);
}
if (card->startingDVDV) {
card->startingDVDV = 0;
DecoderStartDecode(card);
}
if (card->startingDVDA) {
card->startingDVDA = 0;
AudioSetPlayMode(card, AUDIO_PLAY);
}
}
return 0;
}
//////////////////////////////
// //
// Char Device Procedures //
// //
//////////////////////////////
static ssize_t PSwrite(struct file *file, const char *data, size_t count,
loff_t * offset)
{
struct cvdv_cards *card =
minorlist[MINOR(file->f_dentry->d_inode->i_rdev) % MAXDEV]; // minor number modulo 16
int channel = MINOR(file->f_dentry->d_inode->i_rdev) / MAXDEV; // minor number div. 16
struct StreamSetup *setup = &card->setup;
// int i;
// int laststart=-1;
// int B3=0, B5=0, C0=0, E0=0, BD=0, BF=0;
int res;
if (card != NULL) {
if (count > 0) { // Do we have data?
if ((res = Prepare(card)))
return res;
if ((setup->streamtype != stream_ES)
&& (setup->streamtype != stream_PES))
channel = 0;
// only ES and PES come in separate streams
switch (channel) {
case 0:
if (!card->use_ring)
MargiSetBuffers(card, NBBUF*
CHANNELBUFFERSIZE);
if (!(count = MargiPush(card, count, data))){
if (card->DMAABusy)
interruptible_sleep_on(
&card->wqA);
}
break;
case 1:
// todo
break;
}
}
return count;
} else {
printk(KERN_ERR LOGNAME
": Video Decoder Prepare failed: device with this minor number not found\n");
return -ENODEV; // device with this minor number not found
}
}
static unsigned int PSpoll(struct file *file, poll_table * table)
{
struct cvdv_cards *card =
minorlist[MINOR(file->f_dentry->d_inode->i_rdev) % MAXDEV]; // minor number modulo 16
// int channel=MINOR(file->f_dentry->d_inode->i_rdev) / MAXDEV; // minor number div. 16
if (card != NULL) {
return POLLOUT | POLLWRNORM; // always writeable, HAS TO BE CHANGED!!!!
} else
return POLLERR; // device with this minor number not found
}
static int PSioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct cvdv_cards *card = minorlist[MINOR(inode->i_rdev) % MAXDEV]; // minor number modulo 16
// int channel=MINOR(inode->i_rdev) / MAXDEV; // minor number div. 16
struct drawcmd *dc;
struct decodercmd *command;
u16 attr;
if (card != NULL) {
if (_IOC_TYPE(cmd) == CVDV_IOCTL_MAGIC)
switch (_IOC_NR(cmd)) {
case IOCTL_DRAW: // Drawing commands
dc = (struct drawcmd *) arg;
switch (dc->cmd) {
case OSD_Close:
printk(KERN_DEBUG LOGNAME
": OSD Close\n");
return OSDClose(card);
case OSD_Open: // Open(x0,y0,x1,y1,BitPerPixel(2/4/8),mix(0..15))
return OSDOpen(card, dc->x0,
dc->y0, dc->x1,
dc->y1,
dc->color & 0x0F,
(dc->color >> 4) &
0x0F);
case OSD_Show:
return OSDShow(card);
case OSD_Hide:
return OSDHide(card);
case OSD_Clear:
return OSDClear(card);
case OSD_Fill: // Fill(color)
return OSDFill(card, dc->color);
case OSD_SetColor: // SetColor(color,R(x0),G(y0),B(x1),opacity(y1))
//printk(KERN_DEBUG LOGNAME ": OSD SetColor(%d,%d,%d,%d,%d)\n",
//dc->color,dc->x0,dc->y0,dc->x1,dc->y1);
return (OSDSetColor
(card, dc->color, dc->x0,
dc->y0, dc->x1, 0,
(dc->y1 != 255),
(dc->y1 == 0)) >= 0);
case OSD_SetPalette: // SetPalette(firstcolor{color},lastcolor{x0},data)
return OSDSetPalette(card,
dc->color,
dc->x0, (u8 *)
dc->data);
case OSD_SetTrans: // SetTrans(transparency{color})
return OSDSetTrans(card,
(dc->color >> 4)
& 0x0F);
case OSD_SetPixel: // SetPixel(x0,y0,color)
return OSDSetPixel(card, dc->x0,
dc->y0,
dc->color);
case OSD_GetPixel: // GetPixel(x0,y0);
return OSDGetPixel(card, dc->x0,
dc->y0);
case OSD_SetRow: // SetRow(x0,y0,x1,(u8*)data)
return OSDSetRow(card, dc->x0,
dc->y0, dc->x1,
(u8 *) dc->data);
case OSD_SetBlock: // SetBlock(x0,y0,x1,y1,(u8*)data)
return OSDSetBlock(card, dc->x0,
dc->y0, dc->x1,
dc->y1,
dc->color,
(u8 *)
dc->data);
case OSD_FillRow: // FillRow(x0,y0,x1,color)
return OSDFillRow(card, dc->x0,
dc->y0, dc->x1,
dc->color);
case OSD_FillBlock: // FillRow(x0,y0,x1,y1,color)
return OSDFillBlock(card, dc->x0,
dc->y0, dc->x1,
dc->y1,
dc->color);
case OSD_Line: // Line(x0,y0,x1,y1,color);
return OSDLine(card, dc->x0,
dc->y0, dc->x1,
dc->y1, dc->color);
case OSD_Query: // Query(x0,y0,x1,y1,aspect(color:11)
return OSDQuery(card, &dc->x0,
&dc->y0, &dc->x1,
&dc->y1,
&dc->color);
case OSD_Test:
return OSDTest(card);
default:
return -EINVAL;
}
case IOCTL_DECODER:
command = (struct decodercmd *) arg;
switch (command->cmd) {
/*
case Decoder_CSS:
return DecoderCSS(card,
command->param1,
command->data1);
*/
case Decoder_Set_Videosystem:
printk(KERN_DEBUG LOGNAME
": -- Decoder_Set_Videosystem\n");
card->videomode =
(videosystem) command->param1;
SetVideoSystem(card);
return 0;
case Decoder_Set_Streamtype:
printk(KERN_DEBUG LOGNAME
": -- Decoder_Set_Streamtype\n");
card->setup.streamtype =
(stream_type) command->param1;
return 0;
case Decoder_Set_Audiotype:
printk(KERN_DEBUG LOGNAME
": -- Decoder_Set_Audiotype\n");
card->setup.audioselect =
(audio_type) command->param1;
DecoderPrepareAudio(card);
return 0;
case Decoder_Set_VideoStreamID:
printk(KERN_DEBUG LOGNAME
": -- Decoder_Set_VideoStreamID\n");
card->setup.videoID =
command->param1;
DecoderPrepareVideo(card);
return 0;
case Decoder_Set_AudioStreamID:
printk(KERN_DEBUG LOGNAME
": -- Decoder_Set_AudioStreamID 0x%02X 0x%02X\n",command->param1,command->param2);
card->setup.audioID =
command->param1;
card->setup.audioIDext =
command->param2;
attr = card->lastaattr;
DecoderSelectAudioID(card);
card->lastaattr = attr;
return 0;
case Decoder_Still_Put:
return DecoderShowStill(card,
command->
param1,
command->
param2,
command->
data1,
command->
data2);
case Decoder_Still_Get:
return DecoderGetStill(card,
&command->
param1,
&command->
param2,
command->
data1,
command->
data2);
case Decoder_Pause: // pause{param1} 0=run 1=pause 2=toggle
if (command->param1 == 2) {
if (card->paused)
DecoderUnPause
(card);
else
DecoderPause(card);
} else {
if (!command->param1)
DecoderUnPause
(card);
else
DecoderPause(card);
}
return 0;
case Decoder_Highlight: // active{param1}, color information(SL_COLI or AC_COLI){data1[4]}, button position(BTN_POSI){data2[6]}
return DecoderHighlight(card,
command->
param1,
command->
data1,
command->
data2);
case Decoder_SPU: // stream{param1}, active{param2}
return DecoderSPUStream(card,
command->
param1,
command->
param2);
case Decoder_SPU_Palette: // length{param1}, palette{data1}
return DecoderSPUPalette(card,
command->
param1,
command->
data1);
case Decoder_GetNavi: // data1 will be filled with PCI or DSI pack, and 1024 will be returned
return DecoderGetNavi(card,
command->
data1);
case Decoder_SetKaraoke: // Vocal1{param1}, Vocal2{param2}, Melody{param3}
return DecoderKaraoke(card,
command->
param1,
command->
param2,
command->
param3);
case Decoder_Set_Videoattribute:
printk(KERN_DEBUG LOGNAME
": -- Decoder_Set_Videoattribute\n");
if (!card->ChannelBuffersAllocated) {
DecoderStreamReset(card);
MargiFlush(card);
card->setup.streamtype =
stream_DVD;
card->setup.videoID = 0;
DecoderPrepareVideo(card);
//VideoSetBackground(card,1,0,0,0); // black
//DecoderPreparePS(card, -1, 1,2,2,3,1);
DecoderPreparePS(card, 0,
0, 2, 2,
3, 1);
}
SetVideoAttr(card,
command->param1);
card->startingDVDV = 1; // tell the card to start playing as soon as ES-buffers are sufficiently full
return 0;
case Decoder_Set_Audioattribute:
printk(KERN_DEBUG LOGNAME
": -- Decoder_Set_Audioattribute\n");
SetAudioAttr(card,
command->param1);
card->startingDVDA =
((card->setup.audioselect !=
audio_none)
&& (card->setup.audioselect != audio_disable)); // tell the card to start playing as soon as ES-buffers are sufficiently full
return 0;
case Decoder_WriteBlock: // DVD-Sector{data1}, sectorsize{param1{2048}}, initialsector{param2{bool}}, set_SCR{param3}
return DecoderWriteBlock(card,
command->
data1,
command->
param1,
command->
param2,
command->
param3);
default:
return -EINVAL;
}
default:
return -EINVAL;
} else
return -EINVAL;
} else {
printk(KERN_ERR LOGNAME
": Video Decoder Prepare failed: device with this minor number not found\n");
return -ENODEV; // device with this minor number not found
}
}
static int PSmmap(struct file *file, struct vm_area_struct *vm)
{
return -ENODEV;
}
static int PSopen(struct inode *inode, struct file *file)
{
struct cvdv_cards *card = minorlist[MINOR(inode->i_rdev) % MAXDEV]; // minor number modulo 16
int channel = MINOR(inode->i_rdev) / MAXDEV; // minor number div. 16
int i, closed;
if (card != NULL) {
printk(KERN_DEBUG LOGNAME ": -- PSopen %d\n",channel);
CloseCard(card);
DecoderStreamReset(card);
DecoderSetupReset(card);
if (card->open[channel])
printk(KERN_DEBUG LOGNAME
": PSopen - already open: channel %d\n",
channel);
closed = 1;
for (i = 0; i < MINORNUM; i++)
if (card->open[i])
closed = 0;
if (closed) { // first open() for this card?
MargiFreeBuffers(card);
VideoSetBackground(card, 1, 0, 0, 0); // black
}
card->open[channel]++;
//MOD_INC_USE_COUNT;
return 0;
} else {
printk(KERN_ERR LOGNAME
": Video Decoder Prepare failed: device with this minor number not found\n");
return -ENODEV; // device with this minor number not found
}
}
static int PSrelease(struct inode *inode, struct file *file)
{
struct cvdv_cards *card = minorlist[MINOR(inode->i_rdev) % MAXDEV]; // minor number modulo 16
int channel = MINOR(inode->i_rdev) / MAXDEV; // minor number div. 16
int i, closed;
if (card != NULL) {
printk(KERN_DEBUG LOGNAME ": -- PSrelease\n");
if (!card->open[channel])
printk(KERN_DEBUG LOGNAME
": PSrelease - not open: channel %d\n",
channel);
card->open[channel]--;
//MOD_DEC_USE_COUNT;
if (!card->open[channel]) {
closed = 1;
for (i = 0; i < MINORNUM; i++)
if (card->open[i])
closed = 0;
if (closed) { // last close() for this card?
printk(KERN_DEBUG LOGNAME
": PSrelease - last close\n");
// flush remaining data
MargiFlush(card);
card->channelApos = 0;
card->channelBpos = 0;
if ((card->DMAABusy || card->DMABBusy) && (card->intdecodestatus)) { // ongoing DMA?
printk(KERN_DEBUG LOGNAME
": Delayed closing: A=%d B=%d\n",
card->DMAABusy,
card->DMABBusy);
card->closing = 1; // then delay closing until DMA finished,
} else { // otherwise
CloseCard(card); // close immediately
}
}
}
return 0;
} else {
printk(KERN_ERR LOGNAME
": Video Decoder Prepare failed: device with this minor number not found\n");
return -ENODEV; // device with this minor number not found
}
}
//////////////////////////
// //
// Char Device Hookup //
// //
//////////////////////////
// Hookups for a write-only device, that accepts MPEG-2 Program Stream
struct file_operations cvdv_fileops = {
write: PSwrite,
poll: PSpoll,
ioctl: PSioctl,
mmap: PSmmap,
open: PSopen,
release: PSrelease,
};
LinuxTV legacy CVS <linuxtv.org/cvs>