00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #ifdef HAVE_CONFIG_H
00027 # include <config.h>
00028 #endif
00029
00030 #include <ctype.h>
00031 #include <stdio.h>
00032 #include <stdlib.h>
00033 #include <string.h>
00034 #include <getopt.h>
00035 #include <assert.h>
00036 #include <unistd.h>
00037 #include <stdarg.h>
00038
00039 #include <dbus/dbus.h>
00040
00041 #include "../osspec.h"
00042 #include "../logger.h"
00043
00044 #include "linux_common.h"
00045 #include "linux_pci.h"
00046 #include "linux_i2c.h"
00047 #include "linux_usb.h"
00048 #include "linux_ide.h"
00049 #include "linux_class_block.h"
00050 #include "linux_class_scsi.h"
00051 #include "linux_class_i2c_adapter.h"
00052 #include "linux_class_v4l.h"
00053 #include "linux_class_net.h"
00054 #include "linux_class_input.h"
00055
00056 #include "libsysfs/libsysfs.h"
00057
00067 char sysfs_mount_path[SYSFS_PATH_MAX];
00068
00069
00070
00085 static void visit_class_device(const char* path, dbus_bool_t visit_children)
00086 {
00087 struct sysfs_class_device* class_device;
00088 struct sysfs_directory* subdir;
00089
00090 class_device = sysfs_open_class_device(path);
00091 if( class_device==NULL )
00092 DIE(("Coulnd't get sysfs class device object for path %s", path));
00093
00094
00095
00096
00097
00098
00099
00100
00101 if( strcmp(class_device->classname, "scsi_host")==0 )
00102 visit_class_device_scsi_host(path, class_device);
00103 else if( strcmp(class_device->classname, "scsi_device")==0 )
00104 visit_class_device_scsi_device(path, class_device);
00105 else if( strcmp(class_device->classname, "i2c-adapter")==0 )
00106 visit_class_device_i2c_adapter(path, class_device);
00107 else if( strcmp(class_device->classname, "video4linux")==0 )
00108 visit_class_device_v4l(path, class_device);
00109 else if( strcmp(class_device->classname, "block")==0 )
00110 visit_class_device_block(path, class_device);
00111 else if( strcmp(class_device->classname, "net")==0 )
00112 visit_class_device_net(path, class_device);
00113
00114 if( visit_children && class_device->directory!=NULL &&
00115 class_device->directory->subdirs!=NULL )
00116 {
00117 dlist_for_each_data(class_device->directory->subdirs, subdir,
00118 struct sysfs_directory)
00119 {
00120 char newpath[SYSFS_PATH_MAX];
00121 snprintf(newpath, SYSFS_PATH_MAX, "%s/%s", path, subdir->name);
00122 visit_class_device(newpath, TRUE);
00123 }
00124 }
00125
00126 sysfs_close_class_device(class_device);
00127 }
00128
00139 static void visit_class(const char* class_name, dbus_bool_t visit_children)
00140 {
00141 struct sysfs_class* cls = NULL;
00142 struct sysfs_class_device* cur = NULL;
00143
00144 cls = sysfs_open_class(class_name);
00145 if( cls==NULL )
00146 {
00147 HAL_ERROR(("Error opening class %s\n", class_name));
00148 return;
00149 }
00150
00151 if( cls->devices!=NULL )
00152 {
00153 dlist_for_each_data(cls->devices, cur, struct sysfs_class_device)
00154 {
00155 visit_class_device(cur->path, visit_children);
00156 }
00157 }
00158
00159 sysfs_close_class(cls);
00160 }
00161
00175 static void visit_device(const char* path, dbus_bool_t visit_children)
00176 {
00177 struct sysfs_device* device;
00178 struct sysfs_directory* subdir;
00179 struct sysfs_class* cls;
00180 struct sysfs_class_device* class_device;
00181
00182 device = sysfs_open_device(path);
00183 if( device==NULL )
00184 DIE(("Coulnd't get sysfs device object for path %s", path));
00185
00186
00187
00188
00189
00190
00191
00192 if( device->bus!=NULL )
00193 {
00194 if( strcmp(device->bus, "pci")==0 )
00195 visit_device_pci(path, device);
00196 else if( strcmp(device->bus, "usb")==0 )
00197 visit_device_usb(path, device);
00198
00199
00200
00201
00202 else if( strcmp(device->bus, "ide")==0 )
00203 visit_device_ide(path, device);
00205 else if( strncmp(device->bus_id, "ide", 3)==0 )
00206 visit_device_ide_host(path, device);
00207 else if( strcmp(device->bus, "i2c")==0 )
00208 visit_device_i2c(path, device);
00209 else if( strncmp(device->bus_id, "i2c", 3)==0 )
00210 {
00211
00212
00213
00214
00215 cls = sysfs_open_class("i2c-adapter");
00216 if (cls != NULL)
00217 {
00218 if( cls->devices!=NULL )
00219 {
00220 dlist_for_each_data(cls->devices, class_device, struct sysfs_class_device)
00221 {
00222 printf("device->bus_id = %s, cls->name = %s\n", device->bus_id, class_device->name);
00223 if ( strcmp(device->bus_id, class_device->name) == 0 )
00224 visit_class_device_i2c_adapter(class_device->path, class_device);
00225 }
00226 }
00227 sysfs_close_class(cls);
00228 }
00229 }
00230 {
00231
00232 }
00233
00234
00235
00236
00237 }
00238
00239
00240 if( visit_children && device->directory->subdirs!=NULL )
00241 {
00242 dlist_for_each_data(device->directory->subdirs, subdir,
00243 struct sysfs_directory)
00244 {
00245 char newpath[SYSFS_PATH_MAX];
00246 snprintf(newpath, SYSFS_PATH_MAX, "%s/%s", path, subdir->name);
00247 visit_device(newpath, TRUE);
00248 }
00249 }
00250
00251 sysfs_close_device(device);
00252 }
00253
00254
00255
00256
00257 void osspec_init(DBusConnection* dbus_connection)
00258 {
00259 int rc;
00260 DBusError error;
00261
00262
00263 rc = sysfs_get_mnt_path(sysfs_mount_path, SYSFS_PATH_MAX);
00264 if( rc!=0 )
00265 {
00266 DIE(("Couldn't get mount path for sysfs"));
00267 }
00268 HAL_INFO(("Mountpoint for sysfs is %s", sysfs_mount_path));
00269
00270 linux_pci_init();
00271 linux_usb_init();
00272
00273 linux_ide_init();
00274 linux_class_v4l_init();
00275 linux_class_scsi_init();
00276 linux_class_block_init();
00277 linux_class_net_init();
00278
00279
00280 dbus_error_init(&error);
00281 dbus_bus_add_match(dbus_connection,
00282 "type='signal',"
00283 "interface='org.kernel.udev.NodeMonitor',"
00284
00285 "path='/org/kernel/udev/NodeMonitor'", &error);
00286 if( dbus_error_is_set(&error) )
00287 {
00288 HAL_WARNING(("Cannot subscribe to udev signals, error=%s",
00289 error.message));
00290 }
00291 }
00292
00294 dbus_bool_t is_probing;
00295
00296
00297 void osspec_probe()
00298 {
00299 char path[SYSFS_PATH_MAX];
00300 struct sysfs_directory* current;
00301 struct sysfs_directory* dir;
00302
00303 is_probing = TRUE;
00304
00305
00306 strncpy(path, sysfs_mount_path, SYSFS_PATH_MAX);
00307 strncat(path, SYSFS_DEVICES_DIR, SYSFS_PATH_MAX);
00308
00309 dir = sysfs_open_directory(path);
00310 if( dir==NULL )
00311 {
00312 DIE(("Error opening sysfs directory at %s\n", path));
00313 }
00314 if( sysfs_read_directory(dir)!=0 )
00315 {
00316 DIE(("Error reading sysfs directory at %s\n", path));
00317 }
00318 if( dir->subdirs!=NULL )
00319 {
00320 dlist_for_each_data(dir->subdirs, current, struct sysfs_directory)
00321 {
00322 visit_device(current->path, TRUE);
00323 }
00324 }
00325 sysfs_close_directory(dir);
00326
00327
00328 visit_class("video4linux", TRUE);
00329
00330
00331 visit_class("scsi_host", FALSE);
00332
00333
00334 visit_class("scsi_device", FALSE);
00335
00336
00337 visit_class("block", TRUE);
00338
00339
00340 visit_class("net", TRUE);
00341
00342
00343 linux_class_input_probe();
00344
00345 is_probing = FALSE;
00346
00347
00348
00349
00350 linux_pci_detection_done();
00351 linux_usb_detection_done();
00352
00353 linux_ide_detection_done();
00354 linux_class_block_detection_done();
00355 linux_class_input_detection_done();
00356 linux_class_net_detection_done();
00357 linux_class_scsi_detection_done();
00358 }
00359
00361 #define HOTPLUG_INPUT_MAX 128
00362
00371 static DBusHandlerResult handle_hotplug(DBusConnection* connection,
00372 DBusMessage* message)
00373 {
00374 DBusMessageIter iter;
00375 DBusMessageIter dict_iter;
00376 dbus_bool_t is_add;
00377 char* subsystem;
00378 char input_name[HOTPLUG_INPUT_MAX];
00379 char input_phys[HOTPLUG_INPUT_MAX];
00380 char input_key[HOTPLUG_INPUT_MAX];
00381 int input_ev=0;
00382 int input_rel=0;
00383 int input_abs=0;
00384 int input_led=0;
00385 char sysfs_devpath[SYSFS_PATH_MAX];
00386
00387 sysfs_devpath[0] = '\0';
00388 input_name[0] = input_phys[0] = input_key[0] = '\0';
00389
00390 dbus_message_iter_init(message, &iter);
00391
00392 if( dbus_message_iter_get_arg_type(&iter)!=DBUS_TYPE_STRING )
00393 {
00395 dbus_message_unref(message);
00396 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00397 }
00398 subsystem = dbus_message_iter_get_string(&iter);
00399
00400 dbus_message_iter_next(&iter);
00401 dbus_message_iter_init_dict_iterator(&iter, &dict_iter);
00402
00403 is_add = FALSE;
00404
00405 for( ;dbus_message_iter_has_next(&dict_iter);
00406 dbus_message_iter_next(&dict_iter))
00407 {
00408 char* key;
00409 char* value;
00410
00411 key = dbus_message_iter_get_dict_key(&dict_iter);
00412 value = dbus_message_iter_get_string(&dict_iter);
00413
00414
00415
00416 if( strcmp(key, "ACTION")==0 )
00417 {
00418 if( strcmp(value, "add")==0 )
00419 {
00420 is_add = TRUE;
00421 }
00422 }
00423 else if( strcmp(key, "DEVPATH")==0 )
00424 {
00425 strncpy(sysfs_devpath, sysfs_mount_path, SYSFS_PATH_MAX);
00426 strncat(sysfs_devpath, value, SYSFS_PATH_MAX);
00427 }
00428 else if( strcmp(key, "NAME")==0 )
00429 strncpy(input_name, value, HOTPLUG_INPUT_MAX);
00430 else if( strcmp(key, "PHYS")==0 )
00431 strncpy(input_phys, value, HOTPLUG_INPUT_MAX);
00432 else if( strcmp(key, "KEY")==0 )
00433 strncpy(input_key, value, HOTPLUG_INPUT_MAX);
00434 else if( strcmp(key, "EV")==0 )
00435 input_ev = parse_dec(value);
00436 else if( strcmp(key, "REL")==0 )
00437 input_rel = parse_hex(value);
00438 else if( strcmp(key, "ABS")==0 )
00439 input_abs = parse_hex(value);
00440 else if( strcmp(key, "LED")==0 )
00441 input_led = parse_hex(value);
00442 }
00443
00444 HAL_INFO(("HotplugEvent %s, subsystem=%s devpath=%s",
00445 (is_add ? "add" : "remove"), subsystem,
00446 sysfs_devpath[0]!='\0' ? sysfs_devpath : "(none)"));
00447
00448 if( sysfs_devpath[0]!='\0' &&
00449 (strcmp(subsystem, "usb")==0 ||
00450 strcmp(subsystem, "pci")==0 ||
00451
00452 strcmp(subsystem, "i2c")==0))
00453 {
00454
00455 if( is_add )
00456 {
00457 HAL_INFO(("Adding device @ sysfspath %s", sysfs_devpath));
00458 visit_device(sysfs_devpath, FALSE);
00459 }
00460 else
00461 {
00462 HalDevice* d;
00463
00464 d = ds_device_find_by_key_value_string("linux.sysfs_path",
00465 sysfs_devpath, TRUE);
00466 if( d==NULL )
00467 {
00468 HAL_WARNING(("Couldn't remove device @ %s on hotplug remove",
00469 sysfs_devpath));
00470 }
00471 else
00472 {
00473 HAL_INFO(("Removing device @ sysfspath %s, udi %s",
00474 sysfs_devpath, d->udi));
00475
00476 if( ds_property_exists(d, "info.persistent") &&
00477 ds_property_get_bool(d, "info.persistent") )
00478 {
00479 ds_property_set_bool(d, "info.not_available", TRUE);
00480
00481
00482
00483 ds_property_remove(d, "info.parent");
00484 ds_property_remove(d, "info.physical_device");
00485 ds_property_remove(d, "linux.sysfs_path");
00486 ds_property_remove(d, "linux.sysfs_path_device");
00487 HAL_INFO(("Device %s is persistent, so not removed",
00488 d->udi));
00489 }
00490 else
00491 {
00492 ds_device_destroy(d);
00493 }
00494 }
00495 }
00496 }
00497 else if( sysfs_devpath[0]!='\0' &&
00498 (strcmp(subsystem, "net")==0 ||
00499 strcmp(subsystem, "block")==0 ||
00500 strcmp(subsystem, "scsi_host")==0 ||
00501 strcmp(subsystem, "scsi_device")==0 ||
00502 strcmp(subsystem, "i2c-adapter")==0 ||
00503 strcmp(subsystem, "video4linux")==0 ))
00504 {
00505 if( is_add )
00506 {
00507 HAL_INFO(("Adding classdevice @ sysfspath %s", sysfs_devpath));
00508 visit_class_device(sysfs_devpath, FALSE);
00509 }
00510 else
00511 {
00512 HalDevice* d;
00513 d = ds_device_find_by_key_value_string("linux.sysfs_path",
00514 sysfs_devpath, TRUE);
00515 if( d==NULL )
00516 {
00517 HAL_WARNING(("Couldn't remove device @ %s on hotplug remove",
00518 sysfs_devpath));
00519 }
00520 else
00521 {
00522 if( strcmp(subsystem, "block")==0 )
00523 linux_class_block_removed(d);
00524
00525 HAL_INFO(("Removing classdevice @ sysfspath %s, udi %s",
00526 sysfs_devpath, d->udi));
00527 ds_device_destroy(d);
00528 }
00529 }
00530 }
00531 else if( strcmp(subsystem, "input")==0 )
00532 {
00533 if( is_add )
00534 {
00538 linux_class_input_handle_hotplug_add(input_name, input_phys,
00539 input_key,
00540 input_ev, input_rel,
00541 input_abs, input_led);
00542 }
00543 else
00544 {
00545
00546
00547
00548
00549 }
00550 }
00551
00552 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00553 }
00554
00555
00556 static void handle_udev_node_created_found_device(HalDevice* d,
00557 void* data1, void* data2);
00558
00567 static DBusHandlerResult handle_udev_node_created(DBusConnection* connection,
00568 DBusMessage* message)
00569 {
00570 char* filename;
00571 char* sysfs_path;
00572 char sysfs_dev_path[SYSFS_PATH_MAX];
00573
00574 if( dbus_message_get_args(message, NULL,
00575 DBUS_TYPE_STRING, &filename,
00576 DBUS_TYPE_STRING, &sysfs_path,
00577 DBUS_TYPE_INVALID) )
00578 {
00579 strncpy(sysfs_dev_path, sysfs_mount_path, SYSFS_PATH_MAX);
00580 strncat(sysfs_dev_path, sysfs_path, SYSFS_PATH_MAX);
00581 HAL_INFO(("udev NodeCreated: %s %s\n", filename, sysfs_dev_path));
00582
00583
00584
00585
00586 ds_device_async_find_by_key_value_string(
00587 "linux.sysfs_path_device",
00588 sysfs_dev_path,
00589 FALSE,
00590 handle_udev_node_created_found_device,
00591 (void*) filename, NULL,
00592 HAL_LINUX_HOTPLUG_TIMEOUT);
00593
00594
00595
00596 dbus_free(sysfs_path);
00597 }
00598
00599 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00600 }
00601
00608 static void handle_udev_node_created_found_device(HalDevice* d,
00609 void* data1, void* data2)
00610 {
00611 char* filename = (char*) data1;
00612
00613 if( d!=NULL )
00614 {
00615 HAL_INFO(("Setting block.device=%s for udi=%s", filename, d->udi));
00616 ds_property_set_string(d, "block.device", filename);
00617 linux_class_block_check_if_ready_to_add(d);
00618 }
00619 else
00620 {
00621 HAL_WARNING(("No HAL device corresponding to device %s", filename));
00622 }
00623
00624 dbus_free(filename);
00625 }
00626
00635 DBusHandlerResult osspec_filter_function(DBusConnection* connection,
00636 DBusMessage* message,
00637 void* user_data)
00638 {
00639
00640
00641
00642
00643
00644
00645
00646
00647 if( dbus_message_is_method_call(
00648 message,
00649 "org.freedesktop.Hal.Linux.Hotplug",
00650 "HotplugEvent") &&
00651 strcmp(dbus_message_get_path(message),
00652 "/org/freedesktop/Hal/Linux/Hotplug")==0 )
00653 {
00654 return handle_hotplug(connection, message);
00655 }
00656 else if( dbus_message_is_signal(message,
00657 "org.kernel.udev.NodeMonitor",
00658 "NodeCreated") )
00659 {
00660 return handle_udev_node_created(connection, message);
00661 }
00662 else if( dbus_message_is_signal(message, "org.kernel.udev.NodeMonitor",
00663 "NodeDeleted") )
00664 {
00665
00666
00667
00668 }
00669
00670 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00671 }
00672