~ubuntu-branches/ubuntu/precise/xserver-xorg-video-openchrome-lts-trusty/precise-proposed

« back to all changes in this revision

Viewing changes to src/xvmc/viaLowLevel.c

  • Committer: Package Import Robot
  • Author(s): Maarten Lankhorst
  • Date: 2014-05-15 12:47:33 UTC
  • Revision ID: package-import@ubuntu.com-20140515124733-qw5cb5dqlvejqsy3
Tags: upstream-0.3.3
Import upstream version 0.3.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*****************************************************************************
 
2
 * VIA Unichrome XvMC extension client lib.
 
3
 *
 
4
 * Copyright (c) 2004 Thomas Hellstr�m. All rights reserved.
 
5
 * Copyright (c) 2003 Andreas Robinson. All rights reserved.
 
6
 *
 
7
 * Permission is hereby granted, free of charge, to any person obtaining a
 
8
 * copy of this software and associated documentation files (the "Software"),
 
9
 * to deal in the Software without restriction, including without limitation
 
10
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 
11
 * and/or sell copies of the Software, and to permit persons to whom the
 
12
 * Software is furnished to do so, subject to the following conditions:
 
13
 *
 
14
 * The above copyright notice and this permission notice shall be included in
 
15
 * all copies or substantial portions of the Software.
 
16
 *
 
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
18
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
19
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 
20
 * AUTHOR(S) OR COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 
21
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 
22
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 
23
 * DEALINGS IN THE SOFTWARE.
 
24
 */
 
25
 
 
26
/*
 
27
 * Low-level functions that deal directly with the hardware. In the future,
 
28
 * these functions might be implemented in a kernel module. Also, some of them
 
29
 * would benefit from DMA.
 
30
 *
 
31
 * Authors: Andreas Robinson 2003. Thomas Hellstr�m 2004.
 
32
 */
 
33
 
 
34
#include "viaXvMCPriv.h"
 
35
#include "viaLowLevel.h"
 
36
#include <time.h>
 
37
#include <sys/time.h>
 
38
#include <stdio.h>
 
39
 
 
40
typedef struct
 
41
{
 
42
    CARD32 agp_buffer[LL_AGP_CMDBUF_SIZE];
 
43
    CARD32 pci_buffer[LL_PCI_CMDBUF_SIZE];
 
44
    unsigned agp_pos;
 
45
    unsigned pci_pos;
 
46
    unsigned flip_pos;
 
47
    int use_agp;
 
48
    int agp_mode;
 
49
    int agp_header_start;
 
50
    int agp_index;
 
51
    int fd;
 
52
    drm_context_t *drmcontext;
 
53
    drmLockPtr hwLock;
 
54
    drmAddress mmioAddress;
 
55
    drmAddress fbAddress;
 
56
    unsigned fbStride;
 
57
    unsigned fbDepth;
 
58
    unsigned width;
 
59
    unsigned height;
 
60
    unsigned curWaitFlags;
 
61
    int performLocking;
 
62
    unsigned errors;
 
63
    drm_via_mem_t tsMem;
 
64
    CARD32 tsOffset;
 
65
    volatile CARD32 *tsP;
 
66
    CARD32 curTimeStamp;
 
67
    CARD32 lastReadTimeStamp;
 
68
    int agpSync;
 
69
    CARD32 agpSyncTimeStamp;
 
70
    unsigned chipId;
 
71
} XvMCLowLevel;
 
72
 
 
73
/*
 
74
 * For Other architectures than i386 these might have to be modified for
 
75
 * bigendian etc.
 
76
 */
 
77
 
 
78
#define MPEGIN(xl,reg)                                                  \
 
79
    *((volatile CARD32 *)(((CARD8 *)(xl)->mmioAddress) + 0xc00 + (reg)))
 
80
 
 
81
#define VIDIN(ctx,reg)                                                  \
 
82
    *((volatile CARD32 *)(((CARD8 *)(ctx)->mmioAddress) + (reg)))
 
83
 
 
84
#define REGIN(ctx,reg)                                                  \
 
85
    *((volatile CARD32 *)(((CARD8 *)(ctx)->mmioAddress) + 0x0000 + (reg)))
 
86
 
 
87
#define HQV_CONTROL             0x3D0
 
88
#define HQV_SRC_STARTADDR_Y     0x3D4
 
89
#define HQV_SRC_STARTADDR_U     0x3D8
 
90
#define HQV_SRC_STARTADDR_V     0x3DC
 
91
#define HQV_MINIFY_DEBLOCK      0x3E8
 
92
 
 
93
#define HQV_SW_FLIP         0x00000010
 
94
#define HQV_FLIP_STATUS     0x00000001
 
95
#define HQV_SUBPIC_FLIP     0x00008000
 
96
#define HQV_FLIP_ODD        0x00000020
 
97
#define HQV_DEINTERLACE     0x00010000
 
98
#define HQV_FIELD_2_FRAME   0x00020000
 
99
#define HQV_FRAME_2_FIELD   0x00040000
 
100
#define HQV_FIELD_UV        0x00100000
 
101
#define HQV_DEBLOCK_HOR     0x00008000
 
102
#define HQV_DEBLOCK_VER     0x80000000
 
103
 
 
104
#define V_COMPOSE_MODE          0x298
 
105
#define V1_COMMAND_FIRE         0x80000000
 
106
#define V3_COMMAND_FIRE         0x40000000
 
107
 
 
108
/* SUBPICTURE Registers */
 
109
#define SUBP_CONTROL_STRIDE     0x3C0
 
110
#define SUBP_STARTADDR          0x3C4
 
111
#define RAM_TABLE_CONTROL       0x3C8
 
112
#define RAM_TABLE_READ          0x3CC
 
113
 
 
114
/* SUBP_CONTROL_STRIDE              0x3c0 */
 
115
#define SUBP_HQV_ENABLE             0x00010000
 
116
#define SUBP_IA44                   0x00020000
 
117
#define SUBP_AI44                   0x00000000
 
118
#define SUBP_STRIDE_MASK            0x00001fff
 
119
#define SUBP_CONTROL_MASK           0x00070000
 
120
 
 
121
/* RAM_TABLE_CONTROL                0x3c8 */
 
122
#define RAM_TABLE_RGB_ENABLE        0x00000007
 
123
 
 
124
#define VIA_REG_STATUS          0x400
 
125
#define VIA_REG_GEMODE          0x004
 
126
#define VIA_REG_SRCBASE         0x030
 
127
#define VIA_REG_DSTBASE         0x034
 
128
#define VIA_REG_PITCH           0x038
 
129
#define VIA_REG_SRCCOLORKEY     0x01C
 
