register.c 15.8 KB
Newer Older
1 2
/*
 * This file is part of libbluray
3
 * Copyright (C) 2010-2017  Petri Hintukainen <phintuka@users.sourceforge.net>
4
 *
gates's avatar
gates committed
5 6 7 8
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
9
 *
gates's avatar
gates committed
10
 * This library is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
gates's avatar
gates committed
12 13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
14
 *
gates's avatar
gates committed
15 16 17
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library. If not, see
 * <http://www.gnu.org/licenses/>.
18 19
 */

Petri Hintukainen's avatar
Petri Hintukainen committed
20 21 22 23
#if HAVE_CONFIG_H
#include "config.h"
#endif

24
#include "register.h"
25 26 27

#include "player_settings.h"

28 29 30
#include "util/attributes.h"
#include "util/macro.h"
#include "util/logging.h"
31
#include "util/mutex.h"
32

33 34
#include <stdlib.h>
#include <string.h>
35 36 37 38 39 40 41

/*
 * Initial values for player status/setting registers (5.8.2).
 *
 * PS in comment indicates player setting -> register can't be changed from movie object code.
 */

42
static const uint32_t bd_psr_init[BD_PSR_COUNT] = {
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
    1,           /*     PSR0:  Interactive graphics stream number */
    0xff,        /*     PSR1:  Primary audio stream number */
    0x0fff0fff,  /*     PSR2:  PG TextST stream number and PiP PG stream number*/
    1,           /*     PSR3:  Angle number */
    0xffff,      /*     PSR4:  Title number */
    0xffff,      /*     PSR5:  Chapter number */
    0,           /*     PSR6:  PlayList ID */
    0,           /*     PSR7:  PlayItem ID */
    0,           /*     PSR8:  Presentation time */
    0,           /*     PSR9:  Navigation timer */
    0xffff,      /*     PSR10: Selected button ID */
    0,           /*     PSR11: Page ID */
    0xff,        /*     PSR12: User style number */
    0xff,        /* PS: PSR13: User age */
    0xffff,      /*     PSR14: Secondary audio stream number and secondary video stream number */
58 59 60 61 62 63 64 65 66 67
                 /* PS: PSR15: player capability for audio */
    BLURAY_ACAP_LPCM_48_96_SURROUND |
    BLURAY_ACAP_LPCM_192_SURROUND   |
    BLURAY_ACAP_DDPLUS_SURROUND     |
    BLURAY_ACAP_DDPLUS_DEP_SURROUND |
    BLURAY_ACAP_DTSHD_CORE_SURROUND |
    BLURAY_ACAP_DTSHD_EXT_SURROUND  |
    BLURAY_ACAP_DD_SURROUND         |
    BLURAY_ACAP_MLP_SURROUND,

68 69 70 71
    0xffffff,    /* PS: PSR16: Language code for audio */
    0xffffff,    /* PS: PSR17: Language code for PG and Text subtitles */
    0xffffff,    /* PS: PSR18: Menu description language code */
    0xffff,      /* PS: PSR19: Country code */
72 73 74 75
                 /* PS: PSR20: Region code */ /* 1 - A, 2 - B, 4 - C */
    BLURAY_REGION_B,
                 /* PS: PSR21: Output mode preference */
    BLURAY_OUTPUT_PREFER_2D,
Petri Hintukainen's avatar
Petri Hintukainen committed
76 77 78
    0,           /*     PSR22: Stereoscopic status */
    0,           /* PS: PSR23: Display capability */
    0,           /* PS: PSR24: 3D capability */
79 80 81 82
    0,           /* PS: PSR25: UHD capability */
    0,           /* PS: PSR26: UHD display capability */
    0,           /* PS: PSR27: HDR preference */
    0,           /* PS: PSR28: SDR conversion preference */
83 84 85 86
                 /* PS: PSR29: player capability for video */
    BLURAY_VCAP_SECONDARY_HD |
    BLURAY_VCAP_25Hz_50Hz,

87
    0x1ffff,     /* PS: PSR30: player capability for text subtitle */
88 89
                 /* PS: PSR31: Player profile and version */
    BLURAY_PLAYER_PROFILE_2_v2_0,
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
    0,           /*     PSR32 */
    0,           /*     PSR33 */
    0,           /*     PSR34 */
    0,           /*     PSR35 */
    0xffff,      /*     PSR36: backup PSR4 */
    0xffff,      /*     PSR37: backup PSR5 */
    0,           /*     PSR38: backup PSR6 */
    0,           /*     PSR39: backup PSR7 */
    0,           /*     PSR40: backup PSR8 */
    0,           /*     PSR41: */
    0xffff,      /*     PSR42: backup PSR10 */
    0,           /*     PSR43: backup PSR11 */
    0xff,        /*     PSR44: backup PSR12 */
    0,           /*     PSR45: */
    0,           /*     PSR46: */
    0,           /*     PSR47: */
    0xffffffff,  /* PS: PSR48: Characteristic text caps */
    0xffffffff,  /* PS: PSR49: Characteristic text caps */
    0xffffffff,  /* PS: PSR50: Characteristic text caps */
    0xffffffff,  /* PS: PSR51: Characteristic text caps */
    0xffffffff,  /* PS: PSR52: Characteristic text caps */
    0xffffffff,  /* PS: PSR53: Characteristic text caps */
    0xffffffff,  /* PS: PSR54: Characteristic text caps */
    0xffffffff,  /* PS: PSR55: Characteristic text caps */
    0xffffffff,  /* PS: PSR56: Characteristic text caps */
    0xffffffff,  /* PS: PSR57: Characteristic text caps */
    0xffffffff,  /* PS: PSR58: Characteristic text caps */
    0xffffffff,  /* PS: PSR59: Characteristic text caps */
    0xffffffff,  /* PS: PSR60: Characteristic text caps */
    0xffffffff,  /* PS: PSR61: Characteristic text caps */
    /* 62-95:   reserved */
    /* 96-111:  reserved for BD system use */
    /* 112-127: reserved */
};

