/*
 * Parts of this file - the report_desc declaration and the HID usage
 * page / usage definitions - are from NetBSD (lib/libusbhid/usbvar.h and
 * sys/dev/hid/hid.h):
 *
 * Copyright (c) 1998 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Lennart Augustsson (lennart@augustsson.net) at
 * Carlstedt Research & Technology.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

/*-
 * Portions of this file are based on USBDescriptors:
 *
 * Copyright (c) 2015 Colin Granville. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#ifndef USB_H_INCLUDED
#define USB_H_INCLUDED


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

#include "kernel.h"


// NetBSD's usb.h must come first: USBDevFS.h then skips its own copies of the
// descriptor types (its _USB_H_ guard). Note NetBSD's 16-bit fields are uWord
// byte pairs - read them with UGETW().
#include "USB/dev/usb/usb.h"
#include "USB/USBDevFS.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];
};


// 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





#define USB_MAX_ENCODED_STRING_LEN (USB_MAX_STRING_LEN * 3) /* UTF8 */



// HID request/descriptor codes - not part of USBDriver's exported
// USBDevFS.h (only its internal, unexported dev.usb.h.usbhid) - kept local
#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



// 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 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

// D-pad: part of the official USB HID Generic Desktop usage page
// missing from USBDriver's own dev.usb.h.usbhid, which stops at HUG_SYSTEM_MENU_DOWN
#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



#define USB_DEVICEFS_PATH_MAX_LENGTH 200




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

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

usb_descriptor_t* usb_get_descriptor_list(const USBServiceCall* device);

usb_string_descriptor_t* usb_get_device_string_descriptor(const usb_device_t* device, int index);
uint32_t 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, int fs_handle, int* buffer_handle, unsigned int *devfs_handle);

uint32_t usb_get_hid_u_value(uint8_t* buf);
int32_t usb_get_hid_s_value(uint8_t* buf);

#endif
