efi_snp.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00017  */
00018 
00019 FILE_LICENCE ( GPL2_OR_LATER );
00020 
00021 #include <stdlib.h>
00022 #include <string.h>
00023 #include <errno.h>
00024 #include <assert.h>
00025 #include <byteswap.h>
00026 #include <gpxe/netdevice.h>
00027 #include <gpxe/iobuf.h>
00028 #include <gpxe/in.h>
00029 #include <gpxe/pci.h>
00030 #include <gpxe/efi/efi.h>
00031 #include <gpxe/efi/Protocol/DriverBinding.h>
00032 #include <gpxe/efi/Protocol/PciIo.h>
00033 #include <gpxe/efi/Protocol/SimpleNetwork.h>
00034 #include <gpxe/efi/Protocol/ComponentName2.h>
00035 #include <gpxe/efi/Protocol/NetworkInterfaceIdentifier.h>
00036 #include <config/general.h>
00037 
00038 /** @file
00039  *
00040  * gPXE EFI SNP interface
00041  *
00042  */
00043 
00044 /** An SNP device */
00045 struct efi_snp_device {
00046         /** The underlying gPXE network device */
00047         struct net_device *netdev;
00048         /** EFI device handle */
00049         EFI_HANDLE handle;
00050         /** The SNP structure itself */
00051         EFI_SIMPLE_NETWORK_PROTOCOL snp;
00052         /** The SNP "mode" (parameters) */
00053         EFI_SIMPLE_NETWORK_MODE mode;
00054         /** Outstanding TX packet count (via "interrupt status")
00055          *
00056          * Used in order to generate TX completions.
00057          */
00058         unsigned int tx_count_interrupts;
00059         /** Outstanding TX packet count (via "recycled tx buffers")
00060          *
00061          * Used in order to generate TX completions.
00062          */
00063         unsigned int tx_count_txbufs;
00064         /** Outstanding RX packet count (via "interrupt status") */
00065         unsigned int rx_count_interrupts;
00066         /** Outstanding RX packet count (via WaitForPacket event) */
00067         unsigned int rx_count_events;
00068         /** The network interface identifier */
00069         EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL nii;
00070         /** Device name */
00071         wchar_t name[ sizeof ( ( ( struct net_device * ) NULL )->name ) ];
00072         /** The device path
00073          *
00074          * This field is variable in size and must appear at the end
00075          * of the structure.
00076          */
00077         EFI_DEVICE_PATH_PROTOCOL path;
00078 };
00079 
00080 /** EFI simple network protocol GUID */
00081 static EFI_GUID efi_simple_network_protocol_guid
00082         = EFI_SIMPLE_NETWORK_PROTOCOL_GUID;
00083 
00084 /** EFI driver binding protocol GUID */
00085 static EFI_GUID efi_driver_binding_protocol_guid
00086         = EFI_DRIVER_BINDING_PROTOCOL_GUID;
00087 
00088 /** EFI component name protocol GUID */
00089 static EFI_GUID efi_component_name2_protocol_guid
00090         = EFI_COMPONENT_NAME2_PROTOCOL_GUID;
00091 
00092 /** EFI device path protocol GUID */
00093 static EFI_GUID efi_device_path_protocol_guid
00094         = EFI_DEVICE_PATH_PROTOCOL_GUID;
00095 
00096 /** EFI network interface identifier GUID */
00097 static EFI_GUID efi_nii_protocol_guid
00098         = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_GUID;
00099 
00100 /** EFI network interface identifier GUID (extra special version) */
00101 static EFI_GUID efi_nii31_protocol_guid = {
00102         /* At some point, it seems that someone decided to change the
00103          * GUID.  Current EFI builds ignore the older GUID, older EFI
00104          * builds ignore the newer GUID, so we have to expose both.
00105          */
00106         0x1ACED566, 0x76ED, 0x4218,
00107         { 0xBC, 0x81, 0x76, 0x7F, 0x1F, 0x97, 0x7A, 0x89 }
00108 };
00109 
00110 /** EFI PCI I/O protocol GUID */
00111 static EFI_GUID efi_pci_io_protocol_guid
00112         = EFI_PCI_IO_PROTOCOL_GUID;
00113 
00114 /**
00115  * Set EFI SNP mode based on gPXE net device parameters
00116  *
00117  * @v snp               SNP interface
00118  */
00119 static void efi_snp_set_mode ( struct efi_snp_device *snpdev ) {
00120         struct net_device *netdev = snpdev->netdev;
00121         EFI_SIMPLE_NETWORK_MODE *mode = &snpdev->mode;
00122         struct ll_protocol *ll_protocol = netdev->ll_protocol;
00123         unsigned int ll_addr_len = ll_protocol->ll_addr_len;
00124 
00125         mode->HwAddressSize = ll_addr_len;
00126         mode->MediaHeaderSize = ll_protocol->ll_header_len;
00127         mode->MaxPacketSize = netdev->max_pkt_len;
00128         mode->ReceiveFilterMask = ( EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
00129                                     EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST |
00130                                     EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST );
00131         assert ( ll_addr_len <= sizeof ( mode->CurrentAddress ) );
00132         memcpy ( &mode->CurrentAddress, netdev->ll_addr, ll_addr_len );
00133         memcpy ( &mode->BroadcastAddress, netdev->ll_broadcast, ll_addr_len );
00134         ll_protocol->init_addr ( netdev->hw_addr, &mode->PermanentAddress );
00135         mode->IfType = ntohs ( ll_protocol->ll_proto );
00136         mode->MacAddressChangeable = TRUE;
00137         mode->MediaPresentSupported = TRUE;
00138         mode->MediaPresent = ( netdev_link_ok ( netdev ) ? TRUE : FALSE );
00139 }
00140 
00141 /**
00142  * Poll net device and count received packets
00143  *
00144  * @v snpdev            SNP device
00145  */
00146 static void efi_snp_poll ( struct efi_snp_device *snpdev ) {
00147         struct io_buffer *iobuf;
00148         unsigned int before = 0;
00149         unsigned int after = 0;
00150         unsigned int arrived;
00151 
00152         /* We have to report packet arrivals, and this is the easiest
00153          * way to fake it.
00154          */
00155         list_for_each_entry ( iobuf, &snpdev->netdev->rx_queue, list )
00156                 before++;
00157         netdev_poll ( snpdev->netdev );
00158         list_for_each_entry ( iobuf, &snpdev->netdev->rx_queue, list )
00159                 after++;
00160         arrived = ( after - before );
00161 
00162         snpdev->rx_count_interrupts += arrived;
00163         snpdev->rx_count_events += arrived;
00164 }
00165 
00166 /**
00167  * Change SNP state from "stopped" to "started"
00168  *
00169  * @v snp               SNP interface
00170  * @ret efirc           EFI status code
00171  */
00172 static EFI_STATUS EFIAPI
00173 efi_snp_start ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) {
00174         struct efi_snp_device *snpdev =
00175                 container_of ( snp, struct efi_snp_device, snp );
00176 
00177         DBGC2 ( snpdev, "SNPDEV %p START\n", snpdev );
00178 
00179         snpdev->mode.State = EfiSimpleNetworkStarted;
00180         return 0;
00181 }
00182 
00183 /**
00184  * Change SNP state from "started" to "stopped"
00185  *
00186  * @v snp               SNP interface
00187  * @ret efirc           EFI status code
00188  */
00189 static EFI_STATUS EFIAPI
00190 efi_snp_stop ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) {
00191         struct efi_snp_device *snpdev =
00192                 container_of ( snp, struct efi_snp_device, snp );
00193 
00194         DBGC2 ( snpdev, "SNPDEV %p STOP\n", snpdev );
00195 
00196         snpdev->mode.State = EfiSimpleNetworkStopped;
00197         return 0;
00198 }
00199 
00200 /**
00201  * Open the network device
00202  *
00203  * @v snp               SNP interface
00204  * @v extra_rx_bufsize  Extra RX buffer size, in bytes
00205  * @v extra_tx_bufsize  Extra TX buffer size, in bytes
00206  * @ret efirc           EFI status code
00207  */
00208 static EFI_STATUS EFIAPI
00209 efi_snp_initialize ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
00210                      UINTN extra_rx_bufsize, UINTN extra_tx_bufsize ) {
00211         struct efi_snp_device *snpdev =
00212                 container_of ( snp, struct efi_snp_device, snp );
00213         int rc;
00214 
00215         DBGC2 ( snpdev, "SNPDEV %p INITIALIZE (%ld extra RX, %ld extra TX)\n",
00216                 snpdev, ( ( unsigned long ) extra_rx_bufsize ),
00217                 ( ( unsigned long ) extra_tx_bufsize ) );
00218 
00219         if ( ( rc = netdev_open ( snpdev->netdev ) ) != 0 ) {
00220                 DBGC ( snpdev, "SNPDEV %p could not open %s: %s\n",
00221                        snpdev, snpdev->netdev->name, strerror ( rc ) );
00222                 return RC_TO_EFIRC ( rc );
00223         }
00224 
00225         snpdev->mode.State = EfiSimpleNetworkInitialized;
00226         return 0;
00227 }
00228 
00229 /**
00230  * Reset the network device
00231  *
00232  * @v snp               SNP interface
00233  * @v ext_verify        Extended verification required
00234  * @ret efirc           EFI status code
00235  */
00236 static EFI_STATUS EFIAPI
00237 efi_snp_reset ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN ext_verify ) {
00238         struct efi_snp_device *snpdev =
00239                 container_of ( snp, struct efi_snp_device, snp );
00240         int rc;
00241 
00242         DBGC2 ( snpdev, "SNPDEV %p RESET (%s extended verification)\n",
00243                 snpdev, ( ext_verify ? "with" : "without" ) );
00244 
00245         netdev_close ( snpdev->netdev );
00246         snpdev->mode.State = EfiSimpleNetworkStarted;
00247 
00248         if ( ( rc = netdev_open ( snpdev->netdev ) ) != 0 ) {
00249                 DBGC ( snpdev, "SNPDEV %p could not reopen %s: %s\n",
00250                        snpdev, snpdev->netdev->name, strerror ( rc ) );
00251                 return RC_TO_EFIRC ( rc );
00252         }
00253 
00254         snpdev->mode.State = EfiSimpleNetworkInitialized;
00255         return 0;
00256 }
00257 
00258 /**
00259  * Shut down the network device
00260  *
00261  * @v snp               SNP interface
00262  * @ret efirc           EFI status code
00263  */
00264 static EFI_STATUS EFIAPI
00265 efi_snp_shutdown ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) {
00266         struct efi_snp_device *snpdev =
00267                 container_of ( snp, struct efi_snp_device, snp );
00268 
00269         DBGC2 ( snpdev, "SNPDEV %p SHUTDOWN\n", snpdev );
00270 
00271         netdev_close ( snpdev->netdev );
00272         snpdev->mode.State = EfiSimpleNetworkStarted;
00273         return 0;
00274 }
00275 
00276 /**
00277  * Manage receive filters
00278  *
00279  * @v snp               SNP interface
00280  * @v enable            Receive filters to enable
00281  * @v disable           Receive filters to disable
00282  * @v mcast_reset       Reset multicast filters
00283  * @v mcast_count       Number of multicast filters
00284  * @v mcast             Multicast filters
00285  * @ret efirc           EFI status code
00286  */
00287 static EFI_STATUS EFIAPI
00288 efi_snp_receive_filters ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, UINT32 enable,
00289                           UINT32 disable, BOOLEAN mcast_reset,
00290                           UINTN mcast_count, EFI_MAC_ADDRESS *mcast ) {
00291         struct efi_snp_device *snpdev =
00292                 container_of ( snp, struct efi_snp_device, snp );
00293         unsigned int i;
00294 
00295         DBGC2 ( snpdev, "SNPDEV %p RECEIVE_FILTERS %08x&~%08x%s %ld mcast\n",
00296                 snpdev, enable, disable, ( mcast_reset ? " reset" : "" ),
00297                 ( ( unsigned long ) mcast_count ) );
00298         for ( i = 0 ; i < mcast_count ; i++ ) {
00299                 DBGC2_HDA ( snpdev, i, &mcast[i],
00300                             snpdev->netdev->ll_protocol->ll_addr_len );
00301         }
00302 
00303         /* Lie through our teeth, otherwise MNP refuses to accept us */
00304         return 0;
00305 }
00306 
00307 /**
00308  * Set station address
00309  *
00310  * @v snp               SNP interface
00311  * @v reset             Reset to permanent address
00312  * @v new               New station address
00313  * @ret efirc           EFI status code
00314  */
00315 static EFI_STATUS EFIAPI
00316 efi_snp_station_address ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN reset,
00317                           EFI_MAC_ADDRESS *new ) {
00318         struct efi_snp_device *snpdev =
00319                 container_of ( snp, struct efi_snp_device, snp );
00320         struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
00321 
00322         DBGC2 ( snpdev, "SNPDEV %p STATION_ADDRESS %s\n", snpdev,
00323                 ( reset ? "reset" : ll_protocol->ntoa ( new ) ) );
00324 
00325         /* Set the MAC address */
00326         if ( reset )
00327                 new = &snpdev->mode.PermanentAddress;
00328         memcpy ( snpdev->netdev->ll_addr, new, ll_protocol->ll_addr_len );
00329 
00330         /* MAC address changes take effect only on netdev_open() */
00331         if ( netdev_is_open ( snpdev->netdev ) ) {
00332                 DBGC ( snpdev, "SNPDEV %p MAC address changed while net "
00333                        "devive open\n", snpdev );
00334         }
00335 
00336         return 0;
00337 }
00338 
00339 /**
00340  * Get (or reset) statistics
00341  *
00342  * @v snp               SNP interface
00343  * @v reset             Reset statistics
00344  * @v stats_len         Size of statistics table
00345  * @v stats             Statistics table
00346  * @ret efirc           EFI status code
00347  */
00348 static EFI_STATUS EFIAPI
00349 efi_snp_statistics ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN reset,
00350                      UINTN *stats_len, EFI_NETWORK_STATISTICS *stats ) {
00351         struct efi_snp_device *snpdev =
00352                 container_of ( snp, struct efi_snp_device, snp );
00353         EFI_NETWORK_STATISTICS stats_buf;
00354 
00355         DBGC2 ( snpdev, "SNPDEV %p STATISTICS%s", snpdev,
00356                 ( reset ? " reset" : "" ) );
00357 
00358         /* Gather statistics */
00359         memset ( &stats_buf, 0, sizeof ( stats_buf ) );
00360         stats_buf.TxGoodFrames = snpdev->netdev->tx_stats.good;
00361         stats_buf.TxDroppedFrames = snpdev->netdev->tx_stats.bad;
00362         stats_buf.TxTotalFrames = ( snpdev->netdev->tx_stats.good +
00363                                     snpdev->netdev->tx_stats.bad );
00364         stats_buf.RxGoodFrames = snpdev->netdev->rx_stats.good;
00365         stats_buf.RxDroppedFrames = snpdev->netdev->rx_stats.bad;
00366         stats_buf.RxTotalFrames = ( snpdev->netdev->rx_stats.good +
00367                                     snpdev->netdev->rx_stats.bad );
00368         if ( *stats_len > sizeof ( stats_buf ) )
00369                 *stats_len = sizeof ( stats_buf );
00370         if ( stats )
00371                 memcpy ( stats, &stats_buf, *stats_len );
00372 
00373         /* Reset statistics if requested to do so */
00374         if ( reset ) {
00375                 memset ( &snpdev->netdev->tx_stats, 0,
00376                          sizeof ( snpdev->netdev->tx_stats ) );
00377                 memset ( &snpdev->netdev->rx_stats, 0,
00378                          sizeof ( snpdev->netdev->rx_stats ) );
00379         }
00380 
00381         return 0;
00382 }
00383 
00384 /**
00385  * Convert multicast IP address to MAC address
00386  *
00387  * @v snp               SNP interface
00388  * @v ipv6              Address is IPv6
00389  * @v ip                IP address
00390  * @v mac               MAC address
00391  * @ret efirc           EFI status code
00392  */
00393 static EFI_STATUS EFIAPI
00394 efi_snp_mcast_ip_to_mac ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN ipv6,
00395                           EFI_IP_ADDRESS *ip, EFI_MAC_ADDRESS *mac ) {
00396         struct efi_snp_device *snpdev =
00397                 container_of ( snp, struct efi_snp_device, snp );
00398         struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
00399         const char *ip_str;
00400         int rc;
00401 
00402         ip_str = ( ipv6 ? "(IPv6)" /* FIXME when we have inet6_ntoa() */ :
00403                    inet_ntoa ( *( ( struct in_addr * ) ip ) ) );
00404         DBGC2 ( snpdev, "SNPDEV %p MCAST_IP_TO_MAC %s\n", snpdev, ip_str );
00405 
00406         /* Try to hash the address */
00407         if ( ( rc = ll_protocol->mc_hash ( ( ipv6 ? AF_INET6 : AF_INET ),
00408                                            ip, mac ) ) != 0 ) {
00409                 DBGC ( snpdev, "SNPDEV %p could not hash %s: %s\n",
00410                        snpdev, ip_str, strerror ( rc ) );
00411                 return RC_TO_EFIRC ( rc );
00412         }
00413 
00414         return 0;
00415 }
00416 
00417 /**
00418  * Read or write non-volatile storage
00419  *
00420  * @v snp               SNP interface
00421  * @v read              Operation is a read
00422  * @v offset            Starting offset within NVRAM
00423  * @v len               Length of data buffer
00424  * @v data              Data buffer
00425  * @ret efirc           EFI status code
00426  */
00427 static EFI_STATUS EFIAPI
00428 efi_snp_nvdata ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN read,
00429                  UINTN offset, UINTN len, VOID *data ) {
00430         struct efi_snp_device *snpdev =
00431                 container_of ( snp, struct efi_snp_device, snp );
00432 
00433         DBGC2 ( snpdev, "SNPDEV %p NVDATA %s %lx+%lx\n", snpdev,
00434                 ( read ? "read" : "write" ), ( ( unsigned long ) offset ),
00435                 ( ( unsigned long ) len ) );
00436         if ( ! read )
00437                 DBGC2_HDA ( snpdev, offset, data, len );
00438 
00439         return EFI_UNSUPPORTED;
00440 }
00441 
00442 /**
00443  * Read interrupt status and TX recycled buffer status
00444  *
00445  * @v snp               SNP interface
00446  * @v interrupts        Interrupt status, or NULL
00447  * @v txbufs            Recycled transmit buffer address, or NULL
00448  * @ret efirc           EFI status code
00449  */
00450 static EFI_STATUS EFIAPI
00451 efi_snp_get_status ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
00452                      UINT32 *interrupts, VOID **txbufs ) {
00453         struct efi_snp_device *snpdev =
00454                 container_of ( snp, struct efi_snp_device, snp );
00455 
00456         DBGC2 ( snpdev, "SNPDEV %p GET_STATUS", snpdev );
00457 
00458         /* Poll the network device */
00459         efi_snp_poll ( snpdev );
00460 
00461         /* Interrupt status.  In practice, this seems to be used only
00462          * to detect TX completions.
00463          */
00464         if ( interrupts ) {
00465                 *interrupts = 0;
00466                 /* Report TX completions once queue is empty; this
00467                  * avoids having to add hooks in the net device layer.
00468                  */
00469                 if ( snpdev->tx_count_interrupts &&
00470                      list_empty ( &snpdev->netdev->tx_queue ) ) {
00471                         *interrupts |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
00472                         snpdev->tx_count_interrupts--;
00473                 }
00474                 /* Report RX */
00475                 if ( snpdev->rx_count_interrupts ) {
00476                         *interrupts |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
00477                         snpdev->rx_count_interrupts--;
00478                 }
00479                 DBGC2 ( snpdev, " INTS:%02x", *interrupts );
00480         }
00481 
00482         /* TX completions.  It would be possible to design a more
00483          * idiotic scheme for this, but it would be a challenge.
00484          * According to the UEFI header file, txbufs will be filled in
00485          * with a list of "recycled transmit buffers" (i.e. completed
00486          * TX buffers).  Observant readers may care to note that
00487          * *txbufs is a void pointer.  Precisely how a list of
00488          * completed transmit buffers is meant to be represented as an
00489          * array of voids is left as an exercise for the reader.
00490          *
00491          * The only users of this interface (MnpDxe/MnpIo.c and
00492          * PxeBcDxe/Bc.c within the EFI dev kit) both just poll until
00493          * seeing a non-NULL result return in txbufs.  This is valid
00494          * provided that they do not ever attempt to transmit more
00495          * than one packet concurrently (and that TX never times out).
00496          */
00497         if ( txbufs ) {
00498                 if ( snpdev->tx_count_txbufs &&
00499                      list_empty ( &snpdev->netdev->tx_queue ) ) {
00500                         *txbufs = "Which idiot designed this API?";
00501                         snpdev->tx_count_txbufs--;
00502                 } else {
00503                         *txbufs = NULL;
00504                 }
00505                 DBGC2 ( snpdev, " TX:%s", ( *txbufs ? "some" : "none" ) );
00506         }
00507 
00508         DBGC2 ( snpdev, "\n" );
00509         return 0;
00510 }
00511 
00512 /**
00513  * Start packet transmission
00514  *
00515  * @v snp               SNP interface
00516  * @v ll_header_len     Link-layer header length, if to be filled in
00517  * @v len               Length of data buffer
00518  * @v data              Data buffer
00519  * @v ll_src            Link-layer source address, if specified
00520  * @v ll_dest           Link-layer destination address, if specified
00521  * @v net_proto         Network-layer protocol (in host order)
00522  * @ret efirc           EFI status code
00523  */
00524 static EFI_STATUS EFIAPI
00525 efi_snp_transmit ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
00526                    UINTN ll_header_len, UINTN len, VOID *data,
00527                    EFI_MAC_ADDRESS *ll_src, EFI_MAC_ADDRESS *ll_dest,
00528                    UINT16 *net_proto ) {
00529         struct efi_snp_device *snpdev =
00530                 container_of ( snp, struct efi_snp_device, snp );
00531         struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
00532         struct io_buffer *iobuf;
00533         int rc;
00534         EFI_STATUS efirc;
00535 
00536         DBGC2 ( snpdev, "SNPDEV %p TRANSMIT %p+%lx", snpdev, data,
00537                 ( ( unsigned long ) len ) );
00538         if ( ll_header_len ) {
00539                 if ( ll_src ) {
00540                         DBGC2 ( snpdev, " src %s",
00541                                 ll_protocol->ntoa ( ll_src ) );
00542                 }
00543                 if ( ll_dest ) {
00544                         DBGC2 ( snpdev, " dest %s",
00545                                 ll_protocol->ntoa ( ll_dest ) );
00546                 }
00547                 if ( net_proto ) {
00548                         DBGC2 ( snpdev, " proto %04x", *net_proto );
00549                 }
00550         }
00551         DBGC2 ( snpdev, "\n" );
00552 
00553         /* Sanity checks */
00554         if ( ll_header_len ) {
00555                 if ( ll_header_len != ll_protocol->ll_header_len ) {
00556                         DBGC ( snpdev, "SNPDEV %p TX invalid header length "
00557                                "%ld\n", snpdev,
00558                                ( ( unsigned long ) ll_header_len ) );
00559                         efirc = EFI_INVALID_PARAMETER;
00560                         goto err_sanity;
00561                 }
00562                 if ( len < ll_header_len ) {
00563                         DBGC ( snpdev, "SNPDEV %p invalid packet length %ld\n",
00564                                snpdev, ( ( unsigned long ) len ) );
00565                         efirc = EFI_BUFFER_TOO_SMALL;
00566                         goto err_sanity;
00567                 }
00568                 if ( ! ll_dest ) {
00569                         DBGC ( snpdev, "SNPDEV %p TX missing destination "
00570                                "address\n", snpdev );
00571                         efirc = EFI_INVALID_PARAMETER;
00572                         goto err_sanity;
00573                 }
00574                 if ( ! net_proto ) {
00575                         DBGC ( snpdev, "SNPDEV %p TX missing network "
00576                                "protocol\n", snpdev );
00577                         efirc = EFI_INVALID_PARAMETER;
00578                         goto err_sanity;
00579                 }
00580                 if ( ! ll_src )
00581                         ll_src = &snpdev->mode.CurrentAddress;
00582         }
00583 
00584         /* Allocate buffer */
00585         iobuf = alloc_iob ( len );
00586         if ( ! iobuf ) {
00587                 DBGC ( snpdev, "SNPDEV %p TX could not allocate %ld-byte "
00588                        "buffer\n", snpdev, ( ( unsigned long ) len ) );
00589                 efirc = EFI_DEVICE_ERROR;
00590                 goto err_alloc_iob;
00591         }
00592         memcpy ( iob_put ( iobuf, len ), data, len );
00593 
00594         /* Create link-layer header, if specified */
00595         if ( ll_header_len ) {
00596                 iob_pull ( iobuf, ll_header_len );
00597                 if ( ( rc = ll_protocol->push ( snpdev->netdev,
00598                                                 iobuf, ll_dest, ll_src,
00599                                                 htons ( *net_proto ) )) != 0 ){
00600                         DBGC ( snpdev, "SNPDEV %p TX could not construct "
00601                                "header: %s\n", snpdev, strerror ( rc ) );
00602                         efirc = RC_TO_EFIRC ( rc );
00603                         goto err_ll_push;
00604                 }
00605         }
00606 
00607         /* Transmit packet */
00608         if ( ( rc = netdev_tx ( snpdev->netdev, iob_disown ( iobuf ) ) ) != 0){
00609                 DBGC ( snpdev, "SNPDEV %p TX could not transmit: %s\n",
00610                        snpdev, strerror ( rc ) );
00611                 efirc = RC_TO_EFIRC ( rc );
00612                 goto err_tx;
00613         }
00614 
00615         /* Record transmission as outstanding */
00616         snpdev->tx_count_interrupts++;
00617         snpdev->tx_count_txbufs++;
00618 
00619         return 0;
00620 
00621  err_tx:
00622  err_ll_push:
00623         free_iob ( iobuf );
00624  err_alloc_iob:
00625  err_sanity:
00626         return efirc;
00627 }
00628 
00629 /**
00630  * Receive packet
00631  *
00632  * @v snp               SNP interface
00633  * @v ll_header_len     Link-layer header length, if to be filled in
00634  * @v len               Length of data buffer
00635  * @v data              Data buffer
00636  * @v ll_src            Link-layer source address, if specified
00637  * @v ll_dest           Link-layer destination address, if specified
00638  * @v net_proto         Network-layer protocol (in host order)
00639  * @ret efirc           EFI status code
00640  */
00641 static EFI_STATUS EFIAPI
00642 efi_snp_receive ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
00643                   UINTN *ll_header_len, UINTN *len, VOID *data,
00644                   EFI_MAC_ADDRESS *ll_src, EFI_MAC_ADDRESS *ll_dest,
00645                   UINT16 *net_proto ) {
00646         struct efi_snp_device *snpdev =
00647                 container_of ( snp, struct efi_snp_device, snp );
00648         struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
00649         struct io_buffer *iobuf;
00650         const void *iob_ll_dest;
00651         const void *iob_ll_src;
00652         uint16_t iob_net_proto;
00653         int rc;
00654         EFI_STATUS efirc;
00655 
00656         DBGC2 ( snpdev, "SNPDEV %p RECEIVE %p(+%lx)", snpdev, data,
00657                 ( ( unsigned long ) *len ) );
00658 
00659         /* Poll the network device */
00660         efi_snp_poll ( snpdev );
00661 
00662         /* Dequeue a packet, if one is available */
00663         iobuf = netdev_rx_dequeue ( snpdev->netdev );
00664         if ( ! iobuf ) {
00665                 DBGC2 ( snpdev, "\n" );
00666                 efirc = EFI_NOT_READY;
00667                 goto out_no_packet;
00668         }
00669         DBGC2 ( snpdev, "+%zx\n", iob_len ( iobuf ) );
00670 
00671         /* Return packet to caller */
00672         memcpy ( data, iobuf->data, iob_len ( iobuf ) );
00673         *len = iob_len ( iobuf );
00674 
00675         /* Attempt to decode link-layer header */
00676         if ( ( rc = ll_protocol->pull ( snpdev->netdev, iobuf, &iob_ll_dest,
00677                                         &iob_ll_src, &iob_net_proto ) ) != 0 ){
00678                 DBGC ( snpdev, "SNPDEV %p could not parse header: %s\n",
00679                        snpdev, strerror ( rc ) );
00680                 efirc = RC_TO_EFIRC ( rc );
00681                 goto out_bad_ll_header;
00682         }
00683 
00684         /* Return link-layer header parameters to caller, if required */
00685         if ( ll_header_len )
00686                 *ll_header_len = ll_protocol->ll_header_len;
00687         if ( ll_src )
00688                 memcpy ( ll_src, iob_ll_src, ll_protocol->ll_addr_len );
00689         if ( ll_dest )
00690                 memcpy ( ll_dest, iob_ll_dest, ll_protocol->ll_addr_len );
00691         if ( net_proto )
00692                 *net_proto = ntohs ( iob_net_proto );
00693 
00694         efirc = 0;
00695 
00696  out_bad_ll_header:
00697         free_iob ( iobuf );
00698 out_no_packet:
00699         return efirc;
00700 }
00701 
00702 /**
00703  * Poll event
00704  *
00705  * @v event             Event
00706  * @v context           Event context
00707  */
00708 static VOID EFIAPI efi_snp_wait_for_packet ( EFI_EVENT event,
00709                                              VOID *context ) {
00710         EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
00711         struct efi_snp_device *snpdev = context;
00712 
00713         DBGCP ( snpdev, "SNPDEV %p WAIT_FOR_PACKET\n", snpdev );
00714 
00715         /* Do nothing unless the net device is open */
00716         if ( ! netdev_is_open ( snpdev->netdev ) )
00717                 return;
00718 
00719         /* Poll the network device */
00720         efi_snp_poll ( snpdev );
00721 
00722         /* Fire event if packets have been received */
00723         if ( snpdev->rx_count_events != 0 ) {
00724                 DBGC2 ( snpdev, "SNPDEV %p firing WaitForPacket event\n",
00725                         snpdev );
00726                 bs->SignalEvent ( event );
00727                 snpdev->rx_count_events--;
00728         }
00729 }
00730 
00731 /** SNP interface */
00732 static EFI_SIMPLE_NETWORK_PROTOCOL efi_snp_device_snp = {
00733         .Revision       = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION,
00734         .Start          = efi_snp_start,
00735         .Stop           = efi_snp_stop,
00736         .Initialize     = efi_snp_initialize,
00737         .Reset          = efi_snp_reset,
00738         .Shutdown       = efi_snp_shutdown,
00739         .ReceiveFilters = efi_snp_receive_filters,
00740         .StationAddress = efi_snp_station_address,
00741         .Statistics     = efi_snp_statistics,
00742         .MCastIpToMac   = efi_snp_mcast_ip_to_mac,
00743         .NvData         = efi_snp_nvdata,
00744         .GetStatus      = efi_snp_get_status,
00745         .Transmit       = efi_snp_transmit,
00746         .Receive        = efi_snp_receive,
00747 };
00748 
00749 /**
00750  * Locate net device corresponding to EFI device
00751  *
00752  * @v driver            EFI driver
00753  * @v device            EFI device
00754  * @ret netdev          Net device, or NULL if not found
00755  */
00756 static struct net_device *
00757 efi_snp_netdev ( EFI_DRIVER_BINDING_PROTOCOL *driver, EFI_HANDLE device ) {
00758         EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
00759         union {
00760                 EFI_PCI_IO_PROTOCOL *pci;
00761                 void *interface;
00762         } u;
00763         UINTN pci_segment, pci_bus, pci_dev, pci_fn;
00764         unsigned int pci_busdevfn;
00765         struct net_device *netdev = NULL;
00766         EFI_STATUS efirc;
00767 
00768         /* See if device is a PCI device */
00769         if ( ( efirc = bs->OpenProtocol ( device,
00770                                           &efi_pci_io_protocol_guid,
00771                                           &u.interface,
00772                                           driver->DriverBindingHandle,
00773                                           device,
00774                                           EFI_OPEN_PROTOCOL_BY_DRIVER )) !=0 ){
00775                 DBGCP ( driver, "SNPDRV %p device %p is not a PCI device\n",
00776                         driver, device );
00777                 goto out_no_pci_io;
00778         }
00779 
00780         /* Get PCI bus:dev.fn address */
00781         if ( ( efirc = u.pci->GetLocation ( u.pci, &pci_segment, &pci_bus,
00782                                             &pci_dev, &pci_fn ) ) != 0 ) {
00783                 DBGC ( driver, "SNPDRV %p device %p could not get PCI "
00784                        "location: %s\n",
00785                        driver, device, efi_strerror ( efirc ) );
00786                 goto out_no_pci_location;
00787         }
00788         DBGCP ( driver, "SNPDRV %p device %p is PCI %04lx:%02lx:%02lx.%lx\n",
00789                 driver, device, ( ( unsigned long ) pci_segment ),
00790                 ( ( unsigned long ) pci_bus ), ( ( unsigned long ) pci_dev ),
00791                 ( ( unsigned long ) pci_fn ) );
00792 
00793         /* Look up corresponding network device */
00794         pci_busdevfn = PCI_BUSDEVFN ( pci_bus, PCI_DEVFN ( pci_dev, pci_fn ) );
00795         if ( ( netdev = find_netdev_by_location ( BUS_TYPE_PCI,
00796                                                   pci_busdevfn ) ) == NULL ) {
00797                 DBGCP ( driver, "SNPDRV %p device %p is not a gPXE network "
00798                         "device\n", driver, device );
00799                 goto out_no_netdev;
00800         }
00801         DBGC ( driver, "SNPDRV %p device %p is %s\n",
00802                driver, device, netdev->name );
00803 
00804  out_no_netdev:
00805  out_no_pci_location:
00806         bs->CloseProtocol ( device, &efi_pci_io_protocol_guid,
00807                             driver->DriverBindingHandle, device );
00808  out_no_pci_io:
00809         return netdev;
00810 }
00811 
00812 /**
00813  * Locate SNP corresponding to EFI device
00814  *
00815  * @v driver            EFI driver
00816  * @v device            EFI device
00817  * @ret snp             EFI SNP, or NULL if not found
00818  */
00819 static struct efi_snp_device *
00820 efi_snp_snpdev ( EFI_DRIVER_BINDING_PROTOCOL *driver, EFI_HANDLE device ) {
00821         EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
00822         union {
00823                 EFI_SIMPLE_NETWORK_PROTOCOL *snp;
00824                 void *interface;
00825         } u;
00826         struct efi_snp_device *snpdev = NULL;
00827         EFI_STATUS efirc;
00828 
00829         if ( ( efirc = bs->OpenProtocol ( device,
00830                                           &efi_simple_network_protocol_guid,
00831                                           &u.interface,
00832                                           driver->DriverBindingHandle,
00833                                           device,
00834                                           EFI_OPEN_PROTOCOL_GET_PROTOCOL))!=0){
00835                 DBGC ( driver, "SNPDRV %p device %p could not locate SNP: "
00836                        "%s\n", driver, device, efi_strerror ( efirc ) );
00837                 goto err_no_snp;
00838         }
00839 
00840         snpdev =  container_of ( u.snp, struct efi_snp_device, snp );
00841         DBGCP ( driver, "SNPDRV %p device %p is SNPDEV %p\n",
00842                 driver, device, snpdev );
00843 
00844         bs->CloseProtocol ( device, &efi_simple_network_protocol_guid,
00845                             driver->DriverBindingHandle, device );
00846  err_no_snp:
00847         return snpdev;
00848 }
00849 
00850 /**
00851  * Check to see if driver supports a device
00852  *
00853  * @v driver            EFI driver
00854  * @v device            EFI device
00855  * @v child             Path to child device, if any
00856  * @ret efirc           EFI status code
00857  */
00858 static EFI_STATUS EFIAPI
00859 efi_snp_driver_supported ( EFI_DRIVER_BINDING_PROTOCOL *driver,
00860                            EFI_HANDLE device,
00861                            EFI_DEVICE_PATH_PROTOCOL *child ) {
00862         struct net_device *netdev;
00863 
00864         DBGCP ( driver, "SNPDRV %p DRIVER_SUPPORTED %p (%p)\n",
00865                 driver, device, child );
00866 
00867         netdev = efi_snp_netdev ( driver, device );
00868         return ( netdev ? 0 : EFI_UNSUPPORTED );
00869 }
00870 
00871 /**
00872  * Attach driver to device
00873  *
00874  * @v driver            EFI driver
00875  * @v device            EFI device
00876  * @v child             Path to child device, if any
00877  * @ret efirc           EFI status code
00878  */
00879 static EFI_STATUS EFIAPI
00880 efi_snp_driver_start ( EFI_DRIVER_BINDING_PROTOCOL *driver,
00881                        EFI_HANDLE device,
00882                        EFI_DEVICE_PATH_PROTOCOL *child ) {
00883         EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
00884         EFI_DEVICE_PATH_PROTOCOL *path;
00885         EFI_DEVICE_PATH_PROTOCOL *subpath;
00886         MAC_ADDR_DEVICE_PATH *macpath;
00887         struct efi_snp_device *snpdev;
00888         struct net_device *netdev;
00889         size_t subpath_len;
00890         size_t path_prefix_len = 0;
00891         unsigned int i;
00892         EFI_STATUS efirc;
00893 
00894         DBGCP ( driver, "SNPDRV %p DRIVER_START %p (%p)\n",
00895                 driver, device, child );
00896 
00897         /* Determine device path prefix length */
00898         if ( ( efirc = bs->OpenProtocol ( device,
00899                                           &efi_device_path_protocol_guid,
00900                                           ( void * ) &path,
00901                                           driver->DriverBindingHandle,
00902                                           device,
00903                                           EFI_OPEN_PROTOCOL_BY_DRIVER )) !=0 ){
00904                 DBGCP ( driver, "SNPDRV %p device %p has no device path\n",
00905                         driver, device );
00906                 goto err_no_device_path;
00907         }
00908         subpath = path;
00909         while ( subpath->Type != END_DEVICE_PATH_TYPE ) {
00910                 subpath_len = ( ( subpath->Length[1] << 8 ) |
00911                                 subpath->Length[0] );
00912                 path_prefix_len += subpath_len;
00913                 subpath = ( ( ( void * ) subpath ) + subpath_len );
00914         }
00915 
00916         /* Allocate the SNP device */
00917         snpdev = zalloc ( sizeof ( *snpdev ) + path_prefix_len +
00918                           sizeof ( *macpath ) );
00919         if ( ! snpdev ) {
00920                 efirc = EFI_OUT_OF_RESOURCES;
00921                 goto err_alloc_snp;
00922         }
00923 
00924         /* Identify the net device */
00925         netdev = efi_snp_netdev ( driver, device );
00926         if ( ! netdev ) {
00927                 DBGC ( snpdev, "SNPDEV %p cannot find netdev for device %p\n",
00928                        snpdev, device );
00929                 efirc = EFI_UNSUPPORTED;
00930                 goto err_no_netdev;
00931         }
00932         snpdev->netdev = netdev_get ( netdev );
00933 
00934         /* Sanity check */
00935         if ( netdev->ll_protocol->ll_addr_len > sizeof ( EFI_MAC_ADDRESS ) ) {
00936                 DBGC ( snpdev, "SNPDEV %p cannot support link-layer address "
00937                        "length %d for %s\n", snpdev,
00938                        netdev->ll_protocol->ll_addr_len, netdev->name );
00939                 efirc = EFI_INVALID_PARAMETER;
00940                 goto err_ll_addr_len;
00941         }
00942 
00943         /* Populate the SNP structure */
00944         memcpy ( &snpdev->snp, &efi_snp_device_snp, sizeof ( snpdev->snp ) );
00945         snpdev->snp.Mode = &snpdev->mode;
00946         if ( ( efirc = bs->CreateEvent ( EVT_NOTIFY_WAIT, TPL_NOTIFY,
00947                                          efi_snp_wait_for_packet, snpdev,
00948                                          &snpdev->snp.WaitForPacket ) ) != 0 ){
00949                 DBGC ( snpdev, "SNPDEV %p could not create event: %s\n",
00950                        snpdev, efi_strerror ( efirc ) );
00951                 goto err_create_event;
00952         }
00953 
00954         /* Populate the SNP mode structure */
00955         snpdev->mode.State = EfiSimpleNetworkStopped;
00956         efi_snp_set_mode ( snpdev );
00957 
00958         /* Populate the NII structure */
00959         snpdev->nii.Revision =
00960                 EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION;
00961         strncpy ( snpdev->nii.StringId, "gPXE",
00962                   sizeof ( snpdev->nii.StringId ) );
00963 
00964         /* Populate the device name */
00965         for ( i = 0 ; i < sizeof ( netdev->name ) ; i++ ) {
00966                 /* Damn Unicode names */
00967                 assert ( i < ( sizeof ( snpdev->name ) /
00968                                sizeof ( snpdev->name[0] ) ) );
00969                 snpdev->name[i] = netdev->name[i];
00970         }
00971 
00972         /* Populate the device path */
00973         memcpy ( &snpdev->path, path, path_prefix_len );
00974         macpath = ( ( ( void * ) &snpdev->path ) + path_prefix_len );
00975         subpath = ( ( void * ) ( macpath + 1 ) );
00976         memset ( macpath, 0, sizeof ( *macpath ) );
00977         macpath->Header.Type = MESSAGING_DEVICE_PATH;
00978         macpath->Header.SubType = MSG_MAC_ADDR_DP;
00979         macpath->Header.Length[0] = sizeof ( *macpath );
00980         memcpy ( &macpath->MacAddress, netdev->ll_addr,
00981                  sizeof ( macpath->MacAddress ) );
00982         macpath->IfType = ntohs ( netdev->ll_protocol->ll_proto );
00983         memset ( subpath, 0, sizeof ( *subpath ) );
00984         subpath->Type = END_DEVICE_PATH_TYPE;
00985         subpath->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
00986         subpath->Length[0] = sizeof ( *subpath );
00987 
00988         /* Install the SNP */
00989         if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
00990                         &snpdev->handle,
00991                         &efi_simple_network_protocol_guid, &snpdev->snp,
00992                         &efi_device_path_protocol_guid, &snpdev->path,
00993                         &efi_nii_protocol_guid, &snpdev->nii,
00994                         &efi_nii31_protocol_guid, &snpdev->nii,
00995                         NULL ) ) != 0 ) {
00996                 DBGC ( snpdev, "SNPDEV %p could not install protocols: "
00997                        "%s\n", snpdev, efi_strerror ( efirc ) );
00998                 goto err_install_protocol_interface;
00999         }
01000 
01001         DBGC ( snpdev, "SNPDEV %p installed for %s as device %p\n",
01002                snpdev, netdev->name, snpdev->handle );
01003         return 0;
01004 
01005         bs->UninstallMultipleProtocolInterfaces (
01006                         snpdev->handle,
01007                         &efi_simple_network_protocol_guid, &snpdev->snp,
01008                         &efi_device_path_protocol_guid, &snpdev->path,
01009                         &efi_nii_protocol_guid, &snpdev->nii,
01010                         &efi_nii31_protocol_guid, &snpdev->nii,
01011                         NULL );
01012  err_install_protocol_interface:
01013         bs->CloseEvent ( snpdev->snp.WaitForPacket );
01014  err_create_event:
01015  err_ll_addr_len:
01016         netdev_put ( netdev );
01017  err_no_netdev:
01018         free ( snpdev );
01019  err_alloc_snp:
01020         bs->CloseProtocol ( device, &efi_device_path_protocol_guid,
01021                             driver->DriverBindingHandle, device );
01022  err_no_device_path:
01023         return efirc;
01024 }
01025 
01026 /**
01027  * Detach driver from device
01028  *
01029  * @v driver            EFI driver
01030  * @v device            EFI device
01031  * @v num_children      Number of child devices
01032  * @v children          List of child devices
01033  * @ret efirc           EFI status code
01034  */
01035 static EFI_STATUS EFIAPI
01036 efi_snp_driver_stop ( EFI_DRIVER_BINDING_PROTOCOL *driver,
01037                       EFI_HANDLE device,
01038                       UINTN num_children,
01039                       EFI_HANDLE *children ) {
01040         EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
01041         struct efi_snp_device *snpdev;
01042 
01043         DBGCP ( driver, "SNPDRV %p DRIVER_STOP %p (%ld %p)\n",
01044                 driver, device, ( ( unsigned long ) num_children ), children );
01045 
01046         /* Locate SNP device */
01047         snpdev = efi_snp_snpdev ( driver, device );
01048         if ( ! snpdev ) {
01049                 DBGC ( driver, "SNPDRV %p device %p could not find SNPDEV\n",
01050                        driver, device );
01051                 return EFI_DEVICE_ERROR;
01052         }
01053 
01054         /* Uninstall the SNP */
01055         bs->UninstallMultipleProtocolInterfaces (
01056                         snpdev->handle,
01057                         &efi_simple_network_protocol_guid, &snpdev->snp,
01058                         &efi_device_path_protocol_guid, &snpdev->path,
01059                         &efi_nii_protocol_guid, &snpdev->nii,
01060                         &efi_nii31_protocol_guid, &snpdev->nii,
01061                         NULL );
01062         bs->CloseEvent ( snpdev->snp.WaitForPacket );
01063         netdev_put ( snpdev->netdev );
01064         free ( snpdev );
01065         bs->CloseProtocol ( device, &efi_device_path_protocol_guid,
01066                             driver->DriverBindingHandle, device );
01067         return 0;
01068 }
01069 
01070 /** EFI SNP driver binding */
01071 static EFI_DRIVER_BINDING_PROTOCOL efi_snp_binding = {
01072         efi_snp_driver_supported,
01073         efi_snp_driver_start,
01074         efi_snp_driver_stop,
01075         0x10,
01076         NULL,
01077         NULL
01078 };
01079 
01080 /**
01081  * Look up driver name
01082  *
01083  * @v wtf               Component name protocol
01084  * @v language          Language to use
01085  * @v driver_name       Driver name to fill in
01086  * @ret efirc           EFI status code
01087  */
01088 static EFI_STATUS EFIAPI
01089 efi_snp_get_driver_name ( EFI_COMPONENT_NAME2_PROTOCOL *wtf __unused,
01090                           CHAR8 *language __unused, CHAR16 **driver_name ) {
01091 
01092         *driver_name = L"" PRODUCT_SHORT_NAME " Driver";
01093         return 0;
01094 }
01095 
01096 /**
01097  * Look up controller name
01098  *
01099  * @v wtf               Component name protocol
01100  * @v device            Device
01101  * @v child             Child device, or NULL
01102  * @v language          Language to use
01103  * @v driver_name       Device name to fill in
01104  * @ret efirc           EFI status code
01105  */
01106 static EFI_STATUS EFIAPI
01107 efi_snp_get_controller_name ( EFI_COMPONENT_NAME2_PROTOCOL *wtf __unused,
01108                               EFI_HANDLE device __unused,
01109                               EFI_HANDLE child __unused,
01110                               CHAR8 *language __unused,
01111                               CHAR16 **controller_name __unused ) {
01112 
01113         /* Just let EFI use the default Device Path Name */
01114         return EFI_UNSUPPORTED;
01115 }
01116 
01117 /** EFI SNP component name protocol */
01118 static EFI_COMPONENT_NAME2_PROTOCOL efi_snp_name = {
01119         efi_snp_get_driver_name,
01120         efi_snp_get_controller_name,
01121         "en"
01122 };
01123 
01124 /**
01125  * Install EFI SNP driver
01126  *
01127  * @ret rc              Return status code
01128  */
01129 int efi_snp_install ( void ) {
01130         EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
01131         EFI_DRIVER_BINDING_PROTOCOL *driver = &efi_snp_binding;
01132         EFI_STATUS efirc;
01133 
01134         driver->ImageHandle = efi_image_handle;
01135         if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
01136                         &driver->DriverBindingHandle,
01137                         &efi_driver_binding_protocol_guid, driver,
01138                         &efi_component_name2_protocol_guid, &efi_snp_name,
01139                         NULL ) ) != 0 ) {
01140                 DBGC ( driver, "SNPDRV %p could not install protocols: "
01141                        "%s\n", driver, efi_strerror ( efirc ) );
01142                 return EFIRC_TO_RC ( efirc );
01143         }
01144 
01145         DBGC ( driver, "SNPDRV %p driver binding installed as %p\n",
01146                driver, driver->DriverBindingHandle );
01147         return 0;
01148 }

Generated on Tue Apr 6 20:01:09 2010 for gPXE by  doxygen 1.5.7.1