/*
 * PSR ids for debugging
 */
128
static const char * const bd_psr_name[BD_PSR_COUNT] = {
129 130
    "IG_STREAM_ID",
    "PRIMARY_AUDIO_ID",
131
    "PG_STREAM",
132
    "ANGLE_NUMBER",
133
    "TITLE_NUMBER",
134 135 136 137 138 139 140 141 142 143 144 145 146
    "CHAPTER",
    "PLAYLIST",
    "PLAYITEM",
    "TIME",
    "NAV_TIMER",
    "SELECTED_BUTTON_ID",
    "MENU_PAGE_ID",
    "STYLE",
    "PARENTAL",
    "SECONDARY_AUDIO_VIDEO",
    "AUDIO_CAP",
    "AUDIO_LANG",
    "PG_AND_SUB_LANG",
Petri Hintukainen's avatar
Petri Hintukainen committed
147 148 149 150 151 152 153 154
    "MENU_LANG",
    "COUNTRY",
    "REGION",
    "OUTPUT_PREFER",
    "3D_STATUS",
    "DISPLAY_CAP",
    "3D_CAP",
    //"PSR_VIDEO_CAP",
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
};

/*
 * data
 */

typedef struct {
    void *handle;
    void (*cb)(void *, BD_PSR_EVENT*);
} PSR_CB_DATA;

struct bd_registers_s
{
    uint32_t     psr[BD_PSR_COUNT];
    uint32_t     gpr[BD_GPR_COUNT];

    /* callbacks */
Petri Hintukainen's avatar
Petri Hintukainen committed
172
    unsigned     num_cb;
173
    PSR_CB_DATA *cb;
174

175
    BD_MUTEX     mutex;
176 177 178 179 180 181 182 183 184 185
};

/*
 * init / free
 */

