4 * Generic class utility functions for libsysfs
6 * Copyright (C) IBM Corp. 2003
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 void sysfs_close_cls_dev(void *dev)
28 sysfs_close_class_device((struct sysfs_class_device *)dev);
32 * class_name_equal: compares class_devices' name
33 * @a: class_name looking for
34 * @b: sysfs_class_device being compared
36 static int class_name_equal(void *a, void *b)
38 if (a == NULL || b == NULL)
41 if (strcmp(((unsigned char *)a), ((struct sysfs_class_device *)b)->name)
49 * sysfs_close_class_device: closes a single class device.
50 * @dev: class device to close.
52 void sysfs_close_class_device(struct sysfs_class_device *dev)
55 if (dev->directory != NULL)
56 sysfs_close_directory(dev->directory);
57 if (dev->sysdevice != NULL)
58 sysfs_close_device(dev->sysdevice);
59 if (dev->driver != NULL)
60 sysfs_close_driver(dev->driver);
66 * sysfs_close_class: close single class
67 * @class: class structure
69 void sysfs_close_class(struct sysfs_class *cls)
72 if (cls->directory != NULL)
73 sysfs_close_directory(cls->directory);
74 if (cls->devices != NULL)
75 dlist_destroy(cls->devices);
81 * alloc_class_device: mallocs and initializes new class device struct.
82 * returns sysfs_class_device or NULL.
84 static struct sysfs_class_device *alloc_class_device(void)
86 return (struct sysfs_class_device *)
87 calloc(1, sizeof(struct sysfs_class_device));
91 * alloc_class: mallocs new class structure
92 * returns sysfs_class struct or NULL
94 static struct sysfs_class *alloc_class(void)
96 return (struct sysfs_class *)calloc(1, sizeof(struct sysfs_class));
100 * open_class_dir: opens up sysfs class directory
101 * returns sysfs_directory struct with success and NULL with error
103 static struct sysfs_directory *open_class_dir(const unsigned char *name)
105 struct sysfs_directory *classdir = NULL;
106 unsigned char classpath[SYSFS_PATH_MAX];
113 memset(classpath, 0, SYSFS_PATH_MAX);
114 if ((sysfs_get_mnt_path(classpath, SYSFS_PATH_MAX)) != 0) {
115 dprintf("Sysfs not supported on this system\n");
119 strcat(classpath, SYSFS_CLASS_DIR);
120 strcat(classpath, "/");
121 strcat(classpath, name);
122 classdir = sysfs_open_directory(classpath);
123 if (classdir == NULL) {
125 dprintf("Class %s not supported on this system\n", name);
128 if ((sysfs_read_directory(classdir)) != 0) {
129 dprintf("Error reading %s class dir %s\n", name, classpath);
130 sysfs_close_directory(classdir);
138 * sysfs_open_class_device: Opens and populates class device
139 * @path: path to class device.
140 * returns struct sysfs_class_device with success and NULL with error.
142 struct sysfs_class_device *sysfs_open_class_device(const unsigned char *path)
144 struct sysfs_class_device *cdev = NULL;
145 struct sysfs_directory *dir = NULL;
146 struct sysfs_link *curl = NULL;
147 struct sysfs_device *sdev = NULL;
148 struct sysfs_driver *drv = NULL;
154 cdev = alloc_class_device();
156 dprintf("calloc failed\n");
159 if ((sysfs_get_name_from_path(path, cdev->name, SYSFS_NAME_LEN)) != 0) {
161 dprintf("Invalid class device path %s\n", path);
162 sysfs_close_class_device(cdev);
166 dir = sysfs_open_directory(path);
168 dprintf("Error opening class device at %s\n", path);
169 sysfs_close_class_device(cdev);
172 if ((sysfs_read_directory(dir)) != 0) {
173 dprintf("Error reading class device at %s\n", path);
174 sysfs_close_directory(dir);
175 sysfs_close_class_device(cdev);
178 sysfs_read_all_subdirs(dir);
179 cdev->directory = dir;
180 strcpy(cdev->path, dir->path);
182 /* get driver and device, if implemented */
183 if (cdev->directory->links != NULL) {
184 dlist_for_each_data(cdev->directory->links, curl,
186 if (strncmp(curl->name, SYSFS_DEVICES_NAME, 6) == 0) {
187 sdev = sysfs_open_device(curl->target);
189 cdev->sysdevice = sdev;
190 if (cdev->driver != NULL)
191 strncpy(sdev->driver_name,
195 } else if (strncmp(curl->name,
196 SYSFS_DRIVERS_NAME, 6) == 0) {
197 drv = sysfs_open_driver(curl->target);
200 if (cdev->sysdevice != NULL) {
201 strncpy(cdev->sysdevice->name,
204 if (drv->devices == NULL)
209 dlist_unshift(drv->devices,
220 * get_all_class_devices: gets all devices for class
221 * @class: class to get devices for
222 * returns 0 with success and -1 with failure
224 static int get_all_class_devices(struct sysfs_class *cls)
226 struct sysfs_class_device *dev = NULL;
227 struct sysfs_directory *cur = NULL;
229 if (cls == NULL || cls->directory == NULL) {
233 if (cls->directory->subdirs == NULL)
235 dlist_for_each_data(cls->directory->subdirs, cur,
236 struct sysfs_directory) {
237 dev = sysfs_open_class_device(cur->path);
239 dprintf("Error opening device at %s\n", cur->path);
242 if (cls->devices == NULL)
243 cls->devices = dlist_new_with_delete
244 (sizeof(struct sysfs_class_device),
245 sysfs_close_cls_dev);
246 dlist_unshift(cls->devices, dev);
252 * sysfs_open_class: opens specific class and all its devices on system
253 * returns sysfs_class structure with success or NULL with error.
255 struct sysfs_class *sysfs_open_class(const unsigned char *name)
257 struct sysfs_class *cls = NULL;
258 struct sysfs_directory *classdir = NULL;
267 dprintf("calloc failed\n");
270 strcpy(cls->name, name);
271 classdir = open_class_dir(name);
272 if (classdir == NULL) {
273 dprintf("Invalid class, %s not supported on this system\n",
275 sysfs_close_class(cls);
278 cls->directory = classdir;
279 strcpy(cls->path, classdir->path);
280 if ((get_all_class_devices(cls)) != 0) {
281 dprintf("Error reading %s class devices\n", name);
282 sysfs_close_class(cls);
290 * sysfs_get_class_device: Get specific class device using the device's id
291 * @class: class to find device on
292 * @name: class name of the device
294 struct sysfs_class_device *sysfs_get_class_device(struct sysfs_class *class,
297 if (class == NULL || name == NULL) {
302 return (struct sysfs_class_device *)dlist_find_custom(class->devices,
303 name, class_name_equal);
307 * sysfs_open_class_device_by_name: Locates a specific class_device and returns it.
308 * Class_device must be closed using sysfs_close_class_device
309 * @classname: Class to search
310 * @name: name of the class_device
312 struct sysfs_class_device *sysfs_open_class_device_by_name
313 (const unsigned char *classname, unsigned char *name)
315 struct sysfs_class *class = NULL;
316 struct sysfs_class_device *cdev = NULL, *rcdev = NULL;
318 if (classname == NULL || name == NULL) {
323 class = sysfs_open_class(classname);
325 dprintf("Error opening class %s\n", classname);
329 cdev = sysfs_get_class_device(class, name);
331 dprintf("Error getting class device %s from class %s\n",
333 sysfs_close_class(class);
337 rcdev = sysfs_open_class_device(cdev->directory->path);
339 dprintf("Error getting class device %s from class %s\n",
341 sysfs_close_class(class);
344 sysfs_close_class(class);
350 * sysfs_get_classdev_attributes: returns a dlist of attributes for
351 * the requested class_device
352 * @cdev: sysfs_class_dev for which attributes are needed
353 * returns a dlist of attributes if exists, NULL otherwise
355 struct dlist *sysfs_get_classdev_attributes(struct sysfs_class_device *cdev)
357 if (cdev == NULL || cdev->directory == NULL)
360 return (cdev->directory->attributes);
364 * sysfs_find_device_class: locates the device the device is on
365 * @bus_id: device to look for
366 * @classname: buffer to copy class name to
367 * @bsize: size of buffer
368 * returns 0 with success and -1 with error
370 int sysfs_find_device_class(const unsigned char *bus_id,
371 unsigned char *classname, size_t bsize)
373 unsigned char class[SYSFS_NAME_LEN], clspath[SYSFS_NAME_LEN];
374 unsigned char *cls = NULL, *clsdev = NULL;
375 struct dlist *clslist = NULL, *clsdev_list = NULL;
377 if (bus_id == NULL || classname == NULL) {
382 strcpy(class, SYSFS_CLASS_DIR);
383 clslist = sysfs_open_subsystem_list(class);
384 if (clslist != NULL) {
385 dlist_for_each_data(clslist, cls, char) {
386 memset(clspath, 0, SYSFS_NAME_LEN);
387 strcpy(clspath, SYSFS_CLASS_DIR);
388 strcat(clspath, "/");
389 strcat(clspath, cls);
390 clsdev_list = sysfs_open_subsystem_list(clspath);
391 if (clsdev_list != NULL) {
392 dlist_for_each_data(clsdev_list,
394 if (strcmp(bus_id, clsdev) == 0) {
397 sysfs_close_list(clsdev_list);
398 sysfs_close_list(clslist);
402 sysfs_close_list(clsdev_list);
405 sysfs_close_list(clslist);
411 * sysfs_get_classdev_attr: searches class device's attributes by name
412 * @clsdev: class device to look through
413 * @name: attribute name to get
414 * returns sysfs_attribute reference with success or NULL with error
416 struct sysfs_attribute *sysfs_get_classdev_attr
417 (struct sysfs_class_device *clsdev, const unsigned char *name)
419 struct sysfs_attribute *cur = NULL;
421 if (clsdev == NULL || clsdev->directory == NULL ||
422 clsdev->directory->attributes == NULL || name == NULL) {
427 cur = sysfs_get_directory_attribute(clsdev->directory,
428 (unsigned char *)name);
436 * sysfs_write_classdev_attr: modify writable attribute value for the given
438 * @dev: class device name for which the attribute has to be changed
439 * @attrib: attribute to change
440 * @value: value to change to
441 * @len: size of buffer at "value"
442 * Returns 0 on success and -1 on error
444 int sysfs_write_classdev_attr(unsigned char *dev, unsigned char *attrib,
445 unsigned char *value, size_t len)
447 struct sysfs_class_device *clsdev = NULL;
448 struct sysfs_attribute *attribute = NULL;
449 unsigned char class_name[SYSFS_NAME_LEN];
451 if (dev == NULL || attrib == NULL || value == NULL) {
456 memset(class_name, 0, SYSFS_NAME_LEN);
457 if ((sysfs_find_device_class(dev,
458 class_name, SYSFS_NAME_LEN)) < 0) {
459 dprintf("Class device %s not found\n", dev);
462 clsdev = sysfs_open_class_device_by_name(class_name, dev);
463 if (clsdev == NULL) {
464 dprintf("Error opening %s in class %s\n", dev, class_name);
467 attribute = sysfs_get_directory_attribute(clsdev->directory, attrib);
468 if (attribute == NULL) {
469 dprintf("Attribute %s not defined for device %s on class %s\n",
470 attrib, dev, class_name);
471 sysfs_close_class_device(clsdev);
474 if ((sysfs_write_attribute(attribute, value, len)) < 0) {
475 dprintf("Error setting %s to %s\n", attrib, value);
476 sysfs_close_class_device(clsdev);
479 sysfs_close_class_device(clsdev);
484 * sysfs_read_classdev_attr: read an attribute for a given class device
485 * @dev: class device name for which the attribute has to be read
486 * @attrib: attribute to read
487 * @value: buffer to return value to user
488 * @len: size of buffer at "value"
489 * Returns 0 on success and -1 on error
491 int sysfs_read_classdev_attr(unsigned char *dev, unsigned char *attrib,
492 unsigned char *value, size_t len)
494 struct sysfs_class_device *clsdev = NULL;
495 struct sysfs_attribute *attribute = NULL;
496 unsigned char class_name[SYSFS_NAME_LEN];
498 if (dev == NULL || attrib == NULL || value == NULL) {
503 memset(class_name, 0, SYSFS_NAME_LEN);
504 if ((sysfs_find_device_class(dev,
505 class_name, SYSFS_NAME_LEN)) < 0) {
506 dprintf("Class device %s not found\n", dev);
509 clsdev = sysfs_open_class_device_by_name(class_name, dev);
510 if (clsdev == NULL) {
511 dprintf("Error opening %s in class %s\n", dev, class_name);
514 attribute = sysfs_get_directory_attribute(clsdev->directory, attrib);
515 if (attribute == NULL) {
516 dprintf("Attribute %s not defined for device %s on class %s\n",
517 attrib, dev, class_name);
518 sysfs_close_class_device(clsdev);
521 if (attribute->len > len) {
522 dprintf("Value length %d is greater that suppled buffer %d\n",
523 attribute->len, len);
524 sysfs_close_class_device(clsdev);
527 strncpy(value, attribute->value, attribute->len);
528 value[(attribute->len)+1] = 0;
529 sysfs_close_class_device(clsdev);