Main Page | Modules | Data Structures | File List | Data Fields | Related Pages

class_device.c

00001 /***************************************************************************
00002  * CVSID: $Id: class_device.c,v 1.10 2004/04/22 21:52:05 david Exp $
00003  *
00004  * Generic methods for class devices
00005  *
00006  * Copyright (C) 2003 David Zeuthen, <david@fubar.dk>
00007  *
00008  * Licensed under the Academic Free License version 2.0
00009  *
00010  * This program is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version.
00014  *
00015  * This program is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software
00022  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
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 #include <limits.h>
00039 
00040 #include "../logger.h"
00041 #include "../device_store.h"
00042 #include "../hald.h"
00043 
00044 #include "common.h"
00045 #include "class_device.h"
00046 
00054 typedef struct {
00055     HalDevice *device;
00056     ClassDeviceHandler *handler;
00057 } AsyncInfo;
00058 
00059 static void
00060 class_device_got_device_file (HalDevice *d, gpointer user_data, 
00061                   gboolean prop_exists);
00062 
00063 static void
00064 class_device_final (ClassDeviceHandler* self, HalDevice *d);
00065 
00066 
00075 dbus_bool_t
00076 class_device_accept (ClassDeviceHandler *self,
00077              const char *path,
00078              struct sysfs_class_device *class_device,
00079              dbus_bool_t is_probing)
00080 {
00081 
00082     /*HAL_INFO (("path = %s, classname = %s", 
00083       path, self->sysfs_class_name));*/
00084 
00085     /* only care about given sysfs class name */
00086     if (strcmp (class_device->classname, self->sysfs_class_name) == 0) {
00087         return TRUE;
00088     }
00089 
00090     return FALSE;
00091 }
00092 
00103 void
00104 class_device_visit (ClassDeviceHandler *self,
00105             const char *path,
00106             struct sysfs_class_device *class_device,
00107             dbus_bool_t is_probing)
00108 {
00109     HalDevice *d;
00110     char dev_file[SYSFS_PATH_MAX];
00111     char dev_file_prop_name[SYSFS_PATH_MAX];
00112 
00113     /* don't care if there is no sysdevice */
00114     if (class_device->sysdevice == NULL) {
00115         return;
00116     }
00117 
00118     /* Construct a new device and add to temporary device list */
00119     d = hal_device_new ();
00120     hal_device_store_add (hald_get_tdl (), d);
00121 
00122     /* Need some properties if we are to appear in the tree on our own */
00123     if (!self->merge_or_add) {
00124         hal_device_property_set_string (d, "info.bus", 
00125                         self->hal_class_name);
00126         hal_device_property_set_string (d, "linux.sysfs_path", path);
00127         hal_device_property_set_string (d, "linux.sysfs_path_device", 
00128                     class_device->sysdevice->path);
00129     } 
00130 
00131     /* Temporary property used for _udev_event() */
00132     hal_device_property_set_string (d, ".udev.sysfs_path", path);
00133     hal_device_property_set_string (d, ".udev.class_name", 
00134                     self->sysfs_class_name);
00135 
00136     /* We may require a device file */
00137     if (self->require_device_file) {
00138 
00139         /* Find the property name we should store the device file in */
00140         self->get_device_file_target (self, d, path, class_device,
00141                           dev_file_prop_name, 
00142                           SYSFS_PATH_MAX);
00143         hal_device_property_set_string (d, ".target_dev", 
00144                         dev_file_prop_name);
00145 
00146         /* Ask udev about the device file if we are probing */
00147         if (is_probing) {
00148             if (!class_device_get_device_file (path, dev_file, 
00149                                SYSFS_PATH_MAX)) {
00150                 HAL_WARNING (("Couldn't get device file for "
00151                           "sysfs path %s", path));
00152                 return;
00153             }
00154 
00155             /* If we are not probing this function will be called 
00156              * upon receiving a dbus event */
00157             self->udev_event (self, d, dev_file);
00158         }
00159     }
00160 
00161     /* Now find the physical device; this happens asynchronously as it
00162      * might be added later. */
00163     if (self->merge_or_add) {
00164         AsyncInfo *ai = g_new0 (AsyncInfo, 1);
00165         ai->device = d;
00166         ai->handler = self;
00167 
00168         /* find the sysdevice */
00169         hal_device_store_match_key_value_string_async (
00170             hald_get_gdl (),
00171             "linux.sysfs_path_device",
00172             class_device->sysdevice->path,
00173             class_device_got_sysdevice, ai,
00174             is_probing ? 0 : HAL_LINUX_HOTPLUG_TIMEOUT);
00175     } else {
00176         char *parent_sysfs_path;
00177         AsyncInfo *ai = g_new0 (AsyncInfo, 1);
00178 
00179         parent_sysfs_path = 
00180             get_parent_sysfs_path (class_device->sysdevice->path);
00181 
00182         ai->device = d;
00183         ai->handler = self;
00184 
00185         /* find the parent */
00186         hal_device_store_match_key_value_string_async (
00187             hald_get_gdl (),
00188             "linux.sysfs_path_device",
00189             parent_sysfs_path,
00190             class_device_got_parent_device, ai,
00191             is_probing ? 0 : HAL_LINUX_HOTPLUG_TIMEOUT);
00192     }
00193 }
00194 
00203 void
00204 class_device_removed (ClassDeviceHandler* self, const char *sysfs_path, 
00205               HalDevice *d)
00206 {
00207     HAL_INFO (("sysfs_path = '%s'", sysfs_path));
00208 }
00209 
00217 void
00218 class_device_udev_event (ClassDeviceHandler *self, HalDevice *d, 
00219              char *dev_file)
00220 {
00221     const char *target_dev;
00222     char *target_dev_copy;
00223 
00224     /* merge the device file name into the name determined above */
00225     target_dev = hal_device_property_get_string (d, ".target_dev");
00226     assert (target_dev != NULL);
00227 
00228     /* hmm, have to make a copy because somewhere asynchronously we
00229      * remove .target_dev */
00230     target_dev_copy = strdup (target_dev);
00231     assert (target_dev_copy != NULL);
00232 
00233     /* this will invoke _got_device_file per the _async_wait_for_  below */
00234     hal_device_property_set_string (d, target_dev_copy, dev_file);
00235 
00236     free (target_dev_copy);
00237 }
00238 
00239 
00248 void
00249 class_device_got_parent_device (HalDeviceStore *store, HalDevice *parent, 
00250                 gpointer user_data)
00251 {
00252     AsyncInfo *ai = user_data;
00253     HalDevice *d = (HalDevice *) ai->device;
00254     ClassDeviceHandler *self = ai->handler;
00255 
00256     g_free (ai);
00257 
00258     if (parent == NULL) {
00259         HAL_WARNING (("No parent for class device at sysfs path %s",
00260                   d->udi));
00261         /* get rid of temporary device */
00262         hal_device_store_remove (hald_get_tdl (), d);
00263         g_object_unref (d);
00264         return;
00265     }
00266 
00267     /* set parent */
00268     hal_device_property_set_string (d, "info.parent", parent->udi);
00269 
00270     /* wait for the appropriate property for the device file */
00271     if (self->require_device_file) {
00272         const char *target_dev;
00273         target_dev = hal_device_property_get_string (d, ".target_dev");
00274         assert (target_dev != NULL);
00275 
00276         hal_device_async_wait_property (
00277             d, target_dev, 
00278             class_device_got_device_file,
00279             (gpointer) self,
00280             is_probing ? 0 : HAL_LINUX_HOTPLUG_TIMEOUT);
00281     } else {
00282         class_device_final (self, d);
00283     }
00284 }
00285 
00286 
00295 void
00296 class_device_got_sysdevice (HalDeviceStore *store, 
00297                 HalDevice *sysdevice, 
00298                 gpointer user_data)
00299 {
00300     AsyncInfo *ai = user_data;
00301     HalDevice *d = (HalDevice *) ai->device;
00302     ClassDeviceHandler *self = ai->handler;
00303 
00304     HAL_INFO (("Entering d=0x%0x, sysdevice=0x%0x!", d, sysdevice));
00305 
00306     if (sysdevice == NULL) {
00307         HAL_WARNING (("Sysdevice for a class device never appeared!"));
00308         /* get rid of temporary device */
00309         hal_device_store_remove (hald_get_tdl (), d);
00310         g_object_unref (d);
00311         return;
00312     }
00313 
00314     /* special case : merge onto the usb device, not the usb interface */
00315     if (hal_device_has_property (sysdevice, "info.bus") &&
00316         hal_device_has_property (sysdevice, "info.parent") &&
00317         (strcmp (hal_device_property_get_string (sysdevice, "info.bus"),
00318                              "usbif") == 0)) {
00319         const char *parent_udi;
00320         HalDevice *parent_device;
00321 
00322         parent_udi = hal_device_property_get_string (sysdevice, 
00323                                  "info.parent");
00324         parent_device = hal_device_store_find (hald_get_gdl (),
00325                                parent_udi);
00326         if (parent_device != NULL) {
00327             sysdevice = parent_device;
00328         }
00329     }
00330     
00331     /* store the name of the sysdevice in a temporary property */
00332     hal_device_property_set_string (d, ".sysdevice", sysdevice->udi);
00333 
00334     /* wait for the appropriate property for the device file */
00335     if (self->require_device_file) {
00336         const char *target_dev;
00337         target_dev = hal_device_property_get_string (d, ".target_dev");
00338         assert (target_dev != NULL);
00339 
00340         hal_device_async_wait_property (
00341             d, target_dev, 
00342             class_device_got_device_file,
00343             (gpointer) self,
00344             is_probing ? 0 : HAL_LINUX_HOTPLUG_TIMEOUT);
00345     } else {
00346         class_device_final (self, d);
00347     }
00348 }
00349 
00350 static void
00351 class_device_got_device_file (HalDevice *d, gpointer user_data, 
00352                   gboolean prop_exists)
00353 {
00354     ClassDeviceHandler *self = (ClassDeviceHandler *) user_data;
00355 
00356     /*HAL_INFO (("entering"));*/
00357 
00358     if (!prop_exists) {
00359         HAL_WARNING (("Never got device file for class device at %s", 
00360                   hal_device_property_get_string (d, ".udev.sysfs_path")));
00361         hal_device_store_remove (hald_get_tdl (), d);
00362         g_object_unref (d);
00363         return;
00364     }
00365 
00366     class_device_final (self, d);
00367 }
00368 
00369 static void
00370 class_device_final (ClassDeviceHandler* self, HalDevice *d)
00371 {
00372     const char *sysfs_path = NULL;
00373     struct sysfs_class_device *class_device;
00374 
00375     /* get more information about the device from the specialised 
00376      * function */
00377     sysfs_path = hal_device_property_get_string (d, ".udev.sysfs_path");
00378     assert (sysfs_path != NULL);
00379     class_device = sysfs_open_class_device (sysfs_path);
00380     if (class_device == NULL)
00381         DIE (("Coulnd't get sysfs class device object for path %s", 
00382               sysfs_path));
00383     self->pre_process (self, d, sysfs_path, class_device);
00384     sysfs_close_class_device (class_device);
00385 
00386     if (self->merge_or_add) {
00387         const char *sysdevice_udi;
00388         HalDevice *sysdevice;
00389 
00390         /* get the sysdevice from the temporary cookie */
00391         sysdevice_udi = hal_device_property_get_string (d, ".sysdevice");
00392         assert (sysdevice_udi != NULL);
00393         sysdevice = hal_device_store_find (hald_get_gdl (),
00394                            sysdevice_udi);
00395         assert (sysdevice != NULL);
00396 
00397         /* remove various temporary properties */
00398         hal_device_property_remove (d, ".udev.sysfs_path");
00399         hal_device_property_remove (d, ".udev.class_name");
00400         hal_device_property_remove (d, ".sysdevice");
00401         hal_device_property_remove (d, ".target_dev");
00402           
00403         /* merge information from temporary device onto the physical
00404          * device */
00405         hal_device_merge (sysdevice, d);
00406 
00407         HAL_INFO (("Merged udi=%s onto %s", 
00408                hal_device_get_udi (d),
00409                hal_device_get_udi (sysdevice)));
00410 
00411         /* get rid of temporary device */
00412         hal_device_store_remove (hald_get_tdl (), d);
00413         g_object_unref (d);
00414 
00415         self->post_merge (self, sysdevice);
00416     } else {
00417         char *new_udi;
00418         HalDevice *new_d;
00419 
00420         /* remove various temporary properties */
00421         hal_device_property_remove (d, ".udev.sysfs_path");
00422         hal_device_property_remove (d, ".udev.class_name");
00423         hal_device_property_remove (d, ".sysdevice");
00424         hal_device_property_remove (d, ".target_dev");
00425 
00426         /* Compute a proper UDI (unique device id) and try to locate a 
00427          * persistent unplugged device or simply add this new device...
00428          */
00429         new_udi = rename_and_merge (d, self->compute_udi, self->hal_class_name);
00430         if (new_udi != NULL) {
00431             new_d = hal_device_store_find (hald_get_gdl (),
00432                                new_udi);
00433 
00434             self->got_udi (self, new_d!=NULL ? new_d : d, new_udi);
00435 
00436             hal_device_store_add (hald_get_gdl (),
00437                           new_d != NULL ? new_d : d);
00438         }
00439         hal_device_store_remove (hald_get_tdl (), d);
00440         g_object_unref (d);
00441     }
00442 }
00443 
00444 
00448 void
00449 class_device_init (ClassDeviceHandler *self)
00450 {
00451 }
00452 
00457 void
00458 class_device_detection_done (ClassDeviceHandler *self)
00459 {
00460 }
00461 
00465 void
00466 class_device_shutdown (ClassDeviceHandler *self)
00467 {
00468 }
00469 
00470 
00485 void 
00486 class_device_pre_process (ClassDeviceHandler *self,
00487               HalDevice *d,
00488               const char *sysfs_path,
00489               struct sysfs_class_device *class_device)
00490 {
00491     /* this function is left intentionally blank */
00492 }
00493 
00502 void
00503 class_device_post_merge (ClassDeviceHandler *self,
00504              HalDevice *d)
00505 {
00506     /* this function is left intentionally blank */
00507 }
00508 
00514 void
00515 class_device_tick (ClassDeviceHandler *self)
00516 {
00517 }
00518 
00533 void
00534 class_device_get_device_file_target (ClassDeviceHandler *self,
00535                      HalDevice *d,
00536                      const char *sysfs_path,
00537                      struct sysfs_class_device *class_device,
00538                      char* dev_file_prop,
00539                      int dev_file_prop_len)
00540 {
00541     snprintf (dev_file_prop, dev_file_prop_len, 
00542           "%s.device", self->hal_class_name);
00543 }
00544 
00545 void
00546 class_device_got_udi (ClassDeviceHandler *self,
00547               HalDevice *d,
00548               const char *udi)
00549 {
00550 }
00551 

Generated on Sat Apr 24 19:57:44 2004 for HAL by doxygen 1.3.6-20040222