#ifndef USB_H_INCLUDED
#define USB_H_INCLUDED


#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include "kernel.h"

#include "oslib/os.h"
#include "oslib/devicefs.h"



// this is really just a string name for a connected USB device
// e.g. 'USB4'
typedef struct USBDevice usb_device_t;


// this is NetBSD: /lib/libusbhid/usbvar.h

struct report_desc {
    unsigned int   size;
    unsigned char  data[1];
};





// these are based on NetBSD: /sys/dev/usb/usb.h


// etherusb doesn't have this packed.  hmm.
typedef __packed struct
{
  uint8_t     bLength;
  uint8_t     bDescriptorType;
  uint16_t    bcdUSB;
  uint8_t     bDeviceClass;
  uint8_t     bDeviceSubClass;
  uint8_t     bDeviceProtocol;
  uint8_t     bMaxPacketSize;
  uint16_t    idVendor;
  uint16_t    idProduct;
  uint16_t    bcdDevice;
  uint8_t     iManufacturer;
  uint8_t     iProduct;
  uint8_t     iSerialNumber;
  uint8_t     bNumConfigurations;
} usb_device_descriptor_t;

#define USB_DEVICE_DESCRIPTOR           1
#define USB_DEVICE_DESCRIPTOR_SIZE 18



typedef __packed struct
{
  uint8_t     bLength;
  uint8_t     bDescriptorType;
  uint16_t    wTotalLength;
  uint8_t     bNumInterface;
  uint8_t     bConfigurationValue;
  uint8_t     iConfiguration;
  uint8_t     bmAttributes;
  uint8_t     bMaxPower;
  //usb_descriptor_t*     data[];  //  Colin has this - why?
} usb_config_descriptor_t;

#define USB_CONFIGURATION_DESCRIPTOR    2
#define USB_CONFIG_DESCRIPTOR_SIZE 9


typedef __packed struct
{
  uint8_t     bLength;
  uint8_t     bDescriptorType;
  uint8_t     bInterfaceNumber;
  uint8_t     bAlternateSetting;
  uint8_t     bNumEndpoints;
  uint8_t     bInterfaceClass;
  uint8_t     bInterfaceSubClass;
  uint8_t     bInterfaceProtocol;
  uint8_t     iInterface;
} usb_interface_descriptor_t;

#define USB_INTERFACE_DESCRIPTOR        4
#define USB_INTERFACE_DESCRIPTOR_SIZE 9


typedef __packed struct
{
  uint8_t     bLength;
  uint8_t     bDescriptorType;
  uint8_t     bEndpointAddress;
  uint8_t     bmAttributes;
  uint16_t    wMaxPacketSize;
  uint8_t     bInterval;
} usb_endpoint_descriptor_t;

#define USB_ENDPOINT_DESCRIPTOR         5
#define USB_ENDPOINT_DESCRIPTOR_SIZE 7



// Colin has this - do we need it?
/*
typedef __packed struct
{
    USB_DescriptorBase;
    uint8_t             bFirstInterface;
    uint8_t             bInterfaceCount;
    uint8_t             bFunctionClass;
    uint8_t             bFunctionSubClass;
    uint8_t             bFunctionProtocol;
    uint8_t             iFunction;
} USB_InterfaceAssociationDescriptor;
#define USB_INTERFACE_ASSOCIATION_DESCRIPTOR         0x0b
*/



typedef __packed struct {
  uint8_t     bLength;
  uint8_t     bDescriptorType;
  uint8_t     bMaxBurst;
  uint8_t     bmAttributes;
  uint16_t    wBytesPerInterval;
} usb_endpoint_ss_comp_descriptor_t;
#define USB_ENDPOINT_SS_COMP_DESCRIPTOR_SIZE 6



typedef __packed struct {
  uint8_t     bLength;
  uint8_t     bDescriptorType;
  uint16_t    wTotalLength;
  uint8_t     bNumDeviceCaps;
} usb_bos_descriptor_t;
#define USB_BOS_DESCRIPTOR_SIZE 5


struct usb_ctl_report_desc {
  int              ucrd_size;
  unsigned char    ucrd_data[1024];    /* filled data size will vary */
};



#define USB_MAX_STRING_LEN 128
#define USB_LANGUAGE_TABLE 0	/* # of the string language id table */
#define USB_MAX_ENCODED_STRING_LEN (USB_MAX_STRING_LEN * 3) /* UTF8 */