130
#define VIA_REG_KEYCONTROL      0x02C
 
131
#define VIA_REG_SRCPOS          0x008
 
132
#define VIA_REG_DSTPOS          0x00C
 
133
#define VIA_REG_GECMD           0x000
 
134
#define VIA_REG_DIMENSION       0x010  /* width and height */
 
135
#define VIA_REG_FGCOLOR         0x018
 
136
 
 
137
#define VIA_VR_QUEUE_BUSY       0x00020000      /* Virtual Queue is busy */
 
138
#define VIA_CMD_RGTR_BUSY       0x00000080      /* Command Regulator is busy */
 
139
#define VIA_2D_ENG_BUSY         0x00000002      /* 2D Engine is busy */
 
140
#define VIA_3D_ENG_BUSY         0x00000001      /* 3D Engine is busy */
 
141
#define VIA_GEM_8bpp            0x00000000
 
142
#define VIA_GEM_16bpp           0x00000100
 
143
#define VIA_GEM_32bpp           0x00000300
 
144
#define VIA_GEC_BLT             0x00000001
 
145
#define VIA_PITCH_ENABLE        0x80000000
 
146
#define VIA_GEC_INCX            0x00000000
 
147
#define VIA_GEC_DECY            0x00004000
 
148
#define VIA_GEC_INCY            0x00000000
 
149
#define VIA_GEC_DECX            0x00008000
 
150
#define VIA_GEC_FIXCOLOR_PAT    0x00002000
 
151
 
 
152
#define VIA_BLIT_CLEAR 0x00
 
153
#define VIA_BLIT_COPY 0xCC
 
154
#define VIA_BLIT_FILL 0xF0
 
155
#define VIA_BLIT_SET 0xFF
 
156
 
 
157
#define VIA_SYNCWAITTIMEOUT 50000      /* Might be a bit conservative */
 
158
#define VIA_DMAWAITTIMEOUT 150000
 
159
#define VIA_VIDWAITTIMEOUT 50000
 
160
#define VIA_XVMC_DECODERTIMEOUT 50000  /*(microseconds) */
 
161
 
 
162
#define H1_ADDR(val) (((val) >> 2) | 0xF0000000)
 
163
#define WAITFLAGS(xl, flags)                    \
 
164
    (xl)->curWaitFlags |= (flags)
 
165
#define BEGIN_RING_AGP(xl,size)                                         \
 
166
    do {                                                                \
 
167
        if ((xl)->agp_pos > (LL_AGP_CMDBUF_SIZE-(size))) {              \
 
168
            agpFlush(xl);                                               \
 
169
        }                                                               \
 
170
    } while(0)
 
171
#define OUT_RING_AGP(xl, val)                   \
 
172
    (xl)->agp_buffer[(xl)->agp_pos++] = (val)
 
173
#define OUT_RING_QW_AGP(xl, val1, val2)                 \
 
174
    do {                                                \
 
175
        (xl)->agp_buffer[(xl)->agp_pos++] = (val1);     \
 
176
        (xl)->agp_buffer[(xl)->agp_pos++] = (val2);     \
 
177
    } while (0)
 
178
 
 
179
#define LL_HW_LOCK(xl)                                                  \
 
180
    do {                                                                \
 
181
        DRM_LOCK((xl)->fd,(xl)->hwLock,*(xl)->drmcontext,0);            \
 
182
    } while(0);
 
183
#define LL_HW_UNLOCK(xl)                                        \
 
184
    do {                                                        \
 
185
        DRM_UNLOCK((xl)->fd,(xl)->hwLock,*(xl)->drmcontext);    \
 
186
    } while(0);
 
187
 
 
188
/*
 
189
 * We want to have two concurrent types of thread taking the hardware
 
190
 * lock simulataneously. One is the video out thread that needs immediate
 
191
 * access to flip an image. The other is everything else which may have
 
192
 * the lock for quite some time. This is only so the video out thread can
 
193
 * sneak in and display an image while other resources are busy.
 
194
 */
 
195
 
 
196
void
 
197
hwlLock(void *xlp, int videoLock)
 
198
{
 
199
    XvMCLowLevel *xl = (XvMCLowLevel *) xlp;
 
200
 
 
201
    LL_HW_LOCK(xl);
 
202
}
 
203
 
 
204
void
 
205
hwlUnlock(void *xlp, int videoLock)
 
206
{
 
207
    XvMCLowLevel *xl = (XvMCLowLevel *) xlp;
 
208
 
 
209
    LL_HW_UNLOCK(xl);
 
210
}
 
211
 
 
212
static unsigned
 
213
timeDiff(struct timeval *now, struct timeval *then)
 
214
{
 
215
    return (now->tv_usec >= then->tv_usec) ?
 
216
        now->tv_usec - then->tv_usec :
 
217
        1000000 - (then->tv_usec - now->tv_usec);
 
218
}
 
219
 
 
220
void
 
221
setAGPSyncLowLevel(void *xlp, int val, CARD32 timeStamp)
 
222
{
 
223
    XvMCLowLevel *xl = (XvMCLowLevel *) xlp;
 
224
 
 
225
    xl->agpSync = val;
 
226
    xl->agpSyncTimeStamp = timeStamp;
 
227
}
 
228
 
 
229
CARD32
 
230
viaDMATimeStampLowLevel(void *xlp)
 
231
{
 
232
    XvMCLowLevel *xl = (XvMCLowLevel *) xlp;
 
233
 
 
234
    if (xl->use_agp) {
 
235
        viaBlit(xl, 32, xl->tsOffset, 1, xl->tsOffset, 1, 1, 1, 0, 0,
 
236
            VIABLIT_FILL, xl->curTimeStamp);
 
237
        return xl->curTimeStamp++;
 
238
    }
 
239
    return 0;
 
240
}
 
241
 
 
242
static void
 
243
viaDMAWaitTimeStamp(XvMCLowLevel * xl, CARD32 timeStamp, int doSleep)
 
244
{
 
245
    struct timeval now, then;
 
246
    struct timezone here;
 
247
    struct timespec sleep, rem;
 
248
 
 
249
    if (xl->use_agp && (timeStamp > xl->lastReadTimeStamp)) {
 
250
        sleep.tv_nsec = 1;
 
251
        sleep.tv_sec = 0;
 
252
        here.tz_minuteswest = 0;
 
253
        here.tz_dsttime = 0;
 
254
        gettimeofday(&then, &here);
 
255
 
 
256
        while (timeStamp > (xl->lastReadTimeStamp = *xl->tsP)) {
 
257
            gettimeofday(&now, &here);
 
258
            if (timeDiff(&now, &then) > VIA_DMAWAITTIMEOUT) {
 
259
                if ((timeStamp > (xl->lastReadTimeStamp = *xl->tsP))) {
 
260
                    xl->errors |= LL_DMA_TIMEDOUT;
 
261
                    break;
 
262
                }
 
263
            }
 
264
            if (doSleep)
 
265
                nanosleep(&sleep, &rem);
 
266
        }
 
267
    }
 
268
}
 
