#ifndef DEVICE_H_INCLUDED
#define DEVICE_H_INCLUDED

#include "usbjoystick.h"   // Joystick_MaxAxes

#define JOY_TYPE_STANDARD   0
#define JOY_TYPE_XBOX360    1
#define JOY_TYPE_XBOX360WL  2

// Per-driver quirk bits (joy_device_struct.quirks).
//   JOY_QUIRK_NO_SERIAL - this device's USB iSerialNumber is not a stable,
//     per-unit identifier (cheap Xbox360 clones synthesise a fresh value
//     each enumeration; even genuine Xbox360 pads have no useful serial).
//     The config-store fingerprint ignores the serial for such devices and
//     keys by VID:PID only - see c.config config_fingerprint(), doc.Config.
#define JOY_QUIRK_NO_SERIAL   (1u << 0)
//   JOY_QUIRK_LOSSY_OUTPUT - this device can drop a command without any
//     error (the Xbox 360 wireless receiver), so a rumble stop is sent more
//     than once. See c.rumble, doc.Rumble.
#define JOY_QUIRK_LOSSY_OUTPUT (1u << 1)

// How output reaches the device (joy_device_struct.output_transport).
#define JOY_OUTPUT_NONE       0
#define JOY_OUTPUT_ENDPOINT   1   // interrupt OUT endpoint on the pad's interface
#define JOY_OUTPUT_CONTROL    2   // HID SET_REPORT on the control pipe

typedef int (joy_device_data_valid_fn)(char *d);

// Start-up for a device that sends nothing until asked; runs once the
// descriptor has parsed, before the slot's endpoints are known.
typedef _kernel_oserror *(joy_init_fn)(const usb_device_t *dev, uint8_t interface);

// Sends the slot's current rumble strengths (joy_data[slot].output).
typedef _kernel_oserror *(joy_rumble_fn)(uint32_t slot);

// Sends the slot's player LED.
typedef _kernel_oserror *(joy_led_fn)(uint32_t slot);

// Called from the upcall handler with each whole packet read from a slot;
// input says whether the validator accepted it. Runs where no USB write is
// possible: it may only set state, read the clock and request a callback.
typedef void (joy_packet_fn)(uint32_t slot, const uint8_t *data, uint32_t len, int input);

// Corrects a report in place before it is decoded; body is the report data,
// after any report id and report_data_offset.
typedef void (joy_fixup_fn)(uint8_t *body);

struct joy_device_struct {
  uint8_t                    interface_class;
  uint8_t                    interface_subclass;
  uint8_t                    interface_protocol;
  uint16_t                   vendor_id;
  uint16_t                   product_id;
  char                       *name;
  uint8_t                    type;
  uint8_t                    *report_descriptor;
  uint8_t                    report_descriptor_length;
  uint8_t                    report_data_offset;      // additional bytes before report data starts
  joy_init_fn                *init;
  uint8_t                    auto_invert_axes[Joystick_MaxAxes];
  uint8_t                    auto_invert_axes_length;
  joy_device_data_valid_fn   *data_valid;
  uint32_t                   quirks;                  // JOY_QUIRK_* bitfield
  uint8_t                    output_transport;        // JOY_OUTPUT_*
  joy_rumble_fn              *rumble;
  joy_led_fn                 *led;
  joy_packet_fn              *packet;
  joy_fixup_fn               *fixup;
  uint32_t                   auto_map_skip_buttons;   // buttons the automatic mapping leaves unbound (bit n = button n)
};

extern uint32_t joy_devices_count;



int xbox360wireless_data_validator(char *d);

struct joy_device_struct *lookup_joy_device(uint8_t iClass, uint8_t iSubClass, uint8_t iProtocol, uint16_t vendor, uint16_t product);


#endif