typedef __packed struct
{
  uint8_t     bLength;
  uint8_t     bDescriptorType;
  uint16_t    bString[127];       // Colin has [1], RISC OS usbd has [127]
} usb_string_descriptor_t;
#define USB_STRING_DESCRIPTOR           3


/* The following struct allows you to cast then extract the length and type */
typedef __packed struct
{
  uint8_t     bLength;
  uint8_t     bDescriptorType;
  uint8_t     bDescriptorSubtype;
  //  uint8_t             data[];   // Colin has this entry - why?
} usb_descriptor_t;



#define UT_GET_DIR(a) ((a) & 0x80)
#define UT_WRITE		0x00
#define UT_READ			0x80

#define UT_GET_TYPE(a) ((a) & 0x60)
#define UT_STANDARD		0x00
#define UT_CLASS		0x20
#define UT_VENDOR		0x40

#define UT_GET_RECIPIENT(a) ((a) & 0x1f)
#define UT_DEVICE		0x00
#define UT_INTERFACE		0x01
#define UT_ENDPOINT		0x02
#define UT_OTHER		0x03

#define UT_READ_DEVICE		(UT_READ  | UT_STANDARD | UT_DEVICE)
#define UT_READ_INTERFACE	(UT_READ  | UT_STANDARD | UT_INTERFACE)
#define UT_READ_ENDPOINT	(UT_READ  | UT_STANDARD | UT_ENDPOINT)
#define UT_WRITE_DEVICE		(UT_WRITE | UT_STANDARD | UT_DEVICE)
#define UT_WRITE_INTERFACE	(UT_WRITE | UT_STANDARD | UT_INTERFACE)
#define UT_WRITE_ENDPOINT	(UT_WRITE | UT_STANDARD | UT_ENDPOINT)
#define UT_READ_CLASS_DEVICE	(UT_READ  | UT_CLASS | UT_DEVICE)
#define UT_READ_CLASS_INTERFACE	(UT_READ  | UT_CLASS | UT_INTERFACE)
#define UT_READ_CLASS_OTHER	(UT_READ  | UT_CLASS | UT_OTHER)
#define UT_READ_CLASS_ENDPOINT	(UT_READ  | UT_CLASS | UT_ENDPOINT)
#define UT_WRITE_CLASS_DEVICE	(UT_WRITE | UT_CLASS | UT_DEVICE)
#define UT_WRITE_CLASS_INTERFACE (UT_WRITE | UT_CLASS | UT_INTERFACE)
#define UT_WRITE_CLASS_OTHER	(UT_WRITE | UT_CLASS | UT_OTHER)
#define UT_WRITE_CLASS_ENDPOINT	(UT_WRITE | UT_CLASS | UT_ENDPOINT)
#define UT_READ_VENDOR_DEVICE	(UT_READ  | UT_VENDOR | UT_DEVICE)
#define UT_READ_VENDOR_INTERFACE (UT_READ  | UT_VENDOR | UT_INTERFACE)
#define UT_READ_VENDOR_OTHER	(UT_READ  | UT_VENDOR | UT_OTHER)
#define UT_READ_VENDOR_ENDPOINT	(UT_READ  | UT_VENDOR | UT_ENDPOINT)
#define UT_WRITE_VENDOR_DEVICE	(UT_WRITE | UT_VENDOR | UT_DEVICE)
#define UT_WRITE_VENDOR_INTERFACE (UT_WRITE | UT_VENDOR | UT_INTERFACE)
#define UT_WRITE_VENDOR_OTHER	(UT_WRITE | UT_VENDOR | UT_OTHER)
#define UT_WRITE_VENDOR_ENDPOINT (UT_WRITE | UT_VENDOR | UT_ENDPOINT)


/* Standard Requests Codes from the USB 2.0 spec, table 9-4 */
#define UR_GET_STATUS		0x00
#define UR_CLEAR_FEATURE	0x01
#define UR_SET_FEATURE		0x03
#define UR_SET_ADDRESS		0x05
#define UR_GET_DESCRIPTOR	0x06
#define  UDESC_DEVICE		0x01
#define  UDESC_CONFIG		0x02
#define  UDESC_STRING		0x03
#define  UDESC_INTERFACE	0x04
#define  UDESC_ENDPOINT		0x05
#define  UDESC_DEVICE_QUALIFIER	0x06
#define  UDESC_OTHER_SPEED_CONFIGURATION 0x07
#define  UDESC_INTERFACE_POWER	0x08
#define  UDESC_OTG		0x09
#define  UDESC_DEBUG		0x0a
#define  UDESC_INTERFACE_ASSOC	0x0b
#define  UDESC_CS_DEVICE	0x21	/* class specific */
#define  UDESC_CS_CONFIG	0x22
#define  UDESC_CS_STRING	0x23
#define  UDESC_CS_INTERFACE	0x24
#define  UDESC_CS_ENDPOINT	0x25
#define  UDESC_HUB		0x29
#define  UDESC_SSHUB		0x2a
#define UR_SET_DESCRIPTOR	0x07
#define UR_GET_CONFIG		0x08
#define UR_SET_CONFIG		0x09
#define UR_GET_INTERFACE	0x0a
#define UR_SET_INTERFACE	0x0b
#define UR_SYNCH_FRAME		0x0c



