chiark / gitweb /
[PATCH] clean up some debugging stuff in namedev.c
[elogind.git] / libsysfs / sysfs_bus.c
1 /*
2  * sysfs_bus.c
3  *
4  * Generic bus utility functions for libsysfs
5  *
6  * Copyright (C) 2003 International Business Machines, Inc.
7  *
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.
12  *
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.
17  *
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
21  *
22  */
23 #include "libsysfs.h"
24 #include "sysfs.h"
25
26 /**
27  * sysfs_close_bus: close single bus
28  * @bus: bus structure
29  */
30 void sysfs_close_bus(struct sysfs_bus *bus)
31 {
32         struct sysfs_device *curdev = NULL, *nextdev = NULL;
33         struct sysfs_driver *curdrv = NULL, *nextdrv = NULL;
34
35         if (bus != NULL) {
36                 if (bus->directory != NULL)
37                         sysfs_close_directory(bus->directory);
38                 for (curdev = bus->devices; curdev != NULL;
39                      curdev = nextdev) {
40                         nextdev = curdev->next;
41                         sysfs_close_device(curdev);
42                 }
43                 for (curdrv = bus->drivers; curdrv != NULL;
44                      curdrv = nextdrv) {
45                         nextdrv = curdrv->next;
46                         sysfs_close_driver(curdrv);
47                 }
48                 free(bus);
49         }
50 }
51
52 /**
53  * alloc_bus: mallocs new bus structure
54  * returns sysfs_bus_bus struct or NULL
55  */
56 static struct sysfs_bus *alloc_bus(void)
57 {
58         return (struct sysfs_bus *)calloc(1, sizeof(struct sysfs_bus));
59 }
60
61 /**
62  * open_bus_dir: opens up sysfs bus directory
63  * returns sysfs_directory struct with success and NULL with error
64  */
65 static struct sysfs_directory *open_bus_dir(const char *name)
66 {
67         struct sysfs_directory *busdir = NULL, *cur = NULL, *next = NULL;
68         char buspath[SYSFS_PATH_MAX];
69
70         if (name == NULL) {
71                 errno = EINVAL;
72                 return NULL;
73         }
74
75         memset(buspath, 0, SYSFS_PATH_MAX);
76         if ((sysfs_get_mnt_path(buspath, SYSFS_PATH_MAX)) != 0) {
77                 dprintf(stderr, "Sysfs not supported on this system\n");
78                 return NULL;
79         }
80
81         strcat(buspath, SYSFS_BUS_DIR);
82         strcat(buspath, "/");
83         strcat(buspath, name);
84         busdir = sysfs_open_directory(buspath);
85         if (busdir == NULL) {
86                 errno = EINVAL;
87                 dprintf(stderr,"Bus %s not supported on this system\n",
88                         name);
89                 return NULL;
90         }
91         if ((sysfs_read_directory(busdir)) != 0) {
92                 dprintf(stderr, "Error reading %s bus dir %s\n", name, 
93                         buspath);
94                 sysfs_close_directory(busdir);
95                 return NULL;
96         }
97         /* read in devices and drivers subdirs */
98         for (cur = busdir->subdirs; cur != NULL; cur = next) {
99                 next = cur->next;
100                 if ((sysfs_read_directory(cur)) != 0)
101                         continue;
102         }
103
104         return busdir;
105 }
106
107 /**
108  * add_dev_to_bus: adds a bus device to bus device list
109  * @bus: bus to add the device
110  * @dev: device to add
111  */
112 static void add_dev_to_bus(struct sysfs_bus *bus, struct sysfs_device *dev)
113 {
114         if (bus != NULL && dev != NULL) {
115                 dev->next = bus->devices;
116                 bus->devices = dev;
117         }
118 }
119
120 /**
121  * add_driver_to_bus: adds a bus driver to bus driver list
122  * @bus: bus to add driver to
123  * @driver: driver to add
124  */
125 static void add_driver_to_bus(struct sysfs_bus *bus, 
126                                 struct sysfs_driver *driver)
127 {
128         if (bus != NULL && driver != NULL) {
129                 driver->next = bus->drivers;
130                 bus->drivers = driver;
131         }
132 }
133
134 /**
135  * get_all_bus_devices: gets all devices for bus
136  * @bus: bus to get devices for
137  * returns 0 with success and -1 with failure
138  */
139 static int get_all_bus_devices(struct sysfs_bus *bus)
140 {
141         struct sysfs_device *bdev = NULL;
142         struct sysfs_directory *cur = NULL;
143         struct sysfs_dlink *curl = NULL, *nextl = NULL;
144         char dirname[SYSFS_NAME_LEN];
145
146         if (bus == NULL || bus->directory == NULL) {
147                 errno = EINVAL;
148                 return -1;
149         }
150         for (cur = bus->directory->subdirs; cur != NULL; cur = cur->next) {
151                 memset(dirname, 0, SYSFS_NAME_LEN);
152                 if ((sysfs_get_name_from_path(cur->path, dirname,
153                     SYSFS_NAME_LEN)) != 0)
154                         continue;
155                 if (strcmp(dirname, SYSFS_DEVICES_NAME) != 0)
156                         continue;
157                 for (curl = cur->links; curl != NULL; curl = nextl) {
158                         nextl = curl->next;
159                         bdev = sysfs_open_device(curl->target->path);
160                         if (bdev == NULL) {
161                                 dprintf(stderr, "Error opening device at %s\n",
162                                         curl->target->path);
163                                 continue;
164                         }
165                         add_dev_to_bus(bus, bdev);
166                 }
167         }
168                         
169         return 0;
170 }
171
172 /**
173  * get_all_bus_drivers: get all pci drivers
174  * @bus: pci bus to add drivers to
175  * returns 0 with success and -1 with error
176  */
177 static int get_all_bus_drivers(struct sysfs_bus *bus)
178 {
179         struct sysfs_driver *driver = NULL;
180         struct sysfs_directory *cur = NULL, *next = NULL;
181         struct sysfs_directory *cursub = NULL, *nextsub = NULL;
182         char dirname[SYSFS_NAME_LEN];
183
184         if (bus == NULL || bus->directory == NULL) {
185                 errno = EINVAL;
186                 return -1;
187         }
188         for (cur = bus->directory->subdirs; cur != NULL; cur = next) {
189                 next = cur->next;
190                 memset(dirname, 0, SYSFS_NAME_LEN);
191                 if ((sysfs_get_name_from_path(cur->path, dirname,
192                     SYSFS_NAME_LEN)) != 0)
193                         continue;
194                 if (strcmp(dirname, SYSFS_DRIVERS_NAME) != 0)
195                         continue;
196                 for (cursub = cur->subdirs; cursub != NULL; cursub = nextsub) {
197                         nextsub = cursub->next;
198                         driver = sysfs_open_driver(cursub->path);
199                         if (driver == NULL) {
200                                 dprintf(stderr, "Error opening driver at %s\n",
201                                         cursub->path);
202                                 continue;
203                         }
204                         add_driver_to_bus(bus, driver);
205                 }
206         }
207         
208         return 0;
209 }
210
211 /**
212  * match_bus_device_to_driver: returns 1 if device is bound to driver
213  * @driver: driver to match
214  * @busid: busid of device to match
215  * returns 1 if found and 0 if not found
216  */
217 static int match_bus_device_to_driver(struct sysfs_driver *driver, char *busid)
218 {
219         struct sysfs_dlink *cur = NULL, *next = NULL;
220         int found = 0;
221
222         if (driver == NULL || driver->directory == NULL || busid == NULL) {
223                 errno = EINVAL;
224                 return found;
225         }
226         for (cur = driver->directory->links; cur != NULL && found == 0;
227              cur = next) {
228                 next = cur->next;
229                 if ((strcmp(cur->name, busid)) == 0)
230                         found++;
231         }
232         return found;
233 }
234
235 /**
236  * link_bus_devices_to_drivers: goes through and links devices to drivers
237  * @bus: bus to link
238  */
239 static void link_bus_devices_to_drivers(struct sysfs_bus *bus)
240 {
241         struct sysfs_device *dev = NULL, *nextdev = NULL;
242         struct sysfs_driver *drv = NULL, *nextdrv = NULL;
243         
244         if (bus != NULL && bus->devices != NULL && bus->drivers != NULL) {
245                 for (dev = bus->devices; dev != NULL; dev = nextdev) {
246                         nextdev = dev->next;
247
248                         for (drv = bus->drivers; drv != NULL; drv = nextdrv) {
249                                 nextdrv = drv->next;
250                                 if ((match_bus_device_to_driver(drv, 
251                                     dev->bus_id)) != 0) {
252                                         dev->driver = drv;
253                                         drv->device = dev;
254                                 }
255                         }
256                 }
257         }
258 }
259
260 /**
261  * sysfs_open_bus: opens specific bus and all its devices on system
262  * returns sysfs_bus structure with success or NULL with error.
263  */
264 struct sysfs_bus *sysfs_open_bus(const char *name)
265 {
266         struct sysfs_bus *bus = NULL;
267         struct sysfs_directory *busdir = NULL;
268
269         if (name == NULL) {
270                 errno = EINVAL;
271                 return NULL;
272         }
273
274         bus = alloc_bus();
275         if (bus == NULL) {
276                 perror("malloc");
277                 return NULL;
278         }
279         strcpy(bus->name, name);        
280         busdir = open_bus_dir(name);
281         if (busdir == NULL) {
282                 dprintf(stderr,"Invalid bus, %s not supported on this system\n",
283                         name);
284                 sysfs_close_bus(bus);
285                 return NULL;
286         }
287         bus->directory = busdir;
288         if ((get_all_bus_devices(bus)) != 0) {
289                 dprintf(stderr, "Error reading %s bus devices\n", name);
290                 sysfs_close_bus(bus);
291                 return NULL;
292         }
293         if ((get_all_bus_drivers(bus)) != 0) {
294                 dprintf(stderr, "Error reading %s bus drivers\n", name);
295                 sysfs_close_bus(bus);
296                 return NULL;
297         }
298         link_bus_devices_to_drivers(bus);
299
300         return bus;
301 }