/* 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; } static char *cimlogo[] = { ".............................................", ".............................................", "......................###....................", ".....................#####...................", ".....................######..................", "..............#......#####...................", "...........#####....######...................", ".........########...######...................", "........########....######...................", ".......#########...######....................", "......########.....######...####.............", ".....#######.......#####...#####.............", ".....######.......######...######............", "....#######.......######....######...........", "....######........######....######...........", "....#####........######......#####...........", "...######........######......#####...........", "...#####.........######......######..........", "...#####.........#####.......######..........", "...#####........######........#####..........", "...#####........######.......######..........", "...#####........#####.........#####..........", "...#####.......######........######..........", "...#####.......######........#####...........", "...######.......####.........#####...........", "....#####........##.........######...........", "....######..................######...........", "....######.................######............", ".....#######..............######.....#####...", ".....########............#######....#######..", "......#########........########.....#######..", ".......#######################......########.", "........#####################.......#######..", "..........#################.........#######..", "............#############............#####...", "...............#.#####.................##....", ".............................................", "............................................." }; ///////////////////////////////////////////// // // // Controlling the L64021 MPEG-2 Decoder // // // ///////////////////////////////////////////// int OSDTest(struct cvdv_cards *card) { int i, j, col, x0, y0, x1, y1,aspx; u8 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) { // 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)) { // 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 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 } printk(KERN_DEBUG LOGNAME ": 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, 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, NBBUF* CHANNELBUFFERSIZE); 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); OSDClose(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; int count; count = ring_read_rest(&(card->rbuf)); if (count > 0 ) card->DMAABusy = 1; 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 card->channelApos = 0; card->channelBpos = 0; if ((card->DMAABusy || card->DMABBusy || count >1000 ) && (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 printk(KERN_DEBUG LOGNAME ": closing now\n"); } } } 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, };