/* 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 // // // ///////////////////////////////////////////////////////////////////// // Convergence CV2300i #define __NO_VERSION__ //#include #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_typedmx.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; ifilternum; 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; ifilternum; 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; iusers[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