xref: /haiku/src/add-ons/kernel/drivers/input/usb_hid/QuirkyDevices.cpp (revision 820dca4df6c7bf955c46e8f6521b9408f50b2900)
1 /*
2  * Copyright 2011 Michael Lotz <mmlr@mlotz.ch>
3  * Distributed under the terms of the MIT license.
4  */
5 
6 
7 #include "QuirkyDevices.h"
8 
9 #include "HIDWriter.h"
10 
11 #include <string.h>
12 
13 #include <usb/USB_hid.h>
14 
15 
16 static status_t
17 sixaxis_init(usb_device device, const usb_configuration_info *config,
18 	size_t interfaceIndex)
19 {
20 	TRACE_ALWAYS("found SIXAXIS controller, putting it in operational mode\n");
21 
22 	// an extra get_report is required for the SIXAXIS to become operational
23 	uint8 dummy[18];
24 	status_t result = gUSBModule->send_request(device, USB_REQTYPE_INTERFACE_IN
25 			| USB_REQTYPE_CLASS, B_USB_REQUEST_HID_GET_REPORT, 0x03f2 /* ? */,
26 		interfaceIndex, sizeof(dummy), dummy, NULL);
27 	if (result != B_OK) {
28 		TRACE_ALWAYS("failed to set operational mode: %s\n", strerror(result));
29 	}
30 
31 	return result;
32 }
33 
34 
35 static status_t
36 sixaxis_build_descriptor(HIDWriter &writer)
37 {
38 	writer.BeginCollection(COLLECTION_APPLICATION,
39 		B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_JOYSTICK);
40 
41 	main_item_data_converter converter;
42 	converter.flat_data = 0; // defaults
43 	converter.main_data.array_variable = 1;
44 	converter.main_data.no_preferred = 1;
45 
46 	writer.SetReportID(1);
47 
48 	// unknown / padding
49 	writer.DefineInputPadding(1, 8);
50 
51 	// digital button state on/off
52 	writer.DefineInputData(19, 1, converter.main_data, 0, 1,
53 		B_HID_USAGE_PAGE_BUTTON, 1);
54 
55 	// padding to 32 bit boundary
56 	writer.DefineInputPadding(13, 1);
57 
58 	// left analog stick
59 	writer.DefineInputData(1, 8, converter.main_data, 0, 255,
60 		B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_X);
61 	writer.DefineInputData(1, 8, converter.main_data, 0, 255,
62 		B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_Y);
63 
64 	// right analog stick
65 	writer.DefineInputData(1, 8, converter.main_data, 0, 255,
66 		B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_X);
67 	writer.DefineInputData(1, 8, converter.main_data, 0, 255,
68 		B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_Y);
69 
70 	// unknown / padding
71 	writer.DefineInputPadding(4, 8);
72 
73 	// pressure sensitive button states
74 	writer.DefineInputData(12, 8, converter.main_data, 0, 255,
75 		B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_VNO, B_HID_UID_GD_VNO);
76 
77 	// unknown / padding / operation mode / battery status / connection ...
78 	writer.DefineInputPadding(15, 8);
79 
80 	// accelerometer x, y and z
81 	writer.DefineInputData(3, 16, converter.main_data, 0, UINT16_MAX,
82 		B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_VX);
83 
84 	// gyroscope
85 	writer.DefineInputData(1, 16, converter.main_data, 0, UINT16_MAX,
86 		B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_VBRZ);
87 
88 	return writer.EndCollection();
89 }
90 
91 
92 static status_t
93 xbox360_build_descriptor(HIDWriter &writer)
94 {
95 	writer.BeginCollection(COLLECTION_APPLICATION,
96 		B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_JOYSTICK);
97 
98 	main_item_data_converter converter;
99 	converter.flat_data = 0; // defaults
100 	converter.main_data.array_variable = 1;
101 	converter.main_data.no_preferred = 1;
102 
103 	// unknown / padding / byte count
104 	writer.DefineInputPadding(2, 8);
105 
106 	// dpad / buttons
107 	writer.DefineInputData(11, 1, converter.main_data, 0, 1,
108 		B_HID_USAGE_PAGE_BUTTON, 1);
109 	writer.DefineInputPadding(1, 1);
110 	writer.DefineInputData(4, 1, converter.main_data, 0, 1,
111 		B_HID_USAGE_PAGE_BUTTON, 12);
112 
113 	// triggers
114 	writer.DefineInputData(1, 8, converter.main_data, 0, 255,
115 		B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_Z);
116 	writer.DefineInputData(1, 8, converter.main_data, 0, 255,
117 		B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_RZ);
118 
119 	// sticks
120 	writer.DefineInputData(2, 16, converter.main_data, -32768, 32767,
121 		B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_X);
122 	writer.DefineInputData(2, 16, converter.main_data, -32768, 32767,
123 		B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_X);
124 
125 	// unknown / padding
126 	writer.DefineInputPadding(6, 8);
127 
128 	return writer.EndCollection();
129 }
130 
131 
132 usb_hid_quirky_device gQuirkyDevices[] = {
133 	{
134 		// The Sony SIXAXIS controller (PS3) needs a GET_REPORT to become
135 		// operational which we do in sixaxis_init. Also the normal report
136 		// descriptor doesn't contain items for the motion sensing data
137 		// and pressure sensitive buttons, so we constrcut a new report
138 		// descriptor that includes those extra items.
139 		0x054c, 0x0268, USB_INTERFACE_CLASS_HID, 0, 0,
140 		sixaxis_init, sixaxis_build_descriptor
141 	},
142 
143 	{
144 		// XBOX 360 controllers aren't really HID (marked vendor specific).
145 		// They therefore don't provide a HID/report descriptor either. The
146 		// input stream is HID-like enough though. We therefore claim support
147 		// and build a report descriptor of our own.
148 		0, 0, 0xff /* vendor specific */, 0x5d /* XBOX controller */, 0x01,
149 		NULL, xbox360_build_descriptor
150 	}
151 };
152 
153 int32 gQuirkyDeviceCount
154 	= sizeof(gQuirkyDevices) / sizeof(gQuirkyDevices[0]);
155