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