269
 
 
270
static int
 
271
viaDMAInitTimeStamp(XvMCLowLevel * xl)
 
272
{
 
273
    int ret = 0;
 
274
 
 
275
    if (xl->use_agp) {
 
276
        xl->tsMem.context = *(xl->drmcontext);
 
277
        xl->tsMem.size = 64;
 
278
        xl->tsMem.type = VIA_MEM_VIDEO;
 
279
        if ((ret = drmCommandWriteRead(xl->fd, DRM_VIA_ALLOCMEM, &xl->tsMem,
 
280
                sizeof(xl->tsMem))) < 0)
 
281
            return ret;
 
282
        if (xl->tsMem.size != 64)
 
283
            return -1;
 
284
        xl->tsOffset = (xl->tsMem.offset + 31) & ~31;
 
285
        xl->tsP = (CARD32 *) xl->fbAddress + (xl->tsOffset >> 2);
 
286
        xl->curTimeStamp = 1;
 
287
        *xl->tsP = 0;
 
288
    }
 
289
    return 0;
 
290
}
 
291
 
 
292
static int
 
293
viaDMACleanupTimeStamp(XvMCLowLevel * xl)
 
294
{
 
295
 
 
296
    if (!(xl->tsMem.size) || !xl->use_agp)
 
297
        return 0;
 
298
    return drmCommandWrite(xl->fd, DRM_VIA_FREEMEM, &xl->tsMem,
 
299
        sizeof(xl->tsMem));
 
300
}
 
301
 
 
302
static CARD32
 
303
viaMpegGetStatus(XvMCLowLevel * xl)
 
304
{
 
305
    return MPEGIN(xl, 0x54);
 
306
}
 
307
 
 
308
static int
 
309
viaMpegIsBusy(XvMCLowLevel * xl, CARD32 mask, CARD32 idle)
 
310
{
 
311
    CARD32 tmp = viaMpegGetStatus(xl);
 
312
 
 
313
    /*
 
314
     * Error detected.
 
315
     * FIXME: Are errors really shown when error concealment is on?
 
316
     */
 
317
 
 
318
    if (tmp & 0x70)
 
319
        return 0;
 
320
 
 
321
    return (tmp & mask) != idle;
 
322
}
 
323
 
 
324
static void
 
325
syncDMA(XvMCLowLevel * xl, unsigned int doSleep)
 
326
{
 
327
 
 
328
    /*
 
329
     * Ideally, we'd like to have an interrupt wait here, but, according to second hand
 
330
     * information, the hardware does not support this, although earlier S3 chips do that.
 
331
     * It is therefore not implemented into the DRM, and we'll do a user space wait here.
 
332
     */
 
333
 
 
334
    struct timeval now, then;
 
335
    struct timezone here;
 
336
    struct timespec sleep, rem;
 
337
 
 
338
    sleep.tv_nsec = 1;
 
339
    sleep.tv_sec = 0;
 
340
    here.tz_minuteswest = 0;
 
341
    here.tz_dsttime = 0;
 
342
    gettimeofday(&then, &here);
 
343
    while (!(REGIN(xl, VIA_REG_STATUS) & VIA_VR_QUEUE_BUSY)) {
 
344
        gettimeofday(&now, &here);
 
345
        if (timeDiff(&now, &then) > VIA_DMAWAITTIMEOUT) {
 
346
            if (!(REGIN(xl, VIA_REG_STATUS) & VIA_VR_QUEUE_BUSY)) {
 
347
                xl->errors |= LL_DMA_TIMEDOUT;
 
348
                break;
 
349
            }
 
350
        }
 
351
        if (doSleep)
 
352
            nanosleep(&sleep, &rem);
 
353
    }
 
354
    while (REGIN(xl, VIA_REG_STATUS) & VIA_CMD_RGTR_BUSY) {
 
355
        gettimeofday(&now, &here);
 
356
        if (timeDiff(&now, &then) > VIA_DMAWAITTIMEOUT) {
 
357
            if (REGIN(xl, VIA_REG_STATUS) & VIA_CMD_RGTR_BUSY) {
 
358
                xl->errors |= LL_DMA_TIMEDOUT;
 
359
                break;
 
360
            }
 
361
        }
 
362
        if (doSleep)
 
363
            nanosleep(&sleep, &rem);
 
364
    }
 
365
}
 
366
 
 
367
static void
 
368
syncVideo(XvMCLowLevel * xl, unsigned int doSleep)
 
369
{
 
370
    /*
 
371
     * Wait for HQV completion. Nothing strange here. We assume that the HQV
 
372
     * Handles syncing to the V1 / V3 engines by itself. It should be safe to
 
373
     * always wait for SUBPIC_FLIP completion although subpictures are not
 
374
     * always used.
 
375
     */
 
376
 
 
377
    struct timeval now, then;
 
378
    struct timezone here;
 
379
    struct timespec sleep, rem;
 
380
 
 
381
    sleep.tv_nsec = 1;
 
382
    sleep.tv_sec = 0;
 
383
    here.tz_minuteswest = 0;
 
384
    here.tz_dsttime = 0;
 
385
    gettimeofday(&then, &here);
 
386
    while (VIDIN(xl, HQV_CONTROL) & (HQV_SW_FLIP | HQV_SUBPIC_FLIP)) {
 
387
        gettimeofday(&now, &here);
 
388
        if (timeDiff(&now, &then) > VIA_SYNCWAITTIMEOUT) {
 
389
            if (VIDIN(xl, HQV_CONTROL) & (HQV_SW_FLIP | HQV_SUBPIC_FLIP)) {
 
390
                xl->errors |= LL_VIDEO_TIMEDOUT;
 
391
                break;
 
392
            }
 
393
        }
 
394
        if (doSleep)
 
395
            nanosleep(&sleep, &rem);
 
396
    }
 
397
}
 
398
 
 
399
static void
 
400
syncAccel(XvMCLowLevel * xl, unsigned int mode, unsigned int doSleep)
 
