Difference between revisions of "/dev/di"

From WiiBrew
Jump to: navigation, search
(Document behavior of clearing the error interrupt across versions)
(Version history: Note whether these versions write 0xDEADBEEF to kernel memory on error)
Line 82: Line 82:
 
  ! Version
 
  ! Version
 
  ! <abbr title="Out of bounds">OoB</abbr> [[#0x8D DVDLowUnencryptedRead|0x8D]]
 
  ! <abbr title="Out of bounds">OoB</abbr> [[#0x8D DVDLowUnencryptedRead|0x8D]]
  ! <abbr title="Issues 0xE0 when the error interrupt is set before running another command, in addition to clearing the interrupt">0xE0 error</abbr>
+
  ! <abbr title="Issues 0xE0 when the error interrupt is set before running another command, in addition to clearing the interrupt">0xE0 on<br>error</abbr>
 +
! <abbr title="Attempts to write 0xDEADBEEF to kernel memory (0xFFFF0000) on diFatalError, in addition to calling CancelThread and entering an infinite loop.  Error message is also '(diFatalError) *** DI FATAL ERROR: %s\nExiting\n' instead of '(diFatalError) Fatal error in DI driver: %s\nExiting\n' to on these versions.">DEADBEEF<br>fatal error</abbr>
 
  ! [[#0x90 DVDLowGetNoDiscOpenPartitionParams|0x90]]
 
  ! [[#0x90 DVDLowGetNoDiscOpenPartitionParams|0x90]]
 
  ! [[#0x91 DVDLowNoDiscOpenPartition|0x91]]
 
  ! [[#0x91 DVDLowNoDiscOpenPartition|0x91]]
Line 94: Line 95:
 
  | {{No}}
 
  | {{No}}
 
  | {{Yes}}
 
  | {{Yes}}
 +
| {{No}}
 
  | {{No}}
 
  | {{No}}
 
  | {{No}}
 
  | {{No}}
Line 105: Line 107:
 
  | {{Yes}}
 
  | {{Yes}}
 
  | {{Yes}}
 
  | {{Yes}}
 +
| {{No}}
 
  | {{Yes}}
 
  | {{Yes}}
 
  | {{Yes}}
 
  | {{Yes}}
Line 116: Line 119:
 
  |rowspan="3" {{Yes}}
 
  |rowspan="3" {{Yes}}
 
  |rowspan="3" {{No}}
 
  |rowspan="3" {{No}}
 +
|rowspan="3" {{Yes}}
 
  |rowspan="3" {{Partial}}
 
  |rowspan="3" {{Partial}}
 
  |rowspan="3" {{Partial}}
 
  |rowspan="3" {{Partial}}
Line 131: Line 135:
 
  |rowspan="3" {{Yes}}
 
  |rowspan="3" {{Yes}}
 
  |rowspan="3" {{Yes}}
 
  |rowspan="3" {{Yes}}
 +
|rowspan="3" {{No}}
 
  |rowspan="3" {{Partial}}
 
  |rowspan="3" {{Partial}}
 
  |rowspan="3" {{Partial}}
 
  |rowspan="3" {{Partial}}
Line 146: Line 151:
 
  | {{Yes}}
 
  | {{Yes}}
 
  | {{No}}
 
  | {{No}}
 +
| {{Yes}}
 
  | {{Partial}}
 
  | {{Partial}}
 
  | {{Partial}}
 
  | {{Partial}}
Line 157: Line 163:
 
  | {{Yes}}
 
  | {{Yes}}
 
  | {{No}}
 
  | {{No}}
 +
| {{Yes}}
 
  | {{Partial}}
 
  | {{Partial}}
 
  | {{Partial}}
 
  | {{Partial}}

Revision as of 02:37, 28 November 2019

See also: Hardware/Drive Interface


/dev/di is the IOS driver used to control the disc drive. This documentation is mostly based on the most recent version (dated Jun 3 2009 07:49:09 and included in IOS58 and IOS80). Names are based on function names found in Nintendo titles (which print an error message including the name if the Ioctl or Ioctlv fails). DVDLowRequestAudioStatus and DVDLowAudioStream are not found in Wii titles, but the names can be found in debug symbols included in various Gamecube games.

The input to all /dev/di commands (other than enable DVD video) is the following struct, which must be sized 0x20 and aligned 4:

struct diCommand {
  u8 command; // Same as the ioctl number
  u8 padding1, padding2, padding3;
  u32 arg1;
  u32 arg2;
  u32 arg3;
  u32 arg4;
  u32 arg5;
  u32 arg6;
  u32 arg7;
}

The command field should match the ioctl number (other than with enable DVD video), but if they do not match the ioctl number is the one that is used. The ioctl handler includes a warning stating the following:

(DiIoctl) Note: IOCTL command (0x##) doesn't match block command (0x##)
(DiIoctl) Note: This is normal for DVD software before 6-24

Contents

Return values

"Internal command result" is used within the DI driver, and is converted to the actual return value by commandResultToIoctlReturn (at 20200114).

Return value Internal command result Meaning
-1 N/A Returned by the IPC handler for invalid pointers (not directly part of /dev/di)
0 N/A Returned by enable dvd video (0x8e) on success.
0x1 0x0000 OK/Success
0x2 0xa000 Drive error (bit 2 (DEINT) of DISR set)
0x4 N/A Returned after DVDLowWaitForCoverClose (0x79). Also could theoretically be or'd onto most other return values if a flag (20209000) is set, but this flag is never set.
0x8 N/A Not actually returned by any DI ioctls, but Nintendo's libraries will OR this value when breakRequested is true, and the bit is reserved for that purpose.
0x10 0x8000 Read timed out (took over 15000000µs, i.e. 15 seconds, to respond; this mainly happens when bad parameters result in DILENGTH not being written)
0x20 0x7700 Security error (e.g. buffer size too small, attempting to enable DVD video, etc)
0x40 0x7800 Verify error (when call to ES_DiVerify fails when opening a partition)
0x80 0xb000 Bad argument

Version history

There are 10 known versions of the DI driver found in various IOS versions, based on the IOS versions still present on NUS. It is quite likely that there are additional changes not noted here.

Overview
Version OoB 0x8D 0xE0 on
error
DEADBEEF
fatal error
0x90 0x91 0x92 0x93 0x94 0x95 0x96
Oct 5 2006 17:41:21 No Yes No No No No No No No No
Jun 8 2007 18:17:09 Yes Yes No Yes Yes Yes Yes Yes Yes No
Jul 11 2008 14:34:27 Yes No Yes Partial Partial Partial Yes Yes Yes Yes
Jul 24 2008 00:30:13
Dec 24 2008 13:51:06
Jul 14 2008 19:25:32 Yes Yes No Partial Partial Partial Yes Yes Yes No
Jul 14 2008 19:32:38
Jul 24 2008 20:08:45
Nov 24 2008 15:39:09 Yes No Yes Partial Partial Partial Yes Yes Yes Yes
Jun 3 2009 07:49:09 Yes No Yes Partial Partial Partial Yes Yes Yes Yes

Oct 5 2006 17:41:21

Used in monolithic IOS versions (those prior to IOS28, obviously excluding stubbed IOS versions). As these versions have only a single ELF file for all modules, there is no single hash for the DI driver.

In this version, 0x8D DVDLowUnencryptedRead only accepted the start and end being between 0 and 0x14000, and IOCtls 0x95 DVDLowGetStatusRegister and 0x96 DVDLowGetControlRegister and all IOCtlVs other than 0x8B DVDLowOpenPartition did not exist. 0x87 and 0x7F DVDLowSetSpinupFlag did exist as the current stubs.

This version will issues command 0xE0 to the drive if the error interrupt is set before a command runs (in addition to clearing the interrupt). It prints a message before it issues the command, but not if the issued command fails.

MD5 Varies
Thing Virtual address Physical address Size
Code (and entry point) 20200000 13580000 0x6704
Data (ES vars) 20207000 13587000 0x140
BSS (zero'd) 20208000 13588000 0x2BE08
Stack 2022bd40 ? 0x8000
Protected heap 20208020 ? 0x4000
Open heap 13400000 ? 0x18000

Jun 8 2007 18:17:09

Used by early builds of certain IOS versions. No current version of IOS uses this build.

  • IOS30 prior to v2816 (stubbing)
  • IOS31 prior to v3088
  • IOS33 prior to v2832 (v1040 only)
  • IOS34 prior to v3087 (v1039 only)
  • IOS35 prior to v3088 (v1040 only)
  • IOS36 prior to v3090 (v1042 only)
  • IOS37 prior to v3609 (v2070 only)

This version adds 0x95 DVDLowGetStatusRegister, but 0x96 DVDLowGetControlRegister is still missing. It also allows all 3 ranges in 0x8D DVDLowUnencryptedRead. Finally, it adds all of the IOCtlVs (which are also exposed as IOCtls): 0x90 DVDLowGetNoDiscOpenPartitionParams, 0x91 DVDLowNoDiscOpenPartition, 0x92 DVDLowGetNoDiscBufferSizes, 0x93 DVDLowOpenPartitionWithTmdAndTicket, and 0x94 DVDLowOpenPartitionWithTmdAndTicketView.

This version will issues command 0xE0 to the drive if the error interrupt is set before a command runs, and additionally prints a asecond message if that fails in DiIoctl (which exists in all subsequent versions, even those that do not actually issue a command so it cannot ever fail).

MD5 c808d8b90a74a4ee808b199a1b1e8d53
Thing Virtual address Physical address Size
Code (and entry point) 20200000 139B0000 0x80E0
Data (ES vars) 20209000 139B9000 0x140
BSS (zero'd) 2020A000 139BA000 0x2BDC4
Stack 2022ddc4 ? 0x8000
Protected heap 2020a020 ? 0x4000
Open heap 13600000 ? 0x18000

Jul 11 2008 14:34:27

Used by several IOS builds:

  • IOS37 starting with v2816
  • IOS50 v4889 (v5120 is a stub)
  • IOS51 v4633 (v4864 is a stub)
  • IOS52 v5661 (v5888 is a stub)
  • IOS53 (all versions)
  • IOS55 (all versions)

Adds 0x96 DVDLowGetControlRegister. Removes IOCtlVs 0x90 DVDLowGetNoDiscOpenPartitionParams, 0x91 DVDLowNoDiscOpenPartition, and 0x92 DVDLowGetNoDiscBufferSizes.

MD5 382d4a5cafdb1e28ba039d25db7c4c1f
Thing Virtual address Physical address Size
Code (and entry point) 20200000 139B0000 0x8088
Data (ES vars) 20209000 139B9000 0x140
BSS (zero'd) 2020A000 139BA000 0x2BDC4
Stack 2022ddc4 ? 0x8000
Protected heap 2020a020 ? 0x4000
Open heap 13600000 ? 0x18000

Jul 14 2008 19:25:32

Replaces the Jun 8 build for IOS versions other than IOS37:

  • IOS31 starting with v3088
  • IOS33 starting with v2832
  • IOS34 starting with v3087
  • IOS35 starting with v3088
  • IOS36 starting with v3090

Does not have 0x96 DVDLowGetControlRegister. Also removes IOCtlVs 0x90, 0x91, and 0x92.

MD5 366021c440e6377044f8ca8c94e2e6bc
Thing Virtual address Physical address Size
Code (and entry point) 20200000 139B0000 0x7D74
Data (ES vars) 20208000 139B8000 0x140
BSS (zero'd) 20209000 139B9000 0x2BDC4
Stack 2022cdc4 ? 0x8000
Protected heap 20209020 ? 0x4000
Open heap 13600000 ? 0x18000

Jul 14 2008 19:32:38

Only found in IOS28 (which is the first build that split things into modules). The only difference between the build from 7 minutes earlier is that the open heap is at address 0x13800000 (0x9c << 0x15) instead of address 0x13600000 (0x9b << 0x15). This is a 1-byte difference at offset 920 in the file or at address 202007fc. (There are technically 2 other differences between the versions, for the build date strings.)

MD5 49f714dd1a0985fbd4c44ee9fe4f945a
Thing Virtual address Physical address Size
Code (and entry point) 20200000 139B0000 0x7D74
Data (ES vars) 20208000 139B8000 0x140
BSS (zero'd) 20209000 139B9000 0x2BDC4
Stack 2022cdc4 ? 0x8000
Protected heap 20209020 ? 0x4000
Open heap 13800000 ? 0x18000

Jul 24 2008 00:30:13

Only found in IOS48. Has both 0x95 and 0x96; does not have 0x90, 0x91, and 0x92.

Identical to the Jul 11 2008 14:34:27 build apart from the priority of the main thread being set to 0x1b instead of 0x54 (all versions other than this and Jul 24 2008 20:08:45 use 0x54). This results in byte differences at address 20207f40 (file offset 8068), as well as in some ELF header area (file offset 114), and the timestamps.

MD5 108011e89e557d4e8adf1a02f87cb8ea
Thing Virtual address Physical address Size
Code (and entry point) 20200000 139B0000 0x8088
Data (ES vars) 20209000 139B9000 0x140
BSS (zero'd) 2020A000 139BA000 0x2BDC4
Stack 2022ddc4 ? 0x8000
Protected heap 2020a020 ? 0x4000
Open heap 13600000 ? 0x18000

Jul 24 2008 20:08:45

Only found in IOS38. Has 0x95 but not 0x96; also does not have 0x90, 0x91, and 0x92.

Identical to the Jul 14 2008 19:25:32 build apart from the priority of the main thread being set to 0x1b instead of 0x54 (all versions other than this and Jul 24 2008 00:30:13 use 0x54). This results in byte differences at address 20207c2c (file offset 7d54), as well as in some ELF header area (file offset 114), and the timestamps.

MD5 ef1a8c1270f82e0993f504f1e17a5152
Thing Virtual address Physical address Size
Code (and entry point) 20200000 139B0000 0x7D74
Data (ES vars) 20208000 139B8000 0x140
BSS (zero'd) 20209000 139B9000 0x2BDC4
Stack 2022cdc4 ? 0x8000
Protected heap 20209020 ? 0x4000
Open heap 13600000 ? 0x18000

Nov 24 2008 15:39:09

Used in the first builds of a few IOS versions:

Has both 0x95 and 0x96; does not have 0x90, 0x91, and 0x92.

MD5 48e1be8f767feb59cbc51aa4329d735a
Thing Virtual address Physical address Size
Code (and entry point) 20200000 139B0000 0x7F00
Data (ES vars) 20208000 139B8000 0x140
BSS (zero'd) 20209000 139B9000 0x2BDC4
Stack 2022cdc4 ? 0x8000
Protected heap 20209020 ? 0x4000
Open heap 13600000 ? 0x18000

Dec 24 2008 13:51:06

Used in all versions of IOS41, IOS43, IOS45, and IOS46. Has both 0x95 and 0x96; does not have 0x90, 0x91, and 0x92.

Rebuild with no changes (other than the timestamps) of Jul 11 2008 14:34:27.

MD5 72122c88cdcd4279cc09e197d3079624
Thing Virtual address Physical address Size
Code (and entry point) 20200000 139B0000 0x8088
Data (ES vars) 20209000 139B9000 0x140
BSS (zero'd) 2020A000 139BA000 0x2BDC4
Stack 2022ddc4 ? 0x8000
Protected heap 2020a020 ? 0x4000
Open heap 13600000 ? 0x18000

Jun 3 2009 07:49:09

Used in several IOS versions, and also updated versions of builds that used the Nov 24 2008 version.

  • IOS56 starting with v5405
  • IOS57 starting with v5661
  • IOS61 starting with v5405
  • IOS70 v6687 (v6912 is a stub)
  • IOS80 in all versions
MD5 89f7dc21f07e2cae97c3a571b23d8abd
Thing Virtual address Physical address Size
Code (and entry point) 20200000 139B0000 0x7FF0
Data (ES vars) 20208000 139B8000 0x140
BSS (zero'd) 20209000 139B9000 0x2BDC4
Stack 2022cdc4 ? 0x8000
Protected heap 20209020 ? 0x4000
Open heap 13600000 ? 0x18000

IoctlVs

An incorrect size or alignment, or an incorrect in count or out count, will result in a return value of 0x80. Commands not listed here will cause a hang.

IoctlVs and Ioctls both go to one shared function that actually handles them which takes a diCommand; IoctlV is used when there are multiple pointers being passed to simplify conversion from virtual to physical addresses (which happens on the PPC side in both Nintendo's and libogc's IoctlV function). The IoctlVs will modify the passed diCommand to have additional parameters, noted in yellow. This means that in some cases the Ioctl can be used directly.

0x8B DVDLowOpenPartition

Opens a partition, including verifying it through /dev/es (the resulting error code will be written to the specified location, even if it is 0). DVDLowReadDiskID needs to have been called beforehand.

Returns 0x80 if DVDLowReadDiskID has not been called, or a partition is already open, 0x20 if allocations fail or the partition does not pass some DI security checks (valid cert offset, valid tmd offset, presence of hashes, presense of tmd), and 0x40 for an ES error.

This command will clear the error interrupt if it is set.

Vector
Index Name Direction Size Alignment
0 Command In 0x20 4
1 Ticket (optional) In 0x2a4 if present, not checked if absent (should be 0) 32
2 Shared certs (optional) In Arbitrary if present, not checked if absent (should be 0) 32
3 TMD Out 0x49e4 32
4 ES Error Out 0x20 (of which only the first 4 bytes are used) 4
Command
Offset Type Name
0 u8 Command (0x8B)
4 off_t Partition offset
8 Ticket* Ticket
12 size_t Shared certs size
16 u8* Shared certs
20 TMD* tmd
24 u32* ES error output

0x90 DVDLowGetNoDiscOpenPartitionParams

Dummied out on all current IOS versions; always returns 0x80. However, still usable as an Ioctl (which is probably unintended). System menu 4.3U (among other titles) still has a PPC-side implementation (815504c4) but this is not used (the higher-level function that calls it is gone due to not being referenced).

Vector
Index Name Direction Size Alignment
0 Command In 0x20 4
1 TMD size pointer (not used) In 4 4 (32 on PPC side)
2 Shared certs size pointer (not used) In 4 4 (32 on PPC side)
3 Ticket Out 0x2A4 32
4 TMD size pointer (again; aliases with previous pointer) Out 4 4 (32 on PPC side)
5 TMD Out TMD size, from before (i.e. *vector[4].data) 32
6 Shared certs size pointer (again; aliases with the previous pointer) Out 4 4 (32 on PPC side)
7 Shared certs Out Shared certs size, from before (i.e. *vector[6].data) 32
8 Partition data offset pointer Out 4 4 (32 on PPC side)
9 H3 hashes Out 0x18000 32

After validating sizes and alignments, the params field of the command is set to a stack-allocated structure:

struct nodiscopenparams {
  undefined4 unused1;
  ticket * ticket; // Set to vector[3].data
  undefined4 unused2;
  size_t tmdSize; // Set to *vector[4].data
  tmd * tmd; // Set to vector[5].data
  size_t sharedCertsSize; // Set to *vector[6].data
  byte * sharedCerts; // Set to vector[7].data
  off_t partitionDataOffset; // Set to partitionOffset + partition->dataOffset after working
  h3buffer * h3Hashes; // set to vector[9].data
}

After executing at a lower level (see §0x90 DVDLowGetNoDiscOpenPartitionParams ioctl), tmdSize, sharedCertsSize, and partitionDataOffset are written back to vectors 4, 6, and 8 respectively. (If an error occurs, all three are instead set to 0.)

Command
Offset Type Name
0 u8 Command (0x90)
4 off_t Partition position (>> 2)
8 nodiscopenparams* params

0x91 DVDLowNoDiscOpenPartition

Dummied out on all current IOS versions; always returns 0x80. However, still usable as an Ioctl (which is probably unintended).

Presumably, the ioctlv would have validated size and alignment, and then filled in additional parameters on the command before passing it on to the shared logic that it is still accessible via the ioctlv. However, no PPC-side code exists so the exact ioctlv arguments are unknown.

Vector
Index Name Direction Size Alignment
0 Command In 0x20 4
1 Ticket In 0x2a4 32
2 TMD In Not checked 32
3 Shared certs In Not checked 32
4 H3 hashes In 0x18000 32
5 ES Error Out 4 (properly sized, unlike with regular open partition) 4

After validating sizes and alignments, the params field of the command is set to a stack-allocated structure:

struct nodiscopenparams {
  undefined4 unused1;
  ticket * ticket; // Set to vector[1].data
  undefined4 unused2;
  size_t tmdSize; // Set to vector[2].size
  tmd * tmd; // Set to vector[2].data
  size_t sharedCertsSize; // Set to vector[3].size
  byte * sharedCerts; // Set to vector[3].data
  off_t partitionDataOffset; // Set by command
  h3buffer * h3Hashes; // set to vector[4].data
}


Command
Offset Type Name
0 u8 Command (0x91)
4 off_t Partition data offset
4 nodiscopenparams* params
8 u32 * ES error output (vector[5].data)

0x92 DVDLowGetNoDiscBufferSizes

Dummied out on all current IOS versions; always returns 0x80. However, still usable as an Ioctl (which is probably unintended). System menu 4.3U (among other titles) still has a PPC-side implementation (815502b8) but this is not used (the higher-level function that calls it is gone due to not being referenced). This does allow determination of the inputs, though:

Vector
Index Name Direction Size Alignment
0 Command In 0x20 4
1 TMD size pointer Out 4 4 (32 on ppc side)
2 Shared certs size pointer Out 4 4 (32 on ppc side)

Both pointers must be non-zero. The ioctlv fills in additional parameters on the command.

Command
Offset Type Name
0 u8 Command (0x92)
4 off_t Partition position (>> 2)
8 u32 * TMD Size out
12 u32 * Cert Chain Size Out

0x93 DVDLowOpenPartitionWithTmdAndTicket

Opens a partition, including verifying it through /dev/es (the resulting error code will be written to the specified location, even if it is 0). DVDLowReadDiskID needs to have been called beforehand. This function takes an already-read TMD and can take an already-read ticket, which means it can be faster since the ticket does not need to be read from the disc.

Returns 0x80 if DVDLowReadDiskID has not been called, or a partition is already open, 0x20 if allocations fail or the partition does not pass some DI security checks (valid cert offset, valid tmd offset, presence of hashes), and 0x40 for an ES error.

This command will clear the error interrupt if it is set.

Vector
Index Name Direction Size Alignment
0 Command In 0x20 4
1 Ticket (optional) In 0x2a4 if present, not checked if absent (should be 0) 32
2 TMD (required) In Arbitrary 32
3 Shared certs (optional) In Arbitrary 32
4 ES Error Out 0x20 (of which only the first 4 bytes are used) 4
Command
Offset Type Name
0 u8 Command (0x93)
4 off_t Partition offset
4 runopenpartparam* params
8 u32 * ES error output

After running, the first argument is a pointer to a (stack-allocated) structure used by this and 0x94:

struct runopenpartparam {
  off_t position;
  ticket * ticket; // Only used by 0x93
  ticketview * ticketview; // Only used by 0x94
  size_t tmdSize;
  tmd * tmd;
  size_t sharedCertsSize;
  u8 * sharedCerts;
}

0x94 DVDLowOpenPartitionWithTmdAndTicketView

Opens a partition, including verifying it through /dev/es (the resulting error code will be written to the specified location, even if it is 0). DVDLowReadDiskID needs to have been called beforehand. This function takes an already-read TMD and can take an already-read ticket ticket view, which means it can be faster since the ticket does not need to be read from the disc.

Returns 0x80 if DVDLowReadDiskID has not been called, or a partition is already open, 0x20 if allocations fail or the partition does not pass some DI security checks (valid cert offset, valid tmd offset, presence of hashes), and 0x40 for an ES error.

This command will clear the error interrupt if it is set.

Vector
Index Name Direction Size Alignment
0 Command In 0x20 4
1 Ticket View (optional) In 0x98 if present, not checked if absent (should be 0) 32
2 TMD (required) In Arbitrary 32
3 Shared certs (optional) In Arbitrary 32
4 ES Error Out 0x20 (of which only the first 4 bytes are used) 4
Command
Offset Type Name
0 u8 Command (0x94)
4 off_t Partition offset
4 runopenpartparam* params (see above)
8 u32 * ES error output

Ioctls

Using a number not listed here results in a return value of 0x80. The input buffer must be sized 0x20 (except for command 0x8E). Unless otherwise noted, commands return 1 on success.

Ioctls are implemented in two functions: DiIoctl and handleDiCommand. handleDiCommand is actually also used by IoctlV as well, and other than for DVDLowOpenPartition, IoctlV commands are accidentally exposed as Ioctls as well. The following commands are implemented in DiIoctl:

Commands implemented in DiIoctl
  • 0x79 DVDLowWaitForCoverClose
  • 0x7A DVDLowGetCoverRegister
  • 0x83 DVDLowGetLength
  • 0x84 Get DIIMMBUF
  • 0x85 DVDLowUnmaskCoverInterrupt
  • 0x86 DVDLowClearCoverInterrupt
  • 0x87
  • 0x88 DVDLowGetCoverStatus
  • 0x89 Enable Cover Interrupt
  • 0x8B DVDLowOpenPartition ioctl
  • 0x8E DVDLowEnableDvdVideo
  • 0x95 DVDLowGetStatusRegister
  • 0x96 DVDLowGetControlRegister

Commands will clear the error interrupt by writing bit 2 of DISR if it is set after execution. Furthermore, the same check happens before execution, but this should generally not happen barring other code directly writing to the DI registers (a warning is logged in this case). These checks happen in handleDiCommand, so commands implemented in DiIoctl are not affected; additionally the second check is skipped for 0x8A DVDLowReset and 0xE0 DVDLowRequestError. In some versions, the second check will also issue a request error command to the drive (which, as a side effect, clears the error in the drive itself, which would break a second DVDLowRequestError — that explains why it is skipped).

If an output buffer size check fails, DIMAR and DILENGTH will not be written, and there is code that sets the return value to 0x20. However, the driver still attempts to start the transfer, which will fail due to not writing DILENGTH (which should have counted back down 0 after any previous successful transfer[check]); this will result in an eventual timeout and returning of 0x10[check].

0x12 DVDLowInquiry

Retrieves information about the drive verison; see yagcd §5.7.3.1 for more info.

The output buffer size must be ≥ 0x20, or DIMAR and DILENGTH will not be written. It must also be 32-bit aligned, or else the driver will hang.

Note that YAGCD is incorrect and there is actually one additional byte after the drive date, apparently indicating the version. This is not new to the Wii.

DICMDBUF0 = 0x12000000
DILENGTH = 0x20
DIMAR = outbuf
DICMDBUF1 = 0
DICR = TSTART | DMA
Command
Offset Type Name
0 u8 Command (0x12)

0x70 DVDLowReadDiskID

Reads the current disc ID and initializes the drive. Many other commands will not work before this (either by explicitly checking, or due to the drive returning error 0x05xxxxxx).

This command cannot be used while the drive interface is resetting (if syscall 0x46 syscall_check_di_reset returns true); in which case it will return 0x80. 0x80 will also be returned if the output buffer is not 32-byte aligned.

The output buffer size must be ≥ 0x20, or DIMAR and DILENGTH will not be written.

DICMDBUF0 = 0xA8000040
DICMDBUF1 = 0
DICMDBUF2 = 0x20
DILENGTH = 0x20
DIMAR = dest
DICR = TSTART | DMA
Command
Offset Type Name
0 u8 Command (0x70)

After this command has finished reading, the driver will also look at the 4 bytes at offset 0x18 in the output (i.e. outbuf[6] if outbuf is a u32 array) for the Wii magicword 0x5D1C9EA3 to determine if it is a Wii disc. If it is a Wii disc, and it has not already read it, it will read 0x44 (padded to 0x60) bytes starting at byte 0x20 (i.e. the game title, and the disable hashing and disable encryption flags). Thus, after the first call, DVDLowGetLength will return 0x60, and on later calls it will return 0x20.

0x71 DVDLowRead

Reads and decrypts disc data. This command can only be used if hashing and encryption are enabled for the disc. DVDLowOpenPartition needs to have been called before for the keys to be read.

The output buffer has no requirements on alignment, but will perform better if 32-byte aligned since it can avoid a copy from a buffer within the driver. Similarly, the offset and size can be any value, but ones that are sector-aligned (sizes that are multiples of 0x7C00 and offsets that are multiples of 0x1F00) avoid copies for the first and/or last sector that needs to be read and decrypted. Each individual sector is read using command 0xA8.

This command immediately returns 0x20 if the buffer is too small, and also returns 0x20 if something went wrong with decryption or hashing and 2 for a drive error.

If everything completed successfully, the last length value used by DVDLowGetLength is set to offset (almost certainly a mistake on Nintendo's end). Otherwise, it is set to 0.

Command
Offset Type Name
0 u8 Command (0x71)
4 size_t Size (bytes)
8 off_t Offset (bytes >> 2)

0x79 DVDLowWaitForCoverClose

Waits for a disc to be inserted; if there is already a disc inserted, it must be removed first. This command does not time out; if no disc is inserted, it will wait forever. (As such, I'm not entirely sure how it can be cancelled; I assume but have not checked that the Wii Fit Channel uses this when waiting for the Wii Fit disc to be inserted, but that can be canceled...)

Continuously waits for a DI interrupt, and when it receives one it checks for the cover interrupt (bit 2 of DICVR); if it is set it then checks if the cover is closed (bit 0 of DICVR) and if sufficient time has ellapsed. It also clears the TC and error interrupts should they occur.

The output buffer is not used, and it may be null. Its size is not checked.

On completion, returns 0x4.

Command
Offset Type Name
0 u8 Command (0x79)

0x7A DVDLowGetCoverRegister

Stores the current value of DICVR into outbuf, which must be at least 4 bytes in size (or else 0x20 is returned). Note that Nintendo titles also refer to this as DVDLowPrepareCoverRegister, but that function simply asynchronously reads it into game memory so that it can be accessed by a separate function later. (A similar name pattern is found for the other get-reg commands.)

Command
Offset Type Name
0 u8 Command (0x7A)

0x7E DVDLowNotifyReset

Resets internal flags, closes the open partition (if there is one), clears the transfer complete interrupt and drive error interrupt, enables the transfer complete interrupt and error interrupt, and disables the cover interrupt.

Command
Offset Type Name
0 u8 Command (0x7E)

0x7F DVDLowSetSpinupFlag

Prints the message "(handleDiCommand) DI_SET_SPINUP_FLAG_CMD should have been executed in the PPC shim layer only" and returns 0x80.

The PPC-side simply stores a boolean which is later used as the parameter to DVDLowReset. For some reason, Nintendo decided to give it an ioctl number as well, even though it didn't need one.

Command
Offset Type Name
0 u8 Command (0x7F)

0x80 DVDLowReadDvdPhysical

Probably related to DVD-Video[check].

The output buffer size must be ≥ 0x800, or DIMAR and DILENGTH will not be written. The output buffer also needs to be 32-byte aligned, or else the driver will hang.

DICMDBUF0 = 0xAD000000 | (position << 8) // AD00XX00
DICMDBUF1 = 0
DICMDBUF2 = 0
DILENGTH = 0x800
DIMAR = dest
DICR = TSTART | DMA
Command
Offset Type Name
0 u8 Command (0x80)
7 u8 Position(?)

0x81 DVDLowReadDvdCopyright

Probably related to DVD-Video[check].

DICMDBUF0 = 0xAD010000 | (position << 8) // AD01XX00
DICMDBUF1 = 0
DICMDBUF2 = 0
DICR = TSTART

The contents of DIIMMBUF (u32) are written to the output buffer. The output buffer size is not checked, but 4 would be a sane value.

Command
Offset Type Name
0 u8 Command (0x81)
7 u8 Position(?)

0x82 DVDLowReadDvdDiscKey

Probably related to DVD-Video[check].

The output buffer size must be ≥ 0x800, or DIMAR and DILENGTH will not be written. The output buffer also needs to be 32-byte aligned, or else the driver will hang.

DICMDBUF0 = 0xAD020000 | (position << 8) // AD02XX00
DICMDBUF1 = 0
DICMDBUF2 = 0
DILENGTH = 0x800
DIMAR = dest
DICR = TSTART | DMA
Command
Offset Type Name
0 u8 Command (0x82)
7 u8 Position(?)

0x83 DVDLowGetLength

Stores the last DILENGTH value into outbuf, which must be at least 4 bytes in size (or else 0x20 is returned). Note that this doesn't directly read DILENGTH, but rather a separate value that is set when DILENGTH is set (and zero'd if a read error occurs on a command that uses DILENGTH; this means that this command cannot be used to get the amount of data still left to be transfered when the error happened).

Command
Offset Type Name
0 u8 Command (0x83)

0x84 Get DIIMMBUF

Stores the current value of DIIMMBUF into outbuf, which must be at least 4 bytes in size (or else 0x20 is returned).

Command
Offset Type Name
0 u8 Command (0x83)

0x85 DVDLowUnmaskCoverInterrupt

Disables the cover interrupt by clearing bit 1 of DICVR (leaving bit zero unchanged). Does not clear the cover interrupt if it is currently asserted (does not write bit 2).

The output buffer is not used, and it may be null. Its size is not checked.

Command
Offset Type Name
0 u8 Command (0x85)

0x86 DVDLowClearCoverInterrupt

Clears the cover interrupt by writing bit 2 of DICVR (leaving the other bits unchanged).

The output buffer is not used, and it may be null. Its size is not checked.

Command
Offset Type Name
0 u8 Command (0x86)

0x87

Dummied out; does nothing (and always returns 1). Possibly an ID reserved for a PPC-only command (DVDLowBreak?), as is also done with DVDLowSetSpinupFlag?

The output buffer is not used, and it may be null. Its size is not checked.

Command
Offset Type Name
0 u8 Command (0x87)

0x88 DVDLowGetCoverStatus

Checks the current cover status and stores the result into outbuf, which must be at least 4 bytes in size (or else 0x20 is returned).

The result is 0 right after a reset[check], 1 if a disc is not inserted (bit 1 of DICVR set), and 2 if a disc is inserted (bit 1 of DICVR not set).

Command
Offset Type Name
0 u8 Command (0x88)

0x89 Enable Cover Interrupt

Enables the cover interrupt by setting bit 1 of DICVR (leaving bit zero unchanged). Does not clear the cover interrupt if it is currently asserted (does not write bit 2).

The output buffer is not used, and it may be null. Its size is not checked.

Command
Offset Type Name
0 u8 Command (0x89)

0x8A DVDLowReset

Resets the drive, using syscalls 0x44, 0x45, and 0x46. If a reset is already in progress (syscall_check_di_reset returns true), then it immediately calls syscall_deassert_di_reset; otherwise, it calls syscall_assert_di_reset, waits 12µs, and then calls syscall_deassert_di_reset. Afterwards, registers are reset in the same way as DVDLowNotifyReset other than the cover interrupt. The cover interrupt is temporarilly disabled during this process, but is reenabled afterwards if it was enabled before.

Enable spinup is passed to syscall 0x4e, which activates the DI_SPIN GPIO if it is 0 and disables it otherwise.

The output buffer is not used, and it may be null. Its size is not checked.

Command
Offset Type Name
0 u8 Command (0x8A)
4 u32 Enable spinup

0x8B DVDLowOpenPartition ioctl

Returns 0x20 and prints a warning that "OPEN_PARTITION done through Ioctlv, not Ioctl".

The output buffer is not used, and it may be null. Its size is not checked.

Command
Offset Type Name
0 u8 Command (0x8B)

0x8C DVDLowClosePartition

Closes the currently-open partition, removing information about its keys and such.

The output buffer is not used, and it may be null. Its size is not checked.

Command
Offset Type Name
0 u8 Command (0x8C)

0x8D DVDLowUnencryptedRead

Reads raw data from the disc. Only usable in the "System Area" of the disc. The start and end must lie within a single one of the following ranges or else 0x20 is returned:

Ranges
Start (offset) Start (bytes) Length (offset) Length (bytes) End (offset) End (bytes)
0 0 0x14000 0x50000 0x14000 0x50000
0x460A0000 0x118280000 8 0x20 0x460A0008 0x118280020
0x7ED40000 0x1FB500000 8 0x20 0x7ED40008 0x1FB500020

The output buffer must be 32-byte aligned and the length must also be a multiple of 32; otherwise, 0x80 is returned.

The output buffer size must be ≥ length, or DIMAR and DILENGTH will not be written.

DICMDBUF0 = 0xA8000000
DICMDBUF1 = position
DICMDBUF2 = length
DILENGTH = length
DIMAR = dest
DICR = TSTART|DMA

Versions of IOS prior to IOS30 only permitted reads in the first range[check]. Nintendo titles check on startup if they are running an IOS ≥ 30 (and ≤ 253) and if so, perform some DI checks; specifically, they attempt to read 0x20 bytes from 0x460a0000 (or from 0x7ed40000 if the byte at 0x8000319c is 0x81 — possibly related to dual-layer discs?). If this read attempt returns anything other than 2, the game will refuse to start with the message "An error has occurred. Press the Eject Button, remove the Game Disc, and turn off the power to the console. Please read the Wii Operations Manual for further instructions." If the drive error is anything other than 0x0052100 (OK/Logical block address out of range), the game will refuse to start with the message "Error #001, unauthorized device has been detected."

Command
Offset Type Name
0 u8 Command (0x8D)
4 size_t Length (bytes)
8 off_t Position (>> 2)

0xA8 Unchecked Unencrypted Read

DVDLowUnencryptedRead without any restrictions on the regions it can be used; internal use only. Attempting to use this from IOS_Ioctl will result in return 0x20. Otherwise idential to DVDLowUnencryptedRead, including the alignment and size checks.

0x8E DVDLowEnableDvdVideo

Can only be called by uid[check] 0. The restrictions on inbuf are different: it only needs to have a size of at least 1. If the value is 0, performs syscall 0x50 with true as the parameter; otherwise, false is the parameter. (Syscall 0x50 takes disable as a parameter, while this takes enable).

If the uid is incorrect or inbuf is size 0, returns 0x20.

Inbuf
Offset Type Name
0 bool Enable

0x90 DVDLowGetNoDiscOpenPartitionParams ioctl

Prepares an argument for use with DVDLowNoDiscOpenPartition. There is some overlap between this structure and runopenpartparam; they may actually be the same structure. A disc needs to be inserted and DVDLowReadDiscID must have been called for this to actually be used.

No other alignment, size, or pointer target validation happens when using the ioctl. Presumably, this would have happened in the ioctlv.

Returns 0x80 if DVDLowReadDiscID has not been called or the tmdSize or sharedCertsSize is too small, and 0x20 if the partition's tmd offset or cert chain is 0, or if the disc has encryption enabled but is not encryped.

struct nodiscopenparams {
  undefined4 unused1;
  ticket * ticket; // Must be set; size 0x2a4
  undefined4 unused2;
  size_t tmdSize; // Must be set
  tmd * tmd; // Pointer to a buffer of size tmdSize
  size_t sharedCertsSize; // Must be set
  byte * sharedCerts; // Pointer to a buffer of size sharedCertsSize
  off_t partitionDataOffset; // Set to partitionOffset + partition->dataOffset
  h3buffer * h3Hashes; // Must be set; 0x18000
}

The output buffer is not used, and it may be null. Its size is not checked.

Command
Offset Type Name
0 u8 Command (0x90)
4 off_t Partition position (>> 2)
8 nodiscopenparams* params

0x91 DVDLowNoDiscOpenPartition ioctl

Opens/checks a partition on a disc, using data that was read from the disc earlier and without reading anything new from the disc. (Presumably, this would have been used to speed up startup times, though it isn't usable as-is.)

The output buffer is not used, and it may be null. Its size is not checked.

Returns 0x80 if a partition is already open, 0x40 if /dev/es does not accept the output, and 0x20 if H3 hash verification failed. The resulting es error code will be written to the specified location, even if it is 0.

Command
Offset Type Name
0 u8 Command (0x91)
4 nodiscopenparams* params
8 u32 * ES error output

0x92 DVDLowGetNoDiscBufferSizes ioctl

Gets the values needed for tmdSize and sharedCertsSize. A disc needs to be inserted and DVDLowReadDiscID must have been called for this to actually be used.

No other alignment, size, or pointer target validation happens when using the ioctl. Presumably, this would have happened in the ioctlv.

The output buffer is not used, and it may be null. Its size is not checked.

Returns 0x80 if DVDLowReadDiscID has not been called, and 0x20 if the partition's tmd offset or cert chain is 0, or if the disc has encryption enabled but is not encryped.

Command
Offset Type Name
0 u8 Command (0x92)
4 off_t Partition position (>> 2)
8 u32 * TMD Size out
12 u32 * Cert Chain Size Out

0x93 DVDLowOpenPartitionWithTmdAndTicket ioctl

Should behave identically to the ioctlv, as long as pointers are properly translated (when using ioctl, it does not know to translate random pointers in the inbuf, nor does it know to check them). Using the ioctl bypasses the size and alignment validation that happens in the ioctlv.

Command
Offset Type Name
0 u8 Command (0x93)
4 runopenpartparam* params
8 u32 * ES error output

0x94 DVDLowOpenPartitionWithTmdAndTicketView ioctl

Should behave identically to the ioctlv, as long as pointers are properly translated (when using ioctl, it does not know to translate random pointers in the inbuf, nor does it know to check them). Using the ioctl bypasses the size and alignment validation that happens in the ioctlv.

Command
Offset Type Name
0 u8 Command (0x93)
4 runopenpartparam* params
8 u32 * ES error output

0x95 DVDLowGetStatusRegister

Stores the current value of DISR into outbuf, which must be at least 4 bytes in size (or else 0x20 is returned).

Command
Offset Type Name
0 u8 Command (0x95)

0x96 DVDLowGetControlRegister

Stores the current value of DICR into outbuf, which must be at least 4 bytes in size (or else 0x20 is returned).

Command
Offset Type Name
0 u8 Command (0x96)

0xA4 DVDLowReportKey

Original purpose unknown. Does not work on retail drives.

Nintendo titles send this after performing the off-disc DVDLowUnencryptedRead check to verify that they are on official hardware; specifically, the first parameter is set to 4 (internally, 0x40000 >> 16) and the second parameter is set to 0. If this call returns anything other than 2, the "An error has occurred" message will be shown. If the drive error is anything other than 0x0053100 (OK/Invalid Request Medium Format Corrupted) or 0x0052000 (OK/Invalid command operation code), the "Error #001" message will be shown.

The output buffer size must be ≥ 0x20, or DIMAR and DILENGTH will not be written. The output buffer also needs to be 32-byte aligned, or else the driver will hang.

DICMDBUF0 = 0xA4000000 | (param1 << 16) // A4XX0000
DICMDBUF1 = param2 & 0xFFFFFF
DICMDBUF2 = 0
DILENGTH = 0x20
DIMAR = dest
DICR = TSTART | DMA
Command
Offset Type Name
0 u8 Command (0xA4)
7 u8 param1
8 u32 param2

0xAB DVDLowSeek

Seeks to the sector containing a specific position on the disc.

The output buffer is not used, and it may be null. Its size is not checked.

if (encryptionEnabled) {
 sectorNum = position / 0x1F00
 start = partitionOffset + sectorNum * 0x2000
} else {
 start = partitionOffset + position
}

DICMDBUF0 = 0xab000000
DICMDBUF1 = start
DICR = TSTART
Command
Offset Type Name
0 u8 Command (0xAB)
4 off_t Position (>> 2)

0xD0 DVDLowReadDvd

Probably related to DVD-Video[check].

The output buffer size must be ≥ 0x800 * length, or DIMAR and DILENGTH will not be written. The output buffer also needs to be 32-byte aligned, or else the driver will hang.

DICMDBUF0 = 0xD0000000 | ((flag1 & 1) << 7) | ((flag2 & 1) << 6) // D00000C0, D0000080, D0000040, D0000000
DICMDBUF1 = position & 0xFFFFFF
DICMDBUF2 = length & 0xFFFFFF
DILENGTH = 0x800 * length
DIMAR = dest
DICR = TSTART | DMA
Command
Offset Type Name
0 u8 Command (0xD0)
7 bool Flag1
11 bool Flag2
12 size_t Length?
16 off_t Position?

0xD1 DVDLowReadDvdConfig

Probably related to DVD-Video[check].

The contents of DIIMMBUF (u32) are written to the output buffer. The output buffer size is not checked, but 4 would be a sane value.

DICMDBUF0 = 0xD1000000 | ((flag1 & 1) << 16) | param2 // D10000XX, D10100XX
DICMDBUF1 = position & 0xFFFFFF
DICMDBUF2 = 0
DICR = TSTART
Command
Offset Type Name
0 u8 Command (0xD1)
7 bool Flag1
11 u8 Param2
12 off_t Position?

0xD2 DVDLowStopLaser

Disables the laser.

The contents of DIIMMBUF (u32) are written to the output buffer. The output buffer size is not checked, but 4 would be a sane value.

DICMDBUF0 = 0xD2000000
DICR = TSTART
Command
Offset Type Name
0 u8 Command (0xD2)

0xD9 DVDLowOffset

Unknown. The offset(?) provided is stored by the driver, but isn't read.

The contents of DIIMMBUF (u32) are written to the output buffer. The output buffer size is not checked, but 4 would be a sane value.

DICMDBUF0 = 0xD9000000 | ((flag & 1) << 16) // 0xD9000000, 0xD9010000
DICMDBUF1 = offset
DICR = TSTART
Command
Offset Type Name
0 u8 Command (0xD9)
7 bool flag
8 off_t Offset?

0xDA DVDLowReadDiskBca

Reads the last 0x40 bytes of the burst cutting area. Note that the actual BCA is 188 (0xBC) bytes long; the area returned by this command is mostly 0'd except for the last 12 bytes (except for New Super Mario Bros. Wii, which also has a 1 byte before those 12 bytes, which the game checks for as some kind of copy protection it seems).

The output buffer size must be ≥ 0x40, or DIMAR and DILENGTH will not be written. The output buffer also needs to be 32-byte aligned, or else the driver will hang.

DICMDBUF0 = 0xDA000000
DILENGTH = 0x40
DIMAR = dest
DICR = TSTART | DMA
Command
Offset Type Name
0 u8 Command (0xDA)

0xDB DVDLowRequestDiscStatus

Unknown[check].

The contents of DIIMMBUF (u32) are written to the output buffer. The output buffer size is not checked, but 4 would be a sane value.

DICMDBUF0 = 0xDB000000
DICR = TSTART
Command
Offset Type Name
0 u8 Command (0xDB)

0xDC DVDLowRequestRetryNumber

Unknown[check].

The contents of DIIMMBUF (u32) are written to the output buffer. The output buffer size is not checked, but 4 would be a sane value.

DICMDBUF0 = 0xDC000000
DICR = TSTART
Command
Offset Type Name
0 u8 Command (0xDC)

0xDD DVDLowSetMaximumRotation

Sets the maximum rotation speed, allegedly[check]? Does not actually seem to have any impact on the speed of the drive (based on the sound it makes; Gamecube games continue to make one sound and Wii games continue to make a faster sound, regardless of the value used).

Using a speed of 3 will result in the drive erroring with code 0x052400 (Invalid Field in command packet) and the ioctl returning 2.

Nintendo's wrapper code internally shifts its parameter down by 16 (so titles pass 0x20000 and the ioctl uses 2). It looks like titles also only ever use the speed of 2[check] (the higher-level DVDDownRotationAsync only uses speed 2, and the other calls that happen in the drive reset handler also only use 2 — though they also only happen when the value at 800030e6 is 0x8003, apparently tied to the device code returned from inquiry or'd with 0x8000, and my drive has a device code of 2).

The output buffer is not used, and it may be null. Its size is not checked.

DICMDBUF0 = 0xDD000000 | ((speed & 3) << 16) // DD000000, DD010000, DD020000, DD030000
DICR = TSTART
Command
Offset Type Name
0 u8 Command (0xDD)
7 u8 Speed

0xDF DVDLowSerMeasControl

Unknown[check]. Possibly "sensor measurement control" or "servo measurement control".

The output buffer size must be ≥ 0x20, or DIMAR and DILENGTH will not be written. The output buffer also needs to be 32-byte aligned, or else the driver will hang.

DICMDBUF0 = 0xDF000000 | ((flag1 & 1) << 17) | ((flag2 & 1) << 16) // DF030000, DF010000, DF020000, DF000000
DILENGTH = 0x20
DIMAR = dest
DICR = TSTART | DMA
Command
Offset Type Name
0 u8 Command (0xDF)
7 bool Flag1
11 bool Flag2

0xE0 DVDLowRequestError

Reads the current drive error. Does not clear the error interrupt.

The contents of DIIMMBUF (u32) are written to the output buffer. The output buffer size is not checked, but 4 would be a sane value.

See yagcd §5.7.3.5 for a partial list of error codes. Byte 4 is as described in yagcd. The 3rd byte an SCSI Sense Key, and bytes 2 and 1 are SCSI ASC/ASCQ.

DICMDBUF0 = 0xE0000000
DICR = TSTART
Command
Offset Type Name
0 u8 Command (0xE0)

0xE1 DVDLowAudioStream

Plays an audio stream, according to yagcd §5.7.1 and this article. The audio stream is played through the Audio Interface. Audio is not decrypted, making this command useless for Wii games.

The output buffer is not used, and it may be null. Its size is not checked.

DICMDBUF0 = 0xE1000000 | ((mode & 3) << 16) // E1000000, E1010000, E1020000, E1030000
DICMDBUF1 = position
DICMDBUF2 = length
DICR = TSTART

Modes:

  • 0 → Wait for the current stream to finish before starting the new one (if present)
  • 1 → Immediately stop the current stream. The parameters are ignored (and will not be reflected by 0xE2).
  • 2 → Invalid, fails with error 0x052401 (invalid audio command) and returns 2
  • 3 → Invalid, fails with error 0x052401 (invalid audio command) and returns 2

If length and position are both 0, then audio streaming stops.

Command
Offset Type Name
0 u8 Command (0xE1)
7 u8 Mode
8 size_t Length
12 off_t Position

0xE2 DVDLowRequestAudioStatus

Requests information about an audio stream, according to yagcd §5.7.1 and this article.

The output buffer is not used, and it may be null. Its size is not checked. This is somewhat odd, as the response is put into into DIIMMBUF.

DICMDBUF0 = 0xE2000000 | ((request & 3) << 16) // E2000000, E2010000, E2020000, E2030000
DICMDBUF1 = 0
DICR = TSTART

Requests:

  • 0 → Is stream playing (sets DIIMMBUF to 0 or 1)
  • 1 → Current playback address (sets DIIMMBUF to current location, with sector-level granularity, and as a 32-bit offset; the result is always a multiple of 0x2000)
  • 2 → Playback start address (sets DIIMBUF to the value previously configured from play audio stream)
  • 3 → Playback length (sets DIIMBUF to the value previously configured from play audio stream)
Command
Offset Type Name
0 u8 Command (0xE2)
7 u8 Request

0xE3 DVDLowStopMotor

Stops the motor. The motor can be re-activated by performing a reset with spinup enabled.

If the eject flag is set, the disc will be ejected after the motor is stopped. The kill flag is odder; from libogc:

Warning, this will kill your drive untill the next reset. Will not respond to DI commands, will not take in or eject the disc. Your drive will be d - e - d, dead.

I deem this function to be harmless, as normal operation will resume after a reset. However, I am not liable for anyones drive exploding as a result from using this function.

The contents of DIIMMBUF (u32) are written to the output buffer. The output buffer size is not checked, but 4 would be a sane value.

DICMDBUF0 = 0xE3000000 | ((eject & 1) << 17) | ((kill & 1) << 20) // E3120000, E3020000, E3100000, E3000000
DICMDBUF1 = 0
DICR = TSTART
Command
Offset Type Name
0 u8 Command (0xE3)
7 bool Eject
11 bool Kill

0xE4 DVDLowAudioBufferConfig

Audio buffer configuration.

The contents of DIIMMBUF (u32) are written to the output buffer. The output buffer size is not checked, but 4 would be a sane value.

DICMDBUF0 = 0xE4000000 | ((enable & 1) << 16) | (bufSize & 0xf) // E401000X, E400000X
DICMDBUF1 = 0
DICR = TSTART

The system menu issues this for Gamecube games based off of the audio streaming and streaming buffer size fields in the Wii Disc header; byte 8 indicates whether or not it is enabled and byte 9 indicates the buffer size (defaulting to 10 if set to 0 while streaming is enabled).

This command can only be issued immediately after reading the disc ID; calls before that will return 0x05020401 (Disk ID not read) and calls after a read will error with 0x052402 (Configuration out of permitted period). Since DVDLowReadDiskID does an additional read for Wii discs, this command cannot be used on a Wii disc. Bypassing /dev/di and manually writing the DI registers does allow the other commands to be used.

Command
Offset Type Name
0 u8 Command (0xE4)
7 bool Enable DVD audio
11 u8 Streaming buffer size