BD_REGISTERS *bd_registers_init(void)
{
    BD_REGISTERS *p = calloc(1, sizeof(BD_REGISTERS));

186 187
    if (p) {
        memcpy(p->psr, bd_psr_init, sizeof(bd_psr_init));
188

189 190
        bd_mutex_init(&p->mutex);
    }
191

192 193 194 195 196 197
    return p;
}

void bd_registers_free(BD_REGISTERS *p)
{
    if (p) {
198
        bd_mutex_destroy(&p->mutex);
199

200 201 202 203 204 205 206
        X_FREE(p->cb);
    }

    X_FREE(p);
}

/*
207 208 209 210 211
 * PSR lock / unlock
 */

void bd_psr_lock(BD_REGISTERS *p)
{
212
    bd_mutex_lock(&p->mutex);
213 214 215 216
}

void bd_psr_unlock(BD_REGISTERS *p)
{
217
    bd_mutex_unlock(&p->mutex);
218 219 220 221
}

/*
 * PSR change callback register / unregister
222 223 224 225
 */

void bd_psr_register_cb  (BD_REGISTERS *p, void (*callback)(void*,BD_PSR_EVENT*), void *cb_handle)
{
226
    /* no duplicates ! */
227
    PSR_CB_DATA *cb;
Petri Hintukainen's avatar
Petri Hintukainen committed
228
    unsigned i;
229 230 231

    bd_psr_lock(p);

232 233
    for (i = 0; i < p->num_cb; i++) {
        if (p->cb[i].handle == cb_handle && p->cb[i].cb == callback) {
234 235

            bd_psr_unlock(p);
236 237 238 239
            return;
        }
    }

240 241 242 243 244 245
    cb = realloc(p->cb, (p->num_cb + 1) * sizeof(PSR_CB_DATA));
    if (cb) {
        p->cb = cb;
        p->cb[p->num_cb].cb     = callback;
        p->cb[p->num_cb].handle = cb_handle;
        p->num_cb++;
246 247 248
    } else {
        BD_DEBUG(DBG_BLURAY|DBG_CRIT, "bd_psr_register_cb(): realloc failed\n");
    }
249 250

    bd_psr_unlock(p);
251 252 253 254
}

void bd_psr_unregister_cb(BD_REGISTERS *p, void (*callback)(void*,BD_PSR_EVENT*), void *cb_handle)
{
Petri Hintukainen's avatar
Petri Hintukainen committed
255
    unsigned i = 0;
256

Petri Hintukainen's avatar
Petri Hintukainen committed
257
    bd_psr_lock(p);
258

Petri Hintukainen's avatar
Petri Hintukainen committed
259 260
    while (i < p->num_cb) {
        if (p->cb[i].handle == cb_handle && p->cb[i].cb == callback) {
261 262
            if (--p->num_cb && i < p->num_cb) {
                memmove(p->cb + i, p->cb + i + 1, sizeof(PSR_CB_DATA) * (p->num_cb - i));
Petri Hintukainen's avatar
Petri Hintukainen committed
263
                continue;
264 265
            }
        }
Petri Hintukainen's avatar
Petri Hintukainen committed
266 267
        i++;
    }
268

Petri Hintukainen's avatar
Petri Hintukainen committed
269
    bd_psr_unlock(p);
270 271 272
}

/*
273
 * PSR state save / restore
274 275 276 277 278
 */

void bd_psr_save_state(BD_REGISTERS *p)
{
    /* store registers 4-8 and 10-12 to backup registers */
279 280 281

    bd_psr_lock(p);

282 283
    memcpy(p->psr + 36, p->psr + 4,  sizeof(uint32_t) * 5);
    memcpy(p->psr + 42, p->psr + 10, sizeof(uint32_t) * 3);
284

Petri Hintukainen's avatar
Petri Hintukainen committed
285 286 287
    /* generate save event */

    if (p->num_cb) {
Ian Curtis's avatar
Ian Curtis committed
288 289 290 291 292
        BD_PSR_EVENT ev;
        ev.ev_type = BD_PSR_SAVE;
        ev.psr_idx = -1;
        ev.old_val = 0;
        ev.new_val = 0;
Petri Hintukainen's avatar
Petri Hintukainen committed
293 294 295 296 297 298 299

        unsigned j;
        for (j = 0; j < p->num_cb; j++) {
            p->cb[j].cb(p->cb[j].handle, &ev);
        }
    }

300
    bd_psr_unlock(p);
301 302
}