401
{
 
402
    struct timeval now, then;
 
403
    struct timezone here;
 
404
    struct timespec sleep, rem;
 
405
    CARD32 mask = ((mode & LL_MODE_2D) ? VIA_2D_ENG_BUSY : 0) |
 
406
        ((mode & LL_MODE_3D) ? VIA_3D_ENG_BUSY : 0);
 
407
 
 
408
    sleep.tv_nsec = 1;
 
409
    sleep.tv_sec = 0;
 
410
    here.tz_minuteswest = 0;
 
411
    here.tz_dsttime = 0;
 
412
    gettimeofday(&then, &here);
 
413
    while (REGIN(xl, VIA_REG_STATUS) & mask) {
 
414
        gettimeofday(&now, &here);
 
415
        if (timeDiff(&now, &then) > VIA_SYNCWAITTIMEOUT) {
 
416
            if (REGIN(xl, VIA_REG_STATUS) & mask) {
 
417
                xl->errors |= LL_ACCEL_TIMEDOUT;
 
418
                break;
 
419
            }
 
420
        }
 
421
        if (doSleep)
 
422
            nanosleep(&sleep, &rem);
 
423
    }
 
424
}
 
425
 
 
426
static void
 
427
syncMpeg(XvMCLowLevel * xl, unsigned int mode, unsigned int doSleep)
 
428
{
 
429
    /*
 
430
     * Ideally, we'd like to have an interrupt wait here, but from information from VIA
 
431
     * at least the MPEG completion interrupt is broken on the CLE266, which was
 
432
     * discovered during validation of the chip.
 
433
     */
 
434
 
 
435
    struct timeval now, then;
 
436
    struct timezone here;
 
437
    struct timespec sleep, rem;
 
438
    CARD32 busyMask = 0;
 
439
    CARD32 idleVal = 0;
 
440
    CARD32 ret;
 
441
 
 
442
    sleep.tv_nsec = 1;
 
443
    sleep.tv_sec = 0;
 
444
    here.tz_minuteswest = 0;
 
445
    here.tz_dsttime = 0;
 
446
    gettimeofday(&then, &here);
 
447
    if (mode & LL_MODE_DECODER_SLICE) {
 
448
        busyMask = VIA_SLICEBUSYMASK;
 
449
        idleVal = VIA_SLICEIDLEVAL;
 
450
    }
 
451
    if (mode & LL_MODE_DECODER_IDLE) {
 
452
        busyMask |= VIA_BUSYMASK;
 
453
        idleVal = VIA_IDLEVAL;
 
454
    }
 
455
    while (viaMpegIsBusy(xl, busyMask, idleVal)) {
 
456
        gettimeofday(&now, &here);
 
457
        if (timeDiff(&now, &then) > VIA_XVMC_DECODERTIMEOUT) {
 
458
            if (viaMpegIsBusy(xl, busyMask, idleVal)) {
 
459
                xl->errors |= LL_DECODER_TIMEDOUT;
 
460
            }
 
461
            break;
 
462
        }
 
463
        if (doSleep)
 
464
            nanosleep(&sleep, &rem);
 
465
    }
 
466
 
 
467
    ret = viaMpegGetStatus(xl);
 
468
    if (ret & 0x70) {
 
469
        xl->errors |= ((ret & 0x70) >> 3);
 
470
    }
 
471
    return;
 
472
}
 
473
 
 
474
static void
 
475
pciFlush(XvMCLowLevel * xl)
 
476
{
 
477
    int ret;
 
478
    drm_via_cmdbuffer_t b;
 
479
    unsigned mode = xl->curWaitFlags;
 
480
 
 
481
    b.buf = (char *)xl->pci_buffer;
 
482
    b.size = xl->pci_pos * sizeof(CARD32);
 
483
    if (xl->performLocking)
 
484
        hwlLock(xl, 0);
 
485
    if ((mode != LL_MODE_VIDEO) && (mode != 0))
 
486
        syncDMA(xl, 0);
 
487
    if ((mode & LL_MODE_2D) || (mode & LL_MODE_3D))
 
488
        syncAccel(xl, mode, 0);
 
489
    if (mode & LL_MODE_VIDEO)
 
490
        syncVideo(xl, 0);
 
491
    if (mode & (LL_MODE_DECODER_SLICE | LL_MODE_DECODER_IDLE))
 
492
        syncMpeg(xl, mode, 0);
 
493
    ret = drmCommandWrite(xl->fd, DRM_VIA_PCICMD, &b, sizeof(b));
 
494
    if (xl->performLocking)
 
495
        hwlUnlock(xl, 0);
 
496
    if (ret) {
 
497
        xl->errors |= LL_PCI_COMMAND_ERR;
 
498
    }
 
499
    xl->pci_pos = 0;
 
500
    xl->curWaitFlags = 0;
 
501
}
 
502
 
 
503
static void
 
504
agpFlush(XvMCLowLevel * xl)
 
505
{
 
506
    drm_via_cmdbuffer_t b;
 
507
    int ret;
 
508
 
 
509
    if (xl->use_agp) {
 
510
        b.buf = (char *)xl->agp_buffer;
 
511
        b.size = xl->agp_pos * sizeof(CARD32);
 
512
        if (xl->agpSync) {
 
513
            syncXvMCLowLevel(xl, LL_MODE_DECODER_IDLE, 1,
 
514
                xl->agpSyncTimeStamp);
 
515
            xl->agpSync = 0;
 
516
        }
 
517
        if (xl->performLocking)
 
518
            hwlLock(xl, 0);
 
519
        do {
 
520
            ret = drmCommandWrite(xl->fd, DRM_VIA_CMDBUFFER, &b, sizeof(b));
 
521
        } while (-EAGAIN == ret);
 
522
        if (xl->performLocking)
 
523
            hwlUnlock(xl, 0);
 
524
 
 
525
        if (ret) {
 
526
            xl->errors |= LL_AGP_COMMAND_ERR;
 
527
        } else {
 
528
            xl->agp_pos = 0;
 
529
        }
 
530
        xl->curWaitFlags &= LL_MODE_VIDEO;
 
531
    } else {
 
532
        unsigned mode = xl->curWaitFlags;
 
533
 
 
534
        b.buf = (char *)xl->agp_buffer;
 
535
        b.size = xl->agp_pos * sizeof(CARD32);
 
536
        if (xl->performLocking)
 
537
            hwlLock(xl, 0);
 
538
        if ((mode != LL_MODE_VIDEO) && (mode != 0))
 
539
            syncDMA(xl, 0);
 
540
        if ((mode & LL_MODE_2D) || (mode & LL_MODE_3D))
 
541
            syncAccel(xl, mode, 0);
 
542
        if (mode & LL_MODE_VIDEO)
 
543
            syncVideo(xl, 0);
 
544
        if (mode & (LL_MODE_DECODER_SLICE | LL_MODE_DECODER_IDLE))
 
545
            syncMpeg(xl, mode, 0);
 
546
        ret = drmCommandWrite(xl->fd, DRM_VIA_PCICMD, &b, sizeof(b));
 
547
        if (xl->performLocking)
 
548
            hwlUnlock(xl, 0);
 
549
        if (ret) {
 
550
            xl->errors |= LL_PCI_COMMAND_ERR;
 
551
        }
 
552
        xl->agp_pos = 0;
 
553
        xl->curWaitFlags = 0;
 
554
    }
 
555
}
 
