1 | /* |
---|
2 | * Copyright (C) 2006 Michael Brown <mbrown@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 | }; |
---|