Fix component name bugs when input Controller Name is invalid
[people/mcb30/edk2.git] / edk2 / EdkUnixPkg / Dxe / UnixThunk / Bus / BlockIo / UnixBlockIo.c
1 /*++\r
2 \r
3 Copyright (c) 2004 - 2005, Intel Corporation                                                         \r
4 All rights reserved. This program and the accompanying materials                          \r
5 are licensed and made available under the terms and conditions of the BSD License         \r
6 which accompanies this distribution.  The full text of the license may be found at        \r
7 http://opensource.org/licenses/bsd-license.php                                            \r
8                                                                                           \r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
11 \r
12 Module Name:\r
13 \r
14   UnixBlockIo.c\r
15 \r
16 Abstract:\r
17 \r
18   Produce block IO abstractions for real devices on your PC using Posix APIs.\r
19   The configuration of what devices to mount or emulate comes from UNIX \r
20   environment variables. The variables must be visible to the Microsoft* \r
21   Developer Studio for them to work.\r
22 \r
23   <F>ixed       - Fixed disk like a hard drive.\r
24   <R>emovable   - Removable media like a floppy or CD-ROM.\r
25   Read <O>nly   - Write protected device.\r
26   Read <W>rite  - Read write device.\r
27   <block count> - Decimal number of blocks a device supports.\r
28   <block size>  - Decimal number of bytes per block.\r
29 \r
30   UNIX envirnonment variable contents. '<' and '>' are not part of the variable, \r
31   they are just used to make this help more readable. There should be no \r
32   spaces between the ';'. Extra spaces will break the variable. A '!' is \r
33   used to seperate multiple devices in a variable.\r
34 \r
35   EFI_UNIX_VIRTUAL_DISKS = \r
36     <F | R><O | W>;<block count>;<block size>[!...]\r
37 \r
38   EFI_UNIX_PHYSICAL_DISKS =\r
39     <drive letter>:<F | R><O | W>;<block count>;<block size>[!...]\r
40 \r
41   Virtual Disks: These devices use a file to emulate a hard disk or removable\r
42                  media device. \r
43                  \r
44     Thus a 20 MB emulated hard drive would look like:\r
45     EFI_UNIX_VIRTUAL_DISKS=FW;40960;512\r
46 \r
47     A 1.44MB emulated floppy with a block size of 1024 would look like:\r
48     EFI_UNIX_VIRTUAL_DISKS=RW;1440;1024\r
49 \r
50   Physical Disks: These devices use UNIX to open a real device in your system\r
51 \r
52     Thus a 120 MB floppy would look like:\r
53     EFI_UNIX_PHYSICAL_DISKS=B:RW;245760;512\r
54 \r
55     Thus a standard CD-ROM floppy would look like:\r
56     EFI_UNIX_PHYSICAL_DISKS=Z:RO;307200;2048\r
57 \r
58 \r
59   * Other names and brands may be claimed as the property of others.\r
60 \r
61 --*/\r
62 \r
63 #include <fcntl.h>\r
64 #include <unistd.h>\r
65 #include "UnixBlockIo.h"\r
66 \r
67 //\r
68 // Block IO protocol member functions\r
69 //\r
70 STATIC\r
71 EFI_STATUS\r
72 EFIAPI\r
73 UnixBlockIoReadBlocks (\r
74   IN EFI_BLOCK_IO_PROTOCOL  *This,\r
75   IN UINT32                 MediaId,\r
76   IN EFI_LBA                Lba,\r
77   IN UINTN                  BufferSize,\r
78   OUT VOID                  *Buffer\r
79   )\r
80 /*++\r
81 \r
82 Routine Description:\r
83 \r
84   TODO: Add function description\r
85 \r
86 Arguments:\r
87 \r
88   This        - TODO: add argument description\r
89   MediaId     - TODO: add argument description\r
90   Lba         - TODO: add argument description\r
91   BufferSize  - TODO: add argument description\r
92   Buffer      - TODO: add argument description\r
93 \r
94 Returns:\r
95 \r
96   TODO: add return values\r
97 \r
98 --*/\r
99 ;\r
100 \r
101 STATIC\r
102 EFI_STATUS\r
103 EFIAPI\r
104 UnixBlockIoWriteBlocks (\r
105   IN EFI_BLOCK_IO_PROTOCOL  *This,\r
106   IN UINT32                 MediaId,\r
107   IN EFI_LBA                Lba,\r
108   IN UINTN                  BufferSize,\r
109   IN VOID                   *Buffer\r
110   )\r
111 /*++\r
112 \r
113 Routine Description:\r
114 \r
115   TODO: Add function description\r
116 \r
117 Arguments:\r
118 \r
119   This        - TODO: add argument description\r
120   MediaId     - TODO: add argument description\r
121   Lba         - TODO: add argument description\r
122   BufferSize  - TODO: add argument description\r
123   Buffer      - TODO: add argument description\r
124 \r
125 Returns:\r
126 \r
127   TODO: add return values\r
128 \r
129 --*/\r
130 ;\r
131 \r
132 STATIC\r
133 EFI_STATUS\r
134 EFIAPI\r
135 UnixBlockIoFlushBlocks (\r
136   IN EFI_BLOCK_IO_PROTOCOL  *This\r
137   )\r
138 /*++\r
139 \r
140 Routine Description:\r
141 \r
142   TODO: Add function description\r
143 \r
144 Arguments:\r
145 \r
146   This  - TODO: add argument description\r
147 \r
148 Returns:\r
149 \r
150   TODO: add return values\r
151 \r
152 --*/\r
153 ;\r
154 \r
155 STATIC\r
156 EFI_STATUS\r
157 EFIAPI\r
158 UnixBlockIoResetBlock (\r
159   IN EFI_BLOCK_IO_PROTOCOL  *This,\r
160   IN BOOLEAN                ExtendedVerification\r
161   )\r
162 /*++\r
163 \r
164 Routine Description:\r
165 \r
166   TODO: Add function description\r
167 \r
168 Arguments:\r
169 \r
170   This                  - TODO: add argument description\r
171   ExtendedVerification  - TODO: add argument description\r
172 \r
173 Returns:\r
174 \r
175   TODO: add return values\r
176 \r
177 --*/\r
178 ;\r
179 \r
180 //\r
181 // Private Worker functions\r
182 //\r
183 STATIC\r
184 EFI_STATUS\r
185 UnixBlockIoCreateMapping (\r
186   IN EFI_UNIX_IO_PROTOCOL             *UnixIo,\r
187   IN EFI_HANDLE                         EfiDeviceHandle,\r
188   IN CHAR16                             *Filename,\r
189   IN BOOLEAN                            ReadOnly,\r
190   IN BOOLEAN                            RemovableMedia,\r
191   IN UINTN                              NumberOfBlocks,\r
192   IN UINTN                              BlockSize\r
193   )\r
194 /*++\r
195 \r
196 Routine Description:\r
197 \r
198   TODO: Add function description\r
199 \r
200 Arguments:\r
201 \r
202   UnixIo         - TODO: add argument description\r
203   EfiDeviceHandle - TODO: add argument description\r
204   Filename        - TODO: add argument description\r
205   ReadOnly        - TODO: add argument description\r
206   RemovableMedia  - TODO: add argument description\r
207   NumberOfBlocks  - TODO: add argument description\r
208   BlockSize       - TODO: add argument description\r
209   DeviceType      - TODO: add argument description\r
210 \r
211 Returns:\r
212 \r
213   TODO: add return values\r
214 \r
215 --*/\r
216 ;\r
217 \r
218 STATIC\r
219 EFI_STATUS\r
220 UnixBlockIoReadWriteCommon (\r
221   IN  UNIX_BLOCK_IO_PRIVATE *Private,\r
222   IN UINT32                   MediaId,\r
223   IN EFI_LBA                  Lba,\r
224   IN UINTN                    BufferSize,\r
225   IN VOID                     *Buffer,\r
226   IN CHAR8                    *CallerName\r
227   )\r
228 /*++\r
229 \r
230 Routine Description:\r
231 \r
232   TODO: Add function description\r
233 \r
234 Arguments:\r
235 \r
236   Private     - TODO: add argument description\r
237   MediaId     - TODO: add argument description\r
238   Lba         - TODO: add argument description\r
239   BufferSize  - TODO: add argument description\r
240   Buffer      - TODO: add argument description\r
241   CallerName  - TODO: add argument description\r
242 \r
243 Returns:\r
244 \r
245   TODO: add return values\r
246 \r
247 --*/\r
248 ;\r
249 \r
250 STATIC\r
251 EFI_STATUS\r
252 UnixBlockIoError (\r
253   IN UNIX_BLOCK_IO_PRIVATE      *Private\r
254   )\r
255 /*++\r
256 \r
257 Routine Description:\r
258 \r
259   TODO: Add function description\r
260 \r
261 Arguments:\r
262 \r
263   Private - TODO: add argument description\r
264 \r
265 Returns:\r
266 \r
267   TODO: add return values\r
268 \r
269 --*/\r
270 ;\r
271 \r
272 STATIC\r
273 EFI_STATUS\r
274 UnixBlockIoOpenDevice (\r
275   UNIX_BLOCK_IO_PRIVATE         *Private\r
276   )\r
277 /*++\r
278 \r
279 Routine Description:\r
280 \r
281   TODO: Add function description\r
282 \r
283 Arguments:\r
284 \r
285   Private - TODO: add argument description\r
286 \r
287 Returns:\r
288 \r
289   TODO: add return values\r
290 \r
291 --*/\r
292 ;\r
293 \r
294 STATIC\r
295 CHAR16                                    *\r
296 GetNextElementPastTerminator (\r
297   IN  CHAR16  *EnvironmentVariable,\r
298   IN  CHAR16  Terminator\r
299   )\r
300 /*++\r
301 \r
302 Routine Description:\r
303 \r
304   TODO: Add function description\r
305 \r
306 Arguments:\r
307 \r
308   EnvironmentVariable - TODO: add argument description\r
309   Terminator          - TODO: add argument description\r
310 \r
311 Returns:\r
312 \r
313   TODO: add return values\r
314 \r
315 --*/\r
316 ;\r
317 EFI_DRIVER_BINDING_PROTOCOL gUnixBlockIoDriverBinding = {\r
318   UnixBlockIoDriverBindingSupported,\r
319   UnixBlockIoDriverBindingStart,\r
320   UnixBlockIoDriverBindingStop,\r
321   0xa,\r
322   NULL,\r
323   NULL\r
324 };\r
325 \r
326 EFI_STATUS\r
327 EFIAPI\r
328 UnixBlockIoDriverBindingSupported (\r
329   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,\r
330   IN  EFI_HANDLE                   Handle,\r
331   IN  EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath\r
332   )\r
333 /*++\r
334 \r
335 Routine Description:\r
336 \r
337 Arguments:\r
338 \r
339 Returns:\r
340 \r
341   None\r
342 \r
343 --*/\r
344 // TODO:    This - add argument and description to function comment\r
345 // TODO:    Handle - add argument and description to function comment\r
346 // TODO:    RemainingDevicePath - add argument and description to function comment\r
347 {\r
348   EFI_STATUS              Status;\r
349   EFI_UNIX_IO_PROTOCOL  *UnixIo;\r
350 \r
351   //\r
352   // Open the IO Abstraction(s) needed to perform the supported test\r
353   //\r
354   Status = gBS->OpenProtocol (\r
355                   Handle,\r
356                   &gEfiUnixIoProtocolGuid,\r
357                   (VOID **)&UnixIo,\r
358                   This->DriverBindingHandle,\r
359                   Handle,\r
360                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
361                   );\r
362   if (EFI_ERROR (Status)) {\r
363     return Status;\r
364   }\r
365 \r
366   //\r
367   // Make sure the UnixThunkProtocol is valid\r
368   //\r
369   Status = EFI_UNSUPPORTED;\r
370   if (UnixIo->UnixThunk->Signature == EFI_UNIX_THUNK_PROTOCOL_SIGNATURE) {\r
371 \r
372     //\r
373     // Check the GUID to see if this is a handle type the driver supports\r
374     //\r
375     if (CompareGuid (UnixIo->TypeGuid, &gEfiUnixVirtualDisksGuid) ) {\r
376       Status = EFI_SUCCESS;\r
377     }\r
378   }\r
379 \r
380   //\r
381   // Close the I/O Abstraction(s) used to perform the supported test\r
382   //\r
383   gBS->CloseProtocol (\r
384         Handle,\r
385         &gEfiUnixIoProtocolGuid,\r
386         This->DriverBindingHandle,\r
387         Handle\r
388         );\r
389 \r
390   return Status;\r
391 }\r
392 \r
393 EFI_STATUS\r
394 EFIAPI\r
395 UnixBlockIoDriverBindingStart (\r
396   IN  EFI_DRIVER_BINDING_PROTOCOL   *This,\r
397   IN  EFI_HANDLE                    Handle,\r
398   IN  EFI_DEVICE_PATH_PROTOCOL      *RemainingDevicePath\r
399   )\r
400 /*++\r
401 \r
402 Routine Description:\r
403 \r
404 Arguments:\r
405 \r
406 Returns:\r
407 \r
408   None\r
409 \r
410 --*/\r
411 // TODO:    This - add argument and description to function comment\r
412 // TODO:    Handle - add argument and description to function comment\r
413 // TODO:    RemainingDevicePath - add argument and description to function comment\r
414 {\r
415   EFI_STATUS                  Status;\r
416   EFI_UNIX_IO_PROTOCOL       *UnixIo;\r
417   CHAR16                      Buffer[FILENAME_BUFFER_SIZE];\r
418   CHAR16                      *Str;\r
419   BOOLEAN                     RemovableMedia;\r
420   BOOLEAN                     WriteProtected;\r
421   UINTN                       NumberOfBlocks;\r
422   UINTN                       BlockSize;\r
423   INTN                        i;\r
424 \r
425   //\r
426   // Grab the protocols we need\r
427   //\r
428   Status = gBS->OpenProtocol (\r
429                   Handle,\r
430                   &gEfiUnixIoProtocolGuid,\r
431                   (void *)&UnixIo,\r
432                   This->DriverBindingHandle,\r
433                   Handle,\r
434                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
435                   );\r
436   if (EFI_ERROR (Status)) {\r
437     return Status;\r
438   }\r
439 \r
440   //\r
441   // Set DiskType\r
442   //\r
443   if (!CompareGuid (UnixIo->TypeGuid, &gEfiUnixVirtualDisksGuid)) {\r
444     Status = EFI_UNSUPPORTED;\r
445     goto Done;\r
446   }\r
447 \r
448   Status  = EFI_NOT_FOUND;\r
449   //  Extract filename.\r
450   Str     = UnixIo->EnvString;\r
451   i = 0;\r
452   while (*Str && *Str != ':')\r
453     Buffer[i++] = *Str++;\r
454   Buffer[i] = 0;\r
455   if (*Str != ':') {\r
456     goto Done;\r
457   }\r
458 \r
459   Str++;\r
460 \r
461   RemovableMedia = FALSE;\r
462   WriteProtected = TRUE;\r
463   NumberOfBlocks = 0;\r
464   BlockSize = 512;\r
465   do {\r
466     if (*Str == 'R' || *Str == 'F') {\r
467       RemovableMedia = (BOOLEAN) (*Str == 'R');\r
468       Str++;\r
469     }\r
470     if (*Str == 'O' || *Str == 'W') {\r
471       WriteProtected  = (BOOLEAN) (*Str == 'O');\r
472       Str++;\r
473     }\r
474     if (*Str == 0)\r
475       break;\r
476     if (*Str != ';')\r
477       goto Done;\r
478     Str++;\r
479 \r
480     NumberOfBlocks  = Atoi (Str);\r
481     Str       = GetNextElementPastTerminator (Str, ';');\r
482     if (NumberOfBlocks == 0)\r
483       break;\r
484 \r
485     BlockSize = Atoi (Str);\r
486     if (BlockSize != 0)\r
487       Str       = GetNextElementPastTerminator (Str, ';');\r
488   } while (0);\r
489 \r
490   //\r
491   // If we get here the variable is valid so do the work.\r
492   //\r
493   Status = UnixBlockIoCreateMapping (\r
494                                       UnixIo,\r
495                                       Handle,\r
496                                       Buffer,\r
497                                       WriteProtected,\r
498                                       RemovableMedia,\r
499                                       NumberOfBlocks,\r
500                                       BlockSize\r
501                                       );\r
502 \r
503 Done:\r
504   if (EFI_ERROR (Status)) {\r
505     gBS->CloseProtocol (\r
506           Handle,\r
507           &gEfiUnixIoProtocolGuid,\r
508           This->DriverBindingHandle,\r
509           Handle\r
510           );\r
511   }\r
512 \r
513   return Status;\r
514 }\r
515 \r
516 EFI_STATUS\r
517 EFIAPI\r
518 UnixBlockIoDriverBindingStop (\r
519   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,\r
520   IN  EFI_HANDLE                   Handle,\r
521   IN  UINTN                        NumberOfChildren,\r
522   IN  EFI_HANDLE                   *ChildHandleBuffer\r
523   )\r
524 /*++\r
525 \r
526 Routine Description:\r
527 \r
528   TODO: Add function description\r
529 \r
530 Arguments:\r
531 \r
532   This              - TODO: add argument description\r
533   Handle            - TODO: add argument description\r
534   NumberOfChildren  - TODO: add argument description\r
535   ChildHandleBuffer - TODO: add argument description\r
536 \r
537 Returns:\r
538 \r
539   EFI_UNSUPPORTED - TODO: Add description for return value\r
540 \r
541 --*/\r
542 {\r
543   EFI_BLOCK_IO_PROTOCOL   *BlockIo;\r
544   EFI_STATUS              Status;\r
545   UNIX_BLOCK_IO_PRIVATE *Private;\r
546 \r
547   //\r
548   // Get our context back\r
549   //\r
550   Status = gBS->OpenProtocol (\r
551                   Handle,\r
552                   &gEfiBlockIoProtocolGuid,\r
553                   (void *)&BlockIo,\r
554                   This->DriverBindingHandle,\r
555                   Handle,\r
556                   EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
557                   );\r
558   if (EFI_ERROR (Status)) {\r
559     return EFI_UNSUPPORTED;\r
560   }\r
561 \r
562   Private = UNIX_BLOCK_IO_PRIVATE_DATA_FROM_THIS (BlockIo);\r
563 \r
564   //\r
565   // BugBug: If we need to kick people off, we need to make Uninstall Close the handles.\r
566   //         We could pass in our image handle or FLAG our open to be closed via\r
567   //         Unistall (== to saying any CloseProtocol will close our open)\r
568   //\r
569   Status = gBS->UninstallMultipleProtocolInterfaces (\r
570                   Private->EfiHandle,\r
571                   &gEfiBlockIoProtocolGuid,\r
572                   &Private->BlockIo,\r
573                   NULL\r
574                   );\r
575   if (!EFI_ERROR (Status)) {\r
576 \r
577     Status = gBS->CloseProtocol (\r
578                     Handle,\r
579                     &gEfiUnixIoProtocolGuid,\r
580                     This->DriverBindingHandle,\r
581                     Handle\r
582                     );\r
583 \r
584     //\r
585     // Shut down our device\r
586     //\r
587     Private->UnixThunk->Close (Private->fd);\r
588 \r
589     //\r
590     // Free our instance data\r
591     //\r
592     FreeUnicodeStringTable (Private->ControllerNameTable);\r
593 \r
594     gBS->FreePool (Private);\r
595   }\r
596 \r
597   return Status;\r
598 }\r
599 \r
600 STATIC\r
601 CHAR16 *\r
602 GetNextElementPastTerminator (\r
603   IN  CHAR16  *EnvironmentVariable,\r
604   IN  CHAR16  Terminator\r
605   )\r
606 /*++\r
607 \r
608 Routine Description:\r
609 \r
610   Worker function to parse environment variables.\r
611 \r
612 Arguments:\r
613   EnvironmentVariable - Envirnment variable to parse.\r
614 \r
615   Terminator          - Terminator to parse for.\r
616 \r
617 Returns: \r
618 \r
619   Pointer to next eliment past the first occurence of Terminator or the '\0'\r
620   at the end of the string.\r
621 \r
622 --*/\r
623 {\r
624   CHAR16  *Ptr;\r
625 \r
626   for (Ptr = EnvironmentVariable; *Ptr != '\0'; Ptr++) {\r
627     if (*Ptr == Terminator) {\r
628       Ptr++;\r
629       break;\r
630     }\r
631   }\r
632 \r
633   return Ptr;\r
634 }\r
635 \r
636 STATIC\r
637 EFI_STATUS\r
638 UnixBlockIoCreateMapping (\r
639   IN EFI_UNIX_IO_PROTOCOL             *UnixIo,\r
640   IN EFI_HANDLE                         EfiDeviceHandle,\r
641   IN CHAR16                             *Filename,\r
642   IN BOOLEAN                            ReadOnly,\r
643   IN BOOLEAN                            RemovableMedia,\r
644   IN UINTN                              NumberOfBlocks,\r
645   IN UINTN                              BlockSize\r
646   )\r
647 /*++\r
648 \r
649 Routine Description:\r
650 \r
651   TODO: Add function description\r
652 \r
653 Arguments:\r
654 \r
655   UnixIo         - TODO: add argument description\r
656   EfiDeviceHandle - TODO: add argument description\r
657   Filename        - TODO: add argument description\r
658   ReadOnly        - TODO: add argument description\r
659   RemovableMedia  - TODO: add argument description\r
660   NumberOfBlocks  - TODO: add argument description\r
661   BlockSize       - TODO: add argument description\r
662   DeviceType      - TODO: add argument description\r
663 \r
664 Returns:\r
665 \r
666   TODO: add return values\r
667 \r
668 --*/\r
669 {\r
670   EFI_STATUS              Status;\r
671   EFI_BLOCK_IO_PROTOCOL   *BlockIo;\r
672   UNIX_BLOCK_IO_PRIVATE *Private;\r
673   UINTN                   Index;\r
674 \r
675   Status = gBS->AllocatePool (\r
676                   EfiBootServicesData,\r
677                   sizeof (UNIX_BLOCK_IO_PRIVATE),\r
678                   (void *)&Private\r
679                   );\r
680   ASSERT_EFI_ERROR (Status);\r
681 \r
682   EfiInitializeLock (&Private->Lock, EFI_TPL_NOTIFY);\r
683 \r
684   Private->UnixThunk = UnixIo->UnixThunk;\r
685 \r
686   Private->Signature  = UNIX_BLOCK_IO_PRIVATE_SIGNATURE;\r
687   Private->LastBlock  = NumberOfBlocks - 1;\r
688   Private->BlockSize  = BlockSize;\r
689 \r
690   for (Index = 0; Filename[Index] != 0; Index++) {\r
691     Private->Filename[Index] = Filename[Index];\r
692   }\r
693 \r
694   Private->Filename[Index]      = 0;\r
695 \r
696   Private->Mode                 = (ReadOnly ? O_RDONLY : O_RDWR);\r
697 \r
698   Private->NumberOfBlocks       = NumberOfBlocks;\r
699   Private->fd                   = -1;\r
700 \r
701   Private->ControllerNameTable  = NULL;\r
702 \r
703   AddUnicodeString (\r
704     "eng",\r
705     gUnixBlockIoComponentName.SupportedLanguages,\r
706     &Private->ControllerNameTable,\r
707     Filename\r
708     );\r
709 \r
710   BlockIo = &Private->BlockIo;\r
711   BlockIo->Revision = EFI_BLOCK_IO_PROTOCOL_REVISION;\r
712   BlockIo->Media = &Private->Media;\r
713   BlockIo->Media->BlockSize = Private->BlockSize;\r
714   BlockIo->Media->LastBlock = Private->NumberOfBlocks - 1;\r
715   BlockIo->Media->MediaId = 0;;\r
716 \r
717   BlockIo->Reset = UnixBlockIoResetBlock;\r
718   BlockIo->ReadBlocks = UnixBlockIoReadBlocks;\r
719   BlockIo->WriteBlocks = UnixBlockIoWriteBlocks;\r
720   BlockIo->FlushBlocks = UnixBlockIoFlushBlocks;\r
721 \r
722   BlockIo->Media->ReadOnly = ReadOnly;\r
723   BlockIo->Media->RemovableMedia = RemovableMedia;\r
724   BlockIo->Media->LogicalPartition = FALSE;\r
725   BlockIo->Media->MediaPresent = TRUE;\r
726   BlockIo->Media->WriteCaching = FALSE;\r
727 \r
728   BlockIo->Media->IoAlign = 1;\r
729 \r
730   Private->EfiHandle  = EfiDeviceHandle;\r
731   Status              = UnixBlockIoOpenDevice (Private);\r
732   if (!EFI_ERROR (Status)) {\r
733 \r
734     Status = gBS->InstallMultipleProtocolInterfaces (\r
735                     &Private->EfiHandle,\r
736                     &gEfiBlockIoProtocolGuid,\r
737                     &Private->BlockIo,\r
738                     NULL\r
739                     );\r
740     if (EFI_ERROR (Status)) {\r
741       FreeUnicodeStringTable (Private->ControllerNameTable);\r
742       gBS->FreePool (Private);\r
743     }\r
744 \r
745     DEBUG ((EFI_D_INIT, "BlockDevice added: %s\n", Filename));\r
746   }\r
747 \r
748   return Status;\r
749 }\r
750 \r
751 STATIC\r
752 EFI_STATUS\r
753 UnixBlockIoOpenDevice (\r
754   UNIX_BLOCK_IO_PRIVATE                 *Private\r
755   )\r
756 /*++\r
757 \r
758 Routine Description:\r
759 \r
760   TODO: Add function description\r
761 \r
762 Arguments:\r
763 \r
764   Private - TODO: add argument description\r
765 \r
766 Returns:\r
767 \r
768   TODO: add return values\r
769 \r
770 --*/\r
771 {\r
772   EFI_STATUS            Status;\r
773   UINT64                FileSize;\r
774   UINT64                EndOfFile;\r
775   EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
776 \r
777   BlockIo = &Private->BlockIo;\r
778   EfiAcquireLock (&Private->Lock);\r
779 \r
780   //\r
781   // If the device is already opened, close it\r
782   //\r
783   if (Private->fd >= 0) {\r
784     BlockIo->Reset (BlockIo, FALSE);\r
785   }\r
786 \r
787   //\r
788   // Open the device\r
789   //\r
790   Private->fd = Private->UnixThunk->Open\r
791     (Private->Filename, Private->Mode, 0644);\r
792 \r
793   if (Private->fd < 0) {\r
794     DEBUG ((EFI_D_INFO, "PlOpenBlock: Could not open %s\n",\r
795             Private->Filename));\r
796     BlockIo->Media->MediaPresent  = FALSE;\r
797     Status                        = EFI_NO_MEDIA;\r
798     goto Done;\r
799   }\r
800 \r
801   if (!BlockIo->Media->MediaPresent) {\r
802     //\r
803     // BugBug: try to emulate if a CD appears - notify drivers to check it out\r
804     //\r
805     BlockIo->Media->MediaPresent = TRUE;\r
806     EfiReleaseLock (&Private->Lock);\r
807     EfiAcquireLock (&Private->Lock);\r
808   }\r
809 \r
810   //\r
811   // get the size of the file\r
812   //\r
813   Status = SetFilePointer64 (Private, 0, &FileSize, SEEK_END);\r
814 \r
815   if (EFI_ERROR (Status)) {\r
816     FileSize = MultU64x32 (Private->NumberOfBlocks, Private->BlockSize);\r
817     DEBUG ((EFI_D_ERROR, "PlOpenBlock: Could not get filesize of %s\n", Private->Filename));\r
818     Status = EFI_UNSUPPORTED;\r
819     goto Done;\r
820   }\r
821 \r
822   if (Private->NumberOfBlocks == 0) {\r
823     Private->NumberOfBlocks = DivU64x32 (FileSize, Private->BlockSize);\r
824   }\r
825 \r
826   EndOfFile = MultU64x32 (Private->NumberOfBlocks, Private->BlockSize);\r
827 \r
828   if (FileSize != EndOfFile) {\r
829     //\r
830     // file is not the proper size, change it\r
831     //\r
832     DEBUG ((EFI_D_INIT, "PlOpenBlock: Initializing block device: %a\n", Private->Filename));\r
833 \r
834     //\r
835     // first set it to 0\r
836     //\r
837     Private->UnixThunk->FTruncate (Private->fd, 0);\r
838 \r
839     //\r
840     // then set it to the needed file size (OS will zero fill it)\r
841     //\r
842     Private->UnixThunk->FTruncate (Private->fd, EndOfFile);\r
843   }\r
844 \r
845   DEBUG ((EFI_D_INIT, "%HPlOpenBlock: opened %s%N\n", Private->Filename));\r
846   Status = EFI_SUCCESS;\r
847 \r
848 Done:\r
849   if (EFI_ERROR (Status)) {\r
850     if (Private->fd >= 0) {\r
851       BlockIo->Reset (BlockIo, FALSE);\r
852     }\r
853   }\r
854 \r
855   EfiReleaseLock (&Private->Lock);\r
856   return Status;\r
857 }\r
858 \r
859 STATIC\r
860 EFI_STATUS\r
861 UnixBlockIoError (\r
862   IN UNIX_BLOCK_IO_PRIVATE      *Private\r
863   )\r
864 /*++\r
865 \r
866 Routine Description:\r
867 \r
868   TODO: Add function description\r
869 \r
870 Arguments:\r
871 \r
872   Private - TODO: add argument description\r
873 \r
874 Returns:\r
875 \r
876   TODO: add return values\r
877 \r
878 --*/\r
879 {\r
880   return EFI_DEVICE_ERROR;\r
881 \r
882 #if 0\r
883   EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
884   EFI_STATUS            Status;\r
885   BOOLEAN               ReinstallBlockIoFlag;\r
886 \r
887 \r
888   BlockIo = &Private->BlockIo;\r
889 \r
890   switch (Private->UnixThunk->GetLastError ()) {\r
891 \r
892   case ERROR_NOT_READY:\r
893     Status                        = EFI_NO_MEDIA;\r
894     BlockIo->Media->ReadOnly      = FALSE;\r
895     BlockIo->Media->MediaPresent  = FALSE;\r
896     ReinstallBlockIoFlag          = FALSE;\r
897     break;\r
898 \r
899   case ERROR_WRONG_DISK:\r
900     BlockIo->Media->ReadOnly      = FALSE;\r
901     BlockIo->Media->MediaPresent  = TRUE;\r
902     BlockIo->Media->MediaId += 1;\r
903     ReinstallBlockIoFlag  = TRUE;\r
904     Status                = EFI_MEDIA_CHANGED;\r
905     break;\r
906 \r
907   case ERROR_WRITE_PROTECT:\r
908     BlockIo->Media->ReadOnly  = TRUE;\r
909     ReinstallBlockIoFlag      = FALSE;\r
910     Status                    = EFI_WRITE_PROTECTED;\r
911     break;\r
912 \r
913   default:\r
914     ReinstallBlockIoFlag  = FALSE;\r
915     Status                = EFI_DEVICE_ERROR;\r
916     break;\r
917   }\r
918 \r
919   if (ReinstallBlockIoFlag) {\r
920     BlockIo->Reset (BlockIo, FALSE);\r
921 \r
922     gBS->ReinstallProtocolInterface (\r
923           Private->EfiHandle,\r
924           &gEfiBlockIoProtocolGuid,\r
925           BlockIo,\r
926           BlockIo\r
927           );\r
928   }\r
929 \r
930   return Status;\r
931 #endif\r
932 }\r
933 \r
934 STATIC\r
935 EFI_STATUS\r
936 UnixBlockIoReadWriteCommon (\r
937   IN  UNIX_BLOCK_IO_PRIVATE     *Private,\r
938   IN UINT32                       MediaId,\r
939   IN EFI_LBA                      Lba,\r
940   IN UINTN                        BufferSize,\r
941   IN VOID                         *Buffer,\r
942   IN CHAR8                        *CallerName\r
943   )\r
944 /*++\r
945 \r
946 Routine Description:\r
947 \r
948   TODO: Add function description\r
949 \r
950 Arguments:\r
951 \r
952   Private     - TODO: add argument description\r
953   MediaId     - TODO: add argument description\r
954   Lba         - TODO: add argument description\r
955   BufferSize  - TODO: add argument description\r
956   Buffer      - TODO: add argument description\r
957   CallerName  - TODO: add argument description\r
958 \r
959 Returns:\r
960 \r
961   EFI_NO_MEDIA - TODO: Add description for return value\r
962   EFI_MEDIA_CHANGED - TODO: Add description for return value\r
963   EFI_INVALID_PARAMETER - TODO: Add description for return value\r
964   EFI_SUCCESS - TODO: Add description for return value\r
965   EFI_BAD_BUFFER_SIZE - TODO: Add description for return value\r
966   EFI_INVALID_PARAMETER - TODO: Add description for return value\r
967   EFI_SUCCESS - TODO: Add description for return value\r
968 \r
969 --*/\r
970 {\r
971   EFI_STATUS  Status;\r
972   UINTN       BlockSize;\r
973   UINT64      LastBlock;\r
974   INT64       DistanceToMove;\r
975   UINT64      DistanceMoved;\r
976 \r
977   if (Private->fd < 0) {\r
978     Status = UnixBlockIoOpenDevice (Private);\r
979     if (EFI_ERROR (Status)) {\r
980       return Status;\r
981     }\r
982   }\r
983 \r
984   if (!Private->Media.MediaPresent) {\r
985     DEBUG ((EFI_D_INIT, "%s: No Media\n", CallerName));\r
986     return EFI_NO_MEDIA;\r
987   }\r
988 \r
989   if (Private->Media.MediaId != MediaId) {\r
990     return EFI_MEDIA_CHANGED;\r
991   }\r
992 \r
993   if ((UINT32) Buffer % Private->Media.IoAlign != 0) {\r
994     return EFI_INVALID_PARAMETER;\r
995   }\r
996   \r
997   //\r
998   // Verify buffer size\r
999   //\r
1000   BlockSize = Private->BlockSize;\r
1001   if (BufferSize == 0) {\r
1002     DEBUG ((EFI_D_INIT, "%s: Zero length read\n", CallerName));\r
1003     return EFI_SUCCESS;\r
1004   }\r
1005 \r
1006   if ((BufferSize % BlockSize) != 0) {\r
1007     DEBUG ((EFI_D_INIT, "%s: Invalid read size\n", CallerName));\r
1008     return EFI_BAD_BUFFER_SIZE;\r
1009   }\r
1010 \r
1011   LastBlock = Lba + (BufferSize / BlockSize) - 1;\r
1012   if (LastBlock > Private->LastBlock) {\r
1013     DEBUG ((EFI_D_INIT, "ReadBlocks: Attempted to read off end of device\n"));\r
1014     return EFI_INVALID_PARAMETER;\r
1015   }\r
1016   //\r
1017   // Seek to End of File\r
1018   //\r
1019   DistanceToMove = MultU64x32 (Lba, BlockSize);\r
1020   Status = SetFilePointer64 (Private, DistanceToMove, &DistanceMoved, SEEK_SET);\r
1021 \r
1022   if (EFI_ERROR (Status)) {\r
1023     DEBUG ((EFI_D_INIT, "WriteBlocks: SetFilePointer failed\n"));\r
1024     return UnixBlockIoError (Private);\r
1025   }\r
1026 \r
1027   return EFI_SUCCESS;\r
1028 }\r
1029 \r
1030 STATIC\r
1031 EFI_STATUS\r
1032 EFIAPI\r
1033 UnixBlockIoReadBlocks (\r
1034   IN EFI_BLOCK_IO_PROTOCOL  *This,\r
1035   IN UINT32                 MediaId,\r
1036   IN EFI_LBA                Lba,\r
1037   IN UINTN                  BufferSize,\r
1038   OUT VOID                  *Buffer\r
1039   )\r
1040 /*++\r
1041 \r
1042   Routine Description:\r
1043     Read BufferSize bytes from Lba into Buffer.\r
1044 \r
1045   Arguments:\r
1046     This       - Protocol instance pointer.\r
1047     MediaId    - Id of the media, changes every time the media is replaced.\r
1048     Lba        - The starting Logical Block Address to read from\r
1049     BufferSize - Size of Buffer, must be a multiple of device block size.\r
1050     Buffer     - Buffer containing read data\r
1051 \r
1052   Returns:\r
1053     EFI_SUCCESS           - The data was read correctly from the device.\r
1054     EFI_DEVICE_ERROR      - The device reported an error while performing the read.\r
1055     EFI_NO_MEDIA          - There is no media in the device.\r
1056     EFI_MEDIA_CHANGED     - The MediaId does not matched the current device.\r
1057     EFI_BAD_BUFFER_SIZE   - The Buffer was not a multiple of the block size of the \r
1058                             device.\r
1059     EFI_INVALID_PARAMETER - The read request contains device addresses that are not \r
1060                             valid for the device.\r
1061 \r
1062 --*/\r
1063 {\r
1064   UNIX_BLOCK_IO_PRIVATE *Private;\r
1065   ssize_t                 len;\r
1066   EFI_STATUS              Status;\r
1067 \r
1068   Private = UNIX_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);\r
1069 \r
1070   Status  = UnixBlockIoReadWriteCommon (Private, MediaId, Lba, BufferSize, Buffer, "UnixReadBlocks");\r
1071   if (EFI_ERROR (Status)) {\r
1072     return Status;\r
1073   }\r
1074 \r
1075   len = Private->UnixThunk->Read (Private->fd, Buffer, BufferSize);\r
1076   if (len != BufferSize) {\r
1077     DEBUG ((EFI_D_INIT, "ReadBlocks: ReadFile failed.\n"));\r
1078     return UnixBlockIoError (Private);\r
1079   }\r
1080 \r
1081   //\r
1082   // If we wrote then media is present.\r
1083   //\r
1084   This->Media->MediaPresent = TRUE;\r
1085   return EFI_SUCCESS;\r
1086 }\r
1087 \r
1088 STATIC\r
1089 EFI_STATUS\r
1090 EFIAPI\r
1091 UnixBlockIoWriteBlocks (\r
1092   IN EFI_BLOCK_IO_PROTOCOL  *This,\r
1093   IN UINT32                 MediaId,\r
1094   IN EFI_LBA                Lba,\r
1095   IN UINTN                  BufferSize,\r
1096   IN VOID                   *Buffer\r
1097   )\r
1098 /*++\r
1099 \r
1100   Routine Description:\r
1101     Write BufferSize bytes from Lba into Buffer.\r
1102 \r
1103   Arguments:\r
1104     This       - Protocol instance pointer.\r
1105     MediaId    - Id of the media, changes every time the media is replaced.\r
1106     Lba        - The starting Logical Block Address to read from\r
1107     BufferSize - Size of Buffer, must be a multiple of device block size.\r
1108     Buffer     - Buffer containing read data\r
1109 \r
1110   Returns:\r
1111     EFI_SUCCESS           - The data was written correctly to the device.\r
1112     EFI_WRITE_PROTECTED   - The device can not be written to.\r
1113     EFI_DEVICE_ERROR      - The device reported an error while performing the write.\r
1114     EFI_NO_MEDIA          - There is no media in the device.\r
1115     EFI_MEDIA_CHNAGED     - The MediaId does not matched the current device.\r
1116     EFI_BAD_BUFFER_SIZE   - The Buffer was not a multiple of the block size of the \r
1117                             device.\r
1118     EFI_INVALID_PARAMETER - The write request contains a LBA that is not \r
1119                             valid for the device.\r
1120 \r
1121 --*/\r
1122 {\r
1123   UNIX_BLOCK_IO_PRIVATE *Private;\r
1124   ssize_t                 len;\r
1125   EFI_STATUS              Status;\r
1126 \r
1127   Private = UNIX_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);\r
1128 \r
1129   Status  = UnixBlockIoReadWriteCommon (Private, MediaId, Lba, BufferSize, Buffer, "UnixWriteBlocks");\r
1130   if (EFI_ERROR (Status)) {\r
1131     return Status;\r
1132   }\r
1133 \r
1134   len = Private->UnixThunk->Write (Private->fd, Buffer, BufferSize);\r
1135   if (len != BufferSize) {\r
1136     DEBUG ((EFI_D_INIT, "ReadBlocks: WriteFile failed.\n"));\r
1137     return UnixBlockIoError (Private);\r
1138   }\r
1139 \r
1140   //\r
1141   // If the write succeeded, we are not write protected and media is present.\r
1142   //\r
1143   This->Media->MediaPresent = TRUE;\r
1144   This->Media->ReadOnly     = FALSE;\r
1145   return EFI_SUCCESS;\r
1146 }\r
1147 \r
1148 STATIC\r
1149 EFI_STATUS\r
1150 EFIAPI\r
1151 UnixBlockIoFlushBlocks (\r
1152   IN EFI_BLOCK_IO_PROTOCOL  *This\r
1153   )\r
1154 /*++\r
1155 \r
1156   Routine Description:\r
1157     Flush the Block Device.\r
1158 \r
1159   Arguments:\r
1160     This             - Protocol instance pointer.\r
1161 \r
1162   Returns:\r
1163     EFI_SUCCESS      - All outstanding data was written to the device\r
1164     EFI_DEVICE_ERROR - The device reported an error while writting back the data\r
1165     EFI_NO_MEDIA     - There is no media in the device.\r
1166 \r
1167 --*/\r
1168 {\r
1169   return EFI_SUCCESS;\r
1170 }\r
1171 \r
1172 STATIC\r
1173 EFI_STATUS\r
1174 EFIAPI\r
1175 UnixBlockIoResetBlock (\r
1176   IN EFI_BLOCK_IO_PROTOCOL  *This,\r
1177   IN BOOLEAN                ExtendedVerification\r
1178   )\r
1179 /*++\r
1180 \r
1181   Routine Description:\r
1182     Reset the Block Device.\r
1183 \r
1184   Arguments:\r
1185     This                 - Protocol instance pointer.\r
1186     ExtendedVerification - Driver may perform diagnostics on reset.\r
1187 \r
1188   Returns:\r
1189     EFI_SUCCESS           - The device was reset.\r
1190     EFI_DEVICE_ERROR      - The device is not functioning properly and could \r
1191                             not be reset.\r
1192 \r
1193 --*/\r
1194 {\r
1195   UNIX_BLOCK_IO_PRIVATE *Private;\r
1196 \r
1197   Private = UNIX_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);\r
1198 \r
1199   if (Private->fd >= 0) {\r
1200     Private->UnixThunk->Close (Private->fd);\r
1201     Private->fd = -1;\r
1202   }\r
1203 \r
1204   return EFI_SUCCESS;\r
1205 }\r
1206 \r
1207 UINTN\r
1208 Atoi (\r
1209   CHAR16  *String\r
1210   )\r
1211 /*++\r
1212 \r
1213 Routine Description:\r
1214 \r
1215   Convert a unicode string to a UINTN\r
1216 \r
1217 Arguments:\r
1218 \r
1219   String - Unicode string.\r
1220 \r
1221 Returns: \r
1222 \r
1223   UINTN of the number represented by String.  \r
1224 \r
1225 --*/\r
1226 {\r
1227   UINTN   Number;\r
1228   CHAR16  *Str;\r
1229 \r
1230   //\r
1231   // skip preceeding white space\r
1232   //\r
1233   Str = String;\r
1234   while ((*Str) && (*Str == ' ')) {\r
1235     Str++;\r
1236   }\r
1237   //\r
1238   // Convert ot a Number\r
1239   //\r
1240   Number = 0;\r
1241   while (*Str != '\0') {\r
1242     if ((*Str >= '0') && (*Str <= '9')) {\r
1243       Number = (Number * 10) +*Str - '0';\r
1244     } else {\r
1245       break;\r
1246     }\r
1247 \r
1248     Str++;\r
1249   }\r
1250 \r
1251   return Number;\r
1252 }\r
1253 \r
1254 EFI_STATUS\r
1255 SetFilePointer64 (\r
1256   IN  UNIX_BLOCK_IO_PRIVATE    *Private,\r
1257   IN  INT64                      DistanceToMove,\r
1258   OUT UINT64                     *NewFilePointer,\r
1259   IN  INTN                      MoveMethod\r
1260   )\r
1261 /*++\r
1262 \r
1263 This function extends the capability of SetFilePointer to accept 64 bit parameters\r
1264 \r
1265 --*/\r
1266 // TODO: function comment is missing 'Routine Description:'\r
1267 // TODO: function comment is missing 'Arguments:'\r
1268 // TODO: function comment is missing 'Returns:'\r
1269 // TODO:    Private - add argument and description to function comment\r
1270 // TODO:    DistanceToMove - add argument and description to function comment\r
1271 // TODO:    NewFilePointer - add argument and description to function comment\r
1272 // TODO:    MoveMethod - add argument and description to function comment\r
1273 {\r
1274   EFI_STATUS    Status;\r
1275   off_t         res;\r
1276 \r
1277   res = Private->UnixThunk->Lseek(Private->fd, DistanceToMove, MoveMethod);\r
1278   if (res == -1) {\r
1279     Status = EFI_INVALID_PARAMETER;\r
1280   }\r
1281 \r
1282   if (NewFilePointer != NULL) {\r
1283     *NewFilePointer = res;\r
1284   }\r
1285 \r
1286   return Status;\r
1287 }\r