Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / ipxe / src / drivers / linux / linux.c
1 /*
2  * Copyright (C) 2010 Piotr JaroszyƄski <p.jaroszynski@gmail.com>
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18
19 FILE_LICENCE(GPL2_OR_LATER);
20
21 /** @file
22  *
23  * Linux root_device and root_driver.
24  */
25
26 #include <errno.h>
27 #include <string.h>
28 #include <stdio.h>
29 #include <ipxe/linux.h>
30 #include <ipxe/malloc.h>
31 #include <ipxe/settings.h>
32
33 LIST_HEAD(linux_device_requests);
34 LIST_HEAD(linux_global_settings);
35
36 /** Go over the device requests looking for a matching linux driver to handle them. */
37 static int linux_probe(struct root_device *rootdev)
38 {
39         struct linux_device_request *request;
40         struct linux_driver *driver;
41         struct linux_device *device = NULL;
42         int rc;
43
44         /* Apply global settings */
45         linux_apply_settings(&linux_global_settings, NULL);
46
47         list_for_each_entry(request, &linux_device_requests, list) {
48                 if (! device)
49                         device = zalloc(sizeof(*device));
50
51                 if (! device)
52                         return -ENOMEM;
53
54                 rc = 1;
55
56                 for_each_table_entry(driver, LINUX_DRIVERS) {
57                         if ((rc = strcmp(driver->name, request->driver)) == 0)
58                                 break;
59                 }
60
61                 if (rc != 0) {
62                         printf("Linux driver '%s' not found\n", request->driver);
63                         continue;
64                 }
65
66                 if (! driver->can_probe) {
67                         printf("Driver '%s' cannot handle any more devices\n", driver->name);
68                         continue;
69                 }
70
71                 /* We found a matching driver so add the device to the hierarchy */
72                 list_add(&device->dev.siblings, &rootdev->dev.children);
73                 device->dev.parent = &rootdev->dev;
74                 INIT_LIST_HEAD(&device->dev.children);
75
76                 if (driver->probe(device, request) == 0) {
77                         device->driver = driver;
78                         device->dev.driver_name = driver->name;
79                         /* Driver handled the device so release ownership */
80                         device = NULL;
81                 } else {
82                         /* Driver failed to handle the device so remove it from the hierarchy
83                          * and reuse the object */
84                         list_del(&device->dev.siblings);
85                 }
86         };
87
88         free(device);
89
90         return 0;
91 }
92
93 /** Remove all the linux devices registered in probe() */
94 static void linux_remove(struct root_device *rootdev)
95 {
96         struct linux_device *device;
97         struct linux_device *tmp;
98
99         list_for_each_entry_safe(device, tmp, &rootdev->dev.children, dev.siblings) {
100                 list_del(&device->dev.siblings);
101                 device->driver->remove(device);
102                 free(device);
103         }
104 }
105
106 /** Linux root driver */
107 static struct root_driver linux_root_driver = {
108         .probe = linux_probe,
109         .remove = linux_remove,
110 };
111
112 /** Linux root device */
113 struct root_device linux_root_device __root_device = {
114         .dev = { .name = "linux" },
115         .driver = &linux_root_driver,
116 };
117
118 struct linux_setting *linux_find_setting(char *name, struct list_head *settings)
119 {
120         struct linux_setting *setting;
121         struct linux_setting *result = NULL;
122
123         /* Find the last occurrence of a setting with the specified name */
124         list_for_each_entry(setting, settings, list) {
125                 if (strcmp(setting->name, name) == 0) {
126                         result = setting;
127                 }
128         }
129
130         return result;
131 }
132
133 void linux_apply_settings(struct list_head *new_settings, struct settings *settings_block)
134 {
135         struct linux_setting *setting;
136         int rc;
137
138         list_for_each_entry(setting, new_settings, list) {
139                 /* Skip already applied settings */
140                 if (setting->applied)
141                         continue;
142
143                 struct setting *s = find_setting(setting->name);
144                 if (s) {
145                         rc = storef_setting(settings_block, find_setting(setting->name), setting->value);
146                         if (rc != 0)
147                                 DBG("linux storing setting '%s' = '%s' failed\n", setting->name, setting->value);
148                         setting->applied = 1;
149                 } else {
150                         DBG("linux unknown setting '%s'\n", setting->name);
151                 }
152         }
153 }