The %pL and %pR bars followed every drop of the level, and had nothing
like the peak marker of the built-in peak meter. With the new "hold"
bar option a bar falls back at the peak meter's release rate, and the
highest level is held for the peak hold time, both from the same
settings as the built-in meter (peak_meter_get_times()). Without the
option the bars are as before.
The held peak is a block ending at the held level, 1 pixel thick or as
many as the optional number after "hold" says (eg. "hold, 4"). On a bar
with a fill image the block is drawn from the same part of the image,
so a bar drawn as LED segments holds a whole segment.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I5c6262ba02b7d2df6c5f80f15d4a1d4354ef8e26
A52 files cut from a longer stream can start partway through a frame.
The metadata parser required a sync word at offset 0 and rejected
them, although the codec can resync. Scan the first 64 KB for a frame
header that is followed by a second valid header, record it as
first_frame_offset, and use that offset when seeking and resuming.
Tested in the simulator (perfsim) and on a Sansa Clip+: a file
starting with 675 bytes of a partial frame now plays. In the
simulator it decodes all 3161 frames with the same output as the file
without those bytes, and seeks land on frame starts.
Fixes FS#9056
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I5d72b1cd1d8437491ec00a38459e391fb158b9a2
RFC 7845 specifies R128_TRACK_GAIN and R128_ALBUM_GAIN for loudness
normalization in Opus files, but Rockbox only understood the
REPLAYGAIN_* tags. Parse the R128 tags as Q7.8 dB values relative to
-23 LUFS and add 5 dB to match the ReplayGain reference level. If a
file has both kinds of tags, the R128 tags take priority.
Fixes FS#13624
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I0ef08a7897ec5ee8d1e5d99e7d9ea3901847fa52
The SID codec never finishes on its own, so test_codec would decode
forever and a directory test would stall on the first SID file. Count
the decoded samples and halt the codec after 120 seconds of audio. Also
set the track length to that limit so the benchmark results are correct
and show the elapsed time while decoding.
Fixes FS#13662
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I4e7e99bf41d00c5597aae9d48b837e28df5b75c0
afr_configure() returned 1 for every message. For
DSP_PROC_NEW_FORMAT that is PROC_NEW_FORMAT_DEACTIVATED, so the
DSP did not call the stage for the buffer that brought a new
format: the first buffer of each track went out unfiltered, and
the filters started on the second. That is 128 samples of a WAV
file, and the whole first block of a codec with 32-bit
non-interleaved output, 4608 samples of a FLAC file.
A codec sets the format again at the start of every track, so
between gapless tracks this put a short stretch of unfiltered
audio into filtered audio, heard as a click at the join.
Return 0, as the other stages do.
Found with test_codec's DSP checksums on a Sansa Clip+: a model
of the DSP with fatigue reduction left out of each file's first
buffer reproduces the sixteen checksums of two runs, and none of
them with it left in. Listening on the same player, the click
between gapless tracks is gone with this change.
Change-Id: I7a1193fa0a4ee0c983cbcc5c1af201e1678579d0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The rows that calibrated the Clip+ model in utils/perfsim, timed on
AS3525v2 with the tick timer's count for a 2/3 microsecond clock:
- calls, returns and loads into pc, interlocks after a load and
after a multiply, multiplies by operand size
- a miss with work after it, on each word of its line, back to
back, and evicting a dirty line; a load or store to the line
still filling
- stores to lines not cached: one stream, a word a line, four
words at a time, two streams turn about
- copies between uncached buffers, within a memory and across
- fetch misses in code written where it runs
- loops of adds and of branches by how many lines they cover, and
a cached pointer chase likewise
- the TTA filter stage by stage and Tremor's window loop
On AS3525v2 the miss rows run in DRAM and again in the RAM inside
the SoC, where codecs are loaded.
Rows that turned out to say nothing, or that a later row replaced,
stay in the file under TEST_CYC_ARCHIVE, each with why.
TEST_CYC_QUICK runs only the newest rows.
With these rows the plugin is about 140 KB on ARMv5, so it is left
out where the plugin buffer is 128 KB or less: the Clip, the m200v4
and the c200v2.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I4ec45da514d0abaa02e1e041fd1a0387490994ed
A test plugin that measures what ARM instructions cost on the running
device. Each row times sixteen copies of one instruction in a loop and
subtracts the empty loop, giving cycles per instruction. Where plugins
get IRAM, each row is run with code and data in each combination of
IRAM and DRAM.
It covers ALU, shifts, branches, the load and store forms (including
halfword and register-offset loads), load-use, and the multiplier at
narrow and full-width operands. ARMv5 adds the DSP multiplies, clz,
qadd, ldrd/strd and pld; ARMv6 adds the top-word and dual 16-bit
multiplies, umaal, ssat, rev, the extends, pkhbt, the SIMD adds and
multiply result latency. Cache misses are priced by a pointer chase
and by sequential streams over working sets either side of the cache.
Timing uses the SoC's microsecond counter on PP502x, PP5002, S5L870x,
S5L8720, TCC7801 and i.MX233, and the tick elsewhere. Results go to
the screen and to /test_cyc.txt.
Built only with test plugins enabled, on native ARM targets that run
ARM code (not Cortex-M).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I4a41f6daaa27fb817f411de89901a117c5c70f4d
The radio is heard through the codec's input PGA at +12 dB, but on
the recording screen the gain started at 0 dB, so a recording was
much quieter than what was heard just before. Start the line gain,
which the radio uses, at +12 dB.
Defining the defaults also makes the line gain a saved setting on
this target; before, it went back to 0 dB at every boot.
Tested on a YP-CP3: switching from the FM screen to the recording
screen with FM as the source keeps the same loudness.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: Id65ce25515d7143b2ca21e5ef2a110a356303380
The headphone amplifier enable, GPIO F2, shares its pin with SDRAM
address line A12 and is A12 until switched in IOMUXB. Rockbox never
switched it, so driving F2 never reached the amplifier: started from
the Rockbox bootloader, playback and the FM radio were near silent
and distorted. They only worked when the original firmware had run
first, as it switches the pin. The 16 MB of SDRAM does not use A12.
Tested on a YP-CP3 booted from the Rockbox bootloader.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I40610aaf88f06fd4831d07174b0f66a4ba32204d
When the text reached the bottom of the screen it started again at
the top, over what was there, so the old lines showed through the
new. Scroll up a line instead, as test_codec does.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I024eda05bbcca6f1539893ea609c89f562436e2f
The tests always ran on HOME_DIR, so a card could not be tested, and
the internal storage could not be left alone.
Where there is more than one volume the plugin now asks which to
test when it starts: HOME_DIR as before, or any volume the root
directory lists. "Select disk" in its menu changes it. The test
directory, the test file and the log are all on the disk chosen,
where the log used to go to HOME_DIR, so that testing a card writes
nothing to the internal storage. The log names the disk.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: Ib243fdd32fa205e00bc2b39d776e0fc8a420a1f0
What the built-in recording screen shows and the skin tags did not:
- %RS size of the current recording, as "1.5MB"
- %RP seconds in the pre-record buffer, empty unless pre-recording
- %Rc clips counted by the peak meter
- %Rt trigger state by name; as a conditional off, ready, steady, go,
postrec, retrig, continue
- %Rw recording warnings in hex, empty while there are none
- %Ri recording source by name; as a conditional the same on every
target: mic, line in, digital, FM radio
- %Rg gain of the source in dB, the left channel's for line in and FM
The manual gets a Recording section covering these and the recording
tags that were there, none of which it described.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I889f95fd472c472c2589393a6c77eff4a4fd5c8f
- %Rf printed the sample rate with "%lu.%1lu", a field width rather
than a precision: 44100 Hz came out as "44.100", 22050 Hz as "22.50".
It is now in kHz without trailing zeros: "44.1", "22.05", "48".
- %Re switched on the format setting plus one, so its text named the
next format: "aiff" for WAV up to nothing for MP3. It now names the
format set, MP3 as "mp3" like the others.
- %Rb printed the index of the MP3 bitrate setting, "12" for 128 kbps.
It now prints the bitrate in kbps. Dead code from 2009 goes.
- %Rm was true for stereo: rec_channels is 0 for stereo. The classic
status bar has shown the mono icon for stereo recordings since 2009.
- %Rn counted the minutes on past 59, so %Rh:%Rn:%Rs showed 01:61:05
after an hour. It now counts within the hour, as %Rs does.
As conditionals %Rf, %Re and %Rb keep their values, so the classic
status bar's sample rate, format and bitrate icons are unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: Id9fb5c0b71fc0a44c5c7b3239a74397cb71090bf
The bootloader starts the OF when the player is woken by plugging in
USB, because the OF was the only firmware that could give the host
write access to the internal flash. A build with FTL_ALLOW_WRITE
can do that itself, so boot Rockbox there and leave the OF to a held
key. Builds without it keep the old behaviour.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I74af2f8c56436a3f7c9ad97d1b1638469807f0dc
The NAND's SYS volume holds the bootloader's firmware and is hidden
unless a build defines HAVE_RK27XX_NAND_SYS. Getting at it, e.g. to
replace BASE.RKW, needed a special build.
Add "NAND SYS on next USB" to the debug menu. While it is set, the
next USB connection shows SYS through the USER drive, as "NAND SYS",
and the switch clears when that connection ends. It is decided once
per connection, so setting it while connected waits for the next
one, and it is held in RAM only. Writes still need FTL_ALLOW_WRITE.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: Idda3f1c5e00bea511618021397a6cb3bb0be7361
Before the original firmware resets itself, e.g. at the end of a
firmware update, it stores a boot mode in an undocumented GPIO1
register that keeps its value over the reset. The NAND bootloader
reads it to decide whether to boot at all, then starts our
bootloader, which chose Rockbox or the OF from the buttons alone, so
an OF that restarted itself came back up as Rockbox.
Rockbox never writes the register and it reads 0 after power-on, so
boot the OF whenever it is set.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I22a98cafad48f66302a8401c9df847a073675a58
Before it jumps to an image, the rk27xx NAND bootloader writes three
words at the address in RKW header field 0x14: a magic, its version
and which copy of the image it loaded. The original firmware never
initialises them: it reports the version over USB and counts its own
reboots in the third word, and once the count reaches 5 it reboots
into a mode the NAND bootloader will not boot. When our bootloader
started the OF, nothing wrote them, so the OF ran with whatever was
left in DRAM.
Field 0x14 of our own images held a constant taken from some other
image. Point it at the last 12 bytes of DRAM, which nothing uses
before our bootloader runs. load_rkw() in the bootloader now reads
the words there before loading an image, and writes them at the
address in the loaded image's header when that lies between the
image and the bootloader. Started over USB, it passes version 0.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: Ife1d63e361a780c28a9f0626d110552b98bb6b7f
The host configures the device before Rockbox has handed the storage
over, and mass storage allocated its buffer right then. On the
recording screen the recording buffer still holds all free memory at
that point and cannot shrink, so plugging in USB there panicked with
"usb_storage_init_connection(): OOM". Recording closes, and frees its
buffer, only on SYS_USB_CONNECTED, which the handover broadcasts.
Playback does not hit this: its buffer gives memory up on request.
The buffer is only needed to run commands, and commands already wait
for the handover. So it is allocated, and the endpoint primed for the
first command, in the notify event that both handover paths in usb.c
send, or at once when the storage is already handed over. Until then
the host's first command waits at the endpoint, NAKed. GET_MAX_LUN,
which comes before the handover, is answered from the core's control
buffer instead of the transfer buffer. Targets with static USB buffers
are unchanged.
Tested on a Samsung YP-CP3: USB plugged in on the recording screen,
at boot and from the main menu, mounts, and files copied both ways
keep their checksums.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: Icadc24fd52a07d03125234e492dab0ede9e339c9
Plugging in USB on the recording screen closes recording, but the input
stays selected: the screen switches it back to playback only when it
ends, which is after USB mode, at the unplug. On a Samsung YP-CP3,
whose codec passes the microphone or FM radio through to the
headphones while recording, the input could be heard all through USB
mode. Switch to playback before entering it.
Tested on a YP-CP3.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I194d5e120cc39685aa43cea4741e826a86ed2c65
commit_discard_idcache() invalidated both cache ways at run time, at
every codec and plugin load and every USB connect. With the cache on,
the CPU crashed in the poll loop when that loop started a cache line of
its own; with the cache off around it, since 0e1952a4d1, code fetched
again afterwards could come back wrong. On a Samsung YP-CP3 a build
with a few changes elsewhere took an undefined instruction exception
in the USB interrupt handler at every boot into USB mode, always at
the same instruction, wherever the linker put it. The same build with
only the invalidate at USB connect replaced by a nop booted and
worked.
The original firmware invalidates the ways only once, at power-on with
the cache off, as crt0.S does, and after that only single lines. None
is needed at run time: the cache is unified and write-through, so what
the CPU writes, code included, is in memory and in any cached copy, and
every DMA into memory - SD reads, USB receives, recording - discards
the lines of its own buffer first. NAND is read by the CPU. So
commit_discard_idcache(), and commit_discard_dcache() with it, now do
nothing.
Tested on a YP-CP3, with the build that crashed: it boots into USB
mode, copies files with matching checksums, plays several formats,
runs plugins (fft with playback, bubbles), and records.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I14301a0c05736e28e53a3365c838f4a4a73052b3
Themes for a given device often reference the assets of the default
cabbiev2 theme. Record a list of what is bundled, and check anything
not included with the theme against that list.
If something is still missing, then that's an error.
This applies to fonts, wps files, backdrops, icons, and so forth.
Change-Id: I5ff7feaae892c8b9a81c2cb3035879672f3e6c29
The DSP gets its output samplerate from the codec thread when a
track is played. test_codec did not set it, so its runs with the
DSP used the rate of the last track played, or the default if
there was none: after "Playback frequency" was changed, they
resampled to the old rate until something had been played.
Set it from the mixer for each file, as the codec thread does.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
"Checksum with DSP" and "Checksum folder with DSP" give the CRC32
of the DSP's 16-bit output for a file or a folder, as "Checksum"
does for the codec's output. That lets the DSP of a device, with
its settings, be checked against a reference for several files in
one run; "Write WAV with DSP" writes one file, /test.wav.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
b7170e03c4 added window_lookup_mid, 512 bytes, to IRAM on every
target. On the targets with 48KB of IRAM for a codec that left
the ATRAC3 codecs 48 bytes too large to link (iPod Color and the
other PP502x players with 96KB of IRAM).
Put the table in IRAM only on the targets with more, like the
decoder's other large tables. Nothing changes there.
Built for iPod Color, where the two codecs now have 476 bytes of
IRAM to spare, and for the iriver H120.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The decoder gave the DSP samples with two fractional bits (sample
depth 17), far fewer than any other codec. The DSP's filters are
only as precise as the samples they are given: with an equalizer
band at a low frequency the output was noise, or held at full
scale.
Scale the last stage of the synthesis filter up by 11 bits and
set the sample depth to 28. On ARMv4 the bits are taken from the
64-bit sums of the dewindowing, which had them. Elsewhere the
input of that stage is scaled, in its matrixing step; that is not
done on ARMv4 because its multiplier takes longer for the larger
operands (51.97 against 48.85 MHz below). The Coldfire path uses
the C matrixing and has not been run.
Seven files decoded under perfsim for the Sansa e200v1 and Clip+:
shifted down again, the e200v1 output is within one step of the
old output, and the Clip+ output no further from the e200v1's
than before. Through a ten band equalizer with bands at 32 and
64 Hz (the filter fix of the DSP included), the noise of
atrac3_lp2_132.oma falls from -64 dB to -101 dB relative to the
signal.
Estimated with perfsim (not measured on a device),
atrac3_lp2_132.oma: e200v1 48.81 -> 48.85 MHz, Clip+ 26.91 ->
26.96 MHz.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The dewindowing loop is 72% of ATRAC3 decoding on ARM7TDMI. The
window is symmetric, so read only its first half: each pair of
coefficients serves two inputs from the front of the 48 and, with
the two swapped, two from the back. That halves the coefficient
loads and lets them be done four at a time.
The sums are kept in 64 bits, so the new order of the additions
does not change the result: the PCM output of seven files is
byte-identical.
Estimated with perfsim for the Sansa e200v1 (not measured on the
device), atrac3_lp2_132.oma: 53.74 -> 48.81 MHz.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The ARMv5E dewindowing routine takes 16 of each product's bits,
rounded down, so each sum of 24 products came out about 12 units
low. Through the filter bank that put a dc offset of about 12 LSB
(of 16 bits) on the output and, from the high band, a tone at half
the sample rate; together they were four fifths of the decoder's
error on these targets.
Start the sums 12 up. Also correct a comment in both ARM files.
Checked with perfsim (Sansa Clip+ build) against ffmpeg's decode of
seven files: the dc offset goes from 11 to 12 LSB down to under
1 LSB, and the error from about -66 dBFS to -69 to -72 dBFS, the
same as the ARMv4 routine gives. Decoding is 0.7% slower (26.73 to
26.91 MHz for atrac3_lp2_132.oma). The ARMv4 output is unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
applyVariableGain() applied the constant gain before a gain point
in a do-while loop, so at least eight samples of it, even when
there are none: when the point is at the start of the block or
follows straight after the previous one. Every later gain point in
the block was then eight samples late. This came in with the loop
unrolling of 51a8be1a0f.
Use a while loop, as ffmpeg does.
Checked with perfsim (Sansa e200v1 build) against ffmpeg's decode.
Over the whole of atrac3_lp2_132.oma the SNR goes from 45 to 51 dB
and the worst frame from 14 to 21 dB; the right channel of a joint
stereo RM file goes from 37 to 54 dB. What is left is a noise floor
near -72 dBFS in every frame, from the 2 fractional bits the
decoder works with.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Only the first and last 128 points of the 512 point window were
applied, and the 256 between were taken to be one. They are not:
the window rises to 1.207 there. Every block was therefore up to
1.6 dB low over half its length, which left the output 0.7 dB low
on average and an error about 23 dB below the signal at all
frequencies.
Add the missing half of the table and apply it.
Checked with perfsim (Sansa e200v1 build) against ffmpeg's decode,
with the two previous fixes applied before and after:
level SNR
five plain stereo RM files -0.7 dB 23 dB -> 0.0 dB 54-57 dB
joint stereo RM file -0.7 dB 23 dB -> 0.0 dB 37-45 dB
joint stereo OMA file -0.7 dB 23 dB -> 0.0 dB 45 dB
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The spectra of the odd QMF bands are stored reversed. 8722c6f2bb
moved that reversal out of IMLT() and into the decoding of the
coefficients, but did it within each scale factor band, one place
off, and not at all for tonal components. The odd bands, which is
5.5 to 11 kHz and above 16.5 kHz at 44.1 kHz, have been decoded
wrongly since: against ffmpeg's decode that range was uncorrelated.
Reverse the whole band in IMLT() again, as ffmpeg does. The old
commit measured the saving it is giving up as 0.11 MHz on PP5024.
Checked with perfsim (Sansa e200v1 build) against ffmpeg's decode
of an OMA file and six RM files: the coherence of the 5.7 to 10.7
kHz range goes from under 0.01 to 0.99, the same as other bands.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Since 2e314093c8 the ATRAC3 decoder takes its frame size from
id3->bytesperframe, which the RM metadata parser does not set. With
a frame size of zero, a file in plain stereo mode had its second
channel decoded from the first channel's data: both outputs were
the left channel.
Set it from the RM sub packet size before the decoder is opened.
Checked with perfsim (Sansa e200v1 build) on six ATRAC3 .rm files:
the two channels were identical sample for sample before, and each
now follows its own channel of ffmpeg's decode.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Both decoders rejected extended sequential JPEGs (SOF1), which are
baseline files in all but name when they have 8-bit samples, and
16-bit quantization tables, which libjpeg writes for very low
quality settings unless told to force baseline.
Accept SOF1 with 8-bit samples, and read 16-bit table entries. The
core loader keeps its tables in 16 bits and scales them for the IDCT,
so it rejects entries over 8191; libjpeg's largest at quality 1 is
4950. Files using more than two Huffman tables are still rejected.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I705a61402b4a0ab252995f8559b7ff2f68b05d72
The comment packet is not used by the codec, but skipping it grew
the stream's packet buffer to the packet's full size. Heap use rose
with the size of the tags: a file with 300 KB of embedded album art
needed 617 KB of heap, and one with 940 KB of art could not be
opened even with a 992 KB codec buffer.
Skip the packet without storing it: forget the part already
buffered and let ogg_stream_pagein() drop the rest, as it does for
a packet whose start was lost.
Seeking to the start of a file ran the headers through the stream
again, which buffered the whole comment packet by the normal path.
Start the seek search at the first audio page instead, as libvorbis
does, and handle a target inside that page.
With both, heap use no longer depends on the tags. Large tags cost
at most about 90 KB over an untagged file, from the two Ogg buffers
growing to hold one full page each.
Checked with perfsim on the Sansa Clip+ model, not on a device,
with the heap limited to what a 512 KB codec buffer leaves:
files with up to 1.5 MB of art or 240 KB of text decode to the
same PCM hashes as the untagged audio, and 15 seeks per file,
including to 0, 30 and 150 ms, give the same positions and PCM
as the unmodified codec on ten files. Chained streams were not
tested.
Change-Id: Id27ebf98b436d813cfa3179951eee5bd7b2c0cd2
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Where the LSP curve peaks, the value its -1/4 power is taken of is
far below one step of 16.16 and was rounded to zero. pow_m1_4() of
zero is enormous, the block's levels are taken relative to that
maximum, and so the whole block came out about 46 dB down. In
StutteringFile.wma (22 kHz mono, 20 kbps) this muted a block here
and there, which is heard as a stutter.
Pass the value to pow_m1_4() with all of its 38 fractional bits.
Checked with perfsim (Sansa e200v1 build) against ffmpeg's decode
of that file, in blocks of 46 ms: 11 of 841 were off by more than
1 dB, the worst by 10.6 dB; none are now, the worst by 0.4 dB.
Four other files with LSP exponents are unchanged or closer, and
files without them are byte-identical.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Tremor is built here with CHANNELS 2: synthesis produces no PCM
for a stream with more channels, so a 5.1 file "played" as nothing
at all. It was still set up in full first, which took 416 to 880 KB
of the codec heap for the 5.1 and 7.1 files tried, and wrote one
entry per channel into arrays sized for two.
Refuse such a stream when its identification header is read. The
codec then returns an error at once, with under 8 KB of heap used.
Checked with perfsim on the Sansa Clip+ model, not on a device:
six 5.1 and 7.1 files are refused, and 13 stereo and mono files
give the same PCM hashes as before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Very low bitrate WMA files send their spectral envelope as LSP
coefficients. The curve computed from them squares two products
whose value can reach about a million, in 16.16 fixed point. Where
the envelope should be lowest the squares overflowed, and those
points came out near the curve's maximum instead: bands at the top
of the spectrum up to 17 dB too loud, and everything else a few dB
low, as levels are taken relative to the maximum.
Sum the squares in 64 bits, and let pow_m1_4() take a value above
the 16.16 range.
Checked with perfsim (Sansa e200v1 build). The curve is within
0.2 dB of ffmpeg's formula at all 57600 points of 80 blocks traced
from two files. Against ffmpeg's decode, as the mean difference in
band levels over the whole file, with the noise coding fix applied
before and after:
StutteringFile (22 kHz mono, 20 kbps) 1.6 dB -> 0.3 dB
shoujicomcn2117164 (same) 0.2 dB -> 0.1 dB
terra8k (11 kHz mono, 8 kbps) 0.3 dB -> 0.0 dB
Only the five files that use LSP exponents change; the other 23
are byte-identical.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Low bitrate WMA files code their upper bands as noise at a given
power. Those bands came out 12 to 25 dB too quiet, which dulled
the treble. Two things were wrong.
The exponent pointer was moved too far in blocks whose exponents
have another resolution. This is ffmpeg's r20756 (f78501b264,
"Fix apparent 10l typos introduced in r8627"); r8627 was merged
here in 2f1da8d24a but the fix for it never was.
The fixed point gain of a band lost nearly all its precision: it
was zero for three bands in four in the file traced, and the sum
for a band's power overflowed in a quarter of them. Compute the
gain in 64 bits, once a band. The factor for the noise below the
first coded coefficient (WMA v1 only) was 16 bits too large and is
corrected by the same reasoning; no file here exercises it.
Checked with perfsim (Sansa e200v1 build) against ffmpeg's decode,
as the mean difference in band levels over the whole file:
01 - Jane Austen (44.1 kHz, 32 kbps) 5.5 dB -> 0.0 dB
07.Devil.In.My.Mind (same) 6.2 dB -> 0.0 dB
beyonthepain907z (same) 6.8 dB -> 0.0 dB
moshimoashitaga (same) 2.8 dB -> 0.0 dB
Four more noise coded files, already within 0.3 dB, now match too.
The output of the 15 files without noise coding is byte-identical.
Files that use LSP exponents still differ in their top bands; that
is a separate fault in the LSP curve.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A payload normally holds one codec packet of blockalign bytes, but
some files put several in each. Only the first was decoded, so such
a file played one packet in every 8 or 15, as a few seconds of
broken sound, and then ended.
Step through the payload in blockalign sized packets.
Checked with perfsim (Sansa e200v1 build) against ffmpeg's decode:
doors-test.wma (WMA v2, 11 kHz mono), 15 packets a payload:
80896 of 1205760 samples before, all of them after, 86 dB SNR
test.wma (WMA v1, 44.1 kHz stereo), 8 packets a payload:
1294336 of 10346496 samples before, all after, 114 dB SNR
The output of 26 other WMA files is byte-identical before and after.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A WMA Professional stream of 16 bits per sample played about 48 dB
too quiet and with a noise floor near -70 dBFS.
ffmpeg scales the transform's output by the stream's sample size.
That was dropped when the decoder was converted to fixed point
(d884af2b99, 16284ae8ae), and the output is passed to the DSP as if
every stream had 24 bits. A stream of fewer bits has a lower
quantization step to match, so it came out low by the difference,
and it used the bottom of the integer quantization table, where the
factors have only a few significant bits.
Decode a 16 or 20 bit stream at the level of a 24 bit stream: use
that stream's quantization step, and scale each band's factor by
the ratio that is left. 24 bit streams are not affected.
Checked with perfsim (Sansa e200v1 build) against ffmpeg's decode
of a 16 bit, 192 kbps stereo file, the only such file to hand:
level SNR vs ffmpeg noise
before -48 dB 37 dB -70 dBFS
after correct 85 dB -117 dBFS
A 24 bit file's output is byte-identical before and after. The
20 bit case follows the same rule but is untested.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Currently if you want to compile a bootloader like so:
$ ../tools/configure --rbdir=/.rockbox.aigoerosq --target=aigoerosq --type=b
This won't work because the bootloader is hard coded to look for the rockbox Linux binary in /.rockbox/rockbox.erosq regardless of what is specified by '--rbdir'.
This commit adds support for ROCKBOX_DIR in the hosted HibyOS bootloaders.
After compiling, they can be installed with adb via (for example):
adb push build/bootloader.erosq /usr/bin/bootloader.erosq
Change-Id: Ic4ceb75107f608beacfd497998a11a5874e87ac1
inverse_channel_transform() ran its general N-channel matrix loop
for every sample of a stereo stream, where the matrix is exactly
+-1.0. That loop was a quarter to a third of the whole decode, and
GCC 9.5.0 compiles it worse than 4.9.4 did, which made the codec
6-9% slower on ARM7TDMI after the toolchain update.
Handle a group of two channels separately: add and subtract when
the matrix is +-1.0, and a plain four multiply loop otherwise. More
than two channels still use the general loop.
This reverses the regression from the GCC 9.5.0 update and goes
well past it. The loop the newer compiler handled badly is no longer
used for stereo, so the two compilers now give the same speed to
within 1%, about 25% faster than the codec was with GCC 4.9.4
(estimated with perfsim, e200v1, wmapro_141k: 25.81 MHz with 4.9.4
before this change, 19.5 MHz with either compiler after it).
Output is bit-identical: whole-file PCM hashes match before and
after for five stereo files at 55-271 kbps, built with GCC 9.5.0
and with 4.9.4, and also with the multiply path forced on.
Measured with test_codec, wmapro_141k.wma, MHz for real time:
Sansa e200v1 27.99 -> 19.70
Sansa Clip+ 21.78 -> 15.80
Estimated with perfsim for the other files (e200v1 / Clip+):
wmapro_55k 25.21 -> 17.06 / 20.02 -> 13.71
wmapro_80k 26.17 -> 18.01 / 20.75 -> 14.44
wmapro_173k 28.52 -> 20.29 / 22.55 -> 16.25
wmapro_271k 30.85 -> 22.52 / 24.34 -> 18.04
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The WM8750 frames its ADC on ADCLRC and its DAC on DACLRC. As the I2S
slave both are inputs, and the rk27xx has a single LRCK, which on the
YP-CP3 evidently does not reach ADCLRC: with the rk27xx as the master,
the recording DMA got exact zeros on most visits to the recording
screen and real samples only by chance, sometimes changing partway
through a visit. That stays so with the codec PLL no longer glitching
the I2S clocks (previous commit); with the codec as the master it does
not happen.
The codec now drives BCLK and both LRCKs itself, and the rk27xx I2S
transmitter and receiver are slaves. The codec's MCLK still comes from
the rk27xx codec PLL at 256 fs, so sample rates stay exact. The
original firmware runs the codec as master too, but off a fixed 12 MHz
in USB mode.
RK27XX_I2S_MCLK says the rk27xx makes the codec's MCLK, apart from
CODEC_SLAVE, which also makes it the I2S master. The YP-CP3 drops
CODEC_SLAVE for RK27XX_I2S_MCLK, and the WM8750 driver sets its master
bit as it does for any codec that is not a slave.
Tested on a YP-CP3: playback, FM radio, the recording screen's peak
meter on every visit, recording from the microphone and from FM.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I0dc93d3b2c45fddf61649702a931d11806e78cbf
Every start of recording applies the sample rate again, mostly
unchanged, and set_codec_freq() reprogrammed the codec PLL each time.
That glitches MCLK and every I2S clock made of it, right before the
recording receiver is reset and starts on them. Whether it then kept
its framing came down to code timing: on the Samsung YP-CP3 the
recording screen's peak meter showed one channel empty and the other
saturated on some visits, and builds with debug code added never did.
The PLL is now left alone when it already runs the rate asked for. On a
real change the lock bit, which may still show the old lock at first,
is polled only after the 0.3 ms the datasheet gives for locking, with a
timeout of at least a full tick, and the clocks get 1 ms more to settle
before anything starts on them.
Tested on a YP-CP3, together with the codec as I2S master: the peak
meter on every one of many visits to the recording screen, with the
microphone and FM, and at 22 kHz.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I2267e17c5bc7d8044715e762dbb6b92f45af4dcc
Replaces flac_lpc_32_c, the wide predictor path every 24-bit stream
takes, and 16-bit streams encoded at high coefficient precision. The
coefficients are invariant for the whole call, but the C loop reloaded
all of them for every output sample and spilled its loop bound to the
stack on top of that. Orders 1-8 now keep every coefficient in a
register; orders 10 and 12, which is what -8 emits, get their own
unrolled loops instead of the generic chunked one. An ARMv5E kernel
using the packed 16-bit multiplies is included behind
FLAC_LPC32_NARROW_ASM, off by default: it needs bps <= 16, and only
about half the subframes of such a stream can use it.
Measured with test_codec on 24-bit/96kHz streams. At predictor order 12:
36.24 MHz on e200 (ARMv4) against 62.29 MHz before. The same file
improves from 37.65 MHz to 27.3 MHz on Clip+ (ARMv5).
Bit-exact against flac -d over four complete streams on both targets,
with and without the assembly, and the kernels are checked against an
int64_t reference across every order 1-32, qlevel 0-15 and coefficient
precision 1-15.
The rarely-executed orders stay in DRAM: the codec's IRAM window on
PP502x is nearly full and demoting them measured no cost, leaving 96
bytes free. FLAC_LPC32_NO_IRAM demotes the whole filter.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Change-Id: Icd8bd298973b9f5c26c103af8adf47b03489d69f
A file's length and first cluster are only written to its directory
entry when it is closed, and the log was closed at the end of
plugin_start() alone. Leaving by USB or by power off goes through
exit() instead, so a whole run's log could be left as an empty file
with its data in clusters nothing pointed to.
Close the log from an atexit handler, close it when a run over a
folder ends, and close and reopen it after each track so that at
most one result is lost if the player dies.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I613d0ad8c637d7f48a82eb09bc310c6fcc6d77f9
Of the two divisions a sample left in the entropy decoder, the first
divides the range by the Rice pivot, which is small: below 1024 for
99.9% of the samples of a 16-bit test file and never as much as 4096.
Keep a table of reciprocals, filled in as divisors turn up, and
divide with a 32x32->64 multiply and one correction. Larger divisors
go to the division routine as before. The other division, by help,
has no such pattern.
This is for ARMv5 and later without a hardware divide. ARMv4 has
its own divider with a reciprocal table already, and a long multiply
is slow there; its codec is unchanged.
The table is 16 KB of bss. With r = (2^32 - 1) / n the estimate is
the quotient or one less for any 32-bit numerator, checked against
true division for every n below 4096.
MHz for real time in perfsim's model of the Clip+, -c1000, -c2000
and -c3000: 32.5, 48.4, 76.4 to 30.1, 46.0, 74.0. A Clip+ measures
30.63 at -c1000, from 32.85, with the same checksum, 1008ffab.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I555ff83d7e19919848c8fb7b8d12ecfa671a976b
After the division routines the entropy decoder was the largest part
of Monkey's Audio at the fast levels, with two things to gain.
All of its state, the range coder's and the Rice parameters, was in
statics, so each use was a load and each update a store: about half
of the function's time on ARM7TDMI, where a load is 3 cycles. Copy
it to locals for the length of a block and write it back after. The
functions that take a pointer to it have to be inlined for that to
work, and on ARMv4 gcc left the per-sample one out of line, so force
them.
The symbol was found by dividing low by help and searching the count
table for the quotient. counts[n] <= low / help is the same as
counts[n] * help <= low, so search with the multiply instead: the
first symbols are by far the likeliest. That leaves two divisions a
sample from three.
MHz for real time in perfsim's models, -c1000, -c2000 and -c3000:
Clip+ (ARMv5) 37.9, 53.8, 81.8 to 32.5, 48.4, 76.4
e200 (ARMv4) 45.3, 68.6, 111.4 to 35.2, 58.5, 101.3
A Clip+ measures 32.85 at -c1000 (61.4 before this and the division
change), with test_codec's checksum, 1008ffab, the same as the old
code's. The standalone decoder gives identical output for all four
levels tested. The path for files older than 3.98 has the same
change and was not tested, for want of a file.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: Idf9002a5b5f3a423f44f70443936ea5ac427cd12
lib/arm_support/support-arm.S was written to replace libgcc's
division for ARM, and bff5a35c3c (FS#10943, 2010) added it to the
core, the plugin library and the codec library alike. When
1501df045f (2013) replaced EXTRA_LIBS with explicit lists, plugins
kept it and codecs did not, and they have taken their division from
libgcc since.
With the gcc 4.4 toolchain that cost little: its libgcc had a
routine that used clz. With gcc 9.5 libgcc has no soft-float ARMv5
variant, so ARMv5 targets get the ARMv4 routine, a shift and
subtract loop of about 130 cycles a division.
Monkey's Audio divides two or three times a sample in its range
decoder and, without codec IRAM, does it in C. On a Clip+ it is
11% to 21% slower than 3.14 was, with over half of -c1000's decode
in __udivsi3. MP2 is 4% to 7% slower.
Put libarm_support back, ahead of libgcc. In perfsim's model of
the Clip+ a division falls to 44 cycles, Monkey's Audio by 38%, 30%
and 22% at -c1000, -c2000 and -c3000 (60.9 to 37.9 MHz at -c1000),
and MP2 by 3% to 7%; nothing else moves by more than 0.6%. A Clip+
decodes -c1000 with the same checksum as before.
A division by zero in a codec goes to __div0 again, and so to the
firmware's handler, as it did with support-arm.S and with the old
libgcc (3.14's ape.codec calls it). The gcc 9.5 libgcc returns
from its own stub instead.
Change-Id: I6a9a79ce8e85bca69870349a5c0823f392a578b6
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CabbieV2 had an FM screen only for the 160x128 and 128x128 greyscale
targets. Add one for 400x240, laid out like its WPS: station art and
names where the album art and track info are, the frequency in the
progress bar, Scan/Preset, MHz and Stereo/Mono below it, and hold,
battery, volume and signal strength along the bottom.
Both screens share one backdrop, its header bar empty: each draws its
label, NOW PLAYING or FM RADIO, in Helvetica Bold rather than having it
painted into a backdrop of its own. The shuffle and repeat
placeholders, painted into the old WPS backdrop, are images drawn
while those are off.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I0331184479589cd4953bd78f4ead336f5d9b6fea
A theme's own font is converted into the build; fonts its skins load
themselves with %Fl were not, and needed the font package - or the
skin fell back to another font. Convert those as well, the way the
images a skin uses are copied with it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: Ifb698f7417287954130be9b466fe3b2248c5c773
make install skipped every wps/ subfolder whose name has a dot in it:
the test meant for "." and ".." matched a dot anywhere. A theme named
with one lost its images.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: Ic225960349e5d73ae4defa7524fa2cee5066e920
Entering the FM screen with no presets asks whether to scan for them.
The question and the scan clear the screen, after fms_fix_displays()
had shown the skin's backdrop, and nothing showed it again: the skin
redraws only its viewports, so the backdrop stayed missing everywhere
else - the header bar of CabbieV2's FM screen among it.
Leave the FM screen for the question and the scan and enter it again
after, as for the other screens shown from it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I7caadf3ac2a03f2825176084d8969ae6e59af471
The results were drawn right after backlight_on(), which only queues
a request to the backlight thread. lcd_update() does nothing while the
LCD is off, and the plugin then blocked waiting for a key without
updating again, so the display could keep showing the last progress
line. Refresh the display periodically while waiting for a key.
Also scroll the log up when the screen is full instead of wrapping
around to the top and overwriting old lines, which made the output
hard to read when testing a whole folder.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Regression introduced in f87ff3a9b, which made it possible for audio
playback to request a freq under 44.1KHz, instead of treating 44.1 as
a floor (and upsampling)
However, there is a report of 22KHz files playing back distorted on an
imx233 target.
IMO a 44KHz floor is reasonable, but this bug is a symptom of something
deeper. Perhaps the mp3 codec isn't doing the right thing, or there's
an issue in the pcm mixer somewhere, or the imx233 codec doesn't properly
handle 22KHz? Further investigation is warranted.
Change-Id: I751ce05f8605de7f90d3eb7b3c98873487df438b
The frame decoder reads from one flat buffer and cannot refill it, but
request_buffer() only guarantees 32KiB of contiguous data (the buffering
guard area). Frames that can be larger than that, such as high
resolution or poorly compressible streams (FLAC decoder testbench file
31), could be handed to the decoder truncated, which read past the end
of the data and lost sync.
When a request returns less than the largest frame the stream can
contain (STREAMINFO max framesize, or a bound from block size, channels
and bit depth) and it is not the end of the file, copy the frame into a
private static buffer and decode from that. Streams whose frames always
fit never touch the buffer and pay one comparison per frame. The buffer
is 64KiB, or sized for the 4608 sample blocks of memory limited targets,
and is left out entirely when MEMORYSIZE is 2MB or less.
Also fail with a codec error, instead of advancing past the data, if a
decoded frame consumed more bytes than were provided.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Change-Id: Ib4cf85ad513f8e096f73d13b4374d072e1745cb2
On colour targets the image viewer hands every file its own decoder
rejects to jpegp, including damaged ones, but jpegp barely checks its
input. Corrupt and truncated files crashed or hung it:
- At the end of the file GETC() kept returning stale bytes, so marker
searches and table reads never ended. Feed EOI markers (FF D9)
instead, which ends every loop, and stop calling read() there. This
state is reset in OPEN(): the overlay loader does not clear .bss.
- A file ending before any scan decoded as a blank image. Report it as
corrupt instead.
- Out of range header values were used as array indexes: Huffman and
conditioning table IDs, Huffman table sizes, sampling factors, scan
component counts and spectral selection. Reject them, and frames of
zero width or with no components.
- Invalid Huffman codes walked past the code length table, run lengths
wrote past coefficient 63, and huge coefficients indexed past the
IDCT clamp table. Bound all three.
- An odd DAC segment length never ended its loop.
- The coefficient buffer size could overflow an int.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I49465f38d283e159274d2f381029280cea42a8f1
- uisimulator/bitmaps/UI-samsungypcp3.bmp: the YP-CP3 from the front,
614x324, the 400x240 screen at 40,37. Dithered to RGB565: the
simulator converts its background to the 16-bit LCD format, which
turned the case's gradients into bands.
- sim-ui-defines.h: its window and screen position
- buttonmap/samsung-ypcp3.c: the YP-R0's keyboard layout - the
YP-CP3 shares its keypad - and click areas for the joystick, Back and
Menu below it, and User (Rec) and Power on the top edge above them
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I9146fd54400d85636a97509993b393bff8b1ab78
Accomplish this by checksumming the english language input
and (1) including that in binary files and (2) checking the
value matches what was compiled into the firmware image
Not sure if this is the best approach but it works.
Change-Id: I8f79ad1b9d1cdf69e6a085d7b3dd1b5e078af04b
jpegp converted every image from YCbCr, so RGB JPEGs showed scrambled
colours. That affects progressive RGB files, and now also baseline RGB
files the jpeg decoder rejects and hands on to jpegp, such as RGB with
the R component sampled 2x2.
Record the JFIF and Adobe APP14 markers, decide the colour space with
the same rule as the other decoders, and skip the YUV conversion for
RGB.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: If023eeb612b7f8a891d21fbe0070ab43c5a08f17
Both decoders treated every 3-component image as YCbCr, so RGB JPEGs
(as written by cjpeg -rgb, and by some Adobe software) came out with
wrong colours.
Decide the colour space as libjpeg does: a JFIF marker means YCbCr;
otherwise the transform flag of an Adobe APP14 marker decides (0 is
RGB); otherwise component IDs 'R', 'G', 'B' mean RGB.
Core loader: on colour targets R, G and B are stored in place in the
row buffer and the YUV conversion is skipped. Greyscale builds now
also decode G and B for RGB and combine them into luma per block,
which needs every component to be one block per MCU; other RGB
layouts are rejected there.
Plugin: RGB needs one block per MCU for every component, otherwise it
is rejected (colour targets fall back to jpegp). Colour builds convert
the R, G and B planes to YCbCr in place after decoding, so display and
greyscale view modes are unchanged; greyscale builds combine R, G and
B into luma per block as the core does.
Code size on the e200: core loader +351 bytes, plugin decoder +603
bytes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: Ib24a0b7690ca4c00b3ac01b2f511309efeac5975
This allows fonts, backdrops, and wps/fms/sbs to be checked.
Note that while settings _names_ are validated, the _values_
can not always be checked. Detectable settings errors
are flagged, but are not considered fatal.
Change-Id: I2a2b7ad94462e983345a1e692eccd6bd57e90eb9
The YP-CP3 shares the YP-R0's keypad and so its plugin keymaps; with
the 400x240 screen handled every plugin builds.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I516ab057c081e710cbc1cf6eca2b24ee87231244
Seven plugins have no layout or bitmaps for a 400x240 landscape
screen - the Samsung YP-CP3's, which no target building plugins has had
in that orientation. Give each the 320x240 one: the same height, and
centred in the 80 pixels more width wherever a 320x240 background has
to line up with it.
- bubbles, invadrox, rockblox: the 320x240 layout and background,
centred; the margins are cleared
- sudoku, jewels: the 320x240 bitmaps; their layouts already centre
themselves or use the width
- superdom: the 320x240 box size and board items - boxes as wide as
the screen allows make the board taller than it
- wormlet: the sizes of 320x240
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I223154da5da2250ba0f6068106ba9bec242a29ee
Five layouts define SCORENUM_Y as SCORE_Y + (...) unbracketed, so the
playfield update after each frame, PLAYFIELD_Y + 1 - SCORENUM_Y -
FONT_HEIGHT high, added that part rather than subtracting it: on a
240-line screen it ran 25 lines past the bottom. Most LCD drivers clip
it; the rk27xx one did not, and nothing in the playfield moved.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: Icecf7780d81595db9d6e42125fc421cc1cb40339
The LCD controller's CSn/WEn/RDn strobes count bus clocks, set once for
1-4-1 clocks: a 120 ns write cycle at the 50 MHz bus clock, but 60 ns
when the CPU is boosted and the bus runs at 100 MHz. That is too fast
for the Samsung YP-CP3's panel: with the CPU boosted it showed stray
pixels, and partial updates left tearing behind moving things - the
boot logo too, as the firmware boosts before lcd_init().
Double the clocks while boosted, 2-8-2, which keeps the write cycle at
120 ns: set_cpu_frequency() switches them before raising the clock and
after lowering it, and lcd init picks them for the clock it runs at -
the bootloader stays at crt0's CPUFREQ_MAX.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I482073c16af39c6b1856a0e18d19a747c78975f0
lcd_update_rect() waited on the channel's CTL_L LLP_DST_EN bit, which
the last descriptor has clear: it clears when the last block is
loaded, not when it is done. The update returned with that line still
being read, and the next one reprogrammed the window and the channel
under it.
Wait for the channel to disable itself, which it does after its last
block.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: Icf9314fbe40b8ea53a7f5f24ea11513e87a54cf6
lcd_update_rect() took the rect as given. One reaching past the screen
set a GRAM window off the panel, so the update showed nothing, and
built one DMA descriptor per line into scr_llp[LCD_HEIGHT] - past its
end for a rect taller than what is left of the screen. What follows
scr_llp in memory is the PCM driver's locks and then all_queues, the
kernel's queue list: a later broadcast posted to garbage.
invadrox asks for such a rect every frame. On a Samsung YP-CP3 nothing
of its playfield moved - aliens, bombs, the ship - and powering off
afterwards took a data abort in queue_post() from interrupt context.
Clip the rect to the screen, as other targets do, and do nothing if
nothing is left. Every rk27xx screen is a multiple of 4 pixels each
way, so aligning the clipped rect to 4 cannot take it past the edge.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I1f8bf865251859cd223e208a807c9a9da76a0ba0
Damaged and truncated JPEGs could make the image viewer read or write
outside its buffers:
- process_markers() trusted segment lengths, and Huffman table symbol
counts, so a segment running past the end of the file was parsed
from whatever memory followed it. Check that each marker segment,
and each Huffman table in it, lies within the file.
- A file without a complete SOS header was decoded from a NULL entropy
data pointer, as load_image() checked only for DQT and SOF. Require
SOS as well.
- img_mem() computed the image size in an int, which overflows for a
large image (a 65535x65535 file came out as 0), so the decode wrote
far past the buffer. Compute it in 64 bits and saturate.
Found with the jpeg-conformance files of the imazen codec-corpus,
which include truncated files and files from fuzzing.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I1e2a9a4346fd1c0e34b0813267c6317dbf704bc7
Every program waited out its tPROG, about 0.8 ms on the Samsung
YP-CP3, before returning. Over USB mass storage that wait comes before
the status of each write command goes back to the host, and so before
the host sends the next one: nothing else runs during it.
Return once the program is started, WP# still lifted, and finish it -
wait, check the status, restore WP# - at the next chip access, or at
flash_sync(), which ftl_sync() calls. A program's result then arrives
with the next flash call; no caller checks flash_program()'s. A copy
still reports its own programs, the last one included, as the FTL
moves the data elsewhere when one fails.
On the YP-CP3 the NAND wrote at 3.64 MB/s; now 4.37 MB/s, against
4.35 MB/s in the original firmware, every read verified, also after a
power cycle.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I8de01f8be052e5d3ff06f550c614865fb1946f05
copy_sectors() copied one destination raw page at a time, so on a
two-plane part every page of a copy took two programs and two tPROG.
Its buffer already holds a page of every plane: copy that much at once,
and flash_program() programs the planes together.
Copies are most of the programs when the FTL closes blocks that random
writes left part written. Over USB mass storage on a Samsung YP-CP3 a
stress test that ran 66792 one-plane programs ran 692 now, with 43958
two-plane ones, and its program time fell from 85 s to 59 s.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: Icc60d250ecc75c83c2d817efb7678333bffe3137
Every sector of a read was transferred from the chip into a controller
slot and then copied out of it, the next transfer starting only after
the copy. Start it before: it goes into the next slot, not the one
being copied.
On the Samsung YP-CP3, same test: reads at 8.25 MB/s, the original
firmware's speed, every read verified, also after a power cycle.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I53f77ea3c00bb449d772357e39602cca9c5cdba3
flash_init() sets FMWAIT to 0x1081, as the OF's FlashInit() does, and
nothing changed it after. But the OF, and the Samsung YP-CP3's NAND
bootloader, follow it with FlashTimingCfg(), at every bus clock
change: from chip 0's access time and the bus clock it derives a
timing that, for the YP-CP3's 25 ns Samsung part at 100 MHz, is 0x60
- by the RK28 controller's register layout, under half the bus cycles
per byte.
Do the same once chips are detected, for 100 MHz: the AHB runs at
CPUFREQ_MAX / 2 or slower, where the value only gains margin.
Over USB mass storage on the YP-CP3 the NAND read at 5.70 MB/s and
wrote at 3.26 MB/s; now 6.83 and 3.65 MB/s, every read verified, also
after a power cycle.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I356214c5d10e65952abc3334f5fae5deb2e02cff
usb_drv_exit() masks the UDC interrupt in the interrupt controller at
every disconnect, but only usb_init_device(), once at boot, unmasked
it. After the first unplug the UDC raised no more interrupts: on the
next plug the charging icon showed - plug detection polls VBUS_STS -
but the host's reset and requests went unanswered, so the device never
enumerated and the USB screen never came up.
Unmask it in usb_drv_init(), which runs at every connect, so that it
pairs with the mask in usb_drv_exit(). The interrupt is now masked
while USB is off, at boot too; nothing needs it then.
Tested on a Samsung YP-CP3: it enumerates at every replug.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: Iab7b7e93c140990c39b0e6dfae23ffcc829f6ab2
Every sector of a write waited for the previous sector's transfer to
the chip before it was copied into a controller slot, so the copy and
the transfer never ran together. The slot the copy goes to is not the
one in transfer: copy first and wait only before the BCH engine and
the transfer restart.
On the Samsung YP-CP3, same test: 3.26 MB/s, every read verified, also
after a power cycle.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I41f43658916891a2ded74bbe21b6970f7cc78068
On a two-plane part an FTL page spans the same page of two blocks, one
in each plane, and flash_program() programmed them one after the other:
two program busy times (tPROG) per page. The original firmware's
FlashProgEnhanced() programs both with one two-plane program - 80h, the
first page, 11h, a wait of tDBSY, 81h, the second page, 10h - so the
planes share one tPROG.
Do the same where the runs of a write cover the same page of both
planes, on parts that take 81h for the second page. The original
firmware sends 80h there on Toshiba and Micron parts, which address
the planes differently too; those still program a page at a time.
enum vendor_t moves to nand-target.h for the check.
Over USB mass storage on a Samsung YP-CP3 the NAND wrote at 2.22 MB/s,
against 4.35 MB/s in the original firmware; now 2.86 MB/s, every read
verified.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I2f40e2ec426cf787b4ce452cbd0d0eb4b702e168
flash_read() latched the page afresh for every sector. The controller
streams a page from its first sector, so each sector also cost a
transfer of every sector before it in the page: reading an 8-sector
page sector by sector took 8 array loads and 36 sector transfers
instead of 1 and 8. Over USB mass storage on a Samsung YP-CP3 the
NAND read at 1.87 MB/s, against 8.25 MB/s in the original firmware.
Read each run of sectors that lie consecutively in one raw page with a
single latch. On a two-plane part a run of FTL sectors stays in one
page until it moves on to the other plane.
On the YP-CP3, same test: 5.64 MB/s, every read verified.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I9b08e56f4429ae432ccd2d2e23b9b34c18e56e97
Firmware builds reprogram the SDRAM controller twice. system_init()
sets burst 8, T_RP = T_RCD = 1 and the refresh, with CAS 3 since
a6538abd16 - CAS 2 on HM60X/HM801. And set_sdram_timing(), on every CPU
frequency change, rewrites the mode: CAS 2 whenever the AHB runs at
100 MHz or below, which is every clock this code sets.
On a generic rk2705 the firmware hangs in system_init() on those writes;
with them skipped it boots. Doing the same writes from IRAM, so that
nothing touches the SDRAM while the controller reprograms the chip,
hangs the same way: it is the settings themselves. The board's SDRAM
is an Elpida EDS1216AATA-75 (16 MB), a 133 MHz part at CAS 3 whose
minimum clock period at CAS 2 is 10 ns - exactly the 100 MHz it runs
at here, with no margin, next to minimal T_RP/T_RCD.
On a Samsung YP-CP3 the firmware boots but corrupts memory at random
once the clock first changes: data aborts on valid addresses in
unrelated code, undefined instruction exceptions on valid instructions,
glitches in the boot logo, crashes on USB plug and unplug. A memory
test over 15 MB passes with the boot's setup (CAS 3, burst 1,
T_RP = T_RCD = 2) and with system_init()'s values alike - it never
changes the clock - and skipping only the system_init() writes is not
enough, as set_sdram_timing() still selects CAS 2. With both removed
the YP-CP3 runs, passes a USB mass storage stress test and survives
USB unplug.
The boot ROM's and the bootloaders' setup works on every rk27xx target
seen, and nothing before Rockbox changes it (the NAND bootloader's
stage 1 and rk27load's s1 only probe the organisation). The gain
claimed for the tweak was a slight improvement in memory throughput.
So remove it for every rk27xx target, the HM60X/HM801 CAS 2 included,
and have set_sdram_timing() adjust only the refresh to the bus clock.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: Icd063367783b0ae6eb80bad67d908269c07e704f
Every SD write failed. The card took the write command and went to
receive-data state, but never saw the block: CMD12 still found it there,
and the controller reported a missing CRC status after each block, 20
retries over. Reads worked. Stress-tested over USB mass storage on a
generic rk2705, with a SDHC card, in the normal firmware and in the
bootloader alike.
sd_init_card() switched the card to high-speed mode with CMD6. This host
is an SD 1.01 controller with a card clock of at most 25 MHz, per the
rk27xx datasheet; high speed and CMD6 came with SD 1.10, and a card
switched to it evidently does not take the data this host drives. The
original firmware never switches: after selecting the card it sets the
block length and a 1-bit bus and stays at default speed. A slower card
clock did not help; dropping the switch alone did.
Leave the card at default speed. Tested on a generic rk2705:
ums_stress.py over a 32 MiB window of the card - fill, verify, edge
sizes, a mixed read/write soak - passes at 2.3 MB/s writing and reading,
about 75% of what a 1-bit bus at 25 MHz carries.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: Icfafab0bb460c8c0fda3dea455df9a36622bf764
When all three components share 1x2 or 2x1 sampling there is no chroma
subsampling, but each interleaved MCU holds two blocks per component.
The core loader assumed one chroma block per MCU, so these files (the
folder.jpg in the original report) decoded to garbage and have been
rejected since chroma sampling is validated.
Lay out the MCU generically in fix_headers(): each component's H x V
blocks in turn, with a per-block position that places chroma blocks
with the same offsets as luma. The MCU size and decode buffer now come
from the luma sampling in colour builds too, and the chroma IDCT scale
from the luma:chroma sampling ratio, which is unchanged for 1x1
chroma. The unused subsample_x/y fields are removed.
All other layouts decode byte-identically to before at every scale.
The new layouts decode byte-identically to the same image encoded as
4:4:4. Code size drops by 108 bytes on the e200 and struct jpeg by
20 bytes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I63a894d6609e56f3553a902afd6278ce70e04637
Both JPEG decoders accepted several baseline layouts they cannot decode
and produced garbage without an error:
- chroma with sampling factors other than 1x1 (the MCU layout is chosen
from luma alone, so any other chroma layout desynchronises)
- files written as more than one scan, where the first scan does not
hold every component (it was decoded as if it were interleaved)
- scans whose components are not in frame order
- a height of 0 in SOF, to be defined later by a DNL marker
Reject these in process_markers(). The imageviewer then falls back to
the jpegp decoder on colour targets, which handles all of them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: Ia3373f2b934eef6e3f354b4d064faf2d89868050
Both JPEG decoders ignored the Tq selector in the frame header and
always dequantized luma with table 0 and chroma with table 1. Files
with a single shared table multiplied chroma by an empty table, and
files with separate Cb and Cr tables used the wrong one for Cr.
imageviewer/jpeg: build one dequantization table per component (3
instead of 2, +256 bytes) from the table it selects. tab_membership is
no longer used and is removed.
Core loader: the raw tables are pre-scaled in place for the IDCT, and
luma and chroma can use different IDCT scales. fix_quant_tables() now
maps each component to a table slot, copying a table that luma and
chroma share at different scales to a slot no component uses (there are
4 slots and at most 3 components, so one is always free), and rewrites
quanttable_select to that slot. No extra memory.
Selectors above 3 are rejected.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: If04c61fb0fef95da11d98d9918ea7225d8a440b0
Both JPEG decoders ignored the DC/AC table selectors in the SOS header
and always decoded luma with tables 0 and chroma with tables 1, the
layout libjpeg writes by default. Files where all components share
table 0, or where the slots are assigned differently, decoded to noise.
Look up each component's tables from its selectors instead. Baseline
JPEG only allows tables 0 and 1, which both decoders already hold, so
this needs no extra memory; selectors above 1 are rejected. In the core
loader tab_membership is no longer used and is removed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: Ie1ec407ddecf1256fef410b1256b97af412fb194
The bit reader refilled from the input buffer without checking its end.
The end-of-data check in the decode loops only runs once per MCU row, so
a stream that desynchronises (or is truncated) read past the end of the
file buffer for the rest of the row. Return zero bytes past the end
instead; the pointer still advances so the per-row check stops the
decode.
Found with AddressSanitizer on a JPEG whose chroma is sampled more
densely than its luma.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: Iaada1bc3cbf62b18f10fb2377c12d4d5cb9524de
config.h defines HAVE_STORAGE_FLUSH for the rk27xx Scheme A FTL when
CONFIG_STORAGE has STORAGE_NAND and CONFIG_NAND is NAND_RK27XX. sim.h
undefines CONFIG_NAND but keeps CONFIG_STORAGE, so a simulator for a
NAND target - the iPod nano 2G - evaluated the undefined macro:
"CONFIG_NAND" is not defined, evaluates to 0 [-Wundef]
Test that it is defined first.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: Id1e328f08c14d7c5528d29f110fdbb8be68ab2f5
The debug menu tests CONFIG_NAND == NAND_RK27XX to include the FTL
scheme finder. Most targets do not define CONFIG_NAND at all, so every
native build but rk27xx's warned twice:
"CONFIG_NAND" is not defined, evaluates to 0 [-Wundef]
Test that it is defined first.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I82a1e8fa2f09aac1c5f0d746fb6d475e389d12d6
CONFIG_RK27XX_FTL selects the FTL a target's NAND uses,
RK27XX_FTL_SCHEME_A or RK27XX_FTL_SCHEME_B. rk27generic and the YP-CP3
are Scheme A, the HM-60x Scheme B. ftl-rk27xx.c mounts the one named;
for Scheme B it maps the drives onto the volumes ID block 1 records:
the system disk from LBA 0, the user volume after the system data
area.
The other rk27xx targets with NAND - HM-801, MA8, MA8C, MA9, MA9C and
iHiFi 760, 770, 770C, 800, 960 - have no confirmed scheme. They drop
the NAND from storage and build only the FTL scheme finder, so users
can report what their device holds and the scheme can then be set.
Only Scheme A flushes at shutdown: Scheme B holds nothing in RAM.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I484217b82c6de7316b90b354c012bfbaa263b3dd
Many rk27xx targets have NAND whose format nobody has examined. The
finder reads ID block 1 and the first page of the first 512 blocks and
says which FTL formatted them: Scheme A by its remap-log blocks,
Scheme B by its bad-block table and data headers, another Scheme B
generation by other 0xFxxx tags. The later ID block layout ('RK27' at
0x0a) records the FTL area's BCH strength at 0x1ed - 8 on the HM-601,
14 on the Archos Vision 28 - and the scan reads in that mode.
It is read-only, shown in the debug menu as "View FTL scheme", and
built for targets whose NAND is not storage - none yet.
Run on dumps of an HM-601 it reports Scheme B, a Samsung YP-CP3
Scheme A, and an Archos Vision 28 the other Scheme B generation.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I0528f9d2a6996089b6488a77b43942f6fd1f2c16
Scheme B is the self-describing NAND format of the HiFiMAN HM-601 and
similar players: every block carries its logical number and a version
in its metadata, so the mapping is rebuilt by a scan at mount, and
small writes go through a 16-page RAM cache journalled to flash.
ftl-scheme-b.c is a reimplementation from reverse engineering. The
format and the behaviour were worked out by analysing the machine code
of the HM-601's NAND bootloader and of a compiled Rockchip FTL object
from the rk2808 platform, which handles the same format, and checked
against dumps of the media; no source code was used. Where the two
binaries differ the HM-601 is followed: 16-bit versions compared
across wrap, plain 0xF200/0xF100 tags, a copy that stamps one header
on every page. The number of open exchange blocks is configurable - 8
on the HM-601, whose mount recovers no more.
Checked by running the compiled object under qemu over a NAND
simulator, side by side with this code, on a 4 GiB HM-601 dump: the
same state after mount, identical reads of all 3958 logical blocks,
and flash programs and erases identical one for one - over 600 random
writes on each of three seeds and at every power-cut point of three
sweeps, 1435 points - with 0 wrong sectors.
Not built yet: no target selects it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: Icb935ea78d716c1e51f1453fc3ab3f47f3467027
The controller has a second ECC mode, BCHCTL bit 13: t=14 instead of
t=8, over the same field and polynomial. Some firmware writes its FTL
area in it - the Archos Vision 28 does - while every boot area seen is
t=8.
flash_set_ecc() selects the mode for reads and copies of the FTL area;
flash_read_raw(), which reads the boot area, stays at t=8. Writing is
refused in t=14 mode: a t=14 sector is a 538-byte record on the media
(3 metadata and 23 parity bytes), the program path addresses 528-byte
records, and programming in that mode has not been tried.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: Iaf4ce9274b72838b7719232fc49cdce0cceecbac
The flash layer writes 0x00 into metadata byte 1 of every page it
programs, which is how Scheme A tells a programmed page from an erased
one. Scheme B keeps a 16-bit field in bytes 0-1 of every sector - its
block tags, versions and block numbers - so it needs the byte as
written.
Add flash_set_meta_passthrough() to turn the forcing off, and
flash_copy_meta(), a copy that either keeps each sector's own metadata
or programs a page of it given by the caller: Scheme B's copy stamps
one header on every page it moves.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I49b2c24d812284af2c50d776f0942b5b1b989c98
The NAND holds two volumes, SYS and USER; the split is recorded in the
boot area, so they are separate drives rather than partitions of one.
SYS is hidden: nothing in it is the user's, and deleting or overfilling
it stops the device booting. HAVE_RK27XX_NAND_SYS, documented in the
config and off, brings it back as a drive of its own.
storage.c numbers drives by driver, SD first:
default HAVE_RK27XX_NAND_SYS
drive 0 SD SD
drive 1 NAND USER NAND SYS
drive 2 NAND USER
NUM_DRIVES was 1, which was already wrong for a target whose
CONFIG_STORAGE names both SD and NAND.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: Ic68921838faef0ff6fd296d43e86ec3a10a091c5
ftl-rk27xx.c has been four empty stubs since 2010. Fill them in with
the flash translation layer the rk2705/rk2706 original firmware uses,
called Scheme A here to tell it from the log-structured layout of later
firmware. It reads and writes that format exactly as the original
firmware does, so a device keeps working with its original firmware
after Rockbox has written to it.
- ftl-scheme-a.{c,h}: the FTL. The file opens with a description of
the on-flash format and how the FTL works: the SYS and USER volumes,
super-blocks and zones, the zone table, the remap log and its mirror,
the exchange record and the write protocol, power-loss recovery, bad
blocks. Oddities of the original firmware kept for compatibility are
marked where they are.
- Parameters that differ between firmware builds - the zone reserve
base, the system zone offset, the format flag - are recovered from
the media at mount and checked against its structure; a mount that
cannot confirm them is read-only. A mount that would have to repair
the remap log while not allowed to write fails rather than serve
wrong data.
- ftl-rk27xx.c: the storage glue. It finds the boot area's ID block,
which records where SYS ends, and mounts the FTL.
- ata-nand-rk27xx.c: a drive per volume. SYS holds the original
firmware - on a Rockbox device including the BASE.RKW that chainloads
the bootloader - and nothing of the user's, so it is a drive only when
the target defines HAVE_RK27XX_NAND_SYS. Capacity comes from the FTL's
tables, not from raw block geometry.
- config.h: HAVE_STORAGE_FLUSH for the rk27xx NAND. The FTL holds up to
three part-written pages in RAM; storage_flush() commits them at
shutdown and ROLO.
Writing is opt-in: without FTL_ALLOW_WRITE the FTL mounts read-only and
never writes the flash, not even a repair the mount could make.
Two bugs of the original firmware are not reproduced. A write starting
before a page held part-written in RAM and running through it left two
buffers holding that page, and the older one was later programmed over
the newer data; such a write now flushes the held page first. And its
bad-block marker took two of its three metadata bytes from the stack,
which can make a retired block look like a remap-log block; the marker
is now written in full.
Tested in a host simulator on NAND images of a Samsung YP-CP3 and a
generic rk2705, against the original firmware's FTL object run under
qemu-arm: identical traces of every read, program and erase, with a
hash of the data each program writes, over mounting and reading, random
writes with every sector verified, a power cut at every flash operation
of a write, and a program or erase failure at every one.
On a generic rk2705: the read-only mount reports the layout and
capacities the original firmware does and every file's MD5 matches; a
write test passes 8192/8192 across a remount and a power cycle.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I573d944389cefb456ecf38c6c7b91bebfe0fe377
system_init() gates the clocks of modules a firmware build does not use,
and the list included the NAND controller's HCLK. Once the NAND is
storage, the first access to the controller - flash_init() writing
FMWAIT at 0x180e8004 - takes a data abort on the unclocked peripheral.
No rk27xx target stored to NAND before, which is why this never showed.
The LCDC clock in the same list stays gated: the firmware draws with it
gated, the MCU interface running from the LCDC HCLK, which is not.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I52a4dc9e63fe5b89c85b60dc3ef77d74528dc06f
flash-rk27xx.c drives the NAND controller and its BCH engine for the
flash translation layer that follows. It knows the chip's geometry and
how to read, program, erase and copy sectors, but not what the sectors
mean.
- Addresses are 512-byte sectors in a linear view of the chip where a
block is a super-block: on a two-plane part, one physical block from
each plane, consecutive pages alternating between them. The layer
maps that view to the chip; the FTL never sees planes.
- Every sector carries 16 spare bytes: 13 of BCH code, generated and
checked by the hardware, and 3 for the FTL. Byte 1 is written 0x00 on
every program - the "page programmed" marker the original firmware's
FTL keys its mount and recovery on.
- The program sequence was read out of the original firmware's own
machine code. The write kick is the read kick plus FL_WR, and the BCH
engine needs BCH_WR to encode rather than decode.
- A copy is read through the ECC engine and programmed, never the
chip's internal data move, which on this MLC part would carry bit
errors forward.
- Writes are refused until the FTL enables them, and writes into the
boot area are dropped and reported successful, as the original
firmware does. The write-protect line is lifted only for the duration
of each program or erase.
- Failures and timeouts are counted: the FTL can act on few of them.
Only the first chip is handled; every device the FTL has been checked
on has one.
Tested on a generic rk2705 directly, on a free block: a program across
both planes, a single-sector program with metadata, a whole page, a
copy and an erase each read back byte-exact through the controller's
ECC decode, which also shows the code it generated is valid.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: If6ffa9f9811172f4f8829c1e68d6de9466a022c8
flash_init() identifies a chip by looking its READ ID device code up in
device_code[] and taking the capacity from device_info[] at the same
index. device_code[] had seven entries and device_info[] eight: 0xd5
(16 Gbit) was dropped when the table was transcribed from the OF. Every
code after the gap picked up the capacity one row up, so a 0xd7
(32 Gbit, 4 GiB) part was sized at 2 GiB.
On a generic rk2705 that halved total_phy_sec to 4194304, and the FTL
looked for its tables in the wrong place and read erased flash. With the
entry restored it reports 8388608, matching the chip and the host-side
dump of the same unit.
The OF's own table, as it appears in its NAND bootloader:
76 79 f1 da dc d3 d5 d7 00 00 02 00 00 00 04 00 ...
A compile-time check now fails the build if the two tables differ in
length again. Also fixes two register addresses in the same loop that
were missing a digit (0x180E204/0x180E208 for 0x180E8204/0x180E8208);
they are stored for reference only and nothing reads them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: Ia70c249eea2e44ea34aef52d8ae20860b2b5db9d
nand-rk27xx.c held a complete transcription of the OF's NAND handling -
chip detection, geometry derivation, chip select, ECC reads - inside
"#if 0", written as documentation back when the FTL was still unknown.
It has therefore never been compiled.
Enabling it exposed three things nothing had ever caught:
- flash_init() looks up ManufactureIDTbl[] and DeviceCode[], but the
tables are named manufacture_id_tbl[] and device_code[]
- mlc_refresh_row, flash_pend_cmd and flash_read_status_cmd are
assigned but were never defined
- memcpy() was used without including string.h
struct flashspec_t moves to nand-target.h, with flash_spec[] and
total_phy_sec declared there, because the FTL's flash primitives need
the geometry flash_init() derives. The "_raw" fields describe one
physical plane and the others the multi-plane view the FTL addresses;
that distinction is load-bearing for the FTL's address mapping, so both
are kept.
flash_read_page() is renamed flash_read_page_raw(). It reads a whole
page unbuffered and without ECC, and the name is needed for the FTL
primitive that does the ECC read.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Change-Id: I3eb2d6f41d72b3239a0f9493e49532c242c588fa
BCHCTL bit 13 and the whole of BCHST were marked unknown. Both are
needed by any driver that reads NAND through the controller's ECC
engine: a read has to be able to report an uncorrectable sector, and MLC
parts want a refresh once a sector needs enough correction.
BCHCTL bit 13 ECC strength, clear = t=8, set = t=14 (both m=13,
poly 0x25af). Established by decoding both modes
against real media until the stored ECC bytes
reproduced.
BCHST bit 0 result valid
bit 2 error - uncorrectable when set together with bit 0
bits 6:3 number of corrected bit errors
Taken from the rk2705 NAND bootloader's ECC read loop:
tst r0,#1 ; tst r0,#4 both set -> sector uncorrectable
lsl r0,#25 ; lsr r0,#28 -> (BCHST >> 3) & 0xf, corrected bits
cmp r0,#3 >= 3 triggers a block refresh
The threshold agrees with MlcRefreshHook in the Samsung OF's flash.o, so
two independent firmwares say the same thing.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Change-Id: I1e356d5510827b46035f1d7d4a2cc69f4e83f43f
At a CELT to hybrid mode switch, opus_decode_frame() runs CELT's pitch
PLC nested in the new frame, and celt_decode_lost() held a copy of up to
2 KB of excitation for celt_fir(). On stackOverflow.opus that overran
the 9 KB codec stack on native targets such as the e200v2. Filtering in
place from the last sample down needs no copy; output is bit-identical.
Worst case over all 242 mode switches of stackOverflow.opus, measured
under qemu: 9140 -> 7676 bytes below opus_decode(), against 8912 left
for it on the e200v2.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: Iaa9f57182ad86ab76c81c55bea72aa517cc18230
commit_discard_idcache() invalidated both cache ways while running from
cached SDRAM. When the loop polling for the invalidate to finish starts on
a cache line of its own, it is fetched through the ways being invalidated
and the CPU takes a data abort, reported at the loop's branch. Whether it
crashed thus depended on where the linker put the function.
usb_storage calls it on every USB connect. On rk27generic a jpeg change
that grew clip_jpeg_fd by 8 bytes moved the loop onto a new line, and the
firmware crashed as the USB screen came up, with an empty backtrace.
Turn the cache controller off around the invalidate, as crt0.S does at
start-up. The cache is write-through, so no data is lost.
Tested on a generic rk2705 with the function padded so the poll loop starts
a new cache line: without this change it crashes at the first USB connect,
with it the device enumerates as a mass storage device. The normally
linked build works too.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I319b811fdef30717999b60132000e70f410001fc
The rk27xx UDC driver was fixed and stress-tested on a generic rk2705
against the USB core of early 2026 - including a port to the control
request API of that time. Meanwhile the core took over the EP0 state
machine (usb_core_setup_received()) and endpoint allocation, and the
driver was converted to both without the fixes. This carries them over.
Transfers and resets (a mass-storage stress test fell off the bus after
10,000 - 27,000 operations without these):
- Transfers are set up with interrupts disabled: the interrupt handler
advances buf/cnt of the same endpoint for the next packet.
- ep_write()'s wait for TXFULL to clear is bounded by an iteration count.
It also runs in the interrupt handler, where current_tick never
advances, so a tick timeout spun forever.
- A bus reset cancels transfers - usb_drv_cancel_all_transfers() was
empty - instead of re-initialising the completion semaphores, which
loses a thread blocked on one for good; blocked senders are woken with
an error and the enabled endpoints NAKed and flushed. The reset handler
also calls usb_core_bus_reset(), which it never did.
- Blocking sends time out after a second and report the error.
- An ACK with no transfer armed (one cancelled by a reset) is ignored.
Configuration:
- The configuration number is DEV_INFO [11:8]; it was read as bits 10:7,
bit 7 being DEV_EN, so configuration 1 was reported as 2.
- The UDC completes SET_ADDRESS and SET_CONFIGURATION itself, raising no
interrupt, so udc_helper() - which reports them from DEV_INFO - also
runs from a tick task while the device is unconfigured. After a bus
reset of a configured device the host re-sends SET_CONFIGURATION and
goes straight to a bulk command that NAKs without interrupting: without
the tick, the device never came back.
EP0, with the core now running the control state machine:
- Right after connect the UDC reports one SETUP with both registers zero;
no host sends that, and it is ignored.
- A SETUP clears a stall, and ends - reported to the core as failed -
any EP0 transfer still in flight, which belongs to a request the host
abandoned; otherwise the core would wait for it forever. EP0 stall uses
the EP0 registers, not endpoints[0], a stub without registers.
- Control reads are clipped to wLength and end with a zero length packet
when a short answer fills whole packets.
- The core arms status stages with no buffer; they land in a dummy one.
- A status OUT arriving while the data IN is still going - the host took
less than was offered - ends the data stage too.
- At a bus reset EP0 transfers are dropped silently: the core resets its
own EP0 state.
Tested on a generic rk2705. The transfer, reset and configuration fixes
first against the USB core of early 2026: RAM-disk, NAND and SD stress
tests over USB mass storage, and usbreset recovery. Then the driver as it
is here, on the current core: enumeration, and a mass-storage stress test
of three LUNs at once (RAM disk, NAND, SD) that also passes after an eject
and a cold power cycle.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I1b2d03ca8f688f2a0e7b28ead64b7ab050a0a9e8
The UDC was only ever connected from the interrupt handler, on CONN_INTR.
That needs a cable-insert edge after the stack is up, and there is none
when the cable is already in - booting with it plugged, or taking the
controller over from the ROM loader or hwstub, which leave it enumerated
as a different device. The device then never enumerated.
Connecting from usb_drv_init() would not do either: usb_core_init() calls
it first, before the class drivers are set up and before the core sets its
own state, so a fast host enumerated against state that was then
overwritten and the descriptor read timed out - depending on timing.
Add usb_drv_connect(), which drops off the bus, resets the PHY and
reconnects, and call it from usb_enable() after usb_core_init() returns.
Tested on a generic rk2705, loaded over hwstub with the cable in: the
device drops off, comes back and enumerates as Rockbox.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I372bd6a49594c00909ada0cc43b046178140e755
sd_read_sectors() and sd_write_sectors() take sd_mtx and power the
controller, then check the requested range and return -1 on failure -
leaving the mutex held and the controller on. Check the range first.
With no card present numblocks is 0, so every request takes that path.
Rockbox mutexes are recursive for the owning thread, so the first thread
to touch the SD drive keeps working, and every other thread that does
blocks forever.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I16c2be3bde5c62946fdedaabe115b6c4bc330467
The folded Rice value was unfolded with a signed shift, which is wrong
once it reaches 2^31, and the unary length limit was (INT_MAX >> k) + 2,
about half of what a 32-bit residual can need. Streams with very large
residuals (FLAC decoder testbench file 63) were misparsed, overran the
frame and lost sync at the next one. Unfold as unsigned and derive the
limit from UINT_MAX, clamped to INT_MAX. The fast path is unchanged.
The existing 0x80000000 error check now also works as intended, since
the Golomb reader's error value maps to it. The FLAC spec forbids a
residual of -2^31.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Change-Id: I0bdce9db69e1b30565ecc23126923ba401b7deca
On ARMv5E and later the fixed-phase FIR cycles at 8, 12 and 16 kHz load
two samples a word and take two coefficients a word from a literal
pool; smla<x><y> picks the halves, so an odd-aligned window costs
nothing. Outputs are paired as two interleaved accumulator chains. The
FIR buffer is now word aligned. Generated by
silk/arm/gen_resampler_armv5e.py. Bit-exact; OPUS_ARM_NO_SILK_ASM
disables it, and config.h sets that on M-profile cores.
Measured on the Clip+, silk_5.opus (WB SILK):
20.93 -> 15.84 MHz, -24.3%.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: Ibec71fd52542f768f22e2970c9f8c45118c708b9
On ARMv4 the fixed-phase FIR cycles at 8, 12 and 16 kHz run as adds of
shifted samples rather than multiplies: every coefficient is a constant,
and a shifted add is one cycle where mla plus loading the coefficient is
five or six. Each sample is loaded once per cycle and added into the
two or three outputs it feeds, sharing partial products such as 31x
between them, about 27 adds per output. The kernels are generated by
silk/arm/gen_resampler_armv4.py. Bit-exact; OPUS_ARM_NO_SILK_ASM
disables them.
Measured on the e200v1, silk_5.opus (WB SILK), with the previous commit:
36.31 -> 28.85 MHz, -20.5%.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: Ic1fd5777e91d182248f43954e4b6ae977309dc5d
The FM screen had no actions for the rk27xx generic keypad; give it those
its keymap already maps (menu, play, stop, exit) in radio.c.
The board's tuner is an RDA5807P. It keeps being driven as a TEA5767, in
the chip's compatible mode, as the original firmware does: tuning, seek
and the stereo indicator work so, and the RDA mode would bring nothing
here - this variant has no RDS. Say so next to CONFIG_TUNER.
The tuner's audio is on the codec's line input 1: only that line is
powered and mixed in while the radio plays (RK27XX_CODEC_FM_LINE 1). With
line 2 instead the radio is silent.
Tested on the rk27generic board: manual tuning, seek, stereo indicator and
audio.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I2135ee484705ff0fce6d88e73288d8ed2aec6c2d
audiohw_set_monitor() switched the output mixer from the DAC to both line
bypasses: voice and beeps went silent while the radio played, and a line
nobody listened to was mixed in, with its noise. Both line inputs were
also powered from start-up on.
- the target names the line its tuner is on, RK27XX_CODEC_FM_LINE (1 or
2); both are used where it does not say
- monitoring adds that line's bypass to the DAC instead of replacing it
- the line inputs stay in standby until monitored, and go back after
Only rk27generic uses the internal codec - the other rk27xx targets
have external DACs or codecs.
Tested on rk27generic: the radio plays through the monitored line, key
clicks stay audible over it, and playback is unaffected.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I177fdf605e4d997159898c868b2186c9584eb19a
The 8, 12 and 16 kHz to 48 kHz steps visit only two or three FIR phases
in a fixed cycle, so each set of input samples is read once and reused
across outputs. Bit-exact; OPUS_NO_SILK_FIXED_PHASE disables it.
Measured with silk_5.opus (WB SILK):
e200v1: 36.31 -> 33.38 MHz, -8.1%
Clip+: 21.66 -> 20.93 MHz, -3.4%
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: Icb0f8ded62739dfee1f574e4888a54c778aa3d53
Bootloaders with this change are now able to boot rockbox binaries over
1MB. (1.5MB buffer led to bootloader hanging)
Change-Id: I540bd4146aaa7236df93e74f6f2c69aa32e4a874
The contents of appextra are added to the INCLUDES list, eg:
appextra="recorder:hosted"
will result in this at compile time:
INCLUDES += -I$(APPDIR)/recorder -I$(APPDIR)/hosted
With that in mind,
* 'gui' and 'recorder' have been set for all targets other than
the original charcell Archos. Globally set these instead of
using them everywhere.
* 'hosted' was effectively a no-op and removed entirely.
* 'radio' was specified on a lot of targets that didn't have a radio,
just make it global as well.
The net result is that only the android targets now define 'appextra' in
their configure entry. A future patch will remove the need to specify
the ones that are now global.
Change-Id: I751284cde4785077c54405a8a10be819021e4255
It's not part of the build farm, doesn't have a manual, and isn't
even listed on the www site or wiki yet.
Change-Id: I5fc79d0316717898f16ff794cba114a46472ae8f
- config: HAVE_RECORDING, sources microphone and FM, 8-48 kHz
- wm8751.c: the YP-CP3's own audiohw_set_recsrc(). The rk27xx cannot
send received samples straight back out, so what is heard of an input
goes through the codec's analog bypass - the input PGA into the output
mixers: the radio always, the microphone never. As in the original
firmware, the radio passes the PGA at +12 dB when only listened to,
and the microphone - mono, on RINPUT2 - gets +13 dB boost and is
recorded by the right ADC onto both channels (the original firmware's
noise gate is left out). The HD300's version assumes the microphone on
INPUT3 and headphones on OUT1, and switches OUT2 - the YP-CP3's
headphones - off.
- wm8751.c: the playback-only FM monitor added for the YP-CP3 goes; the
radio is routed by audiohw_set_recsrc() now, as on the HD300
- wm8751.h: DATSEL, which ADC feeds each channel of the output data
Only partly tested on hardware: FM radio still plays, and the recording
screen's peak meter follows the microphone. Not yet tested: a recorded
file played back, recording FM, recording gain range.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I3c25f4333f765d98dddc2fd722c111f8493bbe77
The keymap had no recording screen context, so on the recording screen
no key produced ACTION_REC_PAUSE and recording could not be started; nor
did the FM screen have a record action.
- recording screen: User starts and pauses, held opens a new file;
left/right set the gain of the selected line; Menu opens the settings
- FM screen: User records the radio (FM_RECORD enabled for this keypad)
User is the Rec key on the Samsung YP-CP3, which shares this keypad.
Tested only in a YP-CP3 build, not yet on hardware; the YP-R0 itself was
not built.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I655865d0dcf3e72da4e2d1cba24bc296919ec261
pcm-rk27xx.c had no recording at all. Add it for targets with
HAVE_RECORDING: HDMA channel 1 moves the I2S Rx FIFO into the recording
buffer - hdreq 7, fixed source, incrementing destination, 32-bit inc8
slices, the mirror of the playback channel and the setup the Samsung
YP-CP3's original firmware uses. Playback keeps channel 0, so the two can
run together.
- HDMA_ISR holds both channels' masks and flags; playback used to write
all of it, clearing whatever the other channel had. Each channel now
updates only its own bits, and INT_HDMA serves each channel's count
down flag. Both channels start masked and clear.
- Recording cannot mask the shared interrupt, so pcm_rec_lock() defers a
completed buffer to pcm_rec_unlock() instead.
- In master mode the I2S Rx side runs only while recording: started with
nothing reading its FIFO it upsets playback. I2S_RXCTL gets the Tx
frame format, plus bit 24 as the YP-CP3's original firmware sets it.
- audio-rk27xx.c routes inputs through audiohw_set_recsrc() on targets
that record.
Only partly tested, on a YP-CP3: playback and FM radio still work after
the interrupt changes, and the recording screen's peak meter follows the
microphone, so samples arrive through the DMA. Not yet tested: playing
back a recorded file, recording FM, long recordings, recording while
playing. A known risk: a flag set by the hardware in the few cycles of
the read-modify-write of HDMA_ISR would be lost and stall that channel.
Other rk27xx targets build; their playback was not retested on hardware.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: Idc64bce8075d0fc628c29767fc33beda4fff4342
The YP-CP3's tuner is a Silicon Labs Si470x at I2C address 0x20, an
Si4703 by the RDS the original firmware enables. The firmware drives it
the Si470x way - writes from register 2, reads from 0x0A - starts its
oscillator with TEST1 = 0x8100 and a 500 ms wait before ENABLE, and has
no power or reset line for it.
- config: CONFIG_TUNER SI4700 with RDS, polled (no interrupt line
needed), and FM radio as an input source
- si4700.c: the YP-CP3 starts the oscillator as the Sansas do
- power-ypcp3.c: tuner power stubs - there is nothing to switch
- the rk27xx tuner I2C glue, and "radio" in the target's configure entry
- wm8751.c: audiohw_set_monitor() for a WM8750 target that plays the
radio but cannot record (rk27xx has no recording yet). The tuner, on
LINPUT1/RINPUT1, goes through the input PGA at +12 dB - as in the
original firmware - into the output mixers, the DAC staying in the mix.
The existing monitor routing lives in the recording code and switches
OUT2 off, which is the YP-CP3's headphone output.
Tested on a YP-CP3: stations tune and play at a sane level.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: Ic097fc85dbd7fb71fcc28c97a9d378fa09599e79
The YP-CP3 uses Wolfson WM8750. Headphones are wired on OUT2 and
a headphone amplifier enabled by GPIO F2, active high -
all RE from the original firmware.
The original firmware runs the codec as I2S master in its 12 MHz "USB
mode", fed a fixed 12 MHz MCLK, which puts 44.1 kHz at 44.118. Rockbox
instead makes the rk27xx the master and clocks the codec from the codec
PLL at exactly 256 fs (CODEC_SLAVE, as every other rk27xx target with an
external codec), so the codec's CLOCKING register is its normal-mode
256 fs setting at every rate. 96 kHz is left out: the WM8750 cannot take
it at 256 fs.
- config: HAVE_WM8750, CODEC_SLAVE, rates 8-48 kHz; the WM8750 has
hardware tone controls, so HAVE_SW_TONE_CONTROLS goes
- ypcp3/wmcodec-ypcp3.c: register writes over the rk27xx I2C driver
- wm8751.c: on the YP-CP3, power on and drive OUT2 instead of OUT1, set
the volume there, and switch the amplifier with the outputs
- english.lang: the YP-CP3 gets the bass/treble cutoff settings the
WM8750 brings
Tested on a YP-CP3: playback at 44.1 and 48 kHz on headphones, pitch and
volume correct.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I870038fb6a21a9c26b025e3df7c220fd925f49f6
Found in the original firmware by its command-in-address protocol
and bit-reversed data; the original firmware leaves it
in 12-hour mode, which the driver now handles.
Change-Id: I9f4147d3057aaa6aa498a1750cb4e746d69b1be6
The S-35390A keeps the hour either as 0-23 or - its default after a
power-on reset - as 0-11 plus a p.m. flag, selected by the 12/24 bit of
status register 1. The driver assumed 24-hour mode and never set it: it
masked the p.m. flag off, so on a chip left in 12-hour mode every
afternoon read as morning, and writing an afternoon time stored an
out-of-range hour.
Read the mode in rtc_init() and convert the hour both ways. The chip's
mode is left alone, as another firmware on the same player may depend on
it - the Samsung YP-CP3's original firmware runs it in 12-hour mode and
never touches the bit. If the status register cannot be read, the driver
keeps assuming 24-hour mode, as before.
Upstream removed the driver with its only users, the Meizu M3/M6 and
Samsung YP-S3 ports (1a33d7990a); the Samsung YP-CP3 needs it, so it
comes back here, with RTC_S35390A and its SOURCES entry.
Also pick the I2C header by CONFIG_I2C, so rk27xx targets can use the
driver; i2c_read()/i2c_write() have the same shape there.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I54d8c8cfaa1b88237f6c4b08d2a510ec9fce8ec5
set_codec_freq()'s table of codec PLL settings names every rate from 8 to
96 kHz by its HW_FREQ_ index, which exists only for rates in the target's
HW_SAMPR_CAPS. Every CODEC_SLAVE target so far has all of them; a codec
without 96 kHz at 256 fs - the WM8750 - leaves HW_FREQ_96 undefined and
the table no longer builds.
Wrap each entry in HW_HAVE_xx_(), as the codec drivers' tables do. For
the existing targets the table is unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: Ifab688ffa6f83c5319d686fcf40fc2b887c75d24
Scaffolding for a port, starting from the rk27xx generic target: configure
entry 146 (target id 117, model number 132), config/samsungypcp3.h, and
firmware/target/arm/rk27xx/ypcp3/.
- LCD: the rk27xx LCD interface (lcdif-rk27xx.c) with this panel's init
sequence, from RE. See g#1050. Looks like SPFD5420A 18-bit bus,
400x240 landscape. It differs from the generic panel's sequence in the
gamma curve and in not writing VCOM_HV1.
- Backlight: PD4 / PWM0 with the generic board's timing, which the hwstub
work found to be the same.
- Storage: the microSD slot. Card detect is PC7, active low,
as on the generic board.
- Keys: the YP-R0's key set - five-way yog, Back, Menu, Rec/User, Power -
so the target uses SAMSUNG_YPR0_PAD and its keymaps. Eight keys sit on
two resistor ladders on the LSADC, found in the original firmware and
measured on a unit:
channel 1 up 158, down 295, select 435, left 561, right 687
channel 2 menu 155, back 292, user 431
each key owning half a step either side of its reading;
power is GPIO C1, active high.
Builds as firmware and as bootloader. Status 3 (unusable) in builds.pm.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: Iff4984023415f341ca7507af6b5b2b551201e953
A single-component (grayscale) scan is non-interleaved, so its MCU is
one 8x8 block regardless of the sampling factors in the frame header
(T.81 A.2.2). Some encoders write H=2,V=2 for the lone component, which
sent both the imageviewer plugin decoder and the core loader down the
4:2:0 path: 6 blocks per 16x16 MCU, the image treated as colour, and
the entropy data overrun.
Force 1x1 sampling for single-component frames when parsing SOF0 so
these images use the 4:4:4 layout with one block per MCU. Also add the
missing else in fix_headers() in the core loader, matching the plugin.
Tested on a Sansa e200 with both the plugin and the core loader, and
the plugin in the e200 simulator and built for PC and for ARM (qemu).
Fixes FS#13749.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: Iac2f925aab8cd602930470dca5da7dfb44e15961
A total sample count of 0 means unknown. It made the track length 0 and the
bitrate estimate in flac_init() divided by it, crashing the codec (FLAC
decoder testbench file 45). Report a bitrate of 0 in that case.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
An escape code with a raw bit width of 0 means every residual in the
partition is zero. get_sbits(&gb, 0) shifts by 32, which is undefined and
returned stale cache bits instead of 0, so such streams decoded to garbage
(FLAC decoder testbench file 64).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
print_mp3entry() dereferences mb_track_id, but get_metadata() does not set
every field of the uninitialized stack struct. For FLAC files this left
garbage in the pointer and warble segfaulted in strlen about a third of the
time, before decoding started. Clear the struct first.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
A crash bug in those versions of texinfo (fixed in 7.20) caused the
glibc manual to fail to build. There is no build-time argument to
disable the manual, but there is a version check that gracefully
accomplishes the same thing.
So, add 7.0/7.1 in the glibc configure script blacklist.
Change-Id: If841aceeb7986db8274d145a5ea317278890eb30
Upstream's OPUS_ARM_INLINE_ASM means any ARM with inline assembly, with
OPUS_ARM_INLINE_EDSP layered on top for ARMv5E. config.h instead defines
exactly one of them per core, so the names read as broader than they are,
and code added ARM_ARCH tests beside them to pin the scope down. Renamed
to OPUS_ARM_ASM_ARMV4_ONLY and OPUS_ARM_ASM_ARMV5E_AND_LATER throughout
celt and silk, upstream files included; README.rockbox records it for the
next libopus sync.
No code change: opus.elf disassembly and section sizes are identical
before and after on ARMv4 (e200v1), ARMv5E (Clip+) and ARMv6 (iPod Nano
4G).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I89932d348dedd76748a1bc7b3f2e7de1c5be49c8
USB mass storage writes ran at 0.03 MB/s in the firmware - to the NAND
and to the SD card alike - while the bootloader, with the same driver,
wrote the same NAND at 2 MB/s. The firmware adds a HID interface, and
without it writes ran at full speed.
The UDC's endpoints come in groups of three - bulk OUT, bulk IN,
interrupt IN: 1-3, 4-6 and so on - and allocation handed out the first
free endpoint of each type, so HID's interrupt endpoint 3 landed in the
group of mass storage's bulk endpoints 1 and 2. The host polls it every
16 ms, the idle endpoint NAKs, and each poll costs the group's bulk
traffic: writes advanced about one packet per poll. Polled every 125 us
instead, they all but stopped; moved to endpoint 6, in a group of its
own, they ran at 2.36 MB/s, as without HID.
Never give an interrupt endpoint a group with bulk endpoints in use, or
the other way round, whichever class asks first. Since which endpoints
are available then depends on what is already allocated, the driver
tracks the allocation itself - option 2 of usb_drv.h, as usb-designware
does - with its context in usb-rk27xx.h, which usb_core.c includes before
usb_drv.h. HID keeps working.
Tested on a generic rk2705 with ums_stress.py over USB mass storage to
the SD card: 0.03 MB/s with HID on endpoint 3, 2.36 MB/s with it on
endpoint 6 - the allocation this change produces for mass storage plus
HID. (Measured with the driver's earlier allocator, before the USB core
took allocation over; this carries the same rule into the new scheme.)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: Ib80ed206a3705f2c76fc8457b5c0a54d60a46402
delay_nop() in lcd-rk27generic.c and udelay() in system-rk27xx.c both
count a register down with subs, but pass it as an input operand only:
asm volatile ("1: subs %[n], %[n], #1\n bne 1b" : : [n] "r" (cycles));
That tells GCC the register is unchanged afterwards, so it is free to
load a constant once and reuse the register for every later call with the
same argument. Current GCC does exactly that in lcd_display_init():
ldr r4, =10000 @ first delay_nop(10000)
subs r4, r4, #1 @ ... counts r4 down to 0
bl lcd_write_reg
subs r4, r4, #1 @ next delay_nop(10000): r4 not reloaded,
@ 0 - 1 wraps, loop runs 2^32 times
At 4 cycles per iteration and 200 MHz that is 85.9 s per wrapped call.
Nine calls wrap, so lcd_init() took 9 x 85.9 = 773 s. Measured on a
generic rk2705 with a tick timestamp either side of lcd_display_init():
77320 ticks at HZ=100, i.e. 773.2 s. With this fix it is 9 ticks, clear
loop included.
That is why lcd_init() looked like a hang on current toolchains while it
worked when the port was written. It also explains why no LCDC clock,
divider, gating or strobe-timing change had any effect: the time was
never spent in the LCD controller.
udelay() happens to work today because its count is computed at run time
on each call, but it has the same undefined behaviour and gets the same
fix.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: Iecdd6cca0701c35bce3427f359a9a638b21291b5
A host that is done with a mass-storage device - "safely remove", eject,
udisksctl power-off - sends START STOP UNIT with the start bit clear, and
may cut power right after. usb_storage only marked the LUN ejected.
Storage drivers can still hold data in RAM at that point: a flash
translation layer keeps part-written pages until a later write completes
them, and HAVE_STORAGE_FLUSH exists so they can be committed - but only
shutdown and ROLO called it. On a device unplugged after a proper eject
and then losing power, that data was lost although the host had done
everything right.
Call storage_flush() on stop and on eject, on targets that define
HAVE_STORAGE_FLUSH. The SCSI handler runs in the USB thread, as do the
reads and writes, so the flush cannot race them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I5b5811858c75dfb3ee89535ab59f4a19663945df
Thanks for the SET_ADDRESS rework. I think it leaves one case uncovered:
a host whose first request is SET_ADDRESS ends up with a device whose
interfaces are all numbered 0.
Two things still depend on the core seeing a request before the address arrives:
1. usb_core assigns interfaces and endpoints only on the first control
request it handles in DEFAULT. When SET_ADDRESS comes first, the driver
completes it and usb_core_set_address() moves the state to ADDRESS. So
allocate_interfaces_and_endpoints() never runs.
2. Under USB_DETECT_BY_REQUEST, usb.c enables the class drivers only
on a USB_TRANSFER_COMPLETION event. The SET_ADDRESS status stage now
completes inside the driver, so the drivers are still disabled when the
address arrives.
Change-Id: Ifacb8b07cbdefb0dee3d414c2257a50a08759f3d
run_file() joins /mnt/sd_0 and the filename without a /, so /bin/sh cannot open any script and always returns 2.
The path bug has been fixed and the buffer size adjusted and freed after execution.
GPT 6 Sol did the work. I'm just the meat proxy.
Change-Id: I644a773b2bd707e0ee2d8c70c91b7a6075cf2622
A host can replace an unfinished control transfer with a new SETUP. ARC
and DesignWare flush EP0 without reporting completion callbacks, leaving
the core waiting for a data/status packet that will never arrive.
Explicitly notify the core after both directions and stale completion
bits have been cancelled. Return an abandoned data/status stage to READY.
If a queued or running handler still owns the request and data buffer,
keep that ownership and suppress its response; dispatch only the latest
replacement when it returns. A driver-owned SET_ADDRESS can also cancel
a deferred request without passing its SETUP to the core.
Do not overwrite an arbitrary busy state in usb_core_setup_received().
ARC cancellation is a prerequisite in the preceding patch; DesignWare
cancels both EP0 directions before notifying and rearming reception.
Change-Id: Ia8e0a68fe47ccab952168da24a2f76e311ca2b15
Four `ARM_ARCH == 5` checks -- in SOURCES and celt/arm/{bands_arm,
comb_filter_arm,vq_arm}.h -- excluded ARMv6 from every ARMv5E kernel:
denorm_band, haar1, comb_filter_const, celt_sat, deemphasis_stereo_simple,
exp_rotation1 and normres_scale all silently fell back to plain C on
ARM1136/ARM1176, since ARMv6 is a strict superset of the EDSP instructions
those kernels use. Widened to ARM_ARCH >= 5, matching config.h's own
OPUS_ARM_INLINE_EDSP gate, which was already ARM_ARCH > 4.
These four can't be fixed at the commits that introduced them: those
commits are already merged into master under different SHAs. A fifth
instance of the same bug, in celt/arm/mdct_armv5e.h, was fixed at its
origin commit instead, since that one is still open for review.
Verified on both native ARMv6 targets (iPod Nano 4G, ARM1176JZ-S; Gigabeat
S, ARM1136JF-S) and the hosted Samsung YP-R0 (ARM1176JZ-S, cross toolchain
built for the occasion): all three now link and call all 16 ARMv5E
kernels, where they linked and called zero before this fix. Decoded PCM
bit-identical to the ARMv5E build under qemu.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Change-Id: I7e6f6b421b9c0203812fb45d2258c7eb81738d98
53% of the dimensions a decode walks hold no pulses, and that arm leaves
_k alone, so the two CELT_PVQ_U_ROW pointers stay valid. U is
non-decreasing in _k, so p <= _i < q is the single unsigned test
(_i-p) < (q-p). Bit-exact over 8.2M samples.
Modelled: -0.40% ARMv4, -0.78% ARMv5E; the function -4.8% and -7.1%.
Measured: e200v1 39.19 -> 38.96 MHz, Clip+ 28.13 -> 28.08 MHz.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Change-Id: Id50be222e101aeabd9a1f4cf5380d3244da610ff
At stride 1 the rotation chain writes X[i+stride] and reads it straight
back, so one load an iteration is redundant and one store is dead. The
kernel carries that value, narrowed, since mul reads all 32 bits where
smulbb does not. Bit-exact over 8.2M samples.
Modelled: -0.87% ARMv4, the function -10.0%.
Measured: e200v1 39.59 -> 39.19 MHz.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Change-Id: Idbd1a088bc805fecfb9ee54fc372ad16a7d91606
34 functions and the ARMv4 kernels, chosen by a greedy fill of the free
codec IRAM window ranked by cycles per byte. The mixed-radix
butterflies give their IRAM back, being unreachable under the prime
factor transform.
The cycle model does not see this at all: it models no instruction cache.
Measured: e200v1 48.96 -> 42.60 MHz; reclaiming the mixed-radix IRAM was
a further -0.52%.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Change-Id: I9e22025cba99521750a3b664cd0d59357fcd0810
Every 48 kHz CELT length is 15 times a power of two and the factors are
co-prime, so the inter-stage twiddles -- 73% of the FFT multiplies at
N=480 -- vanish. New pfa_fft15 and mdct_postrot_pfa kernels on both
cores; accuracy also improves 0.3 to 0.4 dB against opusdec.
Modelled: -6.17% ARMv4, -1.82% ARMv5E.
Measured: e200v1 42.33 -> 40.10 MHz, Clip+ 29.30 -> 28.24 MHz.
Rescheduling these kernels, folded in here, measured a further -0.75% on
e200v1 and -0.39% on Clip+.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Change-Id: Ifa4a30d1045e905522828958949954615faa440d
One ldr fetches two celt_norm coefficients and smlabb/smlatt take the
halves apart; scalar fallback when the three pointers disagree on
alignment.
Modelled: -0.88% ARMv5E.
Measured: Clip+ 28.13 -> 28.08 MHz, the same build with and without it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Change-Id: I79719132ccecfb7664616bca019e3856ee3479da
Handle SET_ADDRESS directly when each controller receives SETUP, before
passing other requests to the core. Cancel transfers, send the status
response in the driver and queue usb_core_notify_set_address(); the core
only updates its address/configuration state. Remove usb_drv_set_address
and avoid a request callback from the core back into the controller.
Keep status completions for this driver-owned request out of the core EP0
state machine. ARC writes DEVICEADDR and notifies after successful status
IN completion; other controllers retain their existing register/status
ordering or automatic address handling. Use IRQ-local operations on
DesignWare rather than helpers which unconditionally re-enable its IRQ.
Take the low seven bits of wValue; do not impose new validation on the
unspecified wIndex/wLength fields. Convert all eleven firmware backends;
the separate hwstub API is unchanged.
Change-Id: I7b96275df90c14ef4a9954f04ac6fdc004ec8d6c
We already shut down the playback path and the voice path, but that
doesn't necessarily mean the PCM hardware is idle.
Add a call to pcm_play_stop() to ensure the PCM sink is completely idle.
This will prevent a badly-timed callback from firing during a ROLO
operation.
Change-Id: I1eb8c105895fb47bc3d0af91b4d87345f5399aa4
Advertise only the implemented 32, 44.1 and 48 kHz stereo formats. Add
128-byte packets at 32 kHz and wrap the 44.1 kHz cadence at ten packets;
a uint8_t wrap at 256 otherwise emits extra samples every cycle.
Use the serialized UAC header length (including baInterfaceNr), maintain
the active alternate setting, accept alt 0 on non-streaming interfaces,
and retain the last valid sample rate when a SET_CUR request is rejected.
Change-Id: I41dab55fc0c7d2e6474492f97062e9838bc3aebf
A host may send a command after SET_CONFIGURATION while filesystem clients are still acknowledging the storage handover. Previously TEST UNIT READY could report no medium, while other commands could reach storage before exclusive access was granted.
Retain the first CBW until exclusive access is available. Notify the mass-storage class when handover completes, then execute the retained command and keep the OUT endpoint unarmed until its CSW. On BOT reset, discard the retained CBW and accept a new command.
This changes command handling while waiting for ownership. The policy for requesting, preserving and releasing exclusive storage is handled by a separate preparatory patch.
Change-Id: If82fc87160e9d7da930a3217445fea92e58dd1ec
Do not release and reacquire the disk when a host repeats configuration
or resets the bus before selecting mass storage again. This avoids
remounting local filesystems while the host still owns the disk.
After reset the filesystems remain unmounted until the host selects a
configuration which releases storage, or the cable is unplugged. A host
normally reconfigures promptly; one that never does leaves the disk
unavailable locally until unplug, rather than risking simultaneous access.
Change-Id: I6e296247dd2227e549105d85760613c1a81554a1
Rockbox lists no encoder, so CELT_DECODE_ONLY folds away the thirteen
encoder branches in celt/bands.c and stops gcc keeping their values live
across quant_partition's recursive calls. 2,976 bytes smaller.
Modelled: -0.47% ARMv4, -0.69% ARMv5E.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Change-Id: Ie96a0a63e035ab0cdcdbe9eeeb6691f24fecfa41
Its reachable input set is 2,985 (qn,i) pairs for any stream ever, so it
tabulates exactly in 6,484 bytes. Verified exhaustively against the
compiled functions. Only built for PP5022/PP5024, where the tables fit
the 80 KB IRAM window; elsewhere it measured no gain.
Measured, e200v1: 39.18 -> 38.96 MHz with the tables in IRAM, 39.07 with
them in DRAM. Clip+: 28.05 -> 28.08 MHz, so not built there.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Change-Id: I38417793dc337ec6cb61139cc919d23ac09b04dd
This re-enables upstream ASM optimizations for Cortex-M. Only the
our downstream improvements are disabled, as they do not assemble in
thumb2 mode.
Change-Id: Icca1b3dbf04786c7714fb4eef92ad66aa55132f3
* Only use new ARMv5e optimizations on classic (non-M) profile
* fix inconsistent ARM_ARCH >= 5 vs == 5
Fixes red in 0c4345475a and ae223933bf
Change-Id: Ieb688679d2d698a19870b1a63b4151a8593e04e0
radix-3, 4 and 5. The gain is bookkeeping: twiddles addressed by
displacement from one base register, post-indexed stores, and C_MUL's
Q15 doubling folded into the add that consumes it.
Modelled: -4.72% ARMv5E, opus_fft_impl -25.3%.
Measured: Clip+ 30.89 -> 29.33 MHz.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Change-Id: I173667ebb13308f83bd6fcb4e876f5a56c698cd3
Pre-rotation, post-rotation and mirror, with a packed-twiddle complex
multiply throughout.
Modelled: -8.0% ARMv5E against the C loops.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Change-Id: I3fcaf2343e04e3f3f4462fc442f8fac623729631
deemphasis_stereo_simple on both cores, with the filter state kept
unshifted and shifted inside the add that consumes it.
Modelled: -0.53% ARMv4, -0.96% ARMv5E.
Measured with the three preceding commits: e200v1 49.42 -> 48.96 MHz,
Clip+ 32.83 -> 30.89 MHz.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Change-Id: Id09297974f3b66a5a193b524d68fd8844f71cc02
Currently, the link points to the unofficial bootloader builds and installation instructions by freemyipod.org, but it can be changed at any time by the rockbox.org website maintainer.
Co-authored-by: ChatGPT-5.6 Luna
Change-Id: I05a78a6540ebcc0e03a1f12f5d765e69e68af00c
ARMv4 has no CLZ, so all 8,680 ilog2 calls went through libgcc's
__clzsi2. Fifteen branchless instructions replace it.
Modelled: -0.91% ARMv4; ARMv5E unaffected, it already emits CLZ.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Change-Id: Ib84b97acb687da4101e02bad1b0e8bbd256d32df
The USB core can accept a replacement SETUP while the previous control transfer is unfinished. Before dispatching that SETUP, flush both EP0 directions and discard their old completion bits so old descriptors cannot be reported as the new transfer. Leave non-control endpoints alone.
The register-stub test verifies both flushes, EP0 completion clearing and release of old EP0 waiters. This complements the separate generic control-request state-machine fix.
Change-Id: If595c7c0cfade7d855f113587621847926143606
audio_hard_stop() should be called *prior* to rolo_load(), and indeed
already is at every call site.
The reason to remove it from inside rolo_load() as opposed to the call
sites is because those already show a feedback splash while the audio
path is being shut down.
Change-Id: Ib6b995f7172c6a92599ace75245909730b2e941a
Move the iriver-specific functions for detecting flashed
Rockbox/OF images into system-iriver.c and remove the
HAVE_FLASHED_ROCKBOX define which is now redundant (all
targets using system-iriver.c enable it).
Copyright attribution on the new system-iriver.h header
is a best guess from Git history.
Change-Id: If1933f881a63fd517162ab9ca8f4a3007b997739
Only Coldfire targets have ever implemented this. Gate it
behind CPU_COLDFIRE so the stub functions won't be needed
in other targets.
Change-Id: I507952c40a04d813a40296142a6eba1df24b0a68
Some files were not using the standard header with the
Rockbox logo. Add this and move any technical notes into
a separate comment.
Change-Id: Idaac932cd56154c7b785ba0e6c0231a21878f786
CLEAR_FEATURE(ENDPOINT_HALT) must reset the selected non-control endpoint data toggle as well as removing STALL. Set the corresponding ARC toggle-reset bit when clearing the halt, including when the endpoint is already unstalled. EP0 keeps its SETUP-controlled toggle handling.
The register-stub test checks IN/OUT independently and verifies that EP0 does not receive a non-control toggle reset.
Change-Id: I18bce488ec250336512bfda4db6ff369d21d9180
If RESET and IOC/SOF are reported together, the old interrupt order can refill audio or report completions from descriptors invalidated by the reset. Handle RESET first and return without dispatching those stale events. Disable SOF refill and stop the batch ring when resetting the controller.
The register-stub regression exercises simultaneous RESET, IOC and SOF and checks that no old completion or refill is dispatched.
Change-Id: Iac98df59aea30dfee155302f7ad31c6ba9902975
comb_filter_const on both cores, and celt_synthesis's SIG_SAT clamp
four samples at a time through one ldm and one stm.
Modelled for the saturation loop: -1.05% ARMv4, -1.42% ARMv5E.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Change-Id: I381afab451eb29a91513ce6ab29c1b2d565b7ee9
denormalise_bands on both cores; exp_rotation1, haar1 and the
normalise_residual scaling loop on ARMv5E. Bit-exact.
Modelled: -0.50% ARMv4, -2.91% ARMv5E.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Change-Id: If40f5dbe7cb9e7c12aa0a5b4ac9e73433a850b6e
98.6% of __udivsi3 calls are ec_decode and ec_decode_bin computing
val/ext, where the quotient only matters below 2^16. Exact over 80
million cases including corrupt-stream values.
Modelled: -1.34% ARMv4, -2.37% ARMv5E.
Measured with the previous commit: e200v1 50.80 -> 49.42 MHz,
Clip+ 33.40 -> 32.83 MHz.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Change-Id: Ia09cb6cd8e42d4885e4d5be0f84862b9b951136c
Modern rockbox builds are just larger than 1MB on the Sansa Fuze/Fuzev2,
which exceeds the reserved space to load the firmware.
The other AMS targets are a little under 1MB, so their time is likely
to come soon. Bump the buffer to 2MB so we never have to worry about
this again.
Change-Id: Ie6bf998596f5e55f5cc8e576a2a22639344306a4
If the variable is provided, the resulting .dmg will be uploaded to Apple's servers for notarization. If successful, Apple's notarization ticket is attached to the image.
Notarization of ~30MiB .dmg takes 40-50 seconds including upload time, ~30 seconds sans the upload time.
Tested building and notarizing of Rockbox Utility, Rockbox Theme Editor, and both as a single target, i.e. deploy.
Co-authored-by: ChatGPT-5.6 Luna
Change-Id: Ib31b1f825893111d23248fb8511fe5b6c73d5525
Cuts realtime decode on the Sansa e200v1 from 52.1 MHz to 50.8 MHz.
clt_mdct_backward was the largest remaining item at 13.5% of decode.
Only the three inner loops move to assembly. The setup stays in C, so
mdct.c remains readable and the assembly needs no knowledge of
mdct_lookup.
What the compiled loops lose is registers. Each needs more live values
than gcc can hold, so it spills the loop-invariant pointers, strides and
limits and reloads them every pass: five stack accesses per iteration in
the post-rotation alone. Holding the twiddle as a 16-bit value and
accumulating the product pair with smull/smlal is what makes the
bookkeeping fit, needing seven live registers where the shifted
MULT16_32_Q15 form needs nine.
ldm/stm helps only where the addressing allows. The post-rotation walks
the buffer from both ends and so reads and writes contiguous pairs. The
pre-rotation reads the spectrum through a runtime stride and writes
through the bitrev table, so only its 8-byte output pair merges, and the
TDAC mirror merges nothing.
Over 160 ms of stereo music, traced under qemu:
clt_mdct_backward 1,037,962 -> 900,982 -13.2%
whole decode 7,695,876 -> 7,558,896 -1.8%
loads 650,157 -> 611,667 -5.9%
stores 350,605 -> 323,605 -7.7%
multiplies 337,493 -> 337,493 unchanged
Accuracy improves substantially, because all three loops keep 32 bits of
each Q15 product where MULT16_32_Q15_armv4 drops the low bit, and the
backward MDCT applies three such rounds per sample. The rounding SNR of
the backward transform rises about 9.5 dB, and its worst case error falls
from 708 to 186. Decoded output differs from the previous build in 90 of
15,360 samples, each by one LSB.
Build with OPUS_ARM_NO_MDCT_ASM to select the C loops instead.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Change-Id: I3c4404b4dbe581d8bcf1f357266a658a068fdb50
Cuts realtime Opus decode on the Sansa e200v1 (PP502x, ARM7TDMI) from
55.55 MHz to 52.1 MHz.
Two exact changes to celt/kiss_fft.c first:
- kf_bfly5 folds the four cosine products into a shift and a single
multiply. cos(2*pi/5) + cos(4*pi/5) is exactly -1/2, and the Q15
constants satisfy that identity exactly (10126 - 26510 == -16384), so
the substitution gives up no accuracy.
- kf_bfly3, kf_bfly4 and kf_bfly5 peel the pass that twiddles by
twiddles[0], which is 1, by rotating the loop rather than duplicating
the body. In fixed point twiddles[0] is 32767 rather than 32768, so
skipping it also drops a small systematic gain error.
Then celt/arm/kiss_fft_armv4_asm.S replaces the radix-3, radix-4 and
radix-5 bodies, reached through OVERRIDE_kf_bfly3/4/5. The compiled
kernels spill their loop-invariant pointers and reload them every pass,
and gcc will not form ldm/stm from contiguous C accesses: it reorders the
loads while scheduling and does not hand out ascending register pairs.
The assembly keeps the bookkeeping resident and sends the transient
butterfly values to the frame instead, in bursts.
Over 160 ms of stereo music, traced under qemu and costed with an
ARM7TDMI model:
FFT cycles 1,876,926 -> 1,430,748 -23.8%
whole decode 8,142,054 -> 7,695,876 -5.5%
loads 769,935 -> 650,157 -15.6%
stores 409,999 -> 350,605 -14.5%
multiplies 350,909 -> 337,493 -3.8%
text 3,368 -> 2,656 bytes
The radix-5 fold accounts for the whole multiply reduction. The assembly
leaves the count untouched and wins purely on memory traffic.
Accuracy improves by up to 2.9 dB rather than degrading, because the
assembly keeps all 32 bits of each Q15 product where MULT16_32_Q15_armv4
drops the low bit. Decoded output differs from the C build in 27 of
15,360 samples, each by one LSB.
Build with OPUS_ARM_NO_FFT_ASM to select the C butterflies instead.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Change-Id: I2e8a0904da8a85b654ff648a01234348977a0edc
A contributor's check archive matches the row exactly and passes
test_crash clean. test_ftl disagrees with the oracle on two logical
pages in one block - a second, distinct false positive from the
A5D5D589 x2 case: a closed data block addressed purely by position,
with one stale leftover page. Confirmed against the decode notes
(_FTLRestore's "closed blocks -> map" step) and documented in
test_ftl.c alongside the existing false positive.
Testing evidence: utils/ipodnano3g/RESULTS.md.
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Change-Id: Ib24d2df18e2b0e60e000ee6ea43bef9c214f7f72
A contributor's check archive matches the row exactly and passes both
host tests clean: test_ftl agrees with the oracle on all 3,964,928
sectors, test_crash survives 100 power cuts with 0 sectors wrong.
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Change-Id: I7c651c94332e0a04686ce8855a274735ae39546c
Four check archives (B614D5EC x2, A5D5D589 x2, A5D5D589 x4, 3E94D589 x2)
all match their table rows and pass test_crash clean. Three pass test_ftl
outright; A5D5D589 x2 disagrees with the oracle on two logical pages,
traced to _FTLRestore's own tie-break between two competing logs
(verified instruction-for-instruction against osos 1.1.3) - Apple's own
firmware would resolve the same medium the same way, so this is not a
defect. test_ftl.c gets a note explaining the false positive for future
archives that hit it.
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Change-Id: If8de0d6b1175981a292c5c45fbc092d5a6e0891a
A contributor's check archive for a 2-chip-enable A5D5D52C unit matches
the row exactly and replays clean against the host FTL suite. The row
moves in with the validated chips on this evidence alone - no on-device
write test has been run.
Testing evidence: utils/ipodnano3g/RESULTS.md.
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Change-Id: Ia9e00c0e880b10785da3ab52bc98dc93e94acfaf
The contributor NAND check tool went in before the driver changes that
followed it. This brings it up to the current tree.
Testing evidence: utils/ipodnano3g/RESULTS.md.
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Change-Id: Ie7712e0d7eaf75b880a9d134715ce1396a8545f8
The host-side tools the Nano 3G NAND driver and FTL were developed and
tested with, so the evidence in those changes can be reproduced and the
next chip can be added without rediscovering any of it: regdiff (register-
write comparison against Apple's sequencer programs), ftltest (the host
FTL test suite), chiptable.py, the FTL decode notes, and RESULTS.md, the
measurements the earlier changes quote.
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Change-Id: I321e06291ca393e18dbd5f71c2c6371fcda9a94d
Reject the first out-of-range configuration index and omit class descriptors for drivers whose initialization failed.
Change-Id: I1f74dcceb69f19b52650aa6ae3f38331e320b151
Account only completed data-stage bytes in the CSW residue. Halt the requested data pipe before returning failed status for an unsupported command with a data phase.
Send ATA IDENTIFY from the initialized transfer buffer rather than a stale READ/WRITE buffer pointer, and reject unsupported WRITE BUFFER variants.
Change-Id: I9855f56b3555c2a69724681cb028e57f733dae0e
- The main binary in *.app/Contents/MacOS/ was not signed using the "hardened runtime" option.
- The ipodpatcher and sansapatcher binaries in RockboxUtility.app/Contents/bin/ were not signed at all.
The produced .dmg images are now suitable for notarization so the app inside can be installed and started with no security warnings.
They are not notarized yet, as this takes a significant amount of time, but it can be done manually using:
xcrun notarytool submit build-qt/RockboxUtility.dmg --keychain-profile <your-profile> --wait
xcrun stapler staple build-qt/RockboxUtility.dmg
Only ARM macOS is supported at the moment.
Co-authored-by: ChatGPT-5.6 Luna
Change-Id: Id88d7da18f541f9f503172f5dcb5b17d64e0602e
Adds the platform file, modelled on the Nano 2G's and the iPod
Classic's, and corrects the supported-versions text shared by the Nano
manuals, which said Rockbox does not run on the third generation.
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Change-Id: Ie6290d67ae113086cb8a63c825eb9db9544c1d49
Fills in the stubs the Nano 3G port was left with, taking each from how
the original firmware drives the same hardware.
Testing evidence: firmware/target/arm/s5l8702/ipodnano3g/TESTING.md.
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Change-Id: Iea5314769502f5941a176600869591756c5e3233
Rockbox only drives NAND parts proven on hardware, and this tree has one
model to prove them on. This is the image that lets an owner of another
Nano 3G supply what validating theirs takes: a bootloader built with
-DNAND_CHECK and run from DFU, which never touches the NOR flash or
writes to the NAND.
Testing evidence: firmware/target/arm/s5l8702/ipodnano3g/TESTING.md.
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Change-Id: I46328b69f8011337790f35a195de97b5bcf347a5
Several symbols were missing these annotations so the compiler wasn't
handling thumb interworking correctly.
Should resolve tone control crashes seen on clipv1 and our handful of
other 2MB armv5 targets that we build (mostly) in thumb mode.
Change-Id: If8c533a5f10b6592a2d2bec519f2c4d6539d7a66
When we request a thumb build on a non-thumb-only target, we hand
compilation to a script that tries to build everything as thumb, falling
back to non-thumb arm mode if the thumb build fails. In order for
this to work, the compiler flag -mthumb-interwork is required.
Move this definition out of the thumb-cc script, and into the configure
script (ie along with the other target-specific definitions)
Change-Id: Idc1f8caa088dbbf710b169b272de61cc0b7c9ca6
The Nano 3G keeps everything behind the S5L8702 flash controller and
Apple's FTL ("Whimory"), and nand-nano3g.c was a stub, so the port had
no storage at all. This is the flash driver, the FTL and the wiring that
makes the NAND Rockbox's disk. The three are one change because neither
half is usable without the other: the driver alone cannot see a
filesystem, and the FTL alone has nothing to drive.
Testing evidence: firmware/target/arm/s5l8702/ipodnano3g/TESTING.md.
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Change-Id: Ib04a991489ff3a1a63cd55552e4a8d7ec7a5fc8c
The DX50 keymap already defines button_context_yesno, but
target_get_context_mapping() did not select it for
CONTEXT_YESNOSCREEN. As a result, physical buttons could not
operate dialogs such as "Playlist finished. Play again?".
Add the missing context mapping.
Tested on iBasso DX50 hardware: Play and Previous accept Yes;
Next and Power cancel.
Change-Id: I9f6078b45a48047a662aad5f231d0adac9a42d5d
Most of the churn here occurs because 'filesize' is one of
the redefined filesystem functions, but some of the structs
used by the native FS code also include a 'filesize' member
variable which gets renamed by the macro in some but not all
source files.
It's easier to rename 'filesize()' to 'ffilesize()' rather
than try to clean up the macro mess or renaming the struct
members.
There is weirdness with root_realpath() which now breaks on
native builds because it was assumed to be unprefixed there.
dir_get_info() was unprefixed everywhere but this just seems
inconsistent; make it follow the FS_PREFIX() convention too.
Change-Id: Ic3700c6234ea45f32679c1a8429d70fdb8f4088a
A target that defines HAVE_STORAGE_READONLY provides storage_readonly(),
and USB mass storage reports such a drive write protected: MODE SENSE
sets the WP bit, and WRITE(10) and WRITE(16) fail with DATA PROTECT /
WRITE PROTECTED before taking data, so a host mounts it read-only
instead of failing each write as a medium error. Only NAND storage wires
it up so far.
The iPod Nano 3G, added in the changes that follow, defines it: its FTL
mounts read-only in the bootloader and after a failed commit, and the
NAND check image is always read-only.
Built for the Nano 3G (bootloader, check image, firmware) without new
warnings. On hardware, Linux and Windows hosts have read the
always-read-only check image over USB; no host write has been made to a
read-only drive.
AI provenance: developed with Claude Opus 5 (Anthropic), used through
Claude Code. The model wrote most of the code and this message under
Andrew Rice's direction. Any hardware testing described above was
carried out by Andrew Rice, who is responsible for this change.
Change-Id: Idb34def2d588047e5dced9bac1521c00b37dd5e5
libusb_control_transfer returns <0 for errors,
0 is success without any bytes, read and ret >0
is the amount if bytes read.
Tested command: sudo ./usbboot --vid 0xa108 --pid 0x1000 --cpuinfo
Before:
Can't get CPU info: 8
After:
CPU info: X1000_v1
Change-Id: Ied6d430406239ea4f99e7c83274d99ae4c555899
Add the HiBy R1 and X1600 USB boot path, sharing the boot-package reader
with X1000. Load the returning USB stage separately from the flash SPL,
check its DDR result, then upload and run the second-stage bootloader.
Built on macOS; error paths checked with mocked USB transfers.
Change-Id: I501c1ffdb9e3d5f0c76a379ec6d229ec579bf100
pmu_preinit() masked register 0x10 with 0xdb, which clears bits 2 and
5. With bit 2 clear the NAND chip does not answer and nand_init() fails.
Masking with 0xdf clears only bit 5 and leaves bit 2 alone.
Measured on a 4GB Nano 3G. Every build that had worked carried debug
PMU reads, i.e. extra I2C delay, so delay was the confound to rule out
and each mask was tried with and without it:
0xdb, no extra delay dead
0xdb, extra delay dead
0xdf, extra delay reads (3 runs)
0xdf, no extra delay reads
One early 0xdf build without instrumentation failed once (rc=-1). That
has not been explained; the final validation run is the same
configuration and reads correctly.
Reading the register back after pmu_preinit() gives 0xdf. The new mask
keeps bit 2 and "| 0x8" only sets bit 3, so bit 2 is set as the BootROM
left it - the old mask was clearing it. Bit 5 is hidden by the mask, so
what the ROM leaves there is not known.
What bit 2 does is not established. The old comment guessed "bit4 is
related to NAND, LDO_0x15 on/off"; the register does sit among the NAND
supply settings (0x15 reads back the value commented as Vnand), but no
datasheet was consulted, so the new comment states only the observed
effect.
AI provenance: developed with Claude Opus 5 (Anthropic), used through
Claude Code. The model wrote most of the code and this message under
Andrew Rice's direction. Any hardware testing described above was
carried out by Andrew Rice, who is responsible for this change.
Change-Id: Iee73f876b7b6a5c85e09f8bf1c5ac174a49409e0
The S5L8702 has two flash memory controllers; the BootROM uses the first
at 0x38a00000 and addresses the second at +0x400. FMC_BASE was defined
for the S5L8700 and S5L8701 only.
Also add the registers Apple's NANDReadPage (BootROM 0x20009910) uses
that are not in the existing S5L8700 set, and three FMCSTAT bits. Their
real names are unknown, so they are named for what they were observed to
do and the comments say which are inferred rather than measured.
No functional change: this header only adds definitions.
AI provenance: developed with Claude Opus 5 (Anthropic), used through
Claude Code. The model wrote most of the code and this message under
Andrew Rice's direction. Any hardware testing described above was
carried out by Andrew Rice, who is responsible for this change.
Change-Id: Ib8c808128abc9a117cb811fe1fe47bffa4ec0abe
Database still opened an empty list when the config failed to parse. This results in the Device being complete unresponsive and needs a hard-reboot.
This shows a file-not-found splash instead and return to the previous menu.
Change-Id: Ifbb6998c46a4685eae486cffd89833f93a172713
Apple fitted at least five makers' NAND to the Nano 3G, in eighteen
chip and chip-enable combinations. Rockbox's Nano 3G NAND support can
only be enabled for writing on a chip that has been validated on
hardware, and so far one has. This gives owners of the others a way to
send what validation needs without installing anything.
nano3g-check.dfu runs from DFU mode (mks5lboot --dfusend). It reads the
chip ids on every chip enable, matches Apple's chip table, tries a
read-only mount, and shows a short summary. It then serves the raw NAND
over USB as a write-protected disk: sector 0 a text report, then 16-byte
spare records for every page, then page data. Nothing is written to the
iPod's NAND or NOR.
nandcheck.py collect finds that disk on Linux, macOS or Windows and
writes a few-MB archive: the report, every page's spare metadata and
read result, and every page that is not user data or erased (the FTL
and VFL control structures and Apple's bad-block records). It includes
no file contents and not the serial number. The README lists the chips,
how to tell which one an iPod has, and the procedure.
The image is the Nano 3G bootloader built with -DNAND_CHECK from the
Nano 3G NAND driver work, which is not merged yet.
Tested on a 4GB Nano 3G (Hynix A514D3AD x4): sent with mks5lboot
--dfusend, the disk appears within seconds, and collect reads it in 7
minutes with no ECC failures or timeouts. The archive mounts in the
driver's host FTL tests with every sector resolving to its newest copy.
AI provenance: developed with Claude Opus 5 (Anthropic), used through
Claude Code. The model wrote most of the code and this message under
Andrew Rice's direction. Any hardware testing described above was
carried out by Andrew Rice, who is responsible for this change.
Change-Id: Id790997768ee79451b7adeb5e9764dc8054faf4c
Registers the Nano 3G (platform ipodnano3g, model number 117, "nn3g"
header) so mks5lboot can build DFU installers and uninstallers for it,
adds its original bootloader to the dualboot code, and lists the
platform in the usage text and the README.
The target has to be named ipodnano3g rather than nano3g: the dualboot
Makefile derives the source directory and the piezo driver's file name
from it.
The per-target OF hash table is the substantive change. identify_fw()
decrypts the IM3 header's data_sign with the hardware UKEY and looks it
up in of_sha[], and anything not listed is taken to be a Rockbox
bootloader. The table held only iPod Classic firmware, so on a Nano 3G
the installer took Apple's own bootloader for a Rockbox one and gave up,
and the uninstaller would have refused to restore it. Both bail out
before writing, so nothing is damaged, but neither can work. The table
is now per target, and lists the bootloader of every Nano 3G firmware
release, 1.0.1 to 1.1.3.
The decrypted data_sign is the first 16 bytes of the SHA-1 of the
plaintext bootloader, so it is the same on every unit. Each release's
updater image (aupd, GID-encrypted, in the ipsw) carries that bootloader,
0x1f800 bytes, at the start of a NOR image. The aupd of each release was
decrypted on a Nano 3G with the hardware GID key and hashed on the host.
For 1.1.3 the result matches the data_sign read from a 4GB unit (model
MA978) whose NOR had never been written to, and the bootloader in its
aupd is byte-identical to the decrypted copy the installer relocated on
that unit. 1.1.2 and 1.1.3 ship the same bootloader.
dualboot.c is generated, and only the Nano 3G arrays are added. The iPod
Classic arrays are left byte-for-byte as they were: rebuilding them with
a different compiler changes their bytes, which would ship an untested
installer to Classic users for no reason.
The dualboot Makefile did not build from the current tree for any
target, which the committed blobs, older than both problems, had hidden.
config.h needs autoconf.h, which tools/configure generates per target,
so each target now takes a CONFIGDIR_<target> pointing at a configured
bootloader build for it, e.g.
make CONFIGDIR_ipod6g=../../../build-ipod6g-bl \
CONFIGDIR_ipodnano3g=../../../build-nano3g-bl
And the linker script is preprocessed with __ASSEMBLER__ defined, under
which config.h now emits the ldmpc/ldrpc assembler macros that ld
rejects; the sed that cleans it now also drops .macro, .endm and .syntax
lines and the macro bodies. Before these fixes the iPod Classic build
failed first on the missing autoconf.h and then with a linker syntax
error; with them it builds both blobs.
Tested on that unit, with s5l8702pwnage delivering the images through
Apple's DFU, and again with mks5lboot's own --bl-inst and --bl-uninst:
the installer put Rockbox in NOR, the unit then booted
Rockbox, and holding MENU booted Apple's firmware from the relocated
original bootloader; the uninstaller restored it and the unit booted
Apple's firmware again. Those images carried a table holding only the
1.1.3 entry. The Nano 3G blobs in dualboot.c were then rebuilt with the
Makefile for the full table - with the one-entry table the rebuild was
byte-identical to what the tested images carried - and mks5lboot
--bl-inst with them installed Rockbox on the same unit, which booted
Rockbox and, holding MENU, Apple's firmware. The uninstaller built with
the full table has not been run, and no firmware other than 1.1.3 has
been installed to or uninstalled from on hardware. For the iPod Classic,
the uninstaller DFU this builds is byte-identical to the one built
before this change.
AI provenance: developed with Claude Opus 5 (Anthropic), used through
Claude Code. The model wrote most of the code and this message under
Andrew Rice's direction. Any hardware testing described above was
carried out by Andrew Rice, who is responsible for this change.
Change-Id: I4b2fa692ac4110192ccbde0f1790b0ae2d1c73f5
backlight_on_button_hold / remote_backlight_on_button_hold
were never added to the Plugin API nor backlight_use_settings() helper
Change-Id: I75999af76f98244a870ab86564e591c8a900e66c
The generic USB core calls usb_drv_set_address() after starting the
zero-length status stage for SET_ADDRESS. On an iPod Video 5.5G connected
to a V-MODA VAMP VERZA, applying the address at that point causes the
accessory to reset the USB bus and enumeration does not continue.
Keep the generic USB core unchanged. In the ARC driver, capture a standard
device SET_ADDRESS request when its setup packet arrives and defer writing
REG_DEVICEADDR until the successful zero-length EP0 IN status transfer
completes. Clear any pending address on a new setup packet or USB bus reset.
With this driver-specific change the VAMP completes enumeration, iAP
authentication, 44.1 kHz digital-audio negotiation, and audio playback.
Tested on real hardware:
- Apple iPod Video 5.5G
- V-MODA VAMP VERZA over 30-pin USB
- 44.1 kHz digital audio playback
Development provenance:
The debugging process and patch preparation were performed with assistance
from OpenAI ChatGPT (GPT-5.6 Sol). I built and tested the firmware on the
hardware and verified the final behavior.
Change-Id: Ic9392d211dccda568fd42b06cb2b8853d4b8e893
Add S5L8702 VPU-B initialization, reset, bitstream input, frame output,
and cache maintenance to the iPod 6G target. Advertise it with
HAVE_HW_H264 and append a capability-gated decoder interface to the
plugin API.
Keep MP4 parsing, AAC decode and mixer output, A/V synchronization,
playback controls, resume state, and presentation in the multi-file
h264_player plugin. The target layer exposes decoder operations only.
Accept non-fragmented MP4/M4V containing Constrained Baseline H.264
through level 3.0, up to 640x480 at 30 fps, with optional AAC-LC audio.
Validate codec configuration and all sample-table relationships before
activating the hardware.
Read MP4 tables in bulk, boost the CPU while preparing them, and report
staged loading progress so long movies do not appear to hang during
startup.
Register the viewer and document its format limits and controls. The
libm4a compatibility fixes needed by video-first containers remain in
the preceding standalone change.
Tested on an iPod Classic 6G through an isolated Rolo nightly runtime:
H.264/AAC playback and M4V startup succeeded. Normal and
isolated-runtime iPod 6G builds also complete, and git diff --check is
clean.
Change-Id: I1e96c65c7d0b4231a94f602f8052f1b26d6e4a80
This was added in commit 8ff2c81bd to prevent a custom
root menu UI from flashing on screen in some themes
when returning from a plugin. Because the display isn't
updated in this scenario anymore, the workaround can be
safely eliminated.
Change-Id: Ie46b0921cfdad6e45a31661a5d451dc2717171d6
Top, bottom, and right icons were displayed too far to
the left. Apparently a long-standing issue.
Icon width is 7, so subtract 7/2 = 3 pixels, instead
of 4, from calculated center, and only 7 pixels, instead
of 8, from the right vp edge.
Change-Id: I8440a4fef4778a66d56117a05b3fe4c36ac8dadd
Remove trailing whitespace from int settings, so
that right-aligned or centered values look correct
in Quickscreen for settings such as Brightness.
Change-Id: I006cf3c3e8b30be2246e7370f26e0428fa47e54b
Size the reduced stco lookup with ceiling division. The table stores
chunk entries 0, divider, 2 * divider, and so on, so floor division
allocated one entry too few whenever the original count had a
remainder.
Treat a valid media-information atom whose first child is not smhd as
a non-audio track and skip the remainder. Continue scanning subsequent
tracks so AAC decoding works when an MP4 places its video track before
the audio track, while still rejecting malformed atom sizes and
malformed sound headers.
Keep these container fixes independent of the H.264 player and target
driver so they can be reviewed and applied to libm4a on their own.
Build-tested as part of the normal and isolated-runtime iPod 6G
configurations and hardware-tested with AAC audio in M4V playback.
Change-Id: I8c711525932f54ecbdad982c7f7ddc9490c5668d
Add some hardcoded flick gestures in the list UI:
Top -> open quickscreen
Left -> go back
Right -> go to the WPS
The WPS also gets a set of hardcoded flick shortcuts:
Top -> open quickscreen
Left -> go to file / database browser
Right -> view playlist
Bottom -> context menu
These are enabled by default in pointing mode but can
be disabled using the "Touchscreen Flick Shortcuts"
option.
Change-Id: Ib30a338ebb9662cd136985da6d34ed5b041e4077
Add Off, Auto, and On choices under the LCD settings menu for targets
with HAVE_COMPOSITE_VIDEO_OUT. Off is the default and leaves accessory
ADC, video registers, framebuffer conversion, output clocks, and CPU
boost untouched.
Auto enables output only for the qualified Philips dock signature. On
still requires a physically present, fully identified dock and permits
other detected composite accessories.
Document the menu behavior and the corresponding configuration-file
values in the iPod Classic manual.
Hardware tested on an iPod Classic 6G/7G with a Philips DCP750/37.
Change-Id: I649149daa331a95aa31110e1f2260a4a00ba789a
Add NTSC composite output for the iPod Classic 6G/7G using the
S5L8702 video processor, mixer, and encoder. Reconstruct the setup used
by the original firmware and mirror the 320x240 LCD in a centered
648x432 viewport.
Expose the driver through HAVE_COMPOSITE_VIDEO_OUT and a
target-neutral videoout interface. Keep the S5L8702 MMIO layout and
register definitions with the other SoC definitions in s5l87xx.h.
Convert LCD updates from RGB565 to planar YUV420. MPEG playback copies
decoded YUV420 planes directly, avoiding an RGB round trip. Hold output
clocks and CPU boost only while the memory-backed layer is active, and
restore them on disable or power-off.
Defer dock identification out of the serial tick because the accessory
resistor ADC path sleeps. Auto detection recognizes the measured Philips
DCP750/37 resistor range; manual mode can qualify other attached docks.
Leave interrupts enabled during the encoder's 10 ms reset wait so PCM
DMA can service linked-buffer completions when a dock is inserted during
audio playback. Keep reset assertion, reset release, all SVID register
writes, and pipeline start atomic so the composite setup cannot
interleave.
Hardware tested on an iPod Classic 6G/7G with a Philips DCP750/37 for
correct colors and geometry, stable UI mirroring, and full-screen MPEG
playback.
Change-Id: I669f2477d5cc707b48f7d24384c713d874a80e3f
Listen to GUI_EVENT_NEED_UI_UPDATE events and redraw, so
screen doesn't disappear if a theme draws over the UI vp.
Occurs in situations when the SBS is redrawn after waking
the screen, or when the song changes.
Change-Id: I062e802959ab9d34d8c04b7f82da6b87efb5d739
Reduces GNU complexity score from 7 to 2.
Use separate inline functions that group setting
- x-position and width for left and right text viewport
- y-position and height for all text viewports
- position/dimensions for icons viewport
Change-Id: I14f4eee1f4d6fefa9acbf4a37970a535e77990b1
importing discards duplicate entries based on context + action code
however you may want multiple entries to map to the same action
and you can't do it within the same context
instead only consider an entry as a duplicate if they have the same
context, actioncode, button, and prebutton
Change-Id: I5aba3459505987ba37e26758aec62f02fcf8165a
The parent vp wasn't set before checking the string size,
so, in certain scenarios, the size was calculated using a
different font than the one configured for the UI viewport.
Change-Id: I66bb2e496598811f6169a118de5cb83b451fa292
I intended to remove this in commit a8f8aa40b9 ("lastfm_scrobbler:
fetch rbversion from plugin API") but apparently forgot to do so,
so the scrobbler plugin was still rebuilding itself when RBVERSION
changes. Removing the header fixes that.
Change-Id: I6740d72ad35f5037a6a4a7580559a6c980b3225b
Eliminate special case for transition to the Shortcuts menu.
The SBS refresh doesn't cause a screen update anymore, and
has negligible cost, so do it regardless.
Reverts the changes to quickscreen.c introduced in commit
dfd9c10 ("Eliminate skin updates in between activities")
+ simplify quickscreen_draw_item (no effect on behavior)
Change-Id: I3fca976de554c720cb69a41566fd0d0a7e6ea92d
Fixes possible crash in case of pathological
UI vp dimensions, when attempting to clear a
QS item's vp.
E.g. https://github.com/federicoplg/musicOS
(commit c5e8570) configures a 1x1 UI viewport
at x=319 y=239, resulting in left/right item
viewports that have negative width or height.
Minor additional simplifications with no
effect on behavior:
- Combine actions requiring cleanup in a setup function.
Put it below the existing cleanup function
- Rename quick_screen_quick to quickscreen_show, and
quickscreen_run to quickscreen_main
- Iterate over items using FOR_QS_ITEMS macro
- Remove quickscreen_draw_item's int_value
- quickscreen_update: immediately continue if qs skinned
- Remove some obsolete #includes
Change-Id: I49aea3be837b861bdcd5132e84fef858df72327b
The "View RAM info" debug screen reports the host system's memory. It
calls sysinfo(2) and reads /proc/meminfo, but it is guarded only by
HIBY_LINUX.
That breaks the win32 simulator for all seven HIBY_LINUX targets -
agptekrocker, aigoerosq, hibyr1, hibyr3proii, hidizsap80max, xduoox20
and xduoox3ii - because HIBY_LINUX is still defined when the simulator
is cross-compiled for Windows, and mingw has no <sys/sysinfo.h>:
apps/debug_menu.c:146:10: fatal error: sys/sysinfo.h: No such file or directory
Exclude simulators at all three sites - the include, the function and
the menu entry - matching the !defined(SIMULATOR) guards already used
elsewhere in this file. On a simulator the screen reports the developer
machine's memory rather than the simulated device's, so it does not
belong there on any host.
Verified by building agptekrocker three ways: as a Windows simulator,
which now succeeds; as a Linux simulator, which still succeeds; and for
the device itself with arm-rockbox-linux-gnueabi, which still succeeds
and keeps the screen.
Provenance, per the AI disclosure requirement in docs/CONTRIBUTING: this
change was drafted with Claude Code (Anthropic Claude Opus 5) at my
direction. Patch set 3 adopts Solomon Peachy's review suggestion to key
the guard off SIMULATOR rather than __linux__.
Change-Id: If8a09da82d22118924a3375e05739dcd5640e11d
The reason 16/24-bit on the DAC does not work is that this
configures the I2S frame length, and the X1000's AIC uses
a hardcoded 64-bit frame length regardless of the bit depth
selected at the AIC input side. The AIC will pad the lower
bits of the 32-bit output sample with zeros.
Change-Id: I48c9893ca358248a63f24e3f75149da988943953
apps/plugins/lua/rockaux.c defines strerror() and strcoll() so the Lua
plugin has something to link against on native targets, which have no
libc providing them. Hosted targets do have a libc, and defining them
there is at best redundant.
On the Windows simulator it is worse than redundant. Both come from
mingw's libmsvcrt.a, and because that is a static archive the linker
pulls in an archive member for an unrelated symbol, then finds a second
definition of these two, so lua.rock fails to link:
libmsvcrt.a(...): multiple definition of `strcoll';
rockaux.o:rockaux.c:244: first defined here
libmsvcrt.a(...): multiple definition of `strerror';
rockaux.o:rockaux.c:47: first defined here
On hosted Linux there is no diagnostic, because glibc supplies these
from a shared library where a local definition simply wins. That means
the plugin has been quietly shadowing glibc's strerror() with a stub
that always returned NULL, which is presumably not intended either.
Guard both with CONFIG_PLATFORM & PLATFORM_NATIVE, matching the guard
used a few lines above for errno. Hosted targets now get the real
implementations from their own libc.
This also silences a "redeclared without dllimport attribute" warning
that GCC 16 emits for the same clash.
Verified by building xduoox3 as a Windows simulator, xduoox3 as a Linux
simulator, and sansaclip as a native ARM target: all three link cleanly
with no multiple-definition errors.
Provenance, per the AI disclosure requirement in docs/CONTRIBUTING: this
change was drafted with Claude Code (Anthropic Claude Opus 5) at my
direction. Patch set 2 adopts Aidan MacDonald's review suggestion to key
the guard off PLATFORM_NATIVE rather than _WIN32.
Change-Id: I8ffb6fd792147c9067afa708003b1285fb9d07a4
Pure file move, in preparation for a second Ingenic SoC.
dma, gpio, i2c, installer, kernel, nand and the SPL NAND backend
move from target/mips/ingenic_x1000/ to target/mips/ingenic/
Drivers that cannot move as whole files, because part of each is
genuinely X1000-specific, are left alone for now: msc, uart, sfc, the
debug menu and the OST helpers in system-x1000.c.
Verified as a no-op: built at target 246 --type=b before and after from
the same source path, bootloader.bin is byte-identical, and every moved
file's object has the same instruction stream under its new name.
Builds clean with no warnings for targets 246, 260 and 247, both
--type=n and --type=b.
Change-Id: I9f67c23384df49b8c4554d695b772bcd54a4e32f
Co-Authored-By: Claude Opus 5
sdmmc_host looks only at the transport status the controller returns,
and passes NULL for the response of every data transfer, so nothing ever
reads R1. A card does not signal a rejected command by failing the
transfer: it answers normally and simply does not commit the data. A
write refused for a write-protect violation, an address error or an
internal ECC failure is therefore reported to the filesystem as a
success.
Add sdmmc_host_submit_cmd_r1(), which fails a command whose response
carries any bit in SD_R1_CARD_ERROR, and use it for SET_BLOCKLEN and the
read or write itself. Those responses were already being received and
discarded, so this costs no extra bus traffic.
The R1 of the transfer command is returned before the data moves, so it
cannot report a failure which happened during the transfer. Whatever
ends the transfer has to be checked too: CMD12 where it terminates a
multiblock transfer, and CMD13 (SEND_STATUS) where CMD23 was used and
there is no closing command. Without the CMD13 an error is reported only
on the next transfer, against the wrong sector.
A CMD12-terminated read which ends on the last block of the card will
have tried to read past the end, and the SD spec (4.3.3, "Block Read")
requires the resulting OUT_OF_RANGE to be ignored. It is masked out for
exactly that case.
Only valid for R1 and R1b. A controller cannot apply the check itself
because it is told the response length rather than its format, and R3,
R6 and R7 are also 48-bit responses carrying unrelated bits in the same
positions.
Affects any target building sdmmc_host.
Exercised on X1600 hardware over 8 GiB of sequential reads with no
errors; the error path itself was not observed to trigger. Not run on
X1000 hardware.
Change-Id: I4a80dd29385d3eb4f256bc745a84f96e7054bbf8
Co-Authored-By: Claude Opus 5
This commit does the following changes to the 3ds port:
- Rename the target from ctru to 3ds.
- Rename all files and functions with the ctru naming convention to 3ds.
- Created a new file and folder structure that will better integrate future console ports that share the same codebase.
- Fixed a buffer overflow bug in pcm code.
Change-Id: I17c6f86df64eb99dd2b653485d70832ff46b2ba8
During Rockbox installation or update, the progress window currently
becomes unresponsive to screen-reader navigation while archive
inspection, free-space calculation and extraction are in progress. A
blind user cannot reliably move through or read the status messages and
therefore cannot determine what the utility is doing, how far the
installation has progressed, or whether an error has occurred.
The cause is that these operations are performed synchronously in the
GUI thread after a package has been downloaded. Although the
installation itself continues, the user interface cannot process
keyboard input and accessibility events reliably until the operation
finishes.
The attached patch moves the package installation work to a low-priority
QThread. Downloading remains asynchronous as before, while progress and
log signals from archive extraction are delivered back to the GUI thread
through Qt connections. This keeps the progress window fully navigable
with a screen reader throughout the installation.
Change-Id: I9a36a736e5b4bf98de8c3a71151679a4c1333dc7
Replace the dead infinite loop in power_off() with sim_do_exit()
which properly shuts down kernel, timer, mcuhwc, and cfgu services
before calling exit(0). Remove the stale sys_poweroff() declaration
in system-ctru.h; the generic implementation in powermgmt.c handles
SYS_POWEROFF broadcasting.
Change-Id: I247c4de482c66c3a060d0b88b7e2239ecec189c5
Restore paths_init() to create /3ds/.rockbox and the config
directory tree at startup, so Rockbox works without manual SD
card setup.
Edited by Vencislav Atanasov: Use the ROCKBOX_DIR macro instead of hardcoding the paths.
Change-Id: I33ab8e588cdca58285d50e9e5698a8071b381cf4
Some 512G Samsung cards (and possibly other cards) seem to
have problems with repeated single block read commands and
sometimes just time out without ever sending the data. The
card response is received OK and reports no errors but no
data is received.
The problem also occurs if a multiple block read is used to
transfer a single block but doesn't seem to occur when more
than one block is transferred.
Less commonly, timeouts can occur on write commands but it
is not clear if that happens only after a timed out read.
Adding a delay of a few tens of milliseconds before each
read/write single block command appears to prevent this.
Change-Id: I5a02b71f59cc02832acaf30e5f900a3ee8804e76
Remove all SD protocol handling and all target specific code
like GPIO/interrupt handling and clock parent setup. This can
now be handled from sdmmc_host_target_init() for each target.
Now only the clock frequency is managed by the MSC driver.
To make this code easier to factor out later, it's confined
to helper functions that do not access the driver state.
One small change is that MSCxDIV output is now clamped to a
minimum of 50MHz to avoid unnecessary frequency changes. The
MSC_CLKRT divider can still divide 50MHz down to 400 KHz so
there is no downside to this.
Auto-CMD12 is now unused. Using it would make error handling
more difficult for sdmmc_host since the controller does not
expose response data for the auto-CMD12.
Explicit CMD12 was not handled correctly in the old version
of the driver because the busy signal was ignored for R1b
responses if there was no associated data transfer. This is
now fixed by waiting for the PRG_DONE interrupt instead of
END_CMD_RES for non-data transfer R1b type commands.
Since existing X1000 targets are all very similar they use
a shared implementation in sdmmc-x1000-common.c for clock
setup and card detection. New targets can either use this
or create a separate file if they are different enough to
warrant one.
Change-Id: I35396637325d7c06a10151bb6aee64cabdc7b682
The ipod4g target has already had UDMA 2 disabled
(see commits 7d78503 and d118f47) due to reported
instabilities. The iPod color, using stock hardware,
appears to be affected too.
Change-Id: I9aea2efce3026938f719da4e5372b233ff6234cf
Route bass and treble adjustments through Rockbox's DSP pipeline
using biquad filters, making the Bass/Treble sliders in Sound
Settings functional rather than no-ops.
💘 Generated with Crush
Assisted-by: Crush:deepseek-v4-pro
Change-Id: I5d168aaa233fe450defaea03d6657732abd2ec47
Map the circle pad to directional buttons, giving an alternative
input method to the D-pad. Uses a deadzone of 64 to prevent
unintended movement from minor stick drift.
💘 Generated with Crush
Assisted-by: Crush:deepseek-v4-pro
Edited by Vencislav Atanasov: Fixed KEY_SELECT handling.
Change-Id: I34bf7127688423fca209e199d9535e032ad8b753
This prevents needlessly rebuilding the plugin whenever
RBVERSION changes. (This was introduced by the removal
of CVS $Revision$ tags.)
Change-Id: Ic981c86319edb9c7eb7f0c1de71d4fbaba8989ac
Rockbox Utility currently exposes SAPI5 voice speed but not the SAPI
voice volume. The encoder volume setting is applied after synthesis, so
it cannot prevent clipping or distortion already present in the
generated wave file.
This patch adds a Volume control to the SAPI5 TTS configuration. The
value is passed to the standard SpVoice.Volume property before
synthesis.
Change-Id: Ifa43e55f716f98150e94c86e5e6a6c8bce0ca852
On large touchscreens the software keyboard can now run in "point mode". Keys are laid out finger-sized and tapped directly instead of being navigated with a cursor. Targets opt in with HAVE_KBD_POINT_MODE.
Key size is derived from LCD_DPI so a key is about 5mm across whatever the panel density, falling back to a fixed size where DPI is unknown.
A phone-style default layout in the UI font, across three flip pages of eight lines. Page two is page one shifted (i.e caps). Page three completes Latin-1 and adds additional accented letters common to the other European locales.
Space is drawn as an icon, since the UI font has no glyph for it.
Change-Id: Ibe2e305b3c22b1f9152358cf3864b9445b67b463
Co-Author: Claude Opus 4.8
Voices the index, performer, and title of each cuesheet entry. Uses
talkclips if any are available.
Change-Id: If54931cb5bbeb698f23146479192c1d6fe387657
According to commit 7327d9fb6c ("Implement set block count
(CMD23) for x1000 target") some cards may experience data
corruption with certain controllers when CMD12 is used to
terminate multiblock writes. Using set block count (CMD23)
is reported to fix this issue.
Following the approach in that patch, use the SCR register
to probe support for CMD23, but disable use at runtime if
CMD23 generates an illegal command error.
Change-Id: I3ee1e48939b79b848fbda12c6737f2f974f47fa0
The SCR register is needed for detecting if the card
supports certain commands like SET_BLOCK_COUNT.
Change-Id: I48cbf8fff497b71fb831ba546a462b27bb30851f
When an SBS uses the new %QT tag (added in 96f42a5)
to retrieve the name of the top Quickscreen setting
(thus likely wants to draw its own QS UI), we disable
the built-in interface until a new SBS file is applied.
Fixes lag encountered in Themify 2 due to invisible
built-in Quickscreen UI that kept being re-drawn.
Change-Id: Id4f295f959c2d16d1650f6fc066c3ceca6685405
Keep track of the type of skin file being parsed,
in case a tag needs this info.
E.g. %Lt should be ignored in any skin other than
SBS files.
Change-Id: Ib7e52c3e6810196cb566adb65619a1b847cf20ef
If volume was set as one of the Quickscreen items,
the value wasn't updated when pressing ACTION_QS_VOLUP
or -DOWN.
Change-Id: Ie6531535745592d7b53006560f1db8c5b7dbfb97
For each setting adjustment, the whole QS was
redrawn, including icons that never change at
all. Only redraw the viewports that contain a
setting that has been adjusted.
Change-Id: I74188fbf382a92c6e8bf517d9518c3a96bdd21ef
Reduces GNU Complexity score from 6 to 2.
Slightly adjusts behavior:
1) With TIMEOUT_NOBLOCK and peak meters enabled,
skin_wait_for_action always returned BUTTON_NONE,
and did nothing else. Presumably unintentional.
WPS was not affected, since it always uses HZ/5 for the
timeout. The FM screen uses TIMEOUT_NOBLOCK only when
fms_do_button_loop is called with update_screen == true.
skin_wait_for_action now returns the result of get_action
in any given scenario.
2) fixes incorrect next_refresh calculation when peak_meters
are enabled on multiple screens
3) button loop now refreshes peak meters when
current_tick >= next_refresh, instead of when
current_tick > next_refresh
Change-Id: Iaca37dbdde6057f593659b2feb97b61ac4cc4b02
Because DMA is still running until CMD12 is issued the second
cache discard must occur after CMD12, otherwise the cache may
contain a stale copy of data. While the buffer is garbage at
this point it's probably not a good idea to leave the buffer
in a weird state where the cache doesn't match what's in RAM.
Change-Id: I7caf91d17631c92686ef0ad6f148e6c1d1bcbfa0
The splash contrast workaround for the iPod reFresh themes compares
foreground and background colours against hard-coded RGB565 values.
This prevents the workaround from being applied on targets using other
pixel formats, such as XRGB8888 hosted targets.
Use LCD_RGBPACK() and SCREEN_COLOR_TO_NATIVE() to obtain the equivalent
colours for the active screen instead.
Code change and commit message generated by GPT-5.6 Sol. Compiled on
my hosted Eros Q build and confirmed working correctly.
Change-Id: Id15669bc7b8cec11bd4ee645c0b671db4499d2cd
Quickscreen will ignore update_delay so that the SBS
is updated after each button press, without any lag.
The SBS may display settings that are adjusted by the
Quickscreen (e.g. cabbiev2's Shuffle and Repeat icons,
or the brightness slider included in themes like
Adwaitapod and Themify).
Change-Id: I28716e81cb77e235eb009bff91c96f510365f435
Appears to be a regression introduced in e454a39, where
MIN_LINES was increased from 4 to 5, along with changing
nb_lines <= MIN_LINES to nb_lines < MIN_LINES
The top and bottom sections are supposed to switch
from 2 to 1 lines if there are fewer available lines
than MIN_LINES.
Each of the three vertical section uses two lines,
resulting in overlapping viewports, if there are exactly
5 available lines.
Icons mentioned in the comment don't really play into
that.
Change-Id: I3a0e921d9f53a490fece0ce59457feaf84a80d3b
The frame-scheduling logic cherry picked from the 'rockpod'
fork [1] was not correct for high-speed hosts and broke USB
Audio output.
The DWC seems to schedule based on the DWC_DSTS.SOFFN field,
which is a 14-bit microframe number for high-speed hosts. For
full speed hosts SOFFN is the LSB-aligned 11-bit frame number.
For high-speed hosts, USB Audio and iAP use a bInterval of 4
for the ISO endpoint which means the host sends a packet every
8 microframes. Thus, we only receive data on even microframes,
which is why adding frame scheduling broke things (and why we
got away with not doing it before).
For full speed the bInterval is 1, we get a packet each frame
and we do need to tell the core to receive on odd frames.
This code is still not completely correct for arbitrary ISO
endpoints -- for that we would need the function drivers to
provide the (micro)frame number on which they want to send or
receive.
Tested by forcing full speed at the device side by setting
USB_DW_DCFG_SPEED=3. USB Audio works fine in both high and
full speed modes now.
[1] c390dfdbdf
Change-Id: I17d283821cd0861e414c48208ca67f6e98464d7c
This means it will end up in nightlies, get voice builds, etc.
Next up is to add it to the themesite..
Change-Id: I78dc77addebceb49773adaa3b70e9a457585fe62
The ES9018K2M DAC used on hw3/hw4 defaults to 32-bit audio frames but
when configuring it to match the SoC I2S settings (ie 16 or 24-bit)
it results in garbled output for unexplained reasons.
Change-Id: If3074f38178b19520ca6222a1e020ea210069a6d
HibyOS-based target: keymaps, LED, powermgmt, bootloader and sim support,
plus cabbiev2 for the new 360x640x16 screen. Opus 5 helped w/ debugging
and the initial scaffolding.
Updated name to FB_STRIDE_MISMATCH, added simulator bmp and specs.
Change-Id: If797ac6581cf75d9d1fcf36e615ee03cf6f905d6
Tune accel/decel/press coefficients and add a braking force which
kicks in when swiping in the opposite direction of scrolling. This
is instead of the usual acceleration force.
Change-Id: I2b220c98674933a6957d6982020406342cd019bd
Add configurable acceleration settings. There are 3 settings which
are applied at different times during scrolling. "accel" is used to
calculate the acceleration applied to the list based on the swipe
speed. "decel" determines the deceleration force applied based on
the list scroll speed, and "press" is an additional deceleration
force applied if you are pressing on the screen.
All settings have the general form:
kinetic scroll accel: <a0> <a1> <delay>
kinetic scroll decel: <a0> <a1> <delay>
kinetic scroll press: <a0> <a1> <delay>
where the formula for the acceleration is "accel = a0 + a1*vel" and
"vel" is the input velocity (swipe speed for accel, list scroll speed
for decel/press).
The delay parameter is a value in milliseconds which acts as a grace
period where the acceleration will *not* be applied. For example, if
you specify 250ms for decel, then deceleration will not kick in until
250ms after scrolling starts. For press, the delay is based on the
duration of the touchscreen press.
All settings have sane default values and don't need to be configured
to enable kinetic scrolling; it is always enabled. But the settings are
there for those who want to tweak the behavior.
Change-Id: I9723b496b2b5d3fb3643af60b169754fdba497f0
Add a low-overhead detector for flick gestures, which are quick
swiping motions from the screen edges.
Change-Id: I3ef2dad328fdf566923575d437376e100a2ab8df
Kinetic scrolling now accelerates when repeatedly swiping over
the screen, so you can scroll through large lists easily without
using the scrollbar. Press & hold to slow down and stop.
Menu items can no longer be selected during a kinetic scroll
event, to reduce the chance of accidental selections.
Change-Id: I05b7d5fe6681a9edf53096b1fa265442fb31bf33
* Dedicated FIFO mode requires a non-zero multi-count for periodic INs
* Add ISO frame polarity
* Correct max packet size for high-speed ISOC operation
Change-Id: I2c0d40b5f8d0e1e4cf43369631f17c7f80c6fab2
Debug -> USB Serial calls usb_core_enable_driver(USB_DRIVER_SERIAL, ...), which sets a flag inside usb_core. usb_core_init() clears every driver's enabled flag on each connect and runs after the toggle, so the choice is gone before any descriptor is built: the menu reports the new state and nothing changes.
Hold the setting in firmware/usb.c and reapply it from usb_configure_drivers() on each connect, which is where the other drivers are already configured. usb_set_serial()/usb_get_serial() sit alongside usb_set_hid(), which works this way for the same reason.
toggle_usb_core_driver() goes with it: toggle_usb_serial() was its only
caller, and a generic wrapper around a call that cannot persist is not worth keeping.
Affects any target building USB_ENABLE_SERIAL.
Change-Id: I171a532d23cc9cf0efe0a01c2836b69846333a4d
Co-Authored-By: Claude Opus 4.8
usb_serial_control_request() copies the line coding and returns handled = true without calling usb_core_control_response(). usb_core only answers requests a driver declines, so returning handled makes the status stage the driver's responsibility and nothing sends it. The host sees the request accepted and then times out waiting for status.
Every other branch in this function already responds but this one was missed.
Affects any target building USB_ENABLE_SERIAL. The symptom is a CDC console that enumerates and then stalls when a terminal opens it and sets the line rate.
Change-Id: Icd97805971c68ce3a599cf01e9f6aa103c61c2ec
Co-Authored-By: Claude Opus 4.8
nand_init() guards its one-time setup with a static `inited` flag that
nothing ever assigns, so every call re-runs the initialiser. That resets
refcount to 0 on a driver another caller may already hold open, and the next nand_close() then decrements from zero and tears the driver down underneath its user.
Assign the flag, and fix the caller that reaches this. On a failed open the installer's updater_cleanup() would call nand_close() against a driver nand_open() never took a reference on, because nand_open() only takes one once it has identified the chip; release the lock and drop the pointer instead.
Change-Id: I88d54ac5bca9bcebb62fd9c6f50f1acf982a9a3b
Co-Authored-By: Claude Opus 4.8
backup_bootloader() and restore_bootloader() initialise `fd = 0` and their error paths close it unconditionally. Any failure before the file is opened updater_init(), or the size check between them therefore reaches close(0) and closes whatever fd 0 happens to be. On a native target that is whatever the filesystem layer handed out first, so an unrelated open file is closed and the damage surfaces somewhere else entirely.
Initialise to -1 instead, which is the value close() ignores.
Found by inspection while bringing up another Ingenic target. Not run on
X1000 hardware.
Change-Id: Ib043f79f0b7edc7c70ccd77cbff54e264ed2b2de
Co-Authored-By: Claude Opus 4.8
The enable check read
if(r & (1 << info->en_bit) == 0)
`==` binds tighter than `&`, so this evaluates as `r & ((1 << bit) == 0)`,
i.e. `r & 0`, which is always false. The check never fired, and a supply
that was switched off reported the voltage it would have had if enabled.
Callers cannot tell "off" from "on at this voltage", so anything reading a rail back to confirm it came up gets a false confirmation.
Found by inspection while bringing up another Ingenic target. Not run on
X1000 hardware as I do not have one of these devices.
Change-Id: I19fc89ff33cce047160d826ce2344cc34b26e224
Co-Authored-By: Claude Opus 4.8
1. The "Ignore files" checkbox was saved in the settings but not
consulted when starting generation. Patterns from the text field were
therefore applied even when the checkbox was unchecked. The pattern list
is now passed to TalkFileCreator only when the option is enabled.
2. Ignore patterns were converted to regular expressions by replacing only
'*' and '?'. Other regular-expression characters were left unescaped and
matches were not properly bounded. The patch uses Qt's
wildcardToRegularExpression() conversion instead.
3. The Talk generation dialog initially focused "Strip Extensions" because of
widget creation order. It now explicitly focuses the folder tree, matching
the task flow and making keyboard and screen-reader use more predictable.
4. The handling of talkclips.ignore is also corrected so that files below a
marked directory are skipped recursively. Previously Rockbox Utility could
generate talkclips.ignore.talk and clips for files below .rockbox even though
.rockbox/talkclips.ignore was present.
Change-Id: I1f9f14ed7fc057bc254f62148a7ef8ffb69425ed
Voice file and Talk clip generation currently run synchronously in the
GUI thread. During long TTS operations this prevents the progress window
from processing input and accessibility events. On Windows this makes
the progress list unavailable to screen readers such as NVDA and can
make Rockbox Utility appear to be hung.
The attached patch moves VoiceFileCreator and TalkFileCreator to
low-priority QThreads while keeping ProgressLoggerGui in the GUI thread.
Progress and log signals are delivered through queued Qt connections.
Cancellation remains available while a synchronous TTS request is
running. The abort flags used across threads are atomic and the abort
signal is sent through a direct connection. Worker objects and threads
are deleted through the standard finished / deleteLater lifecycle.
Talk generation now passes all selected folders to one worker and
processes them sequentially, emitting the final done signal only once.
This preserves multiple-folder selection without starting work in the
GUI thread.
Change-Id: I58aa66333d43e1be249c84e0cf46c17c119a8360
- makes SOURCE_DATE_EPOCH affect BUILDDATE and version string
- makes wpsbuild.pl output deterministic
- omits unnecessary extended metadata from zip files
- runs strip-nondeterminism on zip files if REPRODUCIBLE_ZIP is set
Change-Id: I1617e3f5233b2bc356fcfa6457be1a7785c303f9
After the SAPI5 error handling added for FS#13972, the Test TTS button
can fail with SAPI error 5 even though the engine and voice are
configured correctly. The test also destroys its QSoundEffect and
temporary file before asynchronous playback can complete.
Config::testTts() used a QTemporaryFile with no .wav extension.
TTSSapi::voice() removes the requested output before synthesis so that a
stale file cannot be mistaken for successful output. SAPI SpFileStream
was therefore asked to create an extensionless output file and returned
error 5 (invalid procedure call or argument).
After successful synthesis, QSoundEffect was allocated on the stack, its
loop count was set to zero, and the temporary file was removed when
testTts() returned. This does not allow asynchronous playback to
complete reliably.
* create a temporary directory and requests an initially
nonexistent tts-test.wav inside it;
* keep the directory and generated wave file alive for playback;
* keep QSoundEffect alive until playback finishes or fails;
* request one playback and clean up all temporary data afterward.
Change-Id: I8e482ab846e6445889118e121025ec48d3776d6b
iap-serial was hardcoded to return "ROCKBOX", and it was
not implemented at all in iap-usb.
Extend the iap-serial implementation to return the contents of
<ROCKBOX_DIR>/playername.txt, or "Rockbox" if there is an error
opening/reading that file.
And cut-n-paste this into the iap-usb side of things
Change-Id: I9d328be390b4cc8bd92237f996c41ef1e5e19724
This covers the rockbox binary (or bootloader), which increases the zip
file by 60-80k depending on the target.
It currently *excludes* codecs and plugins, which can add over 1MB to
the zip file. We can revisit this when/if we move to distributing 7zip
files instead.
Change-Id: Iec72dd3aa634ceca716975c13b7fa8707a485d30
Both Ubuntu and Windows fail to report the proper sample rate on my machines, causing crackling sound on my hiby r1. Since we explicitly specify the only supported sample rate (48 kHz), just ignore the reported value.
Change-Id: Ie6e85bf94f9e15fca0c968441d5a8ce5a0088b77
Last patch didn't swap both x and y so was wrong and messed up the coord pair
I didn't want to add more swapping due to extra overhead
ultimately the issue is that you have 1/2 pixel error (-1 0 1)
and when doing the reverse line the error is on the wrong side
so instead get the first point from the opposite dinc
Change-Id: I141c4af36a601314f2b509a9ebfcfab3b5213bcd
Decode the jack remote's play/pause and volume buttons via the
"Mikey" controller (I2C 0x72) and report them as multimedia keys so
they work on every screen, like the OF. Protocol reverse engineered
on-device, notes in mikey-6g.c.
Change-Id: If5f3d3abf043c0ce0d8ca7beb0f4b591e41c5c43
The existing code treated any ready-read notification from cscript as
proof that synthesis had completed. The SAPI script can emit other
output, so the Utility could check for the wave file before the explicit
SYNC reply and report that the output file did not exist.
The script also used global "On Error Resume Next" without reporting
errors from SpFileStream.Open(), SpVoice.Speak(), or
SpFileStream.Close(). Several waits had no timeout, allowing the GUI
thread to remain blocked indefinitely.
The changes:
* reports SAPI COM errors to Rockbox Utility;
* verifies that SAPI actually created the requested wave file;
* waits for the explicit SYNC reply instead of any process output;
* applies finite timeouts to vendor queries, synthesis, and shutdown;
* terminates a stuck private cscript process safely;
* restarts cscript and retries the current string up to three times when a
third-party SAPI engine stops responding during a long generation run.
Change-Id: I2cf2aefb704353c648bef0c4312f35282ac4e25d
VoiceFileCreator::createVoiceFile() stored corrFile as the address of a
local QTemporaryFile (or a local QFile used as fallback). Both objects
were destroyed before VoiceFileCreator::create() called
TalkGenerator::setLang(), leaving a dangling pointer.
On Windows this produced an access violation in RockboxUtility.exe
immediately after the voice strings had been read. Windows reported
exception 0xc0000005.
The change gives the corrections file QObject lifetime under
VoiceFileCreator, uses the built-in corrections file as a persistent
default, and replaces it with a persistent extracted QTemporaryFile when
extraction succeeds.
Change-Id: I29a371d2431021833676dec2b875186a3c021b13
* Moldavian (Mihai Alexandru Vasiliu)
* Romanian (Mihai Alexandru Vasiliu)
* Simplified Chinese (Wang Ji)
Change-Id: I586102fc47999667dec959f9f846ddd10061ad5f
iAP accessories that query the track information via mode3/mode4 result
in a call to get_metatada(). This routinely overlows the current 6KB
thread stack into the iAP RX buffer, possibly corrupting the current iAP
packet being received/processed. Bumping this to 8K should yield over
1K of headroom.
(The tagcache scanning thread uses a 16KB stack in comparison)
Inspired by commit 99b21cd6c on the rockpod fork. (Nux Li)
Change-Id: Ibe997f3ae9dab2dcc2d9947f0b49d206a5b006b6
Without this we'd need 6.7 or newer, which isn't that big of a deal except
we want to support producing RHEL9-based AppImages.
Change-Id: I931be94400d0d19af7fba498f46f174f51a4cd8b
Holding HOLD on the remote while powering on was incorrectly
detected as a bootloader mode entry request because remote_type()
was not yet initialized. Add sleep(HZ/8) after lcd_remote_init()
and re-check remote_button_hold() only if a remote is detected.
Fixes erratic bootloader entry on remote-connected H300.
Change-Id: Ic042cf5ff40713e93b2096d4ee48d7e1001ce4a5
Allows any EQ band to be set to any of Low Shelf, Peak, or High Shelf, instead of hardcoding the types per band.
Change-Id: I470ab916359092ba465e7b6331baed3bf11b2fc9
use require "audio_status" to use the new AUDIO_STATUS_ defines
use require "file_attrs" to use the new FILE_ATTR_ defines
Change-Id: If0b3b612e92e9e5b361a9487ccca2d40f79a953e
Fixes possible crash during playback with
'Auto-Change Directory' setting enabled.
When the currently playing directory changes, the
skin may be updated on the main thread while the
playback thread is executing create_and_play_dir
and has yet to add any indices to the newly created
playlist.
Introduced in commit 41d5ca3.
Change-Id: I6e930f2db546c7690b362ba8c1a4907d0348ff52
PictureFlow refuses to start on the larger panels in this family with
"Not enough memory for album art cache", no matter how small the
library is.
It is PF_PLAYBACK_CAPABLE here, so it deliberately takes the plugin
buffer instead of stealing the audio buffer in order to keep playback
running. It then gives a quarter of that buffer to its album art cache,
which needs DISPLAY_WIDTH * DISPLAY_HEIGHT * sizeof(pix_t) bytes:
HiBy R1 480x800 -> 400x533 -> 416 KiB
HiBy R3 Pro II 480x720 -> 360x480 -> 338 KiB
Surfans F28 320x480 -> 240x320 -> 150 KiB
A quarter of 512KiB is only 128KiB, so all three fail the check before
they ever look at the library. The rest of the family tops out at
320x240 and needs at most 68KiB, which is why the old value went
unnoticed.
Most hibyos devices only have 32MB of RAM in total, and the OS and its
daemons eat about two thirds of that, so there is nothing spare to hand
out and the buffer stays at 512KiB. The three affected targets happen to
be exactly the 64MB ones, and they are also the only members of the
family configured with MEMORYSIZE >= 16, so key the size off that.
Plugins are dlopen()ed on hosted targets, so pluginbuf is plain BSS and
plugin.lds/DRAMSIZE do not apply.
Change-Id: I38db01231bbb8d139cb2239623a79250e0e46b61
`channel_stopped` compacts the `active_channels` array, so we should check the same index for the next active channel.
Change-Id: I54c42f9b6c97f0c54d43b8faae0052e856f3c06d
Use flac_seek by time even when elapsedtime is 0, and apply it as a fallback for failed offset seeks since it provides more robust error recovery.
Change-Id: I438888fba02bda38137f3f1347bb1f657ef9c166
Implement the USB Audio Class DAC on the HiBy R1 and R3ProII, driven by
the usb_audio setting from the scaffolding patch: the host plays audio
over USB and the player's CS43131 renders it.
The vendor kernel provides a UAC gadget function "uac_sa" whose char
device /dev/uac_sa delivers the host's PCM: the isochronous OUT frames
are converted to left-justified S16-in-S32 stereo and queued in a kernel
ring, drained with a non-blocking read(). The data path lives in
usb-dac-hiby.c -- a pump thread drains /dev/uac_sa into a small
single-producer/single-consumer ring and the mixer callback hands that
PCM to the codec through the normal ALSA output path. No resampling is
needed because Rockbox clocks the codec at the host-negotiated rate.
The DAC is built on the existing configfs gadget and binds the UDC like
ADB, while usb_power_only keeps the USB thread out of the way. In charge
mode it is a standalone self-bound gadget. In adb mode it is composed
alongside adb on one gadget so the host gets a sound card and adb at
once; uac_sa must be the first-linked function (audio interfaces 0-1)
because the vendor function hard-codes its interface numbers.
The pump is hardware-only, so usb-dac-hiby.c is excluded from simulator
builds; the usb_audio_get_active() playback-interlock stub lives with the
scaffolding.
The R3ProII shares this hosted HiBy port and the same userspace gadget,
and the data path is codec-agnostic, so nothing here is R1-specific.
Only the R1 has been validated on-device.
Co-Authored-By: Claude Opus 4.8
Change-Id: I64c57ede27f411a2c61d41a7e0fa127b51a7b5b9
Introduce the generic, target-agnostic pieces for a gadget-driven USB
Audio Class DAC, gated by the HAVE_HOST_USB_AUDIO target flag so they stay
inert unless a target opts in.
Rather than adding a new USB mode, reuse the existing usb_audio setting
(never / always / while charge-only / while mass-storage) with its
LANG_USB_DAC string, usb_set_audio() callback and the
PCM_MIXER_CHAN_USBAUDIO mixer channel. HAVE_HOST_USB_AUDIO becomes the
umbrella capability flag for this common code; USB_ENABLE_AUDIO stays the
native usbstack class-driver contract (which needs HAVE_USBSTACK and so
cannot be used by hosted ports whose kernel owns the USB controller).
usb_set_audio() is declared here and implemented by the target (natively
by the usbstack driver, or in the hosted port for gadget targets, as with
usb_audio_get_active()), and applied at settings load. The playback
interlock in wps.c/playback.c keeps local playback from mixing with host
audio while the DAC is active. Simulator stubs for usb_set_audio() and
usb_audio_get_active() keep sim builds linking.
Co-Authored-By: Claude Opus 4.8
Change-Id: I5b7738508c24721d91d4c32379102a1ac7c6228b
thread_get_debug_info() computes the current stack usage as
stack_used_current * 100 / thread->stack_size with no guard against a zero
stack size. On hosted targets the main thread has stack_size == 0, so
opening the "View OS stacks" debug screen divides by zero and panics with a
floating point exception.
Guard the division and report 0% when the stack size is unknown, which
matches the stack_usage() helper.
Likely affects all hosted non-SDL targets, but tested/confirmed on my
HiBy R1.
Change-Id: I8ecc56f53f1e97e8a59ca71c0e08a66093fecbae
This flag was added in GCC 16; older versions of GCC don't
accept it and don't produce the warning, so they don't need
any special handling.
Change-Id: I13fcba07cafe0b4133de8b03ede681d2454249e4
Wipe the PCM buffer when starting playback from a paused state.
This prevents unwanted crossfade when manually pausing and then
selecting a new track.
Change-Id: I55e21004c12a2cd67417b627d471e3da115b7077
when browsing the filename gets cut off due to the
length of the parent path
Instead strip the parent from the beginning for files
Change-Id: Ib9dadffabced89b5895420cb696227ca8cc444a2
0 is an invalid value to set on Hiby as "Output Port Switch". For devices with multiple outputs, we need to ensure it is set to a valid port.
Change-Id: I16ea2e620fae3034dccf3267d316924d8e2c0a95
The warning comes from code generated by QT's MOC, so there isn't
anything to be done until QT addresses this properly.
Change-Id: Ia88ac9af91acbab783b683a6f0b4f4a304aa9e4d
hibyr1 defines HAVE_USB_ADB so the USB mode setting offers an ADB
entry, but hiby_set_usb_mode() never handled USB_MODE_ADB (it fell
through to default), so selecting ADB did nothing.
Wire USB_MODE_ADB up to enable_adb(). It builds the adb function on
the gadget and hands the functionfs mount and adbd to the vendor
respawner /sbin/adbserver.sh, rather than mounting functionfs inline
(which the original code flagged as flaky); adbd binds the UDC itself,
so usb_enable() leaves the UDC alone in ADB mode. disable_adb() unlinks
the adb function and unmounts its functionfs but leaves the function in
place to be reused, matching how adbserver.sh cycles it, so re-enabling
adb never re-creates it.
The mass-storage LUN is removable, so the host clears its backing file
when it ejects the volume (Linux does this on unmount). Re-arm the LUN
in usb_enable() on each connect, so the disk is exported on every
insert and not only the first.
Assisted-by: Claude Opus 4.8
Change-Id: Ia8f119a1a599e6dd3c1219cb4e193c753725a06a
Results in cleaner code versus effectively cut-n-pasting the driver's
completion callbacks into the endpoint structure.
Change-Id: I043c46c91796f787dec098a7db043481834950a0
desc: format string for how dates will be read back. Y == 4-digit year, A == month name, m == numeric month, d == numeric day. For example, "AdY" will read "January 21 2021"
desc: format string for how dates will be read back. Y == 4-digit year (grouped), y == 4-digit year (numeric), A == month name, m == numeric month, d == numeric day. For example, for 2021-01-05, "AdY" will be voiced as "January 5 twenty twenty-one" and "dmy" will be voiced as "5 1 two thousand twenty one
user: core
<source>
*: "dAY"
</source>
<dest>
*: "dAY"
*: "~dAY"
</dest>
<voice>
*: ""
@ -15917,16 +15903,16 @@
</phrase>
<phrase>
id: LANG_DEFAULT_BROWSER
desc: in Settings
desc: deprecated
user: core
<source>
*: "Default Browser"
*: ""
</source>
<dest>
*: "Alapértelmezett böngésző"
*: ""
</dest>
<voice>
*: "Alapértelmezett böngésző"
*: ""
</voice>
</phrase>
<phrase>
@ -16975,3 +16961,171 @@
*: "~U S B"
</voice>
</phrase>
<phrase>
id: LANG_SET_CONTEXT_ITEM
desc: WPS context item
user: core
<source>
*: "Set Context Item"
</source>
<dest>
*: "Kontextus elem beállítása"
</dest>
<voice>
*: "Kontextus elem beállítása"
</voice>
</phrase>
<phrase>
id: LANG_KEEP_DIRECTORY
desc: file browser setting
user: core
<source>
*: "Always remember last folder"
</source>
<dest>
*: "Mindig emlékezzen a legutóbbi mappára"
</dest>
<voice>
*: "Mindig emlékezzen a legutóbbi mappára"
</voice>
</phrase>
<phrase>
id: LANG_FILE_NOT_FOUND
desc: When file does not exist
user: core
<source>
*: "File not found"
</source>
<dest>
*: "Fájl nem található"
</dest>
<voice>
*: "Fájl nem található"
</voice>
</phrase>
<phrase>
id: LANG_SHOW_IN_FILES
desc: Reveal item in File Browser
user: core
<source>
*: "Show in Files"
</source>
<dest>
*: "Mutatás a Fájlokban"
</dest>
<voice>
*: "Mutatás a Fájlokban"
</voice>
</phrase>
<phrase>
id: LANG_CHANNEL_SWAP
desc: in sound_settings
user: core
<source>
*: "Swap Left & Right"
</source>
<dest>
*: "Bal & Jobb megcserélése"
</dest>
<voice>
*: "Bal & Jobb megcserélése"
</voice>
</phrase>
<phrase>
id: LANG_COUNTDOWN_TIMER_SET
desc: countdown_timer plugin - header shown on the setup screen where the user enters the countdown duration
user: core
<source>
*: "SET TIMER"
</source>
<dest>
*: "IDŐZÍTŐ BEÁLLÍTÁSA"
</dest>
<voice>
*: "Időzítő beállítása"
</voice>
</phrase>
<phrase>
id: LANG_COUNTDOWN_TIMER_RUNNING
desc: countdown_timer plugin - status label shown while the countdown is active
user: core
<source>
*: "RUNNING"
</source>
<dest>
*: "FUT"
</dest>
<voice>
*: "Fut"
</voice>
</phrase>
<phrase>
id: LANG_COUNTDOWN_TIMER_PAUSED
desc: countdown_timer plugin - status label shown while the countdown is paused
user: core
<source>
*: "PAUSED"
</source>
<dest>
*: "MEGÁLLÍTVA"
</dest>
<voice>
*: "Megállítva"
</voice>
</phrase>
<phrase>
id: LANG_COUNTDOWN_TIMER_OVERTIME
desc: countdown_timer plugin - status label shown when the countdown has passed zero and is counting up
user: core
<source>
*: "OVERTIME"
</source>
<dest>
*: "TÚLÓRA"
</dest>
<voice>
*: "Túlóra"
</voice>
</phrase>
<phrase>
id: LANG_COUNTDOWN_TIMER_FINISHED
desc: countdown_timer plugin - status label shown at the moment the countdown expires
android,hifietma*,zenvision: "Press BACK to cancel."
android,hifietma*: "Press BACK to cancel."
cowond2,creativezenxfi2,ibassodx50,ibassodx90,mrobe500,ondavx747: "Press POWER to cancel."
ihifi760,ihifi960: "Double tap RETURN to cancel."
ihifi770,ihifi770c,ihifi800: "Press HOME to cancel."
@ -14450,7 +14450,7 @@
<dest>
*: "Druk op LINKS om te annuleren."
android: "Druk op RECHTS om te annuleren."
hifietma*,zenvision: "Druk op BACK om te annuleren."
hifietma*: "Druk op BACK om te annuleren."
cowond2,creativezenxfi2,ibassodx50,ibassodx90,mrobe500,ondavx747: "Druk op POWER om te annuleren."
ihifi760,ihifi960: "Dubbeltik op RETURN om te annuleren."
ihifi770,ihifi770c,ihifi800: "Druk op HOME om te annuleren."
@ -14466,7 +14466,7 @@
<voice>
*: "Druk op LINKS om te annuleren."
android: "Druk op RECHTS om te annuleren."
hifietma*,zenvision: "Druk op BACK om te annuleren."
hifietma*: "Druk op BACK om te annuleren."
cowond2,creativezenxfi2,ibassodx50,ibassodx90,mrobe500,ondavx747: "Druk op POWER om te annuleren."
ihifi760,ihifi960: "Dubbeltik op RETURN om te annuleren."
ihifi770,ihifi770c,ihifi800: "Druk op HOME om te annuleren."
@ -14707,20 +14707,6 @@
*: "Geen plug-in"
</voice>
</phrase>
<phrase>
id: LANG_OPEN_PLUGIN_SET_WPS_CONTEXT_PLUGIN
desc: open plugin module
user: core
<source>
*: "Set WPS Context Plugin"
</source>
<dest>
*: "Stel WPS Context Plugin in"
</dest>
<voice>
*: "Stel WPS Context Plugin in"
</voice>
</phrase>
<phrase>
id: LANG_PARAMETER
desc:
@ -15202,7 +15188,7 @@
</phrase>
<phrase>
id: LANG_VOICED_DATE_FORMAT
desc: format string for how dates will be read back. Y == 4-digit year, A == month name, m == numeric month, d == numeric day. For example, "AdY" will read "January 21 2021"
desc: format string for how dates will be read back. Y == 4-digit year (grouped), y == 4-digit year (numeric), A == month name, m == numeric month, d == numeric day. For example, for 2021-01-05, "AdY" will be voiced as "January 5 twenty twenty-one" and "dmy" will be voiced as "5 1 two thousand twenty one
user: core
<source>
*: "dAY"
@ -15811,16 +15797,16 @@
</phrase>
<phrase>
id: LANG_DEFAULT_BROWSER
desc: in Settings
desc: deprecated
user: core
<source>
*: "Default Browser"
*: ""
</source>
<dest>
*: "Standaard Browser"
*: ""
</dest>
<voice>
*: "Standaard Browser"
*: ""
</voice>
</phrase>
<phrase>
@ -16967,3 +16953,185 @@
*: "~U S B"
</voice>
</phrase>
<phrase>
id: LANG_ANNOUNCE_STATUS
desc: announnnce_status plugin
user: core
<source>
*: "Announce Status"
</source>
<dest>
*: "Status aankondigen"
</dest>
<voice>
*: "Status aankondigen"
</voice>
</phrase>
<phrase>
id: LANG_SET_CONTEXT_ITEM
desc: WPS context item
user: core
<source>
*: "Set Context Item"
</source>
<dest>
*: "Contextitem instellen"
</dest>
<voice>
*: "Contextitem instellen"
</voice>
</phrase>
<phrase>
id: LANG_KEEP_DIRECTORY
desc: file browser setting
user: core
<source>
*: "Always remember last folder"
</source>
<dest>
*: "Altijd laatste map onthouden"
</dest>
<voice>
*: "Altijd laatste map onthouden"
</voice>
</phrase>
<phrase>
id: LANG_FILE_NOT_FOUND
desc: When file does not exist
user: core
<source>
*: "File not found"
</source>
<dest>
*: "Bestand niet gevonden"
</dest>
<voice>
*: "Bestand niet gevonden"
</voice>
</phrase>
<phrase>
id: LANG_SHOW_IN_FILES
desc: Reveal item in File Browser
user: core
<source>
*: "Show in Files"
</source>
<dest>
*: "In bestanden tonen"
</dest>
<voice>
*: "In bestanden tonen"
</voice>
</phrase>
<phrase>
id: LANG_CHANNEL_SWAP
desc: in sound_settings
user: core
<source>
*: "Swap Left & Right"
</source>
<dest>
*: "Links & Rechts omwisselen"
</dest>
<voice>
*: "Links & Rechts omwisselen"
</voice>
</phrase>
<phrase>
id: LANG_COUNTDOWN_TIMER_SET
desc: countdown_timer plugin - header shown on the setup screen where the user enters the countdown duration
user: core
<source>
*: "SET TIMER"
</source>
<dest>
*: "TIMER INSTELLEN"
</dest>
<voice>
*: "Timer instellen"
</voice>
</phrase>
<phrase>
id: LANG_COUNTDOWN_TIMER_RUNNING
desc: countdown_timer plugin - status label shown while the countdown is active
user: core
<source>
*: "RUNNING"
</source>
<dest>
*: "ACTIEF"
</dest>
<voice>
*: "Actief"
</voice>
</phrase>
<phrase>
id: LANG_COUNTDOWN_TIMER_PAUSED
desc: countdown_timer plugin - status label shown while the countdown is paused
user: core
<source>
*: "PAUSED"
</source>
<dest>
*: "GEPAUZEERD"
</dest>
<voice>
*: "Gepauzeerd"
</voice>
</phrase>
<phrase>
id: LANG_COUNTDOWN_TIMER_OVERTIME
desc: countdown_timer plugin - status label shown when the countdown has passed zero and is counting up
user: core
<source>
*: "OVERTIME"
</source>
<dest>
*: "OVER TIJD"
</dest>
<voice>
*: "Over tijd"
</voice>
</phrase>
<phrase>
id: LANG_COUNTDOWN_TIMER_FINISHED
desc: countdown_timer plugin - status label shown at the moment the countdown expires
android,hifietma*,zenvision: "Press BACK to cancel."
android,hifietma*: "Press BACK to cancel."
cowond2,creativezenxfi2,ibassodx50,ibassodx90,mrobe500,ondavx747: "Press POWER to cancel."
ihifi760,ihifi960: "Double tap RETURN to cancel."
ihifi770,ihifi770c,ihifi800: "Press HOME to cancel."
@ -14704,7 +14704,7 @@
</source>
<dest>
*: "Nhấn LEFT để hủy."
android,hifietma*,zenvision: "Nhấn BACK để hủy."
android,hifietma*: "Nhấn BACK để hủy."
cowond2,creativezenxfi2,ibassodx50,ibassodx90,mrobe500,ondavx747: "Nhấn POWER để hủy."
ihifi760,ihifi960: "Nhấn đúp RETURN để hủy."
ihifi770,ihifi770c,ihifi800: "Nhấn HOME để hủy."
@ -14719,7 +14719,7 @@
</dest>
<voice>
*: "Nhấn LEFT để hủy."
android,hifietma*,zenvision: "Nhấn BACK để hủy."
android,hifietma*: "Nhấn BACK để hủy."
cowond2,creativezenxfi2,ibassodx50,ibassodx90,mrobe500,ondavx747: "Nhấn POWER để hủy."
ihifi760,ihifi960: "Nhấn đúp RETURN để hủy."
ihifi770,ihifi770c,ihifi800: "Nhấn HOME để hủy."
@ -14960,20 +14960,6 @@
*: "Không phải là plugin"
</voice>
</phrase>
<phrase>
id: LANG_OPEN_PLUGIN_SET_WPS_CONTEXT_PLUGIN
desc: open plugin module
user: core
<source>
*: "Set WPS Context Plugin"
</source>
<dest>
*: "Đặt ngữ cảnh Wps của Plugin"
</dest>
<voice>
*: "Đặt ngữ cảnh WPS của Plugin"
</voice>
</phrase>
<phrase>
id: LANG_PARAMETER
desc:
@ -15214,7 +15200,7 @@
</phrase>
<phrase>
id: LANG_VOICED_DATE_FORMAT
desc: format string for how dates will be read back. Y == 4-digit year, A == month name, m == numeric month, d == numeric day. For example, "AdY" will read "January 21 2021"
desc: format string for how dates will be read back. Y == 4-digit year (grouped), y == 4-digit year (numeric), A == month name, m == numeric month, d == numeric day. For example, for 2021-01-05, "AdY" will be voiced as "January 5 twenty twenty-one" and "dmy" will be voiced as "5 1 two thousand twenty one
user: core
<source>
*: "dAY"
@ -15823,16 +15809,16 @@
</phrase>
<phrase>
id: LANG_DEFAULT_BROWSER
desc: in Settings
desc: deprecated
user: core
<source>
*: "Default Browser"
*: ""
</source>
<dest>
*: "Trình duyệt mặc định"
*: ""
</dest>
<voice>
*: "Trình duyệt mặc định"
*: ""
</voice>
</phrase>
<phrase>
@ -16971,3 +16957,205 @@
*: "~U S B"
</voice>
</phrase>
<phrase>
id: LANG_SET_CONTEXT_ITEM
desc: WPS context item
user: core
<source>
*: "Set Context Item"
</source>
<dest>
*: "Đặt Vật phẩm Bối cảnh"
</dest>
<voice>
*: "Đặt Vật phẩm Bối cảnh"
</voice>
</phrase>
<phrase>
id: LANG_KEEP_DIRECTORY
desc: file browser setting
user: core
<source>
*: "Always remember last folder"
</source>
<dest>
*: "Luôn ghi nhớ thư mục lần trước"
</dest>
<voice>
*: "Luôn ghi nhớ thư mục lần trước"
</voice>
</phrase>
<phrase>
id: LANG_FILE_NOT_FOUND
desc: When file does not exist
user: core
<source>
*: "File not found"
</source>
<dest>
*: "Không tìm thấy tập tin"
</dest>
<voice>
*: "Không tìm thấy tập tin"
</voice>
</phrase>
<phrase>
id: LANG_SHOW_IN_FILES
desc: Reveal item in File Browser
user: core
<source>
*: "Show in Files"
</source>
<dest>
*: "Hiển thị trong Tập Tin"
</dest>
<voice>
*: "Hiển thị trong Tập Tin"
</voice>
</phrase>
<phrase>
id: LANG_CHANNEL_SWAP
desc: in sound_settings
user: core
<source>
*: "Swap Left & Right"
</source>
<dest>
*: "Hoán đổi Trái & Phảii"
</dest>
<voice>
*: "Hoán đổi Trái & Phảii"
</voice>
</phrase>
<phrase>
id: LANG_COUNTDOWN_TIMER_SET
desc: countdown_timer plugin - header shown on the setup screen where the user enters the countdown duration
user: core
<source>
*: "SET TIMER"
</source>
<dest>
*: "ĐẶT KHOẢNG THỜI GIAN"
</dest>
<voice>
*: "Đặt khoảng thời gian"
</voice>
</phrase>
<phrase>
id: LANG_COUNTDOWN_TIMER_RUNNING
desc: countdown_timer plugin - status label shown while the countdown is active
user: core
<source>
*: "RUNNING"
</source>
<dest>
*: "ĐANG CHẠY"
</dest>
<voice>
*: "Đang chạy"
</voice>
</phrase>
<phrase>
id: LANG_COUNTDOWN_TIMER_PAUSED
desc: countdown_timer plugin - status label shown while the countdown is paused
user: core
<source>
*: "PAUSED"
</source>
<dest>
*: "Tạm dừng"
</dest>
<voice>
*: "Tạm dừng"
</voice>
</phrase>
<phrase>
id: LANG_COUNTDOWN_TIMER_OVERTIME
desc: countdown_timer plugin - status label shown when the countdown has passed zero and is counting up
user: core
<source>
*: "OVERTIME"
</source>
<dest>
*: "QUÁ GIỜ"
</dest>
<voice>
*: "Quá giờ"
</voice>
</phrase>
<phrase>
id: LANG_COUNTDOWN_TIMER_FINISHED
desc: countdown_timer plugin - status label shown at the moment the countdown expires
user: core
<source>
*: "FINISHED"
</source>
<dest>
*: "HOÀN THÀNH"
</dest>
<voice>
*: "Hoàn thành"
</voice>
</phrase>
<phrase>
id: LANG_EQUALIZER_BAND
desc: in the equalizer settings menu
user: core
<source>
*: "Filter %d"
</source>
<dest>
*: "Bộ lọc %d"
</dest>
<voice>
*: "Bộ lọc"
</voice>
</phrase>
<phrase>
id: LANG_EQUALIZER_FILTER_TYPE
desc: in the equalizer settings menu
user: core
<source>
*: "Filter Type"
</source>
<dest>
*: "Kiểu Bộ lọc"
</dest>
<voice>
*: "Kiểu bộ lọc"
</voice>
</phrase>
<phrase>
id: LANG_COMPOSITE_VIDEO_OUTPUT
desc: Enables composite video framebuffer mirroring on supported targets