iPXE
device.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2006 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 <string.h>
00027 #include <ipxe/list.h>
00028 #include <ipxe/tables.h>
00029 #include <ipxe/init.h>
00030 #include <ipxe/interface.h>
00031 #include <ipxe/device.h>
00032 
00033 /**
00034  * @file
00035  *
00036  * Device model
00037  *
00038  */
00039 
00040 /** Registered root devices */
00041 static LIST_HEAD ( devices );
00042 
00043 /** Device removal inhibition counter */
00044 int device_keep_count = 0;
00045 
00046 /**
00047  * Probe a root device
00048  *
00049  * @v rootdev           Root device
00050  * @ret rc              Return status code
00051  */
00052 static int rootdev_probe ( struct root_device *rootdev ) {
00053         int rc;
00054 
00055         DBG ( "Adding %s root bus\n", rootdev->dev.name );
00056         if ( ( rc = rootdev->driver->probe ( rootdev ) ) != 0 ) {
00057                 DBG ( "Failed to add %s root bus: %s\n",
00058                       rootdev->dev.name, strerror ( rc ) );
00059                 return rc;
00060         }
00061 
00062         return 0;
00063 }
00064 
00065 /**
00066  * Remove a root device
00067  *
00068  * @v rootdev           Root device
00069  */
00070 static void rootdev_remove ( struct root_device *rootdev ) {
00071         rootdev->driver->remove ( rootdev );
00072         DBG ( "Removed %s root bus\n", rootdev->dev.name );
00073 }
00074 
00075 /**
00076  * Probe all devices
00077  *
00078  * This initiates probing for all devices in the system.  After this
00079  * call, the device hierarchy will be populated, and all hardware
00080  * should be ready to use.
00081  */
00082 static void probe_devices ( void ) {
00083         struct root_device *rootdev;
00084         int rc;
00085 
00086         for_each_table_entry ( rootdev, ROOT_DEVICES ) {
00087                 list_add ( &rootdev->dev.siblings, &devices );
00088                 INIT_LIST_HEAD ( &rootdev->dev.children );
00089                 if ( ( rc = rootdev_probe ( rootdev ) ) != 0 )
00090                         list_del ( &rootdev->dev.siblings );
00091         }
00092 }
00093 
00094 /**
00095  * Remove all devices
00096  *
00097  */
00098 static void remove_devices ( int booting __unused ) {
00099         struct root_device *rootdev;
00100         struct root_device *tmp;
00101 
00102         if ( device_keep_count != 0 ) {
00103                 DBG ( "Refusing to remove devices on shutdown\n" );
00104                 return;
00105         }
00106 
00107         list_for_each_entry_safe ( rootdev, tmp, &devices, dev.siblings ) {
00108                 rootdev_remove ( rootdev );
00109                 list_del ( &rootdev->dev.siblings );
00110         }
00111 }
00112 
00113 struct startup_fn startup_devices __startup_fn ( STARTUP_NORMAL ) = {
00114         .startup = probe_devices,
00115         .shutdown = remove_devices,
00116 };
00117 
00118 /**
00119  * Identify a device behind an interface
00120  *
00121  * @v intf              Interface
00122  * @ret device          Device, or NULL
00123  */
00124 struct device * identify_device ( struct interface *intf ) {
00125         struct interface *dest;
00126         identify_device_TYPE ( void * ) *op =
00127                 intf_get_dest_op ( intf, identify_device, &dest );
00128         void *object = intf_object ( dest );
00129         void *device;
00130 
00131         if ( op ) {
00132                 device = op ( object );
00133         } else {
00134                 /* Default is to return NULL */
00135                 device = NULL;
00136         }
00137 
00138         intf_put ( dest );
00139         return device;
00140 }