556
 
 
557
unsigned
 
558
flushXvMCLowLevel(void *xlp)
 
559
{
 
560
    unsigned errors;
 
561
    XvMCLowLevel *xl = (XvMCLowLevel *) xlp;
 
562
 
 
563
    if (xl->pci_pos)
 
564
        pciFlush(xl);
 
565
    if (xl->agp_pos)
 
566
        agpFlush(xl);
 
567
    errors = xl->errors;
 
568
    xl->errors = 0;
 
569
    return errors;
 
570
}
 
571
 
 
572
void
 
573
flushPCIXvMCLowLevel(void *xlp)
 
574
{
 
575
    XvMCLowLevel *xl = (XvMCLowLevel *) xlp;
 
576
 
 
577
    if (xl->pci_pos)
 
578
        pciFlush(xl);
 
579
    if (!xl->use_agp && xl->agp_pos)
 
580
        agpFlush(xl);
 
581
}
 
582
 
 
583
__inline static void
 
584
pciCommand(XvMCLowLevel * xl, unsigned offset, unsigned value, unsigned flags)
 
585
{
 
586
    if (xl->pci_pos > (LL_PCI_CMDBUF_SIZE - 2))
 
587
        pciFlush(xl);
 
588
    if (flags)
 
589
        xl->curWaitFlags |= flags;
 
590
    xl->pci_buffer[xl->pci_pos++] = (offset >> 2) | 0xF0000000;
 
591
    xl->pci_buffer[xl->pci_pos++] = value;
 
592
}
 
593
 
 
594
void
 
595
viaMpegSetSurfaceStride(void *xlp, ViaXvMCContext * ctx)
 
596
{
 
597
    CARD32 y_stride = ctx->yStride;
 
598
    CARD32 uv_stride = y_stride >> 1;
 
599
    XvMCLowLevel *xl = (XvMCLowLevel *) xlp;
 
600
 
 
601
    BEGIN_RING_AGP(xl, 2);
 
602
    OUT_RING_QW_AGP(xl, H1_ADDR(0xc50),
 
603
        (y_stride >> 3) | ((uv_stride >> 3) << 16));
 
604
    WAITFLAGS(xl, LL_MODE_DECODER_IDLE);
 
605
}
 
606
 
 
607
void
 
608
viaVideoSetSWFLipLocked(void *xlp, unsigned yOffs, unsigned uOffs,
 
609
    unsigned vOffs, unsigned yStride, unsigned uvStride)
 
610
{
 
611
    XvMCLowLevel *xl = (XvMCLowLevel *) xlp;
 
612
 
 
613
    pciCommand(xl, HQV_SRC_STARTADDR_Y, yOffs, LL_MODE_VIDEO);
 
614
    pciCommand(xl, HQV_SRC_STARTADDR_U, uOffs, 0);
 
615
    pciCommand(xl, HQV_SRC_STARTADDR_V, vOffs, 0);
 
616
}
 
617
 
 
618
void
 
619
viaVideoSWFlipLocked(void *xlp, unsigned flags, int progressiveSequence)
 
620
{
 
621
    CARD32 andWd, orWd;
 
622
    XvMCLowLevel *xl = (XvMCLowLevel *) xlp;
 
623
 
 
624
    andWd = 0;
 
625
    orWd = 0;
 
626
 
 
627
    if ((flags & XVMC_FRAME_PICTURE) == XVMC_BOTTOM_FIELD) {
 
628
        andWd = 0xFFFFFFFFU;
 
629
        orWd = HQV_FIELD_UV |
 
630
            HQV_DEINTERLACE |
 
631
            HQV_FIELD_2_FRAME |
 
632
            HQV_FRAME_2_FIELD |
 
633
            HQV_SW_FLIP | HQV_FLIP_ODD | HQV_FLIP_STATUS | HQV_SUBPIC_FLIP;
 
634
    } else if ((flags & XVMC_FRAME_PICTURE) == XVMC_TOP_FIELD) {
 
635
        andWd = ~HQV_FLIP_ODD;
 
636
        orWd = HQV_FIELD_UV |
 
637
            HQV_DEINTERLACE |
 
638
            HQV_FIELD_2_FRAME |
 
639
            HQV_FRAME_2_FIELD |
 
640
            HQV_SW_FLIP | HQV_FLIP_STATUS | HQV_SUBPIC_FLIP;
 
641
    } else if ((flags & XVMC_FRAME_PICTURE) == XVMC_FRAME_PICTURE) {
 
642
        andWd = ~(HQV_DEINTERLACE |
 
643
            HQV_FRAME_2_FIELD | HQV_FIELD_2_FRAME | HQV_FIELD_UV);
 
644
        orWd = HQV_SW_FLIP | HQV_FLIP_STATUS | HQV_SUBPIC_FLIP;
 
645
    }
 
646
    if (progressiveSequence) {
 
647
        andWd &= ~HQV_FIELD_UV;
 
648
        orWd &= ~HQV_FIELD_UV;
 
649
    }
 
650
 
 
651
    pciCommand(xl, HQV_CONTROL, (VIDIN(xl,
 
652
                HQV_CONTROL) & andWd) | orWd, 0);
 
653
}
 
654
 
 
655
void
 
656
viaMpegSetFB(void *xlp, unsigned i,
 
657
    unsigned yOffs, unsigned uOffs, unsigned vOffs)
 
658
{
 
659
    XvMCLowLevel *xl = (XvMCLowLevel *) xlp;
 
660
 
 
661
    i *= 12;
 
662
    BEGIN_RING_AGP(xl, 6);
 
663
    OUT_RING_QW_AGP(xl, H1_ADDR(0xc20 + i), yOffs >> 3);
 
664
    OUT_RING_QW_AGP(xl, H1_ADDR(0xc24 + i), uOffs >> 3);
 
665
    OUT_RING_QW_AGP(xl, H1_ADDR(0xc28 + i), vOffs >> 3);
 
666
    WAITFLAGS(xl, LL_MODE_DECODER_IDLE);
 
667
}
 
668
 
 
669
void
 
670
viaMpegBeginPicture(void *xlp, ViaXvMCContext * ctx,
 
671
    unsigned width, unsigned height, const XvMCMpegControl * control)
 
