The polling thread and the frontend shared one adapter list under an
OSFastMutex, which the frontend took on every poll, and the HID attach
callbacks queued events by swapping the list head out and back in. That
swap pair is not atomic as a whole: two callbacks at once (the HID
stack calls them from more than one thread) can each take the list and
put theirs back over the other's, losing an attach or a detach. A lost
detach leaves the pad registered for good.
Each thread now keeps its own list and hands adapters across through
the lock-free stacks of mpsc_stack.h:
attach callbacks -> hid_events -> polling thread
polling thread -> hid_new -> frontend: adapters to set up
frontend -> hid_retired -> polling thread: to free
An adapter's state is a retro_atomic_int_t, and each value is moved on
by one thread only, so no two ever write it from the same state. The
read completion runs the packet handler before it says READY, since
READY is when the polling thread may start winding the adapter down;
it used to say READY first. The frontend deregisters and deinitialises
a pad as it retires the adapter, the polling thread frees the adapter,
and at shutdown the polling thread tears down what is left, as before.
No lock remains, and the frontend's poll no longer takes one.
samples/input/wiiu_hid_threads runs the driver against stand-ins for
Cafe OS on pthreads: two threads attach and detach devices while the
frontend polls and an "IOS" thread completes the reads, and every pad
must be registered, fed, deregistered and deinitialised in order, on
the right threads, with nothing left at shutdown. Its negative build
loses the reads in flight at shutdown and must fail. Against the old
driver (32-bit PowerPC under qemu) it fails: a few hundred pads of
detached devices are never torn down.
The Pro Controller, and the pads that pass for one (8BitDo's in Switch
mode among them), now give a core their accelerometer and gyroscope,
read as SDL reads them:
- The sensors' calibration is read from the pad's flash with the stick
calibration: the factory's at 0x6020, then the user's origins at
0x8026 where the user calibrated.
- Subcommand 0x40 turns the sensors on while a core asks for them and
off when it is done, sent from the poll like the player lights.
- Each report 0x30 carries three samples; the newest one is kept. The
values go out in g and radians a second, on the axes SDL gives them,
which are the DualShock 4's, and so on the same axes as winraw's
DualShock 4 and DualSense.
How it gets there:
- Pad handlers can now have set_sensor and sensor ops.
- hidraw and winusb route the driver's sensor calls to the slot's
handler.
- The hid joypad driver passes the frontend's set_sensor_state and
get_sensor_input on to its hid driver.
- The beside layer sends a hid pad's sensor calls to the hid driver
rather than to the joypad driver it stands beside.
connect_parity_test checks the calibration reads, the 0x40 commands and
the values from a sample.
The DualShock 3, DualShock 4, DualSense and both Switch Pro handlers,
and the generic pads read from their report descriptors, now keep
their state as an input_pad_view_t, decoded straight into it and read
by their getters. hidraw and winusb hand reports to the handlers only
in their poll, so the state does not change between polls and they
lend it through a new hid_driver_t view(), as udev and winraw lend
theirs: the bridge reads it in place, with nothing copied.
The beside layer passes view() through, so a WinUSB pad beside
winraw is lent, and winraw's own pads stay lent while it is there
instead of falling back to copies. A generic pad's hat is part of its
view, which the drivers' hat reads now use.
connect_parity holds each converted handler's view to its getters
after every report, and the DualShock 3's axes to the copying
handler's; hidraw_hid, winusb_hid and the frontend harness's beside
lane check the lend.
Every hid pad handler that lights the pad - the DualShock 3, DualSense
and Edge, Switch Pro, Switch 2 Pro and Wii Remote - lit its hid slot,
once, when it started. After a driver restart the pads can come back in
other slots and are moved back to the ports they had, and a port can be
pointed at another pad in the menu or by a reservation: the lights then
showed the wrong player, and a pad no port reads was still lit.
The frontend now tells the joypad driver which port reads each pad,
and the hid drivers pass it to the pad's handler, which relights from
its packet handler - the pad's own thread - so nothing waits. The lowest
port reading a pad is shown; on none, the lights go out. The Switch
pads take the console's patterns past player 4.
It costs one countdown a poll: every 32 polls the ports are compared
with what the driver was last told, and only a change, a driver start
or a pad starting beside the joypad driver tells it again. The player
is kept for each slot, so a pad plugged in is lit for its port as it
starts. A handler never told, under a hid driver that does not pass it
on, lights its slot as before.
joypad_slots covers the slot's player across pads and threads;
connect_parity the DualSense and Switch Pro relighting.
The DualSense handler built its own USB output report and sent nothing
over Bluetooth. It now sends what raw input's driver sends for these
pads (input/common/sony_pad_output.h): over USB or Bluetooth as the
pad came, with Bluetooth's checksum, the player's lights at the first
report and rumble at the poll after a change. The motors are driven
the newer way on a DualSense Edge, which now has an interface of its
own, and on a DualSense from firmware 2.21, which its feature report
0x20 tells. Nothing is sent behind a Bluetooth stack's own header,
whose framing of output is that stack's.
A HID driver can now say a device is on Bluetooth (is_bluetooth): on
Windows every report comes at the longest one's length, so a
DualSense's 10-byte Bluetooth report cannot be told from USB's by it.
connect_parity_test holds the reports sent to the shared builder's,
over USB, over Bluetooth and on a padded report the driver says is
Bluetooth's, and checks the Edge and firmware 2.21 get the newer
motor control.
A DualShock 3 connects over Bluetooth to the address it was last given
over USB, in its feature report 0xF5. Joypad drivers can now read and
set that address for a pad that keeps one (get_bt_host/set_bt_host,
also on the HID driver interface): the udev driver through the hidraw
node it reads the pressures from, and hidraw_hid through the pad's own
node, both for a pad on USB.
This computer's Bluetooth address is read on Linux from the kernel's
HCI socket, the first adapter that is up, with no BlueZ library.
Information > Input Information lists the adapter with its address,
and under a controller that keeps one the address it connects to -
"This Computer" when it is this one's - with "Pair with This Computer"
to set it when it is not.
samples/input/hidraw_hid checks that the address is read and set as
0xF5 most significant byte first.
A joypad driver's state call answers the RetroPad's sixteen as a mask.
It was handed the port's binds for it, and every driver chose, for
each of the sixteen at every call, between the port's own bind and
its controller's profile's: thirty-eight copies of the same two
lines, each a reason the binds' records cannot change shape.
The frontend has made that choice already and keeps it - the port's
resolved set, worked out when a bind changes. The state call takes
two lists from it instead: the pad's button behind each of the
sixteen (NO_BTN for none) and the pad's axis (AXIS_NONE for none).
int16_t (*state)(rarch_joypad_info_t *joypad_info,
const uint16_t *joykeys, const uint32_t *joyaxes, unsigned port);
and the same for an HID backend's. In the 29 joypad drivers, the Wii
U's three and the six HID backends that is the signature and the two
lines, by script: each keeps its own loop and whatever is its own
about it (the DOS one answers nothing, the PS4's and the parallel
port's go by buttons alone, and so on). No file of theirs names a
bind, a set of binds or a profile's any more, and
tools/input_state_grab_check.py holds them to it (a selftest case
with it).
The frontend's side:
- input_joypad_port_state() makes the call. For a port read by its
own controller it hands over the resolved set's lists as they
stand, and answers "none" itself where no pad is behind any of the
sixteen. For a read by another controller it resolves the sixteen
for that call, from the port's binds and that controller's profile.
- The resolved set writes the sixteen's places whatever is behind
them, so the lists can be handed over whole.
- The frontend's own loop, which stands in for the drivers read
through a snapshot, takes the same two lists; it found the port's
set from the address of the binds, and finds it from the address
of the list.
- Learning a trigger's rest asks whether the axis's other direction
is bound to anything: of the port's resolved set, where there is
one. For a read by another controller it sees the sixteen it was
handed, where it used to see every bind of the port.
Measured, the frame's input work over 300 frames (X11):
- no controller: 3,796,163 instructions before, 3,786,758 after;
- a controller with a hotkey enabler, through a driver that is read
directly: 4,478,984 before, 4,458,394 after. Its state call alone:
190,376 to 147,272.
Checked:
- samples/input/joypad_bridge_checked, which holds six drivers'
state calls (udev, linuxraw, SDL2, SDL3, DirectInput and the
XInput-only one) to the frontend's loop from the binds, over
thousands of random pads, binds and thresholds: all six pass with
the lists.
- The X11 keyboard session logs the same as before; the hotkey and
quit-combination sessions log the same lines on master's binary
and this one; the frontend harness passes every lane; the
multimedia joystick driver's test passes under Wine.
- Built: Linux in full, and the parallel port, SDL2, HID and libusb
files compiled beside it; Windows in full with a mingw cross
compiler (the XInput and DirectInput driver, the DirectInput one,
raw input and the multimedia joystick among it), and run through
the scripted session under Wine; the Android unity build with the
NDK, with OpenXR on; the Visual C++ 6 project and the QNX drivers
on their stand-ins; a build with the optional features off.
- Not compiled, there being no compiler for them here: the console
drivers (3DS, DOS, GameCube and Wii, PS2, PS3, PS4, PSP and Vita,
Switch, Wii U, Xbox, web), the Apple one, SDL 1, and the HID
backends but libusb's. Their edits are the script's, the same in
every file.
The seventh piece of the mapping compiler's fifth step (plan, section
21). Counted as before, binds are read from the tables at 107 places
in 26 functions of the frontend's file, from 113 in 28 - and in no
driver's.
Both drivers park a poll thread on a flag the teardown sets from another
thread, with no lock either side, as volatile bools that ordered nothing
between the two. The flags are initialised before their thread is
created, and on the Wii USB side before the first goto error, since free
stores through it.
wiiusb_hid's device_detected goes the other way. It is raised by
wiiusb_hid_change_cb, which libogc runs in interrupt context, so an
atomic is not what it wants - the writer is not a thread, and this file's
other interrupt-shared state is volatile for that reason. It was a plain
bool, which left the poll thread free to hold it in a register across the
loop; volatile is the smallest thing that fixes that.
Both files build against the headers already in the tree - libogc under
wii/, wut under wiiu/ - on a 32-bit PowerPC compiler and on all five
retro_atomic backends, unmodified first and then with the change.
Extended RETROK_ values with 18 new items, commonly found on
"multimedia" keyboards.
Mapping added for SDL, X11, Wayland, dinput, winraw keymaps.
Keyboard tester function of Remote Retropad extended to cover new keys.
One fix in Android mapping for #12986
== DETAILS
Put the finishing touches on getting the DS3 to work on Mac OSX.
Basically, there's some differences in the HID interface bewtween
wiiu and osx where OSX expects the first byte of the report to be
the report ID, while wiiu expects that byte to be trimmed off.
I was able to put this behavior in the respective HID
implementations, which eliminated the confusing packet offset
ifdefs.
And, I was able to get the LEDs working again.
== DETAILS
The DS3 driver previously only worked with the Wii U HID implementation.
I adapted this driver from the Linux driver for the DS3. It's not quite
100%--I haven't got the LEDs to work properly--but it's functional.
Going to continue tweaking it to see if I can get the LEDs to work.
== DETAILS
cause of crash: trying to deference init when it's null
the reason it was going into deregister: the HID/VID lookup was
failing because it wasn't getting initialized first
cause of 2nd crash: the "end of pad list" method looked for an entry
with a magic value, so we add an end marker
== DETAILS
When I first implemented the Wii U HID architecture, I ended up
having to design my own implementation because, at the time, I did
not have a way to read the HID device string to allow the existing
code to successfully detect the gamepad.
After spending some time experimenting, I've figured out how to
do this. And that means I can better align the HID driver with other
platforms.
change summary:
- create a single state structure for all three sub-types of wiiu pads
(kpad, wpad, and hid)
- eliminate confusing duplicate pad lists
- eliminate confusing duplicate HID pad drivers (ds3, gamecube
adapter, etc)
- ensure the ds3 driver still works
=== DETAILS
Replaced includes for things that aren't standard library headers so
they use quotes instead of brackets.
Also fixed up a couple of headers that had include-order dependencies.
=== DETAILS
Since @aliaspider wants the `wiiu/` to be something of a mini-SDK, I've
reorganized the code I put in there:
- `wiiu/main.c` now only has the ELF/RPX entrypoints, and the code used
by those entrypoints, with RA code removed (e.g. swapped retro_sleep()
for usleep()). These entrypoints then call main() ...
- Moved `main()` and its support functions back into `frontend/drivers/platform_wiiu.c`
I also renamed some of the support functions I wrote, and better
organized them within the code.
- Moved `wiiu/input/` into the `input/` hierarchy:
* The joypad drivers now live in `input/drivers_joypad/wiiu/`
* The HID driver now lives in `input/drivers_hid/`
* The Wii U specific headers now live in `input/include/wiiu`
* I added `input/include` into the include search path to avoid
using really ugly relative includes
== DETAILS
- DS3 analog wasn't working mainly because I forgot to actually declare the
axes in input/input_autoconfig.c when declaring the pad. Whoops.
- I also moved the axis decoding logic to a more central place, because it
clearly is not Wii U specific.
- Removed some dead commented-out code
== TESTING
Can use analog inputs on both GCA and DS3. Tested in Mario 3 on Nestopia core.
Haven't tested with any actual analog games, but I did confirm via logging
that the correct ranges are produced.
retro_bits_t turned into input_bits_t and there were parts of my
code that needed to update.
== TESTING
No idea if upstream changes broke anything, but it compiles cleanly
now.
== DETAILS
- fix the bitshift math
- read the right bytes out of the ds3 data packet
- remove verbose logging in critical path
- stop caring about errors in the hid read loop -- seems to just
be benign "device not ready" -- or at least, that's what I'm assuming
given that the read eventually succeeds.
== TESTING
Played Mario 3 with the DS3 with no issues.
== DETAILS
- update to not try starting the read loop until after the device
is successfully initialized
- add new HID wrapper macros needed by ds3 driver
- add some debug logging to help with troubleshooting
- add button map for DS3
== TESTING
Tested with local build. DS3 init is not working.
== DETAILS
Whereas the last commit had a hack (that disabled the wiimote
driver in the process), this has.. well, a *different* hack that
allows pads to register in any order.
Note that due to the initialization routines, the gamepad will still
likely always get slot 0. Not sure if this can be overridden via config
or not.
== TESTING
Tested locally with GC adapter
== DETAILS
Now that I have a working implementation, it's time to tidy up a bit:
- there was no need for the HID subsystem's object data to have a reference
to the global hid state (since it's global), so removed it.
- refactored the users of that member to use the global state, defining
reusable macros.
- reorganized the information in *.h files
- removing the hid state also made the constructor changes to the hid driver
unneeded, so I reverted those changes.
== TESTING
Confirmed clean build. Haven't tested the build yet to make sure everything
still works, though.
== DETAILS
- Added a new method to the joypad_connection_t interface for
getting a single button
- wired everything into the hidpad driver
- for testing purposes, hacking the top-level joypad driver
so that kpad isn't used
- add a new RARCH_LOG_BUFFER method to verbosity for logging the
contents of a binary buffer (useful for writing/debugging pad drivers)
- fix a few bugs in the wiiu GC pad driver
The button mapping isn't quite right, and I'm not sure what's
going wrong.