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