10
#include <sys/types.h>
11
#include <sys/ioctl.h>
12
#include <sys/socket.h>
14
#ifndef DBUS_API_SUBJECT_TO_CHANGE
15
#define DBUS_API_SUBJECT_TO_CHANGE 1
18
#include <dbus/dbus.h>
19
#include <hal/libhal.h>
26
* @defgroup HALint Hardware abstraction (HAL) information
27
* @ingroup libhdInternals
32
static void read_hal(hd_data_t *hd_data);
33
static void add_pci(hd_data_t *hd_data);
34
static void link_hal_tree(hd_data_t *hd_data);
36
static int hal_match_str(hal_prop_t *prop, const char *key, const char *val);
38
static int check_udi(const char *udi);
39
static FILE *hd_open_properties(const char *udi, const char *mode);
40
static char *skip_space(char *s);
41
static char *skip_non_eq_or_space(char *s);
42
static char *skip_nonquote(char *s);
43
static void parse_property(hal_prop_t *prop, char *str);
45
static void find_udi(hd_data_t *hd_data, hd_t *hd, int match);
47
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
51
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
54
void hd_scan_hal(hd_data_t *hd_data)
56
if(!hd_probe_feature(hd_data, pr_hal)) return;
58
hd_data->module = mod_hal;
61
remove_hd_entries(hd_data);
62
hd_data->hal = hd_free_hal_devices(hd_data->hal);
64
PROGRESS(1, 0, "read hal data");
68
if(!hd_data->hal) return;
70
link_hal_tree(hd_data);
72
PROGRESS(1, 0, "pci sysfs");
74
hd_pci_read_data(hd_data);
76
PROGRESS(2, 0, "pci devices");
83
void hd_scan_hal_basic(hd_data_t *hd_data)
85
hd_data->module = mod_hal;
88
hd_data->hal = hd_free_hal_devices(hd_data->hal);
90
PROGRESS(1, 0, "read hal data");
96
void read_hal(hd_data_t *hd_data)
100
LibHalContext *hal_ctx;
101
LibHalPropertySet *props;
102
LibHalPropertySetIterator it;
103
char **device_names, **slist, *s;
104
int i, num_devices, type;
108
dbus_error_init(&error);
110
if(!(conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error))) {
111
ADD2LOG(" hal: dbus_bus_get: %s: %s\n", error.name, error.message);
115
ADD2LOG(" hal: connected to: %s\n", dbus_bus_get_unique_name(conn));
117
if(!(hal_ctx = libhal_ctx_new())) return;
119
if(!libhal_ctx_set_dbus_connection(hal_ctx, conn)) return;
121
if(!libhal_ctx_init(hal_ctx, &error)) {
122
ADD2LOG(" hal: libhal_ctx_init: %s: %s\n", error.name, error.message);
127
dbus_error_init(&error);
129
if((device_names = libhal_get_all_devices(hal_ctx, &num_devices, &error))) {
130
ADD2LOG("----- hal device list -----\n");
131
for(i = 0; i < num_devices; i++) {
132
if(!(props = libhal_device_get_all_properties(hal_ctx, device_names[i], &error))) {
133
ADD2LOG(" hal: %s: %s\n", error.name, error.message);
134
dbus_error_init(&error);
138
dev = new_mem(sizeof *dev);
139
dev->udi = new_str(device_names[i]);
140
dev->next = hd_data->hal;
143
ADD2LOG(" %d: udi = '%s'\n", i, dev->udi);
145
for(libhal_psi_init(&it, props); libhal_psi_has_more(&it); libhal_psi_next(&it)) {
146
type = libhal_psi_get_type(&it);
148
prop = new_mem(sizeof *prop);
149
prop->next = dev->prop;
153
case LIBHAL_PROPERTY_TYPE_STRING:
154
prop->type = p_string;
155
prop->key = new_str(libhal_psi_get_key(&it));
156
prop->val.str = new_str(libhal_psi_get_string(&it));
159
case LIBHAL_PROPERTY_TYPE_INT32:
160
prop->type = p_int32;
161
prop->key = new_str(libhal_psi_get_key(&it));
162
prop->val.int32 = libhal_psi_get_int(&it);
165
case LIBHAL_PROPERTY_TYPE_UINT64:
166
prop->type = p_uint64;
167
prop->key = new_str(libhal_psi_get_key(&it));
168
prop->val.uint64 = libhal_psi_get_uint64(&it);
171
case LIBHAL_PROPERTY_TYPE_DOUBLE:
172
prop->type = p_double;
173
prop->key = new_str(libhal_psi_get_key(&it));
174
prop->val.d = libhal_psi_get_double(&it);
177
case LIBHAL_PROPERTY_TYPE_BOOLEAN:
179
prop->key = new_str(libhal_psi_get_key(&it));
180
prop->val.b = libhal_psi_get_bool(&it);
183
case LIBHAL_PROPERTY_TYPE_STRLIST:
185
prop->key = new_str(libhal_psi_get_key(&it));
186
for(slist = libhal_psi_get_strlist(&it); *slist; slist++) {
187
add_str_list(&prop->val.list, *slist);
192
prop->type = p_invalid;
195
if((s = hd_hal_print_prop(prop))) {
200
libhal_free_property_set(props);
201
if(i != num_devices - 1) ADD2LOG("\n");
205
ADD2LOG("----- hal device list end -----\n");
207
libhal_free_string_array(device_names);
209
dbus_error_free(&error);
212
ADD2LOG(" hal: empty device list\n");
216
libhal_ctx_shutdown(hal_ctx, &error);
218
libhal_ctx_free(hal_ctx);
220
dbus_connection_unref(conn);
222
dbus_error_free(&error);
226
void link_hal_tree(hd_data_t *hd_data)
231
for(dev = hd_data->hal; dev; dev = dev->next) {
232
prop = hal_get_str(dev->prop, "info.parent");
234
dev->parent = hal_find_device(hd_data, prop->val.str);
240
hal_device_t *hal_find_device(hd_data_t *hd_data, char *udi)
245
for(dev = hd_data->hal; dev; dev = dev->next) {
246
if(!strcmp(dev->udi, udi)) return dev;
254
void hal_invalidate(hal_prop_t *prop)
256
if(prop->type == p_string) free_mem(prop->val.str);
257
if(prop->type == p_list) free_str_list(prop->val.list);
258
prop->type = p_invalid;
259
memset(&prop->val, 0, sizeof prop->val);
263
void hal_invalidate_all(hal_prop_t *prop, const char *key)
265
for(; (prop = hal_get_any(prop, key)); prop = prop->next) {
266
hal_invalidate(prop);
271
hal_prop_t *hal_get_any(hal_prop_t *prop, const char *key)
273
for(; prop; prop = prop->next) {
274
if(!strcmp(prop->key, key)) return prop;
281
hal_prop_t *hal_get_bool(hal_prop_t *prop, const char *key)
283
for(; prop; prop = prop->next) {
284
if(prop->type == p_bool && !strcmp(prop->key, key)) return prop;
291
hal_prop_t *hal_get_int32(hal_prop_t *prop, const char *key)
293
for(; prop; prop = prop->next) {
294
if(prop->type == p_int32 && !strcmp(prop->key, key)) return prop;
301
hal_prop_t *hal_get_str(hal_prop_t *prop, const char *key)
303
for(; prop; prop = prop->next) {
304
if(prop->type == p_string && !strcmp(prop->key, key)) return prop;
311
char *hal_get_useful_str(hal_prop_t *prop, const char *key)
313
for(; prop; prop = prop->next) {
314
if(prop->type == p_string && !strcmp(prop->key, key)) {
315
if(prop->val.str && strncmp(prop->val.str, "Unknown", sizeof "Unknown" - 1)) return prop->val.str;
324
int hal_match_str(hal_prop_t *prop, const char *key, const char *val)
326
return val && (prop = hal_get_str(prop, key)) && !strcmp(prop->val.str, val);
330
hal_prop_t *hal_get_list(hal_prop_t *prop, const char *key)
332
for(; prop; prop = prop->next) {
333
if(prop->type == p_list && !strcmp(prop->key, key)) return prop;
340
void add_pci(hd_data_t *hd_data)
349
for(dev = hd_data->hal ; dev; dev = dev->next) {
350
if(dev->used) continue;
351
if(!hal_match_str(dev->prop, "info.bus", "pci")) continue;
354
hd = add_hd_entry(hd_data, __LINE__, 0);
356
if((prop = hal_get_str(dev->prop, "linux.sysfs_path"))) hd->sysfs_id = new_str(hd_sysfs_id(prop->val.str));
358
for(pci = hd_data->pci; pci; pci = pci->next) {
359
if(!strcmp(hd_sysfs_id(pci->sysfs_id), hd->sysfs_id)) {
360
hd->detail = new_mem(sizeof *hd->detail);
361
hd->detail->type = hd_detail_pci;
362
hd->detail->pci.data = pci;
368
hd_pci_complete_data(hd);
370
hd->udi = new_str(dev->udi);
371
if(dev->parent) hd->parent_udi = new_str(dev->parent->udi);
373
if((prop = hal_get_int32(dev->prop, "pci.device_protocol"))) hd->prog_if.id = prop->val.int32;
374
if((prop = hal_get_int32(dev->prop, "pci.device_subclass"))) hd->sub_class.id = prop->val.int32;
375
if((prop = hal_get_int32(dev->prop, "pci.device_class"))) hd->base_class.id = prop->val.int32;
377
i = (prop = hal_get_int32(dev->prop, "pci.vendor_id")) ? prop->val.int32 : 0;
378
j = (prop = hal_get_int32(dev->prop, "pci.product_id")) ? prop->val.int32 : 0;
381
hd->vendor.id = MAKE_ID(TAG_PCI, i);
382
hd->device.id = MAKE_ID(TAG_PCI, j);
385
if((s = hal_get_useful_str(dev->prop, "pci.vendor"))) hd->vendor.name = new_str(s);
386
if((s = hal_get_useful_str(dev->prop, "pci.product"))) hd->device.name = new_str(s);
388
i = (prop = hal_get_int32(dev->prop, "pci.subsys_vendor_id")) ? prop->val.int32 : 0;
389
j = (prop = hal_get_int32(dev->prop, "pci.subsys_product_id")) ? prop->val.int32 : 0;
392
hd->sub_vendor.id = MAKE_ID(TAG_PCI, i);
393
hd->sub_device.id = MAKE_ID(TAG_PCI, j);
396
if((s = hal_get_useful_str(dev->prop, "pci.subsys_vendor"))) hd->sub_vendor.name = new_str(s);
397
if((s = hal_get_useful_str(dev->prop, "pci.subsys_product"))) hd->sub_device.name = new_str(s);
399
if((prop = hal_get_str(dev->prop, "linux.sysfs_path"))) hd->sysfs_id = new_str(hd_sysfs_id(prop->val.str));
401
if((prop = hal_get_str(dev->prop, "info.linux.driver"))) add_str_list(&hd->drivers, prop->val.str);
403
hd->hal_prop = dev->prop;
407
for(hd = hd_data->hd; hd; hd = hd->next) {
410
hd->detail->type != hd_detail_pci ||
411
!(pci = hd->detail->pci.data)
421
char *hd_hal_print_prop(hal_prop_t *prop)
423
static char *s = NULL;
428
str_printf(&s, 0, "%s = '%s'", prop->key, prop->val.str);
432
str_printf(&s, 0, "%s = %d (0x%x)", prop->key, prop->val.int32, prop->val.int32);
436
str_printf(&s, 0, "%s = %"PRIu64"ull (0x%"PRIx64"ull)", prop->key, prop->val.uint64, prop->val.uint64);
440
str_printf(&s, 0, "%s = %#g", prop->key, prop->val.d);
444
str_printf(&s, 0, "%s = %s", prop->key, prop->val.b ? "true" : "false");
448
str_printf(&s, 0, "%s = { ", prop->key);
449
for(sl = prop->val.list; sl; sl = sl->next) {
450
str_printf(&s, -1, "'%s'%s", sl->str, sl->next ? ", " : "");
452
str_printf(&s, -1, " }");
456
str_printf(&s, 0, "%s", prop->key);
465
* Ensure that udi is a sane path name.
470
int check_udi(const char *udi)
474
!strncmp(udi, "../", sizeof "../" - 1) ||
475
strstr(udi, "/../") ||
483
int hd_write_properties(const char *udi, hal_prop_t *prop)
488
f = hd_open_properties(udi, "w");
492
for(; prop; prop = prop->next) {
493
if(prop->type == p_invalid) continue;
494
s = hd_hal_print_prop(prop);
495
if(s) fprintf(f, "%s\n", s);
504
hal_prop_t *hd_read_properties(const char *udi)
507
str_list_t *sl0, *sl;
508
hal_prop_t *prop_list = NULL, *prop_list_e = NULL, prop, *p;
510
if(!udi) return NULL;
512
while(*udi == '/') udi++;
514
if(!check_udi(udi)) return NULL;
516
str_printf(&path, 0, "%s/%s", hd_get_hddb_path("udi"), udi);
518
sl0 = read_file(path, 0, 0);
522
for(sl = sl0; sl; sl = sl->next) {
523
parse_property(&prop, sl->str);
524
if(prop.type != p_invalid) {
525
p = new_mem(sizeof *p);
528
prop_list_e->next = p;
529
prop_list_e = prop_list_e->next;
532
prop_list = prop_list_e = p;
536
prop.key = free_mem(prop.key);
546
FILE *hd_open_properties(const char *udi, const char *mode)
548
str_list_t *path, *sl;
555
while(*udi == '/') udi++;
557
if(!check_udi(udi)) return f;
559
path = hd_split('/', udi);
563
dir = new_str(hd_get_hddb_path("udi"));
565
for(err = 0, sl = path; sl->next; sl = sl->next) {
566
str_printf(&dir, -1, "/%s", sl->str);
567
i = lstat(dir, &sbuf);
568
if(i == -1 && errno == ENOENT) {
570
i = lstat(dir, &sbuf);
572
if(i || !S_ISDIR(sbuf.st_mode)) {
579
str_printf(&dir, -1, "/%s", sl->str);
580
f = fopen(dir, mode);
589
char *skip_space(char *s)
591
while(isspace(*s)) s++;
597
char *skip_non_eq_or_space(char *s)
599
while(*s && *s != '=' && !isspace(*s)) s++;
605
char *skip_nonquote(char *s)
607
while(*s && *s != '\'') s++;
613
void parse_property(hal_prop_t *prop, char *str)
615
char *s, *s1, *key, *s_val;
618
memset(prop, 0, sizeof *prop);
619
prop->type = p_invalid;
622
s = skip_non_eq_or_space(key = s);
631
prop->key = new_str(key);
637
s = strrchr(s_val, '\'');
639
prop->type = p_string;
640
prop->val.str = strdup(s_val);
643
s_val = skip_space(s + 1);
644
s1 = strrchr(s_val, '}');
647
while(*s_val++ == '\'') {
648
s = skip_nonquote(s_val);
650
add_str_list(&prop->val.list, s_val);
651
s_val = skip_nonquote(s);
654
else if(!strncmp(s, "true", 4)) {
659
else if(!strncmp(s, "false", 5)) {
664
else if(isdigit(*s) || *s == '+' || *s == '-' || *s == '.') {
665
*skip_non_eq_or_space(s) = 0;
667
prop->type = p_double;
668
prop->val.d = strtod(s, NULL);
672
if(l >= 2 && s[l - 2] == 'l' && s[l - 1] == 'l') {
673
prop->type = p_uint64;
677
prop->type = p_int32;
679
if(l >= 1 && s[l - 1] == 'u') s[--l] = 0;
681
if(prop->type == p_int32) {
682
prop->val.int32 = strtol(s, NULL, 0);
685
prop->val.uint64 = strtoull(s, NULL, 0);
692
void hd_scan_hal_assign_udi(hd_data_t *hd_data)
697
if(!hd_data->hal) return;
699
PROGRESS(2, 0, "assign udi");
701
for(i = 0; i < 3; i++) {
702
for(hd = hd_data->hd; hd; hd = hd->next) find_udi(hd_data, hd, i);
707
void find_udi(hd_data_t *hd_data, hd_t *hd, int match)
710
char *h_sysfsid, *h_devname;
716
/* device file first, thanks to usb devices */
718
/* based on device file */
722
(match == 0 && hd->unix_dev_name) ||
723
(match == 1 && hd->unix_dev_name2) ||
724
(match == 2 && hd->unix_dev_names)
726
) for(dev = hd_data->hal; dev; dev = dev->next) {
727
h_devname = hal_get_useful_str(dev->prop, "linux.device_file");
728
if(!h_devname) h_devname = hal_get_useful_str(dev->prop, "block.device");
730
if(match == 0 && hd->unix_dev_name && !strcmp(hd->unix_dev_name, h_devname)) break;
731
if(match == 1 && hd->unix_dev_name2 && !strcmp(hd->unix_dev_name2, h_devname)) break;
732
if(match == 2 && search_str_list(hd->unix_dev_names, h_devname)) break;
736
/* based on sysfs id, only once for match == 0 */
737
if(!dev && !match && hd->sysfs_id) for(dev = hd_data->hal; dev; dev = dev->next) {
738
h_sysfsid = hd_sysfs_id(hal_get_useful_str(dev->prop, "linux.sysfs_path"));
739
if(h_sysfsid && !strcmp(hd->sysfs_id, h_sysfsid)) break;
743
hd->udi = new_str(dev->udi);
744
hd->hal_prop = dev->prop;