303 304 305 306 307 308 309 310 311 312 313
void bd_psr_reset_backup_registers(BD_REGISTERS *p)
{
    bd_psr_lock(p);

    /* init backup registers to default */
    memcpy(p->psr + 36, bd_psr_init + 36, sizeof(uint32_t) * 5);
    memcpy(p->psr + 42, bd_psr_init + 42, sizeof(uint32_t) * 3);

    bd_psr_unlock(p);
}

314 315
void bd_psr_restore_state(BD_REGISTERS *p)
{
316 317
    uint32_t old_psr[13];
    uint32_t new_psr[13];
318

319 320
    bd_psr_lock(p);

321 322 323
    if (p->num_cb) {
        memcpy(old_psr, p->psr, sizeof(old_psr[0]) * 13);
    }
324 325 326 327 328

    /* restore backup registers */
    memcpy(p->psr + 4,  p->psr + 36, sizeof(uint32_t) * 5);
    memcpy(p->psr + 10, p->psr + 42, sizeof(uint32_t) * 3);

329 330 331 332
    if (p->num_cb) {
        memcpy(new_psr, p->psr, sizeof(new_psr[0]) * 13);
    }

333 334 335 336 337
    /* init backup registers to default */
    memcpy(p->psr + 36, bd_psr_init + 36, sizeof(uint32_t) * 5);
    memcpy(p->psr + 42, bd_psr_init + 42, sizeof(uint32_t) * 3);

    /* generate restore events */
Petri Hintukainen's avatar
Petri Hintukainen committed
338 339 340 341 342 343
    if (p->num_cb) {
        BD_PSR_EVENT ev;
        unsigned     i, j;

        ev.ev_type = BD_PSR_RESTORE;

344
        for (i = 4; i < 13; i++) {
345
            if (i != PSR_NAV_TIMER) {
346 347 348

                ev.psr_idx = i;
                ev.old_val = old_psr[i];
349
                ev.new_val = new_psr[i];
350

351 352
                for (j = 0; j < p->num_cb; j++) {
                    p->cb[j].cb(p->cb[j].handle, &ev);
353 354 355 356
                }
            }
        }
    }
357 358

    bd_psr_unlock(p);
359 360 361 362 363 364
}

/*
 * GPR read / write
 */

365
int bd_gpr_write(BD_REGISTERS *p, unsigned int reg, uint32_t val)
366
{
367
    if (reg >= BD_GPR_COUNT) {
368
        BD_DEBUG(DBG_BLURAY, "bd_gpr_write(%d): invalid register\n", reg);
369 370 371 372 373 374 375
        return -1;
    }

    p->gpr[reg] = val;
    return 0;
}

376
uint32_t bd_gpr_read(BD_REGISTERS *p, unsigned int reg)
377
{
378
    if (reg >= BD_GPR_COUNT) {
379
        BD_DEBUG(DBG_BLURAY, "bd_gpr_read(%d): invalid register\n", reg);
380
        return 0;
381 382 383 384 385 386 387 388 389
    }

    return p->gpr[reg];
}

/*
 * PSR read / write
 */

390
uint32_t bd_psr_read(BD_REGISTERS *p, unsigned int reg)
391
{
392 393
    uint32_t val;

394
    if (reg >= BD_PSR_COUNT) {
395
        BD_DEBUG(DBG_BLURAY, "bd_psr_read(%d): invalid register\n", reg);
396 397 398
        return -1;
    }

399 400 401 402 403 404 405
    bd_psr_lock(p);

    val = p->psr[reg];

    bd_psr_unlock(p);

    return val;
406 407
}

