/*
cvdv.c
Copyright (C) Christian Wolff
Marcus Metzler 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 //
// //
/////////////////////////////////////////////////////////////////////
#define __NO_VERSION__
//#include <linux/module.h>
#include "cvdv.h"
#include "ost/osd.h"
#include "i2c.h"
//////////////////////
// global variables //
//////////////////////
// Our major device number
unsigned int major_device_number;
// my little random function for memory test
uint16_t rnd_seed;
uint16_t rnd(uint16_t range)
{ // returns random 0..(range-1) range<=872
uint32_t b = 75 * (rnd_seed + 1) - 1;
rnd_seed = (uint16_t) (b & 0xFFFF);
return ((b * range) / 0xFFFF) - ((b / 0xFFFF) * range);
}
void rnd_omize(void)
{
rnd_seed = (uint16_t) jiffies;
}
static char *cimlogo[] = {
".............................................",
".............................................",
"......................###....................",
".....................#####...................",
".....................######..................",
"..............#......#####...................",
"...........#####....######...................",
".........########...######...................",
"........########....######...................",
".......#########...######....................",
"......########.....######...####.............",
".....#######.......#####...#####.............",
".....######.......######...######............",
"....#######.......######....######...........",
"....######........######....######...........",
"....#####........######......#####...........",
"...######........######......#####...........",
"...#####.........######......######..........",
"...#####.........#####.......######..........",
"...#####........######........#####..........",
"...#####........######.......######..........",
"...#####........#####.........#####..........",
"...#####.......######........######..........",
"...#####.......######........#####...........",
"...######.......####.........#####...........",
"....#####........##.........######...........",
"....######..................######...........",
"....######.................######............",
".....#######..............######.....#####...",
".....########............#######....#######..",
"......#########........########.....#######..",
".......#######################......########.",
"........#####################.......#######..",
"..........#################.........#######..",
"............#############............#####...",
"...............#.#####.................##....",
".............................................",
"............................................."
};
/////////////////////////////////////////////
// //
// Controlling the L64021 MPEG-2 Decoder //
// //
/////////////////////////////////////////////
int OSDTest(struct cvdv_cards *card)
{
int i, j, col, x0, y0, x1, y1,aspx;
uint8_t b;
if (!card->OSD.open)
return -2;
OSDQuery(card, &x0, &y0, &x1, &y1, &aspx);
OSDShow(card);
OSDSetColor(card, 0, 0, 0, 0, 0, 0, 0);
OSDSetColor(card, 1, 128, 255, 255, 0, 0, 0);
for ( i = 0; i < cimlogo_width; i++){
for ( j = 0; j < cimlogo_height; j++){
b = cimlogo[j][i];
col = (b == '#') ? 1: 0;
OSDSetPixel(card, x0+i, y0+j, col);
}
}
return 0;
}
void SetVideoSystem(struct cvdv_cards *card)
{
uint8_t reg;
// set the hsync and vsync generators in the L64017 according to the video standard
reg = read_indexed_register(card, IIO_VIDEO_CONTROL1);
reg &= ~0x03;
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);
reg |= 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);
reg |= 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);
reg |= 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);
reg |= 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);
reg |= 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);
reg |= 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);
reg |= VMS_PAL;
break;
case PAL60:
break;
}
write_indexed_register(card, IIO_VIDEO_CONTROL1, reg);
// set the pixel generators according to the video standard
L64021Setup(card);
}
int SetVideoAttr(struct cvdv_cards *card, uint16_t vattr)
{
uint8_t video_compression_mode;
uint8_t tv_system;
uint8_t aspect_ratio;
uint8_t display_mode;
uint8_t line_21_switch_1;
uint8_t line_21_switch_2;
uint8_t source_picture_resolution;
uint8_t source_picture_letterboxed;
uint8_t reserved;
uint8_t film_camera_mode;
uint16_t 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)) {
MDEBUG(0,
": Video Decoder Open failed: On-card memory insufficient for frame stores\n");
}
card->lastvattr = vattr;
} else {
MDEBUG(0,
": Video attribute not set, equal to previous one.\n");
}
return 0;
}
int SetAudioAttr(struct cvdv_cards *card, uint16_t aattr)
{
uint8_t audio_coding_mode;
uint8_t multichannel_extension;
uint8_t audio_type;
uint8_t audio_application_mode;
uint8_t quantization_drc;
uint8_t fs;
uint8_t reserved;
uint8_t 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 {
MDEBUG(0,
": 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!
MDEBUG(0,
": 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
MDEBUG(0,
": 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)) {
// 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->stream.hsize > 480)))) { // TODO: include vbvbuffersize
MDEBUG(0,
": 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
}
MDEBUG(1, ": Ready to go\n");
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, uint32_t SCR_base)
{
uint32_t SCR_compare;
uint32_t SCR_compareA;
uint32_t SCR_compareV;
if (card->startingV) {
MDEBUG(0, ": 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
MDEBUG(0, ": 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 | ((uint32_t) DecoderReadByte(card, 0x00A) << 8);
SCR_base =
SCR_base | ((uint32_t) DecoderReadByte(card, 0x00B) << 16);
SCR_base =
SCR_base | ((uint32_t) DecoderReadByte(card, 0x00C) << 24);
SCR_compareA = DecoderReadByte(card, 0x014);
SCR_compareA =
SCR_compareA | ((uint32_t) DecoderReadByte(card, 0x015) <<
8);
SCR_compareA =
SCR_compareA | ((uint32_t) DecoderReadByte(card, 0x016) <<
16);
SCR_compareA =
SCR_compareA | ((uint32_t) DecoderReadByte(card, 0x017) <<
24);
SCR_compareV = DecoderReadByte(card, 0x00D);
SCR_compareV =
SCR_compareV | ((uint32_t) DecoderReadByte(card, 0x00E) <<
8);
SCR_compareV =
SCR_compareV | ((uint32_t) DecoderReadByte(card, 0x00F) <<
16);
SCR_compareV =
SCR_compareV | ((uint32_t) DecoderReadByte(card, 0x010) <<
24);
if (DecoderReadByte(card, 0x013) & 0x03)
MDEBUG(1,": 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, uint8_t * data, int size,
int initial, int setSCR)
{
//int a,v,as,vs,ap,vp;
int res;
uint32_t SCR_base;
int co = 0;
// uint32_t SCR_compare;
res = 0;
Prepare(card);
if (size > 0) {
if (!card->use_ringA)
MargiSetBuffers(card, NBBUF*CHANNELBUFFERSIZE,0);
if (card->startingDVDV || card->startingDVDA)
setSCR = 1;
if (initial) {
DecoderStreamReset(card);
//TODO stop and start channel interface
setSCR = 1;
}
if (setSCR) {
SCR_base = ParseSCR(data);
SetSCR(card, SCR_base);
}
card->DMAABusy = 0;
while (((res = MargiPushA(card, size, data)) < size)
&& co < 1000) {
data+=res;
size-=res;
co++;
MDEBUG(2,
": 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;
card->startingV = 1;
DecoderStartDecode(card);
}
if (card->startingDVDA) {
card->startingDVDA = 0;
card->startingA = 1;
AudioSetPlayMode(card, MAUDIO_PLAY);
}
}
return 0;
}
//////////////////////////////
// //
// Char Device Procedures //
// //
//////////////////////////////
static long margi_write(struct cvdv_cards *card, const char *data,
unsigned long count, int nonblock)
{
int res;
long int out=0;
int free;
free = ring_write_rest(&(card->rbufA));
if (card != NULL) {
card->nonblock = nonblock;
if (count > 0) { // Do we have data?
if ((res = Prepare(card)))
return res;
if (!card->use_ringA)
MargiSetBuffers(card, NBBUF*CHANNELBUFFERSIZE,
0);
if (!nonblock &&
!wait_event_interruptible(
card->wqA,
ring_write_rest(&(card->rbufA)) >count )){
out = MargiPushA(card, count,
data);
} else {
out = MargiPushA(card, count, data);
}
}
return out;
} else {
MDEBUG(0,
": Video Decoder Prepare failed: device with this minor number not found\n");
return -ENODEV; // device with this minor number not found
}
}
static long margi_write_audio(struct cvdv_cards *card, const char *data,
unsigned long count, int nonblock)
{
struct StreamSetup *setup = &card->setup;
int res;
long int out=0;
int free;
free = ring_write_rest(&(card->rbufB));
if (card != NULL) {
card->nonblock = nonblock;
if (count > 0) { // Do we have data?
if ((res = Prepare(card)))
return res;
if ((setup->streamtype == stream_ES)
|| (setup->streamtype == stream_PES)){
if (!card->use_ringB)
MargiSetBuffers(card, NBBUF*
CHANNELBUFFERSIZE,1);
if (!nonblock &&
!wait_event_interruptible(
card->wqB,
ring_write_rest(&(card->rbufB))
> count)){
out = MargiPushB(card, count,
data);
} else {
out = MargiPushB(card, count, data);
}
}
}
return out;
} else {
MDEBUG(0,
": Video Decoder Prepare failed: device with this minor number not found\n");
return -ENODEV; // device with this minor number not found
}
}
void pes_write(uint8_t *buf, int count, void *priv)
{
struct cvdv_cards *card = (struct cvdv_cards *) priv;
margi_write(card, buf, count, 0);
}
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
return margi_write(card, data, count, file->f_flags&O_NONBLOCK);
}
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
if (card != NULL) {
poll_wait(file, &card->wqA , table);
if ( !card->rbufA.buffy || ring_write_rest(&(card->rbufA)) )
return (POLLOUT | POLLWRNORM);
else {
return 0;
}
} else
return POLLERR;
}
static unsigned int poll_audio(struct file *file, poll_table * table)
{
struct cvdv_cards *card =
minorlist[MINOR(file->f_dentry->d_inode->i_rdev) % MAXDEV]; // minor number modulo 16
if (card != NULL) {
poll_wait(file, &card->wqB, table);
if ( !card->rbufB.buffy || ring_write_rest(&(card->rbufB)) )
return (POLLOUT | POLLWRNORM);
else {
return 0;
}
} else
return POLLERR;
}
static int
OSD_DrawCommand(struct cvdv_cards *card,osd_cmd_t *dc)
{
switch (dc->cmd) {
case OSD_Close:
MDEBUG(1,": 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))
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, (uint8_t *)
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,(uint8_t*)data)
return OSDSetRow(card, dc->x0,
dc->y0, dc->x1,
(uint8_t *) dc->data);
case OSD_SetBlock: // SetBlock(x0,y0,x1,y1,(uint8_t*)data)
return OSDSetBlock(card, dc->x0,
dc->y0, dc->x1,
dc->y1,
dc->color,
(uint8_t *)
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;
}
}
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
osd_cmd_t *dc;
struct decodercmd *command;
uint16_t attr;
if (card != NULL) {
if (_IOC_TYPE(cmd) == CVDV_IOCTL_MAGIC)
switch (_IOC_NR(cmd)) {
case IOCTL_DRAW: // Drawing commands
dc = (osd_cmd_t *) arg;
return OSD_DrawCommand(card,dc);
break;
case IOCTL_DECODER:
command = (struct decodercmd *) arg;
switch (command->cmd) {
case Decoder_CSS:
/*
return DecoderCSS(card,
command->param1,
command->data1);
*/
break;
case Decoder_Set_Videosystem:
MDEBUG(1,": -- Decoder_Set_Videosystem\n");
card->videomode =
(videosystem) command->param1;
SetVideoSystem(card);
return 0;
break;
case Decoder_Set_Streamtype:
MDEBUG(1,": -- Decoder_Set_Streamtype\n");
card->setup.streamtype =
(stream_type) command->param1;
return 0;
break;
case Decoder_Set_Audiotype:
MDEBUG(1,": -- Decoder_Set_Audiotype\n");
card->setup.audioselect =
(audio_type) command->param1;
DecoderPrepareAudio(card);
return 0;
break;
case Decoder_Set_VideoStreamID:
MDEBUG(1,": -- Decoder_Set_VideoStreamID\n");
card->setup.videoID =
command->param1;
DecoderPrepareVideo(card);
return 0;
break;
case Decoder_Set_AudioStreamID:
MDEBUG(1,": -- 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;
break;
case Decoder_Still_Put:
return DecoderShowStill(card,
command->
param1,
command->
param2,
command->
data1,
command->
data2);
break;
case Decoder_Still_Get:
return DecoderGetStill(card,
&command->
param1,
&command->
param2,
command->
data1,
command->
data2);
break;
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;
/* Too buggy
case Decoder_FFWD: // pause{param1} =normal 1=ffwd 2=toggle
if (command->param1 == 2) {
if (card->videoffwd)
card->videoffwd = 0;
else
card->videoffwd = 3;
} else {
if (!command->param1)
card->videoffwd = 0;
else
card->videoffwd = 3;
}
return 0;
case Decoder_Slow: // pause{param1} =normal 1=slow 2=toggle
if (command->param1 == 2) {
if (card->videoslow)
card->videoslow = 0;
else
card->videoslow = 4;
} else {
if (!command->param1)
card->videoslow = 0;
else
card->videoslow = 4;
}
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:
MDEBUG(1,": -- Decoder_Set_Videoattribute\n");
if (!card->ChannelBuffersAllocated) {
DecoderStreamReset(card);
MargiFlush(card);
card->setup.streamtype =
stream_DVD;
card->setup.videoID = 0;
DecoderPrepareVideo(card);
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:
MDEBUG(1,": -- 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 {
MDEBUG(0,
": 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 margi_open(struct cvdv_cards *card, int flags)
{
int closed;
if (card != NULL) {
MDEBUG(1, ": -- open \n");
CloseCard(card);
OSDClose(card);
#ifdef NOINT
card->timer.function = Timerfunction;
card->timer.data=(unsigned long) card;
card->timer.expires=jiffies+1;
add_timer(&card->timer);
#endif
if (card->open)
MDEBUG(0,": PSopen - already open\n");
closed = 1;
if (card->open)
closed = 0;
if (closed) { // first open() for this card?
MargiFreeBuffers(card);
VideoSetBackground(card, 1, 0, 0, 0); // black
}
card->open++;
MOD_INC_USE_COUNT;
return 0;
} else {
MDEBUG(0,
": Video Decoder Prepare failed: device with this minor number not found\n");
return -ENODEV; // device with this minor number not found
}
}
static int PSopen(struct inode *inode, struct file *file)
{
struct cvdv_cards *card = minorlist[MINOR(inode->i_rdev) % MAXDEV];
card->audiostate.AVSyncState=true;
return margi_open(card, file->f_flags);
}
static int all_margi_close(struct cvdv_cards *card)
{
if (card != NULL) {
MDEBUG(1, ": -- PSrelease\n");
if (card->open <= 0)
MDEBUG(1,": PSrelease - not open\n");
card->open--;
MOD_DEC_USE_COUNT;
if (!card->open) {
MDEBUG(1,": PSrelease - last close\n");
CloseCard(card); // close immediately
}
return 0;
} else {
MDEBUG(0,": Video Decoder Prepare failed:\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
return all_margi_close(card);
}
//////////////////////////
// //
// 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,
};
#ifdef DVB
static inline int
num2type(struct cvdv_cards *card, int num)
{
if (!card->dvb_devs)
return -2;
if (num>=card->dvb_devs->num)
return -2;
return card->dvb_devs->tab[num];
}
static int
dvbdev_open(struct dvb_device *dvbdev, int num,
struct inode *inode, struct file *file)
{
struct cvdv_cards *card=(struct cvdv_cards *) dvbdev->priv;
int type=num2type(card, num);
int ret=0;
if (type<0)
return -EINVAL;
if (card->users[num] >= card->dvb_devs->max_users[num])
return -EBUSY;
if ((file->f_flags&O_ACCMODE)!=O_RDONLY)
if (card->writers[num] >= card->dvb_devs->max_writers[num])
return -EBUSY;
switch (type) {
case DVB_DEVICE_VIDEO_0:
card->video_blank=true;
card->audiostate.AVSyncState=true;
card->videostate.streamSource=VIDEO_SOURCE_DEMUX;
margi_open(card, file->f_flags);
break;
case DVB_DEVICE_AUDIO_0:
card->audiostate.AVSyncState=true;
card->audiostate.streamSource=AUDIO_SOURCE_DEMUX;
break;
case DVB_DEVICE_DEMUX_0:
if ((file->f_flags&O_ACCMODE)!=O_RDWR)
return -EINVAL;
ret=DmxDevFilterAlloc(&card->dmxdev, file);
break;
case DVB_DEVICE_DVR_0:
card->audiostate.AVSyncState=true;
card->setup.streamtype = stream_PES;
margi_open(card, file->f_flags);
ret=DmxDevDVROpen(&card->dmxdev, file);
break;
case DVB_DEVICE_OSD_0:
break;
default:
return -EINVAL;
}
if (ret<0)
return ret;
if ((file->f_flags&O_ACCMODE)!=O_RDONLY)
card->writers[num]++;
card->users[num]++;
return ret;
}
static int
dvbdev_close(struct dvb_device *dvbdev, int num,
struct inode *inode, struct file *file)
{
struct cvdv_cards *card=(struct cvdv_cards *) dvbdev->priv;
int type=num2type(card, num);
int ret=0;
if (type<0)
return -EINVAL;
switch (type) {
case DVB_DEVICE_VIDEO_0:
case DVB_DEVICE_AUDIO_0:
if (card->open)
all_margi_close(card);
break;
case DVB_DEVICE_DEMUX_0:
ret=DmxDevFilterFree(&card->dmxdev, file);
break;
case DVB_DEVICE_DVR_0:
ret=DmxDevDVRClose(&card->dmxdev, file);
if (card->open)
all_margi_close(card);
break;
case DVB_DEVICE_OSD_0:
break;
default:
return -EINVAL;
}
if (ret<0)
return ret;
if ((file->f_flags&O_ACCMODE)!=O_RDONLY)
card->writers[num]--;
card->users[num]--;
return ret;
}
static ssize_t
dvbdev_write(struct dvb_device *dvbdev, int num,
struct file *file,
const char *buf, size_t count, loff_t *ppos)
{
struct cvdv_cards *card=(struct cvdv_cards *) dvbdev->priv;
int type=num2type(card, num);
switch (type) {
case DVB_DEVICE_VIDEO_0:
if (card->videostate.streamSource!=VIDEO_SOURCE_MEMORY)
return -EPERM;
return margi_write(card, buf, count,
file->f_flags&O_NONBLOCK);
case DVB_DEVICE_AUDIO_0:
if (card->audiostate.streamSource!=AUDIO_SOURCE_MEMORY)
return -EPERM;
if ( card->setup.streamtype != stream_PES )
return -EPERM;
return margi_write_audio(card, buf, count,
file->f_flags&O_NONBLOCK);
case DVB_DEVICE_DVR_0:
return DmxDevDVRWrite(&card->dmxdev, file, buf, count, ppos);
default:
return -EOPNOTSUPP;
}
return 0;
}
static ssize_t
dvbdev_read(struct dvb_device *dvbdev, int num,
struct file *file, char *buf, size_t count, loff_t *ppos)
{
struct cvdv_cards *card=(struct cvdv_cards *) dvbdev->priv;
int type=num2type(card, num);
switch (type) {
case DVB_DEVICE_VIDEO_0:
break;
case DVB_DEVICE_AUDIO_0:
break;
case DVB_DEVICE_DEMUX_0:
return DmxDevRead(&card->dmxdev, file, buf, count, ppos);
case DVB_DEVICE_DVR_0:
return DmxDevDVRRead(&card->dmxdev, file, buf, count, ppos);
case DVB_DEVICE_CA_0:
break;
default:
return -EOPNOTSUPP;
}
return 0;
}
static int
dvbdev_ioctl(struct dvb_device *dvbdev, int num,
struct file *file, unsigned int cmd, unsigned long arg)
{
struct cvdv_cards *card=(struct cvdv_cards *) dvbdev->priv;
void *parg=(void *)arg;
int type=num2type(card, num);
uint16_t attr;
switch (type) {
case DVB_DEVICE_VIDEO_0:
if (((file->f_flags&O_ACCMODE)==O_RDONLY) &&
(cmd!=VIDEO_GET_STATUS))
return -EPERM;
switch (cmd) {
case VIDEO_STOP:
DecoderPause(card);
card->videostate.playState = VIDEO_STOPPED;
if (card->videostate.videoBlank)
VideoSetBackground(card, 1, 0, 0, 0);
return 0;
case VIDEO_PLAY:
if (card->videostate.streamSource==
VIDEO_SOURCE_MEMORY) {
if (card->videostate.playState==VIDEO_FREEZED){
DecoderUnPause(card);
} else {
DecoderUnPause(card);
}
}
break;
case VIDEO_FREEZE:
DecoderPause(card);
break;
case VIDEO_CONTINUE:
if (card->videostate.playState==VIDEO_FREEZED) {
DecoderUnPause(card);
}
break;
case VIDEO_SELECT_SOURCE:
card->videostate.streamSource=(videoStreamSource_t) arg;
break;
case VIDEO_SET_BLANK:
card->videostate.videoBlank=(boolean) arg;
break;
case VIDEO_GET_STATUS:
if(copy_to_user(parg, &card->videostate,
sizeof(struct videoStatus)))
return -EFAULT;
break;
case VIDEO_GET_EVENT:
return -EOPNOTSUPP;
case VIDEO_SET_DISPLAY_FORMAT:
{
videoDisplayFormat_t format=(videoDisplayFormat_t) arg;
uint16_t val=0;
switch(format) {
case VIDEO_PAN_SCAN:
val=VID_PAN_SCAN_PREF;
break;
case VIDEO_LETTER_BOX:
val=VID_VC_AND_PS_PREF;
break;
case VIDEO_CENTER_CUT_OUT:
val=VID_CENTRE_CUT_PREF;
break;
default:
return -EINVAL;
}
card->videostate.videoFormat=format;
return 0;
}
case VIDEO_STILLPICTURE:
{
struct videoDisplayStillPicture pic;
if(copy_from_user(&pic, parg,
sizeof(struct videoDisplayStillPicture)))
return -EFAULT;
break;
}
case VIDEO_FAST_FORWARD:
if (card->videostate.streamSource !=
VIDEO_SOURCE_MEMORY)
return -EPERM;
card->videoffwd = 3;
break;
case VIDEO_SLOWMOTION:
if (card->videostate.streamSource!=VIDEO_SOURCE_MEMORY)
return -EPERM;
card->videoslow = arg;
break;
case VIDEO_GET_CAPABILITIES:
{
int cap=VIDEO_CAP_MPEG1|
VIDEO_CAP_MPEG2|
VIDEO_CAP_SYS|
VIDEO_CAP_PROG|
VIDEO_CAP_SPU|
VIDEO_CAP_NAVI|
VIDEO_CAP_CSS;
if (copy_to_user(parg, &cap,
sizeof(cap)))
return -EFAULT;
break;
}
case VIDEO_SET_STREAMTYPE:
{
int f = -1;
switch(arg){
case VIDEO_CAP_MPEG1:
case VIDEO_CAP_MPEG2:
f = stream_PES;
break;
case VIDEO_CAP_SYS:
case VIDEO_CAP_PROG:
f = stream_PS;
break;
case VIDEO_CAP_SPU:
case VIDEO_CAP_NAVI:
case VIDEO_CAP_CSS:
f = stream_DVD;
}
card->setup.streamtype = f;
}
break;
case VIDEO_SET_ID:
card->setup.videoID = arg;
DecoderPrepareVideo(card);
break;
case VIDEO_SET_SYSTEM:
card->videomode = (videosystem) arg;
SetVideoSystem(card);
break;
case VIDEO_SET_HIGHLIGHT:
{
uint8_t data1[4];
uint8_t data2[6];
videoHighlight_t vh;
if(copy_from_user(&vh, parg, sizeof(videoHighlight_t)))
return -EFAULT;
data1[0] = vh.contrast1;
data1[1] = vh.contrast2;
data1[2] = vh.color1;
data1[3] = vh.color2;
data2[0] = vh.ypos & 0xFF;
data2[1] = (uint8_t) ((vh.ypos >> 1) & 0xFF);
data2[2] = (uint8_t) ((vh.ypos >> 2) & 0xFF);
data2[3] = vh.xpos & 0xFF;
data2[4] = (uint8_t) ((vh.xpos >> 1) & 0xFF);
data2[5] = (uint8_t) ((vh.xpos >> 2) & 0xFF);
return DecoderHighlight(card, vh.active, data1, data2);
break;
}
case VIDEO_SET_SPU:
{
videoSPU_t spu;
if(copy_from_user(&spu, parg, sizeof(videoSPU_t)))
return -EFAULT;
return DecoderSPUStream(card, spu.streamID, spu.active);
break;
}
case VIDEO_SET_SPU_PALETTE:
{
videoSPUPalette_t spup;
if(copy_from_user(&spup, parg, sizeof(videoSPUPalette_t)))
return -EFAULT;
return DecoderSPUPalette(card, spup.length, spup.palette);
break;
}
case VIDEO_GET_NAVI:
{
videoNaviPack_t navi;
navi.length = DecoderGetNavi(card, (u8 *)&(navi.data));
if(copy_to_user(parg, &navi, sizeof(videoNaviPack_t)))
return -EFAULT;
}
break;
case VIDEO_SET_ATTRIBUTES:
{
if (!card->ChannelBuffersAllocated) {
DecoderStreamReset(card);
MargiFlush(card);
card->setup.streamtype = stream_DVD;
card->setup.videoID = 0;
DecoderPrepareVideo(card);
DecoderPreparePS(card, 0, 0, 2, 2, 3, 1);
}
SetVideoAttr(card, arg);
card->startingDVDV = 1;
}
break;
default:
return -ENOIOCTLCMD;
}
return 0;
case DVB_DEVICE_AUDIO_0:
if (((file->f_flags&O_ACCMODE)==O_RDONLY) &&
(cmd!=AUDIO_GET_STATUS))
return -EPERM;
switch (cmd) {
case AUDIO_STOP:
if (card->audiostate.streamSource!=AUDIO_SOURCE_MEMORY)
break;
AudioStopDecode(card);
card->audiostate.playState=AUDIO_STOPPED;
break;
case AUDIO_PLAY:
if (card->audiostate.streamSource!=AUDIO_SOURCE_MEMORY)
break;
AudioSetPlayMode(card, MAUDIO_PLAY);
card->audiostate.playState=AUDIO_PLAYING;
break;
case AUDIO_PAUSE:
card->audiostate.playState=AUDIO_PAUSED;
AudioSetPlayMode(card, MAUDIO_PAUSE);
break;
case AUDIO_CONTINUE:
if (card->audiostate.playState==AUDIO_PAUSED) {
card->audiostate.playState=AUDIO_PLAYING;
AudioSetPlayMode(card, MAUDIO_PLAY);
}
break;
case AUDIO_SELECT_SOURCE:
card->audiostate.streamSource=
(audioStreamSource_t) arg;
break;
case AUDIO_SET_MUTE:
{
AudioMute(card, arg);
card->audiostate.muteState=(boolean) arg;
break;
}
case AUDIO_SET_AV_SYNC:
card->videosync=(boolean) arg;
card->audiostate.AVSyncState=(boolean) arg;
break;
case AUDIO_SET_BYPASS_MODE:
return -EINVAL;
case AUDIO_CHANNEL_SELECT:
card->audiostate.channelSelect=(audioChannelSelect_t) arg;
switch(card->audiostate.channelSelect) {
case AUDIO_STEREO:
break;
case AUDIO_MONO_LEFT:
break;
case AUDIO_MONO_RIGHT:
break;
default:
return -EINVAL;
}
return 0;
case AUDIO_GET_STATUS:
if(copy_to_user(parg, &card->audiostate,
sizeof(struct audioStatus)))
return -EFAULT;
break;
case AUDIO_GET_CAPABILITIES:
{
int cap=AUDIO_CAP_LPCM|
AUDIO_CAP_MP1|
AUDIO_CAP_MP2|
AUDIO_CAP_AC3;
if (copy_to_user(parg, &cap,
sizeof(cap)))
return -EFAULT;
}
break;
case AUDIO_SET_STREAMTYPE:
{
int f = -1;
switch(arg){
case AUDIO_CAP_DTS:
case AUDIO_CAP_MP3:
case AUDIO_CAP_AAC:
case AUDIO_CAP_SDDS:
case AUDIO_CAP_OGG:
f = audio_none;
break;
case AUDIO_CAP_LPCM:
f = audio_LPCM;
break;
case AUDIO_CAP_MP1:
case AUDIO_CAP_MP2:
f = audio_MPEG;
break;
case AUDIO_CAP_AC3:
f = audio_AC3;
break;
}
card->setup.audioselect = (audio_type) f;
DecoderPrepareAudio(card);
break;
}
case AUDIO_SET_ID:
if (arg < 0 || arg >32) arg = 0;
card->setup.audioID = arg;
arg = 0;
case AUDIO_SET_EXT_ID:
if (arg < 0 || arg >32) arg = 0;
card->setup.audioIDext = arg;
attr = card->lastaattr;
DecoderSelectAudioID(card);
card->lastaattr = attr;
break;
case AUDIO_SET_MIXER:
return -EINVAL;
case AUDIO_SET_ATTRIBUTES:
SetAudioAttr(card,arg);
card->startingDVDA = ((card->setup.audioselect != audio_none)
&& (card->setup.audioselect !=
audio_disable));
break;
case AUDIO_SET_KARAOKE:
{
break;
}
default:
return -ENOIOCTLCMD;
}
break;
case DVB_DEVICE_DEMUX_0:
return DmxDevIoctl(&card->dmxdev, file, cmd, arg);
break;
case DVB_DEVICE_OSD_0:
{
switch (cmd) {
case OSD_SEND_CMD:
{
osd_cmd_t doc;
if(copy_from_user(&doc, parg,
sizeof(osd_cmd_t)))
return -EFAULT;
return OSD_DrawCommand(card, &doc);
}
default:
return -EINVAL;
}
break;
}
default:
return -EOPNOTSUPP;
}
return 0;
}
static unsigned int
dvbdev_poll(struct dvb_device *dvbdev, int num,
struct file *file, poll_table * wait)
{
struct cvdv_cards *card=(struct cvdv_cards *) dvbdev->priv;
int type=num2type(card, num);
switch (type) {
case DVB_DEVICE_DEMUX_0:
return DmxDevPoll(&card->dmxdev, file, wait);
case DVB_DEVICE_VIDEO_0:
return PSpoll(file, wait);
case DVB_DEVICE_AUDIO_0:
return poll_audio(file, wait);
case DVB_DEVICE_CA_0:
break;
default:
return -EOPNOTSUPP;
}
return 0;
}
static int
dvbdev_device_type(struct dvb_device *dvbdev, unsigned int num)
{
struct cvdv_cards *card=(struct cvdv_cards *) dvbdev->priv;
return num2type(card, num);
}
#endif
/******************************************************************************
* driver registration
******************************************************************************/
#ifdef DVB
#define INFU 32768
static dvb_devs_t mdvb_devs = {
9,
{
DVB_DEVICE_VIDEO_0, DVB_DEVICE_AUDIO_0,
-1, -1,
DVB_DEVICE_DEMUX_0, DVB_DEVICE_DVR_0,
-1, -1,
DVB_DEVICE_OSD_0,
},
{ INFU, INFU, INFU, INFU, INFU, 1, 1, INFU, 1 },
{ 1, 1, 1, 1, INFU, 1, 1, 1, 1}
};
static int
dvb_start_feed(dvb_demux_feed_t *dvbdmxfeed)
{
dvb_demux_t *dvbdmx=dvbdmxfeed->demux;
struct cvdv_cards * card = (struct cvdv_cards *)dvbdmx->priv;
if (!dvbdmx->dmx.frontend || !card)
return -EINVAL;
if (dvbdmxfeed->type == DMX_TYPE_TS) {
if ((dvbdmxfeed->ts_type & TS_DECODER)
&& (dvbdmxfeed->pes_type<DMX_TS_PES_OTHER)) {
switch (dvbdmx->dmx.frontend->source) {
case DMX_MEMORY_FE:
if (dvbdmxfeed->ts_type & TS_DECODER)
if (dvbdmxfeed->pes_type<2 &&
dvbdmx->pids[0]!=0xffff &&
dvbdmx->pids[1]!=0xffff) {
setup_ts2pes( &card->tsa,
&card->tsv,
dvbdmx->pids,
dvbdmx->pids+1,
pes_write,
(void *)card);
dvbdmx->playing=1;
}
break;
default:
return -EINVAL;
break;
}
}
}
if (dvbdmxfeed->type == DMX_TYPE_SEC) {
int i;
for (i=0; i<dvbdmx->filternum; i++) {
if (dvbdmx->filter[i].state!=DMX_STATE_READY)
continue;
if (dvbdmx->filter[i].type!=DMX_TYPE_SEC)
continue;
if (dvbdmx->filter[i].filter.parent!=
&dvbdmxfeed->feed.sec)
continue;
dvbdmxfeed->feed.sec.is_filtering=1;
dvbdmx->filter[i].state=DMX_STATE_GO;
}
}
return 0;
}
static int
dvb_stop_feed(dvb_demux_feed_t *dvbdmxfeed)
{
dvb_demux_t *dvbdmx=dvbdmxfeed->demux;
struct cvdv_cards * card = (struct cvdv_cards *)dvbdmx->priv;
if (!card)
return -EINVAL;
if (dvbdmxfeed->type == DMX_TYPE_TS) {
if ((dvbdmxfeed->ts_type & TS_DECODER)
&& (dvbdmxfeed->pes_type<=1)) {
if (dvbdmx->playing) {
free_ipack(&card->tsa);
free_ipack(&card->tsv);
DecoderPause(card);
dvbdmx->playing=0;
}
}
}
if (dvbdmxfeed->type == DMX_TYPE_SEC) {
int i;
for (i=0; i<dvbdmx->filternum; i++)
if (dvbdmx->filter[i].state==DMX_STATE_GO &&
dvbdmx->filter[i].filter.parent==
&dvbdmxfeed->feed.sec) {
dvbdmx->filter[i].state=DMX_STATE_READY;
}
}
return 0;
}
static uint16_t get_pid(uint8_t *pid)
{
uint16_t pp = 0;
pp = (pid[0] & PID_MASK_HI)<<8;
pp |= pid[1];
return pp;
}
static int
dvb_write_to_decoder(dvb_demux_feed_t *dvbdmxfeed, uint8_t *buf, size_t count)
{
dvb_demux_t *dvbdmx=dvbdmxfeed->demux;
struct cvdv_cards * card = (struct cvdv_cards *)dvbdmx->priv;
uint16_t pid = 0;
int off = 0;
ipack *p;
if (!card)
return -EINVAL;
pid = get_pid(buf+1);
if (pid == *(card->tsa.pid)) p = &(card->tsa);
else if (pid == *(card->tsv.pid)) p = &(card->tsv);
else return 0;
if (dvbdmxfeed->pes_type>1)
return -1;
if (!(buf[3]&0x10)) // no payload?
return -1;
if (count != TS_SIZE) return -1;
if ( buf[3] & ADAPT_FIELD) { // adaptation field?
off = buf[4] + 1;
}
if (pid == *(card->tsa.pid)){
MDEBUG(0,"AUDIO count: %d off: %d\n",count,off);
margi_write_audio(card, buf+off+4, TS_SIZE-4-off, 0);
} else {
MDEBUG(0,"VIDEO count: %d off: %d\n",count,off);
margi_write(card, buf+off+4, TS_SIZE-4-off, 0);
}
// ts_to_pes( p, buf); // don't need count (=188)
return 0;
}
int dvb_register(struct cvdv_cards *card)
{
int i,ret;
struct dvb_device *dvbd=&card->dvb_dev;
dvb_demux_t *dvbdemux = (dvb_demux_t *)&card->demux;
if (card->dvb_registered)
return -1;
card->dvb_registered=1;
card->audiostate.AVSyncState=0;
card->audiostate.muteState=0;
card->audiostate.playState=AUDIO_STOPPED;
card->audiostate.streamSource=AUDIO_SOURCE_MEMORY;
card->audiostate.channelSelect=AUDIO_STEREO;
card->audiostate.bypassMode=0;
card->videostate.videoBlank=0;
card->videostate.playState=VIDEO_STOPPED;
card->videostate.streamSource=VIDEO_SOURCE_MEMORY;
card->videostate.videoFormat=VIDEO_FORMAT_4_3;
card->videostate.displayFormat=VIDEO_CENTER_CUT_OUT;
// init and register demuxes
memcpy(card->demux_id, "demux0_0", 9);
card->demux_id[7] = 1+0x30;
dvbdemux->priv = (void *) card;
dvbdemux->filternum = 32;
dvbdemux->feednum = 32;
dvbdemux->start_feed = dvb_start_feed;
dvbdemux->stop_feed = dvb_stop_feed;
dvbdemux->write_to_decoder = dvb_write_to_decoder;
dvbdemux->dmx.vendor="CIM";
dvbdemux->dmx.model="sw";
dvbdemux->dmx.id=card->demux_id;
dvbdemux->dmx.capabilities=(DMX_TS_FILTERING|
DMX_SECTION_FILTERING|
DMX_MEMORY_BASED_FILTERING);
DvbDmxInit(&card->demux);
card->dmxdev.filternum=32;
card->dmxdev.demux=&dvbdemux->dmx;
card->dmxdev.capabilities=0;
DmxDevInit(&card->dmxdev);
card->mem_frontend.id="mem_frontend";
card->mem_frontend.vendor="memory";
card->mem_frontend.model="sw";
card->mem_frontend.source=DMX_MEMORY_FE;
ret=dvbdemux->dmx.add_frontend(&dvbdemux->dmx,
&card->mem_frontend);
if (ret<0)
return ret;
ret=dvbdemux->dmx.connect_frontend(&dvbdemux->dmx,
&card->mem_frontend);
if (ret<0)
return ret;
// init and register dvb device structure
dvbd->priv=(void *) card;
dvbd->open=dvbdev_open;
dvbd->close=dvbdev_close;
dvbd->write=dvbdev_write;
dvbd->read=dvbdev_read;
dvbd->ioctl=dvbdev_ioctl;
dvbd->poll=dvbdev_poll;
dvbd->device_type=dvbdev_device_type;
for (i=0; i<DVB_DEVS_MAX; i++)
card->users[i]=card->writers[i]=0;
card->dvb_devs=0;
card->dvb_devs=&mdvb_devs;
return dvb_register_device(dvbd);
}
void dvb_unregister(struct cvdv_cards *card)
{
dvb_demux_t *dvbdemux=&card->demux;
dvbdemux->dmx.close(&dvbdemux->dmx);
dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &card->mem_frontend);
DmxDevRelease(&card->dmxdev);
DvbDmxRelease(&card->demux);
dvb_unregister_device(&card->dvb_dev);
}
#endif
LinuxTV legacy CVS <linuxtv.org/cvs>