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
00027 #ifdef HAVE_CONFIG_H
00028 # include <config.h>
00029 #endif
00030
00031 #include <stdio.h>
00032 #include <string.h>
00033
00034 #include "device.h"
00035 #include "hald_marshal.h"
00036 #include "logger.h"
00037
00038 static GObjectClass *parent_class;
00039
00040 enum {
00041 PROPERTY_CHANGED,
00042 CAPABILITY_ADDED,
00043 LAST_SIGNAL
00044 };
00045
00046 static guint signals[LAST_SIGNAL] = { 0 };
00047
00048 static void
00049 hal_device_finalize (GObject *obj)
00050 {
00051 HalDevice *device = HAL_DEVICE (obj);
00052
00053 g_slist_foreach (device->properties, (GFunc) hal_property_free, NULL);
00054
00055 g_free (device->udi);
00056
00057 if (parent_class->finalize)
00058 parent_class->finalize (obj);
00059 }
00060
00061 static void
00062 hal_device_class_init (HalDeviceClass *klass)
00063 {
00064 GObjectClass *obj_class = (GObjectClass *) klass;
00065
00066 parent_class = g_type_class_peek_parent (klass);
00067
00068 obj_class->finalize = hal_device_finalize;
00069
00070 signals[PROPERTY_CHANGED] =
00071 g_signal_new ("property_changed",
00072 G_TYPE_FROM_CLASS (klass),
00073 G_SIGNAL_RUN_LAST,
00074 G_STRUCT_OFFSET (HalDeviceClass,
00075 property_changed),
00076 NULL, NULL,
00077 hald_marshal_VOID__STRING_BOOL_BOOL,
00078 G_TYPE_NONE, 3,
00079 G_TYPE_STRING,
00080 G_TYPE_BOOLEAN,
00081 G_TYPE_BOOLEAN);
00082
00083 signals[CAPABILITY_ADDED] =
00084 g_signal_new ("capability_added",
00085 G_TYPE_FROM_CLASS (klass),
00086 G_SIGNAL_RUN_LAST,
00087 G_STRUCT_OFFSET (HalDeviceClass,
00088 capability_added),
00089 NULL, NULL,
00090 hald_marshal_VOID__STRING,
00091 G_TYPE_NONE, 1,
00092 G_TYPE_STRING);
00093 }
00094
00095 static void
00096 hal_device_init (HalDevice *device)
00097 {
00098 static int temp_device_counter = 0;
00099
00100 device->udi = g_strdup_printf ("/org/freedesktop/Hal/devices/temp/%d",
00101 temp_device_counter++);
00102 }
00103
00104 GType
00105 hal_device_get_type (void)
00106 {
00107 static GType type = 0;
00108
00109 if (!type) {
00110 static GTypeInfo type_info = {
00111 sizeof (HalDeviceClass),
00112 NULL, NULL,
00113 (GClassInitFunc) hal_device_class_init,
00114 NULL, NULL,
00115 sizeof (HalDevice),
00116 0,
00117 (GInstanceInitFunc) hal_device_init
00118 };
00119
00120 type = g_type_register_static (G_TYPE_OBJECT,
00121 "HalDevice",
00122 &type_info,
00123 0);
00124 }
00125
00126 return type;
00127 }
00128
00129 HalDevice *
00130 hal_device_new (void)
00131 {
00132 HalDevice *device;
00133
00134 device = g_object_new (HAL_TYPE_DEVICE, NULL);
00135
00136 return device;
00137 }
00138
00148 void
00149 hal_device_merge_with_rewrite (HalDevice *target,
00150 HalDevice *source,
00151 const char *target_namespace,
00152 const char *source_namespace)
00153 {
00154 GSList *iter;
00155 size_t source_ns_len;
00156
00157 source_ns_len = strlen (source_namespace);
00158
00159
00160
00161
00162
00163 for (iter = source->properties; iter != NULL; iter = iter->next) {
00164 HalProperty *p = iter->data;
00165 int type;
00166 const char *key;
00167 int target_type;
00168 gchar *target_key;
00169
00170 key = hal_property_get_key (p);
00171
00172
00173 if (strncmp(key, source_namespace, source_ns_len) != 0)
00174 continue;
00175
00176 target_key = g_strdup_printf("%s%s", target_namespace,
00177 key+source_ns_len);
00178
00179 type = hal_property_get_type (p);
00180
00181
00182 target_type = hal_device_property_get_type (target, key);
00183 if (target_type != DBUS_TYPE_NIL && target_type != type)
00184 hal_device_property_remove (target, key);
00185
00186 switch (type) {
00187
00188 case DBUS_TYPE_STRING:
00189 hal_device_property_set_string (
00190 target, target_key,
00191 hal_property_get_string (p));
00192 break;
00193
00194 case DBUS_TYPE_INT32:
00195 hal_device_property_set_int (
00196 target, target_key,
00197 hal_property_get_int (p));
00198 break;
00199
00200 case DBUS_TYPE_BOOLEAN:
00201 hal_device_property_set_bool (
00202 target, target_key,
00203 hal_property_get_bool (p));
00204 break;
00205
00206 case DBUS_TYPE_DOUBLE:
00207 hal_device_property_set_double (
00208 target, target_key,
00209 hal_property_get_double (p));
00210 break;
00211
00212 default:
00213 HAL_WARNING (("Unknown property type %d", type));
00214 break;
00215 }
00216
00217 g_free (target_key);
00218 }
00219
00220
00221
00222 }
00223
00224 void
00225 hal_device_merge (HalDevice *target, HalDevice *source)
00226 {
00227 const char *caps;
00228 GSList *iter;
00229
00230
00231
00232 for (iter = source->properties; iter != NULL; iter = iter->next) {
00233 HalProperty *p = iter->data;
00234 int type;
00235 const char *key;
00236 int target_type;
00237
00238 key = hal_property_get_key (p);
00239 type = hal_property_get_type (p);
00240
00241
00242 if (strcmp (key, "info.capabilities") == 0)
00243 continue;
00244
00245
00246 target_type = hal_device_property_get_type (target, key);
00247 if (target_type != DBUS_TYPE_NIL && target_type != type)
00248 hal_device_property_remove (target, key);
00249
00250 switch (type) {
00251
00252 case DBUS_TYPE_STRING:
00253 hal_device_property_set_string (
00254 target, key,
00255 hal_property_get_string (p));
00256 break;
00257
00258 case DBUS_TYPE_INT32:
00259 hal_device_property_set_int (
00260 target, key,
00261 hal_property_get_int (p));
00262 break;
00263
00264 case DBUS_TYPE_BOOLEAN:
00265 hal_device_property_set_bool (
00266 target, key,
00267 hal_property_get_bool (p));
00268 break;
00269
00270 case DBUS_TYPE_DOUBLE:
00271 hal_device_property_set_double (
00272 target, key,
00273 hal_property_get_double (p));
00274 break;
00275
00276 default:
00277 HAL_WARNING (("Unknown property type %d", type));
00278 break;
00279 }
00280 }
00281
00282
00283
00284 caps = hal_device_property_get_string (source, "info.capabilities");
00285 if (caps != NULL) {
00286 char **split_caps, **iter;
00287
00288 split_caps = g_strsplit (caps, " ", 0);
00289 for (iter = split_caps; *iter != NULL; iter++) {
00290 if (!hal_device_has_capability (target, *iter))
00291 hal_device_add_capability (target, *iter);
00292 }
00293
00294 g_strfreev (split_caps);
00295 }
00296 }
00297
00298 gboolean
00299 hal_device_matches (HalDevice *device1, HalDevice *device2,
00300 const char *namespace)
00301 {
00302 int len;
00303 GSList *iter;
00304
00305 len = strlen (namespace);
00306
00307 for (iter = device1->properties; iter != NULL; iter = iter->next) {
00308 HalProperty *p;
00309 const char *key;
00310 int type;
00311
00312 p = (HalProperty *) iter->data;
00313 key = hal_property_get_key (p);
00314 type = hal_property_get_type (p);
00315
00316 if (strncmp (key, namespace, len) != 0)
00317 continue;
00318
00319 if (!hal_device_has_property (device2, key))
00320 return FALSE;
00321
00322 switch (type) {
00323
00324 case DBUS_TYPE_STRING:
00325 if (strcmp (hal_property_get_string (p),
00326 hal_device_property_get_string (device2,
00327 key)) != 0)
00328 return FALSE;
00329 break;
00330
00331 case DBUS_TYPE_INT32:
00332 if (hal_property_get_int (p) !=
00333 hal_device_property_get_int (device2, key))
00334 return FALSE;
00335 break;
00336
00337 case DBUS_TYPE_BOOLEAN:
00338 if (hal_property_get_bool (p) !=
00339 hal_device_property_get_bool (device2, key))
00340 return FALSE;
00341 break;
00342
00343 case DBUS_TYPE_DOUBLE:
00344 if (hal_property_get_double (p) !=
00345 hal_device_property_get_double (device2, key))
00346 return FALSE;
00347 break;
00348
00349 default:
00350 HAL_WARNING (("Unknown property type %d", type));
00351 break;
00352 }
00353 }
00354
00355 return TRUE;
00356 }
00357
00358 const char *
00359 hal_device_get_udi (HalDevice *device)
00360 {
00361 return device->udi;
00362 }
00363
00364 void
00365 hal_device_set_udi (HalDevice *device, const char *udi)
00366 {
00367 device->udi = g_strdup (udi);
00368 }
00369
00370 void
00371 hal_device_add_capability (HalDevice *device, const char *capability)
00372 {
00373 const char *caps;
00374
00375 caps = hal_device_property_get_string (device, "info.capabilities");
00376
00377 if (caps == NULL) {
00378 hal_device_property_set_string (device, "info.capabilities",
00379 capability);
00380 } else {
00381 if (hal_device_has_capability (device, capability))
00382 return;
00383 else {
00384 char *tmp;
00385
00386 tmp = g_strconcat (caps, " ", capability, NULL);
00387
00388 hal_device_property_set_string (device,
00389 "info.capabilities",
00390 tmp);
00391
00392 g_free (tmp);
00393 }
00394 }
00395
00396 g_signal_emit (device, signals[CAPABILITY_ADDED], 0, capability);
00397 }
00398
00399 gboolean
00400 hal_device_has_capability (HalDevice *device, const char *capability)
00401 {
00402 const char *caps;
00403 char **split_caps, **iter;
00404 gboolean matched = FALSE;
00405
00406 caps = hal_device_property_get_string (device, "info.capabilities");
00407
00408 if (caps == NULL)
00409 return FALSE;
00410
00411 split_caps = g_strsplit (caps, " ", 0);
00412 for (iter = split_caps; *iter != NULL; iter++) {
00413 if (strcmp (*iter, capability) == 0) {
00414 matched = TRUE;
00415 break;
00416 }
00417 }
00418
00419 g_strfreev (split_caps);
00420
00421 return matched;
00422 }
00423
00424 gboolean
00425 hal_device_has_property (HalDevice *device, const char *key)
00426 {
00427 g_return_val_if_fail (device != NULL, FALSE);
00428 g_return_val_if_fail (key != NULL, FALSE);
00429
00430 return hal_device_property_find (device, key) != NULL;
00431 }
00432
00433 int
00434 hal_device_num_properties (HalDevice *device)
00435 {
00436 g_return_val_if_fail (device != NULL, -1);
00437
00438 return g_slist_length (device->properties);
00439 }
00440
00441 HalProperty *
00442 hal_device_property_find (HalDevice *device, const char *key)
00443 {
00444 GSList *iter;
00445
00446 g_return_val_if_fail (device != NULL, NULL);
00447 g_return_val_if_fail (key != NULL, NULL);
00448
00449 for (iter = device->properties; iter != NULL; iter = iter->next) {
00450 HalProperty *p = iter->data;
00451
00452 if (strcmp (hal_property_get_key (p), key) == 0)
00453 return p;
00454 }
00455
00456 return NULL;
00457 }
00458
00459 char *
00460 hal_device_property_to_string (HalDevice *device, const char *key)
00461 {
00462 HalProperty *prop;
00463
00464 prop = hal_device_property_find (device, key);
00465 if (!prop)
00466 return NULL;
00467
00468 return hal_property_to_string (prop);
00469 }
00470
00471 void
00472 hal_device_property_foreach (HalDevice *device,
00473 HalDevicePropertyForeachFn callback,
00474 gpointer user_data)
00475 {
00476 GSList *iter;
00477
00478 g_return_if_fail (device != NULL);
00479 g_return_if_fail (callback != NULL);
00480
00481 for (iter = device->properties; iter != NULL; iter = iter->next) {
00482 HalProperty *p = iter->data;
00483 gboolean cont;
00484
00485 cont = callback (device, p, user_data);
00486
00487 if (cont == FALSE)
00488 return;
00489 }
00490 }
00491
00492 int
00493 hal_device_property_get_type (HalDevice *device, const char *key)
00494 {
00495 HalProperty *prop;
00496
00497 g_return_val_if_fail (device != NULL, DBUS_TYPE_NIL);
00498 g_return_val_if_fail (key != NULL, DBUS_TYPE_NIL);
00499
00500 prop = hal_device_property_find (device, key);
00501
00502 if (prop != NULL)
00503 return hal_property_get_type (prop);
00504 else
00505 return DBUS_TYPE_NIL;
00506 }
00507
00508 const char *
00509 hal_device_property_get_string (HalDevice *device, const char *key)
00510 {
00511 HalProperty *prop;
00512
00513 g_return_val_if_fail (device != NULL, NULL);
00514 g_return_val_if_fail (key != NULL, NULL);
00515
00516 prop = hal_device_property_find (device, key);
00517
00518 if (prop != NULL)
00519 return hal_property_get_string (prop);
00520 else
00521 return NULL;
00522 }
00523
00524 dbus_int32_t
00525 hal_device_property_get_int (HalDevice *device, const char *key)
00526 {
00527 HalProperty *prop;
00528
00529 g_return_val_if_fail (device != NULL, -1);
00530 g_return_val_if_fail (key != NULL, -1);
00531
00532 prop = hal_device_property_find (device, key);
00533
00534 if (prop != NULL)
00535 return hal_property_get_int (prop);
00536 else
00537 return -1;
00538 }
00539
00540 dbus_bool_t
00541 hal_device_property_get_bool (HalDevice *device, const char *key)
00542 {
00543 HalProperty *prop;
00544
00545 g_return_val_if_fail (device != NULL, FALSE);
00546 g_return_val_if_fail (key != NULL, FALSE);
00547
00548 prop = hal_device_property_find (device, key);
00549
00550 if (prop != NULL)
00551 return hal_property_get_bool (prop);
00552 else
00553 return -1;
00554 }
00555
00556 double
00557 hal_device_property_get_double (HalDevice *device, const char *key)
00558 {
00559 HalProperty *prop;
00560
00561 g_return_val_if_fail (device != NULL, -1.0);
00562 g_return_val_if_fail (key != NULL, -1.0);
00563
00564 prop = hal_device_property_find (device, key);
00565
00566 if (prop != NULL)
00567 return hal_property_get_double (prop);
00568 else
00569 return -1.0;
00570 }
00571
00572 gboolean
00573 hal_device_property_set_string (HalDevice *device, const char *key,
00574 const char *value)
00575 {
00576 HalProperty *prop;
00577
00578
00579 prop = hal_device_property_find (device, key);
00580
00581 if (prop != NULL) {
00582 if (hal_property_get_type (prop) != DBUS_TYPE_STRING)
00583 return FALSE;
00584
00585
00586 if (value != NULL &&
00587 strcmp (hal_property_get_string (prop), value) == 0)
00588 return TRUE;
00589
00590 hal_property_set_string (prop, value);
00591
00592 g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
00593 key, FALSE, FALSE);
00594
00595 return TRUE;
00596 }
00597
00598 prop = hal_property_new_string (key, value);
00599
00600 device->properties = g_slist_prepend (device->properties, prop);
00601
00602 g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
00603 key, FALSE, TRUE);
00604
00605 return TRUE;
00606 }
00607
00608 gboolean
00609 hal_device_property_set_int (HalDevice *device, const char *key,
00610 dbus_int32_t value)
00611 {
00612 HalProperty *prop;
00613
00614
00615 prop = hal_device_property_find (device, key);
00616
00617 if (prop != NULL) {
00618 if (hal_property_get_type (prop) != DBUS_TYPE_INT32)
00619 return FALSE;
00620
00621
00622 if (hal_property_get_int (prop) == value)
00623 return TRUE;
00624
00625 hal_property_set_int (prop, value);
00626
00627 g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
00628 key, FALSE, FALSE);
00629
00630 return TRUE;
00631 }
00632
00633 prop = hal_property_new_int (key, value);
00634
00635 device->properties = g_slist_prepend (device->properties, prop);
00636
00637 g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
00638 key, FALSE, TRUE);
00639
00640 return TRUE;
00641 }
00642
00643 gboolean
00644 hal_device_property_set_bool (HalDevice *device, const char *key,
00645 dbus_bool_t value)
00646 {
00647 HalProperty *prop;
00648
00649
00650 prop = hal_device_property_find (device, key);
00651
00652 if (prop != NULL) {
00653 if (hal_property_get_type (prop) != DBUS_TYPE_BOOLEAN)
00654 return FALSE;
00655
00656
00657 if (hal_property_get_bool (prop) == value)
00658 return TRUE;
00659
00660 hal_property_set_bool (prop, value);
00661
00662 g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
00663 key, FALSE, FALSE);
00664
00665 return TRUE;
00666 }
00667
00668 prop = hal_property_new_bool (key, value);
00669
00670 device->properties = g_slist_prepend (device->properties, prop);
00671
00672 g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
00673 key, FALSE, TRUE);
00674
00675 return TRUE;
00676 }
00677
00678 gboolean
00679 hal_device_property_set_double (HalDevice *device, const char *key,
00680 double value)
00681 {
00682 HalProperty *prop;
00683
00684
00685 prop = hal_device_property_find (device, key);
00686
00687 if (prop != NULL) {
00688 if (hal_property_get_type (prop) != DBUS_TYPE_DOUBLE)
00689 return FALSE;
00690
00691
00692 if (hal_property_get_double (prop) == value)
00693 return TRUE;
00694
00695 hal_property_set_double (prop, value);
00696
00697 g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
00698 key, FALSE, FALSE);
00699
00700 return TRUE;
00701 }
00702
00703 prop = hal_property_new_double (key, value);
00704
00705 device->properties = g_slist_prepend (device->properties, prop);
00706
00707 g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
00708 key, FALSE, TRUE);
00709
00710 return TRUE;
00711 }
00712
00713 gboolean
00714 hal_device_property_remove (HalDevice *device, const char *key)
00715 {
00716 HalProperty *prop;
00717
00718 prop = hal_device_property_find (device, key);
00719
00720 if (prop == NULL)
00721 return FALSE;
00722
00723 device->properties = g_slist_remove (device->properties, prop);
00724
00725 hal_property_free (prop);
00726
00727 g_signal_emit (device, signals[PROPERTY_CHANGED], 0,
00728 key, TRUE, FALSE);
00729
00730 return TRUE;
00731 }
00732
00733 void
00734 hal_device_print (HalDevice *device)
00735 {
00736 GSList *iter;
00737
00738 printf ("device udi = %s\n", hal_device_get_udi (device));
00739
00740 for (iter = device->properties; iter != NULL; iter = iter->next) {
00741 HalProperty *p = iter->data;
00742 int type;
00743 const char *key;
00744
00745 key = hal_property_get_key (p);
00746 type = hal_property_get_type (p);
00747
00748 switch (type) {
00749 case DBUS_TYPE_STRING:
00750 printf (" %s = '%s' (string)\n", key,
00751 hal_property_get_string (p));
00752 break;
00753
00754 case DBUS_TYPE_INT32:
00755 printf (" %s = %d 0x%x (int)\n", key,
00756 hal_property_get_int (p),
00757 hal_property_get_int (p));
00758 break;
00759
00760 case DBUS_TYPE_DOUBLE:
00761 printf (" %s = %g (double)\n", key,
00762 hal_property_get_double (p));
00763 break;
00764
00765 case DBUS_TYPE_BOOLEAN:
00766 printf (" %s = %s (bool)\n", key,
00767 (hal_property_get_bool (p) ? "true" :
00768 "false"));
00769 break;
00770
00771 default:
00772 HAL_WARNING (("Unknown property type %d", type));
00773 break;
00774 }
00775 }
00776 printf ("\n");
00777 }
00778
00779
00780 typedef struct {
00781 char *key;
00782 HalDevice *device;
00783 HalDeviceAsyncCallback callback;
00784 gpointer user_data;
00785
00786 guint prop_signal_id;
00787 guint timeout_id;
00788 } AsyncMatchInfo;
00789
00790 static void
00791 destroy_async_match_info (AsyncMatchInfo *ai)
00792 {
00793 g_free (ai->key);
00794 g_signal_handler_disconnect (ai->device, ai->prop_signal_id);
00795 g_source_remove (ai->timeout_id);
00796 g_object_unref (ai->device);
00797 g_free (ai);
00798 }
00799
00800 static void
00801 prop_changed_cb (HalDevice *device, const char *key,
00802 gboolean removed, gboolean added, gpointer user_data)
00803 {
00804 AsyncMatchInfo *ai = user_data;
00805
00806 if (strcmp (key, ai->key) != 0)
00807 return;
00808
00809
00810 if (removed)
00811 goto cleanup;
00812
00813
00814 ai->callback (ai->device, ai->user_data, TRUE);
00815
00816 cleanup:
00817 destroy_async_match_info (ai);
00818 }
00819
00820
00821 static gboolean
00822 async_wait_timeout (gpointer user_data)
00823 {
00824 AsyncMatchInfo *ai = (AsyncMatchInfo *) user_data;
00825
00826 ai->callback (ai->device, ai->user_data, FALSE);
00827
00828 destroy_async_match_info (ai);
00829
00830 return FALSE;
00831 }
00832
00833 void
00834 hal_device_async_wait_property (HalDevice *device,
00835 const char *key,
00836 HalDeviceAsyncCallback callback,
00837 gpointer user_data,
00838 int timeout)
00839 {
00840 HalProperty *prop;
00841 AsyncMatchInfo *ai;
00842
00843
00844 prop = hal_device_property_find (device, key);
00845
00846 if (prop != NULL || timeout==0) {
00847 callback (device, user_data, prop != NULL);
00848 return;
00849 }
00850
00851 ai = g_new0 (AsyncMatchInfo, 1);
00852
00853 ai->device = g_object_ref (device);
00854 ai->key = g_strdup (key);
00855 ai->callback = callback;
00856 ai->user_data = user_data;
00857
00858 ai->prop_signal_id = g_signal_connect (device, "property_changed",
00859 G_CALLBACK (prop_changed_cb),
00860 ai);
00861
00862 ai->timeout_id = g_timeout_add (timeout, async_wait_timeout, ai);
00863 }