xref: /haiku/src/add-ons/kernel/busses/usb/ohci_rh.cpp (revision 1214ef1b2100f2b3299fc9d8d6142e46f70a4c3f)
1 /*
2  * Copyright 2005-2008, Haiku Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *             Jan-Rixt Van Hoye
7  *             Salvatore Benedetto <salvatore.benedetto@gmail.com>
8  */
9 
10 #include "ohci.h"
11 
12 static usb_device_descriptor sOHCIRootHubDevice =
13 {
14 	0x12,					// Descriptor size
15 	USB_DESCRIPTOR_DEVICE,	// Type of descriptor
16 	0x110,					// USB 1.1
17 	0x09,					// Hub type
18 	0,						// Subclass
19 	0,						// Protocol
20 	64,						// Max packet size
21 	0,						// Vendor
22 	0,						// Product
23 	0x110,					// Version
24 	1,						// Index of manufacture string
25 	2,						// Index of product string
26 	0,						// Index of serial number string
27 	1						// Number of configurations
28 };
29 
30 
31 struct ohci_root_hub_configuration_s {
32 	usb_configuration_descriptor	configuration;
33 	usb_interface_descriptor		interface;
34 	usb_endpoint_descriptor			endpoint;
35 	usb_hub_descriptor				hub;
36 } _PACKED;
37 
38 
39 static ohci_root_hub_configuration_s sOHCIRootHubConfig =
40 {
41 	{ // configuration descriptor
42 		9,								// Descriptor length
43 		USB_DESCRIPTOR_CONFIGURATION,	// Descriptor type
44 		34,								// Total size of the configuration
45 		1,								// Number interfaces
46 		1,								// Value of configuration
47 		0,								// Number of configuration
48 		0x40,							// Self powered
49 		0								// Max power (0, because of self power)
50 	},
51 
52 	{ // interface descriptor
53 		9,								// Size
54 		USB_DESCRIPTOR_INTERFACE,		// Type
55 		0,								// Interface number
56 		0,								// Alternate setting
57 		1,								// Num endpoints
58 		0x09,							// Interface class
59 		0,								// Interface subclass
60 		0,								// Interface protocol
61 		0								// Interface
62 	},
63 
64 	{ // endpoint descriptor
65 		7,								// Size
66 		USB_DESCRIPTOR_ENDPOINT,		// Type
67 		USB_REQTYPE_DEVICE_IN | 1, 		// Endpoint address (first in IN endpoint)
68 		0x03,							// Attributes (0x03 = interrupt endpoint)
69 		8,								// Max packet size
70 		0xFF							// Interval 256
71 	},
72 
73 	{ // hub descriptor
74 		9,						// Lenght (including deprecated power
75 								// control mask)
76 		USB_DESCRIPTOR_HUB,		// Type
77 		0,						// Number of ports
78 		0x0000,					// Hub characteristics
79 		50,						// Power on to power good
80 		0,						// Current
81 		0x00,					// Both ports are removable
82 		0xff					// Depricated power control mask
83 	}
84 };
85 
86 struct ohci_root_hub_string_s {
87 	uint8	length;
88 	uint8	descriptor_type;
89 	uint16	unicode_string[12];
90 } _PACKED;
91 
92 
93 static ohci_root_hub_string_s sOHCIRootHubStrings[3] = {
94 	{
95 		4,								// Descriptor length
96 		USB_DESCRIPTOR_STRING,			// Descriptor type
97 		{
98 			0x0409						// Supported language IDs (English US)
99 		}
100 	},
101 
102 	{
103 		22,								// Descriptor length
104 		USB_DESCRIPTOR_STRING,			// Descriptor type
105 		{
106 			'H', 'A', 'I', 'K', 'U',	// Characters
107 			' ', 'I', 'n', 'c', '.'
108 		}
109 	},
110 
111 	{
112 		26,								// Descriptor length
113 		USB_DESCRIPTOR_STRING,			// Descriptor type
114 		{
115 			'O', 'H', 'C', 'I', ' ',	// Characters
116 			'R', 'o', 'o', 't', 'H',
117 			'u', 'b'
118 		}
119 	}
120 };
121 
122 
123 OHCIRootHub::OHCIRootHub(Object *rootObject, int8 deviceAddress)
124    :	Hub(rootObject, rootObject->GetStack()->IndexOfBusManager(rootObject->GetBusManager()),
125    			sOHCIRootHubDevice, deviceAddress, USB_SPEED_FULLSPEED)
126 {
127 }
128 
129 status_t
130 OHCIRootHub::ProcessTransfer(OHCI *ohci, Transfer *transfer)
131 {
132 	if ((transfer->TransferPipe()->Type() & USB_OBJECT_CONTROL_PIPE) == 0)
133 		return B_ERROR;
134 
135 	usb_request_data *request = transfer->RequestData();
136 
137 	TRACE(("usb_ohci_roothub(): request: %d\n", request->Request));
138 
139 	status_t status = B_TIMED_OUT;
140 	size_t actualLength = 0;
141 	switch (request->Request) {
142 		case USB_REQUEST_GET_STATUS: {
143 			if (request->Index == 0) {
144 				// get hub status
145 				actualLength = MIN(sizeof(usb_port_status),
146 					transfer->DataLength());
147 				// the hub reports whether the local power failed (bit 0)
148 				// and if there is a over-current condition (bit 1).
149 				// everything as 0 means all is ok.
150 				// TODO (?) actually check for the value
151 				memset(transfer->Data(), 0, actualLength);
152 				status = B_OK;
153 				break;
154 			}
155 
156 			usb_port_status portStatus;
157 			if (ohci->GetPortStatus(request->Index - 1, &portStatus) >= B_OK) {
158 				actualLength = MIN(sizeof(usb_port_status), transfer->DataLength());
159 				memcpy(transfer->Data(), (void *)&portStatus, actualLength);
160 				status = B_OK;
161 			}
162 			break;
163 		}
164 
165 		case USB_REQUEST_SET_ADDRESS:
166 			if (request->Value >= 128) {
167 				status = B_TIMED_OUT;
168 				break;
169 			}
170 
171 			TRACE(("usb_ohci_roothub():  set address: %d\n", request->Value));
172 			status = B_OK;
173 			break;
174 
175 		case USB_REQUEST_GET_DESCRIPTOR:
176 			TRACE(("usb_ohci_roothub(): get descriptor: %d\n", request->Value >> 8));
177 
178 			switch (request->Value >> 8) {
179 				case USB_DESCRIPTOR_DEVICE: {
180 					actualLength = MIN(sizeof(usb_device_descriptor),
181 						transfer->DataLength());
182 					memcpy(transfer->Data(), (void *)&sOHCIRootHubDevice,
183 						actualLength);
184 					status = B_OK;
185 					break;
186 				}
187 
188 				case USB_DESCRIPTOR_CONFIGURATION: {
189 					actualLength = MIN(sizeof(ohci_root_hub_configuration_s),
190 						transfer->DataLength());
191 					sOHCIRootHubConfig.hub.num_ports = ohci->PortCount();
192 					memcpy(transfer->Data(), (void *)&sOHCIRootHubConfig,
193 						actualLength);
194 					status = B_OK;
195 					break;
196 				}
197 
198 				case USB_DESCRIPTOR_STRING: {
199 					uint8 index = request->Value & 0x00ff;
200 					if (index > 2)
201 						break;
202 
203 					actualLength = MIN(sOHCIRootHubStrings[index].length,
204 						transfer->DataLength());
205 					memcpy(transfer->Data(), (void *)&sOHCIRootHubStrings[index],
206 						actualLength);
207 					status = B_OK;
208 					break;
209 				}
210 
211 				case USB_DESCRIPTOR_HUB: {
212 					actualLength = MIN(sizeof(usb_hub_descriptor),
213 						transfer->DataLength());
214 					sOHCIRootHubConfig.hub.num_ports = ohci->PortCount();
215 					memcpy(transfer->Data(), (void *)&sOHCIRootHubConfig.hub,
216 						actualLength);
217 					status = B_OK;
218 					break;
219 				}
220 			}
221 			break;
222 
223 		case USB_REQUEST_SET_CONFIGURATION:
224 			status = B_OK;
225 			break;
226 
227 		case USB_REQUEST_CLEAR_FEATURE: {
228 			if (request->Index == 0) {
229 				// we don't support any hub changes
230 				TRACE_ERROR(("usb_ohci_roothub(): clear feature: no hub changes\n"));
231 				break;
232 			}
233 
234 			TRACE(("usb_ohci_roothub(): clear feature: %d\n", request->Value));
235 			if (ohci->ClearPortFeature(request->Index - 1, request->Value) >= B_OK)
236 				status = B_OK;
237 			break;
238 		}
239 
240 		case USB_REQUEST_SET_FEATURE: {
241 			if (request->Index == 0) {
242 				// we don't support any hub changes
243 				TRACE_ERROR(("usb_ohci_roothub(): set feature: no hub changes\n"));
244 				break;
245 			}
246 
247 			TRACE(("usb_ohci_roothub(): set feature: %d\n", request->Value));
248 			if (ohci->SetPortFeature(request->Index - 1, request->Value) >= B_OK)
249 				status = B_OK;
250 			break;
251 		}
252 	}
253 
254 	transfer->Finished(status, actualLength);
255 	delete transfer;
256 	return B_OK;
257 }
258