1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
|
/*
* sys.c - pseudo-bus for system 'devices' (cpus, PICs, timers, etc)
*
* Copyright (c) 2002 Patrick Mochel
* 2002 Open Source Development Lab
*
* This exports a 'system' bus type.
* By default, a 'sys' bus gets added to the root of the system. There will
* always be core system devices. Devices can use sys_device_register() to
* add themselves as children of the system bus.
*/
#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/err.h>
/* The default system device parent. */
static struct device system_bus = {
.name = "System Bus",
.bus_id = "sys",
};
/**
* sys_register_root - add a subordinate system root
* @root: new root
*
* This is for NUMA-like systems so they can accurately
* represent the topology of the entire system.
* As boards are discovered, a new struct sys_root should
* be allocated and registered.
* The discovery mechanism should initialize the id field
* of the struture, as well as much of the embedded device
* structure as possible, inlcuding the name, the bus_id
* and parent fields.
*
* This simply calls device_register on the embedded device.
* On success, it will use the struct @root->sysdev
* device to create a pseudo-parent for system devices
* on that board.
*
* The platform code can then use @root to specifiy the
* controlling board when discovering and registering
* system devices.
*/
int sys_register_root(struct sys_root * root)
{
int error = 0;
if (!root)
return -EINVAL;
pr_debug("Registering system board %d\n",root->id);
error = device_register(&root->dev);
if (!error) {
strncpy(root->sysdev.bus_id,"sys",BUS_ID_SIZE);
strncpy(root->sysdev.name,"System Bus",DEVICE_NAME_SIZE);
root->sysdev.parent = &root->dev;
error = device_register(&root->sysdev);
};
return error;
}
/**
* sys_unregister_root - remove subordinate root from tree
* @root: subordinate root in question.
*
* We only decrement the reference count on @root->sysdev
* and @root->dev.
* If both are 0, they will be cleaned up by the core.
*/
void sys_unegister_root(struct sys_root * root)
{
put_device(&root->sysdev);
put_device(&root->dev);
}
/**
* sys_device_register - add a system device to the tree
* @sysdev: device in question
*
* The hardest part about this is getting the ancestry right.
* If the device has a parent - super! We do nothing.
* If the device doesn't, but @dev->root is set, then we're
* dealing with a NUMA like architecture where each root
* has a system pseudo-bus to foster the device.
* If not, then we fallback to system_bus (at the top of
* this file).
*
* One way or another, we call device_register() on it and
* are done.
*
* The caller is also responsible for initializing the bus_id
* and name fields of @sysdev->dev.
*/
int sys_device_register(struct sys_device * sysdev)
{
if (!sysdev)
return -EINVAL;
if (!sysdev->dev.parent) {
if (sysdev->root)
sysdev->dev.parent = &sysdev->root->sysdev;
else
sysdev->dev.parent = &system_bus;
}
/* make sure bus type is set */
if (!sysdev->dev.bus)
sysdev->dev.bus = &system_bus_type;
/* construct bus_id */
snprintf(sysdev->dev.bus_id,BUS_ID_SIZE,"%s%u",sysdev->name,sysdev->id);
pr_debug("Registering system device %s\n", sysdev->dev.bus_id);
return device_register(&sysdev->dev);
}
void sys_device_unregister(struct sys_device * sysdev)
{
if (sysdev)
put_device(&sysdev->dev);
}
struct bus_type system_bus_type = {
.name = "system",
};
static int sys_bus_init(void)
{
bus_register(&system_bus_type);
return device_register(&system_bus);
}
postcore_initcall(sys_bus_init);
EXPORT_SYMBOL(system_bus_type);
EXPORT_SYMBOL(sys_device_register);
EXPORT_SYMBOL(sys_device_unregister);
|