USBJoystick - architecture and source layout
=================================================

What this module is
------------------------
USBJoystick is a RISC OS module that lets a modern USB HID joystick or
gamepad be used by old software written against RISC OS's various
historical joystick interfaces, and provides its own native slot-based
SWI API for new software. See doc.APIs for the full API reference (the
classic APIs it emulates, the native SWI API, and the `*USBJoystick_*`
command set). This note covers how the module itself is put together
internally.

Terminology used throughout the source: a **slot** is a device's own
internal id (`joy_data[slot]`, 0..JOY_MAX-1, assigned in USB attach
order). An **index** is an axis or button's position within one device's
own arrays. The two are never interchangeable - a variable or SWI
register genuinely meaning "which device" is always called `slot`.

Licensing, third-party code and prior art: see doc.License.


Source layout
-----------------
  c, h             C source and headers (see below for the RISC-OS-
                   specific files; c.data, c.descr, c.parse, and their
                   headers are the vendored NetBSD HID parser - keep
                   these close to upstream rather than restyling them,
                   to make future upstream syncs easier)
  s.ukswiv         Hand-written ARM assembler pre-veneer for the UKSWIV
                   (Unknown SWI Vector) claim - see "Vector and service
                   call claims" below
  cmhg             CMHG module header (SWI/command declarations, vector
                   veneers, init/finalise entry points)
  global.h         Shared RISC OS constant headers (errors, keyboard,
                   pointer types) not specific to this module
  Resources.UK     Message-token files: CmdHelp (the *command help/syntax
                   text CMHG looks up via MessageTrans - see the
                   `international:` flag on each command in the CMHG
                   header) and Messages (the module's own _kernel_oserror
                   text, looked up via MessageTrans_ErrorLookup - see
                   c.errors)
  utils            Small standalone BASIC test programs exercising each
                   classic API directly (Acorn8/16-bit, dev-info, ADC,
                   serial port, Joy-module) - useful as executable
                   examples of the register conventions in doc.APIs
  doc              This file, doc.APIs, doc.Config, doc.MouseKeyboard
                   (reference documents), and doc.Todo (the forward-looking
                   list of desirable features / next steps)

