Annotation of margi2/video.c, revision 1.1

1.1     ! cvs         1: /* 
        !             2:     video.c
        !             3: 
        !             4:     Copyright (C) Christian Wolff for convergence integrated media.
        !             5: 
        !             6:     This program is free software; you can redistribute it and/or modify
        !             7:     it under the terms of the GNU General Public License as published by
        !             8:     the Free Software Foundation; either version 2 of the License, or
        !             9:     (at your option) any later version.
        !            10: 
        !            11:     This program is distributed in the hope that it will be useful,
        !            12:     but WITHOUT ANY WARRANTY; without even the implied warranty of
        !            13:     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        !            14:     GNU General Public License for more details.
        !            15: 
        !            16:     You should have received a copy of the GNU General Public License
        !            17:     along with this program; if not, write to the Free Software
        !            18:     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
        !            19: */
        !            20: 
        !            21: //
        !            22: //  Video Decoder
        !            23: //
        !            24: #define __NO_VERSION__
        !            25: 
        !            26: #include "video.h"
        !            27: #include "l64021.h"
        !            28: #include "dram.h"
        !            29: 
        !            30: // Set the background of the OSD and SPU and it's color
        !            31: // mode=0: Video on Black
        !            32: // mode=1: Black
        !            33: // mode=2: Selected Color
        !            34: // mode=3: Video on Selected Color
        !            35: void VideoSetBackground(struct cvdv_cards *card, int mode, u8 Y, u8 Cb,
        !            36:                        u8 Cr)
        !            37: {
        !            38:        DecoderWriteByte(card, 0x10A, Y);
        !            39:        DecoderWriteByte(card, 0x10B, Cb);
        !            40:        DecoderWriteByte(card, 0x10C, Cr);
        !            41:        DecoderMaskByte(card, 0x109, 0xC0, mode << 6);
        !            42: }
        !            43: 
        !            44: 
        !            45: int DecoderStartDecode(struct cvdv_cards *card)
        !            46: {
        !            47:        DecoderSetByte(card, 0x0F6, 0x01);
        !            48:        card->videosync = 1;
        !            49:        return 0;
        !            50: }
        !            51: 
        !            52: int DecoderStopDecode(struct cvdv_cards *card)
        !            53: {
        !            54:        DecoderDelByte(card, 0x0F6, 0x01);
        !            55:        card->videosync = 0;
        !            56:        return 0;
        !            57: }
        !            58: 
        !            59: // Sets Display Override (Still Image Display) to Frame Buffer at specified addresses,
        !            60: // addresses are 16 bit, in 64 byte resolution
        !            61: // mode: 0=off, 1=Frame, 2=Field
        !            62: // width: width of the still picture in 8 pixel units
        !            63: int DecoderStillImageDisplay(struct cvdv_cards *card, int mode, int width,
        !            64:                             u16 LumaAddr, u16 ChromaAddr)
        !            65: {
        !            66:        DecoderStopDecode(card);
        !            67:        DecoderWriteWord(card, 0x11D, LumaAddr);
        !            68:        DecoderWriteWord(card, 0x11F, ChromaAddr);
        !            69:        DecoderWriteByte(card, 0x11B, width & 0x7F);
        !            70:        DecoderMaskByte(card, 0x109, 0x30, (mode & 3) << 4);    // Display Override Mode
        !            71:        return 0;
        !            72: }
        !            73: 
        !            74: // Frees allocated frame buffers
        !            75: int DecoderKillFrameBuffers(struct cvdv_cards *card)
        !            76: {
        !            77:        printk(KERN_DEBUG LOGNAME ": -- DecoderKillFrameBuffers\n");
        !            78:        DecoderStopDecode(card);
        !            79:        DRAMFree(card, card->FrameStoreLuma1);
        !            80:        card->FrameStoreLuma1 = BLANK;
        !            81:        DRAMFree(card, card->FrameStoreChroma1);
        !            82:        card->FrameStoreChroma1 = BLANK;
        !            83:        DRAMFree(card, card->FrameStoreLuma2);
        !            84:        card->FrameStoreLuma2 = BLANK;
        !            85:        DRAMFree(card, card->FrameStoreChroma2);
        !            86:        card->FrameStoreChroma2 = BLANK;
        !            87:        DRAMFree(card, card->FrameStoreLumaB);
        !            88:        card->FrameStoreLumaB = BLANK;
        !            89:        DRAMFree(card, card->FrameStoreChromaB);
        !            90:        card->FrameStoreChromaB = BLANK;
        !            91:        card->FrameBuffersAllocated = 0;
        !            92: //  DecoderWriteWord(
        !            93:        return 0;
        !            94: }
        !            95: 
        !            96: int DecoderSetFrameBuffers(struct cvdv_cards *card, int lines, // number of lines of the decoded MPEG
        !            97:                           int TwoFrames,       // 1 if no B-Frames are present in the video stream, thus allowing only 2 framestores
        !            98:                           int RMM)     // 1 if RMM
        !            99: {
        !           100: #define SEGMENTS 44            // 40..54 for PAL, 44 recommended
        !           101: #define BUFFERSET(buf,adr,align)  if (buf>0) {\
        !           102:        if (buf&((1<<align)-1)) buf=(buf&~((1<<align)-1))+(1<<align);\
        !           103:        addr=DRAMAlloc(card,buf,1<<align);\
        !           104:        if (addr==BLANK) return adr;\
        !           105:        card->buf=addr;\
        !           106:        addr>>=align;\
        !           107:        DecoderWriteByte(card,adr,addr&0xFF);\
        !           108:        DecoderWriteByte(card,adr+1,(addr>>8)&(0x00FF));\
        !           109: }
        !           110:        u32 addr;
        !           111:        int pixel, byteperline; // visible pixel per video line, same for PAL and NTSC
        !           112:        int FrameStoreLuma1, FrameStoreChroma1,
        !           113:            FrameStoreLuma2, FrameStoreChroma2,
        !           114:            FrameStoreLumaB, FrameStoreChromaB;
        !           115:        printk(KERN_DEBUG LOGNAME ": -- DecoderSetFrameBuffers\n");
        !           116:        DecoderStopDecode(card);
        !           117:        //DecoderStopChannel(card);
        !           118:        //lines=((CCIR601Lines(card->videomode)==625)?576:480);
        !           119:        byteperline = (DecoderReadByte(card, 0x116) & 0x7F) * 8;        // main 64-bit reads per line
        !           120:        pixel = byteperline * lines;
        !           121:        FrameStoreLuma1 = FrameStoreLuma2 = FrameStoreLumaB = pixel >> 1;       // 8 bit luma per pixel  in words
        !           122:        FrameStoreChroma1 = FrameStoreChroma2 = FrameStoreChromaB =
        !           123:            pixel >> 2;         // 8+8 bit chroma every 2nd pixel every 2nd line
        !           124:        if (card->FrameBuffersAllocated)
        !           125:                DecoderKillFrameBuffers(card);
        !           126:        BUFFERSET(FrameStoreLuma1, 0x0E0, 5);   // Anchor Frame Store 1
        !           127:        BUFFERSET(FrameStoreChroma1, 0x0E2, 5);
        !           128:        BUFFERSET(FrameStoreLuma2, 0x0E4, 5);   // Anchor Frame Store 2
        !           129:        BUFFERSET(FrameStoreChroma2, 0x0E6, 5);
        !           130:        if (TwoFrames) {
        !           131:                DecoderDelByte(card, 0x0F8, 0x01);
        !           132:        } else {
        !           133: //    if (CCIR601Lines(card->videomode)==525) {  // Normal Mode, NTSC
        !           134:                if (!RMM) {     // Normal Mode, NTSC
        !           135:                        BUFFERSET(FrameStoreLumaB, 0x0E8, 5);   // B Frame Store
        !           136:                        BUFFERSET(FrameStoreChromaB, 0x0EA, 5);
        !           137:                        DecoderDelByte(card, 0x0F8, 0x01);
        !           138:                } else {        // Reduced Memory Mode, PAL
        !           139:                        // 44 segments with 8 lines each (8 bit luma + 4 bit chroma)
        !           140:                        // only display modes 4-8, 10, and 11 are allowed
        !           141:                        FrameStoreLumaB =
        !           142:                            (8 * byteperline * SEGMENTS) >> 1;
        !           143:                        FrameStoreChromaB =
        !           144:                            (4 * byteperline * SEGMENTS) >> 1;
        !           145:                        BUFFERSET(FrameStoreLumaB, 0x0E8, 5);   // B Frame Store
        !           146:                        BUFFERSET(FrameStoreChromaB, 0x0EA, 5);
        !           147:                        DecoderWriteByte(card, 0x121, SEGMENTS << 1);   // Number of segments
        !           148:                        DecoderSetByte(card, 0x0F8, 0x01);
        !           149:                }
        !           150:        }
        !           151:        card->FrameBuffersAllocated = 1;
        !           152: #undef SEGMENTS
        !           153: #undef BUFFERSET
        !           154:        return 0;
        !           155: }
        !           156: 
        !           157: // returns size of the Video ES Buffer in bytes or 0=error
        !           158: u32 DecoderGetVideoESSize(struct cvdv_cards * card)
        !           159: {
        !           160:        if (!card->ChannelBuffersAllocated)
        !           161:                return 0;       // buffer not initialised
        !           162:        return (u32) ((DecoderReadWord(card, 0x04A) & 0x3FFF) -
        !           163:                      (DecoderReadWord(card, 0x048) & 0x3FFF)) * 256;   // bytes
        !           164: }
        !           165: 
        !           166: // returns level of fullness in bytes
        !           167: u32 DecoderGetVideoESLevel(struct cvdv_cards * card)
        !           168: {
        !           169:        u32 items;
        !           170:        items = DecoderReadByte(card, 0x086);
        !           171:        items |= ((DecoderReadWord(card, 0x087) & 0x07FF) << 8);
        !           172:        items *= 8;             // 64 bit per item
        !           173:        return items;
        !           174: }
        !           175: 
        !           176: // pics=0 --> items=bytes
        !           177: // pics=1 --> items=pictures
        !           178: void DecoderSetVideoPanic(struct cvdv_cards *card, int pics, int items)
        !           179: {
        !           180:        if (pics < 0) {
        !           181:                DecoderMaskByte(card, 0x045, 0x18, 0x00 << 3);  // disable panic mode
        !           182:        } else {
        !           183:                if (pics) {
        !           184:                        DecoderWriteMWord(card, 0x086, items & 0x0003FFFF);
        !           185:                        DecoderMaskByte(card, 0x045, 0x18, 0x02 << 3);  // set panic mode to "number of pictures" in VideoES
        !           186:                } else {
        !           187:                        DecoderWriteMWord(card, 0x086,
        !           188:                                          (items / 8) & 0x0003FFFF);
        !           189:                        DecoderMaskByte(card, 0x045, 0x18, 0x01 << 3);  // set panic mode to "number of 8-byte-frames" in VideoES
        !           190:                }
        !           191:        }
        !           192: }
        !           193: 
        !           194: int DecoderClose(struct cvdv_cards *card)
        !           195: {
        !           196:        if (card->DecoderOpen) {
        !           197:                printk(KERN_DEBUG LOGNAME ": -- DecoderClose\n");
        !           198:                DecoderStopDecode(card);
        !           199:                DecoderKillFrameBuffers(card);
        !           200:                card->DecoderOpen = 0;
        !           201:                card->lastvattr = 0;
        !           202:                return 0;
        !           203:        } else
        !           204:                return 1;
        !           205: }
        !           206: 
        !           207: // returns 0 on success, 1 on "picture size too big", 2 on "out of DRAM memory"
        !           208: int DecoderOpen(struct cvdv_cards *card, int x, int y, // size of the decoded MPEG picture
        !           209:                int aspect,     // pixel or picture aspect ratio of the MPEG picture: 1=square pixel 2=3:4 3=9:16 4=1:2.21
        !           210:                int Field,      // 0:Frame (interlaced, MPEG-2) , 1:Field (non-interlaced, MPEG-1) structure
        !           211:                int Letterbox,  // 0:PanScan (4:3), 1:letterbox (16:9, 8:3) picture ratio
        !           212:                int RMM)        // 1:use ReducedMemoryMode
        !           213: {
        !           214:        int mode,               // Display Mode
        !           215:         i, factor,             // zoom factor
        !           216:         top, bottom, left, right, width, height, newwidth, newheight,  // screen size
        !           217:         vaspx, vaspy,          // output video pixel aspect ratio
        !           218:         paspx, paspy,          // input picture pixel aspect ratio
        !           219:         SIF;                   // 0:Full (480/576 lines, MPEG-2), 1:SIF (half, 240/288 lines, MPEG-1) resolution
        !           220: 
        !           221:        printk(KERN_DEBUG LOGNAME
        !           222:               ": -- DecoderOpen x:%d y:%d asp:%d field:%d lt:%d rmm:%d\n",
        !           223:               x, y, aspect, Field, Letterbox, RMM);
        !           224:        if ((x <= 0) || (y <= 0))
        !           225:                return 4;       // picture too small
        !           226: //if (card->DecoderOpen) return 3;
        !           227:        DecoderStopDecode(card);
        !           228:        DecoderClose(card);     // closes only, if already open
        !           229:        vaspy = 11;
        !           230:        vaspx = ((CCIR601Lines(card->videomode) == 525) ? 10 : 12);     // screen pixel aspect ratio
        !           231:        // note: this aspect ratio applies to 704 pixel width, but the card's default is 720, wich is not 3:4 picture aspect ratio anymore!?
        !           232:        i = ((x == 720) ? 704 : x);     // 720 wide is overscan of 704 wide
        !           233:        switch (aspect) {       // MPEG data pixel aspect ratio
        !           234:        case 1:
        !           235:                paspx = 1;
        !           236:                paspy = 1;
        !           237:                break;
        !           238:        default:
        !           239:        case 2:
        !           240:                paspx = 4 * y;
        !           241:                paspy = 3 * i;
        !           242:                break;
        !           243:        case 3:
        !           244:                paspx = 16 * y;
        !           245:                paspy = 9 * i;
        !           246:                break;
        !           247:        case 4:
        !           248:                paspx = 221 * y;
        !           249:                paspy = 100 * i;
        !           250:                break;
        !           251:        }
        !           252:        top =
        !           253:            DecoderReadByte(card,
        !           254:                            0x129) | ((DecoderReadByte(card, 0x12B) & 0x07)
        !           255:                                      << 8);    // current Start- and End Column
        !           256:        bottom =
        !           257:            DecoderReadByte(card,
        !           258:                            0x12A) | ((DecoderReadByte(card, 0x12B) & 0x70)
        !           259:                                      << 4);
        !           260:        height = (bottom - top + 1) * 2;        // screen (frame) height
        !           261:        left =
        !           262:            DecoderReadByte(card,
        !           263:                            0x12C) | ((DecoderReadByte(card, 0x12E) & 0x07)
        !           264:                                      << 8);    // current Start- and End Row
        !           265:        right =
        !           266:            DecoderReadByte(card,
        !           267:                            0x12D) | ((DecoderReadByte(card, 0x12E) & 0x70)
        !           268:                                      << 4);
        !           269:        width = (right - left + 1) / 2; // screen width, 2 clocks = 1 pixel
        !           270: 
        !           271:        if (RMM)
        !           272:                DecoderSetByte(card, 0x0F8, 0x01);
        !           273:        else
        !           274:                DecoderDelByte(card, 0x0F8, 0x01);
        !           275:        //RMM=(DecoderReadByte(card,0x0F8)&0x01);
        !           276:        DecoderWriteByte(card, 0x0EF, 0x08);
        !           277: 
        !           278:        //if (x>width) {  // Is the picture too wide for the screen?
        !           279:        //  DecoderSetByte(card,0x112,0x40);  // Horiz. 2:1 Filter enable
        !           280:        //  x/=2;
        !           281:        //} else {
        !           282:        DecoderDelByte(card, 0x112, 0x40);      // Horiz. 2:1 Filter disable
        !           283:        //}
        !           284: 
        !           285: 
        !           286: 
        !           287: 
        !           288:        if (1 /*Letterbox */ ) {        // Fit to width, reduce height
        !           289:                newwidth = (x * vaspy * paspx / (paspy * vaspx));       // width in right aspect ratio
        !           290:                if (newwidth <= 360) {  // less then about half the screen size?
        !           291:                        SIF = 1;
        !           292:                        newwidth *= 2;
        !           293:                } else {
        !           294:                        SIF = 0;
        !           295:                }
        !           296:                if ((newwidth == 704) || (newwidth == 720))
        !           297:                        width = newwidth;       // standard sizes?
        !           298:                newheight =
        !           299:                    (y * vaspx * paspy / (paspx * vaspy)) * width / x;
        !           300:                factor = newheight * 100 / y;
        !           301:                printk(KERN_INFO LOGNAME
        !           302:                       ": Decoder Open: Display size %d x %d, Picture size %d x %d, Demanded size: %d x %d, factor %d\n",
        !           303:                       width, height, x, y, newwidth, newheight, factor);
        !           304:                // 16:9 Letterbox
        !           305:                if ((aspect == 3)
        !           306:                    || ((aspect == 0)
        !           307:                        && (((factor >= 65) && (factor <= 80))
        !           308:                            || ((factor >= 140) && (factor <= 160))))) {
        !           309:                        if (SIF) {      // height * 1.5, SIF Letterbox
        !           310:                                if (RMM)
        !           311:                                        return 1;       // not supported!
        !           312:                                height = (y * 3) / 2 - 2;
        !           313:                                mode = 3;
        !           314:                        } else {        // height * 0.75, 16:9 Letterbox
        !           315:                                height = (y * 3) / 4 - 2;
        !           316:                                mode = 8;
        !           317:                        }
        !           318:                        // 2.21:1 Letterbox
        !           319:                } else if ((aspect == 4)
        !           320:                           || ((aspect == 0)
        !           321:                               && (((factor >= 45) && (factor <= 60))
        !           322:                                   || (SIF && ((factor >= 90)
        !           323:                                               && (factor <= 110)))))) {
        !           324:                        if (SIF) {      // height * 1
        !           325:                                height = y;
        !           326:                                mode = 5;
        !           327:                        } else {        // height / 2
        !           328:                                height = y / 2;
        !           329:                                mode = 11;
        !           330:                        }
        !           331:                        // 3:4 aspect ratio
        !           332:                } else {
        !           333:                        if (SIF) {
        !           334:                                height = y * 2;
        !           335:                                mode = ((Field && ~RMM) ? 9 : 10);
        !           336:                        } else if (newwidth > 720) {    // picture too wide, scale down to 3/4
        !           337:                                height = (y * 3) / 4;
        !           338:                                mode = 8;
        !           339:                        } else {
        !           340:                                height = y;
        !           341:                                mode = ((Field) ? 7 : 5);
        !           342: //        mode=((Field)?5:7);
        !           343:                        }
        !           344:                }
        !           345:                width = (x * vaspy * paspx / (paspy * vaspx)) * height / y;
        !           346:                if (x < width) {        // does the picture needs a horizontal blow-up?
        !           347:                        DecoderWriteByte(card, 0x115,
        !           348:                                         ((x * 256 + width - 1) / width) & 0xFF);       // Horiz.Filter scale, x/width*256, rounded up
        !           349:                        DecoderSetByte(card, 0x114, 0x02);      // Horiz.Filter enable
        !           350:                } else if (x == width) {
        !           351:                        DecoderWriteByte(card, 0x115, 0);       // 1:1 scale
        !           352:                        DecoderDelByte(card, 0x114, 0x02);      // Horiz.Filter disable
        !           353:                } else if (x <= 720) {
        !           354:                        width = x;
        !           355:                        DecoderWriteByte(card, 0x115, 0);       // 1:1 scale
        !           356:                        DecoderDelByte(card, 0x114, 0x02);      // Horiz.Filter disable
        !           357:                } else {        // picture is more than twice the screen width. sigh.
        !           358:                        return 1;
        !           359:                }
        !           360:        } else {                // Pan-Scan, fit height to maximum
        !           361:                DecoderSetByte(card, 0x117, 0x40);      // pan-scan from bitstream
        !           362: //TODO
        !           363:                newwidth = (x * vaspy * paspx / (paspy * vaspx));       // width in right aspect ratio
        !           364:                newheight = y;
        !           365:                if (newheight <= 288) { // less then about half the screen size?
        !           366:                        SIF = 1;
        !           367:                        newheight *= 2;
        !           368:                } else {
        !           369:                        SIF = 0;
        !           370:                }
        !           371:                if ((newwidth == 704) || (newwidth == 720))
        !           372:                        width = newwidth;       // standard sizes?
        !           373:                //newheight=(y*vaspx*paspy/(paspx*vaspy))*width/x;
        !           374:                factor = newheight * 100 / y;
        !           375:                printk(KERN_INFO LOGNAME
        !           376:                       ": Decoder Open: Display size %d x %d, Picture size %d x %d, Demanded size: %d x %d, factor %d\n",
        !           377:                       width, height, x, y, newwidth, newheight, factor);
        !           378:                if (aspect == 3) {      // 16:9 Letterbox
        !           379:                        if (SIF) {      // height * 1.5, SIF Letterbox
        !           380:                                if (RMM)
        !           381:                                        return 1;       // not supported!
        !           382:                                height = (y * 3) / 2;
        !           383:                                mode = 3;
        !           384:                        } else {        // height * 0.75, 16:9 Letterbox
        !           385:                                height = (y * 3) / 4;
        !           386:                                mode = 8;
        !           387:                        }
        !           388:                } else if (aspect == 4) {       // 2.21:1 Letterbox
        !           389:                        if (SIF) {      // height * 1
        !           390:                                height = y;
        !           391:                                mode = 5;
        !           392:                        } else {        // height / 2
        !           393:                                height = y / 2;
        !           394:                                mode = 11;
        !           395:                        }
        !           396:                } else if (aspect == 2) {       // 3:4 aspect ratio
        !           397:                        if (SIF) {
        !           398:                                height = y * 2;
        !           399:                                mode = ((Field && ~RMM) ? 9 : 10);
        !           400:                        } else if (newwidth > 720) {    // picture too wide, scale down to 3/4
        !           401:                                height = (y * 3) / 4;
        !           402:                                mode = 8;
        !           403:                        } else {
        !           404:                                height = y;
        !           405:                                mode = ((Field) ? 7 : 5);
        !           406: //        mode=((Field)?5:7);
        !           407:                        }
        !           408:                }
        !           409:                width = (x * vaspy * paspx / (paspy * vaspx)) * height / y;
        !           410:                if (x < width) {        // does the picture needs a horizontal blow-up?
        !           411:                        DecoderWriteByte(card, 0x115,
        !           412:                                         ((x * 256 + width - 1) / width) & 0xFF);       // Horiz.Filter scale, x/width*256, rounded up
        !           413:                        DecoderSetByte(card, 0x114, 0x02);      // Horiz.Filter enable
        !           414:                } else if (x == width) {
        !           415:                        DecoderWriteByte(card, 0x115, 0);       // 1:1 scale
        !           416:                        DecoderDelByte(card, 0x114, 0x02);      // Horiz.Filter disable
        !           417:                } else if (x <= 720) {
        !           418:                        width = x;
        !           419:                        DecoderWriteByte(card, 0x115, 0);       // 1:1 scale
        !           420:                        DecoderDelByte(card, 0x114, 0x02);      // Horiz.Filter disable
        !           421:                } else {        // picture is more than twice the screen width. sigh.
        !           422:                        return 1;
        !           423:                }
        !           424:        }
        !           425:        printk(KERN_INFO LOGNAME
        !           426:               ": Decoder Open: Display size %d x %d, Picture size %d x %d  Mode: %d\n",
        !           427:               width, height, x, y, mode);
        !           428: 
        !           429:        // calculate new picture start- and end rows and columns
        !           430:        height /= 2;            // convert back to field height
        !           431:        top += ((bottom - top + 1 - height) / 2);
        !           432:        if (top < 0)
        !           433:                top = 0;
        !           434:        bottom = top + height - 1;
        !           435:        width *= 2;             // convert back to clocks
        !           436:        left += ((right - left + 1 - width) / 2);
        !           437:        if (left < 0)
        !           438:                left = 0;
        !           439:        right = left + width - 1;
        !           440:        DecoderWriteByte(card, 0x12C, left & 0xFF);     // Start- and End Column
        !           441:        DecoderWriteByte(card, 0x12D, right & 0xFF);
        !           442:        DecoderWriteByte(card, 0x12E,
        !           443:                         ((right >> 4) & 0x70) | ((left >> 8) & 0x07));
        !           444:        DecoderWriteByte(card, 0x129, top & 0xFF);      // Start- and End Row
        !           445:        DecoderWriteByte(card, 0x12A, bottom & 0xFF);
        !           446:        DecoderWriteByte(card, 0x12b,
        !           447:                         ((bottom >> 4) & 0x70) | ((top >> 8) & 0x07));
        !           448: 
        !           449:        DecoderWriteByte(card, 0x116, ((x + 7) / 8) & 0x7F);    // Main Reads per Line
        !           450: 
        !           451:        // set the new mode
        !           452:        DecoderMaskByte(card, 0x114, 0x78, (mode & 0x0F) << 3);
        !           453: 
        !           454: //printk(KERN_INFO LOGNAME ": Decoder Open: top/bottom/width / left/right/height  / main reads %d/%d/%d / %d/%d/%d / %d\n",top,bottom,width,left,right,height,((x+7)/8)&0x7F);
        !           455: 
        !           456:        // set the frame store buffers
        !           457:        if ((i = DecoderSetFrameBuffers(card, y, 0, RMM))) {
        !           458:                printk(KERN_ERR LOGNAME
        !           459:                       ": SetFrameBuffers failed for buffer at 0x%03X\n",
        !           460:                       i);
        !           461:                DecoderKillFrameBuffers(card);
        !           462:                return 2;
        !           463:        }
        !           464: 
        !           465:        card->lastvattr = 0;
        !           466:        card->DecoderOpen = 1;
        !           467:        return 0;
        !           468: }
        !           469: 
        !           470: // displays a still image, whose pixel data is in luma and chroma
        !           471: int DecoderShowStill(struct cvdv_cards *card, int width, int height,
        !           472:                     u8 * luma, u8 * chroma)
        !           473: {
        !           474:        u16 addr;
        !           475:        DecoderOpen(card, width, height,
        !           476:                    (((width == 320) || (width == 640) || (width == 384)
        !           477:                      || (width == 768)) ? 1 : 2),
        !           478:                    ((height < 313) ? 1 : 0), 1, 0);
        !           479:        addr =
        !           480:            ((DecoderReadWord(card, 0x11D) == DecoderReadWord(card, 0x0E0))
        !           481:             ? 0x0E4 : 0x0E0);  // choose invisible frame
        !           482:        DRAMWriteByte(card, DecoderReadWord(card, addr) << 5,
        !           483:                      width * height, luma, 1);
        !           484:        DRAMWriteByte(card, DecoderReadWord(card, addr + 2) << 5,
        !           485:                      width * height / 2, chroma, 1);
        !           486:        DecoderStillImageDisplay(card, ((height < 313) ? 2 : 1),
        !           487:                                 DecoderReadByte(card, 0x116) & 0x7F,
        !           488:                                 DecoderReadWord(card, addr),
        !           489:                                 DecoderReadWord(card, addr + 2));
        !           490:        VideoSetBackground(card, 0, 0, 0, 0);   // video on black
        !           491:        return 0;
        !           492: }
        !           493: 
        !           494: // TODO: untested, probably won't work (have to use "main reads per line" instead of width on SIF)
        !           495: int DecoderGetStill(struct cvdv_cards *card, int *width, int *height,
        !           496:                    u8 * luma, u8 * chroma)
        !           497: {
        !           498:        int framebuffer;
        !           499:        if (card->DecoderOpen) {
        !           500:                //*width=((DecoderReadByte(card,0x12D)|((DecoderReadByte(card,0x12E)&0x70)<<4))-(DecoderReadByte(card,0x12C)|((DecoderReadByte(card,0x12E)&0x07)<<8))+1)/2;  // screen width, 2 clocks = 1 pixel
        !           501:                *width = DecoderReadByte(card, 0x116) * 8;
        !           502:                *height =
        !           503:                    ((DecoderReadByte
        !           504:                      (card,
        !           505:                       0x12A) | ((DecoderReadByte(card, 0x12B) & 0x70) <<
        !           506:                                 4)) -
        !           507:                     (DecoderReadByte(card, 0x129) |
        !           508:                      ((DecoderReadByte(card, 0x12B) & 0x07) << 8)) + 1) * 2;   // screen (frame) height
        !           509:                if ((luma != NULL) && (chroma != NULL)) {
        !           510:                        framebuffer =
        !           511:                            (((DecoderReadByte(card, 0x0EE) & 0x0C) == 1) ?
        !           512:                             0x0E4 : 0x0E0);
        !           513:                        DRAMReadByte(card,
        !           514:                                     DecoderReadWord(card,
        !           515:                                                     framebuffer) << 5,
        !           516:                                     (*width) * (*height), luma, 1);
        !           517:                        DRAMReadByte(card,
        !           518:                                     DecoderReadWord(card,
        !           519:                                                     framebuffer + 2) << 5,
        !           520:                                     (*width) * (*height) / 2, chroma, 1);
        !           521:                }
        !           522:                return 0;
        !           523:        } else
        !           524:                return 1;
        !           525: }

LinuxTV legacy CVS <linuxtv.org/cvs>