#define UR_GET_HID_DESCRIPTOR	0x06
#define  UDESC_HID		0x21
#define  UDESC_REPORT		0x22
#define  UDESC_PHYSICAL		0x23
#define UR_SET_HID_DESCRIPTOR	0x07
#define UR_GET_REPORT		0x01
#define UR_SET_REPORT		0x09
#define UR_GET_IDLE		0x02
#define UR_SET_IDLE		0x0a
#define UR_GET_PROTOCOL		0x03
#define UR_SET_PROTOCOL		0x0b







#define USB_CS_UNDEFINED                    0x20
#define USB_CS_DEVICE_DESCRIPTOR            0x21
#define USB_CS_CONFIGURATION_DESCRIPTOR     0x22
#define USB_CS_STRING_DESCRIPTOR            0x23
#define USB_CS_INTERFACE_DESCRIPTOR         0x24
#define USB_CS_ENDPOINT_DESCRIPTOR          0x25



// this looks like NetBSD: /dev/usb/usbhid.h

// Colin's way
typedef __packed struct
{
    uint8_t             bLength;
    uint8_t             bDescriptorType;
    uint16_t            bcdHID;
    uint8_t             bCountryCode;
    uint8_t             bNumDescriptors;
    uint8_t             bReportDescType;
    uint16_t            wReportDescLength;
} usb_hid_device_descriptor_t;

// NetBSD way
/*typedef __packed struct
{
    uint8_t             bLength;
    uint8_t             bDescriptorType;
    uint16_t            bcdHID;
    uint8_t             bCountryCode;
    uint8_t             bNumDescriptors;
    struct {
      uint8_t           bReportDescType;
      uint16_t          wReportDescLength;
    } descrs[1];
} usb_hid_device_descriptor_t;
*/


#define UICLASS_HID                     0x03

#define USB_HID_BOOT_SUBCLASS           1

#define USB_HID_KEYBOARD_PROTOCOL       1
#define USB_HID_MOUSE_PROTOCOL          2

#define USB_HID_CS_NOBOOT               0x30000
#define USB_HID_CS_BOOT                 0x30100



#define UHID_INPUT_REPORT 0x01
#define UHID_OUTPUT_REPORT 0x02
#define UHID_FEATURE_REPORT 0x03




// from netbsd - /sys/dev/hid/hid.h

// usage pages
#define HUP_UNDEFINED		0x0000
#define HUP_GENERIC_DESKTOP	0x0001
#define HUP_SIMULATION		0x0002
#define HUP_VR_CONTROLS		0x0003
#define HUP_SPORTS_CONTROLS	0x0004
#define HUP_GAMING_CONTROLS	0x0005
#define HUP_KEYBOARD		0x0007
#define HUP_LEDS		0x0008
#define HUP_BUTTON		0x0009
#define HUP_ORDINALS		0x000a
#define HUP_TELEPHONY		0x000b
#define HUP_CONSUMER		0x000c
#define HUP_DIGITIZERS		0x000d
#define HUP_PHYSICAL_IFACE	0x000e
#define HUP_UNICODE		0x0010
#define HUP_ALPHANUM_DISPLAY	0x0014
#define HUP_MONITOR		0x0080
#define HUP_MONITOR_ENUM_VAL	0x0081
#define HUP_VESA_VC		0x0082
#define HUP_VESA_CMD		0x0083
#define HUP_POWER		0x0084
#define HUP_BATTERY		0x0085
#define HUP_BARCODE_SCANNER	0x008b
#define HUP_SCALE		0x008c
#define HUP_CAMERA_CONTROL	0x0090
#define HUP_ARCADE		0x0091
#define HUP_VENDOR		0x00ff
#define HUP_MICROSOFT		0xff00
/* XXX compat */
#define HUP_APPLE		0x00ff
#define HUP_WACOM		0xff00

