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
BUSBInterface(BUSBConfiguration * config,uint32 index,uint32 alternate,int rawFD)18 BUSBInterface::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
~BUSBInterface()33 BUSBInterface::~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
51 uint32
Index() const52 BUSBInterface::Index() const
53 {
54 return fIndex;
55 }
56
57
58 uint32
AlternateIndex() const59 BUSBInterface::AlternateIndex() const
60 {
61 if (fAlternate == B_USB_RAW_ACTIVE_ALTERNATE)
62 return ActiveAlternateIndex();
63 return fAlternate;
64 }
65
66
67 const BUSBConfiguration *
Configuration() const68 BUSBInterface::Configuration() const
69 {
70 return fConfiguration;
71 }
72
73
74 const BUSBDevice *
Device() const75 BUSBInterface::Device() const
76 {
77 return fConfiguration->Device();
78 }
79
80
81 uint8
Class() const82 BUSBInterface::Class() const
83 {
84 return fDescriptor.interface_class;
85 }
86
87
88 uint8
Subclass() const89 BUSBInterface::Subclass() const
90 {
91 return fDescriptor.interface_subclass;
92 }
93
94
95 uint8
Protocol() const96 BUSBInterface::Protocol() const
97 {
98 return fDescriptor.interface_protocol;
99 }
100
101
102 const char *
InterfaceString() const103 BUSBInterface::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
119 const usb_interface_descriptor *
Descriptor() const120 BUSBInterface::Descriptor() const
121 {
122 return &fDescriptor;
123 }
124
125
126 status_t
OtherDescriptorAt(uint32 index,usb_descriptor * descriptor,size_t length) const127 BUSBInterface::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
148 uint32
CountEndpoints() const149 BUSBInterface::CountEndpoints() const
150 {
151 return fDescriptor.num_endpoints;
152 }
153
154
155 const BUSBEndpoint *
EndpointAt(uint32 index) const156 BUSBInterface::EndpointAt(uint32 index) const
157 {
158 if (index >= fDescriptor.num_endpoints || fEndpoints == NULL)
159 return NULL;
160
161 return fEndpoints[index];
162 }
163
164
165 uint32
CountAlternates() const166 BUSBInterface::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
179 const BUSBInterface *
AlternateAt(uint32 alternateIndex) const180 BUSBInterface::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
207 uint32
ActiveAlternateIndex() const208 BUSBInterface::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
221 status_t
SetAlternate(uint32 alternateIndex)222 BUSBInterface::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
237 void
_UpdateDescriptorAndEndpoints()238 BUSBInterface::_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