672
{
 
673
 
 
674
    unsigned j, mb_width, mb_height;
 
675
    XvMCLowLevel *xl = (XvMCLowLevel *) xlp;
 
676
 
 
677
    mb_width = (width + 15) >> 4;
 
678
 
 
679
    mb_height =
 
680
        ((control->mpeg_coding == XVMC_MPEG_2) &&
 
681
        (control->flags & XVMC_PROGRESSIVE_SEQUENCE)) ?
 
682
        2 * ((height + 31) >> 5) : (((height + 15) >> 4));
 
683
 
 
684
    BEGIN_RING_AGP(xl, 144);
 
685
    WAITFLAGS(xl, LL_MODE_DECODER_IDLE);
 
686
 
 
687
    OUT_RING_QW_AGP(xl, H1_ADDR(0xc00),
 
688
        ((control->picture_structure & XVMC_FRAME_PICTURE) << 2) |
 
689
        ((control->picture_coding_type & 3) << 4) |
 
690
        ((control->flags & XVMC_ALTERNATE_SCAN) ? (1 << 6) : 0));
 
691
 
 
692
    if (!(ctx->intraLoaded)) {
 
693
        OUT_RING_QW_AGP(xl, H1_ADDR(0xc5c), 0);
 
694
        for (j = 0; j < 64; j += 4) {
 
695
            OUT_RING_QW_AGP(xl, H1_ADDR(0xc60),
 
696
                ctx->intra_quantiser_matrix[j] |
 
697
                (ctx->intra_quantiser_matrix[j + 1] << 8) |
 
698
                (ctx->intra_quantiser_matrix[j + 2] << 16) |
 
699
                (ctx->intra_quantiser_matrix[j + 3] << 24));
 
700
        }
 
701
        ctx->intraLoaded = 1;
 
702
    }
 
703
 
 
704
    if (!(ctx->nonIntraLoaded)) {
 
705
        OUT_RING_QW_AGP(xl, H1_ADDR(0xc5c), 1);
 
706
        for (j = 0; j < 64; j += 4) {
 
707
            OUT_RING_QW_AGP(xl, H1_ADDR(0xc60),
 
708
                ctx->non_intra_quantiser_matrix[j] |
 
709
                (ctx->non_intra_quantiser_matrix[j + 1] << 8) |
 
710
                (ctx->non_intra_quantiser_matrix[j + 2] << 16) |
 
711
                (ctx->non_intra_quantiser_matrix[j + 3] << 24));
 
712
        }
 
713
        ctx->nonIntraLoaded = 1;
 
714
    }
 
715
 
 
716
    if (!(ctx->chromaIntraLoaded)) {
 
717
        OUT_RING_QW_AGP(xl, H1_ADDR(0xc5c), 2);
 
718
        for (j = 0; j < 64; j += 4) {
 
719
            OUT_RING_QW_AGP(xl, H1_ADDR(0xc60),
 
720
                ctx->chroma_intra_quantiser_matrix[j] |
 
721
                (ctx->chroma_intra_quantiser_matrix[j + 1] << 8) |
 
722
                (ctx->chroma_intra_quantiser_matrix[j + 2] << 16) |
 
723
                (ctx->chroma_intra_quantiser_matrix[j + 3] << 24));
 
724
        }
 
725
        ctx->chromaIntraLoaded = 1;
 
726
    }
 
727
 
 
728
    if (!(ctx->chromaNonIntraLoaded)) {
 
729
        OUT_RING_QW_AGP(xl, H1_ADDR(0xc5c), 3);
 
730
        for (j = 0; j < 64; j += 4) {
 
731
            OUT_RING_QW_AGP(xl, H1_ADDR(0xc60),
 
732
                ctx->chroma_non_intra_quantiser_matrix[j] |
 
733
                (ctx->chroma_non_intra_quantiser_matrix[j + 1] << 8) |
 
734
                (ctx->chroma_non_intra_quantiser_matrix[j + 2] << 16) |
 
735
                (ctx->chroma_non_intra_quantiser_matrix[j + 3] << 24));
 
736
        }
 
737
        ctx->chromaNonIntraLoaded = 1;
 
738
    }
 
739
 
 
740
    OUT_RING_QW_AGP(xl, H1_ADDR(0xc90),
 
741
        ((mb_width * mb_height) & 0x3fff) |
 
742
        ((control->flags & XVMC_PRED_DCT_FRAME) ? (1 << 14) : 0) |
 
743
        ((control->flags & XVMC_TOP_FIELD_FIRST) ? (1 << 15) : 0) |
 
744
        ((control->mpeg_coding == XVMC_MPEG_2) ? (1 << 16) : 0) |
 
745
        ((mb_width & 0xff) << 18));
 
746
 
 
747
    OUT_RING_QW_AGP(xl, H1_ADDR(0xc94),
 
748
        ((control->flags & XVMC_CONCEALMENT_MOTION_VECTORS) ? 1 : 0) |
 
749
        ((control->flags & XVMC_Q_SCALE_TYPE) ? 2 : 0) |
 
750
        ((control->intra_dc_precision & 3) << 2) |
 
751
        (((1 + 0x100000 / mb_width) & 0xfffff) << 4) |
 
752
        ((control->flags & XVMC_INTRA_VLC_FORMAT) ? (1 << 24) : 0));
 
753
 
 
754
    OUT_RING_QW_AGP(xl, H1_ADDR(0xc98),
 
755
        (((control->FHMV_range) & 0xf) << 0) |
 
756
        (((control->FVMV_range) & 0xf) << 4) |
 
757
        (((control->BHMV_range) & 0xf) << 8) |
 
758
        (((control->BVMV_range) & 0xf) << 12) |
 
759
        ((control->flags & XVMC_SECOND_FIELD) ? (1 << 20) : 0) |
 
760
        (0x0a6 << 16));
 
761
 
 
762
}
 
763
 
 
764
void
 
765
viaMpegReset(void *xlp)
 
766
{
 
767
    int i, j;
 
768
    XvMCLowLevel *xl = (XvMCLowLevel *) xlp;
 
769
 
 
770
    BEGIN_RING_AGP(xl, 100);
 
771
    WAITFLAGS(xl, LL_MODE_DECODER_IDLE);
 
772
 
 
773
    for (i = 0; i < 14; i++)
 
774
        OUT_RING_QW_AGP(xl, H1_ADDR(0xc08), 0);
 
775
 
 
776
    OUT_RING_QW_AGP(xl, H1_ADDR(0xc98), 0x400000);
 
777
 
 
778
    for (i = 0; i < 6; i++) {
 
779
        OUT_RING_QW_AGP(xl, H1_ADDR(0xc0c), 0x43 | 0x20);
 
780
        for (j = 0xc10; j < 0xc20; j += 4)
 
781
            OUT_RING_QW_AGP(xl, H1_ADDR(j), 0);
 
782
    }
 
783
 
 
784
    OUT_RING_QW_AGP(xl, H1_ADDR(0xc0c), 0xc3 | 0x20);
 
785
    for (j = 0xc10; j < 0xc20; j += 4)
 
786
        OUT_RING_QW_AGP(xl, H1_ADDR(j), 0);
 
787
 
 
788
}
 
