1#include <linux/string.h> 2#include <linux/kernel.h> 3#include <linux/init.h> 4#include <linux/module.h> 5#include <linux/mod_devicetable.h> 6#include <linux/slab.h> 7 8#include <asm/errno.h> 9#include <asm/of_device.h> 10 11/** 12 * of_match_node - Tell if an device_node has a matching of_match structure 13 * @ids: array of of device match structures to search in 14 * @node: the of device structure to match against 15 * 16 * Low level utility function used by device matching. 17 */ 18const struct of_device_id *of_match_node(const struct of_device_id *matches, 19 const struct device_node *node) 20{ 21 while (matches->name[0] || matches->type[0] || matches->compatible[0]) { 22 int match = 1; 23 if (matches->name[0]) 24 match &= node->name 25 && !strcmp(matches->name, node->name); 26 if (matches->type[0]) 27 match &= node->type 28 && !strcmp(matches->type, node->type); 29 if (matches->compatible[0]) 30 match &= of_device_is_compatible(node, 31 matches->compatible); 32 if (match) 33 return matches; 34 matches++; 35 } 36 return NULL; 37} 38 39/** 40 * of_match_device - Tell if an of_device structure has a matching 41 * of_match structure 42 * @ids: array of of device match structures to search in 43 * @dev: the of device structure to match against 44 * 45 * Used by a driver to check whether an of_device present in the 46 * system is in its list of supported devices. 47 */ 48const struct of_device_id *of_match_device(const struct of_device_id *matches, 49 const struct of_device *dev) 50{ 51 if (!dev->node) 52 return NULL; 53 return of_match_node(matches, dev->node); 54} 55 56struct of_device *of_dev_get(struct of_device *dev) 57{ 58 struct device *tmp; 59 60 if (!dev) 61 return NULL; 62 tmp = get_device(&dev->dev); 63 if (tmp) 64 return to_of_device(tmp); 65 else 66 return NULL; 67} 68 69void of_dev_put(struct of_device *dev) 70{ 71 if (dev) 72 put_device(&dev->dev); 73} 74 75static ssize_t dev_show_devspec(struct device *dev, 76 struct device_attribute *attr, char *buf) 77{ 78 struct of_device *ofdev; 79 80 ofdev = to_of_device(dev); 81 return sprintf(buf, "%s", ofdev->node->full_name); 82} 83 84static DEVICE_ATTR(devspec, S_IRUGO, dev_show_devspec, NULL); 85 86/** 87 * of_release_dev - free an of device structure when all users of it are finished. 88 * @dev: device that's been disconnected 89 * 90 * Will be called only by the device core when all users of this of device are 91 * done. 92 */ 93void of_release_dev(struct device *dev) 94{ 95 struct of_device *ofdev; 96 97 ofdev = to_of_device(dev); 98 of_node_put(ofdev->node); 99 kfree(ofdev); 100} 101 102int of_device_register(struct of_device *ofdev) 103{ 104 int rc; 105 106 BUG_ON(ofdev->node == NULL); 107 108 rc = device_register(&ofdev->dev); 109 if (rc) 110 return rc; 111 112 return device_create_file(&ofdev->dev, &dev_attr_devspec); 113} 114 115void of_device_unregister(struct of_device *ofdev) 116{ 117 device_remove_file(&ofdev->dev, &dev_attr_devspec); 118 119 device_unregister(&ofdev->dev); 120} 121 122 123ssize_t of_device_get_modalias(struct of_device *ofdev, 124 char *str, ssize_t len) 125{ 126 const char *compat; 127 int cplen, i; 128 ssize_t tsize, csize, repend; 129 130 /* Name & Type */ 131 csize = snprintf(str, len, "of:N%sT%s", 132 ofdev->node->name, ofdev->node->type); 133 134 /* Get compatible property if any */ 135 compat = of_get_property(ofdev->node, "compatible", &cplen); 136 if (!compat) 137 return csize; 138 139 /* Find true end (we tolerate multiple \0 at the end */ 140 for (i=(cplen-1); i>=0 && !compat[i]; i--) 141 cplen--; 142 if (!cplen) 143 return csize; 144 cplen++; 145 146 /* Check space (need cplen+1 chars including final \0) */ 147 tsize = csize + cplen; 148 repend = tsize; 149 150 if (csize>=len) /* @ the limit, all is already filled */ 151 return tsize; 152 153 if (tsize>=len) { /* limit compat list */ 154 cplen = len-csize-1; 155 repend = len; 156 } 157 158 /* Copy and do char replacement */ 159 memcpy(&str[csize+1], compat, cplen); 160 for (i=csize; i<repend; i++) { 161 char c = str[i]; 162 if (c=='\0') 163 str[i] = 'C'; 164 else if (c==' ') 165 str[i] = '_'; 166 } 167 168 return tsize; 169} 170 171int of_device_uevent(struct device *dev, 172 char **envp, int num_envp, char *buffer, int buffer_size) 173{ 174 struct of_device *ofdev; 175 const char *compat; 176 int i = 0, length = 0, seen = 0, cplen, sl; 177 178 if (!dev) 179 return -ENODEV; 180 181 ofdev = to_of_device(dev); 182 183 if (add_uevent_var(envp, num_envp, &i, 184 buffer, buffer_size, &length, 185 "OF_NAME=%s", ofdev->node->name)) 186 return -ENOMEM; 187 188 if (add_uevent_var(envp, num_envp, &i, 189 buffer, buffer_size, &length, 190 "OF_TYPE=%s", ofdev->node->type)) 191 return -ENOMEM; 192 193 /* Since the compatible field can contain pretty much anything 194 * it's not really legal to split it out with commas. We split it 195 * up using a number of environment variables instead. */ 196 197 compat = of_get_property(ofdev->node, "compatible", &cplen); 198 while (compat && *compat && cplen > 0) { 199 if (add_uevent_var(envp, num_envp, &i, 200 buffer, buffer_size, &length, 201 "OF_COMPATIBLE_%d=%s", seen, compat)) 202 return -ENOMEM; 203 204 sl = strlen (compat) + 1; 205 compat += sl; 206 cplen -= sl; 207 seen++; 208 } 209 210 if (add_uevent_var(envp, num_envp, &i, 211 buffer, buffer_size, &length, 212 "OF_COMPATIBLE_N=%d", seen)) 213 return -ENOMEM; 214 215 /* modalias is trickier, we add it in 2 steps */ 216 if (add_uevent_var(envp, num_envp, &i, 217 buffer, buffer_size, &length, 218 "MODALIAS=")) 219 return -ENOMEM; 220 221 sl = of_device_get_modalias(ofdev, &buffer[length-1], 222 buffer_size-length); 223 if (sl >= (buffer_size-length)) 224 return -ENOMEM; 225 226 length += sl; 227 228 envp[i] = NULL; 229 230 return 0; 231} 232 233 234EXPORT_SYMBOL(of_match_node); 235EXPORT_SYMBOL(of_match_device); 236EXPORT_SYMBOL(of_device_register); 237EXPORT_SYMBOL(of_device_unregister); 238EXPORT_SYMBOL(of_dev_get); 239EXPORT_SYMBOL(of_dev_put); 240EXPORT_SYMBOL(of_release_dev); 241EXPORT_SYMBOL(of_device_uevent); 242EXPORT_SYMBOL(of_device_get_modalias); 243