1aaeffcf7SMichael Lotz/*
2d75a9062SMichael Lotz * Copyright 2009-2011, Michael Lotz, mmlr@mlotz.ch.
3aaeffcf7SMichael Lotz * Distributed under the terms of the MIT License.
4aaeffcf7SMichael Lotz */
5aaeffcf7SMichael Lotz
6fd97180eSMichael Lotz#ifndef USERLAND_HID
75ba33c51SMichael Lotz#include "Driver.h"
8fd97180eSMichael Lotz#else
9fd97180eSMichael Lotz#include "UserlandHID.h"
10fd97180eSMichael Lotz#endif
115ba33c51SMichael Lotz
12e7fcf08dSMichael Lotz#include "HIDReportItem.h"
13e7fcf08dSMichael Lotz#include "HIDReport.h"
14e7fcf08dSMichael Lotz
15e7fcf08dSMichael Lotz#include <string.h>
16e7fcf08dSMichael Lotz
17e7fcf08dSMichael LotzHIDReportItem::HIDReportItem(HIDReport *report, uint32 bitOffset,
18e7fcf08dSMichael Lotz	uint8 bitLength, bool hasData, bool isArray, bool isRelative,
19e7fcf08dSMichael Lotz	uint32 minimum, uint32 maximum, uint32 usageMinimum, uint32 usageMaximum)
20e7fcf08dSMichael Lotz	:	fReport(report),
21e7fcf08dSMichael Lotz		fByteOffset(bitOffset / 8),
22e7fcf08dSMichael Lotz		fShift(bitOffset % 8),
23e7fcf08dSMichael Lotz		fMask(~(0xffffffff << bitLength)),
24d75a9062SMichael Lotz		fBitCount(bitLength),
2526bebb13SMichael Lotz		fByteCount((fShift + fBitCount + 7) / 8),
26e7fcf08dSMichael Lotz		fHasData(hasData),
27e7fcf08dSMichael Lotz		fArray(isArray),
28e7fcf08dSMichael Lotz		fRelative(isRelative),
29e7fcf08dSMichael Lotz		fMinimum(minimum),
30e7fcf08dSMichael Lotz		fMaximum(maximum),
31e7fcf08dSMichael Lotz		fUsageMinimum(usageMinimum),
32e7fcf08dSMichael Lotz		fUsageMaximum(usageMaximum),
33e7fcf08dSMichael Lotz		fData(0),
34e7fcf08dSMichael Lotz		fValid(false)
35e7fcf08dSMichael Lotz{
36e7fcf08dSMichael Lotz}
37e7fcf08dSMichael Lotz
38e7fcf08dSMichael Lotz
395ba33c51SMichael Lotzuint16
405ba33c51SMichael LotzHIDReportItem::UsagePage()
415ba33c51SMichael Lotz{
425ba33c51SMichael Lotz	usage_value value;
435ba33c51SMichael Lotz	value.u.extended = fUsageMinimum;
445ba33c51SMichael Lotz	return value.u.s.usage_page;
455ba33c51SMichael Lotz}
465ba33c51SMichael Lotz
475ba33c51SMichael Lotz
488e1857f7SMichael Lotzuint16
498e1857f7SMichael LotzHIDReportItem::UsageID()
508e1857f7SMichael Lotz{
518e1857f7SMichael Lotz	usage_value value;
528e1857f7SMichael Lotz	value.u.extended = fUsageMinimum;
538e1857f7SMichael Lotz	return value.u.s.usage_id;
548e1857f7SMichael Lotz}
558e1857f7SMichael Lotz
568e1857f7SMichael Lotz
57e7fcf08dSMichael Lotzstatus_t
58e7fcf08dSMichael LotzHIDReportItem::Extract()
59e7fcf08dSMichael Lotz{
60e7fcf08dSMichael Lotz	// The specs restrict items to span at most across 4 bytes, which means
61e7fcf08dSMichael Lotz	// that we can always just byte-align, copy four bytes and then shift and
62e7fcf08dSMichael Lotz	// mask as needed.
63e7fcf08dSMichael Lotz	uint8 *report = fReport->CurrentReport();
64e7fcf08dSMichael Lotz	if (report == NULL)
65e7fcf08dSMichael Lotz		return B_NO_INIT;
66e7fcf08dSMichael Lotz
6726bebb13SMichael Lotz	memcpy(&fData, report + fByteOffset, fByteCount);
68e7fcf08dSMichael Lotz	fData >>= fShift;
69e7fcf08dSMichael Lotz	fData &= fMask;
70e7fcf08dSMichael Lotz
71e7fcf08dSMichael Lotz	if (Signed()) {
72e7fcf08dSMichael Lotz		// sign extend if needed.
73e7fcf08dSMichael Lotz		if ((fData & ~(fMask >> 1)) != 0)
74e7fcf08dSMichael Lotz			fData |= ~fMask;
75e7fcf08dSMichael Lotz
76e7fcf08dSMichael Lotz		fValid = (int32)fData >= (int32)fMinimum
77e7fcf08dSMichael Lotz			&& (int32)fData <= (int32)fMaximum;
78e7fcf08dSMichael Lotz	} else
79e7fcf08dSMichael Lotz		fValid = fData >= fMinimum && fData <= fMaximum;
80e7fcf08dSMichael Lotz
81e7fcf08dSMichael Lotz	return B_OK;
82e7fcf08dSMichael Lotz}
835ba33c51SMichael Lotz
845ba33c51SMichael Lotz
858e1857f7SMichael Lotzstatus_t
868e1857f7SMichael LotzHIDReportItem::Insert()
878e1857f7SMichael Lotz{
888e1857f7SMichael Lotz	uint8 *report = fReport->CurrentReport();
898e1857f7SMichael Lotz	if (report == NULL)
908e1857f7SMichael Lotz		return B_NO_INIT;
918e1857f7SMichael Lotz
928e1857f7SMichael Lotz	uint32 value;
9326bebb13SMichael Lotz	memcpy(&value, report + fByteOffset, fByteCount);
948e1857f7SMichael Lotz	value &= ~(fMask << fShift);
958e1857f7SMichael Lotz
968e1857f7SMichael Lotz	if (fValid)
978e1857f7SMichael Lotz		value |= (fData & fMask) << fShift;
988e1857f7SMichael Lotz
9926bebb13SMichael Lotz	memcpy(report + fByteOffset, &value, fByteCount);
1008e1857f7SMichael Lotz	return B_OK;
1018e1857f7SMichael Lotz}
1028e1857f7SMichael Lotz
1038e1857f7SMichael Lotz
1048e1857f7SMichael Lotzstatus_t
1058e1857f7SMichael LotzHIDReportItem::SetData(uint32 data)
1068e1857f7SMichael Lotz{
1078e1857f7SMichael Lotz	fData = data;
1088e1857f7SMichael Lotz
1098e1857f7SMichael Lotz	if (Signed()) {
1108e1857f7SMichael Lotz		fValid = (int32)fData >= (int32)fMinimum
1118e1857f7SMichael Lotz			&& (int32)fData <= (int32)fMaximum;
1128e1857f7SMichael Lotz	} else
1138e1857f7SMichael Lotz		fValid = fData >= fMinimum && fData <= fMaximum;
1148e1857f7SMichael Lotz
1158e1857f7SMichael Lotz	return fValid ? B_OK : B_BAD_VALUE;
1168e1857f7SMichael Lotz}
1178e1857f7SMichael Lotz
1188e1857f7SMichael Lotz
119d75a9062SMichael Lotzuint32
120d75a9062SMichael LotzHIDReportItem::ScaledData(uint8 scaleToBits, bool toBeSigned)
121d75a9062SMichael Lotz{
1226d551ee4SMichael Lotz	uint32 source;
1236d551ee4SMichael Lotz	if (Signed() != toBeSigned) {
1246d551ee4SMichael Lotz		if (toBeSigned)
1256d551ee4SMichael Lotz			source = (uint32)((int32)fData - (fMaximum + 1) / 2) & fMask;
1266d551ee4SMichael Lotz		else
1276d551ee4SMichael Lotz			source = (uint32)((int32)fData - (int32)fMinimum);
1286d551ee4SMichael Lotz	} else
12910a1a81dSMichael Lotz		source = fData & fMask;
130d75a9062SMichael Lotz
131d75a9062SMichael Lotz	if (fBitCount == scaleToBits)
132d75a9062SMichael Lotz		return source;
133d75a9062SMichael Lotz
134d75a9062SMichael Lotz	int8 shift;
135d75a9062SMichael Lotz	uint32 result = 0;
136d75a9062SMichael Lotz	do {
137d75a9062SMichael Lotz		shift = scaleToBits - fBitCount;
138d75a9062SMichael Lotz		if (shift > 0) {
139d75a9062SMichael Lotz			result |= source << shift;
140d75a9062SMichael Lotz			scaleToBits = shift;
141d75a9062SMichael Lotz		} else
142d75a9062SMichael Lotz			result |= source >> -shift;
143d75a9062SMichael Lotz
144d75a9062SMichael Lotz	} while (shift > 0);
145d75a9062SMichael Lotz
146d75a9062SMichael Lotz	return result;
147d75a9062SMichael Lotz}
148d75a9062SMichael Lotz
149d75a9062SMichael Lotz
1509028fd53SMichael Lotzuint32
1519028fd53SMichael LotzHIDReportItem::ScaledRangeData(uint32 minimum, uint32 maximum)
1529028fd53SMichael Lotz{
1539028fd53SMichael Lotz	uint64 zeroBasedData;
1549028fd53SMichael Lotz	if (Signed())
1559028fd53SMichael Lotz		zeroBasedData = (int32)fData - (int32)fMinimum;
1569028fd53SMichael Lotz	else
1579028fd53SMichael Lotz		zeroBasedData = fData - fMinimum;
1589028fd53SMichael Lotz
1599028fd53SMichael Lotz	return zeroBasedData * (maximum - minimum + 1) / (fMaximum - fMinimum + 1)
1609028fd53SMichael Lotz		+ minimum;
1619028fd53SMichael Lotz}
1629028fd53SMichael Lotz
1639028fd53SMichael Lotz
1646eabc833SMichael Lotzfloat
1656eabc833SMichael LotzHIDReportItem::ScaledFloatData()
1666eabc833SMichael Lotz{
1676eabc833SMichael Lotz	if (Signed()) {
1686eabc833SMichael Lotz		return (double)((int32)fData - (int32)fMinimum)
1696eabc833SMichael Lotz			/ (fMaximum - (int32)fMinimum);
1706eabc833SMichael Lotz	}
1716eabc833SMichael Lotz
1726eabc833SMichael Lotz	return (double)(fData - fMinimum) / (fMaximum - fMinimum);
1736eabc833SMichael Lotz}
1746eabc833SMichael Lotz
1756eabc833SMichael Lotz
1765ba33c51SMichael Lotzvoid
1775ba33c51SMichael LotzHIDReportItem::PrintToStream(uint32 indentLevel)
1785ba33c51SMichael Lotz{
1795ba33c51SMichael Lotz	char indent[indentLevel + 1];
1805ba33c51SMichael Lotz	memset(indent, '\t', indentLevel);
1815ba33c51SMichael Lotz	indent[indentLevel] = 0;
1825ba33c51SMichael Lotz
1835ba33c51SMichael Lotz	TRACE_ALWAYS("%sHIDReportItem %p\n", indent, this);
1847e5b39b6SAlex Smith	TRACE_ALWAYS("%s\tbyte offset: %" B_PRIu32 "\n", indent, fByteOffset);
1855ba33c51SMichael Lotz	TRACE_ALWAYS("%s\tshift: %u\n", indent, fShift);
1867e5b39b6SAlex Smith	TRACE_ALWAYS("%s\tmask: 0x%08" B_PRIx32 "\n", indent, fMask);
1875ba33c51SMichael Lotz	TRACE_ALWAYS("%s\thas data: %s\n", indent, fHasData ? "yes" : "no");
1885ba33c51SMichael Lotz	TRACE_ALWAYS("%s\tarray: %s\n", indent, fArray ? "yes" : "no");
1895ba33c51SMichael Lotz	TRACE_ALWAYS("%s\trelative: %s\n", indent, fRelative ? "yes" : "no");
1907e5b39b6SAlex Smith	TRACE_ALWAYS("%s\tminimum: %" B_PRIu32 "\n", indent, fMinimum);
1917e5b39b6SAlex Smith	TRACE_ALWAYS("%s\tmaximum: %" B_PRIu32 "\n", indent, fMaximum);
1927e5b39b6SAlex Smith	TRACE_ALWAYS("%s\tusage minimum: 0x%08" B_PRIx32 "\n", indent, fUsageMinimum);
1937e5b39b6SAlex Smith	TRACE_ALWAYS("%s\tusage maximum: 0x%08" B_PRIx32 "\n", indent, fUsageMaximum);
1945ba33c51SMichael Lotz}