789
 
 
790
void
 
791
viaMpegWriteSlice(void *xlp, CARD8 * slice, int nBytes, CARD32 sCode)
 
792
{
 
793
    int i, n, r;
 
794
    CARD32 *buf;
 
795
    int count;
 
796
    XvMCLowLevel *xl = (XvMCLowLevel *) xlp;
 
797
 
 
798
    if (xl->errors & (LL_DECODER_TIMEDOUT |
 
799
            LL_IDCT_FIFO_ERROR | LL_SLICE_FIFO_ERROR | LL_SLICE_FAULT))
 
800
        return;
 
801
 
 
802
    n = nBytes >> 2;
 
803
    if (sCode)
 
804
        nBytes += 4;
 
805
    r = nBytes & 3;
 
806
    buf = (CARD32 *) slice;
 
807
 
 
808
    if (r)
 
809
        nBytes += 4 - r;
 
810
 
 
811
    nBytes += 8;
 
812
 
 
813
    BEGIN_RING_AGP(xl, 4);
 
814
    WAITFLAGS(xl, LL_MODE_DECODER_IDLE);
 
815
 
 
816
    OUT_RING_QW_AGP(xl, H1_ADDR(0xc9c), nBytes);
 
817
 
 
818
    if (sCode)
 
819
        OUT_RING_QW_AGP(xl, H1_ADDR(0xca0), sCode);
 
820
 
 
821
    i = 0;
 
822
    count = 0;
 
823
 
 
824
    do {
 
825
        count += (LL_AGP_CMDBUF_SIZE - 20) >> 1;
 
826
        count = (count > n) ? n : count;
 
827
        BEGIN_RING_AGP(xl, (count - i) << 1);
 
828
 
 
829
        for (; i < count; i++) {
 
830
            OUT_RING_QW_AGP(xl, H1_ADDR(0xca0), *buf++);
 
831
        }
 
832
    } while (i < n);
 
833
 
 
834
    BEGIN_RING_AGP(xl, 6);
 
835
 
 
836
    if (r) {
 
837
        OUT_RING_QW_AGP(xl, H1_ADDR(0xca0), *buf & ((1 << (r << 3)) - 1));
 
838
    }
 
839
    OUT_RING_QW_AGP(xl, H1_ADDR(0xca0), 0);
 
840
    OUT_RING_QW_AGP(xl, H1_ADDR(0xca0), 0);
 
841
 
 
842
}
 
843
 
 
844
void
 
845
viaVideoSubPictureOffLocked(void *xlp)
 
846
{
 
847
 
 
848
    CARD32 stride;
 
849
    XvMCLowLevel *xl = (XvMCLowLevel *) xlp;
 
850
 
 
851
    stride = VIDIN(xl, SUBP_CONTROL_STRIDE);
 
852
 
 
853
    pciCommand(xl, SUBP_CONTROL_STRIDE, stride & ~SUBP_HQV_ENABLE,
 
854
        LL_MODE_VIDEO);
 
855
}
 
856
 
 
857
void
 
858
viaVideoSubPictureLocked(void *xlp, ViaXvMCSubPicture * pViaSubPic)
 
859
{
 
860
 
 
861
    unsigned i;
 
862
    CARD32 cWord;
 
863
    XvMCLowLevel *xl = (XvMCLowLevel *) xlp;
 
864
 
 
865
    for (i = 0; i < VIA_SUBPIC_PALETTE_SIZE; ++i) {
 
866
        pciCommand(xl, RAM_TABLE_CONTROL, pViaSubPic->palette[i],
 
867
            LL_MODE_VIDEO);
 
868
    }
 
869
 
 
870
    pciCommand(xl, SUBP_STARTADDR, pViaSubPic->offset, 0);
 
871
    cWord = (pViaSubPic->stride & SUBP_STRIDE_MASK) | SUBP_HQV_ENABLE;
 
872
    cWord |= (pViaSubPic->ia44) ? SUBP_IA44 : SUBP_AI44;
 
873
    pciCommand(xl, SUBP_CONTROL_STRIDE, cWord, 0);
 
874
}
 
875
 
 
876
void
 
877
viaBlit(void *xlp, unsigned bpp, unsigned srcBase,
 
878
    unsigned srcPitch, unsigned dstBase, unsigned dstPitch,
 
879
    unsigned w, unsigned h, int xdir, int ydir, unsigned blitMode,
 
880
    unsigned color)
 
