/* driver/hid/usb/hid/report.h
 *
 * (c) 2002 Simtec Electronics
 *
 * Ben Dooks
 *
 * USB HID Report Descriptor definitions
 *
 * $Id: report.h,v 1.11 2003/08/08 11:17:17 ben Exp $
 *
 * This Library file is part of the Simtec Electronics USB stack development
 *   suite.
 * Specific licence is granted to use this file by third parties for the
 *   development of USB device drivers.
 *
*/

/* document references from:
 *  'Device Class Definition for Human Interface Devices (HID)'
 *  version 1.11  27/6/01
*/

#ifndef __USB_HID_REPORT_H
#define __USB_HID_REPORT_H "$Id: report.h,v 1.11 2003/08/08 11:17:17 ben Exp $"


typedef unsigned int hid_usage_t;    /* 32bit -
					top 16 define the usage page
					bottom 16 define the tag */

#define hid_get_usagepage(ut) ((ut) >> 16)
#define hid_get_usage(ut) ((ut) & 0xffff)

typedef signed int hid_data_t;
typedef unsigned int hid_unsigned_t;

/* hid_global_data
 *
 * global data for the HID parser, which is given to each report when it is
 * created.
*/

typedef struct hid_global_data {
  hid_usage_t        hid_usage;

  hid_data_t         logical_min;
  hid_data_t         logical_max;
  hid_data_t         physical_min;
  hid_data_t         physical_max;
  hid_data_t         exponent;
  hid_data_t         unit;

  hid_data_t         report_size;
  hid_unsigned_t     report_id;
  hid_unsigned_t     report_count;
} hid_global_data_t;

typedef struct hid_global_state {
  struct hid_global_data    data;
} hid_global_state_t;

/* types for main sections, see table in 6.2.2.4 (page 28)  */

typedef enum hid_main_type {
  HID_MAIN_UNKNOWN = 0,
  HID_MAIN_INPUT = 8,
  HID_MAIN_OUTPUT = 9,
  HID_MAIN_FEATURE = 11,
  HID_MAIN_COLLECTION = 10,
  HID_MAIN_END_COLLECTION = 12
} hid_main_type_t;

/* collection type, see table in section 6.2.2.6 (page 33)
*/

typedef enum hid_report_collection_type {
  HID_COLLECTION_PHYSICAL       = 0x00,
  HID_COLLECTION_APPLICATION    = 0x01,
  HID_COLLECTION_LOGICAL        = 0x02,
  HID_COLLECTION_REPORT         = 0x03,
  HID_COLLECTION_NAMED_ARRAY    = 0x04,
  HID_COLLECTION_USAGE_SWITCH   = 0x05,
  HID_COLLECTION_USAGE_MODIFIER = 0x06
} hid_report_collection_type_t;

/* flags for hid reports of the type Input/Output/Feature
 *
 * See the HID spec section 6.2.2.5 (page 30)
 */

#define HID_REPORT_IOF_CONSTANT    (0x001)
#define HID_REPORT_IOF_VARIABLE    (0x002)
#define HID_REPORT_IOF_RELATIVE    (0x004)
#define HID_REPORT_IOF_WRAP        (0x008)
#define HID_REPORT_IOF_NONLINEAR   (0x010)
#define HID_REPORT_IOF_NOPREFFERED (0x020)
#define HID_REPORT_IOF_NULLSTATE   (0x040)
#define HID_REPORT_IOF_VOLATILE    (0x080)
#define HID_REPORT_IOF_BYTES       (0x100)

/* define our data-structures in advance */

struct hid_report;
struct hid_reports;

/* hid_report
 *
 * contains information on a report
 */

struct hid_report {
  hid_unsigned_t    flags;      /* report flags,  HID_REPORT_IOF... */
  hid_main_type_t   type;       /* report type */

#if 0
  /* should be in the global data */
  int               report_size;
  int               report_count;
#endif

  int               usage_count;

  /* usages are only valid in the case we have a variable item, the min and
   * max values are always set */

  hid_usage_t       usage_min;
  hid_usage_t       usage_max;
  hid_usage_t       *usages;

  hid_global_data_t global;
};

struct hid_report_list {
  struct hid_reports  *start;
  struct hid_reports  *end;
};


struct hid_collection {
  hid_report_collection_type_t  type;

  unsigned int         count;
  unsigned int         max_id;

  struct hid_report_list items;

  int                  usage_count;
  hid_usage_t          *usages;
};

/* hid_reports contains a set of reports, or a single report.
 *
 * REPORT     -> this item is a simple report structure
 * COLLECTION -> this item is a collection of reports and/or collections
 * ROOT       -> this exists in the global state to keep everything together
 */

typedef enum hid_reports_type {
  HID_REPORT,
  HID_COLLECTION,
  HID_ROOT
} hid_reports_type_t;


struct hid_reports {
  struct hid_reports     *list;      /* global list */
  struct hid_reports     *next;      /* items on this level */
  struct hid_reports     *parent;    /* parent, or NULL if top-level */

  hid_reports_type_t     type;     /* report or collection */

  union {
    struct hid_report     *report;
    struct hid_collection *collection;
  } data;

};

/* struct hid_tag
 *
 * a parsed representation of a data tag
 */

typedef struct hid_tag {
  unsigned char  tag;
  unsigned char  type;
  short          size;

  /* data -> either a pointer to a long data item (in the passed data block)
   * or the value decoded (in unsigned, and signed)
   */

  union {
    struct {
      unsigned int  uval;
      int           sval;
    } val;
    unsigned char *ptr;
  } data;
} hid_tag_t;

typedef struct hid_parser_stack_entry {
  struct hid_parser_stack_entry   *next;
  struct hid_global_state         state;
} hid_parser_stack_entry_t;

#ifndef HID_MAX_USAGES
#define HID_MAX_USAGES (128)
#endif

typedef struct hid_parser_state {
  struct    hid_parser_stack_entry *stack;

  struct    hid_reports            reports;
  struct    hid_reports            *current_collection;

  struct    hid_global_state       global;

  int                              usage_ptr;

  hid_usage_t                      usages[HID_MAX_USAGES];
  hid_usage_t                      usage_min, usage_max;


} hid_parser_state_t;


#endif /* __USB_HID_REPORT_H */
