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 */
8
9#include <USBKit.h>
10#include <usb_raw.h>
11#include <unistd.h>
12#include <string.h>
13
14
15BUSBEndpoint::BUSBEndpoint(BUSBInterface *interface, uint32 index, int rawFD)
16	:	fInterface(interface),
17		fIndex(index),
18		fRawFD(rawFD)
19{
20	usb_raw_command command;
21	command.endpoint_etc.descriptor = &fDescriptor;
22	command.endpoint_etc.config_index = fInterface->Configuration()->Index();
23	command.endpoint_etc.interface_index = fInterface->Index();
24	command.endpoint_etc.alternate_index = fInterface->AlternateIndex();
25	command.endpoint_etc.endpoint_index = fIndex;
26	if (ioctl(fRawFD, B_USB_RAW_COMMAND_GET_ENDPOINT_DESCRIPTOR_ETC, &command,
27		sizeof(command)) || command.endpoint_etc.status != B_USB_RAW_STATUS_SUCCESS)
28		memset(&fDescriptor, 0, sizeof(fDescriptor));
29}
30
31
32BUSBEndpoint::~BUSBEndpoint()
33{
34}
35
36
37uint32
38BUSBEndpoint::Index() const
39{
40	return fIndex;
41}
42
43
44const BUSBInterface *
45BUSBEndpoint::Interface() const
46{
47	return fInterface;
48}
49
50
51const BUSBConfiguration *
52BUSBEndpoint::Configuration() const
53{
54	return fInterface->Configuration();
55}
56
57
58const BUSBDevice *
59BUSBEndpoint::Device() const
60{
61	return fInterface->Device();
62}
63
64
65bool
66BUSBEndpoint::IsBulk() const
67{
68	return (fDescriptor.attributes & USB_ENDPOINT_ATTR_MASK)
69		== USB_ENDPOINT_ATTR_BULK;
70}
71
72
73bool
74BUSBEndpoint::IsInterrupt() const
75{
76	return (fDescriptor.attributes & USB_ENDPOINT_ATTR_MASK)
77		== USB_ENDPOINT_ATTR_INTERRUPT;
78}
79
80
81bool
82BUSBEndpoint::IsIsochronous() const
83{
84	return (fDescriptor.attributes & USB_ENDPOINT_ATTR_MASK)
85		== USB_ENDPOINT_ATTR_ISOCHRONOUS;
86}
87
88
89bool
90BUSBEndpoint::IsControl() const
91{
92	return (fDescriptor.attributes & USB_ENDPOINT_ATTR_MASK)
93		== USB_ENDPOINT_ATTR_CONTROL;
94}
95
96
97bool
98BUSBEndpoint::IsInput() const
99{
100	return (fDescriptor.endpoint_address & USB_ENDPOINT_ADDR_DIR_IN)
101		== USB_ENDPOINT_ADDR_DIR_IN;
102}
103
104
105bool
106BUSBEndpoint::IsOutput() const
107{
108	return (fDescriptor.endpoint_address & USB_ENDPOINT_ADDR_DIR_IN)
109		== USB_ENDPOINT_ADDR_DIR_OUT;
110}
111
112
113uint16
114BUSBEndpoint::MaxPacketSize() const
115{
116	return fDescriptor.max_packet_size;
117}
118
119
120uint8
121BUSBEndpoint::Interval() const
122{
123	return fDescriptor.interval;
124}
125
126
127const usb_endpoint_descriptor *
128BUSBEndpoint::Descriptor() const
129{
130	return &fDescriptor;
131}
132
133
134ssize_t
135BUSBEndpoint::ControlTransfer(uint8 requestType, uint8 request, uint16 value,
136	uint16 index, uint16 length, void *data) const
137{
138	if (length > 0 && data == NULL)
139		return B_BAD_VALUE;
140
141	usb_raw_command command;
142	command.control.request_type = requestType;
143	command.control.request = request;
144	command.control.value = value;
145	command.control.index = index;
146	command.control.length = length;
147	command.control.data = data;
148
149	if (ioctl(fRawFD, B_USB_RAW_COMMAND_CONTROL_TRANSFER, &command,
150		sizeof(command)) || command.control.status != B_USB_RAW_STATUS_SUCCESS)
151		return B_ERROR;
152
153	return command.control.length;
154}
155
156
157ssize_t
158BUSBEndpoint::InterruptTransfer(void *data, size_t length) const
159{
160	if (length > 0 && data == NULL)
161		return B_BAD_VALUE;
162
163	usb_raw_command command;
164	command.transfer.interface = fInterface->Index();
165	command.transfer.endpoint = fIndex;
166	command.transfer.data = data;
167	command.transfer.length = length;
168
169	if (ioctl(fRawFD, B_USB_RAW_COMMAND_INTERRUPT_TRANSFER, &command,
170		sizeof(command)) || command.transfer.status != B_USB_RAW_STATUS_SUCCESS)
171		return B_ERROR;
172
173	return command.transfer.length;
174}
175
176
177ssize_t
178BUSBEndpoint::BulkTransfer(void *data, size_t length) const
179{
180	if (length > 0 && data == NULL)
181		return B_BAD_VALUE;
182
183	usb_raw_command command;
184	command.transfer.interface = fInterface->Index();
185	command.transfer.endpoint = fIndex;
186	command.transfer.data = data;
187	command.transfer.length = length;
188
189	if (ioctl(fRawFD, B_USB_RAW_COMMAND_BULK_TRANSFER, &command,
190		sizeof(command)) || command.transfer.status != B_USB_RAW_STATUS_SUCCESS)
191		return B_ERROR;
192
193	return command.transfer.length;
194}
195
196
197ssize_t
198BUSBEndpoint::IsochronousTransfer(void *data, size_t length,
199	usb_iso_packet_descriptor *packetDescriptors, uint32 packetCount) const
200{
201	if (length > 0 && data == NULL)
202		return B_BAD_VALUE;
203
204	usb_raw_command command;
205	command.isochronous.interface = fInterface->Index();
206	command.isochronous.endpoint = fIndex;
207	command.isochronous.data = data;
208	command.isochronous.length = length;
209	command.isochronous.packet_descriptors = packetDescriptors;
210	command.isochronous.packet_count = packetCount;
211
212	if (ioctl(fRawFD, B_USB_RAW_COMMAND_ISOCHRONOUS_TRANSFER, &command,
213		sizeof(command)) || command.isochronous.status != B_USB_RAW_STATUS_SUCCESS)
214		return B_ERROR;
215
216	return command.isochronous.length;
217}
218
219
220bool
221BUSBEndpoint::IsStalled() const
222{
223	uint16 status = 0;
224	Device()->ControlTransfer(USB_REQTYPE_ENDPOINT_IN,
225		USB_REQUEST_GET_STATUS, USB_FEATURE_ENDPOINT_HALT,
226		fDescriptor.endpoint_address, sizeof(status), &status);
227	return status != 0;
228}
229
230
231status_t
232BUSBEndpoint::ClearStall() const
233{
234	return Device()->ControlTransfer(USB_REQTYPE_ENDPOINT_OUT,
235		USB_REQUEST_CLEAR_FEATURE, USB_FEATURE_ENDPOINT_HALT,
236		fDescriptor.endpoint_address, 0, NULL);
237}
238