Commit Graph
8 Commits
Author SHA1 Message Date
OpenIPC AI teamandGitHub 2a26e86e45 gk7205v200_otg: stop the UVC gadget freeing its own video device (#149)
Tearing down a UVC gadget that userspace still has open corrupts the V4L2 core:
the node number leaks (the gadget climbs /dev/video0 -> video1 -> video2 across
role switches), and once the kernel is tainted by the WARN that goes with it, a
NULL dereference follows with v4l2_device_release on the backtrace.

struct uvc_device embeds its struct video_device and uvc_free() kfree()s the
lot, but the V4L2 core holds a reference to that video_device for as long as
/dev/videoN is open. Reference-count the structure instead, which is what the
driver's own "TODO reference counting" has been asking for.

Verified on the bench: the gadget returns to /dev/video0 every time instead of
climbing, and no WARN or Oops after repeated switching.
2026-09-06 14:40:07 +03:00
OpenIPC AI teamandGitHub 0df089bf61 gk7205v200_otg: take the role scripts from firmware's package (#148)
Follow-up to OpenIPC/firmware#2370, which moves `usb-mode`,
`uvc-gadget-setup` and `S72usbmode` into a selectable `usb-dual-role`
package. Nothing about them was device-specific; they were only here because
this is where the OTG image was first put together.

So this profile stops carrying its own copies and selects the package instead.
Keeping both would be worse than untidy: firmware installs them in /usr/sbin
and this profile installed them in /usr/bin, so a build with both would put two
versions of each script on the camera and let PATH order decide which ran --
with the copy here being the older, missing the bus settling, the UDC guard and
the idempotent apply that came with the move.

MERGE AFTER the firmware change, not before: until that lands there is no
package to select, and a build from this branch ships no role scripts at all.

What stays here is what is genuinely particular to this board: the defconfig,
the kernel config, and the dwc3/uvc patches.
2026-09-06 14:38:10 +03:00
OpenIPC AI teamandGitHub f86ea4f4a6 gk7205v200_otg: settle the USB role before xHCI probes (#147)
The OTG profile could not see USB devices in host mode. On a board with a
UVC webcam on the USB tail, `lsusb` showed only the two root hubs, while the
same board running a plain lite image enumerated the webcam normally.

The controller was in the host role and the host controller was running --
mode file "host", xhci-hcd bound, USBCMD 0x5, PORTSC1 port-power set -- and
the port still never reported a connect (PORTSC1 0x00000280, CCS clear).

dr_mode = "otg" makes dwc3_core_init() program GCTL.PRTCAPDIR = OTG(3), and
dwc3_core_init_mode() registers xhci-hcd on top of that. This 4.9 dwc3 has no
working OTG role-detection block, so xHCI probes, resets the controller and
brings up its root hubs while the core is in a role it cannot drive. The port
is then dead for the life of that probe.

S72usbmode's `usb-mode host` did not repair it and could not: writing the
debugfs mode file reaches dwc3_set_mode(), which flips GCTL.PRTCAPDIR and
nothing else, leaving the already-probed xHCI with the port state machine it
built in OTG. It also skipped the bind, because xhci-hcd was already bound.

Fix it where the ordering is: patch dwc3_core_init() to program
PRTCAPDIR = HOST for the OTG case, so xHCI probes into a role the core can
drive. dwc3_gadget_init() only registers a UDC and does not care, and
`usb-mode device` re-aims the controller itself when it takes the port.

usb-mode's host path also learns to re-probe an xHCI that was bound in some
other role, which is what makes a newer rootfs recover on an older kernel.
2026-09-06 09:57:08 +03:00
Signor PellegrinoandGitHub a16e77a2f1 Update gk7205v200_otg_generic_defconfig (#144) 2026-09-02 15:24:59 +03:00
Signor PellegrinoandGitHub 60cbe0cd1d Add customizer.sh for IP camera settings (#143)
This script sets a custom upgrade URL for the IP camera and reboots the device to apply changes.
2026-09-02 15:14:40 +03:00
OpenIPC AI teamandGitHub a0418c2987 kernel: drop CONFIG_VT from the device configs that shadow firmware's (#126)
builder.sh copies devices/<item>/* over the firmware checkout before make, so a
device directory that carries its own board .config replaces firmware's copy
outright. OpenIPC/firmware #2308 and #2309 turned CONFIG_VT and CONFIG_INPUT off
across the fleet; the 13 board configs here were never touched by that, so 21
device builds carried on shipping the virtual-terminal layer -- /dev/tty0,
/dev/tty1..63, the keyboard translation tables, console selection and screen
code -- for a monitor and keyboard no camera has. flyrouter pointed this gap out
on #2308.

The transformation is not re-derived here. For each file the symbol-level delta
was taken straight out of firmware's history (85233f0e^..HEAD) for the config it
shadows and replayed, so these land on exactly the state that was reviewed and
proven on hardware there. Every affected symbol in every copy still held
firmware's pre-sweep value, so nothing here was a deliberate customisation --
they were simply stale.

Eleven of the thirteen also needed CONFIG_EXPERT=y first. In drivers/tty/Kconfig
the symbol reads

    config VT
        bool "Virtual terminal" if EXPERT
        select INPUT
        default y

so its prompt exists only under EXPERT, and without it olddefconfig finds the
symbol invisible and forces it back to its default -- "# CONFIG_VT is not set"
on its own does nothing.

Two exceptions:

  * gk7102c keeps CONFIG_INPUT. It sets CONFIG_INPUT_EVDEV=y and firmware's
    gk710x, which it shadows, keeps INPUT for the same reason. Only VT moves.

  * CONFIG_INPUT_LEDS=m is dropped on the six FPV/OTG copies. It is the
    input-to-LED bridge, lives inside `if INPUT`, and firmware never carried it,
    so olddefconfig would have dropped it silently -- stated here so the file
    matches the kernel it generates. CONFIG_LEDS_CLASS is a separate symbol in
    drivers/leds and is untouched: the FPV status LEDs are unaffected.

Nothing consumes VT on any of these. FRAMEBUFFER_CONSOLE is its only in-kernel
consumer and no config in this repository sets it at =y or =m, so the sole
console driver compiled in was DUMMY_CONSOLE and writes to /dev/tty0 went
nowhere. The ingenic t21/t31/t40 copies already matched firmware -- VT off,
INPUT kept for their GPIO keys -- and are left alone.

Verified by generating the kernel config the way builder.sh does: copy
devices/common over a firmware checkout at master and run the configure step,
before and after. gk7205v200_fpv, comparing the two generated
build/linux-custom/.config files symbol by symbol:

    turned OFF (8)   CONSOLE_TRANSLATIONS DUMMY_CONSOLE HW_CONSOLE INPUT
                     INPUT_LEDS VT VT_CONSOLE VT_CONSOLE_SLEEP
    turned ON  (1)   EXPERT
    value changed    none

    LEDS_CLASS=m, TTY, UNIX98_PTYS, SERIAL_AMBA_PL011_CONSOLE, USB_GADGET,
    CFG80211, MAC80211, KALLSYMS, COREDUMP, NAMESPACES, ELF_CORE,
    CORE_DUMP_DEFAULT_ELF_HEADERS, DEBUG_KERNEL, DEBUG_MEMORY_INIT: unchanged.

That last line is the check #2308 missed on its first pass: EXPERT carries
`select DEBUG_KERNEL` and unhides a block of on-by-default options, which there
silently moved COREDUMP and friends. DEBUG_KERNEL was already y in these
configs, so nothing else moved.

Building the kernel both ways in that same tree, on the OpenIPC/linux goke
tarball these devices use:

    gk7205v200_fpv  uImage  2071368 -> 2036040   -35328 bytes (-1.71%)
                    zImage  2058872 -> 2023544   -35328 bytes (-1.72%)

which lines up with the -34680 bytes firmware measured on gk7205v200_lite for
the same delta. drivers/input/input-leds.ko is built in the before tree and is
not built after.
2026-08-25 21:25:13 +03:00
94cce13948 gk7205v200: flip dwc3 to host before unbinding xhci (otg) (#114)
Booting the otg profile with /etc/usbmode = device made S72usbmode's
`usb-mode device` log, on every single boot:

    xhci-hcd xhci-hcd.0.auto: Host not halted after 16000 microseconds.
    xhci-hcd xhci-hcd.0.auto: Host controller not halted, aborting reset.

dwc3_core_init() leaves GCTL.PRTCAPDIR = OTG(3) and this 4.9 dwc3 never
moves off OTG on its own. xhci-hcd binds and registers both buses on top
of that anyway, but it is not actually driving the port -- so unbinding
straight from OTG asks xhci_halt() to halt a host that was never really
running, and it times out.

The gadget composed regardless, so this was cosmetic in practice, but it
left the host controller un-halted: exactly the live-DMA-engine state the
unbind is there to avoid.

Flip the controller to host before unbinding, so the already-bound xHCI
is genuinely running and the unbind halts cleanly. A switch from host is
already in that state, so only boot pays for the extra flip.

Measured on gk7205v200 (Xiongmai IPC_GK7205V200_50H20AI_S38): 5/5 cold
boots warned before, 0/5 after. Runtime host<->device round trips stay
clean and still take ~0.35s, with no reboot and no majestic restart.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-31 18:21:02 +03:00
Dmitry IlyinandGitHub 96633d5577 gk7205v200: add an OTG profile that makes the camera a USB webcam (#113)
Adds gk7205v200_otg_generic, a firmware profile that puts the single DWC3
controller into dual-role so the board can either consume a USB webcam
(existing usbcam path, host role) or present itself to a PC as one (UVC
gadget, device role). The roles are mutually exclusive -- xHCI HCSPARAMS1
reports MaxPorts = 1 -- but usb-mode switches between them at runtime, so
one image covers both and no reboot is needed.

Kernel side, three patches:

0015 sets dr_mode = "otg" in the DTS so dwc3 registers both an xHCI host
and a UDC.

0016 makes device mode actually work on a part that has only ever run as
a host. Three fixes: re-run dwc3_event_buffers_setup() on gadget start
(an xHCI reset wipes GEVNTADR), soft-reset the core before taking the
lock so the PHY is re-initialised (without it high-speed chirp fails),
and swallow the run_stop timeout on pullup(0), which otherwise
permanently poisons cdev->deactivations.

0017 disables the vendor's UVC_SG_REQ path. It hands a whole frame to the
UDC as one scatter-gather request; dwc3 chains those sg entries into a
single isochronous service interval, which on a full-speed link is one
1023-byte packet, so every frame larger than that reached the host
truncated and H.264 decoders reported "bytestream -5" on roughly half the
frames. Goke never shipped this path enabled -- CONFIG_USB_CONFIGFS_F_UVC
is unset in every vendor defconfig, including gk7605v100's, and the SDK
carries no userspace UVC sample -- so it was never exercised. The
mainline path (32 plain one-packet requests) is used instead.

Userspace side: usb-mode switches roles with the unbind/flip/bind
sequencing dwc3_set_mode() does not do on its own, uvc-gadget-setup
composes the configfs gadget, and S72usbmode forces a concrete role at
boot -- not optional, since dr_mode = "otg" leaves GCTL.PRTCAPDIR in a
state this 4.9 dwc3 never moves off by itself.

The descriptors advertise exactly the one format, frame size and interval
majestic is configured to serve, read from /etc/majestic.yaml. majestic
answers every PROBE/COMMIT with its own bFormatIndex/bFrameIndex because
it has one stream and cannot follow the host, so anything extra is an
invitation to select something that will not arrive: asking for MJPEG got
raw H.264 (an SPS where a JPEG SOI belongs, garbage to every consumer),
and asking for 1080p got 720p.

Profile drops the air-unit packages (wifibroadcast, rtl8812au, mavfwd,
mavlink-router, vtund, linux-firmware, wireless-tools) and the whole
wireless kernel stack, which pays for usb_f_uvc.ko and for keeping the
full sensor list -- the fpv trim to IMX307/IMX335 is keyed on
OPENIPC_VARIANT="fpv", and a general-purpose USB webcam should not be
sensor-locked.

Measured on a gk7205v200 lab board over a full-speed link: H.264
1280x720 at 30 fps with zero decoder errors and no dropped buffers, and
MJPEG delivering valid JPEGs at the jpeg channel's own rate.

Requires a majestic built with ENABLE_UVC_GADGET to feed the gadget;
that is a separate change.
2026-07-28 23:21:12 +03:00