408
int bd_psr_setting_write(BD_REGISTERS *p, unsigned int reg, uint32_t val)
409
{
410
    if (reg >= BD_PSR_COUNT) {
411
        BD_DEBUG(DBG_BLURAY, "bd_psr_write(%d, %d): invalid register\n", reg, val);
412 413 414
        return -1;
    }

415 416
    bd_psr_lock(p);

417 418 419
    if (p->psr[reg] == val) {
        BD_DEBUG(DBG_BLURAY, "bd_psr_write(%d, %d): no change in value\n", reg, val);
    } else if (bd_psr_name[reg]) {
420
        BD_DEBUG(DBG_BLURAY, "bd_psr_write(): PSR%-4d (%s) 0x%x -> 0x%x\n", reg, bd_psr_name[reg], p->psr[reg], val);
421
    } else {
422
        BD_DEBUG(DBG_BLURAY, "bd_psr_write(): PSR%-4d 0x%x -> 0x%x\n", reg, p->psr[reg], val);
423 424 425 426
    }

    if (p->num_cb) {
        BD_PSR_EVENT ev;
Petri Hintukainen's avatar
Petri Hintukainen committed
427
        unsigned i;
428

429
        ev.ev_type = p->psr[reg] == val ? BD_PSR_WRITE : BD_PSR_CHANGE;
430 431 432 433 434 435 436 437 438 439 440 441 442 443 444
        ev.psr_idx = reg;
        ev.old_val = p->psr[reg];
        ev.new_val = val;

        p->psr[reg] = val;

        for (i = 0; i < p->num_cb; i++) {
            p->cb[i].cb(p->cb[i].handle, &ev);
        }

    } else {

        p->psr[reg] = val;
    }

445 446 447
    bd_psr_unlock(p);

    return 0;
448 449
}

450
int bd_psr_write(BD_REGISTERS *p, unsigned int reg, uint32_t val)
451 452
{
    if ((reg == 13) ||
Petri Hintukainen's avatar
Petri Hintukainen committed
453
        (reg >= 15 && reg <= 21) ||
454
        (reg >= 23 && reg <= 31) ||
455
        (reg >= 48 && reg <= 61)) {
456
      BD_DEBUG(DBG_BLURAY | DBG_CRIT, "bd_psr_write(%d, %d): read-only register !\n", reg, val);
457 458 459 460 461 462
      return -2;
  }

  return bd_psr_setting_write(p, reg, val);
}

463
int bd_psr_write_bits(BD_REGISTERS *p, unsigned int reg, uint32_t val, uint32_t mask)
464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480
{
    int result;

    if (mask == 0xffffffff) {
        return bd_psr_write(p, reg, val);
    }

    bd_psr_lock(p);

    uint32_t psr_value = bd_psr_read(p, reg);
    psr_value = (psr_value & (~mask)) | (val & mask);
    result = bd_psr_write(p, reg, psr_value);

    bd_psr_unlock(p);

    return result;
}
481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531

/*
 * save / restore registers between playback sessions
 */

void registers_save(BD_REGISTERS *p, uint32_t *psr, uint32_t *gpr)
{
    bd_psr_lock(p);

    memcpy(gpr, p->gpr, sizeof(p->gpr));
    memcpy(psr, p->psr, sizeof(p->psr));

    bd_psr_unlock(p);
}

void registers_restore(BD_REGISTERS *p, const uint32_t *psr, const uint32_t *gpr)
{
    uint32_t new_psr[13];

    bd_psr_lock(p);

    memcpy(p->gpr, gpr, sizeof(p->gpr));
    memcpy(p->psr, psr, sizeof(p->psr));

    memcpy(new_psr, p->psr, sizeof(new_psr[0]) * 13);

    /* generate restore events */
    if (p->num_cb) {
        BD_PSR_EVENT ev;
        unsigned     i, j;

        ev.ev_type = BD_PSR_RESTORE;
        ev.old_val = 0; /* not used with BD_PSR_RESTORE */

        for (i = 4; i < 13; i++) {
            if (i != PSR_NAV_TIMER) {

                p->psr[i] = new_psr[i];

                ev.psr_idx = i;
                ev.new_val = new_psr[i];

                for (j = 0; j < p->num_cb; j++) {
                    p->cb[j].cb(p->cb[j].handle, &ev);
                }
            }
        }
    }

    bd_psr_unlock(p);
}
532 533 534 535 536

