Browse Source

[linux] Add device and driver model

Add the base to build linux drivers and the linux UI code on.  UI
fills device requests, which are later walked over by the linux
root_driver and delegated to specific linux drivers.

Signed-off-by: Piotr Jaroszyński <p.jaroszynski@gmail.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Piotr Jaroszyński 14 years ago
parent
commit
91fb434bda
4 changed files with 298 additions and 0 deletions
  1. 1
    0
      src/Makefile
  2. 152
    0
      src/drivers/linux/linux.c
  3. 1
    0
      src/include/ipxe/errfile.h
  4. 144
    0
      src/include/ipxe/linux.h

+ 1
- 0
src/Makefile View File

@@ -73,6 +73,7 @@ SRCDIRS		+= drivers/block
73 73
 SRCDIRS		+= drivers/nvs
74 74
 SRCDIRS		+= drivers/bitbash
75 75
 SRCDIRS		+= drivers/infiniband
76
+SRCDIRS		+= drivers/linux
76 77
 SRCDIRS		+= interface/pxe interface/efi interface/smbios interface/linux
77 78
 SRCDIRS		+= tests
78 79
 SRCDIRS		+= crypto crypto/axtls crypto/matrixssl

+ 152
- 0
src/drivers/linux/linux.c View File

@@ -0,0 +1,152 @@
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
+			/* Driver handled the device so release ownership */
79
+			device = NULL;
80
+		} else {
81
+			/* Driver failed to handle the device so remove it from the hierarchy
82
+			 * and reuse the object */
83
+			list_del(&device->dev.siblings);
84
+		}
85
+	};
86
+
87
+	free(device);
88
+
89
+	return 0;
90
+}
91
+
92
+/** Remove all the linux devices registered in probe() */
93
+static void linux_remove(struct root_device *rootdev)
94
+{
95
+	struct linux_device *device;
96
+	struct linux_device *tmp;
97
+
98
+	list_for_each_entry_safe(device, tmp, &rootdev->dev.children, dev.siblings) {
99
+		list_del(&device->dev.siblings);
100
+		device->driver->remove(device);
101
+		free(device);
102
+	}
103
+}
104
+
105
+/** Linux root driver */
106
+static struct root_driver linux_root_driver = {
107
+	.probe = linux_probe,
108
+	.remove = linux_remove,
109
+};
110
+
111
+/** Linux root device */
112
+struct root_device linux_root_device __root_device = {
113
+	.dev = { .name = "linux" },
114
+	.driver = &linux_root_driver,
115
+};
116
+
117
+struct linux_setting *linux_find_setting(char *name, struct list_head *settings)
118
+{
119
+	struct linux_setting *setting;
120
+	struct linux_setting *result = NULL;
121
+
122
+	/* Find the last occurrence of a setting with the specified name */
123
+	list_for_each_entry(setting, settings, list) {
124
+		if (strcmp(setting->name, name) == 0) {
125
+			result = setting;
126
+		}
127
+	}
128
+
129
+	return result;
130
+}
131
+
132
+void linux_apply_settings(struct list_head *new_settings, struct settings *settings_block)
133
+{
134
+	struct linux_setting *setting;
135
+	int rc;
136
+
137
+	list_for_each_entry(setting, new_settings, list) {
138
+		/* Skip already applied settings */
139
+		if (setting->applied)
140
+			continue;
141
+
142
+		struct setting *s = find_setting(setting->name);
143
+		if (s) {
144
+			rc = storef_setting(settings_block, find_setting(setting->name), setting->value);
145
+			if (rc != 0)
146
+				DBG("linux storing setting '%s' = '%s' failed\n", setting->name, setting->value);
147
+			setting->applied = 1;
148
+		} else {
149
+			DBG("linux unknown setting '%s'\n", setting->name);
150
+		}
151
+	}
152
+}

+ 1
- 0
src/include/ipxe/errfile.h View File

@@ -61,6 +61,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
61 61
 #define ERRFILE_isapnp		     ( ERRFILE_DRIVER | 0x00020000 )
62 62
 #define ERRFILE_mca		     ( ERRFILE_DRIVER | 0x00030000 )
63 63
 #define ERRFILE_pci		     ( ERRFILE_DRIVER | 0x00040000 )
64
+#define ERRFILE_linux		     ( ERRFILE_DRIVER | 0x00050000 )
64 65
 
