[Date Prev][Date Next] [Thread Prev][Thread Next]
[Thread Index]
[Date Index]
[Author Index]
Re: More on hotplug issue w/HAL
- From: Matthew Mastracci <matt aclaro com>
- To: David Zeuthen <david fubar dk>
- Cc: xdg-list freedesktop org
- Subject: Re: More on hotplug issue w/HAL
- Date: Sat, 10 Jan 2004 11:47:48 -0700
On Fri, 2004-01-09 at 18:10, David Zeuthen wrote:
> Basically, since they are class devices they should just merge
> properties into the PCI device (the silicon) they belong to. This would
> amount to adding the capability i2c_adapter to that device and setting
> the property i2c_adaptor.name to the name we get from sysfs.
I think I've now got this implemented in the attached class device
files.
> This is completely analogue to what the properties merged into the PCI
> device being a USB controller, see
>
> http://freedesktop.org/~david/hal-pci-usb.png
>
> note that this PCI device got the capability serial_controller.usb. This
> would conclude handling of i2c_adapter devices. You would probably put
> this in files linux_class_i2c_adaptor.[ch]
>
> In addition, we should check for i2c devices (which are physical
> devices) and attach them to the proper parent i2c_adaptor. Do you have
> any i2c devices in your sysfs tree? I don't have any :-/ (need to find
> my tv tuner card). This could go in existing files linux_i2c.[ch].
I had to add a special case to visit_device that adds the appropriate
i2c class device when it finds it. I couldn't figure out any other way
to ensure that the i2c adapters were added to the tree before their i2c
subdevices were scanned. USB and PCI have it easy - the bridges for
those devices are on the same bus as the subdevices.
The attached patch works without any special kernel patching. Let me
know how it looks.
Thanks,
Matt
--
Matthew Mastracci <matt aclaro com>
/***************************************************************************
* CVSID: $Id$
*
* linux_class_i2c_adapter.c : I2C functions for sysfs-agent on Linux 2.6
*
* Copyright (C) 2003 David Zeuthen, <david fubar dk>
*
* Licensed under the Academic Free License version 2.0
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
**************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <assert.h>
#include <unistd.h>
#include <stdarg.h>
#include "../logger.h"
#include "../device_store.h"
#include "linux_class_i2c_adapter.h"
/**
* @defgroup HalDaemonLinuxI2cAdapter I2C adapter class
* @ingroup HalDaemonLinux
* @brief I2C adapter class
* @{
*/
/** This function will compute the device uid based on other properties
* of the device. For I2C adapters it is the adapter number.
*
* @param d HalDevice object
* @param append_num Number to append to name if not -1
* @return New unique device id; only good until the
* next invocation of this function
*/
static char* i2c_adapter_compute_udi(HalDevice* d, int append_num)
{
const char* format;
static char buf[256];
if( append_num==-1 )
format = "/org/freedesktop/Hal/devices/i2c_adapter_%d";
else
format = "/org/freedesktop/Hal/devices/i2c_adapter_%d-%d";
snprintf(buf, 256, format,
ds_property_get_int(d, "i2c_adapter.adapter"),
append_num);
return buf;
}
/* fwd decl */
static void visit_class_device_i2c_adapter_got_parent(HalDevice* parent,
void* data1, void* data2);
/** Visitor function for I2C adapter.
*
* This function parses the attributes present and creates a new HAL
* device based on this information.
*
* @param path Sysfs-path for device
* @param device libsysfs object for device
*/
void visit_class_device_i2c_adapter(const char* path,
struct sysfs_class_device* class_device)
{
HalDevice* d;
struct sysfs_attribute* cur;
char* parent_sysfs_path;
char* product_name;
char attr_name[SYSFS_NAME_LEN];
const char* last_elem;
int adapter_num;
int len;
int i;
if( class_device->sysdevice==NULL )
{
HAL_INFO(("Skipping virtual class device at path %s\n", path));
return;
}
HAL_INFO(("i2c_adapter: sysdevice_path=%s, path=%s\n", class_device->sysdevice->path, path));
/** @todo: see if we already got this device */
d = ds_device_new();
ds_property_set_string(d, "info.bus", "i2c_adapter");
ds_property_set_string(d, "linux.sysfs_path", path);
ds_property_set_string(d, "linux.sysfs_path_device",
class_device->sysdevice->path);
/* Sets last_elem to i2c-2 in path=/sys/class/i2c-adapter/i2c-2 */
last_elem = get_last_element(path);
sscanf(last_elem, "i2c-%d", &adapter_num);
ds_property_set_int(d, "i2c_adapter.adapter", adapter_num);
/* guestimate product name */
dlist_for_each_data(sysfs_get_device_attributes(class_device->sysdevice), cur,
struct sysfs_attribute)
{
if( sysfs_get_name_from_path(cur->path,
attr_name, SYSFS_NAME_LEN) != 0 )
continue;
/* strip whitespace */
len = strlen(cur->value);
for(i=len-1; isspace(cur->value[i]); --i)
cur->value[i] = '\0';
/*printf("attr_name=%s -> '%s'\n", attr_name, cur->value);*/
if( strcmp(attr_name, "name")==0 )
product_name = cur->value;
}
ds_property_set_string(d, "info.product", "I2C Adapter Interface");
if ( product_name==NULL )
ds_property_set_string(d, "i2c_adapter.name", "I2C Adapter Interface");
else
ds_property_set_string(d, "i2c_adapter.name", product_name);
parent_sysfs_path = get_parent_sysfs_path(class_device->sysdevice->path);
/* Find parent; this happens asynchronously as our parent might
* be added later. If we are probing this can't happen so the
* timeout is set to zero in that event..
*/
ds_device_async_find_by_key_value_string(
"linux.sysfs_path_device",
parent_sysfs_path,
TRUE,
visit_class_device_i2c_adapter_got_parent,
(void*) d, NULL,
is_probing ? 0 :
HAL_LINUX_HOTPLUG_TIMEOUT);
free(parent_sysfs_path);
}
/** Callback when the parent is found or if there is no parent.. This is
* where we get added to the GDL..
*
* @param parent Async Return value from the find call
* @param data1 User data
* @param data2 User data
*/
static void visit_class_device_i2c_adapter_got_parent(HalDevice* parent,
void* data1, void* data2)
{
char* new_udi = NULL;
HalDevice* new_d = NULL;
HalDevice* d = (HalDevice*) data1;
/*printf("parent=0x%08x\n", parent);*/
if( parent!=NULL )
{
ds_property_set_string(d, "info.parent", parent->udi);
find_and_set_physical_device(d);
ds_property_set_bool(d, "info.virtual", TRUE);
}
else
{
HAL_ERROR(("No parent for I2C adapter device!"));
ds_device_destroy(d);
return;
}
/* Add the i2c_adapter capability to our parent device */
ds_add_capability(parent, "i2c_adapter");
/* Compute a proper UDI (unique device id) and try to locate a persistent
* unplugged device or simple add this new device...
*/
new_udi = rename_and_merge(d, i2c_adapter_compute_udi, "i2c_adapter");
if( new_udi!=NULL )
{
new_d = ds_device_find(new_udi);
if( new_d!=NULL )
{
ds_gdl_add(new_d);
}
}
}
/** Init function for I2C adapter class handling
*
*/
void linux_class_i2c_adapter_init()
{
}
/** This function is called when all device detection on startup is done
* in order to perform optional batch processing on devices
*
*/
void linux_class_i2c_adapter_detection_done()
{
}
/** Shutdown function for I2C adapter class handling
*
*/
void linux_class_i2c_adapter_shutdown()
{
}
/** @} */
/***************************************************************************
* CVSID: $Id$
*
* linux_class_i2c_adapter.h : I2C device handling on Linux 2.6
*
* Copyright (C) 2003 David Zeuthen, <david fubar dk>
*
* Licensed under the Academic Free License version 2.0
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
**************************************************************************/
#ifndef LINUX_CLASS_I2C_ADAPTER_H
#define LINUX_CLASS_I2C_ADAPTER_H
#include "linux_common.h"
void visit_class_device_i2c_adapter(const char* path,
struct sysfs_class_device *class_device);
void linux_class_i2c_adapter_init();
void linux_class_i2c_adapter_detection_done();
void linux_class_i2c_adapter_shutdown();
#endif /* LINUX_CLASS_I2C_ADAPTER_H */
Index: hald/Makefile.am
===================================================================
RCS file: /cvs/hal/hal/hald/Makefile.am,v
retrieving revision 1.8
diff -u -r1.8 Makefile.am
--- hald/Makefile.am 2 Jan 2004 12:15:52 -0000 1.8
+++ hald/Makefile.am 10 Jan 2004 18:47:06 -0000
@@ -22,11 +22,13 @@
linux/linux_osspec.c \
linux/linux_common.h linux/linux_common.c \
linux/linux_pci.h linux/linux_pci.c \
+ linux/linux_i2c.h linux/linux_i2c.c \
linux/linux_usb.h linux/linux_usb.c \
linux/linux_ide.h linux/linux_ide.c \
linux/linux_class_block.h linux/linux_class_block.c \
linux/linux_class_scsi.h linux/linux_class_scsi.c \
linux/linux_class_net.h linux/linux_class_net.c \
+ linux/linux_class_i2c_adapter.h linux/linux_class_i2c_adapter.c \
linux/linux_class_input.h linux/linux_class_input.c
hald_SOURCES += \
Index: hald/linux/linux_osspec.c
===================================================================
RCS file: /cvs/hal/hal/hald/linux/linux_osspec.c,v
retrieving revision 1.10
diff -u -r1.10 linux_osspec.c
--- hald/linux/linux_osspec.c 9 Jan 2004 23:22:58 -0000 1.10
+++ hald/linux/linux_osspec.c 10 Jan 2004 18:47:07 -0000
@@ -48,6 +48,7 @@
#include "linux_ide.h"
#include "linux_class_block.h"
#include "linux_class_scsi.h"
+#include "linux_class_i2c_adapter.h"
#include "linux_class_net.h"
#include "linux_class_input.h"
@@ -100,6 +101,8 @@
visit_class_device_scsi_host(path, class_device);
else if( strcmp(class_device->classname, "scsi_device")==0 )
visit_class_device_scsi_device(path, class_device);
+ else if( strcmp(class_device->classname, "i2c-adapter")==0 )
+ visit_class_device_i2c_adapter(path, class_device);
else if( strcmp(class_device->classname, "block")==0 )
visit_class_device_block(path, class_device);
else if( strcmp(class_device->classname, "net")==0 )
@@ -170,6 +173,8 @@
{
struct sysfs_device* device;
struct sysfs_directory* subdir;
+ struct sysfs_class* cls;
+ struct sysfs_class_device* class_device;
device = sysfs_open_device(path);
if( device==NULL )
@@ -192,12 +197,27 @@
/** @todo This is a hack; is there such a thing as an ide_host? */
else if( strncmp(device->bus_id, "ide", 3)==0 )
visit_device_ide_host(path, device);
- /* Hmm only works on some boxes?? So we have to do hack below
else if( strcmp(device->bus, "i2c")==0 )
- visit_device_i2c(path, device);*/
- else if( strncmp(device->bus_id, "i2c", 3)==0 )
- visit_device_i2c(path, device);
- else
+ visit_device_i2c(path, device);
+ else if( strncmp(device->bus_id, "i2c", 3)==0 )
+ {
+ /* We need to add the i2c-adapter class devices here, otherwise the I2C
+ devices have nowhere to go */
+ cls = sysfs_open_class("i2c-adapter");
+ if (cls != NULL)
+ {
+ if( cls->devices!=NULL )
+ {
+ dlist_for_each_data(cls->devices, class_device, struct sysfs_class_device)
+ {
+ printf("device->bus_id = %s, cls->name = %s\n", device->bus_id, class_device->name);
+ if ( strcmp(device->bus_id, class_device->name) == 0 )
+ visit_class_device_i2c_adapter(path, class_device);
+ }
+ }
+ sysfs_close_class(cls);
+ }
+ }
{
/*printf("bus=%s path=%s\n", device->bus, path);*/
}
@@ -412,7 +432,8 @@
if( sysfs_devpath[0]!='\0' &&
(strcmp(subsystem, "usb")==0 ||
- strcmp(subsystem, "pci")==0) )
+ strcmp(subsystem, "pci")==0 ||
+ strcmp(subsystem, "i2c")==0))
{
if( is_add )
@@ -461,7 +482,8 @@
(strcmp(subsystem, "net")==0 ||
strcmp(subsystem, "block")==0 ||
strcmp(subsystem, "scsi_host")==0 ||
- strcmp(subsystem, "scsi_device")==0) )
+ strcmp(subsystem, "scsi_device")==0 ||
+ strcmp(subsystem, "i2c-adapter")==0) )
{
if( is_add )
{
Index: tools/device-manager/Const.py.in
===================================================================
RCS file: /cvs/hal/hal/tools/device-manager/Const.py.in,v
retrieving revision 1.3
diff -u -r1.3 Const.py.in
--- tools/device-manager/Const.py.in 23 Dec 2003 22:29:59 -0000 1.3
+++ tools/device-manager/Const.py.in 10 Jan 2004 18:47:07 -0000
@@ -19,6 +19,8 @@
BUS_NAMES = {"usb" : "USB",
"usbif" : "USB Interface",
"pci" : "PCI",
+ "i2c" : "I2C",
+ "i2c_adapter" : "I2C Adapter",
"scsi_host" : "SCSI Host",
"scsi_device" : "SCSI",
"block" : "Block",
[Date Prev][Date Next] [Thread Prev][Thread Next]
[Thread Index]
[Date Index]
[Author Index]