]> git.proxmox.com Git - mirror_edk2.git/blame - QuarkPlatformPkg/Library/Tpm12DeviceLibInfineonI2c/TisPc.c
QuarkPlatformPkg: Fix variable set but not used build errors
[mirror_edk2.git] / QuarkPlatformPkg / Library / Tpm12DeviceLibInfineonI2c / TisPc.c
CommitLineData
957649a7
MK
1/** @file\r
2 Basic TIS (TPM Interface Specification) functions for Infineon I2C TPM.\r
3\r
4 Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>\r
5 This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include <PiPei.h>\r
16#include <Library/Tpm12DeviceLib.h>\r
17#include <Library/BaseLib.h>\r
18#include <Library/TimerLib.h>\r
19#include <Library/DebugLib.h>\r
20#include <Library/I2cLib.h>\r
21\r
22//\r
23// Default TPM (Infineon SLB9645) I2C Slave Device Address on Crosshill board.\r
24//\r
25#define TPM_I2C_SLAVE_DEVICE_ADDRESS 0x20\r
26\r
27//\r
28// Default Infineon SLB9645 TPM I2C mapped registers (SLB9645 I2C Comm. Protocol Application Note).\r
29//\r
30#define INFINEON_TPM_ACCESS_0_ADDRESS_DEFAULT 0x0\r
31#define INFINEON_TPM_STS_0_ADDRESS_DEFAULT 0x01\r
32#define INFINEON_TPM_BURST0_COUNT_0_DEFAULT 0x02\r
33#define INFINEON_TPM_BURST1_COUNT_0_DEFAULT 0x03\r
34#define INFINEON_TPM_DATA_FIFO_0_ADDRESS_DEFAULT 0x05\r
35#define INFINEON_TPM_DID_VID_0_DEFAULT 0x09\r
36\r
37//\r
38// Max. retry count for read transfers (as recommended by Infineon).\r
39//\r
40#define READ_RETRY 3\r
41\r
42//\r
43// Guard time of 250us between I2C read and next I2C write transfer (as recommended by Infineon).\r
44//\r
45#define GUARD_TIME 250\r
46\r
47//\r
48// Define bits of ACCESS and STATUS registers\r
49//\r
50\r
51///\r
52/// This bit is a 1 to indicate that the other bits in this register are valid.\r
53///\r
54#define TIS_PC_VALID BIT7\r
55///\r
56/// Indicate that this locality is active.\r
57///\r
58#define TIS_PC_ACC_ACTIVE BIT5\r
59///\r
60/// Set to 1 to indicate that this locality had the TPM taken away while\r
61/// this locality had the TIS_PC_ACC_ACTIVE bit set.\r
62///\r
63#define TIS_PC_ACC_SEIZED BIT4\r
64///\r
65/// Set to 1 to indicate that TPM MUST reset the\r
66/// TIS_PC_ACC_ACTIVE bit and remove ownership for localities less than the\r
67/// locality that is writing this bit.\r
68///\r
69#define TIS_PC_ACC_SEIZE BIT3\r
70///\r
71/// When this bit is 1, another locality is requesting usage of the TPM.\r
72///\r
73#define TIS_PC_ACC_PENDIND BIT2\r
74///\r
75/// Set to 1 to indicate that this locality is requesting to use TPM.\r
76///\r
77#define TIS_PC_ACC_RQUUSE BIT1\r
78///\r
79/// A value of 1 indicates that a T/OS has not been established on the platform\r
80///\r
81#define TIS_PC_ACC_ESTABLISH BIT0\r
82\r
83///\r
84/// When this bit is 1, TPM is in the Ready state,\r
85/// indicating it is ready to receive a new command.\r
86///\r
87#define TIS_PC_STS_READY BIT6\r
88///\r
89/// Write a 1 to this bit to cause the TPM to execute that command.\r
90///\r
91#define TIS_PC_STS_GO BIT5\r
92///\r
93/// This bit indicates that the TPM has data available as a response.\r
94///\r
95#define TIS_PC_STS_DATA BIT4\r
96///\r
97/// The TPM sets this bit to a value of 1 when it expects another byte of data for a command.\r
98///\r
99#define TIS_PC_STS_EXPECT BIT3\r
100///\r
101/// Writes a 1 to this bit to force the TPM to re-send the response.\r
102///\r
103#define TIS_PC_STS_RETRY BIT1\r
104\r
105//\r
106// Default TimeOut values in microseconds\r
107//\r
108#define TIS_TIMEOUT_A (750 * 1000) // 750ms\r
109#define TIS_TIMEOUT_B (2000 * 1000) // 2s\r
110#define TIS_TIMEOUT_C (750 * 1000) // 750ms\r
111#define TIS_TIMEOUT_D (750 * 1000) // 750ms\r
112\r
113//\r
114// Global variable to indicate if TPM I2C Read Transfer has previously occurred.\r
115// NOTE: Given the GUARD_TIME requirement (TpmAccess.h), if this library loaded\r
116// by PEI Drivers this global variable required to be resident in R/W memory\r
117//\r
118BOOLEAN mI2CPrevReadTransfer = FALSE;\r
119\r
120/**\r
121 Writes single byte data to TPM specified by I2C register address.\r
122\r
123 @param[in] TpmAddress The register to write.\r
124 @param[in] Data The data to write to the register.\r
125\r
126**/\r
127VOID\r
128TpmWriteByte (\r
129 IN UINTN TpmAddress,\r
130 IN UINT8 Data\r
131 )\r
132{\r
133 EFI_STATUS Status;\r
134 UINTN WriteLength;\r
135 UINT8 WriteData[2];\r
136 EFI_I2C_DEVICE_ADDRESS I2CDeviceAddr;\r
137\r
138 //\r
139 // Setup I2C Slave device address and address mode (7-bit).\r
140 //\r
141 I2CDeviceAddr.I2CDeviceAddress = TPM_I2C_SLAVE_DEVICE_ADDRESS;\r
142\r
143 //\r
144 // As recommended by Infineon (SLB9645 I2C Communication protocol application\r
145 // note revision 1.0) wait 250 microseconds between a read and a write transfer.\r
146 //\r
147 if (mI2CPrevReadTransfer) {\r
148 MicroSecondDelay (GUARD_TIME);\r
149 }\r
150\r
151 //\r
152 // Write to TPM register.\r
153 //\r
154 WriteLength = 2;\r
155 WriteData[0] = (UINT8)TpmAddress;\r
156 WriteData[1] = Data;\r
157\r
158 Status = I2cWriteMultipleByte (\r
159 I2CDeviceAddr,\r
160 EfiI2CSevenBitAddrMode,\r
161 &WriteLength,\r
162 &WriteData\r
163 );\r
164 if (EFI_ERROR(Status)) {\r
165 DEBUG ((EFI_D_ERROR, "TpmWriteByte(): I2C Write to TPM address %0x failed (%r)\n", TpmAddress, Status));\r
166 ASSERT (FALSE); // Writes to TPM should always succeed.\r
167 }\r
168\r
169 mI2CPrevReadTransfer = FALSE;\r
170}\r
171\r
172/**\r
173 Reads single byte data from TPM specified by I2C register address.\r
174\r
175 Due to stability issues when using I2C combined write/read transfers (with\r
176 RESTART) to TPM (specifically read from status register), a single write is\r
177 performed followed by single read (with STOP condition in between).\r
178\r
179 @param[in] TpmAddress Address of register to read.\r
180\r
181 @return The value register read.\r
182\r
183**/\r
184UINT8\r
185TpmReadByte (\r
186 IN UINTN TpmAddress\r
187 )\r
188{\r
189 UINT8 Data[1];\r
190 UINT8 ReadData;\r
191 UINT8 ReadCount;\r
192\r
193 EFI_I2C_DEVICE_ADDRESS I2CDeviceAddr;\r
194 EFI_I2C_ADDR_MODE I2CAddrMode;\r
195\r
196 EFI_STATUS Status;\r
197\r
198 Status = EFI_SUCCESS;\r
199 ReadData = 0xFF;\r
200 ReadCount = 0;\r
201\r
202 //\r
203 // Locate I2C protocol for TPM I2C access.\r
204 //\r
205 I2CDeviceAddr.I2CDeviceAddress = TPM_I2C_SLAVE_DEVICE_ADDRESS;\r
206 I2CAddrMode = EfiI2CSevenBitAddrMode;\r
207\r
208 //\r
209 // As recommended by Infineon (SLB9645 I2C Communication protocol application\r
210 // note revision 1.0) retry up to 3 times if TPM status, access or burst count\r
211 // registers return 0xFF.\r
212 //\r
213 while ((ReadData == 0xFF) && (ReadCount < READ_RETRY)) {\r
214 //\r
215 // As recommended by Infineon (SLB9645 I2C Communication protocol application\r
216 // note revision 1.0) wait 250 microseconds between a read and a write transfer.\r
217 //\r
218 if (mI2CPrevReadTransfer) {\r
219 MicroSecondDelay (GUARD_TIME);\r
220 }\r
221\r
222 //\r
223 // Write address to TPM.\r
224 //\r
225 Data[0] = (UINT8)TpmAddress;\r
226 Status = I2cWriteByte (\r
227 I2CDeviceAddr,\r
228 I2CAddrMode,\r
229 &Data\r
230 );\r
231\r
232 if (EFI_ERROR(Status)) {\r
233 DEBUG ((EFI_D_INFO, "TpmReadByte(): write to TPM address %0x failed (%r)\n", TpmAddress, Status));\r
234 }\r
235\r
236 mI2CPrevReadTransfer = FALSE;\r
237\r
238 //\r
239 // Read data from TPM.\r
240 //\r
241 Data[0] = (UINT8)TpmAddress;\r
242 Status = I2cReadByte (\r
243 I2CDeviceAddr,\r
244 I2CAddrMode,\r
245 &Data\r
246 );\r
247\r
248 if (EFI_ERROR(Status)) {\r
249 DEBUG ((EFI_D_INFO, "TpmReadByte(): read from TPM address %0x failed (%r)\n", TpmAddress, Status));\r
250 ReadData = 0xFF;\r
251 } else {\r
252 ReadData = Data[0];\r
253 }\r
254\r
255 //\r
256 // Only need to retry 3 times for TPM status, access, and burst count registers.\r
257 // If read transfer is to TPM Data FIFO, do not retry, exit loop.\r
258 //\r
259 if (TpmAddress == INFINEON_TPM_DATA_FIFO_0_ADDRESS_DEFAULT) {\r
260 ReadCount = READ_RETRY;\r
261 } else {\r
262 ReadCount++;\r
263 }\r
264\r
265 mI2CPrevReadTransfer = TRUE;\r
266 }\r
267\r
268 if (EFI_ERROR(Status)) {\r
269 //\r
270 // Only reads to access register allowed to fail.\r
271 //\r
272 if (TpmAddress != INFINEON_TPM_ACCESS_0_ADDRESS_DEFAULT) {\r
273 DEBUG ((EFI_D_ERROR, "TpmReadByte(): read from TPM address %0x failed\n", TpmAddress));\r
274 ASSERT_EFI_ERROR (Status);\r
275 }\r
276 }\r
277 return ReadData;\r
278}\r
279\r
280/**\r
281 Check whether the value of a TPM chip register satisfies the input BIT setting.\r
282\r
283 @param[in] Register TPM register to be checked.\r
284 @param[in] BitSet Check these data bits are set.\r
285 @param[in] BitClear Check these data bits are clear.\r
286 @param[in] TimeOut The max wait time (unit MicroSecond) when checking register.\r
287\r
288 @retval EFI_SUCCESS The register satisfies the check bit.\r
289 @retval EFI_TIMEOUT The register can't run into the expected status in time.\r
290**/\r
291EFI_STATUS\r
292TisPcWaitRegisterBits (\r
293 IN UINTN Register,\r
294 IN UINT8 BitSet,\r
295 IN UINT8 BitClear,\r
296 IN UINT32 TimeOut\r
297 )\r
298{\r
299 UINT8 RegRead;\r
300 UINT32 WaitTime;\r
301\r
302 for (WaitTime = 0; WaitTime < TimeOut; WaitTime += 30){\r
303 RegRead = TpmReadByte (Register);\r
304 if ((RegRead & BitSet) == BitSet && (RegRead & BitClear) == 0)\r
305 return EFI_SUCCESS;\r
306 MicroSecondDelay (30);\r
307 }\r
308 return EFI_TIMEOUT;\r
309}\r
310\r
311/**\r
312 Get BurstCount by reading the burstCount field of a TIS register\r
313 in the time of default TIS_TIMEOUT_D.\r
314\r
315 @param[out] BurstCount Pointer to a buffer to store the got BurstConut.\r
316\r
317 @retval EFI_SUCCESS Get BurstCount.\r
318 @retval EFI_INVALID_PARAMETER BurstCount is NULL.\r
319 @retval EFI_TIMEOUT BurstCount can't be got in time.\r
320**/\r
321EFI_STATUS\r
322TisPcReadBurstCount (\r
323 OUT UINT16 *BurstCount\r
324 )\r
325{\r
326 UINT32 WaitTime;\r
327 UINT8 DataByte0;\r
328 UINT8 DataByte1;\r
329\r
330 if (BurstCount == NULL) {\r
331 return EFI_INVALID_PARAMETER;\r
332 }\r
333\r
334 WaitTime = 0;\r
335 do {\r
336 //\r
337 // BurstCount is UINT16, but it is not 2bytes aligned,\r
338 // so it needs to use TpmReadByte to read two times\r
339 //\r
340 DataByte0 = TpmReadByte (INFINEON_TPM_BURST0_COUNT_0_DEFAULT);\r
341 DataByte1 = TpmReadByte (INFINEON_TPM_BURST1_COUNT_0_DEFAULT);\r
342 *BurstCount = (UINT16)((DataByte1 << 8) + DataByte0);\r
343 if (*BurstCount != 0) {\r
344 return EFI_SUCCESS;\r
345 }\r
346 MicroSecondDelay (30);\r
347 WaitTime += 30;\r
348 } while (WaitTime < TIS_TIMEOUT_D);\r
349\r
350 return EFI_TIMEOUT;\r
351}\r
352\r
353/**\r
354 Set TPM chip to ready state by sending ready command TIS_PC_STS_READY\r
355 to Status Register in time.\r
356\r
357 @retval EFI_SUCCESS TPM chip enters into ready state.\r
358 @retval EFI_TIMEOUT TPM chip can't be set to ready state in time.\r
359**/\r
360EFI_STATUS\r
361TisPcPrepareCommand (\r
362 VOID\r
363 )\r
364{\r
365 EFI_STATUS Status;\r
366\r
367 TpmWriteByte (INFINEON_TPM_STS_0_ADDRESS_DEFAULT, TIS_PC_STS_READY);\r
368 Status = TisPcWaitRegisterBits (\r
369 INFINEON_TPM_STS_0_ADDRESS_DEFAULT,\r
370 TIS_PC_STS_READY,\r
371 0,\r
372 TIS_TIMEOUT_B\r
373 );\r
374 return Status;\r
375}\r
376\r
377/**\r
378 This service requests use TPM12.\r
379\r
380 @retval EFI_SUCCESS Get the control of TPM12 chip.\r
381 @retval EFI_NOT_FOUND TPM12 not found.\r
382 @retval EFI_DEVICE_ERROR Unexpected device behavior.\r
383**/\r
384EFI_STATUS\r
385EFIAPI\r
386Tpm12RequestUseTpm (\r
387 VOID\r
388 )\r
389{\r
390 EFI_STATUS Status;\r
391\r
392 //\r
393 // Check to see if TPM exists\r
394 //\r
395 if (TpmReadByte (INFINEON_TPM_ACCESS_0_ADDRESS_DEFAULT) == 0xFF) {\r
396 return EFI_NOT_FOUND;\r
397 }\r
398\r
399 TpmWriteByte (INFINEON_TPM_ACCESS_0_ADDRESS_DEFAULT, TIS_PC_ACC_RQUUSE);\r
400\r
401 //\r
402 // No locality set before, ACCESS_X.activeLocality MUST be valid within TIMEOUT_A\r
403 //\r
404 Status = TisPcWaitRegisterBits (\r
405 INFINEON_TPM_ACCESS_0_ADDRESS_DEFAULT,\r
406 (UINT8)(TIS_PC_ACC_ACTIVE |TIS_PC_VALID),\r
407 0,\r
408 TIS_TIMEOUT_A\r
409 );\r
410 return Status;\r
411}\r
412\r
413/**\r
414 Send command to TPM for execution.\r
415\r
416 @param[in] TpmBuffer Buffer for TPM command data.\r
417 @param[in] DataLength TPM command data length.\r
418\r
419 @retval EFI_SUCCESS Operation completed successfully.\r
420 @retval EFI_TIMEOUT The register can't run into the expected status in time.\r
421\r
422**/\r
423EFI_STATUS\r
424TisPcSend (\r
425 IN UINT8 *TpmBuffer,\r
426 IN UINT32 DataLength\r
427 )\r
428{\r
429 UINT16 BurstCount;\r
430 UINT32 Index;\r
431 EFI_STATUS Status;\r
432\r
433 Status = TisPcPrepareCommand ();\r
434 if (EFI_ERROR (Status)){\r
435 DEBUG ((DEBUG_ERROR, "The TPM is not ready!\n"));\r
436 goto Done;\r
437 }\r
438 Index = 0;\r
439 while (Index < DataLength) {\r
440 Status = TisPcReadBurstCount (&BurstCount);\r
441 if (EFI_ERROR (Status)) {\r
442 Status = EFI_TIMEOUT;\r
443 goto Done;\r
444 }\r
445 for (; BurstCount > 0 && Index < DataLength; BurstCount--) {\r
446 TpmWriteByte (INFINEON_TPM_DATA_FIFO_0_ADDRESS_DEFAULT, *(TpmBuffer + Index));\r
447 Index++;\r
448 }\r
449 }\r
450 //\r
451 // Ensure the TPM status STS_EXPECT change from 1 to 0\r
452 //\r
453 Status = TisPcWaitRegisterBits (\r
454 INFINEON_TPM_STS_0_ADDRESS_DEFAULT,\r
455 (UINT8) TIS_PC_VALID,\r
456 TIS_PC_STS_EXPECT,\r
457 TIS_TIMEOUT_C\r
458 );\r
459 if (EFI_ERROR (Status)) {\r
460 goto Done;\r
461 }\r
462\r
463 //\r
464 // Start the command\r
465 //\r
466 TpmWriteByte (INFINEON_TPM_STS_0_ADDRESS_DEFAULT, TIS_PC_STS_GO);\r
467\r
468Done:\r
469 if (EFI_ERROR (Status)) {\r
470 //\r
471 // Ensure the TPM state change from "Reception" to "Idle/Ready"\r
472 //\r
473 TpmWriteByte (INFINEON_TPM_STS_0_ADDRESS_DEFAULT, TIS_PC_STS_READY);\r
474 }\r
475\r
476 return Status;\r
477}\r
478\r
479/**\r
480 Receive response data of last command from TPM.\r
481\r
482 @param[out] TpmBuffer Buffer for response data.\r
483 @param[out] RespSize Response data length.\r
484\r
485 @retval EFI_SUCCESS Operation completed successfully.\r
486 @retval EFI_TIMEOUT The register can't run into the expected status in time.\r
487 @retval EFI_DEVICE_ERROR Unexpected device status.\r
488 @retval EFI_BUFFER_TOO_SMALL Response data is too long.\r
489\r
490**/\r
491EFI_STATUS\r
492TisPcReceive (\r
493 OUT UINT8 *TpmBuffer,\r
494 OUT UINT32 *RespSize\r
495 )\r
496{\r
497 EFI_STATUS Status;\r
498 UINT16 BurstCount;\r
499 UINT32 Index;\r
500 UINT32 ResponseSize;\r
501 TPM_RSP_COMMAND_HDR *ResponseHeader;\r
502\r
503 //\r
504 // Wait for the command completion\r
505 //\r
506 Status = TisPcWaitRegisterBits (\r
507 INFINEON_TPM_STS_0_ADDRESS_DEFAULT,\r
508 (UINT8) (TIS_PC_VALID | TIS_PC_STS_DATA),\r
509 0,\r
510 TIS_TIMEOUT_B\r
511 );\r
512 if (EFI_ERROR (Status)) {\r
513 Status = EFI_TIMEOUT;\r
514 goto Done;\r
515 }\r
516 //\r
517 // Read the response data header and check it\r
518 //\r
519 Index = 0;\r
520 BurstCount = 0;\r
521 while (Index < sizeof (TPM_RSP_COMMAND_HDR)) {\r
522 Status = TisPcReadBurstCount (&BurstCount);\r
523 if (EFI_ERROR (Status)) {\r
524 Status = EFI_TIMEOUT;\r
525 goto Done;\r
526 }\r
527 for (; BurstCount > 0 ; BurstCount--) {\r
528 *(TpmBuffer + Index) = TpmReadByte (INFINEON_TPM_DATA_FIFO_0_ADDRESS_DEFAULT);\r
529 Index++;\r
530 if (Index == sizeof (TPM_RSP_COMMAND_HDR))\r
531 break;\r
532 }\r
533 }\r
534\r
535 //\r
536 // Check the response data header (tag, parasize and returncode)\r
537 //\r
538 ResponseHeader = (TPM_RSP_COMMAND_HDR *)TpmBuffer;\r
539 if (SwapBytes16 (ReadUnaligned16 (&ResponseHeader->tag)) != TPM_TAG_RSP_COMMAND) {\r
540 Status = EFI_DEVICE_ERROR;\r
541 goto Done;\r
542 }\r
543\r
544 ResponseSize = SwapBytes32 (ReadUnaligned32 (&ResponseHeader->paramSize));\r
545 if (ResponseSize == sizeof (TPM_RSP_COMMAND_HDR)) {\r
546 Status = EFI_SUCCESS;\r
547 goto Done;\r
548 }\r
549 if (ResponseSize < sizeof (TPM_RSP_COMMAND_HDR)) {\r
550 Status = EFI_DEVICE_ERROR;\r
551 goto Done;\r
552 }\r
553 if (*RespSize < ResponseSize) {\r
554 Status = EFI_BUFFER_TOO_SMALL;\r
555 goto Done;\r
556 }\r
557 *RespSize = ResponseSize;\r
558\r
559 //\r
560 // Continue reading the remaining data\r
561 //\r
562 while (Index < ResponseSize) {\r
563 for (; BurstCount > 0 ; BurstCount--) {\r
564 *(TpmBuffer + Index) = TpmReadByte (INFINEON_TPM_DATA_FIFO_0_ADDRESS_DEFAULT);\r
565 Index++;\r
566 if (Index == ResponseSize) {\r
567 Status = EFI_SUCCESS;\r
568 goto Done;\r
569 }\r
570 }\r
571 Status = TisPcReadBurstCount (&BurstCount);\r
572 if (EFI_ERROR (Status) && (Index < ResponseSize)) {\r
573 Status = EFI_DEVICE_ERROR;\r
574 goto Done;\r
575 }\r
576 }\r
577\r
578Done:\r
579 //\r
580 // Ensure the TPM state change from "Execution" or "Completion" to "Idle/Ready"\r
581 //\r
582 TpmWriteByte (INFINEON_TPM_STS_0_ADDRESS_DEFAULT, TIS_PC_STS_READY);\r
583\r
584 return Status;\r
585}\r
586\r
587/**\r
588 This service enables the sending of commands to the TPM12.\r
589\r
590 @param[in] InputParameterBlockSize Size of the TPM12 input parameter block.\r
591 @param[in] InputParameterBlock Pointer to the TPM12 input parameter block.\r
592 @param[in,out] OutputParameterBlockSize Size of the TPM12 output parameter block.\r
593 @param[in] OutputParameterBlock Pointer to the TPM12 output parameter block.\r
594\r
595 @retval EFI_SUCCESS The command byte stream was successfully sent to\r
596 the device and a response was successfully received.\r
597 @retval EFI_DEVICE_ERROR The command was not successfully sent to the\r
598 device or a response was not successfully received\r
599 from the device.\r
600 @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small.\r
601**/\r
602EFI_STATUS\r
603EFIAPI\r
604Tpm12SubmitCommand (\r
605 IN UINT32 InputParameterBlockSize,\r
606 IN UINT8 *InputParameterBlock,\r
607 IN OUT UINT32 *OutputParameterBlockSize,\r
608 IN UINT8 *OutputParameterBlock\r
609 )\r
610{\r
611 EFI_STATUS Status;\r
612\r
613 Status = TisPcSend (InputParameterBlock, InputParameterBlockSize);\r
614 if (!EFI_ERROR (Status)) {\r
615 Status = TisPcReceive (OutputParameterBlock, OutputParameterBlockSize);\r
616 }\r
617 return Status;\r
618}\r