7581b02e231c3a78e9bcaf16fa5c54279075937b
[mirror_edk2.git] / MdeModulePkg / Universal / Network / MnpDxe / MnpDriver.c
1 /** @file\r
2   Implementation of driver entry point and driver binding protocol.\r
3 \r
4 Copyright (c) 2005 - 2009, Intel Corporation. <BR> \r
5 All rights reserved. This program and the accompanying materials are licensed \r
6 and made available under the terms and conditions of the BSD License which \r
7 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 "MnpDriver.h"\r
16 #include "MnpImpl.h"\r
17 \r
18 \r
19 EFI_DRIVER_BINDING_PROTOCOL gMnpDriverBinding = {\r
20   MnpDriverBindingSupported,\r
21   MnpDriverBindingStart,\r
22   MnpDriverBindingStop,\r
23   0xa,\r
24   NULL,\r
25   NULL\r
26 };\r
27 \r
28 /**\r
29   Test to see if this driver supports ControllerHandle. This service\r
30   is called by the EFI boot service ConnectController(). In\r
31   order to make drivers as small as possible, there are a few calling\r
32   restrictions for this service. ConnectController() must\r
33   follow these calling restrictions. If any other agent wishes to call\r
34   Supported() it must also follow these calling restrictions.\r
35 \r
36   @param[in]  This                 Protocol instance pointer.\r
37   @param[in]  ControllerHandle     Handle of device to test.\r
38   @param[in]  RemainingDevicePath  Optional parameter use to pick a specific \r
39                                    child device to start.\r
40 \r
41   @retval EFI_SUCCESS              This driver supports this device.\r
42   @retval EFI_ALREADY_STARTED      This driver is already running on this device.\r
43   @retval Others                   This driver does not support this device.\r
44 \r
45 **/\r
46 EFI_STATUS\r
47 EFIAPI\r
48 MnpDriverBindingSupported (\r
49   IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
50   IN EFI_HANDLE                   ControllerHandle,\r
51   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL\r
52   )\r
53 {\r
54   EFI_STATUS                   Status;\r
55   EFI_SIMPLE_NETWORK_PROTOCOL  *Snp;\r
56 \r
57   //\r
58   // Test to see if MNP is already installed.\r
59   //\r
60   Status = gBS->OpenProtocol (\r
61                   ControllerHandle,\r
62                   &gEfiManagedNetworkServiceBindingProtocolGuid,\r
63                   NULL,\r
64                   This->DriverBindingHandle,\r
65                   ControllerHandle,\r
66                   EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
67                   );\r
68   if (!EFI_ERROR (Status)) {\r
69     return EFI_ALREADY_STARTED;\r
70   }\r
71 \r
72   //\r
73   // Test to open the Simple Network protocol BY_DRIVER.\r
74   //\r
75   Status = gBS->OpenProtocol (\r
76                   ControllerHandle,\r
77                   &gEfiSimpleNetworkProtocolGuid,\r
78                   (VOID **) &Snp,\r
79                   This->DriverBindingHandle,\r
80                   ControllerHandle,\r
81                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
82                   );\r
83 \r
84   if (EFI_ERROR (Status)) {\r
85     return Status;\r
86   }\r
87 \r
88   //\r
89   // Close the openned SNP protocol.\r
90   //\r
91   gBS->CloseProtocol (\r
92          ControllerHandle,\r
93          &gEfiSimpleNetworkProtocolGuid,\r
94          This->DriverBindingHandle,\r
95          ControllerHandle\r
96          );\r
97 \r
98   return EFI_SUCCESS;\r
99 }\r
100 \r
101 \r
102 /**\r
103   Start this driver on ControllerHandle. This service is called by the\r
104   EFI boot service ConnectController(). In order to make drivers as small \r
105   as possible, there are a few calling restrictions for this service.\r
106   ConnectController() must follow these calling restrictions. If any other\r
107   agent wishes to call Start() it must also follow these calling restrictions.\r
108 \r
109   @param[in]       This                 Protocol instance pointer.\r
110   @param[in]       ControllerHandle     Handle of device to bind driver to.\r
111   @param[in]       RemainingDevicePath  Optional parameter use to pick a specific \r
112                                         child device to start.\r
113 \r
114   @retval EFI_SUCCESS           This driver is added to ControllerHandle.\r
115   @retval EFI_ALREADY_STARTED   This driver is already running on ControllerHandle.\r
116   @retval EFI_OUT_OF_RESOURCES  Failed to allocate memory for Mnp Service Data.\r
117   @retval Others                This driver does not support this device.\r
118   \r
119 **/\r
120 EFI_STATUS\r
121 EFIAPI\r
122 MnpDriverBindingStart (\r
123   IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
124   IN EFI_HANDLE                   ControllerHandle,\r
125   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL\r
126   )\r
127 {\r
128   EFI_STATUS        Status;\r
129   MNP_SERVICE_DATA  *MnpServiceData;\r
130   BOOLEAN           MnpInitialized;\r
131 \r
132   MnpInitialized  = FALSE;\r
133 \r
134   MnpServiceData  = AllocateZeroPool (sizeof (MNP_SERVICE_DATA));\r
135   if (MnpServiceData == NULL) {\r
136     DEBUG ((EFI_D_ERROR, "MnpDriverBindingStart(): Failed to allocate the Mnp Service Data.\n"));\r
137 \r
138     return EFI_OUT_OF_RESOURCES;\r
139   }\r
140 \r
141   //\r
142   // Initialize the Mnp Service Data.\r
143   //\r
144   Status = MnpInitializeServiceData (MnpServiceData, This->DriverBindingHandle, ControllerHandle);\r
145   if (EFI_ERROR (Status)) {\r
146 \r
147     DEBUG ((EFI_D_ERROR, "MnpDriverBindingStart: MnpInitializeServiceData failed, %r.\n",Status));\r
148     goto ErrorExit;\r
149   }\r
150 \r
151   MnpInitialized = TRUE;\r
152 \r
153   //\r
154   // Install the MNP Service Binding Protocol.\r
155   //\r
156   Status = gBS->InstallMultipleProtocolInterfaces (\r
157                   &ControllerHandle,\r
158                   &gEfiManagedNetworkServiceBindingProtocolGuid,\r
159                   &MnpServiceData->ServiceBinding,\r
160                   NULL\r
161                   );\r
162 \r
163 ErrorExit:\r
164 \r
165   if (EFI_ERROR (Status)) {\r
166 \r
167     if (MnpInitialized) {\r
168       //\r
169       // Flush the Mnp Service Data.\r
170       //\r
171       MnpFlushServiceData (MnpServiceData, This->DriverBindingHandle);\r
172     }\r
173 \r
174     FreePool (MnpServiceData);\r
175   }\r
176 \r
177   return Status;\r
178 }\r
179 \r
180 /**\r
181   Stop this driver on ControllerHandle. This service is called by the\r
182   EFI boot service DisconnectController(). In order to make drivers as \r
183   small as possible, there are a few calling restrictions for this service. \r
184   DisconnectController() must follow these calling restrictions. If any other \r
185   agent wishes to call Stop() it must also follow these calling restrictions.\r
186   \r
187   @param[in]  This               Protocol instance pointer.\r
188   @param[in]  ControllerHandle   Handle of device to stop driver on.\r
189   @param[in]  NumberOfChildren   Number of Handles in ChildHandleBuffer. If \r
190                                  number of children is zero stop the entire \r
191                                                                  bus driver.\r
192   @param[in]  ChildHandleBuffer  List of Child Handles to Stop.\r
193 \r
194   @retval EFI_SUCCESS            This driver is removed ControllerHandle.\r
195   @retval EFI_DEVICE_ERROR       The device could not be stopped due to a device error.\r
196 \r
197 **/\r
198 EFI_STATUS\r
199 EFIAPI\r
200 MnpDriverBindingStop (\r
201   IN EFI_DRIVER_BINDING_PROTOCOL  *This,\r
202   IN EFI_HANDLE                   ControllerHandle,\r
203   IN UINTN                        NumberOfChildren,\r
204   IN EFI_HANDLE                   *ChildHandleBuffer OPTIONAL\r
205   )\r
206 {\r
207   EFI_STATUS                    Status;\r
208   EFI_SERVICE_BINDING_PROTOCOL  *ServiceBinding;\r
209   MNP_SERVICE_DATA              *MnpServiceData;\r
210   MNP_INSTANCE_DATA             *Instance;\r
211 \r
212   //\r
213   // Retrieve the MNP service binding protocol from the ControllerHandle.\r
214   //\r
215   Status = gBS->OpenProtocol (\r
216                   ControllerHandle,\r
217                   &gEfiManagedNetworkServiceBindingProtocolGuid,\r
218                   (VOID **) &ServiceBinding,\r
219                   This->DriverBindingHandle,\r
220                   ControllerHandle,\r
221                   EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
222                   );\r
223   if (EFI_ERROR (Status)) {\r
224 \r
225     DEBUG (\r
226       (EFI_D_ERROR,\r
227       "MnpDriverBindingStop: Locate MNP Service Binding Protocol failed, %r.\n",\r
228       Status)\r
229       );\r
230     return EFI_DEVICE_ERROR;\r
231   }\r
232 \r
233   MnpServiceData = MNP_SERVICE_DATA_FROM_THIS (ServiceBinding);\r
234 \r
235   if (NumberOfChildren == 0) {\r
236     //\r
237     // Uninstall the MNP Service Binding Protocol.\r
238     //\r
239     gBS->UninstallMultipleProtocolInterfaces (\r
240            ControllerHandle,\r
241            &gEfiManagedNetworkServiceBindingProtocolGuid,\r
242            ServiceBinding,\r
243            NULL\r
244            );\r
245 \r
246     //\r
247     // Flush the Mnp service data.\r
248     //\r
249     MnpFlushServiceData (MnpServiceData, This->DriverBindingHandle);\r
250 \r
251     FreePool (MnpServiceData);\r
252   } else {\r
253     while (!IsListEmpty (&MnpServiceData->ChildrenList)) {\r
254       //\r
255       // Don't use NetListRemoveHead here, the remove opreration will be done\r
256       // in ServiceBindingDestroyChild.\r
257       //\r
258       Instance = NET_LIST_HEAD (\r
259                    &MnpServiceData->ChildrenList,\r
260                    MNP_INSTANCE_DATA,\r
261                    InstEntry\r
262                    );\r
263 \r
264       ServiceBinding->DestroyChild (ServiceBinding, Instance->Handle);\r
265     }\r
266   }\r
267 \r
268   return Status;\r
269 }\r
270 \r
271 \r
272 /**\r
273   Creates a child handle with a set of I/O services.\r
274 \r
275   @param[in]       This              Protocol instance pointer.\r
276   @param[in, out]  ChildHandle       Pointer to the handle of the child to create. If\r
277                                      it is NULL, then a new handle is created. If\r
278                                                                          it is not NULL, then the I/O services are added \r
279                                                                          to the existing child handle.\r
280 \r
281   @retval EFI_SUCCES                 The protocol was added to ChildHandle. \r
282   @retval EFI_INVALID_PARAMETER      ChildHandle is NULL. \r
283   @retval EFI_OUT_OF_RESOURCES       There are not enough resources availabe to \r
284                                      create the child.\r
285   @retval Others                     The child handle was not created.\r
286 \r
287 **/\r
288 EFI_STATUS\r
289 EFIAPI\r
290 MnpServiceBindingCreateChild (\r
291   IN EFI_SERVICE_BINDING_PROTOCOL  *This,\r
292   IN OUT EFI_HANDLE                *ChildHandle\r
293   )\r
294 {\r
295   EFI_STATUS         Status;\r
296   MNP_SERVICE_DATA   *MnpServiceData;\r
297   MNP_INSTANCE_DATA  *Instance;\r
298   VOID               *Snp;\r
299   EFI_TPL            OldTpl;\r
300 \r
301   if ((This == NULL) || (ChildHandle == NULL)) {\r
302 \r
303     return EFI_INVALID_PARAMETER;\r
304   }\r
305 \r
306   MnpServiceData = MNP_SERVICE_DATA_FROM_THIS (This);\r
307 \r
308   //\r
309   // Allocate buffer for the new instance.\r
310   //\r
311   Instance = AllocateZeroPool (sizeof (MNP_INSTANCE_DATA));\r
312   if (Instance == NULL) {\r
313 \r
314     DEBUG ((EFI_D_ERROR, "MnpServiceBindingCreateChild: Faild to allocate memory for the new instance.\n"));\r
315     return EFI_OUT_OF_RESOURCES;\r
316   }\r
317 \r
318   //\r
319   // Init the instance data.\r
320   //\r
321   MnpInitializeInstanceData (MnpServiceData, Instance);\r
322 \r
323   Status = gBS->InstallMultipleProtocolInterfaces (\r
324                   ChildHandle,\r
325                   &gEfiManagedNetworkProtocolGuid,\r
326                   &Instance->ManagedNetwork,\r
327                   NULL\r
328                   );\r
329   if (EFI_ERROR (Status)) {\r
330 \r
331     DEBUG (\r
332       (EFI_D_ERROR,\r
333       "MnpServiceBindingCreateChild: Failed to install the MNP protocol, %r.\n",\r
334       Status)\r
335       );\r
336     goto ErrorExit;\r
337   }\r
338 \r
339   //\r
340   // Save the instance's childhandle.\r
341   //\r
342   Instance->Handle = *ChildHandle;\r
343 \r
344   Status = gBS->OpenProtocol (\r
345                   MnpServiceData->ControllerHandle,\r
346                   &gEfiSimpleNetworkProtocolGuid,\r
347                   (VOID **) &Snp,\r
348                   gMnpDriverBinding.DriverBindingHandle,\r
349                   Instance->Handle,\r
350                   EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
351                   );\r
352   if (EFI_ERROR (Status)) {\r
353     goto ErrorExit;\r
354   }\r
355 \r
356   //\r
357   // Add the child instance into ChildrenList.\r
358   //\r
359   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
360 \r
361   InsertTailList (&MnpServiceData->ChildrenList, &Instance->InstEntry);\r
362   MnpServiceData->ChildrenNumber++;\r
363 \r
364   gBS->RestoreTPL (OldTpl);\r
365 \r
366 ErrorExit:\r
367 \r
368   if (EFI_ERROR (Status)) {\r
369 \r
370     if (Instance->Handle != NULL) {\r
371 \r
372       gBS->UninstallMultipleProtocolInterfaces (\r
373             &gEfiManagedNetworkProtocolGuid,\r
374             &Instance->ManagedNetwork,\r
375             NULL\r
376             );\r
377     }\r
378 \r
379     FreePool (Instance);\r
380   }\r
381 \r
382   return Status;\r
383 }\r
384 \r
385 \r
386 /**\r
387   Destroys a child handle with a set of I/O services.\r
388    \r
389   The DestroyChild() function does the opposite of CreateChild(). It removes a \r
390   protocol that was installed by CreateChild() from ChildHandle. If the removed \r
391   protocol is the last protocol on ChildHandle, then ChildHandle is destroyed. \r
392    \r
393   @param[in]  This               Pointer to the EFI_SERVICE_BINDING_PROTOCOL \r
394                                  instance.\r
395   @param[in]  ChildHandle        Handle of the child to destroy.\r
396 \r
397   @retval EFI_SUCCES             The protocol was removed from ChildHandle. \r
398   @retval EFI_UNSUPPORTED        ChildHandle does not support the protocol that\r
399                                  is being removed.\r
400   @retval EFI_INVALID_PARAMETER  ChildHandle is not a valid UEFI handle.\r
401   @retval EFI_ACCESS_DENIED      The protocol could not be removed from the\r
402                                  ChildHandle because its services are being\r
403                                  used.\r
404   @retval Others                 The child handle was not destroyed.\r
405 \r
406 **/\r
407 EFI_STATUS\r
408 EFIAPI\r
409 MnpServiceBindingDestroyChild (\r
410   IN EFI_SERVICE_BINDING_PROTOCOL  *This,\r
411   IN EFI_HANDLE                    ChildHandle\r
412   )\r
413 {\r
414   EFI_STATUS                    Status;\r
415   MNP_SERVICE_DATA              *MnpServiceData;\r
416   EFI_MANAGED_NETWORK_PROTOCOL  *ManagedNetwork;\r
417   MNP_INSTANCE_DATA             *Instance;\r
418   EFI_TPL                       OldTpl;\r
419 \r
420   if ((This == NULL) || (ChildHandle == NULL)) {\r
421 \r
422     return EFI_INVALID_PARAMETER;\r
423   }\r
424 \r
425   MnpServiceData = MNP_SERVICE_DATA_FROM_THIS (This);\r
426 \r
427   //\r
428   // Try to retrieve ManagedNetwork Protocol from ChildHandle.\r
429   //\r
430   Status = gBS->OpenProtocol (\r
431                   ChildHandle,\r
432                   &gEfiManagedNetworkProtocolGuid,\r
433                   (VOID **) &ManagedNetwork,\r
434                   gMnpDriverBinding.DriverBindingHandle,\r
435                   ChildHandle,\r
436                   EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
437                   );\r
438   if (EFI_ERROR (Status)) {\r
439 \r
440     return EFI_UNSUPPORTED;\r
441   }\r
442 \r
443   Instance = MNP_INSTANCE_DATA_FROM_THIS (ManagedNetwork);\r
444 \r
445   //\r
446   // MnpServiceBindingDestroyChild may be called twice: first called by\r
447   // MnpServiceBindingStop, second called by uninstalling the MNP protocol\r
448   // in this ChildHandle. Use destroyed to make sure the resource clean code\r
449   // will only excecute once.\r
450   //\r
451   if (Instance->Destroyed) {\r
452 \r
453     return EFI_SUCCESS;\r
454   }\r
455 \r
456   Instance->Destroyed = TRUE;\r
457 \r
458   //\r
459   // Close the Simple Network protocol.\r
460   //\r
461   gBS->CloseProtocol (\r
462          MnpServiceData->ControllerHandle,\r
463          &gEfiSimpleNetworkProtocolGuid,\r
464          gMnpDriverBinding.DriverBindingHandle,\r
465          ChildHandle\r
466          );\r
467 \r
468   //\r
469   // Uninstall the ManagedNetwork protocol.\r
470   //\r
471   Status = gBS->UninstallMultipleProtocolInterfaces (\r
472                   ChildHandle,\r
473                   &gEfiManagedNetworkProtocolGuid,\r
474                   &Instance->ManagedNetwork,\r
475                   NULL\r
476                   );\r
477   if (EFI_ERROR (Status)) {\r
478 \r
479     DEBUG (\r
480       (EFI_D_ERROR,\r
481       "MnpServiceBindingDestroyChild: Failed to uninstall the ManagedNetwork protocol, %r.\n",\r
482       Status)\r
483       );\r
484 \r
485     Instance->Destroyed = FALSE;\r
486     return Status;\r
487   }\r
488 \r
489   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
490 \r
491   //\r
492   // Reset the configuration.\r
493   //\r
494   ManagedNetwork->Configure (ManagedNetwork, NULL);\r
495 \r
496   //\r
497   // Try to flush the RcvdPacketQueue.\r
498   //\r
499   MnpFlushRcvdDataQueue (Instance);\r
500 \r
501   //\r
502   // Clean the RxTokenMap.\r
503   //\r
504   NetMapClean (&Instance->RxTokenMap);\r
505 \r
506   //\r
507   // Remove this instance from the ChildrenList.\r
508   //\r
509   RemoveEntryList (&Instance->InstEntry);\r
510   MnpServiceData->ChildrenNumber--;\r
511 \r
512   gBS->RestoreTPL (OldTpl);\r
513 \r
514   FreePool (Instance);\r
515 \r
516   return Status;\r
517 }\r
518 \r
519 /**\r
520   The entry point for Mnp driver which installs the driver binding and component\r
521   name protocol on its ImageHandle.\r
522 \r
523   @param[in]  ImageHandle  The image handle of the driver.\r
524   @param[in]  SystemTable  The system table.\r
525 \r
526   @retval EFI_SUCCES       The driver binding and component name protocols are \r
527                            successfully installed.\r
528   @retval Others           Other errors as indicated.\r
529 \r
530 **/\r
531 EFI_STATUS\r
532 EFIAPI\r
533 MnpDriverEntryPoint (\r
534   IN EFI_HANDLE        ImageHandle,\r
535   IN EFI_SYSTEM_TABLE  *SystemTable\r
536   )\r
537 {\r
538   return EfiLibInstallDriverBindingComponentName2 (\r
539            ImageHandle,\r
540            SystemTable,\r
541            &gMnpDriverBinding,\r
542            ImageHandle,\r
543            &gMnpComponentName,\r
544            &gMnpComponentName2\r
545            );\r
546 }\r