65 66
 #define ERRFILE_nvs		     ( ERRFILE_DRIVER | 0x00100000 )
66 67
 #define ERRFILE_spi		     ( ERRFILE_DRIVER | 0x00110000 )

+ 144
- 0
src/include/ipxe/linux.h View File

@@ -0,0 +1,144 @@
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
+#ifndef _IPXE_LINUX_H
20
+#define _IPXE_LINUX_H
21
+
22
+FILE_LICENCE(GPL2_OR_LATER);
23
+
24
+/** @file
25
+ *
26
+ * Linux devices, drivers and device requests.
27
+ */
28
+
29
+#include <ipxe/list.h>
30
+#include <ipxe/device.h>
31
+#include <ipxe/settings.h>
32
+
33
+/** A linux device */
34
+struct linux_device {
35
+	/** Generic device */
36
+	struct device dev;
37
+	/** Driver that's handling the device */
38
+	struct linux_driver *driver;
39
+	/** Private data used by drivers */
40
+	void *priv;
41
+};
42
+
43
+struct linux_device_request;
44
+
45
+/** A linux driver */
46
+struct linux_driver {
47
+	/** Name */
48
+	char *name;
49
+	/** Probe function */
50
+	int (*probe)(struct linux_device *device, struct linux_device_request *request);
51
+	/** Remove function */
52
+	void (*remove)(struct linux_device *device);
53
+	/** Can the driver probe any more devices? */
54
+	int can_probe;
55
+};
56
+
57
+/** Linux driver table */
58
+#define LINUX_DRIVERS __table(struct linux_driver, "linux_drivers")
59
+
60
+/** Declare a Linux driver */
61
+#define __linux_driver __table_entry(LINUX_DRIVERS, 01)
62
+
63
+/**
64
+ * Set linux device driver-private data
65
+ *
66
+ * @v device	Linux device
67
+ * @v priv		Private data
68
+ */
69
+static inline void linux_set_drvdata(struct linux_device * device, void *priv)
70
+{
71
+	device->priv = priv;
72
+}
73
+
74
+/**
75
+ * Get linux device driver-private data
76
+ *
77
+ * @v device	Linux device
78
+ * @ret priv	Private data
79
+ */
80
+static inline void *linux_get_drvdata(struct linux_device *device)
81
+{
82
+	return device->priv;
83
+}
84
+
85
+/**
86
+ * A device request.
87
+ *
88
+ * To be created and filled by the UI code.
89
+ */
90
+struct linux_device_request {
91
+	/** Driver name. Compared to the linux drivers' names */
92
+	char *driver;
93
+	/** List node */
94
+	struct list_head list;
95
+	/** List of settings */
96
+	struct list_head settings;
97
+};
98
+
99
+/** A device request setting */
100
+struct linux_setting {
101
+	/** Name */
102
+	char *name;
103
+	/** Value */
104
+	char *value;
105
+	/** Was the setting already applied? */
106
+	int applied;
107
+	/** List node */
108
+	struct list_head list;
109
+};
110
+
111
+/**
112
+ * List of requested devices.
113
+ *
114
+ * Filled by the UI code. Linux root_driver walks over this list looking for an
115
+ * appropriate driver to handle each request by matching the driver's name.
116
+ */
117
+extern struct list_head linux_device_requests;
118
+
119
+/**
120
+ * List of global settings to apply.
121
+ *
122
+ * Filled by the UI code. Linux root_driver applies these settings.
123
+ */
124
+extern struct list_head linux_global_settings;
125
+
126
+/**
127
+ * Look for the last occurrence of a setting with the specified name
128
+ *
129
+ * @v name     Name of the setting to look for
130
+ * @v settings List of the settings to look through
131
+ */
132
+struct linux_setting *linux_find_setting(char *name, struct list_head *settings);
133
+
134
+/**
135
+ * Apply a list of linux settings to a settings block
136
+ *
137
+ * @v new_settings     List of linux_setting's to apply
138
+ * @v settings_block   Settings block to apply the settings to
139
+ * @ret rc             0 on success
140
+ */
141
+extern void linux_apply_settings(struct list_head *new_settings, struct settings *settings_block);
142
+
143
+
144
+#endif /* _IPXE_LINUX_H */

Loading…
Cancel
Save