]>
Commit | Line | Data |
---|---|---|
f85ff305 SR |
1 | #include <linux/string.h> |
2 | #include <linux/kernel.h> | |
3 | #include <linux/of.h> | |
f898f8db | 4 | #include <linux/of_device.h> |
f85ff305 SR |
5 | #include <linux/init.h> |
6 | #include <linux/module.h> | |
7 | #include <linux/mod_devicetable.h> | |
8 | #include <linux/slab.h> | |
9 | ||
10 | #include <asm/errno.h> | |
f85ff305 | 11 | |
f85ff305 SR |
12 | /** |
13 | * of_match_device - Tell if an of_device structure has a matching | |
14 | * of_match structure | |
15 | * @ids: array of of device match structures to search in | |
16 | * @dev: the of device structure to match against | |
17 | * | |
18 | * Used by a driver to check whether an of_device present in the | |
19 | * system is in its list of supported devices. | |
20 | */ | |
21 | const struct of_device_id *of_match_device(const struct of_device_id *matches, | |
22 | const struct of_device *dev) | |
23 | { | |
24 | if (!dev->node) | |
25 | return NULL; | |
26 | return of_match_node(matches, dev->node); | |
27 | } | |
28 | EXPORT_SYMBOL(of_match_device); | |
29 | ||
30 | struct of_device *of_dev_get(struct of_device *dev) | |
31 | { | |
32 | struct device *tmp; | |
33 | ||
34 | if (!dev) | |
35 | return NULL; | |
36 | tmp = get_device(&dev->dev); | |
37 | if (tmp) | |
38 | return to_of_device(tmp); | |
39 | else | |
40 | return NULL; | |
41 | } | |
42 | EXPORT_SYMBOL(of_dev_get); | |
43 | ||
44 | void of_dev_put(struct of_device *dev) | |
45 | { | |
46 | if (dev) | |
47 | put_device(&dev->dev); | |
48 | } | |
49 | EXPORT_SYMBOL(of_dev_put); | |
50 | ||
140b932f | 51 | static ssize_t devspec_show(struct device *dev, |
f85ff305 SR |
52 | struct device_attribute *attr, char *buf) |
53 | { | |
54 | struct of_device *ofdev; | |
55 | ||
56 | ofdev = to_of_device(dev); | |
140b932f | 57 | return sprintf(buf, "%s\n", ofdev->node->full_name); |
f85ff305 SR |
58 | } |
59 | ||
4589f1fe JF |
60 | static ssize_t name_show(struct device *dev, |
61 | struct device_attribute *attr, char *buf) | |
62 | { | |
63 | struct of_device *ofdev; | |
64 | ||
65 | ofdev = to_of_device(dev); | |
66 | return sprintf(buf, "%s\n", ofdev->node->name); | |
67 | } | |
68 | ||
140b932f OH |
69 | static ssize_t modalias_show(struct device *dev, |
70 | struct device_attribute *attr, char *buf) | |
71 | { | |
72 | struct of_device *ofdev = to_of_device(dev); | |
73 | ssize_t len = 0; | |
74 | ||
75 | len = of_device_get_modalias(ofdev, buf, PAGE_SIZE - 2); | |
76 | buf[len] = '\n'; | |
77 | buf[len+1] = 0; | |
78 | return len+1; | |
79 | } | |
80 | ||
81 | struct device_attribute of_platform_device_attrs[] = { | |
82 | __ATTR_RO(devspec), | |
4589f1fe | 83 | __ATTR_RO(name), |
140b932f OH |
84 | __ATTR_RO(modalias), |
85 | __ATTR_NULL | |
86 | }; | |
f85ff305 SR |
87 | |
88 | /** | |
89 | * of_release_dev - free an of device structure when all users of it are finished. | |
90 | * @dev: device that's been disconnected | |
91 | * | |
92 | * Will be called only by the device core when all users of this of device are | |
93 | * done. | |
94 | */ | |
95 | void of_release_dev(struct device *dev) | |
96 | { | |
97 | struct of_device *ofdev; | |
98 | ||
99 | ofdev = to_of_device(dev); | |
100 | of_node_put(ofdev->node); | |
101 | kfree(ofdev); | |
102 | } | |
103 | EXPORT_SYMBOL(of_release_dev); | |
104 | ||
105 | int of_device_register(struct of_device *ofdev) | |
106 | { | |
f85ff305 | 107 | BUG_ON(ofdev->node == NULL); |
6098e2ee JK |
108 | |
109 | device_initialize(&ofdev->dev); | |
110 | ||
111 | /* device_add will assume that this device is on the same node as | |
112 | * the parent. If there is no parent defined, set the node | |
113 | * explicitly */ | |
114 | if (!ofdev->dev.parent) | |
115 | set_dev_node(&ofdev->dev, of_node_to_nid(ofdev->node)); | |
116 | ||
117 | return device_add(&ofdev->dev); | |
f85ff305 SR |
118 | } |
119 | EXPORT_SYMBOL(of_device_register); | |
120 | ||
121 | void of_device_unregister(struct of_device *ofdev) | |
122 | { | |
f85ff305 SR |
123 | device_unregister(&ofdev->dev); |
124 | } | |
125 | EXPORT_SYMBOL(of_device_unregister); | |
09e67ca2 SR |
126 | |
127 | ssize_t of_device_get_modalias(struct of_device *ofdev, | |
128 | char *str, ssize_t len) | |
129 | { | |
130 | const char *compat; | |
131 | int cplen, i; | |
132 | ssize_t tsize, csize, repend; | |
133 | ||
134 | /* Name & Type */ | |
135 | csize = snprintf(str, len, "of:N%sT%s", | |
136 | ofdev->node->name, ofdev->node->type); | |
137 | ||
138 | /* Get compatible property if any */ | |
139 | compat = of_get_property(ofdev->node, "compatible", &cplen); | |
140 | if (!compat) | |
141 | return csize; | |
142 | ||
143 | /* Find true end (we tolerate multiple \0 at the end */ | |
144 | for (i = (cplen - 1); i >= 0 && !compat[i]; i--) | |
145 | cplen--; | |
146 | if (!cplen) | |
147 | return csize; | |
148 | cplen++; | |
149 | ||
150 | /* Check space (need cplen+1 chars including final \0) */ | |
151 | tsize = csize + cplen; | |
152 | repend = tsize; | |
153 | ||
154 | if (csize >= len) /* @ the limit, all is already filled */ | |
155 | return tsize; | |
156 | ||
157 | if (tsize >= len) { /* limit compat list */ | |
158 | cplen = len - csize - 1; | |
159 | repend = len; | |
160 | } | |
161 | ||
162 | /* Copy and do char replacement */ | |
163 | memcpy(&str[csize + 1], compat, cplen); | |
164 | for (i = csize; i < repend; i++) { | |
165 | char c = str[i]; | |
166 | if (c == '\0') | |
167 | str[i] = 'C'; | |
168 | else if (c == ' ') | |
169 | str[i] = '_'; | |
170 | } | |
171 | ||
172 | return tsize; | |
173 | } |