1/*
2 * Copyright 2007-2008, Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Michael Lotz <mmlr@mlotz.ch>
7 *		Salvatore Benedetto <salvatore.benedetto@gmail.com>
8 */
9
10#include <USBKit.h>
11#include <usb_raw.h>
12
13#include <new>
14#include <string.h>
15#include <unistd.h>
16
17
18BUSBInterface::BUSBInterface(BUSBConfiguration *config, uint32 index,
19	uint32 alternate, int rawFD)
20	:	fConfiguration(config),
21		fIndex(index),
22		fAlternate(alternate),
23		fRawFD(rawFD),
24		fEndpoints(NULL),
25		fAlternateCount(0),
26		fAlternates(NULL),
27		fInterfaceString(NULL)
28{
29	_UpdateDescriptorAndEndpoints();
30}
31
32
33BUSBInterface::~BUSBInterface()
34{
35	delete[] fInterfaceString;
36
37	if (fEndpoints != NULL) {
38		for (int32 i = 0; i < fDescriptor.num_endpoints; i++)
39			delete fEndpoints[i];
40		delete[] fEndpoints;
41	}
42
43	if (fAlternates != NULL) {
44		for (uint32 i = 0; i < fAlternateCount; i++)
45			delete fAlternates[i];
46		delete[] fAlternates;
47	}
48}
49
50
51uint32
52BUSBInterface::Index() const
53{
54	return fIndex;
55}
56
57
58uint32
59BUSBInterface::AlternateIndex() const
60{
61	if (fAlternate == B_USB_RAW_ACTIVE_ALTERNATE)
62		return ActiveAlternateIndex();
63	return fAlternate;
64}
65
66
67const BUSBConfiguration *
68BUSBInterface::Configuration() const
69{
70	return fConfiguration;
71}
72
73
74const BUSBDevice *
75BUSBInterface::Device() const
76{
77	return fConfiguration->Device();
78}
79
80
81uint8
82BUSBInterface::Class() const
83{
84	return fDescriptor.interface_class;
85}
86
87
88uint8
89BUSBInterface::Subclass() const
90{
91	return fDescriptor.interface_subclass;
92}
93
94
95uint8
96BUSBInterface::Protocol() const
97{
98	return fDescriptor.interface_protocol;
99}
100
101
102const char *
103BUSBInterface::InterfaceString() const
104{
105	if (fDescriptor.interface == 0)
106		return "";
107
108	if (fInterfaceString)
109		return fInterfaceString;
110
111	fInterfaceString = Device()->DecodeStringDescriptor(fDescriptor.interface);
112	if (fInterfaceString == NULL)
113		return "";
114
115	return fInterfaceString;
116}
117
118
119const usb_interface_descriptor *
120BUSBInterface::Descriptor() const
121{
122	return &fDescriptor;
123}
124
125
126status_t
127BUSBInterface::OtherDescriptorAt(uint32 index, usb_descriptor *descriptor,
128	size_t length) const
129{
130	if (length <= 0 || descriptor == NULL)
131		return B_BAD_VALUE;
132
133	usb_raw_command command;
134	command.generic_etc.descriptor = descriptor;
135	command.generic_etc.config_index = fConfiguration->Index();
136	command.generic_etc.interface_index = fIndex;
137	command.generic_etc.alternate_index = fAlternate;
138	command.generic_etc.generic_index = index;
139	command.generic_etc.length = length;
140	if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_GENERIC_DESCRIPTOR_ETC, &command,
141		sizeof(command)) || command.generic.status != B_USB_RAW_STATUS_SUCCESS)
142		return B_ERROR;
143
144	return B_OK;
145}
146
147
148uint32
149BUSBInterface::CountEndpoints() const
150{
151	return fDescriptor.num_endpoints;
152}
153
154
155const BUSBEndpoint *
156BUSBInterface::EndpointAt(uint32 index) const
157{
158	if (index >= fDescriptor.num_endpoints || fEndpoints == NULL)
159		return NULL;
160
161	return fEndpoints[index];
162}
163
164
165uint32
166BUSBInterface::CountAlternates() const
167{
168	usb_raw_command command;
169	command.alternate.config_index = fConfiguration->Index();
170	command.alternate.interface_index = fIndex;
171	if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_ALT_INTERFACE_COUNT, &command,
172		sizeof(command)) || command.alternate.status != B_USB_RAW_STATUS_SUCCESS)
173		return 1;
174
175	return command.alternate.alternate_info;
176}
177
178
179const BUSBInterface *
180BUSBInterface::AlternateAt(uint32 alternateIndex) const
181{
182	if (fAlternateCount > 0 && fAlternates != NULL) {
183		if (alternateIndex >= fAlternateCount)
184			return NULL;
185
186		return fAlternates[alternateIndex];
187	}
188
189	if (fAlternateCount == 0)
190		fAlternateCount = CountAlternates();
191	if (alternateIndex >= fAlternateCount)
192		return NULL;
193
194	fAlternates = new(std::nothrow) BUSBInterface *[fAlternateCount];
195	if (fAlternates == NULL)
196		return NULL;
197
198	for (uint32 i = 0; i < fAlternateCount; i++) {
199		fAlternates[i] = new(std::nothrow) BUSBInterface(fConfiguration, fIndex,
200			i, fRawFD);
201	}
202
203	return fAlternates[alternateIndex];
204}
205
206
207uint32
208BUSBInterface::ActiveAlternateIndex() const
209{
210	usb_raw_command command;
211	command.alternate.config_index = fConfiguration->Index();
212	command.alternate.interface_index = fIndex;
213	if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_ACTIVE_ALT_INTERFACE_INDEX, &command,
214		sizeof(command)) || command.alternate.status != B_USB_RAW_STATUS_SUCCESS)
215		return 0;
216
217	return command.alternate.alternate_info;
218}
219
220
221status_t
222BUSBInterface::SetAlternate(uint32 alternateIndex)
223{
224	usb_raw_command command;
225	command.alternate.alternate_info = alternateIndex;
226	command.alternate.config_index = fConfiguration->Index();
227	command.alternate.interface_index = fIndex;
228	if (ioctl(fRawFD, B_USB_RAW_COMMAND_SET_ALT_INTERFACE, &command,
229		sizeof(command)) || command.alternate.status != B_USB_RAW_STATUS_SUCCESS)
230		return B_ERROR;
231
232	_UpdateDescriptorAndEndpoints();
233	return B_OK;
234}
235
236
237void
238BUSBInterface::_UpdateDescriptorAndEndpoints()
239{
240	usb_raw_command command;
241	command.interface_etc.descriptor = &fDescriptor;
242	command.interface_etc.config_index = fConfiguration->Index();
243	command.interface_etc.interface_index = fIndex;
244	command.interface_etc.alternate_index = fAlternate;
245	if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_INTERFACE_DESCRIPTOR_ETC, &command,
246		sizeof(command)) || command.interface.status != B_USB_RAW_STATUS_SUCCESS)
247		memset(&fDescriptor, 0, sizeof(fDescriptor));
248
249	if (fEndpoints != NULL) {
250		// Delete old endpoints
251		for (int32 i = 0; i < fDescriptor.num_endpoints; i++)
252			delete fEndpoints[i];
253		delete[] fEndpoints;
254	}
255
256	fEndpoints = new(std::nothrow) BUSBEndpoint *[fDescriptor.num_endpoints];
257	if (fEndpoints == NULL)
258		return;
259
260	for (int32 i = 0; i < fDescriptor.num_endpoints; i++)
261		fEndpoints[i] = new(std::nothrow) BUSBEndpoint(this, i, fRawFD);
262}
263