1 /* 2 * Copyright (C) 2006 Michael Brown <mbrown (at) fensystems.co.uk>. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License as 6 * published by the Free Software Foundation; either version 2 of the 7 * License, or any later version. 8 * 9 * This program is distributed in the hope that it will be useful, but 10 * WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 */ 18 19 FILE_LICENCE ( GPL2_OR_LATER ); 20 21 #include <string.h> 22 #include <gpxe/list.h> 23 #include <gpxe/tables.h> 24 #include <gpxe/device.h> 25 #include <gpxe/init.h> 26 27 /** 28 * @file 29 * 30 * Device model 31 * 32 */ 33 34 /** Registered root devices */ 35 static LIST_HEAD ( devices ); 36 37 /** 38 * Probe a root device 39 * 40 * @v rootdev Root device 41 * @ret rc Return status code 42 */ 43 static int rootdev_probe ( struct root_device *rootdev ) { 44 int rc; 45 46 DBG ( "Adding %s root bus\n", rootdev->dev.name ); 47 if ( ( rc = rootdev->driver->probe ( rootdev ) ) != 0 ) { 48 DBG ( "Failed to add %s root bus: %s\n", 49 rootdev->dev.name, strerror ( rc ) ); 50 return rc; 51 } 52 53 return 0; 54 } 55 56 /** 57 * Remove a root device 58 * 59 * @v rootdev Root device 60 */ 61 static void rootdev_remove ( struct root_device *rootdev ) { 62 rootdev->driver->remove ( rootdev ); 63 DBG ( "Removed %s root bus\n", rootdev->dev.name ); 64 } 65 66 /** 67 * Probe all devices 68 * 69 * This initiates probing for all devices in the system. After this 70 * call, the device hierarchy will be populated, and all hardware 71 * should be ready to use. 72 */ 73 static void probe_devices ( void ) { 74 struct root_device *rootdev; 75 int rc; 76 77 for_each_table_entry ( rootdev, ROOT_DEVICES ) { 78 list_add ( &rootdev->dev.siblings, &devices ); 79 INIT_LIST_HEAD ( &rootdev->dev.children ); 80 if ( ( rc = rootdev_probe ( rootdev ) ) != 0 ) 81 list_del ( &rootdev->dev.siblings ); 82 } 83 } 84 85 /** 86 * Remove all devices 87 * 88 */ 89 static void remove_devices ( int flags ) { 90 struct root_device *rootdev; 91 struct root_device *tmp; 92 93 if ( flags & SHUTDOWN_KEEP_DEVICES ) { 94 DBG ( "Refusing to remove devices on shutdown\n" ); 95 return; 96 } 97 98 list_for_each_entry_safe ( rootdev, tmp, &devices, dev.siblings ) { 99 rootdev_remove ( rootdev ); 100 list_del ( &rootdev->dev.siblings ); 101 } 102 } 103 104 struct startup_fn startup_devices __startup_fn ( STARTUP_NORMAL ) = { 105 .startup = probe_devices, 106 .shutdown = remove_devices, 107 }; 108