]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Usb/UsbBotPei/BotPeim.c
MdeModulePkg: Add PEI USB drivers and related PPIs
[mirror_edk2.git] / MdeModulePkg / Bus / Usb / UsbBotPei / BotPeim.c
1 /** @file
2 BOT Transportation implementation.
3
4 Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>
5
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions
8 of the BSD License which accompanies this distribution. The
9 full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15 **/
16
17 #include "UsbBotPeim.h"
18 #include "BotPeim.h"
19 #include "PeiUsbLib.h"
20
21 /**
22 Reset the given usb device.
23
24 @param PeiServices The pointer of EFI_PEI_SERVICES.
25 @param PeiBotDev The instance to PEI_BOT_DEVICE.
26
27 @retval EFI_INVALID_PARAMETER Can not get usb io ppi.
28 @retval EFI_SUCCESS Failed to reset the given usb device.
29
30 **/
31 EFI_STATUS
32 BotRecoveryReset (
33 IN EFI_PEI_SERVICES **PeiServices,
34 IN PEI_BOT_DEVICE *PeiBotDev
35 )
36 {
37 EFI_USB_DEVICE_REQUEST DevReq;
38 UINT32 Timeout;
39 PEI_USB_IO_PPI *UsbIoPpi;
40 UINT8 EndpointAddr;
41 EFI_STATUS Status;
42
43 UsbIoPpi = PeiBotDev->UsbIoPpi;
44
45 if (UsbIoPpi == NULL) {
46 return EFI_INVALID_PARAMETER;
47 }
48
49 ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
50
51 DevReq.RequestType = 0x21;
52 DevReq.Request = 0xFF;
53 DevReq.Value = 0;
54 DevReq.Index = 0;
55 DevReq.Length = 0;
56
57 Timeout = 3000;
58
59 Status = UsbIoPpi->UsbControlTransfer (
60 PeiServices,
61 UsbIoPpi,
62 &DevReq,
63 EfiUsbNoData,
64 Timeout,
65 NULL,
66 0
67 );
68
69 //
70 // clear bulk in endpoint stall feature
71 //
72 EndpointAddr = (PeiBotDev->BulkInEndpoint)->EndpointAddress;
73 PeiUsbClearEndpointHalt (PeiServices, UsbIoPpi, EndpointAddr);
74
75 //
76 // clear bulk out endpoint stall feature
77 //
78 EndpointAddr = (PeiBotDev->BulkOutEndpoint)->EndpointAddress;
79 PeiUsbClearEndpointHalt (PeiServices, UsbIoPpi, EndpointAddr);
80
81 return Status;
82 }
83
84 /**
85 Send the command to the device using Bulk-Out endpoint.
86
87 This function sends the command to the device using Bulk-Out endpoint.
88 BOT transfer is composed of three phases: Command, Data, and Status.
89 This is the Command phase.
90
91 @param PeiServices The pointer of EFI_PEI_SERVICES.
92 @param PeiBotDev The instance to PEI_BOT_DEVICE.
93 @param Command The command to transfer to device.
94 @param CommandSize The length of the command.
95 @param DataTransferLength The expected length of the data.
96 @param Direction The direction of the data.
97 @param Timeout Indicates the maximum time, in millisecond, which the
98 transfer is allowed to complete.
99
100 @retval EFI_DEVICE_ERROR Successful to send the command to device.
101 @retval EFI_SUCCESS Failed to send the command to device.
102
103 **/
104 EFI_STATUS
105 BotCommandPhase (
106 IN EFI_PEI_SERVICES **PeiServices,
107 IN PEI_BOT_DEVICE *PeiBotDev,
108 IN VOID *Command,
109 IN UINT8 CommandSize,
110 IN UINT32 DataTransferLength,
111 IN EFI_USB_DATA_DIRECTION Direction,
112 IN UINT16 Timeout
113 )
114 {
115 CBW Cbw;
116 EFI_STATUS Status;
117 PEI_USB_IO_PPI *UsbIoPpi;
118 UINTN DataSize;
119
120 UsbIoPpi = PeiBotDev->UsbIoPpi;
121
122 ZeroMem (&Cbw, sizeof (CBW));
123
124 //
125 // Fill the command block, detailed see BOT spec
126 //
127 Cbw.Signature = CBWSIG;
128 Cbw.Tag = 0x01;
129 Cbw.DataTransferLength = DataTransferLength;
130 Cbw.Flags = (UINT8) ((Direction == EfiUsbDataIn) ? 0x80 : 0);
131 Cbw.Lun = 0;
132 Cbw.CmdLen = CommandSize;
133
134 CopyMem (Cbw.CmdBlock, Command, CommandSize);
135
136 DataSize = sizeof (CBW);
137
138 Status = UsbIoPpi->UsbBulkTransfer (
139 PeiServices,
140 UsbIoPpi,
141 (PeiBotDev->BulkOutEndpoint)->EndpointAddress,
142 (UINT8 *) &Cbw,
143 &DataSize,
144 Timeout
145 );
146 if (EFI_ERROR (Status)) {
147 //
148 // Command phase fail, we need to recovery reset this device
149 //
150 BotRecoveryReset (PeiServices, PeiBotDev);
151 return EFI_DEVICE_ERROR;
152 }
153
154 return EFI_SUCCESS;
155 }
156
157 /**
158 Transfer the data between the device and host.
159
160 This function transfers the data between the device and host.
161 BOT transfer is composed of three phases: Command, Data, and Status.
162 This is the Data phase.
163
164 @param PeiServices The pointer of EFI_PEI_SERVICES.
165 @param PeiBotDev The instance to PEI_BOT_DEVICE.
166 @param DataSize The length of the data.
167 @param DataBuffer The pointer to the data.
168 @param Direction The direction of the data.
169 @param Timeout Indicates the maximum time, in millisecond, which the
170 transfer is allowed to complete.
171
172 @retval EFI_DEVICE_ERROR Successful to send the data to device.
173 @retval EFI_SUCCESS Failed to send the data to device.
174
175 **/
176 EFI_STATUS
177 BotDataPhase (
178 IN EFI_PEI_SERVICES **PeiServices,
179 IN PEI_BOT_DEVICE *PeiBotDev,
180 IN UINT32 *DataSize,
181 IN OUT VOID *DataBuffer,
182 IN EFI_USB_DATA_DIRECTION Direction,
183 IN UINT16 Timeout
184 )
185 {
186 EFI_STATUS Status;
187 PEI_USB_IO_PPI *UsbIoPpi;
188 UINT8 EndpointAddr;
189 UINTN Remain;
190 UINTN Increment;
191 UINT32 MaxPacketLen;
192 UINT8 *BufferPtr;
193 UINTN TransferredSize;
194
195 UsbIoPpi = PeiBotDev->UsbIoPpi;
196
197 Remain = *DataSize;
198 BufferPtr = (UINT8 *) DataBuffer;
199 TransferredSize = 0;
200
201 //
202 // retrieve the the max packet length of the given endpoint
203 //
204 if (Direction == EfiUsbDataIn) {
205 MaxPacketLen = (PeiBotDev->BulkInEndpoint)->MaxPacketSize;
206 EndpointAddr = (PeiBotDev->BulkInEndpoint)->EndpointAddress;
207 } else {
208 MaxPacketLen = (PeiBotDev->BulkOutEndpoint)->MaxPacketSize;
209 EndpointAddr = (PeiBotDev->BulkOutEndpoint)->EndpointAddress;
210 }
211
212 while (Remain > 0) {
213 //
214 // Using 15 packets to avoid Bitstuff error
215 //
216 if (Remain > 16 * MaxPacketLen) {
217 Increment = 16 * MaxPacketLen;
218 } else {
219 Increment = Remain;
220 }
221
222 Status = UsbIoPpi->UsbBulkTransfer (
223 PeiServices,
224 UsbIoPpi,
225 EndpointAddr,
226 BufferPtr,
227 &Increment,
228 Timeout
229 );
230
231 TransferredSize += Increment;
232
233 if (EFI_ERROR (Status)) {
234 PeiUsbClearEndpointHalt (PeiServices, UsbIoPpi, EndpointAddr);
235 return Status;
236 }
237
238 BufferPtr += Increment;
239 Remain -= Increment;
240 }
241
242 *DataSize = (UINT32) TransferredSize;
243
244 return EFI_SUCCESS;
245 }
246
247 /**
248 Get the command execution status from device.
249
250 This function gets the command execution status from device.
251 BOT transfer is composed of three phases: Command, Data, and Status.
252 This is the Status phase.
253
254 @param PeiServices The pointer of EFI_PEI_SERVICES.
255 @param PeiBotDev The instance to PEI_BOT_DEVICE.
256 @param TransferStatus The status of the transaction.
257 @param Timeout Indicates the maximum time, in millisecond, which the
258 transfer is allowed to complete.
259
260 @retval EFI_DEVICE_ERROR Successful to get the status of device.
261 @retval EFI_SUCCESS Failed to get the status of device.
262
263 **/
264 EFI_STATUS
265 BotStatusPhase (
266 IN EFI_PEI_SERVICES **PeiServices,
267 IN PEI_BOT_DEVICE *PeiBotDev,
268 OUT UINT8 *TransferStatus,
269 IN UINT16 Timeout
270 )
271 {
272 CSW Csw;
273 EFI_STATUS Status;
274 PEI_USB_IO_PPI *UsbIoPpi;
275 UINT8 EndpointAddr;
276 UINTN DataSize;
277
278 UsbIoPpi = PeiBotDev->UsbIoPpi;
279
280 ZeroMem (&Csw, sizeof (CSW));
281
282 EndpointAddr = (PeiBotDev->BulkInEndpoint)->EndpointAddress;
283
284 DataSize = sizeof (CSW);
285
286 //
287 // Get the status field from bulk transfer
288 //
289 Status = UsbIoPpi->UsbBulkTransfer (
290 PeiServices,
291 UsbIoPpi,
292 EndpointAddr,
293 &Csw,
294 &DataSize,
295 Timeout
296 );
297 if (EFI_ERROR (Status)) {
298 return Status;
299 }
300
301 if (Csw.Signature == CSWSIG) {
302 *TransferStatus = Csw.Status;
303 } else {
304 return EFI_DEVICE_ERROR;
305 }
306
307 return EFI_SUCCESS;
308 }
309
310 /**
311 Send ATAPI command using BOT protocol.
312
313 @param PeiServices The pointer of EFI_PEI_SERVICES.
314 @param PeiBotDev The instance to PEI_BOT_DEVICE.
315 @param Command The command to be sent to ATAPI device.
316 @param CommandSize The length of the data to be sent.
317 @param DataBuffer The pointer to the data.
318 @param BufferLength The length of the data.
319 @param Direction The direction of the data.
320 @param TimeOutInMilliSeconds Indicates the maximum time, in millisecond, which the
321 transfer is allowed to complete.
322
323 @retval EFI_DEVICE_ERROR Successful to get the status of device.
324 @retval EFI_SUCCESS Failed to get the status of device.
325
326 **/
327 EFI_STATUS
328 PeiAtapiCommand (
329 IN EFI_PEI_SERVICES **PeiServices,
330 IN PEI_BOT_DEVICE *PeiBotDev,
331 IN VOID *Command,
332 IN UINT8 CommandSize,
333 IN VOID *DataBuffer,
334 IN UINT32 BufferLength,
335 IN EFI_USB_DATA_DIRECTION Direction,
336 IN UINT16 TimeOutInMilliSeconds
337 )
338 {
339 EFI_STATUS Status;
340 EFI_STATUS BotDataStatus;
341 UINT8 TransferStatus;
342 UINT32 BufferSize;
343
344 BotDataStatus = EFI_SUCCESS;
345 //
346 // First send ATAPI command through Bot
347 //
348 Status = BotCommandPhase (
349 PeiServices,
350 PeiBotDev,
351 Command,
352 CommandSize,
353 BufferLength,
354 Direction,
355 TimeOutInMilliSeconds
356 );
357
358 if (EFI_ERROR (Status)) {
359 return EFI_DEVICE_ERROR;
360 }
361 //
362 // Send/Get Data if there is a Data Stage
363 //
364 switch (Direction) {
365 case EfiUsbDataIn:
366 case EfiUsbDataOut:
367 BufferSize = BufferLength;
368
369 BotDataStatus = BotDataPhase (
370 PeiServices,
371 PeiBotDev,
372 &BufferSize,
373 DataBuffer,
374 Direction,
375 TimeOutInMilliSeconds
376 );
377 break;
378
379 case EfiUsbNoData:
380 break;
381 }
382 //
383 // Status Phase
384 //
385 Status = BotStatusPhase (
386 PeiServices,
387 PeiBotDev,
388 &TransferStatus,
389 TimeOutInMilliSeconds
390 );
391 if (EFI_ERROR (Status)) {
392 BotRecoveryReset (PeiServices, PeiBotDev);
393 return EFI_DEVICE_ERROR;
394 }
395
396 if (TransferStatus == 0x01) {
397 return EFI_DEVICE_ERROR;
398 }
399
400 return BotDataStatus;
401 }