/*
 *
 */

537
int psr_init_3D(BD_REGISTERS *p, int initial_mode, int force)
538 539 540
{
    bd_psr_lock(p);

541 542 543 544 545 546 547 548 549 550 551 552 553 554
    /* make automatic initialization to fail if app has already changed player profile */
    if (!force) {
        if ((bd_psr_read(p, PSR_PROFILE_VERSION) & BLURAY_PLAYER_PROFILE_VERSION_MASK) >= 0x0300) {
            BD_DEBUG(DBG_BLURAY | DBG_CRIT, "psr_init_3D() failed: profile version already set to >= 0x0300 (profile 6)\n");
            bd_psr_unlock(p);
            return -1;
        }
        if (bd_psr_read(p, PSR_PROFILE_VERSION) & BLURAY_PLAYER_PROFILE_3D_FLAG) {
            BD_DEBUG(DBG_BLURAY | DBG_CRIT, "psr_init_3D() failed: 3D already set in profile\n");
            bd_psr_unlock(p);
            return -1;
        }
    }

555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574
    bd_psr_setting_write(p, PSR_OUTPUT_PREFER,
                         BLURAY_OUTPUT_PREFER_3D);

    bd_psr_setting_write(p, PSR_DISPLAY_CAP,
                         BLURAY_DCAP_1080p_720p_3D |
                         BLURAY_DCAP_720p_50Hz_3D |
                         BLURAY_DCAP_NO_3D_CLASSES_REQUIRED |
                         BLURAY_DCAP_INTERLACED_3D |
                         0);

    bd_psr_setting_write(p, PSR_3D_CAP,
                         /* TODO */ 0xffffffff );

    bd_psr_setting_write(p, PSR_PROFILE_VERSION,
                         BLURAY_PLAYER_PROFILE_5_v2_4);

    bd_psr_write(p, PSR_3D_STATUS,
                 !!initial_mode);

    bd_psr_unlock(p);
575 576

    return 0;
577
}
578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615

int psr_init_UHD(BD_REGISTERS *p, int force)
{
    bd_psr_lock(p);

    /* make automatic initialization to fail if app has already changed player profile */
    if (!force) {
        if ((bd_psr_read(p, PSR_PROFILE_VERSION) & BLURAY_PLAYER_PROFILE_VERSION_MASK) >= 0x0300) {
          BD_DEBUG(DBG_BLURAY | DBG_CRIT, "psr_init_UHD() failed: profile version already >= 0x0300\n");
          bd_psr_unlock(p);
          return -1;
        }
        if (bd_psr_read(p, PSR_PROFILE_VERSION) & BLURAY_PLAYER_PROFILE_3D_FLAG) {
            BD_DEBUG(DBG_BLURAY | DBG_CRIT, "psr_init_UHD() failed: 3D already set in profile\n");
            bd_psr_unlock(p);
            return -1;
        }
    }

    bd_psr_setting_write(p, PSR_UHD_CAP,
                         /* TODO */ 0xffffffff );

    bd_psr_setting_write(p, PSR_UHD_DISPLAY_CAP,
                         /* TODO */ 0xffffffff );

    bd_psr_setting_write(p, PSR_UHD_HDR_PREFER,
                         /* TODO */ 0xffffffff );

    bd_psr_setting_write(p, PSR_UHD_SDR_CONV_PREFER,
                         /* TODO */ 0 );

    bd_psr_setting_write(p, PSR_PROFILE_VERSION,
                         BLURAY_PLAYER_PROFILE_6_v3_1);

    bd_psr_unlock(p);

    return 0;
}