/*-
 * Copyright (c) 2000 MAEKAWA Masahide <maekawa@math.sci.kobe-u.ac.jp>
 *		      UCHIYAMA Yasushi
 * 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.
 *
 *	$Maekawa: hid_items.c,v 1.16 2000/04/03 20:31:36 maekawa Exp $
 */

#include <stdio.h>

#include <dev/usb/usb.h>

#include "main.h"
#include "hid.h"

#include <hiddefs.h>

u_int32_t usage_page = 0;
int relative;

int level = 3;

static void hid_main_bits		__P((int, u_int8_t *, size_t));

/*
 * Main Item
 */
void
hid_main_item(tag, buf, bufsize)
	int tag;
	u_int8_t *buf;
	size_t bufsize;
{
	char *name;

	switch (tag) {
	case HID_MAIN_ITEM_INPUT:
		printf(": ");
		hid_main_bits(tag, buf, bufsize);
		break;
	case HID_MAIN_ITEM_OUTPUT:
		printf(": ");
		hid_main_bits(tag, buf, bufsize);
		break;
	case HID_MAIN_ITEM_COLLECTION:
		name = hid_get_collection_name(*buf);
		if (name)
			printf("(%s)", name);
		else
			printf("(Reserved: %02x)", *buf);

		if (bufsize > 1) {
			printf(" - Illegal bSize %d", bufsize);
		}
		printf("\n");
		level++;
		break;
	case HID_MAIN_ITEM_FEATURE:
		printf(": ");
		hid_main_bits(tag, buf, bufsize);
		break;
	case HID_MAIN_ITEM_ENDCOLLECTION:
		printf("\n");
		break;
	}

	return;
}

static void
hid_main_bits(tag, buf, bufsize)
	int tag;
	u_int8_t *buf;
	size_t bufsize;
{
	if (bufsize == 0) {
		printf(" {\n");

		level++;

		iprintf("Data\n");
		iprintf("Array\n");
		iprintf("Absolute\n");
		iprintf("No Wrap\n");
		iprintf("Linear\n");
		iprintf("Preferred State\n");
		iprintf("No Null position\n");

		level--;

		relative = 0;

		iprintf("\n");

		return;
	}

	if (BIT(*buf, 0, 1)) {
		printf("(Constant)\n");
		relative = 0;
		return;
	} else {
		bprintf(buf, bufsize);
		level++;
		printf(" {\n");
		iprintf("Data\n");
	}

	iprintf("%s\n", BIT(*buf, 1, 1) ? "Variable" : "Array");
	iprintf("%s\n", BIT(*buf, 2, 1) ? "Relative" : "Absolute");
	iprintf("%s\n", BIT(*buf, 3, 1) ? "Wrap" : "No Wrap");
	iprintf("%s\n", BIT(*buf, 4, 1) ? "Non Linear" : "Linear");
	iprintf("%s\n", BIT(*buf, 5, 1) ? "No Preferred" : "Preferred State");
	iprintf("%s\n", BIT(*buf, 6, 1) ? "Null State" : "No Null position");

	if (tag != 8) {
		iprintf("%s\n", BIT(*buf, 7, 1) ? "Volatile" : "Non Volatile");
	}

	if (bufsize > 1) {
		buf++;
		iprintf("%s\n", BIT(*buf, 0, 1) ?
			"Buffered Bytes" : "Bit Field");
	}

	level--;

	relative = BIT(buf[0], 1, 3);

	iprintf("}\n");

	return;
}

/*
 * Global Item
 */
void
hid_global_item(tag, buf, bufsize)
	int tag;
	u_int8_t *buf;
	size_t bufsize;
{
	char *name;
	int val = 0, i;

	if (relative) {
		switch (bufsize) {
		case 1:
			val = (int8_t)(*buf);
			break;
		case 2:
			val = (int16_t)(UGETW(buf));
			break;
		case 4:
			val = (int32_t)(UGETDW(buf));
			break;
		default:
			break;
		}
	} else {
		switch (bufsize) {
		case 1:
			val = *buf;
			break;
		case 2:
			val = UGETW(buf);
			break;
		case 4:
			val = UGETDW(buf);
			break;
		default:
			break;
		}
	}

	switch (tag) {
	case HID_GLOBAL_ITEM_USAGE_PAGE:
		for (usage_page = 0, i = 0 ; i < bufsize ; i++) {
			usage_page |= (u_int32_t)(buf[i] << (8 * i));
		}

		printf("(");

		name = hid_get_page_name(usage_page);
		if (name)
			printf("%s", name);
		else
			printf("%d", usage_page);

		printf(")");
		bufsize = 0;
		break;
	}

	if (bufsize > 0) {
		printf(": %d", val);
	}

	printf("\n");

	return;
}

/*
 * Local Item
 */
void
hid_local_item(tag, buf, bufsize)
	int tag;
	u_int8_t *buf;
	size_t bufsize;
{
	u_int32_t val;
	u_int16_t usage;
	char *name;
	int i;

	switch (tag) {
	case HID_LOCAL_ITEM_USAGE:
		printf("(");
		if (bufsize > 2) {
			printf(" - Illegal bSize %d", bufsize);
			break;
		}
		for (usage = 0, i = 0 ; i < bufsize ; i++)
			usage |= (u_int16_t)(buf[i] << (8 * i));
		name = hid_get_usage_name(usage_page, usage);
		if (name)
			printf("%s", name);
		else
			printf("Reserved:0x%x", usage);
		printf(")");
		bufsize = 0;
		break;
	}

	if (bufsize > 0) {
		for (val = 0, i = 0 ; i < bufsize ; i++) {
			val |= (buf[i] << (8 * i));
		}
		printf("(%x)", val);
	}

	printf("\n");

	return;
}
