iPXE
undionly.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2007 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., 51 Franklin Street, Fifth Floor, Boston, MA
00017  * 02110-1301, USA.
00018  *
00019  * You can also choose to distribute this program under the terms of
00020  * the Unmodified Binary Distribution Licence (as given in the file
00021  * COPYING.UBDL), provided that you have satisfied its requirements.
00022  */
00023 
00024 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00025 
00026 #include <stdint.h>
00027 #include <stdlib.h>
00028 #include <stdio.h>
00029 #include <string.h>
00030 #include <ipxe/device.h>
00031 #include <ipxe/init.h>
00032 #include <ipxe/pci.h>
00033 #include <undi.h>
00034 #include <undinet.h>
00035 #include <undipreload.h>
00036 
00037 /** @file
00038  *
00039  * "Pure" UNDI driver
00040  *
00041  * This is the UNDI driver without explicit support for PCI or any
00042  * other bus type.  It is capable only of using the preloaded UNDI
00043  * device.  It must not be combined in an image with any other
00044  * drivers.
00045  *
00046  * If you want a PXE-loadable image that contains only the UNDI
00047  * driver, build "bin/undionly.kpxe".
00048  *
00049  * If you want any other image format, or any other drivers in
00050  * addition to the UNDI driver, build e.g. "bin/undi.dsk".
00051  */
00052 
00053 /** UNDI root bus device */
00054 static struct device undibus_dev;
00055 
00056 /**
00057  * Probe UNDI root bus
00058  *
00059  * @v rootdev           UNDI bus root device
00060  *
00061  * Scans the UNDI bus for devices and registers all devices it can
00062  * find.
00063  */
00064 static int undibus_probe ( struct root_device *rootdev ) {
00065         struct undi_device *undi = &preloaded_undi;
00066         struct device *dev = &undibus_dev;
00067         int rc;
00068 
00069         /* Check for a valie preloaded UNDI device */
00070         if ( ! undi->entry.segment ) {
00071                 DBG ( "No preloaded UNDI device found!\n" );
00072                 return -ENODEV;
00073         }
00074 
00075         /* Add to device hierarchy */
00076         dev->driver_name = "undionly";
00077         if ( undi->pci_busdevfn != UNDI_NO_PCI_BUSDEVFN ) {
00078                 dev->desc.bus_type = BUS_TYPE_PCI;
00079                 dev->desc.location = undi->pci_busdevfn;
00080                 dev->desc.vendor = undi->pci_vendor;
00081                 dev->desc.device = undi->pci_device;
00082                 snprintf ( dev->name, sizeof ( dev->name ),
00083                            "0000:%02x:%02x.%x", PCI_BUS ( undi->pci_busdevfn ),
00084                            PCI_SLOT ( undi->pci_busdevfn ),
00085                            PCI_FUNC ( undi->pci_busdevfn ) );
00086         } else if ( undi->isapnp_csn != UNDI_NO_ISAPNP_CSN ) {
00087                 dev->desc.bus_type = BUS_TYPE_ISAPNP;
00088                 snprintf ( dev->name, sizeof ( dev->name ), "ISAPNP" );
00089         }
00090         dev->parent = &rootdev->dev;
00091         list_add ( &dev->siblings, &rootdev->dev.children);
00092         INIT_LIST_HEAD ( &dev->children );
00093 
00094         /* Create network device */
00095         if ( ( rc = undinet_probe ( undi, dev ) ) != 0 )
00096                 goto err;
00097 
00098         return 0;
00099 
00100  err:
00101         list_del ( &dev->siblings );
00102         return rc;
00103 }
00104 
00105 /**
00106  * Remove UNDI root bus
00107  *
00108  * @v rootdev           UNDI bus root device
00109  */
00110 static void undibus_remove ( struct root_device *rootdev __unused ) {
00111         struct undi_device *undi = &preloaded_undi;
00112         struct device *dev = &undibus_dev;
00113 
00114         undinet_remove ( undi );
00115         list_del ( &dev->siblings );
00116 }
00117 
00118 /** UNDI bus root device driver */
00119 static struct root_driver undi_root_driver = {
00120         .probe = undibus_probe,
00121         .remove = undibus_remove,
00122 };
00123 
00124 /** UNDI bus root device */
00125 struct root_device undi_root_device __root_device = {
00126         .dev = { .name = "UNDI" },
00127         .driver = &undi_root_driver,
00128 };
00129 
00130 /**
00131  * Prepare for exit
00132  *
00133  * @v booting           System is shutting down for OS boot
00134  */
00135 static void undionly_shutdown ( int booting ) {
00136         /* If we are shutting down to boot an OS, clear the "keep PXE
00137          * stack" flag.
00138          */
00139         if ( booting )
00140                 preloaded_undi.flags &= ~UNDI_FL_KEEP_ALL;
00141 }
00142 
00143 struct startup_fn startup_undionly __startup_fn ( STARTUP_LATE ) = {
00144         .shutdown = undionly_shutdown,
00145 };