The pins a board publishes are visible in /dev and each can be read
through its own node, but surveying a whole board that way means an open
and two ioctls per pin, and the signal and interrupt counters the upper
half keeps are not reachable through any of them.
Adds a list of registered pins and publishes it as /proc/gpio, behind
GPIO_PROCFS: a quality of life view of the same kind as /proc/pinctrl
and /proc/reset. Every common field comes from state the upper half
already holds: the pin type, the value through go_read(), how many times
the pin has been registered for signals, and how many interrupts it has
taken. Lines carry the same key:value tokens in the same order, so the
file is machine parseable.
Lower halves may supply an optional go_describe() adding what only they
can say, such as which pad carries the line or how its trigger is
configured. It writes text into a caller supplied buffer and the upper
half owns the line, so a lower half needs no procfs knowledge. A lower
half without it is listed with the common tokens alone.
The pin type index is bounded before use: it comes from the lower half
and the name table cannot cover a type the enumeration does not define.
A pin that cannot be read reports val:- rather than a zero that would
read as a real level.
procfs_register() appends without checking for duplicates, so the entry
is claimed once for the lifetime of the system rather than whenever the
list is empty; pins come and go at run time.
The name is held in a buffer as long as the one gpio_pin_register()
accepts, so a listing always names the same string as /dev.
The pin type name table is declared without an explicit size so that the
assertion beside it compares against the enumeration and can fail; sized
as [GPIO_NPINTYPES] it would have been tautological.
Documents the entry, its tokens, and how a lower half describes a pin.
Off by default: with GPIO_PROCFS unset the list, the lock and the procfs
entry are compiled out, and go_describe() is one more member at the end
of a structure existing lower halves do not reach.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
The TMP112 driver was character mode only, and carried the warning that
says so: a read returns a bare float, at a size the driver chose, and
nothing but code written for this one part can make sense of it.
Add the sensor framework version beside it, in the shape the tree
already uses for a part that has both. The old driver is untouched and
still builds by default; the new one replaces it when
SENSORS_TMP112_UORB is set, and the part then appears as a temperature
topic that the common sensor tools can read without knowing what a
TMP112 is.
It reads on the low priority work queue at whatever interval the caller
asks for. The part converts continuously out of reset, so nothing is
configured and the temperature register always holds the last completed
conversion: a reading is one bus transaction with nothing to wait for.
Reading faster than the part converts repeats a value, which costs bus
traffic and nothing else, so the interval is taken as given: the upper
half treats a lower half that hands back a longer interval than it was
given as a failed request, so clamping here would refuse a fast caller
rather than serve it slowly.
get_info reports what the part is and what its readings mean, so a
consumer need not know it is talking to a TMP112 to know the range and
the resolution.
It also sign extends the reading. The register holds twelve bits, and
the character mode driver treats them as unsigned, so anything below
freezing comes back as a large positive temperature; the part is
specified down to -40C. Fixing that in the old driver would change what
existing callers see, so it is fixed here, where there are no callers
yet to surprise.
This driver also covers the TMP102, which differs in accuracy rather
than in its registers: only the two both parts have are touched.
Documented under the sensors section, beside the other parts with a page
of their own, and listed among the uORB drivers.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
The cooling device renamed in the previous commit was written against a
cpufreq framework that never landed. It includes nuttx/cpufreq.h, which
does not exist, and THERMAL_CDEV_CPUFREQ depends on CPUFREQ, which no
Kconfig in the tree defines, so it has never been selectable and has never
been compiled. The cpufreq half of the dummy driver is orphaned the same
way behind THERMAL_DUMMY_CPUFREQ. Upstream noticed once already and
dropped cpufreq from the sim thermal configuration in 898a5d501f.
devfreq does the same job and is here. It carries the frequency table,
arbitrates windows through QoS, and its DEVFREQ_CONFLICT_PREFER_LOW is
documented as the policy for a device protecting a thermal budget, which
is exactly a cooling device's claim on it. Point the cooling device at
that instead, and the thermal framework can throttle again.
Two things change beyond the API. The cooling state now names a ceiling
rather than a two entry window, because devfreq resolves a conflicting
floor in the ceiling's favour, and that makes the whole table reachable:
max_state is one less than the number of usable entries, state zero leaves
the top entry available and the highest state holds the device at the
bottom one. A DEVFREQ_ENTRY_INVALID entry is a hole the driver has
punched and cannot be installed as a ceiling, so it earns no cooling
state; counting it would both advertise a state the device cannot deliver
and, on reaching it, install a ceiling of ~0u, which caps nothing. And the device is found by name, since devfreq is multi instance
where a cpufreq policy was singular, so THERMAL_CDEV_DEVFREQ_NAME says
which one to cool and what to call the cooling device in a zone's map.
The dummy driver gains a devfreq lower half in place of its cpufreq one,
which gives the tree its first devfreq consumer and makes the whole path
testable without hardware. On sim, walking the dummy zone from 45 to 90
degrees:
temp cooling state frequency
60 0 900
62 1 700
61 2 500
72 3 300
74 4 100
and back down again as it cools.
Also fixes two faults the file could not previously reveal: it called
therr and thinfo without including nuttx/debug.h, and it reached the
driver by casting the policy pointer, which worked only while driver was
the first member.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
This is the rename on its own, with no change to the contents, so that the
port that follows is readable as a diff against the file it came from rather
than as a deletion and a new file.
The reason for the move is in the next commit.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
Nothing in the controller driver is PCI-specific beyond finding the
registers and the interrupt, so an SoC wiring an xHCI controller
directly could not use any of it.
usbhost_xhci.c is now the driver; usbhost_xhci_pci.c is the PCI
attachment, holding the ID table, the BAR mapping and the MSI-X vector.
include/nuttx/usb/xhci.h carries what passes between them: the register
base, a way to attach the interrupt, and a name to report the controller
by, since a system may have more than one.
The interrupt belongs to the bus: the bus attaches and detaches it, and
the driver never holds an interrupt number.
USBHOST_XHCI is the driver and is not selectable on its own;
USBHOST_XHCI_PCI selects it. Another bus adds its own symbol beside it.
No functional change intended.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
Pure rename, so that the history of the driver follows it into the file
that keeps the bulk of the code. The PCI attachment is added back as a
new usbhost_xhci_pci.c in the commit that follows.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
The NXP PCF8563 is a battery backed I2C clock at the fixed address 0x51,
common on RISC-V and ARM boards, and NuttX had no driver for it. The
nearest part in the tree, the PCF85263, has a different register map.
The driver follows the shape of the external I2C clocks already here,
ds3231 and pcf85263: board logic calls pcf8563_rtc_initialize() once the
bus exists, and the chip then answers up_rtc_getdatetime() and
up_rtc_settime() for the system clock.
Three behaviours are deliberate.
The top bit of the seconds register means the oscillator has stopped since
the time was last set, so every register after it holds whatever it stopped
on. A read in that state returns -ENODATA rather than the contents: a
caller told the time is unknown can act on that, one told a wrong time
cannot. A flat backup cell and a clock that has never been set both arrive
here.
The top bit of the month register marks a century rollover, but which value
means which century is a convention that parts disagree on, so no century
is read from it. The chip is treated as a clock for 2000 to 2099, the bit
is written back as it was read, and a date outside those years is refused
rather than stored as one that would read back different. This is what the
mainline Linux driver does.
The counters are stopped across a write so a carry cannot land between the
seconds and the minutes, and restarted even when the write failed, since
the alternative is leaving the clock stopped.
The alarm and countdown timer are not implemented; their registers are
defined.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
The regulator framework has no way out to userspace: consumers reach a
rail by name from inside the kernel, which is the right interface for
controlling one, but it leaves a board with regulators offering no way
to see what they are doing, and a newly written regulator driver cannot
be looked at without writing a consumer for it first.
Adds /proc/regulator, behind REGULATOR_PROCFS, listing every registered
regulator: its present voltage, the range it will accept, whether it is
enabled, how many consumers hold and enable it, its supply, and whether
it is always on or expected on at boot. Lines carry the same key:value
tokens in the same order, so the file is machine parseable. The last
two are worth reading beside the consumer count, since a rail enabled
with no consumers is expected rather than suspect when either is set.
A part usually measures more than the framework has fields for, so
struct regulator_ops_s gains an optional describe method: it writes
key:value text and the renderer appends it to that rail's line. This is
how a driver reports what only it knows, an input voltage, an output
current, a temperature or a fault word, without the framework growing a
field per part or the driver growing procfs code of its own. It is
called with the list mutex held and never from interrupt context, so
reading the part over a bus is allowed.
The voltage and the enabled state are read back from the hardware rather
than recalled, so a rail the boot loader set and nothing has touched
since reads as it actually is. Both calls can fail, and a failure
reports - rather than an errno formatted as a voltage or a rail that
looks switched on.
Reading the hardware is also why this takes the list mutex directly
rather than calling regulator_list_lock(), which additionally disables
interrupts so that callers in interrupt or idle context are safe.
Asking a regulator on a bus what it is doing means a transfer, and a
transfer waits; a task reading a file can afford to wait and an
interrupt handler cannot.
procfs_register() appends without checking for duplicates, so the entry
is claimed once for the lifetime of the system rather than whenever the
list is empty. It also needs FS_PROCFS_REGISTER, which the option now
depends on rather than only FS_PROCFS.
Documents the framework, which had no page at all: the consumer
interface and what counted enables mean, what a driver supplies, and the
new entry.
The entry is read only. What voltage a rail may be is knowledge its
consumers hold, and arranging the order between them is what the
framework is for, so moving one from a shell would step around the part
that matters.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
The SD path never performs the CMD6 switch its eMMC counterpart has
performed for years, so an SD card is left in default speed and every
host clocked accordingly, at 25MHz rather than the 50MHz the card
supports. A TODO in this file has asked for it since 2010; this removes
it.
A host asks for the switch by reporting SDIO_CAPS_SD_HS_MODE, which
mirrors the eMMC capability beside it. The switch is attempted once the
bus is at the default transfer rate and the wide bus is selected, and
the card's own answer decides the outcome: the 64 byte status block
reports the function actually selected, and a card that cannot do what
was asked says so there rather than failing the command. Cards below
version 1.10 of the physical layer specification are not asked, since
CMD6 postdates them.
Only a confirmed switch reaches the host, as the new
CLOCK_SD_TRANSFER_4BIT_HS rate. That is a rate rather than a flag on an
existing one because the host is clocked twice during initialization,
once before the switch can have happened, and a host that cannot tell
the two apart would run a card in default speed past its rated 25MHz.
The enumerator is added last, so no existing driver's switch statement
changes meaning, and the rate reaches only a host that reported the new
capability, which none in tree does.
Every failure path is survivable: a card that declines, a card too old
to ask, and a host that never asks all stay at the default rate.
Documents the two capabilities and the clock rates a lower half has to
handle.
The MMC/SD documentation was three sentences and a pointer to the SDIO
page, so it said nothing about how a card is registered, how the bus width
and clock are negotiated, or what any of the configuration options do. It
now covers those, the ioctl interface and /proc/mmcsd, and the high speed
switch this commit adds is described where somebody looking for it would
look rather than only in the SDIO lower half page.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
xhci_command() returned -ETIMEDOUT when a completion arrived without an
interrupt, although the fallback poll had already retrieved the event,
so callers unwound work the controller had completed.
Use the event's completion code whichever path retrieved it.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
Eight PORTSC bits are write-one-to-clear, so writing back a value just
read clears PED and every change bit that was set, disabling the port
being reset. Mask them out using the new XHCI_PORTSC_RW1C.
The wait after reset also decided on its own counter rather than on the
port, reporting a timeout for a port that enabled on the last iteration.
Test PED, and report PORTSC when it does time out.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
xhci_ctrl_halt() wrote USBCMD zero unconditionally and then waited for
HCH. A controller that was never started is already halted, so the wait
ran to its full length, and clearing the whole register also dropped
INTE and HSEE.
Test HCH first, clear only R/S when it is set, bound the wait with
XHCI_HALT_TIMEOUT_MS, and report USBCMD and USBSTS on failure.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
HCSPARAMS2 may report zero scratchpad buffers; QEMU's does. The driver
sized the array from that count unconditionally and read the NULL from a
zero byte kmm_memalign() as -ENOMEM, so such a controller never started.
Skip the allocation when no_scratch is zero, leaving DCBAA[0] clear.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
xHCI requires aligned accesses of each register's own size, and a
controller may ignore narrower ones; QEMU's does. volatile does not pin
the access width: GCC 16.1.0 at -Os narrows a 32-bit load feeding a
single bit test into a byte load, so polling USBSTS for HCH never
observes the halted state.
Launder each register value through a register with an empty asm, on
loads and stores both, so the access is the width the source specifies.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
drivers/lcd/Kconfig offers CONFIG_LCD_APA102_XRES, CONFIG_LCD_APA102_YRES and
CONFIG_LCD_APA102_FREQUENCY under "if LCD_APA102", but apa102_lcd.c tests for
CONFIG_APA102_XRES, CONFIG_APA102_YRES and CONFIG_APA102_FREQUENCY, which no
Kconfig file defines. The #ifndef fallbacks therefore always win and the
matrix geometry is hard-wired to 16x16 no matter what is configured. The
frequency setting is doubly dead: even the fallback is unused, because
apa102_configspi() calls SPI_SETFREQUENCY() with APA102_SPI_MAXFREQUENCY from
include/nuttx/leds/apa102.h, which is 100 kHz (its "Default 4MHz" comment
notwithstanding), so the chain is always clocked at 100 kHz.
Use the names the Kconfig actually defines and drive the bus at the
configured frequency. The fallback definitions are kept for an
out-of-Kconfig build and given the Kconfig defaults; 16x16 keeps the previous
geometry for anyone who never set the options.
Verified on stm32f4discovery:nsh with CONFIG_LCD_APA102_XRES=8,
CONFIG_LCD_APA102_YRES=4 and CONFIG_LCD_APA102_FREQUENCY=4000000: the shadow
framebuffer in g_apa102dev shrinks to 8x4 LEDs and the SPI frequency
argument is 0x003d0900, where before the settings had no effect at all.
Signed-off-by: Ricard Rosson <ricard@groundbits.com>
Assisted-by: Claude Opus 5 (Claude Code)
drivers/ is built by a single flat Makefile: every per-directory Make.defs
appends its sources to one CSRCS list and its directory to one VPATH, and the
objects all land in drivers/ named after the source basename. Two sources
with the same basename in different subdirectories therefore map to the same
object, and make resolves the prerequisite through VPATH, which is searched
in the order drivers/Makefile includes the Make.defs files. lcd is included
before leds, so drivers/lcd always wins.
Both apa102 and max7219 exist twice, once as an LCD front-end and once as an
LED driver:
drivers/lcd/apa102.c CONFIG_LCD_APA102 drivers/leds/apa102.c CONFIG_LEDS_APA102
drivers/lcd/max7219.c CONFIG_LCD_MAX7219 drivers/leds/max7219.c CONFIG_LEDS_MAX7219
drivers/lcd/Make.defs puts lcd on the VPATH for the whole directory whenever
CONFIG_LCD=y, so selecting only the LED driver still builds apa102.o from
drivers/lcd/apa102.c and the selected LED driver is never compiled at all.
Because the LCD front-ends take their constants from
include/nuttx/lcd/apa102.h and include/nuttx/lcd/max7219.h, which are behind
CONFIG_LCD_APA102 / CONFIG_LCD_MAX7219, the substituted source does not even
compile. With CONFIG_LCD=y + CONFIG_LEDS_APA102=y and CONFIG_LCD_APA102
unset:
lcd/apa102.c:701:20: error: 'APA102_BLACK' undeclared (first use in this
function); did you mean 'APA102_BPP'?
and correspondingly for CONFIG_LEDS_MAX7219 without CONFIG_LCD_MAX7219:
lcd/max7219.c:773:20: error: 'MAX7219_BLACK' undeclared (first use in this
function); did you mean 'MAX7219_BPP'?
So neither LED driver can be built together with CONFIG_LCD, and there is no
diagnostic pointing at the real cause.
Give the LCD front-ends distinct basenames. The LCD side is the adapted use
of these parts (an LED matrix driven as a display), and drivers/lcd already
names such variants for their role, e.g. ht16k33_14seg.c, so the suffix goes
there and the LED drivers keep the plain part names. The CMake build derives
object paths from the source directory and was never affected; its source
lists are updated to match.
Signed-off-by: Ricard Rosson <ricard@groundbits.com>
Assisted-by: Claude Opus 5 (Claude Code)
This change fixes NuttX’s CMake support when NuttX is embedded
in another project via add_subdirectory(). CMake’s CMAKE_SOURCE_DIR
and CMAKE_BINARY_DIR refer to the outermost project, causing NuttX
to access its .config, generated files, host tools, and build artifacts
in the parent project’s directories. The fix introduces NUTTX_DIR and
NUTTX_BINARY_DIR, based on CMAKE_CURRENT_SOURCE_DIR and
CMAKE_CURRENT_BINARY_DIR, and consistently uses them for NuttX
self-references while preserving existing standalone builds. It fixes
the Kconfig initialization failure reported in #19697 and allows an
embedded sim:nsh build to configure, build, and boot successfully.
The change affects only the CMake build system (not Make or Kconfig
defaults), requires the corresponding nuttx-apps change, and does not
extend add_subdirectory() support to cross-compiled non-sim boards due
to CMake’s toolchain-file limitation.
Fixes#19697.
Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Alan Carvalho de Assis <acassis@gmail.com>
HIDKBD_NOGETREPORT reads keyboard reports with DRVR_ASYNCH(), and that
macro is only defined when USBHOST_ASYNCH is set. The option selected
neither, so turning it on by itself fails at the call site with no hint
that a second option was meant to come with it.
Select it. Every in-tree configuration that sets NOGETREPORT already
resolves USBHOST_ASYNCH: ci20:jumbo and sama5d3-xplained:bluetooth
through USBHOST_HUB, and the two linum-stm32h753bi configurations by
setting it directly. No existing build changes.
The two that set it directly no longer can, since a selected symbol is
no longer settable, so savedefconfig drops the line. Their defconfigs
are normalized here to keep them canonical.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
usbhost_destroy() unregisters the keyboard unconditionally, and it runs
for a device that never got as far as being registered as well: an
enumeration that failed part way through, or a device unplugged while it
was still being set up.
The upper half does not tolerate that call. It asserts that the lower
half carries the state keyboard_register() puts there, so a keyboard that
fails to come up takes the system down with an assertion rather than
being cleaned up and forgotten. Seen on a low speed keyboard that
attaches and then does not finish enumerating.
The state the registration leaves behind is what says whether there is
anything to undo, so look at it first.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
Since 00010089b8 uart_writev() takes the data one byte at a time with
uio_copyto() plus uio_advance(). Both of them walk the iovec list and
redo the byte counters for every single byte, so most of the work is
bookkeeping rather than copying. On slow cores this is what limits how
fast the TX buffer can be filled.
Take a pointer to the current iovec segment and read the bytes straight
from it, and move the uio forward once per segment instead of once per
byte. nseg counts only the bytes that really went into the buffer: it
is increased at the end of a loop pass, and that step is skipped when
uart_putxmitchar() fails.
Measured on nRF52840 (Cortex-M4, 64 MHz), 8 MiB write() to a CDC/ACM
port: 223 KB/s to 481 KB/s.
Signed-off-by: raiden00pl <raiden00@railab.me>
Assisted-by: Claude Code
Add Kconfig, Make.defs, and CMakeLists.txt entries for the ondemand governor so it can be enabled via CONFIG_DEVFREQ_GOV_ONDEMAND.
Signed-off-by: guanyi3 <guanyi3@xiaomi.com>
When CONFIG_LIBC_BACKTRACE_DEPTH is not set or <= 0, backtrace_get()
is a macro that always sets depth to 0, making the for-loop body
unreachable (Coverity CID 8405332 DEADCODE).
Wrap backtrace_get() call, the loop, and related variable declarations
with #if CONFIG_LIBC_BACKTRACE_DEPTH > 0 to eliminate the dead code
and avoid unused variable warnings.
Signed-off-by: guanyi3 <guanyi3@xiaomi.com>
QOS_REQ_MIN should return the highest value among all min requests
(most restrictive lower bound), but plist_first returns the lowest.
QOS_REQ_MAX should return the lowest value among all max requests
(most restrictive upper bound), but plist_last returns the highest.
This caused qos constraints to be ineffective. For example, two
requests (32, 208000) and (104000, 104000) would merge to (32, 208000)
instead of the correct (104000, 104000).
Fix by using plist_last for QOS_REQ_MIN and plist_first for QOS_REQ_MAX.
Signed-off-by: guanyi3 <guanyi3@xiaomi.com>
The cached devfreq->cur may become stale when the hardware frequency is
changed externally (e.g. by another core or governor). This causes
driver_target to incorrectly skip frequency transitions when the target
matches the cached value but differs from the actual hardware frequency.
Use driver->get_frequency() to read the real hardware frequency for the
unchanged check, and sync devfreq->cur on match to keep the cache correct.
Signed-off-by: guanyi3 <guanyi3@xiaomi.com>
When devfreq_gov_ondemand_stop() is called from idle task context,
work_cancel() is used instead of work_cancel_sync(), which does not
wait for the currently running worker to complete. If
devfreq_gov_ondemand_exit() then frees governor_data, the worker
may still be accessing it, causing a use-after-free crash.
Fix this by:
- Nullifying dev->governor_data under dev->lock in exit before freeing.
- Moving the governor_data read inside dev->lock in the worker and
adding a NULL check to bail out early if data has been freed.
Signed-off-by: guanyi3 <guanyi3@xiaomi.com>
When multiple QoS requests have no overlapping frequency range (min > max), the previous behavior always clamped to the lower frequency. Add a conflict_policy field to devfreq_driver_s so callers can choose between DEVFREQ_CONFLICT_PREFER_HIGH (default, choose higher freq) and DEVFREQ_CONFLICT_PREFER_LOW (choose lower freq) at registration.
Signed-off-by: guanyi3 <guanyi3@xiaomi.com>
Add the ability to set frequency constraints via procfs write.
Supported formats:
echo <min>,<max> > /proc/devfreq/<name> - set frequency range
echo 0,0 > /proc/devfreq/<name> - remove constraint
The QoS request is bound to the devfreq device lifetime so that
shell commands like echo (which open, write, close immediately)
work correctly. Leading whitespace in the write buffer is skipped
to handle extra writes from nsh echo (e.g. trailing newline).
Also add write permissions in devfreq_stat() and a procfs_qos
field in devfreq_s guarded by CONFIG_DEVFREQ_PROCFS.
Signed-off-by: guanyi3 <guanyi3@xiaomi.com>
(cherry picked from commit 70ae195c84f35a4d0b85fcc14187989b60fc0280)
we may call devfreq_find_by_name() in pm_callback, and shouldn't call nxmutex_lock() in idle_loop, so replace mutex to spinlock.
Signed-off-by: guanyi3 <guanyi3@xiaomi.com>
Add devfreq ondemand governor that scales device frequency based on CPU load. When CPU load exceeds the configured threshold, frequency is set to maximum; otherwise it is scaled proportionally.
Signed-off-by: guanyi3 <guanyi3@xiaomi.com>
It's better not to use global governor, as modifying one device will cause all devices' governor to be modified.
Signed-off-by: guanyi3 <guanyi3@xiaomi.com>
This commit introduces a devfreq framework to manage device frequency
scaling. The framework includes the following features:
1.devfreq governor
- provide governor ops, including init, start, stop, exit
- default governor, performance & powersave
- customized governor, device can provide governor when register
2.runtime register and unregister
- device can runtime register & unregister, search by name
3.suspend and resume
- suspend and resume frequency scaling
4.notify
- register & unregister notifier callback, notify frequency changes
5.qos support
- simplified QoS, manage multiple freq range request
- including init, add/remove/update request, get value
Signed-off-by: guanyi <guanyi@xiaomi.com>
The RAM log is the natural home for boot messages, yet writing to it
during early boot could crash the system it was meant to describe.
ramlog_addbuf took the critical section on every write, and
enter_critical_section consults the current task; on ports whose
first syslog output happens before the task lists exist, that lookup
walks uninitialized state and faults. The notification path was
worse still, locking a scheduler that did not exist yet.
Guard both. Before the task lists exist, plain interrupt masking
protects the buffer just as well, since there is only one thread of
control; and readers are only notified once there is an operating
system to notify them through. The bytes land in the buffer either
way, so nothing logged before the OS is ready is lost.
Found on the EIC7700X port, which logs from its start routine before
the MMU is up: enabling RAMLOG_SYSLOG there turned the boot into a
silent wedge two characters in. With this change the same
configuration boots and `dmesg` replays the full early history.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
A host that enumerates a device says nothing about it unless the whole of
CONFIG_DEBUG_USB_INFO is on, and then it says a great deal else besides.
The quietest case is the one that matters most: a device no class driver
claims produces no output at all, so a user with an unsupported device
sees exactly what a user with no device sees.
Add CONFIG_USBHOST_ANNOUNCE, reporting each device once, in the shape a
reader is likely to recognise from other systems: where it is, what it is,
its vendor, product and release, and the maker, product and serial number
it reports in its own string descriptors. Those cost a control transfer
each, so they are read only where a report was asked for, and only once
the device is addressed.
The report is made after binding rather than from within it, because a
composite device never reaches the class lookup: usbhost_composite() is
tried first and binds it. Whether a driver claimed the device is tracked
rather than read from the returned status, which the per interface loop
sets to OK whatever happened.
The port is given as the path from the root hub, and the path names the
bus, because a device on the first port of a hub and one on the first port
of a controller are otherwise reported identically. struct
usbhost_roothubport_s gains that bus number for the purpose; a driver that
does not set it reports zero, which is the only bus it has.
Class codes are translated where a name is more use than a number, which
includes the HID boot protocols, so a keyboard is reported as a keyboard.
Default n, so no existing configuration changes.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
cdcacm_sndpacket() runs from task context and from the bulk IN
completion callback, which may be interrupt context. cdcuart_dmasend()
advances the xmit tail non-atomically, so a completion arriving mid
setup re-sends the same region and advances the tail past the head,
re-transmitting a ring of stale data.
c497c5feb0 dropped the critical section that used to cover this.
Restore it with priv->lock held across the setup and EP_SUBMIT; the
submit must stay inside to keep request order. cdcuart_dmasend() now
runs with the lock held, so its own acquisition is removed.
The race needs the writer to keep the ring non-empty across
completions, so it only appears at high sustained write rates. On
nRF52840, 131072-byte writes were received as ~147600 bytes - one extra
CDCACM_TXBUFSIZE of stale data per hit. With this change the host
receives exactly what was sent.
Assisted-by: Claude Code
Signed-off-by: raiden00pl <raiden00@railab.me>
The registry is a singly linked list of static structures, so registering
one of them a second time does not add a second entry: it points that
entry's own link at itself, and the list stops having an end.
Nothing notices while every device that turns up matches something near
the head, because the search returns before it reaches the loop. The
first device that matches nothing at all, meaning anything without a
class driver built in, walks the list to look for it and never comes back,
holding the registry lock. On a multiprocessor the rest of the system
follows it down: every other processor that touches the registry spins,
and on the one measured here that included the console, so a board with a
USB keyboard and no keyboard driver came up and then answered nothing.
Registering twice is easy to do by accident. drivers_initialize() calls
usbhost_drivers_initialize(), which registers every class the
configuration selected, and board code that also registers one, which
many boards do, gets a second call for free.
So look before linking, and treat a repeat registration as the no-op the
caller expected it to be.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
The control transfer trace entry names the controller "HXCI", so a log of
an enumeration reads as though a different controller were involved. One
neighbouring entry also spells the port "RHport" where the rest of the
table spells it "RHPort".
Text only. No trace identifier or argument changes.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
The xHCI driver traces endpoint allocation with XHCI_VTRACE2_EPALLOC, but
that id is in neither the enumeration nor the string table, so the driver
does not compile once verbose tracing is turned on:
usbhost_xhci_pci.c:3285: 'XHCI_VTRACE2_EPALLOC' undeclared
It builds today only because usbhost_vtrace2() collapses to a macro that
discards its arguments unless HAVE_USBHOST_TRACE_VERBOSE is defined, which
is what stops anyone finding this until they go looking for a trace.
Add the id and the string to match, keeping the two tables in step.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
A drive that has been anywhere near another operating system almost
always carries a partition table rather than a filesystem starting at
sector zero, so the single block device this driver registers is usually
the one thing nobody can mount. A USB stick written with an installer
image is a good example: sector zero holds a protective MBR, and what
somebody wants is the EFI system partition several gigabytes in.
Read the table and give each partition a block device of its own beside
the whole drive, named the way every other system names them. The
parsing is already in the tree and understands both MBR and GPT; this
only calls it and registers what it finds.
The whole-drive node stays exactly where it was, for anyone who wants
the raw thing or whose drive really does hold a bare filesystem.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
Add a lower-half driver for the Microchip MCP4451 quad digital
potentiometer. Wiper and terminal control access is provided through
the common potentiometer interface, raw register access through
chip-specific ioctl commands.
Signed-off-by: raiden00pl <raiden00@railab.me>
Assisted-by: Claude Code
Add a common upper-half character driver for digital potentiometers
with a generic set of ioctl commands (wiper set/get, terminal control,
device properties) that can be shared by chip-specific lower halves.
Signed-off-by: raiden00pl <raiden00@railab.me>
Assisted-by: Claude Code
cdcuart_txempty() held priv->lock across EP_POLL(), which re-enters the
class through cdcacm_wrcomplete() and takes that same non-recursive lock,
and then took it a second time to read nwrq. Release it after the
disconnected check, matching cdcuart_txready()/cdcuart_rxavailable().
Fixes: cc067ab199 ("drivers/usbdev/cdcacm.c: Use small lock to protect cdcacm")
Signed-off-by: Felipe Moura <moura.fmo@gmail.com>
- The frequency step was truncated to 61 Hz, while it is FXOSC/(2**19),
about 61.035 Hz. The error puts a 915 MHz channel more than 500 kHz away
from the requested frequency, outside its own bandwidth.
- The low or high frequency front end was left at its reset value, so a board
wired for 868 or 915 MHz neither transmitted nor received.
- sx127x_rx_watchdog() is only used by the FSK and OOK path but was compiled
whenever receive support was on, so a LoRa only configuration failed to
build with -Werror. nrf52840-dk:sx127x is such a configuration.
Adds the sync word, the default bandwidth and the default spreading factor as
configuration options, all defaulting to the previous behaviour, and a page
for the driver under components/drivers.
Assisted-by: Claude Code 4.8
Signed-off-by: Jorge Guzman <jorge.gzm@gmail.com>
Character driver for the Semtech SX1301, the baseband processor of a LoRaWAN
gateway, and the two SX125x radios it drives. Received packets come from
read(), downlinks go to write(), and the channel plan, the start and the stop
are ioctls.
The interface is device independent, in nuttx/wireless/lpwan/lora_gw.h with
the commands in the common WLIOC_GW_* space, so another concentrator driver
can implement it and the same application drive it.
Adds a lorawan_gw configuration for the Nucleo F746ZG with a shield of the
LRWAN_GS_HF1 family. Off by default (LPWAN_SX1301).
Assisted-by: Claude Code 4.8
Signed-off-by: Jorge Guzman <jorge.gzm@gmail.com>
Add support for ST7123 touchscreen controller (I2C only).
It requires board level init to register a callback, as polling
mode is not supported.
Signed-off-by: Filipe Cavalcanti <filipe.cavalcanti@espressif.com>
Add support for the Microchip 24CW160 (2048B, 32-byte pages, 2-byte
data address)
Signed-off-by: raiden00pl <raiden00@railab.me>
Assisted-by: Claude Code
A fetch() only lower half is always ready, so a subscriber that asked for
a rate with SNIOC_SET_INTERVAL got no pacing from poll(): the descriptor
reported POLLIN on every pass and the application had to sleep out the
period itself. That does not compose. An application polling several
topics reads them sequentially from one thread, so per read sleeps
serialize: three topics at 10 Hz sleeping 100 ms each yield 3.3 Hz per
topic rather than 10.
Pace it where poll() can act on it instead. A subscriber that never
requested a rate stays always ready, and one that did becomes ready once
per its own interval, driven by a watchdog armed in sensor_poll(). This
is the fetch() side of what sensor_is_updated() already does for a
pushing lower half, so both models now honor a requested rate the same
way.
The wdog_s lives in sensor_user_s rather than in the device, so each
subscriber is paced at its own interval instead of at the minimum across
all of them, and the timer only runs while somebody is polling. The
expiry runs in timer context and takes no lock: poll_notify() is safe
from an interrupt handler, and a teardown that raced it has already
cleared fds, which makes both the notify and the re-arm no-ops. Teardown
therefore just cancels the watchdog where it clears fds, and a watchdog
keeps this off the work queue entirely, which a fetch() only sensor
exists to avoid.
sensor_close() needs nothing of its own: poll_setup() holds a reference
on the file for the duration of the poll, so file_close() cannot run
until poll_teardown() has called sensor_poll() with setup false, and that
already cancelled the watchdog.
Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Felipe Moura <moura.fmo@gmail.com>
A fetch() only lower half reads the device on demand, so its data is
always available and there is never anything to wait for. The upper half
did not reflect that: poll() only reported POLLIN when the descriptor was
opened O_NONBLOCK, and a blocking read() waited on buffersem, which is
only posted when the lower half drives notify_event from an interrupt of
its own.
A fetch() only sensor with no interrupt therefore never satisfied
poll()/read() at all. This is not hypothetical: in the in tree
nucleo-h563zi:dts configuration CONFIG_STM32_DTS_TRIGGER defaults to 0,
which selects stm32_dts_fetch(), and no CONFIG_STM32_DTS_ITEN_* option is
enabled, so the DTS interrupt never fires. A blocking read() on that
sensor waits forever, even though stm32_dts_fetch() performs a complete
software triggered measurement on its own and needs no interrupt at all.
Applications had to work around this by forcing O_NONBLOCK on the
descriptor themselves, see apache/nuttx-apps#3686.
Drop the O_NONBLOCK special case in both paths: sensor_poll() now always
reports POLLIN for a fetch only sensor and sensor_read() calls fetch()
directly instead of waiting. Update the sensor_ops_s::fetch
documentation, which described the old contract.
With the wait gone, buffersem has no waiters left. Its only two readers
were the ones removed here, both in the fetch path: the wait in
sensor_read() and the nxsem_get_value() in sensor_poll(). The remaining
nxsem_post() calls in sensor_push_event() and sensor_notify_event() had
nothing left to wake, so drop the semaphore and those posts as well.
Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Felipe Moura <moura.fmo@gmail.com>