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