// usages, generic desktop
#define HUG_POINTER		0x0001
#define HUG_MOUSE		0x0002
#define HUG_FN_KEY		0x0003
#define HUG_JOYSTICK		0x0004
#define HUG_GAME_PAD		0x0005
#define HUG_KEYBOARD		0x0006
#define HUG_KEYPAD		0x0007
#define HUG_X			0x0030
#define HUG_Y			0x0031
#define HUG_Z			0x0032
#define HUG_RX			0x0033
#define HUG_RY			0x0034
#define HUG_RZ			0x0035
#define HUG_SLIDER		0x0036
#define HUG_DIAL		0x0037
#define HUG_WHEEL		0x0038
#define HUG_HAT_SWITCH		0x0039
#define HUG_COUNTED_BUFFER	0x003a
#define HUG_BYTE_COUNT		0x003b
#define HUG_MOTION_WAKEUP	0x003c
#define HUG_VX			0x0040
#define HUG_VY			0x0041
#define HUG_VZ			0x0042
#define HUG_VBRX		0x0043
#define HUG_VBRY		0x0044
#define HUG_VBRZ		0x0045
#define HUG_VNO			0x0046
#define HUG_TWHEEL		0x0048
#define HUG_SYSTEM_CONTROL	0x0080
#define HUG_SYSTEM_POWER_DOWN	0x0081
#define HUG_SYSTEM_SLEEP	0x0082
#define HUG_SYSTEM_WAKEUP	0x0083
#define HUG_SYSTEM_CONTEXT_MENU	0x0084
#define HUG_SYSTEM_MAIN_MENU	0x0085
#define HUG_SYSTEM_APP_MENU	0x0086
#define HUG_SYSTEM_MENU_HELP	0x0087
#define HUG_SYSTEM_MENU_EXIT	0x0088
#define HUG_SYSTEM_MENU_SELECT	0x0089
#define HUG_SYSTEM_MENU_RIGHT	0x008a
#define HUG_SYSTEM_MENU_LEFT	0x008b
#define HUG_SYSTEM_MENU_UP	0x008c
#define HUG_SYSTEM_MENU_DOWN	0x008d

#define HUG_DPAD_UP 0x90
#define HUG_DPAD_DOWN 0x91
#define HUG_DPAD_RIGHT 0x92
#define HUG_DPAD_LEFT 0x93




#define USB_DEVICE_NAME_LENGTH 20



typedef struct
{
  uint16_t                sum_length;
  uint16_t                descriptors_offset;
  char                    name[USB_DEVICE_NAME_LENGTH];           // e.g. 'USB1'
  uint8_t                 bus;                // Bus number 0-255
  uint8_t                 address;            // Device address 1-127
  uint8_t                 host_address;       // Device address 0-127
  uint8_t                 host_port;          // Port on host device
  uint8_t                 speed;              // Speed
  uint8_t                 unused1;            // Padding
  uint8_t                 unused2;            // Padding
  uint8_t                 unused3;            // Padding
  usb_device_descriptor_t device;             // Device desciptor
} usb_service_t;
// above is USBServiceCall in RISC OS sources


typedef struct usb_service_list
{
  struct usb_service_list* next;              // Or NULL if no more.
  usb_service_t            device;            // Device information.
} usb_service_list_t;
// above is USBServiceAnswer in RISC OS sources

#define USB_DEVICEFS_PATH_MAX_LENGTH 200




// Calls 'fn' for each USB device currently connected.
typedef _kernel_oserror* (usb_scan_devices_fn)(const usb_service_t*, void* handle);

_kernel_oserror* usb_scan_devices(usb_scan_devices_fn* fn, void* handle);

usb_descriptor_t* usb_get_descriptor_list(const usb_service_t* device);

usb_string_descriptor_t* usb_get_device_string_descriptor(const usb_device_t* device, int index);
int usb_string_descriptor_to_ascii(const usb_string_descriptor_t* str, char *buffer);

_kernel_oserror* usb_get_descriptor(const usb_device_t* dev, uint8_t type, uint16_t length, uint8_t* buf);

_kernel_oserror* usb_hid_set_output_report(const usb_device_t* dev, uint8_t interface, uint8_t* buf, uint16_t length);

_kernel_oserror* usb_get_device_handle(const usb_device_t* device, os_fw fs_handle, buffer_b* buffer_handle, unsigned int *devfs_handle);

unsigned int usb_get_hid_u_value(uint8_t* buf);
int usb_get_hid_s_value(uint8_t* buf);
             
#endif
