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 } 402