Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion arch/m68k-amiga/devs/cd/cd.conf
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
##begin config
basename cd
version 40.3
version 40.4
libbasetype struct cdBase
residentpri 5
beginio_func BeginIO
Expand Down
39 changes: 23 additions & 16 deletions arch/m68k-amiga/devs/cd/cd32.c
Original file line number Diff line number Diff line change
Expand Up @@ -1522,24 +1522,31 @@ static LONG CD32_DoIO(struct IOStdReq *io, APTR priv)
}
break;
case CD_PLAYTRACK:
if (io->io_Length == 0) {
err = CDERR_BADLENGTH;
} else if (io->io_Offset <= cu->cu_CDTOC[0].Summary.LastTrack) {
ULONG start;
ULONG end;
ULONG last = io->io_Offset + io->io_Length;

start = bcdmsf2sec(&cu->cu_CDTOC[io->io_Offset].Entry.Position.MSF);
if (last > cu->cu_CDTOC[0].Summary.LastTrack) {
end = bcdmsf2sec(&cu->cu_CDTOC[0].Summary.LeadOut.MSF);
} else {
end = bcdmsf2sec(&cu->cu_CDTOC[last].Entry.Position.MSF);
{
/* CD32 Kickstart consumes word-sized track arguments. Legacy
* callers may initialise only the low words of these fields. */
UWORD track = (UWORD)io->io_Offset;
UWORD count = (UWORD)io->io_Length;

if (count == 0) {
err = CDERR_BADLENGTH;
} else if (track <= cu->cu_CDTOC[0].Summary.LastTrack) {
ULONG start;
ULONG end;
ULONG last = (ULONG)track + count;

start = bcdmsf2sec(&cu->cu_CDTOC[track].Entry.Position.MSF);
if (last > cu->cu_CDTOC[0].Summary.LastTrack) {
end = bcdmsf2sec(&cu->cu_CDTOC[0].Summary.LeadOut.MSF);
} else {
end = bcdmsf2sec(&cu->cu_CDTOC[last].Entry.Position.MSF);
}
err = end > start ?
CD32_StartPlay(cu, io, start, end - start) :
CDERR_BADLENGTH;
}
err = end > start ?
CD32_StartPlay(cu, io, start, end - start) :
CDERR_BADLENGTH;
break;
}
break;
case CD_PLAYMSF:
{
union LSNMSF start, length;
Expand Down
4 changes: 2 additions & 2 deletions arch/m68k-amiga/devs/cd/mmakefile.src
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ FILES := cd cd32
# Native CD32 regressions belong to the CD device component.
#MM- test-amiga-m68k : test-devices-cd-amiga-m68k
#MM- test-amiga-m68k-quick : test-devices-cd-amiga-m68k-quick
#MM- test-devices-cd-amiga-m68k : test-devices-cdpause
#MM- test-devices-cd-amiga-m68k-quick : test-devices-cdpause-quick
#MM- test-devices-cd-amiga-m68k : test-devices-cdpause test-devices-cdplaytrack
#MM- test-devices-cd-amiga-m68k-quick : test-devices-cdpause-quick test-devices-cdplaytrack-quick

#USER_CPPFLAGS += -DDEBUG=1

Expand Down
24 changes: 24 additions & 0 deletions developer/debug/test/devices/cdplaytrack/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
Copyright (C) 2026, The AROS Development Team. All rights reserved.

Build test-devices-cdplaytrack or test-devices-cdplaytrack-quick. The native Amiga CD
device test group selects this regression. Run devices/cdplaytrack/cdplaytracktest
with an audio track numbered 2 present. The test checks ordinary and
upper-word-contaminated track/count fields, asynchronous playback, CD_INFO,
and rejection of counts whose low word is zero.

A disposable fixture can be generated from the repository root:

python3 developer/debug/test/devices/cd/readahead/make_disc.py /tmp/cd-word-data.iso
python3 - <<'PYTHON'
from pathlib import Path
Path('/tmp/cd-word-audio.bin').write_bytes(bytes(2352 * 75 * 20))
Path('/tmp/cd-word.cue').write_text(
'FILE "cd-word-data.iso" BINARY\n'
' TRACK 01 MODE1/2048\n INDEX 01 00:00:00\n'
'FILE "cd-word-audio.bin" BINARY\n'
' TRACK 02 AUDIO\n INDEX 01 00:00:00\n')
PYTHON

Mount /tmp/cd-word.cue in a stock CD32. Its silent audio track is sufficient:
the assertions inspect public playback state, not subjective sound output.
No game image is required. Exit 0 means all checks passed; failures return 20.
96 changes: 96 additions & 0 deletions developer/debug/test/devices/cdplaytrack/cdplaytracktest.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
Copyright (C) 2026, The AROS Development Team. All rights reserved.

Exercise CD_PLAYTRACK callers that initialise only word-sized track
arguments. Requires an audio track 2 longer than 0.1 seconds.
*/
#include <aros/debug.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <devices/cd.h>

static ULONG checks, failures;

static void check(BOOL okay, CONST_STRPTR what)
{
checks++;
if (!okay)
{
bug("CD PLAYTRACK FAIL: %s\n", what);
failures++;
}
}

static void playcase(struct IOStdReq *play, struct IOStdReq *control,
ULONG track, ULONG count, BOOL valid)
{
struct CDInfo info = { 0 };
BOOL completed;

play->io_Command = CD_PLAYTRACK;
play->io_Offset = track;
play->io_Length = count;
play->io_Data = NULL;
SendIO((struct IORequest *)play);
Delay(5);
completed = CheckIO((struct IORequest *)play) != NULL;
bug("CD PLAYTRACK track %08lx count %08lx completed %ld error %ld\n",
track, count, (LONG)completed, (LONG)play->io_Error);
if (valid)
{
check(!completed && play->io_Error == 0,
"valid low-word track arguments start asynchronous playback");
control->io_Command = CD_INFO;
control->io_Data = &info;

Check warning on line 44 in developer/debug/test/devices/cdplaytrack/cdplaytracktest.c

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

developer/debug/test/devices/cdplaytrack/cdplaytracktest.c#L44

Address of local auto-variable assigned to a function parameter.
control->io_Length = sizeof(info);
check(DoIO((struct IORequest *)control) == 0, "read playback state");
check((info.Status & CDSTSF_PLAYING) != 0, "audio playback is active");
}
else
check(completed && play->io_Error == CDERR_BADLENGTH,
"zero low-word track count is rejected");

if (!completed)
AbortIO((struct IORequest *)play);
WaitIO((struct IORequest *)play);
}

int main(void)
{
struct MsgPort *port = CreateMsgPort();
struct IOStdReq *play = NULL, *control = NULL;
BOOL play_open = FALSE, control_open = FALSE;

if (!port)
goto setupfail;
play = (struct IOStdReq *)CreateIORequest(port, sizeof(*play));
control = (struct IOStdReq *)CreateIORequest(port, sizeof(*control));
if (!play || !control)
goto setupfail;
if (OpenDevice("cd.device", 0, (struct IORequest *)play, 0))
goto setupfail;
play_open = TRUE;
if (OpenDevice("cd.device", 0, (struct IORequest *)control, 0))
goto setupfail;
control_open = TRUE;
control->io_Command = CD_PAUSE;
control->io_Length = 0;
check(DoIO((struct IORequest *)control) == 0, "initialise unpaused state");

playcase(play, control, 2, 1, TRUE);
playcase(play, control, 0x00010002, 1, TRUE);
playcase(play, control, 0xffff0002, 0x00020001, TRUE);
playcase(play, control, 2, 0, FALSE);
playcase(play, control, 2, 0x00010000, FALSE);
goto end;
setupfail:
check(FALSE, "set up CD requests");
end:
if (control_open) CloseDevice((struct IORequest *)control);
if (play_open) CloseDevice((struct IORequest *)play);
if (control) DeleteIORequest((struct IORequest *)control);
if (play) DeleteIORequest((struct IORequest *)play);
if (port) DeleteMsgPort(port);
bug("CD PLAYTRACK: %lu/%lu pass, %lu failures\n", checks - failures, checks, failures);
return failures ? 20 : 0;
}
11 changes: 11 additions & 0 deletions developer/debug/test/devices/cdplaytrack/mmakefile.src
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Copyright (C) 2026, The AROS Development Team. All rights reserved.

include $(SRCDIR)/config/aros.cfg
USER_LDFLAGS := -static

#MM test-devices-cdplaytrack : includes linklibs

%build_progs mmake=test-devices-cdplaytrack \
files=cdplaytracktest targetdir=$(AROS_TESTS)/devices/cdplaytrack

%common
Loading