|
|
1.1 ! root 1: /* ! 2: * Copyright (C) 2010 Piotr JaroszyĆski <[email protected]> ! 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.