881
{
 
882
 
 
883
    CARD32 dwGEMode = 0, srcY = 0, srcX, dstY = 0, dstX;
 
884
    CARD32 cmd;
 
885
    XvMCLowLevel *xl = (XvMCLowLevel *) xlp;
 
886
 
 
887
    if (!w || !h)
 
888
        return;
 
889
 
 
890
    switch (bpp) {
 
891
    case 16:
 
892
        dwGEMode |= VIA_GEM_16bpp;
 
893
        break;
 
894
    case 32:
 
895
        dwGEMode |= VIA_GEM_32bpp;
 
896
        break;
 
897
    default:
 
898
        dwGEMode |= VIA_GEM_8bpp;
 
899
        break;
 
900
    }
 
901
 
 
902
    srcX = srcBase & 31;
 
903
    dstX = dstBase & 31;
 
904
    switch (bpp) {
 
905
    case 16:
 
906
        dwGEMode |= VIA_GEM_16bpp;
 
907
        srcX >>= 2;
 
908
        dstX >>= 2;
 
909
        break;
 
910
    case 32:
 
911
        dwGEMode |= VIA_GEM_32bpp;
 
912
        srcX >>= 4;
 
913
        dstX >>= 4;
 
914
        break;
 
915
    default:
 
916
        dwGEMode |= VIA_GEM_8bpp;
 
917
        break;
 
918
    }
 
919
 
 
920
    BEGIN_RING_AGP(xl, 20);
 
921
    WAITFLAGS(xl, LL_MODE_2D);
 
922
 
 
923
    OUT_RING_QW_AGP(xl, H1_ADDR(VIA_REG_GEMODE), dwGEMode);
 
924
    cmd = 0;
 
925
 
 
926
    if (xdir < 0) {
 
927
        cmd |= VIA_GEC_DECX;
 
928
        srcX += (w - 1);
 
929
        dstX += (w - 1);
 
930
    }
 
931
    if (ydir < 0) {
 
932
        cmd |= VIA_GEC_DECY;
 
933
        srcY += (h - 1);
 
934
        dstY += (h - 1);
 
935
    }
 
936
 
 
937
    switch (blitMode) {
 
938
    case VIABLIT_TRANSCOPY:
 
939
        OUT_RING_QW_AGP(xl, H1_ADDR(VIA_REG_SRCCOLORKEY), color);
 
940
        OUT_RING_QW_AGP(xl, H1_ADDR(VIA_REG_KEYCONTROL), 0x4000);
 
941
        cmd |= VIA_GEC_BLT | (VIA_BLIT_COPY << 24);
 
942
        break;
 
943
    case VIABLIT_FILL:
 
944
        OUT_RING_QW_AGP(xl, H1_ADDR(VIA_REG_FGCOLOR), color);
 
945
        cmd |= VIA_GEC_BLT | VIA_GEC_FIXCOLOR_PAT | (VIA_BLIT_FILL << 24);
 
946
        break;
 
947
    default:
 
948
        OUT_RING_QW_AGP(xl, H1_ADDR(VIA_REG_KEYCONTROL), 0x0);
 
949
        cmd |= VIA_GEC_BLT | (VIA_BLIT_COPY << 24);
 
950
    }
 
951
 
 
952
    OUT_RING_QW_AGP(xl, H1_ADDR(VIA_REG_SRCBASE), (srcBase & ~31) >> 3);
 
953
    OUT_RING_QW_AGP(xl, H1_ADDR(VIA_REG_DSTBASE), (dstBase & ~31) >> 3);
 
954
    OUT_RING_QW_AGP(xl, H1_ADDR(VIA_REG_PITCH), VIA_PITCH_ENABLE |
 
955
        (srcPitch >> 3) | (((dstPitch) >> 3) << 16));
 
956
    OUT_RING_QW_AGP(xl, H1_ADDR(VIA_REG_SRCPOS), ((srcY << 16) | srcX));
 
957
    OUT_RING_QW_AGP(xl, H1_ADDR(VIA_REG_DSTPOS), ((dstY << 16) | dstX));
 
958
    OUT_RING_QW_AGP(xl, H1_ADDR(VIA_REG_DIMENSION),
 
959
        (((h - 1) << 16) | (w - 1)));
 
960
    OUT_RING_QW_AGP(xl, H1_ADDR(VIA_REG_GECMD), cmd);
 
961
}
 
962
 
 
963
unsigned
 
964
syncXvMCLowLevel(void *xlp, unsigned int mode, unsigned int doSleep,
 
965
    CARD32 timeStamp)
 
966
{
 
967
    unsigned errors;
 
968
    XvMCLowLevel *xl = (XvMCLowLevel *) xlp;
 
969
 
 
970
    if (mode == 0) {
 
971
        errors = xl->errors;
 
972
        xl->errors = 0;
 
973
        return errors;
 
974
    }
 
975
 
 
976
    if ((mode & (LL_MODE_VIDEO | LL_MODE_3D)) || !xl->use_agp) {
 
977
        if (xl->performLocking)
 
978
            hwlLock(xl, 0);
 
979
        if ((mode != LL_MODE_VIDEO))
 
980
            syncDMA(xl, doSleep);
 
981
        if (mode & LL_MODE_3D)
 
982
            syncAccel(xl, mode, doSleep);
 
983
        if (mode & LL_MODE_VIDEO)
 
984
            syncVideo(xl, doSleep);
 
985
        if (xl->performLocking)
 
986
            hwlUnlock(xl, 0);
 
987
    } else {
 
988
        viaDMAWaitTimeStamp(xl, timeStamp, doSleep);
 
989
    }
 
990
 
 
991
    if (mode & (LL_MODE_DECODER_SLICE | LL_MODE_DECODER_IDLE))
 
992
        syncMpeg(xl, mode, doSleep);
 
993
 
 
994
    errors = xl->errors;
 
995
    xl->errors = 0;
 
996
 
 
997
    return errors;
 
998
}
 
999
 
 
1000
extern void *
 
1001
initXvMCLowLevel(int fd, drm_context_t * ctx,
 
1002
    drmLockPtr hwLock, drmAddress mmioAddress,
 
1003
    drmAddress fbAddress, unsigned fbStride, unsigned fbDepth,
 
1004
    unsigned width, unsigned height, int useAgp, unsigned chipId)
 
1005
{
 
1006
    int ret;
 
1007
    XvMCLowLevel *xl;
 
1008
 
 
1009
    if (chipId == PCI_CHIP_VT3259 || chipId == PCI_CHIP_VT3364) {
 
1010
        fprintf(stderr, "You are using an XvMC driver for the wrong chip.\n");
 
1011
        fprintf(stderr, "Chipid is 0x%04x.\n", chipId);
 
1012
        return NULL;
 
1013
    }
 
1014
 
 
1015
    xl = (XvMCLowLevel *) malloc(sizeof(XvMCLowLevel));
 
1016
 
 
1017
    if (!xl)
 
1018
        return NULL;
 
1019
 
 
1020
    xl->agp_pos = 0;
 
1021
    xl->pci_pos = 0;
 
1022
    xl->use_agp = useAgp;
 
1023
    xl->fd = fd;
 
1024
    xl->drmcontext = ctx;
 
1025
    xl->hwLock = hwLock;
 
1026
    xl->mmioAddress = mmioAddress;
 
1027
    xl->fbAddress = fbAddress;
 
1028
    xl->curWaitFlags = 0;
 
1029
    xl->performLocking = 1;
 
1030
    xl->errors = 0;
 
1031
    xl->agpSync = 0;
 
1032
    ret = viaDMAInitTimeStamp(xl);
 
1033
    if (ret) {
 
1034
        free(xl);
 
1035
        return NULL;
 
1036
    }
 
1037
    return xl;
 
1038
}
 
1039
 
 
1040
void
 
1041
setLowLevelLocking(void *xlp, int performLocking)
 
1042
{
 
1043
    XvMCLowLevel *xl = (XvMCLowLevel *) xlp;
 
1044
 
 
1045
    xl->performLocking = performLocking;
 
1046
}
 
1047
 
 
1048
void
 
1049
closeXvMCLowLevel(void *xlp)
 
1050
{
 
1051
    XvMCLowLevel *xl = (XvMCLowLevel *) xlp;
 
1052
 
 
1053
    viaDMACleanupTimeStamp(xl);
 
1054
    free(xl);
 
1055
}