RISC-OS-specific source files, by responsibility:
  c.usbjoystick    Module state, module_initialise/module_swi/
                   module_finalise
  c.errors         The module's _kernel_oserror lookups - a small table of
                   {error number, message token}, resolved through
                   MessageTrans_ErrorLookup against Resources.UK.Messages
  c.joydev         USB device attach/detach, HID report descriptor
                   parsing, the per-packet decode hot path
  c.buffer         UpCallV handling - pulling raw report bytes out of a
                   joystick's DeviceFS buffer
  c.joyhelp        Misc helpers: axis/stick lookup, the
                   supported_axes_usage[] table, joydata_struct
                   reset/cleanup, and validate_joystick_slot/
                   validate_joystick_slot_active - the slot-range/active
                   checks shared by every command and native SWI
  c.joyswis        The whole Joystick_ SWI chunk (&43F40) - both the
                   Acorn 8/16-bit read API (not "legacy": still the only
                   way a RISC OS game reads a joystick) and the native
                   slot-based additions (Enumerate/DeviceInfo/AxisInfo/
                   AxisValues/GetMapping) - see doc.APIs sections 1 and 5.
                   Everything here is a genuine numbered entry in our own
                   officially-registered chunk, and a real candidate for
                   eventually being upstreamed into standard RISC OS
                   headers, unlike joycompat below.
  c.joycompat      Raw-number `UKSWIV` compatibility trapping for two
                   *other* modules' historical SWIs that we are not - the
                   Serial Port interface's undocumented raw &81540 entry
                   point, and the Teque/Krisalis "Joy" module's RTFM-
                   compatible SWIs (&CFFC0-3, no named-SWI equivalent at
                   all) - see doc.APIs sections 2 and 3. Deliberately kept
                   separate from c.joyswis: nothing here is ever going to
                   be upstreamed, since it's us impersonating someone
                   else's numbering rather than providing our own.
  c.adc            The I/O podule ADC/ADVAL emulation via ByteV - see
                   doc.APIs
  c.mouse          Mouse-pointer emulation via PointerV (movement) and
                   KeyV (the three mouse buttons)
  c.keys           Keyboard synthesis via KeyV - button->key and axis-
                   direction->key, with per-slot tracking of which KeyNo
                   is currently held so keys release cleanly - see
                   doc.MouseKeyboard
  c.config         The settings load/save store - device fingerprinting,
                   the config-file reader/parser and writer, and the
                   auto_map() lookup entry point - see doc.Config
  c.map            auto_map()/unmap() - automatic default mapping when a
                   device is attached/removed
  c.cmds           `*USBJoystick_*` command dispatch; c.cmdmap holds the
                   mapping commands (each sharing its real implementation
                   with the equivalent native SWI in c.joyswis / c.cmdmap -
                   see doc.APIs sections 5/6), c.cmdshow the read-only
                   List/Read/Mapped/Debug commands, c.cmdemu the Emulate*
                   toggles
  c.device         The table of known joystick "device drivers" (USB
                   class/subclass/protocol/VID/PID -> optional baked-in
                   report descriptor and quirks)
  c.usb            RISC-OS-side USB descriptor-walking helpers (distinct
                   from the vendored NetBSD parser, which only
                   understands the report descriptor's own byte format)
  c.debugrep       debug_printf() - wraps Steve Fryatt's Reporter
                   interface


Vector and service-call claims
-----------------------------------
All claimed in module_initialise (c.usbjoystick):

  UpCallV    Notified when a USB device has new receive data available
             (UpCall_DeviceRxDataPresent). c.buffer's
             upcallv_hook_handler uses this to know when to pull a
             joystick's raw HID report bytes out of its DeviceFS buffer.

  UKSWIV     Unknown SWI Vector - lets the module answer SWI numbers
             that don't belong to its own SWI chunk, which is how the
             Serial-Port (&81540) and Joy-module (&CFFC0-3) compatibility
             SWIs work (see doc.APIs) despite not being "real" module
             SWIs. Routed through a hand-written ARM pre-veneer
             (s.ukswiv) that copies the unclaimed SWI number into R9 before
             calling the C handler, and inspects R9 afterwards to decide
             whether to claim the vector or pass it on.

  ByteV      Intercepts OS_Byte calls - used for the ADC/ADVAL emulation
             (c.adc).

  PointerV   Intercepts pointer-position requests - used by c.mouse to
             report a joystick-driven relative pointer movement back to
             the OS pointer manager when mouse control is active.

Service calls (service-call-handler in the CMHG header, dispatched in
c.joydev's servicecall_handler):

  Service_USBDriver (reason "Attach")   New USB device detected -> feeds
                                        joy_check_device() to see if it's
                                        a joystick we recognise.
  Service_DeviceDead                    A device has gone away -> feeds
                                        joy_remove_device() to clean up.

At module init time, usb_scan_devices() also proactively walks any
already-connected devices through the same joy_check_device() path,
rather than waiting for a fresh Attach notification.


Data flow: from a joystick being plugged in to an application reading it
-----------------------------------------------------------------------------
1. USB attach (Service_USBDriver "Attach", or the init-time device scan)
   -> joy_check_device() (c.joydev) walks the device's USB descriptors
   and checks its class/subclass/protocol/VID/PID against the known-
   device table (c.device) via lookup_joy_device().

2. If recognised, the HID Report Descriptor is obtained - either a
   baked-in one from the device table (for devices like XBox360 pads
   that don't self-describe usably), or fetched live from the device -
   and handed to parse_usb_hid_device_descriptor() (c.joydev), which:
     - allocates the next free joy_data[] slot
     - passes the descriptor to the vendored NetBSD HID parser
     - walks every input item under a Joystick/GamePad collection,
       classifying each as a HAT switch, D-pad direction, a supported
       analogue axis (via the supported_axes_usage[] lookup table,
       bounds-checked - this exact bounds check was a real bug fixed
       during the code audit, see git history), or a button
     - computes each axis's scaling slopes once here (not per-read)

3. set_up_joystick() opens the device's DeviceFS path and calls
   auto_map() (c.map) to give the stick sensible default mappings onto
   all the classic APIs immediately, without needing an admin to run any
   *USBJoystick_Map* commands by hand.

4. On every incoming packet, UpCallV fires -> upcallv_hook_handler()
   (c.buffer) matches the DeviceFS handle, pulls the raw bytes via the
   buffer manager, and calls joystick_decode() (c.joydev), which updates
   joy_data[i].axes[]/buttons[] from the raw HID report bytes (HAT/D-pad
   directions are derived here too), and drives mouse-pointer emulation
   if this stick currently has mouse control.

5. Any of the four classic APIs, or *USBJoystick_Read/Debug, simply read
   the live joy_data[i].axes[]/buttons[] through whichever mapping
   indirection (mapped_x_8, adc_map, etc) the relevant *USBJoystick_Map*
   command set up.

6. Service_DeviceDead -> joy_remove_device() closes the handle, releases
   mouse control if this stick had it, renumbers any higher legacy
   mapped_number so they stay contiguous (unmap(), c.map), and resets the
   joy_data[] slot back to defaults.
