Add a lock to protect the critical region in Service APIs for gEfiBlockIoProtocolGuid...
[mirror_edk2.git] / EdkModulePkg / Bus / Usb / UsbMassStorage / Dxe / UsbMassStorage.c
1 /*++
2
3 Copyright (c) 2006 - 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 UsbMassStorage.c
15
16 Abstract:
17
18 USB Mass Storage Driver
19
20 Revision History
21
22 --*/
23
24 #include "UsbMassStorage.h"
25 #include "UsbMassStorageHelper.h"
26
27 //
28 // Block I/O Protocol Interface
29 //
30 STATIC
31 EFI_STATUS
32 EFIAPI
33 USBFloppyReset (
34 IN EFI_BLOCK_IO_PROTOCOL *This,
35 IN BOOLEAN ExtendedVerification
36 );
37
38 STATIC
39 EFI_STATUS
40 EFIAPI
41 USBFloppyReadBlocks (
42 IN EFI_BLOCK_IO_PROTOCOL *This,
43 IN UINT32 MediaId,
44 IN EFI_LBA LBA,
45 IN UINTN BufferSize,
46 OUT VOID *Buffer
47 );
48
49 STATIC
50 EFI_STATUS
51 EFIAPI
52 USBFloppyWriteBlocks (
53 IN EFI_BLOCK_IO_PROTOCOL *This,
54 IN UINT32 MediaId,
55 IN EFI_LBA LBA,
56 IN UINTN BufferSize,
57 IN VOID *Buffer
58 );
59
60 STATIC
61 EFI_STATUS
62 EFIAPI
63 USBFloppyFlushBlocks (
64 IN EFI_BLOCK_IO_PROTOCOL *This
65 );
66
67 //
68 // USB Floppy Driver Global Variables
69 //
70 EFI_DRIVER_BINDING_PROTOCOL gUSBFloppyDriverBinding = {
71 USBFloppyDriverBindingSupported,
72 USBFloppyDriverBindingStart,
73 USBFloppyDriverBindingStop,
74 0xa,
75 NULL,
76 NULL
77 };
78
79 EFI_STATUS
80 EFIAPI
81 USBFloppyDriverBindingSupported (
82 IN EFI_DRIVER_BINDING_PROTOCOL *This,
83 IN EFI_HANDLE Controller,
84 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
85 )
86 /*++
87
88 Routine Description:
89 Test to see if this driver supports ControllerHandle. Any ControllerHandle
90 that has UsbHcProtocol installed will be supported.
91
92 Arguments:
93 This - Protocol instance pointer.
94 Controller - Handle of device to test
95 RemainingDevicePath - Not used
96
97 Returns:
98 EFI_SUCCESS - This driver supports this device.
99 EFI_UNSUPPORTED - This driver does not support this device.
100
101 --*/
102 {
103 EFI_STATUS OpenStatus;
104 EFI_USB_ATAPI_PROTOCOL *AtapiProtocol;
105
106 //
107 // check whether EFI_USB_ATAPI_PROTOCOL exists, if it does,
108 // then the controller must be a USB Mass Storage Controller
109 //
110 OpenStatus = gBS->OpenProtocol (
111 Controller,
112 &gEfiUsbAtapiProtocolGuid,
113 (VOID **) &AtapiProtocol,
114 This->DriverBindingHandle,
115 Controller,
116 EFI_OPEN_PROTOCOL_BY_DRIVER
117 );
118 if (EFI_ERROR (OpenStatus)) {
119 return OpenStatus;
120 }
121
122 gBS->CloseProtocol (
123 Controller,
124 &gEfiUsbAtapiProtocolGuid,
125 This->DriverBindingHandle,
126 Controller
127 );
128
129 return EFI_SUCCESS;
130 }
131
132 EFI_STATUS
133 EFIAPI
134 USBFloppyDriverBindingStart (
135 IN EFI_DRIVER_BINDING_PROTOCOL *This,
136 IN EFI_HANDLE Controller,
137 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
138 )
139 /*++
140
141 Routine Description:
142 Starting the Usb Bus Driver
143
144 Arguments:
145 This - Protocol instance pointer.
146 Controller - Handle of device to test
147 RemainingDevicePath - Not used
148
149 Returns:
150 EFI_SUCCESS - This driver supports this device.
151 EFI_UNSUPPORTED - This driver does not support this device.
152 EFI_DEVICE_ERROR - This driver cannot be started due to device
153 Error
154 EFI_OUT_OF_RESOURCES- Can't allocate memory resources
155 EFI_ALREADY_STARTED - Thios driver has been started
156 --*/
157 {
158 EFI_STATUS Status;
159 EFI_USB_ATAPI_PROTOCOL *AtapiProtocol;
160 USB_FLOPPY_DEV *UsbFloppyDevice;
161
162 UsbFloppyDevice = NULL;
163 //
164 // Check whether Usb Atapi Protocol attached on the controller handle.
165 //
166 Status = gBS->OpenProtocol (
167 Controller,
168 &gEfiUsbAtapiProtocolGuid,
169 (VOID **) &AtapiProtocol,
170 This->DriverBindingHandle,
171 Controller,
172 EFI_OPEN_PROTOCOL_BY_DRIVER
173 );
174 if (EFI_ERROR (Status)) {
175 return Status;
176 }
177
178 Status = gBS->AllocatePool (
179 EfiBootServicesData,
180 sizeof (USB_FLOPPY_DEV),
181 (VOID **) &UsbFloppyDevice
182 );
183 if (EFI_ERROR (Status)) {
184 gBS->CloseProtocol (
185 Controller,
186 &gEfiUsbAtapiProtocolGuid,
187 This->DriverBindingHandle,
188 Controller
189 );
190 return Status;
191 }
192
193 ZeroMem (UsbFloppyDevice, sizeof (USB_FLOPPY_DEV));
194
195 UsbFloppyDevice->Handle = Controller;
196 UsbFloppyDevice->BlkIo.Media = &UsbFloppyDevice->BlkMedia;
197 UsbFloppyDevice->Signature = USB_FLOPPY_DEV_SIGNATURE;
198 UsbFloppyDevice->BlkIo.Reset = USBFloppyReset;
199 UsbFloppyDevice->BlkIo.ReadBlocks = USBFloppyReadBlocks;
200 UsbFloppyDevice->BlkIo.WriteBlocks = USBFloppyWriteBlocks;
201 UsbFloppyDevice->BlkIo.FlushBlocks = USBFloppyFlushBlocks;
202 UsbFloppyDevice->AtapiProtocol = AtapiProtocol;
203
204 //
205 // Identify drive type and retrieve media information.
206 //
207 Status = USBFloppyIdentify (UsbFloppyDevice);
208 if (EFI_ERROR (Status)) {
209 if (UsbFloppyDevice->SenseData != NULL) {
210 gBS->FreePool (UsbFloppyDevice->SenseData);
211 }
212
213 gBS->FreePool (UsbFloppyDevice);
214 gBS->CloseProtocol (
215 Controller,
216 &gEfiUsbAtapiProtocolGuid,
217 This->DriverBindingHandle,
218 Controller
219 );
220 return Status;
221 }
222 //
223 // Install Block I/O protocol for the usb floppy device.
224 //
225 Status = gBS->InstallProtocolInterface (
226 &Controller,
227 &gEfiBlockIoProtocolGuid,
228 EFI_NATIVE_INTERFACE,
229 &UsbFloppyDevice->BlkIo
230 );
231 if (EFI_ERROR (Status)) {
232 if (UsbFloppyDevice->SenseData != NULL) {
233 gBS->FreePool (UsbFloppyDevice->SenseData);
234 }
235
236 gBS->FreePool (UsbFloppyDevice);
237 gBS->CloseProtocol (
238 Controller,
239 &gEfiUsbAtapiProtocolGuid,
240 This->DriverBindingHandle,
241 Controller
242 );
243 return Status;
244 }
245
246 return EFI_SUCCESS;
247
248 }
249
250
251 EFI_STATUS
252 EFIAPI
253 USBFloppyDriverBindingStop (
254 IN EFI_DRIVER_BINDING_PROTOCOL *This,
255 IN EFI_HANDLE Controller,
256 IN UINTN NumberOfChildren,
257 IN EFI_HANDLE *ChildHandleBuffer
258 )
259 /*++
260
261 Routine Description:
262 Stop this driver on ControllerHandle. Support stoping any child handles
263 created by this driver.
264
265 Arguments:
266 This - Protocol instance pointer.
267 Controller - Handle of device to stop driver on
268 NumberOfChildren - Number of Children in the ChildHandleBuffer
269 ChildHandleBuffer - List of handles for the children we need to stop.
270
271 Returns:
272 EFI_SUCCESS
273 EFI_DEVICE_ERROR
274 others
275
276 --*/
277 {
278 EFI_STATUS Status;
279 USB_FLOPPY_DEV *UsbFloppyDevice;
280 EFI_BLOCK_IO_PROTOCOL *BlkIo;
281
282 //
283 // First find USB_FLOPPY_DEV
284 //
285 gBS->OpenProtocol (
286 Controller,
287 &gEfiBlockIoProtocolGuid,
288 (VOID **) &BlkIo,
289 This->DriverBindingHandle,
290 Controller,
291 EFI_OPEN_PROTOCOL_GET_PROTOCOL
292 );
293
294 UsbFloppyDevice = USB_FLOPPY_DEV_FROM_THIS (BlkIo);
295
296 //
297 // Uninstall Block I/O protocol from the device handle
298 //
299 Status = gBS->UninstallProtocolInterface (
300 Controller,
301 &gEfiBlockIoProtocolGuid,
302 &UsbFloppyDevice->BlkIo
303 );
304 if (EFI_ERROR (Status)) {
305 return Status;
306 }
307 //
308 // Stop using EFI_USB_ATAPI_PROTOCOL
309 //
310 gBS->CloseProtocol (
311 Controller,
312 &gEfiUsbAtapiProtocolGuid,
313 This->DriverBindingHandle,
314 Controller
315 );
316
317 if (UsbFloppyDevice->SenseData != NULL) {
318 gBS->FreePool (UsbFloppyDevice->SenseData);
319 }
320
321 gBS->FreePool (UsbFloppyDevice);
322
323 return EFI_SUCCESS;
324 }
325
326
327 STATIC
328 EFI_STATUS
329 EFIAPI
330 USBFloppyReset (
331 IN EFI_BLOCK_IO_PROTOCOL *This,
332 IN BOOLEAN ExtendedVerification
333 )
334 /*++
335
336 Routine Description:
337 Implements EFI_BLOCK_IO_PROTOCOL.Reset() function.
338
339 Arguments:
340 This The EFI_BLOCK_IO_PROTOCOL instance.
341 ExtendedVerification
342 Indicates that the driver may perform a more exhaustive
343 verification operation of the device during reset.
344 (This parameter is ingored in this driver.)
345
346 Returns:
347 EFI_SUCCESS - Success
348 --*/
349 {
350 USB_FLOPPY_DEV *UsbFloppyDevice;
351 EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface;
352 EFI_STATUS Status;
353 EFI_TPL OldTpl;
354
355 OldTpl = gBS->RaiseTPL (EFI_TPL_CALLBACK);
356
357 UsbFloppyDevice = USB_FLOPPY_DEV_FROM_THIS (This);
358
359 UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol;
360
361 //
362 // directly calling EFI_USB_ATAPI_PROTOCOL.Reset() to implement reset.
363 //
364 Status = UsbAtapiInterface->UsbAtapiReset (UsbAtapiInterface, ExtendedVerification);
365
366 gBS->RestoreTPL (OldTpl);
367
368 return Status;
369 }
370
371 STATIC
372 EFI_STATUS
373 EFIAPI
374 USBFloppyReadBlocks (
375 IN EFI_BLOCK_IO_PROTOCOL *This,
376 IN UINT32 MediaId,
377 IN EFI_LBA LBA,
378 IN UINTN BufferSize,
379 OUT VOID *Buffer
380 )
381 /*++
382
383 Routine Description:
384 Implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks() function.
385
386 Arguments:
387 This The EFI_BLOCK_IO_PROTOCOL instance.
388 MediaId The media id that the read request is for.
389 LBA The starting logical block address to read from on the device.
390 BufferSize
391 The size of the Buffer in bytes. This must be a multiple of
392 the intrinsic block size of the device.
393 Buffer A pointer to the destination buffer for the data. The caller
394 is responsible for either having implicit or explicit ownership
395 of the buffer.
396
397 Returns:
398 EFI_INVALID_PARAMETER - Parameter is error
399 EFI_SUCCESS - Success
400 EFI_DEVICE_ERROR - Hardware Error
401 EFI_NO_MEDIA - No media
402 EFI_MEDIA_CHANGED - Media Change
403 EFI_BAD_BUFFER_SIZE - Buffer size is bad
404 --*/
405 {
406 USB_FLOPPY_DEV *UsbFloppyDevice;
407 EFI_STATUS Status;
408 EFI_BLOCK_IO_MEDIA *Media;
409 UINTN BlockSize;
410 UINTN NumberOfBlocks;
411 BOOLEAN MediaChange;
412 EFI_TPL OldTpl;
413
414 Status = EFI_SUCCESS;
415 MediaChange = FALSE;
416 UsbFloppyDevice = USB_FLOPPY_DEV_FROM_THIS (This);
417
418 //
419 // Check parameters
420 //
421 if (Buffer == NULL) {
422 return EFI_INVALID_PARAMETER;
423 }
424
425 if (BufferSize == 0) {
426 return EFI_SUCCESS;
427 }
428
429 OldTpl = gBS->RaiseTPL (EFI_TPL_CALLBACK);
430
431 UsbFloppyTestUnitReady (UsbFloppyDevice);
432
433 Status = UsbFloppyDetectMedia (UsbFloppyDevice, &MediaChange);
434 if (EFI_ERROR (Status)) {
435
436 Status = EFI_DEVICE_ERROR;
437 goto Done;
438 }
439
440 if (MediaChange) {
441 gBS->ReinstallProtocolInterface (
442 UsbFloppyDevice->Handle,
443 &gEfiBlockIoProtocolGuid,
444 &UsbFloppyDevice->BlkIo,
445 &UsbFloppyDevice->BlkIo
446 );
447 }
448
449 Media = UsbFloppyDevice->BlkIo.Media;
450 BlockSize = Media->BlockSize;
451 NumberOfBlocks = BufferSize / BlockSize;
452
453 if (!(Media->MediaPresent)) {
454 Status = EFI_NO_MEDIA;
455 goto Done;
456 }
457
458 if (MediaId != Media->MediaId) {
459 Status = EFI_MEDIA_CHANGED;
460 goto Done;
461 }
462
463 if (BufferSize % BlockSize != 0) {
464 Status = EFI_BAD_BUFFER_SIZE;
465 goto Done;
466 }
467
468 if (LBA > Media->LastBlock) {
469 Status = EFI_INVALID_PARAMETER;
470 goto Done;
471 }
472
473 if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) {
474 Status = EFI_INVALID_PARAMETER;
475 goto Done;
476 }
477
478 if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {
479 Status = EFI_INVALID_PARAMETER;
480 goto Done;
481 }
482
483 while (NumberOfBlocks > 0) {
484
485 if (NumberOfBlocks > BLOCK_UNIT) {
486 Status = USBFloppyRead10 (UsbFloppyDevice, Buffer, LBA, BLOCK_UNIT);
487 } else {
488 Status = USBFloppyRead10 (UsbFloppyDevice, Buffer, LBA, NumberOfBlocks);
489 }
490
491 if (EFI_ERROR (Status)) {
492 This->Reset (This, TRUE);
493 Status = EFI_DEVICE_ERROR;
494 goto Done;
495 }
496
497 if (NumberOfBlocks > BLOCK_UNIT) {
498 NumberOfBlocks -= BLOCK_UNIT;
499 LBA += BLOCK_UNIT;
500 Buffer = (UINT8 *) Buffer + This->Media->BlockSize * BLOCK_UNIT;
501 } else {
502 NumberOfBlocks -= NumberOfBlocks;
503 LBA += NumberOfBlocks;
504 Buffer = (UINT8 *) Buffer + This->Media->BlockSize * NumberOfBlocks;
505 }
506 }
507
508 Done:
509 gBS->RestoreTPL (OldTpl);
510 return Status;
511 }
512
513 STATIC
514 EFI_STATUS
515 EFIAPI
516 USBFloppyWriteBlocks (
517 IN EFI_BLOCK_IO_PROTOCOL *This,
518 IN UINT32 MediaId,
519 IN EFI_LBA LBA,
520 IN UINTN BufferSize,
521 IN VOID *Buffer
522 )
523 /*++
524
525 Routine Description:
526 Implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks() function.
527
528 Arguments:
529 This The EFI_BLOCK_IO_PROTOCOL instance.
530 MediaId The media id that the write request is for.
531 LBA The starting logical block address to be written.
532 The caller is responsible for writing to only
533 legitimate locations.
534 BufferSize
535 The size of the Buffer in bytes. This must be a multiple of
536 the intrinsic block size of the device.
537 Buffer A pointer to the source buffer for the data. The caller
538 is responsible for either having implicit or explicit ownership
539 of the buffer.
540
541 Returns:
542 EFI_INVALID_PARAMETER - Parameter is error
543 EFI_SUCCESS - Success
544 EFI_DEVICE_ERROR - Hardware Error
545 EFI_NO_MEDIA - No media
546 EFI_MEDIA_CHANGED - Media Change
547 EFI_BAD_BUFFER_SIZE - Buffer size is bad
548
549 --*/
550 {
551 USB_FLOPPY_DEV *UsbFloppyDevice;
552 EFI_STATUS Status;
553 EFI_BLOCK_IO_MEDIA *Media;
554 UINTN BlockSize;
555 UINTN NumberOfBlocks;
556 BOOLEAN MediaChange;
557 EFI_TPL OldTpl;
558
559 Status = EFI_SUCCESS;
560 MediaChange = FALSE;
561
562 UsbFloppyDevice = USB_FLOPPY_DEV_FROM_THIS (This);
563
564 //
565 // Check parameters
566 //
567 if (Buffer == NULL) {
568 return EFI_INVALID_PARAMETER;
569 }
570
571 if (BufferSize == 0) {
572 return EFI_SUCCESS;
573 }
574
575 OldTpl = gBS->RaiseTPL (EFI_TPL_CALLBACK);
576
577 UsbFloppyTestUnitReady (UsbFloppyDevice);
578
579 Status = UsbFloppyDetectMedia (UsbFloppyDevice, &MediaChange);
580 if (EFI_ERROR (Status)) {
581
582 Status = EFI_DEVICE_ERROR;
583 goto Done;
584 }
585
586 if (MediaChange) {
587 gBS->ReinstallProtocolInterface (
588 UsbFloppyDevice->Handle,
589 &gEfiBlockIoProtocolGuid,
590 &UsbFloppyDevice->BlkIo,
591 &UsbFloppyDevice->BlkIo
592 );
593 }
594
595 Media = UsbFloppyDevice->BlkIo.Media;
596 BlockSize = Media->BlockSize;
597 NumberOfBlocks = BufferSize / BlockSize;
598
599 if (!(Media->MediaPresent)) {
600 Status = EFI_NO_MEDIA;
601 goto Done;
602 }
603
604 if (MediaId != Media->MediaId) {
605 Status = EFI_MEDIA_CHANGED;
606 goto Done;
607 }
608
609 if (BufferSize % BlockSize != 0) {
610 Status = EFI_BAD_BUFFER_SIZE;
611 goto Done;
612 }
613
614 if (LBA > Media->LastBlock) {
615 Status = EFI_INVALID_PARAMETER;
616 goto Done;
617 }
618
619 if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) {
620 Status = EFI_INVALID_PARAMETER;
621 goto Done;
622 }
623
624 if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {
625 Status = EFI_INVALID_PARAMETER;
626 goto Done;
627 }
628
629 if (UsbFloppyDevice->BlkMedia.ReadOnly) {
630 Status = EFI_WRITE_PROTECTED;
631 goto Done;
632 }
633
634 while (NumberOfBlocks > 0) {
635
636 if (NumberOfBlocks > BLOCK_UNIT) {
637 Status = USBFloppyWrite10 (UsbFloppyDevice, Buffer, LBA, BLOCK_UNIT);
638 } else {
639 Status = USBFloppyWrite10 (UsbFloppyDevice, Buffer, LBA, NumberOfBlocks);
640 }
641
642 if (EFI_ERROR (Status)) {
643 This->Reset (This, TRUE);
644 Status = EFI_DEVICE_ERROR;
645 goto Done;
646 }
647
648 if (NumberOfBlocks > BLOCK_UNIT) {
649 NumberOfBlocks -= BLOCK_UNIT;
650 LBA += BLOCK_UNIT;
651 Buffer = (UINT8 *) Buffer + This->Media->BlockSize * BLOCK_UNIT;
652 } else {
653 NumberOfBlocks -= NumberOfBlocks;
654 LBA += NumberOfBlocks;
655 Buffer = (UINT8 *) Buffer + This->Media->BlockSize * NumberOfBlocks;
656 }
657 }
658
659 Done:
660 gBS->RestoreTPL (OldTpl);
661 return Status;
662 }
663
664 STATIC
665 EFI_STATUS
666 EFIAPI
667 USBFloppyFlushBlocks (
668 IN EFI_BLOCK_IO_PROTOCOL *This
669 )
670 /*++
671
672 Routine Description:
673 Implements EFI_BLOCK_IO_PROTOCOL.FlushBlocks() function.
674 (In this driver, this function just returns EFI_SUCCESS.)
675
676 Arguments:
677 This The EFI_BLOCK_IO_PROTOCOL instance.
678
679 Returns:
680 EFI_SUCCESS - Success
681 --*/
682 {
683 return EFI_SUCCESS;
684 }